content: {-# LANGUAGE NoMonoLocalBinds #-}
  {-# LANGUAGE FlexibleContexts #-}
  -----------------------------------------------------------------------------
  -- |
  -- Module      : System.Taffybar.Information.MPRIS2
  -- Copyright   : (c) Ivan A. Malison
  -- License     : BSD3-style (see LICENSE)
  --
  -- Maintainer  : Ivan A. Malison
  -- Stability   : unstable
  -- Portability : unportable
  --
  -----------------------------------------------------------------------------
  
  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
    { npTitle :: String
    , npArtists :: [String]
    , npStatus :: String
    , npBusName :: DBus.BusName
    } deriving (Show, Eq)
  
  eitherToMaybeWithLog :: (MonadIO m, Show a1) => Either a1 a2 -> m (Maybe a2)
  eitherToMaybeWithLog (Right v) = return $ Just v
  eitherToMaybeWithLog (Left e) = liftIO $ do
    logM "System.Taffybar.Information.MPRIS2" WARNING $
         printf "Got error: %s" $ show e
    return Nothing
  
  getNowPlayingInfo :: MonadIO m => DBus.Client -> m [NowPlaying]
  getNowPlayingInfo client =
    fmap (fromMaybe []) $ eitherToMaybeWithLog =<< liftIO (runExceptT $ do
      allBusNames <- ExceptT $ DBus.listNames client
      let mediaPlayerBusNames =
            filter (isPrefixOf "org.mpris.MediaPlayer2.") allBusNames
          getSongData _busName = runMaybeT $
            do
              let busName = coerce _busName
              metadataMap <-
                MaybeT $ getMetadata client busName >>= eitherToMaybeWithLog
              (title, artists) <- MaybeT $ return $ getSongInfo metadataMap
              status <- MaybeT $ getPlaybackStatus client busName >>=
                                 eitherToMaybeWithLog
              return NowPlaying { npTitle = title
                                , npArtists = artists
                                , npStatus = status
                                , npBusName = busName
                                }
      lift $ catMaybes <$> mapM getSongData mediaPlayerBusNames)
  
  getSongInfo :: M.Map String DBus.Variant -> Maybe (String, [String])
  getSongInfo songData = do
    let lookupVariant k = M.lookup k songData >>= DBus.fromVariant
    artists <- lookupVariant "xesam:artist" <|> pure []
    title <- lookupVariant "xesam:title"
    return (title, artists)
  