{-# LANGUAGE NoMonoLocalBinds #-}
{-# LANGUAGE FlexibleContexts #-}
module System.Taffybar.Information.MPRIS2 where
import Control.Applicative
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Control.Monad.Trans.Except
import Control.Monad.Trans.Maybe
import qualified DBus
import qualified DBus.Client as DBus
import qualified DBus.Internal.Types as DBus
import qualified DBus.TH as DBus
import Data.Coerce
import Data.List
import qualified Data.Map as M
import Data.Maybe
import System.Log.Logger
import System.Taffybar.DBus.Client.MPRIS2
import Text.Printf
data NowPlaying = NowPlaying
{ NowPlaying -> String
npTitle :: String
, NowPlaying -> [String]
npArtists :: [String]
, NowPlaying -> String
npStatus :: String
, NowPlaying -> BusName
npBusName :: DBus.BusName
} deriving (Int -> NowPlaying -> ShowS
[NowPlaying] -> ShowS
NowPlaying -> String
(Int -> NowPlaying -> ShowS)
-> (NowPlaying -> String)
-> ([NowPlaying] -> ShowS)
-> Show NowPlaying
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> NowPlaying -> ShowS
showsPrec :: Int -> NowPlaying -> ShowS
$cshow :: NowPlaying -> String
show :: NowPlaying -> String
$cshowList :: [NowPlaying] -> ShowS
showList :: [NowPlaying] -> ShowS
Show, NowPlaying -> NowPlaying -> Bool
(NowPlaying -> NowPlaying -> Bool)
-> (NowPlaying -> NowPlaying -> Bool) -> Eq NowPlaying
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: NowPlaying -> NowPlaying -> Bool
== :: NowPlaying -> NowPlaying -> Bool
$c/= :: NowPlaying -> NowPlaying -> Bool
/= :: NowPlaying -> NowPlaying -> Bool
Eq)
eitherToMaybeWithLog :: (MonadIO m, Show a1) => Either a1 a2 -> m (Maybe a2)
eitherToMaybeWithLog :: forall (m :: * -> *) a1 a2.
(MonadIO m, Show a1) =>
Either a1 a2 -> m (Maybe a2)
eitherToMaybeWithLog (Right a2
v) = Maybe a2 -> m (Maybe a2)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe a2 -> m (Maybe a2)) -> Maybe a2 -> m (Maybe a2)
forall a b. (a -> b) -> a -> b
$ a2 -> Maybe a2
forall a. a -> Maybe a
Just a2
v
eitherToMaybeWithLog (Left a1
e) = IO (Maybe a2) -> m (Maybe a2)
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Maybe a2) -> m (Maybe a2)) -> IO (Maybe a2) -> m (Maybe a2)
forall a b. (a -> b) -> a -> b
$ do
String -> Priority -> String -> IO ()
logM String
"System.Taffybar.Information.MPRIS2" Priority
WARNING (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
String -> ShowS
forall r. PrintfType r => String -> r
printf String
"Got error: %s" ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$ a1 -> String
forall a. Show a => a -> String
show a1
e
Maybe a2 -> IO (Maybe a2)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe a2
forall a. Maybe a
Nothing
getNowPlayingInfo :: MonadIO m => DBus.Client -> m [NowPlaying]
getNowPlayingInfo :: forall (m :: * -> *). MonadIO m => Client -> m [NowPlaying]
getNowPlayingInfo Client
client =
(Maybe [NowPlaying] -> [NowPlaying])
-> m (Maybe [NowPlaying]) -> m [NowPlaying]
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ([NowPlaying] -> Maybe [NowPlaying] -> [NowPlaying]
forall a. a -> Maybe a -> a
fromMaybe []) (m (Maybe [NowPlaying]) -> m [NowPlaying])
-> m (Maybe [NowPlaying]) -> m [NowPlaying]
forall a b. (a -> b) -> a -> b
$ Either MethodError [NowPlaying] -> m (Maybe [NowPlaying])
forall (m :: * -> *) a1 a2.
(MonadIO m, Show a1) =>
Either a1 a2 -> m (Maybe a2)
eitherToMaybeWithLog (Either MethodError [NowPlaying] -> m (Maybe [NowPlaying]))
-> m (Either MethodError [NowPlaying]) -> m (Maybe [NowPlaying])
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO (Either MethodError [NowPlaying])
-> m (Either MethodError [NowPlaying])
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (ExceptT MethodError IO [NowPlaying]
-> IO (Either MethodError [NowPlaying])
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (ExceptT MethodError IO [NowPlaying]
-> IO (Either MethodError [NowPlaying]))
-> ExceptT MethodError IO [NowPlaying]
-> IO (Either MethodError [NowPlaying])
forall a b. (a -> b) -> a -> b
$ do
[String]
allBusNames <- IO (Either MethodError [String]) -> ExceptT MethodError IO [String]
forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT (IO (Either MethodError [String])
-> ExceptT MethodError IO [String])
-> IO (Either MethodError [String])
-> ExceptT MethodError IO [String]
forall a b. (a -> b) -> a -> b
$ Client -> IO (Either MethodError [String])
DBus.listNames Client
client
let mediaPlayerBusNames :: [String]
mediaPlayerBusNames =
(String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
isPrefixOf String
"org.mpris.MediaPlayer2.") [String]
allBusNames
getSongData :: p -> IO (Maybe NowPlaying)
getSongData p
_busName = MaybeT IO NowPlaying -> IO (Maybe NowPlaying)
forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
runMaybeT (MaybeT IO NowPlaying -> IO (Maybe NowPlaying))
-> MaybeT IO NowPlaying -> IO (Maybe NowPlaying)
forall a b. (a -> b) -> a -> b
$
do
let busName :: BusName
busName = p -> BusName
forall a b. Coercible a b => a -> b
coerce p
_busName
Map String Variant
metadataMap <-
IO (Maybe (Map String Variant)) -> MaybeT IO (Map String Variant)
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT (IO (Maybe (Map String Variant)) -> MaybeT IO (Map String Variant))
-> IO (Maybe (Map String Variant))
-> MaybeT IO (Map String Variant)
forall a b. (a -> b) -> a -> b
$ Client -> BusName -> IO (Either MethodError (Map String Variant))
getMetadata Client
client BusName
busName IO (Either MethodError (Map String Variant))
-> (Either MethodError (Map String Variant)
-> IO (Maybe (Map String Variant)))
-> IO (Maybe (Map String Variant))
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either MethodError (Map String Variant)
-> IO (Maybe (Map String Variant))
forall (m :: * -> *) a1 a2.
(MonadIO m, Show a1) =>
Either a1 a2 -> m (Maybe a2)
eitherToMaybeWithLog
(String
title, [String]
artists) <- IO (Maybe (String, [String])) -> MaybeT IO (String, [String])
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT (IO (Maybe (String, [String])) -> MaybeT IO (String, [String]))
-> IO (Maybe (String, [String])) -> MaybeT IO (String, [String])
forall a b. (a -> b) -> a -> b
$ Maybe (String, [String]) -> IO (Maybe (String, [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (String, [String]) -> IO (Maybe (String, [String])))
-> Maybe (String, [String]) -> IO (Maybe (String, [String]))
forall a b. (a -> b) -> a -> b
$ Map String Variant -> Maybe (String, [String])
getSongInfo Map String Variant
metadataMap
String
status <- IO (Maybe String) -> MaybeT IO String
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT (IO (Maybe String) -> MaybeT IO String)
-> IO (Maybe String) -> MaybeT IO String
forall a b. (a -> b) -> a -> b
$ Client -> BusName -> IO (Either MethodError String)
getPlaybackStatus Client
client BusName
busName IO (Either MethodError String)
-> (Either MethodError String -> IO (Maybe String))
-> IO (Maybe String)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
Either MethodError String -> IO (Maybe String)
forall (m :: * -> *) a1 a2.
(MonadIO m, Show a1) =>
Either a1 a2 -> m (Maybe a2)
eitherToMaybeWithLog
NowPlaying -> MaybeT IO NowPlaying
forall a. a -> MaybeT IO a
forall (m :: * -> *) a. Monad m => a -> m a
return NowPlaying { npTitle :: String
npTitle = String
title
, npArtists :: [String]
npArtists = [String]
artists
, npStatus :: String
npStatus = String
status
, npBusName :: BusName
npBusName = BusName
busName
}
IO [NowPlaying] -> ExceptT MethodError IO [NowPlaying]
forall (m :: * -> *) a. Monad m => m a -> ExceptT MethodError m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO [NowPlaying] -> ExceptT MethodError IO [NowPlaying])
-> IO [NowPlaying] -> ExceptT MethodError IO [NowPlaying]
forall a b. (a -> b) -> a -> b
$ [Maybe NowPlaying] -> [NowPlaying]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe NowPlaying] -> [NowPlaying])
-> IO [Maybe NowPlaying] -> IO [NowPlaying]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (String -> IO (Maybe NowPlaying))
-> [String] -> IO [Maybe NowPlaying]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM String -> IO (Maybe NowPlaying)
forall {p}. Coercible p String => p -> IO (Maybe NowPlaying)
getSongData [String]
mediaPlayerBusNames)
getSongInfo :: M.Map String DBus.Variant -> Maybe (String, [String])
getSongInfo :: Map String Variant -> Maybe (String, [String])
getSongInfo Map String Variant
songData = do
let lookupVariant :: String -> Maybe b
lookupVariant String
k = String -> Map String Variant -> Maybe Variant
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup String
k Map String Variant
songData Maybe Variant -> (Variant -> Maybe b) -> Maybe b
forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Variant -> Maybe b
forall a. IsVariant a => Variant -> Maybe a
DBus.fromVariant
[String]
artists <- String -> Maybe [String]
forall {b}. IsVariant b => String -> Maybe b
lookupVariant String
"xesam:artist" Maybe [String] -> Maybe [String] -> Maybe [String]
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> [String] -> Maybe [String]
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
String
title <- String -> Maybe String
forall {b}. IsVariant b => String -> Maybe b
lookupVariant String
"xesam:title"
(String, [String]) -> Maybe (String, [String])
forall a. a -> Maybe a
forall (m :: * -> *) a. Monad m => a -> m a
return (String
title, [String]
artists)