{-# LANGUAGE FlexibleContexts, OverloadedStrings #-}
module Network.MPD.Commands.Parse where
import Network.MPD.Commands.Types
import Control.Applicative
import Control.Monad.Error
import Data.Maybe (fromMaybe)
import Network.MPD.Util
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.UTF8 as UTF8
parseCount :: [ByteString] -> Either String Count
parseCount :: [ByteString] -> Either String Count
parseCount = (Count -> (ByteString, ByteString) -> Either String Count)
-> Count -> [(ByteString, ByteString)] -> Either String Count
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM Count -> (ByteString, ByteString) -> Either String Count
f Count
forall a. Default a => a
def ([(ByteString, ByteString)] -> Either String Count)
-> ([ByteString] -> [(ByteString, ByteString)])
-> [ByteString]
-> Either String Count
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> [(ByteString, ByteString)]
toAssocList
where f :: Count -> (ByteString, ByteString) -> Either String Count
f :: Count -> (ByteString, ByteString) -> Either String Count
f a :: Count
a ("songs", x :: ByteString
x) = Count -> Either String Count
forall (m :: * -> *) a. Monad m => a -> m a
return (Count -> Either String Count) -> Count -> Either String Count
forall a b. (a -> b) -> a -> b
$ (ByteString -> Maybe Integer)
-> (Integer -> Count) -> Count -> ByteString -> Count
forall a b.
(ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse ByteString -> Maybe Integer
forall a. (Read a, Integral a) => ByteString -> Maybe a
parseNum
(\x' :: Integer
x' -> Count
a { cSongs :: Integer
cSongs = Integer
x'}) Count
a ByteString
x
f a :: Count
a ("playtime", x :: ByteString
x) = Count -> Either String Count
forall (m :: * -> *) a. Monad m => a -> m a
return (Count -> Either String Count) -> Count -> Either String Count
forall a b. (a -> b) -> a -> b
$ (ByteString -> Maybe Integer)
-> (Integer -> Count) -> Count -> ByteString -> Count
forall a b.
(ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse ByteString -> Maybe Integer
forall a. (Read a, Integral a) => ByteString -> Maybe a
parseNum
(\x' :: Integer
x' -> Count
a { cPlaytime :: Integer
cPlaytime = Integer
x' }) Count
a ByteString
x
f _ x :: (ByteString, ByteString)
x = String -> Either String Count
forall a b. a -> Either a b
Left (String -> Either String Count) -> String -> Either String Count
forall a b. (a -> b) -> a -> b
$ (ByteString, ByteString) -> String
forall a. Show a => a -> String
show (ByteString, ByteString)
x
parseOutputs :: [ByteString] -> Either String [Device]
parseOutputs :: [ByteString] -> Either String [Device]
parseOutputs = ([(ByteString, ByteString)] -> Either String Device)
-> [[(ByteString, ByteString)]] -> Either String [Device]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM ((Device -> (ByteString, ByteString) -> Either String Device)
-> Device -> [(ByteString, ByteString)] -> Either String Device
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM Device -> (ByteString, ByteString) -> Either String Device
forall a.
(Eq a, IsString a, Show a) =>
Device -> (a, ByteString) -> Either String Device
f Device
forall a. Default a => a
def)
([[(ByteString, ByteString)]] -> Either String [Device])
-> ([ByteString] -> [[(ByteString, ByteString)]])
-> [ByteString]
-> Either String [Device]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString]
-> [(ByteString, ByteString)] -> [[(ByteString, ByteString)]]
splitGroups ["outputid"]
([(ByteString, ByteString)] -> [[(ByteString, ByteString)]])
-> ([ByteString] -> [(ByteString, ByteString)])
-> [ByteString]
-> [[(ByteString, ByteString)]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> [(ByteString, ByteString)]
toAssocList
where f :: Device -> (a, ByteString) -> Either String Device
f a :: Device
a ("outputid", x :: ByteString
x) = Device -> Either String Device
forall (m :: * -> *) a. Monad m => a -> m a
return (Device -> Either String Device) -> Device -> Either String Device
forall a b. (a -> b) -> a -> b
$ (ByteString -> Maybe Int)
-> (Int -> Device) -> Device -> ByteString -> Device
forall a b.
(ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse ByteString -> Maybe Int
forall a. (Read a, Integral a) => ByteString -> Maybe a
parseNum
(\x' :: Int
x' -> Device
a { dOutputID :: Int
dOutputID = Int
x' }) Device
a ByteString
x
f a :: Device
a ("outputname", x :: ByteString
x) = Device -> Either String Device
forall (m :: * -> *) a. Monad m => a -> m a
return Device
a { dOutputName :: String
dOutputName = ByteString -> String
UTF8.toString ByteString
x }
f a :: Device
a ("outputenabled", x :: ByteString
x) = Device -> Either String Device
forall (m :: * -> *) a. Monad m => a -> m a
return (Device -> Either String Device) -> Device -> Either String Device
forall a b. (a -> b) -> a -> b
$ (ByteString -> Maybe Bool)
-> (Bool -> Device) -> Device -> ByteString -> Device
forall a b.
(ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse ByteString -> Maybe Bool
parseBool
(\x' :: Bool
x' -> Device
a { dOutputEnabled :: Bool
dOutputEnabled = Bool
x'}) Device
a ByteString
x
f _ x :: (a, ByteString)
x = String -> Either String Device
forall a b. a -> Either a b
Left (String -> Either String Device) -> String -> Either String Device
forall a b. (a -> b) -> a -> b
$ (a, ByteString) -> String
forall a. Show a => a -> String
show (a, ByteString)
x
parseStats :: [ByteString] -> Either String Stats
parseStats :: [ByteString] -> Either String Stats
parseStats = (Stats -> (ByteString, ByteString) -> Either String Stats)
-> Stats -> [(ByteString, ByteString)] -> Either String Stats
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM Stats -> (ByteString, ByteString) -> Either String Stats
forall a.
(Eq a, IsString a, Show a) =>
Stats -> (a, ByteString) -> Either String Stats
f Stats
forall a. Default a => a
def ([(ByteString, ByteString)] -> Either String Stats)
-> ([ByteString] -> [(ByteString, ByteString)])
-> [ByteString]
-> Either String Stats
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> [(ByteString, ByteString)]
toAssocList
where
f :: Stats -> (a, ByteString) -> Either String Stats
f a :: Stats
a ("artists", x :: ByteString
x) = Stats -> Either String Stats
forall (m :: * -> *) a. Monad m => a -> m a
return (Stats -> Either String Stats) -> Stats -> Either String Stats
forall a b. (a -> b) -> a -> b
$ (ByteString -> Maybe Integer)
-> (Integer -> Stats) -> Stats -> ByteString -> Stats
forall a b.
(ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse ByteString -> Maybe Integer
forall a. (Read a, Integral a) => ByteString -> Maybe a
parseNum
(\x' :: Integer
x' -> Stats
a { stsArtists :: Integer
stsArtists = Integer
x' }) Stats
a ByteString
x
f a :: Stats
a ("albums", x :: ByteString
x) = Stats -> Either String Stats
forall (m :: * -> *) a. Monad m => a -> m a
return (Stats -> Either String Stats) -> Stats -> Either String Stats
forall a b. (a -> b) -> a -> b
$ (ByteString -> Maybe Integer)
-> (Integer -> Stats) -> Stats -> ByteString -> Stats
forall a b.
(ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse ByteString -> Maybe Integer
forall a. (Read a, Integral a) => ByteString -> Maybe a
parseNum
(\x' :: Integer
x' -> Stats
a { stsAlbums :: Integer
stsAlbums = Integer
x' }) Stats
a ByteString
x
f a :: Stats
a ("songs", x :: ByteString
x) = Stats -> Either String Stats
forall (m :: * -> *) a. Monad m => a -> m a
return (Stats -> Either String Stats) -> Stats -> Either String Stats
forall a b. (a -> b) -> a -> b
$ (ByteString -> Maybe Integer)
-> (Integer -> Stats) -> Stats -> ByteString -> Stats
forall a b.
(ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse ByteString -> Maybe Integer
forall a. (Read a, Integral a) => ByteString -> Maybe a
parseNum
(\x' :: Integer
x' -> Stats
a { stsSongs :: Integer
stsSongs = Integer
x' }) Stats
a ByteString
x
f a :: Stats
a ("uptime", x :: ByteString
x) = Stats -> Either String Stats
forall (m :: * -> *) a. Monad m => a -> m a
return (Stats -> Either String Stats) -> Stats -> Either String Stats
forall a b. (a -> b) -> a -> b
$ (ByteString -> Maybe Integer)
-> (Integer -> Stats) -> Stats -> ByteString -> Stats
forall a b.
(ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse ByteString -> Maybe Integer
forall a. (Read a, Integral a) => ByteString -> Maybe a
parseNum
(\x' :: Integer
x' -> Stats
a { stsUptime :: Integer
stsUptime = Integer
x' }) Stats
a ByteString
x
f a :: Stats
a ("playtime", x :: ByteString
x) = Stats -> Either String Stats
forall (m :: * -> *) a. Monad m => a -> m a
return (Stats -> Either String Stats) -> Stats -> Either String Stats
forall a b. (a -> b) -> a -> b
$ (ByteString -> Maybe Integer)
-> (Integer -> Stats) -> Stats -> ByteString -> Stats
forall a b.
(ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse ByteString -> Maybe Integer
forall a. (Read a, Integral a) => ByteString -> Maybe a
parseNum
(\x' :: Integer
x' -> Stats
a { stsPlaytime :: Integer
stsPlaytime = Integer
x' }) Stats
a ByteString
x
f a :: Stats
a ("db_playtime", x :: ByteString
x) = Stats -> Either String Stats
forall (m :: * -> *) a. Monad m => a -> m a
return (Stats -> Either String Stats) -> Stats -> Either String Stats
forall a b. (a -> b) -> a -> b
$ (ByteString -> Maybe Integer)
-> (Integer -> Stats) -> Stats -> ByteString -> Stats
forall a b.
(ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse ByteString -> Maybe Integer
forall a. (Read a, Integral a) => ByteString -> Maybe a
parseNum
(\x' :: Integer
x' -> Stats
a { stsDbPlaytime :: Integer
stsDbPlaytime = Integer
x' }) Stats
a ByteString
x
f a :: Stats
a ("db_update", x :: ByteString
x) = Stats -> Either String Stats
forall (m :: * -> *) a. Monad m => a -> m a
return (Stats -> Either String Stats) -> Stats -> Either String Stats
forall a b. (a -> b) -> a -> b
$ (ByteString -> Maybe Integer)
-> (Integer -> Stats) -> Stats -> ByteString -> Stats
forall a b.
(ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse ByteString -> Maybe Integer
forall a. (Read a, Integral a) => ByteString -> Maybe a
parseNum
(\x' :: Integer
x' -> Stats
a { stsDbUpdate :: Integer
stsDbUpdate = Integer
x' }) Stats
a ByteString
x
f _ x :: (a, ByteString)
x = String -> Either String Stats
forall a b. a -> Either a b
Left (String -> Either String Stats) -> String -> Either String Stats
forall a b. (a -> b) -> a -> b
$ (a, ByteString) -> String
forall a. Show a => a -> String
show (a, ByteString)
x
parseMaybeSong :: [ByteString] -> Either String (Maybe Song)
parseMaybeSong :: [ByteString] -> Either String (Maybe Song)
parseMaybeSong xs :: [ByteString]
xs | [ByteString] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [ByteString]
xs = Maybe Song -> Either String (Maybe Song)
forall a b. b -> Either a b
Right Maybe Song
forall a. Maybe a
Nothing
| Bool
otherwise = Song -> Maybe Song
forall a. a -> Maybe a
Just (Song -> Maybe Song)
-> Either String Song -> Either String (Maybe Song)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ([(ByteString, ByteString)] -> Either String Song
parseSong ([(ByteString, ByteString)] -> Either String Song)
-> ([ByteString] -> [(ByteString, ByteString)])
-> [ByteString]
-> Either String Song
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> [(ByteString, ByteString)]
toAssocList) [ByteString]
xs
parseSong :: [(ByteString, ByteString)] -> Either String Song
parseSong :: [(ByteString, ByteString)] -> Either String Song
parseSong xs :: [(ByteString, ByteString)]
xs = case [(ByteString, ByteString)]
xs of
("file", path :: ByteString
path):ys :: [(ByteString, ByteString)]
ys -> (Song -> (ByteString, ByteString) -> Either String Song)
-> Song -> [(ByteString, ByteString)] -> Either String Song
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM Song -> (ByteString, ByteString) -> Either String Song
f (Path -> Song
defaultSong (ByteString -> Path
Path ByteString
path)) [(ByteString, ByteString)]
ys
_ -> String -> Either String Song
forall a b. a -> Either a b
Left "Got a song without a file path! This indicates a bug in either libmpd-haskell or MPD itself!"
where
f :: Song -> (ByteString, ByteString) -> Either String Song
f :: Song -> (ByteString, ByteString) -> Either String Song
f s :: Song
s ("Last-Modified", v :: ByteString
v) =
Song -> Either String Song
forall (m :: * -> *) a. Monad m => a -> m a
return Song
s { sgLastModified :: Maybe UTCTime
sgLastModified = ByteString -> Maybe UTCTime
forall t. ParseTime t => ByteString -> Maybe t
parseIso8601 ByteString
v }
f s :: Song
s ("Time", v :: ByteString
v) =
Song -> Either String Song
forall (m :: * -> *) a. Monad m => a -> m a
return Song
s { sgLength :: Integer
sgLength = Integer -> Maybe Integer -> Integer
forall a. a -> Maybe a -> a
fromMaybe 0 (Maybe Integer -> Integer) -> Maybe Integer -> Integer
forall a b. (a -> b) -> a -> b
$ ByteString -> Maybe Integer
forall a. (Read a, Integral a) => ByteString -> Maybe a
parseNum ByteString
v }
f s :: Song
s ("Id", v :: ByteString
v) =
Song -> Either String Song
forall (m :: * -> *) a. Monad m => a -> m a
return (Song -> Either String Song) -> Song -> Either String Song
forall a b. (a -> b) -> a -> b
$ (ByteString -> Maybe Int)
-> (Int -> Song) -> Song -> ByteString -> Song
forall a b.
(ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse ByteString -> Maybe Int
forall a. (Read a, Integral a) => ByteString -> Maybe a
parseNum (\v' :: Int
v' -> Song
s { sgId :: Maybe Id
sgId = Id -> Maybe Id
forall a. a -> Maybe a
Just (Id -> Maybe Id) -> Id -> Maybe Id
forall a b. (a -> b) -> a -> b
$ Int -> Id
Id Int
v' }) Song
s ByteString
v
f s :: Song
s ("Pos", v :: ByteString
v) =
Either String Song
-> (Int -> Either String Song) -> Maybe Int -> Either String Song
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Song -> Either String Song
forall (m :: * -> *) a. Monad m => a -> m a
return (Song -> Either String Song) -> Song -> Either String Song
forall a b. (a -> b) -> a -> b
$ (ByteString -> Maybe Int)
-> (Int -> Song) -> Song -> ByteString -> Song
forall a b.
(ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse ByteString -> Maybe Int
forall a. (Read a, Integral a) => ByteString -> Maybe a
parseNum
(\v' :: Int
v' -> Song
s { sgIndex :: Maybe Int
sgIndex = Int -> Maybe Int
forall a. a -> Maybe a
Just Int
v' }) Song
s ByteString
v)
(Either String Song -> Int -> Either String Song
forall a b. a -> b -> a
const (Either String Song -> Int -> Either String Song)
-> Either String Song -> Int -> Either String Song
forall a b. (a -> b) -> a -> b
$ Song -> Either String Song
forall (m :: * -> *) a. Monad m => a -> m a
return Song
s)
(Song -> Maybe Int
sgIndex Song
s)
f s :: Song
s (k :: ByteString
k, v :: ByteString
v) = Song -> Either String Song
forall (m :: * -> *) a. Monad m => a -> m a
return (Song -> Either String Song)
-> (Maybe Metadata -> Song) -> Maybe Metadata -> Either String Song
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Song -> (Metadata -> Song) -> Maybe Metadata -> Song
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Song
s (\m :: Metadata
m -> Metadata -> Value -> Song -> Song
sgAddTag Metadata
m (ByteString -> Value
Value ByteString
v) Song
s) (Maybe Metadata -> Either String Song)
-> Maybe Metadata -> Either String Song
forall a b. (a -> b) -> a -> b
$
ByteString -> Maybe Metadata
forall a. (Eq a, IsString a) => a -> Maybe Metadata
readMeta ByteString
k
readMeta :: a -> Maybe Metadata
readMeta "ArtistSort" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
ArtistSort
readMeta "Artist" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Artist
readMeta "Album" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Album
readMeta "AlbumArtist" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
AlbumArtist
readMeta "AlbumArtistSort" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
AlbumArtistSort
readMeta "Title" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Title
readMeta "Genre" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Genre
readMeta "Name" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Name
readMeta "Composer" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Composer
readMeta "Performer" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Performer
readMeta "Comment" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Comment
readMeta "Date" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Date
readMeta "Track" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Track
readMeta "Disc" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Disc
readMeta "MUSICBRAINZ_ARTISTID" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
MUSICBRAINZ_ARTISTID
readMeta "MUSICBRAINZ_ALBUMID" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
MUSICBRAINZ_ALBUMID
readMeta "MUSICBRAINZ_ALBUMARTISTID" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
MUSICBRAINZ_ALBUMARTISTID
readMeta "MUSICBRAINZ_TRACKID" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
MUSICBRAINZ_TRACKID
readMeta "MUSICBRAINZ_RELEASETRACKID" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
MUSICBRAINZ_RELEASETRACKID
readMeta _ = Maybe Metadata
forall a. Maybe a
Nothing
parse :: (ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse :: (ByteString -> Maybe a) -> (a -> b) -> b -> ByteString -> b
parse parser :: ByteString -> Maybe a
parser f :: a -> b
f x :: b
x = b -> (a -> b) -> Maybe a -> b
forall b a. b -> (a -> b) -> Maybe a -> b
maybe b
x a -> b
f (Maybe a -> b) -> (ByteString -> Maybe a) -> ByteString -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Maybe a
parser
pair :: (ByteString -> Maybe a) -> (ByteString, ByteString) -> Maybe (a, a)
pair :: (ByteString -> Maybe a) -> (ByteString, ByteString) -> Maybe (a, a)
pair p :: ByteString -> Maybe a
p (x :: ByteString
x, y :: ByteString
y) = case (ByteString -> Maybe a
p ByteString
x, ByteString -> Maybe a
p ByteString
y) of
(Just a :: a
a, Just b :: a
b) -> (a, a) -> Maybe (a, a)
forall a. a -> Maybe a
Just (a
a, a
b)
_ -> Maybe (a, a)
forall a. Maybe a
Nothing