summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/Plugins/Monitors.hs15
-rw-r--r--src/Plugins/Monitors/Mpris.hs129
-rw-r--r--xmobar.cabal9
3 files changed, 153 insertions, 0 deletions
diff --git a/src/Plugins/Monitors.hs b/src/Plugins/Monitors.hs
index 5e1cb62..9f17699 100644
--- a/src/Plugins/Monitors.hs
+++ b/src/Plugins/Monitors.hs
@@ -44,6 +44,9 @@ import Plugins.Monitors.MPD
#ifdef ALSA
import Plugins.Monitors.Volume
#endif
+#ifdef MPRIS
+import Plugins.Monitors.Mpris
+#endif
data Monitors = Weather Station Args Rate
| Network Interface Args Rate
@@ -72,6 +75,10 @@ data Monitors = Weather Station Args Rate
#ifdef ALSA
| Volume String String Args Rate
#endif
+#ifdef MPRIS
+ | Mpris1 String Args Rate
+ | Mpris2 String Args Rate
+#endif
deriving (Show,Read,Eq)
type Args = [String]
@@ -112,6 +119,10 @@ instance Exec Monitors where
#ifdef ALSA
alias (Volume m c _ _) = m ++ ":" ++ c
#endif
+#ifdef MPRIS
+ alias (Mpris1 _ _ _) = "mpris1"
+ alias (Mpris2 _ _ _) = "mpris2"
+#endif
start (Network i a r) = startNet i a r
start (Cpu a r) = startCpu a r
start (MultiCpu a r) = startMultiCpu a r
@@ -140,3 +151,7 @@ instance Exec Monitors where
#ifdef ALSA
start (Volume m c a r) = runM a volumeConfig (runVolume m c) r
#endif
+#ifdef MPRIS
+ start (Mpris1 s a r) = runM a mprisConfig (runMPRIS1 s) r
+ start (Mpris2 s a r) = runM a mprisConfig (runMPRIS2 s) r
+#endif
diff --git a/src/Plugins/Monitors/Mpris.hs b/src/Plugins/Monitors/Mpris.hs
new file mode 100644
index 0000000..32f72d4
--- /dev/null
+++ b/src/Plugins/Monitors/Mpris.hs
@@ -0,0 +1,129 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+----------------------------------------------------------------------------
+-- |
+-- Module : Plugins.Monitors.Mpris
+-- Copyright : (c) Artem Tarasov
+-- License : BSD-style (see LICENSE)
+--
+-- Maintainer : Artem Tarasov <lomereiter@gmail.com>
+-- Stability : unstable
+-- Portability : unportable
+--
+-- MPRIS song info
+--
+----------------------------------------------------------------------------
+
+module Plugins.Monitors.Mpris ( mprisConfig, runMPRIS1, runMPRIS2 ) where
+
+-- TODO: listen to signals
+
+import Plugins.Monitors.Common
+
+import Text.Printf (printf)
+import qualified DBus.Client.Simple as C
+import DBus.Types
+import DBus.Connection ( ConnectionError )
+import Data.Maybe ( fromJust )
+import Data.Int ( Int32, Int64 )
+import System.IO.Unsafe (unsafePerformIO)
+import qualified Data.Text as T
+
+import Control.Exception (try, evaluate)
+
+class MprisVersion a where
+ getProxy :: a -> C.Client -> String -> IO C.Proxy
+ getMetadataReply :: a -> C.Client -> String -> IO [Variant]
+ fieldsList :: a -> [String]
+
+data MprisVersion1 = MprisVersion1
+instance MprisVersion MprisVersion1 where
+ getProxy MprisVersion1 c p = do
+ let playerBusName = T.concat ["org.mpris.", T.pack p]
+ C.proxy c (C.busName_ playerBusName) "/Player"
+ getMetadataReply MprisVersion1 c p = do
+ player <- getProxy MprisVersion1 c p
+ C.call player "org.freedesktop.MediaPlayer" "GetMetadata" []
+ fieldsList MprisVersion1 = [ "album", "artist", "arturl", "time", "title", "tracknumber" ]
+
+data MprisVersion2 = MprisVersion2
+instance MprisVersion MprisVersion2 where
+ getProxy MprisVersion2 c p = do
+ let playerBusName = T.concat ["org.mpris.MediaPlayer2.", T.pack p]
+ C.proxy c (C.busName_ playerBusName) "/org/mpris/MediaPlayer2"
+ getMetadataReply MprisVersion2 c p = do
+ player <- getProxy MprisVersion2 c p
+ C.call player "org.freedesktop.DBus.Properties"
+ "Get"
+ (map (toVariant::String -> Variant)
+ ["org.mpris.MediaPlayer2.Player", "Metadata"]
+ )
+ fieldsList MprisVersion2 = [ "xesam:album", "xesam:artist", "mpris:artUrl"
+ , "mpris:length", "xesam:title", "xesam:trackNumber"
+ ]
+
+mprisConfig :: IO MConfig
+mprisConfig = mkMConfig "<artist> - <title>"
+ [ "album", "artist", "arturl", "length" , "title", "tracknumber"
+ ]
+
+dbusClient :: C.Client
+dbusClient = unsafePerformIO C.connectSession
+
+runMPRIS :: (MprisVersion a) => a -> String -> [String] -> Monitor String
+runMPRIS version playerName _ = do
+ metadata <- io $ getMetadata version dbusClient playerName
+ parseTemplate $ makeList version metadata
+
+runMPRIS1 :: String -> [String] -> Monitor String
+runMPRIS1 = runMPRIS MprisVersion1
+
+runMPRIS2 :: String -> [String] -> Monitor String
+runMPRIS2 = runMPRIS MprisVersion2
+
+---------------------------------------------------------------------------
+
+fromVar :: (IsVariant a) => Variant -> a
+fromVar = fromJust . fromVariant
+
+unpackMetadata :: [Variant] -> [(String, Variant)]
+unpackMetadata [] = []
+unpackMetadata xs = ((map (\(k, v) -> (fromVar k, fromVar v))) . unpack . head) xs where
+ unpack v = case variantType v of
+ TypeDictionary _ _ -> dictionaryItems $ fromVar v
+ TypeVariant -> unpack $ fromVar v
+ TypeStructure _ -> unpack $ head $ structureItems $ fromVar v
+ _ -> []
+
+getMetadata :: (MprisVersion a) => a -> C.Client -> String -> IO [(String, Variant)]
+getMetadata version client player = do
+ reply <- try (getMetadataReply version client player) ::
+ IO (Either ConnectionError [Variant])
+ return $ case reply of
+ Right metadata -> unpackMetadata metadata;
+ Left _ -> []
+
+makeList :: (MprisVersion a) => a -> [(String, Variant)] -> [String]
+makeList version md = map getStr (fieldsList version) where
+ formatTime n = (if hh == 0 then printf "%02d:%02d"
+ else printf "%d:%02d:%02d" hh) mm ss
+ where hh = (n `div` 60) `div` 60
+ mm = (n `div` 60) `mod` 60
+ ss = n `mod` 60
+ getStr str = case lookup str md of
+ Nothing -> ""
+ Just v -> case variantType v of
+ TypeString -> fromVar v
+ TypeInt32 -> let num = fromVar v in
+ case str of
+ "time" -> formatTime num
+ "tracknumber" -> printf "%02d" num
+ "mpris:length" -> formatTime (num `div` 1000000)
+ "xesam:trackNumber" -> printf "%02d" num
+ _ -> (show::Int32 -> String) num
+ TypeInt64 -> let num = fromVar v in
+ case str of
+ "mpris:length" -> formatTime (num `div` 1000000)
+ _ -> (show::Int64 -> String) num
+ TypeArray TypeString -> fromVar $ head $ arrayItems $ fromVar v
+ _ -> ""
diff --git a/xmobar.cabal b/xmobar.cabal
index 1f7b4db..ffd2cd7 100644
--- a/xmobar.cabal
+++ b/xmobar.cabal
@@ -61,6 +61,10 @@ flag with_datezone
description: Enables localized date support
default: False
+flag with_mpris
+ description: MPRIS v1, v2 support
+ default: False
+
executable xmobar
hs-source-dirs: src
main-is: Main.hs
@@ -150,3 +154,8 @@ executable xmobar
build-depends: timezone-olson == 0.1.*, timezone-series == 0.1.*
other-modules: Plugins.DateZone
cpp-options: -DDATEZONE
+
+ if flag(with_mpris) || flag(all_extensions)
+ build-depends: dbus-core >= 0.9.2.1, text >= 0.11.1.5 && < 0.12
+ other-modules: Plugins.Monitors.Mpris
+ cpp-options: -DMPRIS