{-# LANGUAGE FlexibleContexts, OverloadedStrings #-}
module Network.MPD.Commands.Parse where
import Network.MPD.Commands.Types
import Control.Monad.Except
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 Count
a (ByteString
"songs", 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
(\Integer
x' -> Count
a { cSongs :: Integer
cSongs = Integer
x'}) Count
a ByteString
x
f Count
a (ByteString
"playtime", 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
(\Integer
x' -> Count
a { cPlaytime :: Integer
cPlaytime = Integer
x' }) Count
a ByteString
x
f Count
_ (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 [ByteString
"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 Device
a (a
"outputid", 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
(\Int
x' -> Device
a { dOutputID :: Int
dOutputID = Int
x' }) Device
a ByteString
x
f Device
a (a
"outputname", 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 Device
a (a
"outputenabled", 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
(\Bool
x' -> Device
a { dOutputEnabled :: Bool
dOutputEnabled = Bool
x'}) Device
a ByteString
x
f Device
_ (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 Stats
a (a
"artists", 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
(\Integer
x' -> Stats
a { stsArtists :: Integer
stsArtists = Integer
x' }) Stats
a ByteString
x
f Stats
a (a
"albums", 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
(\Integer
x' -> Stats
a { stsAlbums :: Integer
stsAlbums = Integer
x' }) Stats
a ByteString
x
f Stats
a (a
"songs", 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
(\Integer
x' -> Stats
a { stsSongs :: Integer
stsSongs = Integer
x' }) Stats
a ByteString
x
f Stats
a (a
"uptime", 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
(\Integer
x' -> Stats
a { stsUptime :: Integer
stsUptime = Integer
x' }) Stats
a ByteString
x
f Stats
a (a
"playtime", 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
(\Integer
x' -> Stats
a { stsPlaytime :: Integer
stsPlaytime = Integer
x' }) Stats
a ByteString
x
f Stats
a (a
"db_playtime", 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
(\Integer
x' -> Stats
a { stsDbPlaytime :: Integer
stsDbPlaytime = Integer
x' }) Stats
a ByteString
x
f Stats
a (a
"db_update", 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
(\Integer
x' -> Stats
a { stsDbUpdate :: Integer
stsDbUpdate = Integer
x' }) Stats
a ByteString
x
f Stats
_ (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 [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 [(ByteString, ByteString)]
xs = case [(ByteString, ByteString)]
xs of
(ByteString
"file", ByteString
path):[(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
[(ByteString, ByteString)]
_ -> String -> Either String Song
forall a b. a -> Either a b
Left String
"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 Song
s (ByteString
"Last-Modified", 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 Song
s (ByteString
"Time", 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 Integer
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 Song
s (ByteString
"Id", 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 (\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 Song
s (ByteString
"Pos", 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
(\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 Song
s (ByteString
k, 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 (\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 a
"Artist" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Artist
readMeta a
"ArtistSort" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
ArtistSort
readMeta a
"Album" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Album
readMeta a
"AlbumSort" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
AlbumSort
readMeta a
"AlbumArtist" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
AlbumArtist
readMeta a
"AlbumArtistSort" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
AlbumArtistSort
readMeta a
"Title" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Title
readMeta a
"Track" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Track
readMeta a
"Name" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Name
readMeta a
"Genre" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Genre
readMeta a
"Date" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Date
readMeta a
"OriginalDate" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
OriginalDate
readMeta a
"Composer" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Composer
readMeta a
"Performer" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Performer
readMeta a
"Conductor" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Conductor
readMeta a
"Work" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Work
readMeta a
"Grouping" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Grouping
readMeta a
"Comment" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Comment
readMeta a
"Disc" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Disc
readMeta a
"Label" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
Label
readMeta a
"MUSICBRAINZ_ARTISTID" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
MUSICBRAINZ_ARTISTID
readMeta a
"MUSICBRAINZ_ALBUMID" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
MUSICBRAINZ_ALBUMID
readMeta a
"MUSICBRAINZ_ALBUMARTISTID" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
MUSICBRAINZ_ALBUMARTISTID
readMeta a
"MUSICBRAINZ_TRACKID" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
MUSICBRAINZ_TRACKID
readMeta a
"MUSICBRAINZ_RELEASETRACKID" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
MUSICBRAINZ_RELEASETRACKID
readMeta a
"MUSICBRAINZ_WORKID" = Metadata -> Maybe Metadata
forall a. a -> Maybe a
Just Metadata
MUSICBRAINZ_WORKID
readMeta a
_ = 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 ByteString -> Maybe a
parser a -> b
f 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 ByteString -> Maybe a
p (ByteString
x, ByteString
y) = case (ByteString -> Maybe a
p ByteString
x, ByteString -> Maybe a
p ByteString
y) of
(Just a
a, Just a
b) -> (a, a) -> Maybe (a, a)
forall a. a -> Maybe a
Just (a
a, a
b)
(Maybe a, Maybe a)
_ -> Maybe (a, a)
forall a. Maybe a
Nothing