mpris-0.1.0.0: src/DBus/Mpris/Monad.hs
{-# LANGUAGE OverloadedStrings #-}
-- | Convenient monad for running MPRIS actions.
--
-- It is a 'StateT' on top of 'IO' which handles the connection and
-- caches available players as 'BusName' s.
--
-- It contains some useful functions to work with current player and
-- make MPRIS calls.
--
-- For example, to pause the playback on current player, you can do
--
-- > pauseCurrent :: Mpris ()
-- > pauseCurrent = current >>= pause
--
-- To evaluate a Mpris action use 'runMpris' which brings it back into 'IO', for example:
--
-- > main :: IO ()
-- > main = do
-- > let bus = busName_ "org.mpris.MediaPlayer2.mpd"
-- > runMpris $ pause bus
module DBus.Mpris.Monad
( Mpris
, State(..)
, current
, call
, call_
, runMpris
) where
import Control.Exception (bracket)
import Control.Monad (void)
import Control.Monad.State hiding (State)
import DBus
import qualified DBus.Client as D
-- | Internal state.
--
-- It holds the dbus 'client' which is used to make calls.
--
-- The list of 'players' works as a LRU stack, when a player changes
-- it is removed from the list and placed on top.
data State = State { client :: D.Client -- ^ The dbus client used to make the calls
, players :: [BusName] -- ^ List of available players-capable players as bus names
}
-- | Type wrapper for Mpris "monad".
type Mpris a = StateT State IO a
-- | Extract current player from the 'State'.
currentPlayer :: State -> BusName
currentPlayer = head . players
-- | Return current player
current :: Mpris BusName
current = gets currentPlayer
-- | Call a method call in context of current dbus client.
call :: MethodCall -> Mpris (Either MethodError MethodReturn)
call method = do
client <- gets client
liftIO $ D.call client method
-- | Like 'call' but ignores the result.
call_ :: MethodCall -> Mpris ()
call_ = void . call
-- | Run the 'Mpris' computation and return the result inside 'IO'.
runMpris :: Mpris a -> IO a
runMpris code = bracket
(do
client <- D.connectSession
return State { client = client, players = [busName_ "org.mpris.MediaPlayer2.mpd"] })
(\(State {client = client}) -> D.disconnect client)
(evalStateT code)