{- Copyright 2015-2017 Markus Ongyerth This file is part of Monky. Monky is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Monky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Monky. If not, see . -} {-# LANGUAGE OverloadedStrings #-} {-| Module : Monky.Examples.MPD Description : An example module instance for the MPD module Maintainer : ongy Stability : testing Portability : Linux -} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-} module Monky.Examples.MPD ( MPDHandle , getMPDHandle , getMPDHandleF ) where import Data.Text (Text) import qualified Data.Text as T import Data.IORef import System.IO (hPutStrLn, stderr) import System.Posix.Types (Fd) import Monky.MPD import Monky.Modules import Monky.Examples.Utility #if MIN_VERSION_base(4,8,0) #else import Control.Applicative ((<$>), pure, (<*>)) #endif type ConvertFun = (State, Maybe SongInfo) -> Text getSongTitle :: MPDSocket -> ConvertFun -> IO Text -- TODO: Clean this up a bit. Probably do notation? getSongTitle sock fun = (fmap state <$> getMPDStatus sock) >>= getSong where getSong (Left x) = return . T.pack $ x getSong (Right Playing) = do info <- getMPDSong sock case info of Right x -> pure $ fun (Playing, Just x) Left x -> pure $ T.pack x getSong (Right x) = pure $ fun (x, Nothing) -- |The handle for this example data MPDHandle = MPDHandle { _host :: String , _port :: String , _sock :: IORef (Maybe MPDSocket) , _convert :: ConvertFun } -- TODO ignoring errors is never a good idea getEvent :: MPDSocket -> ConvertFun -> IO Text getEvent s fun = do _ <- readOk s t <- getSongTitle s fun _ <- goIdle s " player" return t getFd :: MPDSocket -> IO [Fd] getFd s = do fd <- getMPDFd s _ <- goIdle s " player" return [fd] instance PollModule MPDHandle where getOutput (MPDHandle _ _ s f) = do r <- readIORef s case r of Nothing -> return [MonkyPlain "Broken"] (Just x) -> do ret <- getSongTitle x f return [MonkyPlain ret] initialize (MPDHandle h p r _) = do s <- getMPDSocket h p case s of (Right x) -> writeIORef r (Just x) (Left _) -> return () instance EvtModule MPDHandle where startEvtLoop h@(MPDHandle _ _ s f) fun = do initialize h fun =<< getOutput h r <- readIORef s case r of Nothing -> hPutStrLn stderr "Could not initialize MPDHandle :(" (Just x) -> do [fd] <- getFd x loopFd x fd fun (fmap (\y -> [MonkyPlain y]) . flip getEvent f) defaultConvert :: (State, Maybe SongInfo) -> Text defaultConvert (Playing, Just x) = case tagTitle . songTags $ x of Nothing -> "Can't extract song title" Just y -> y defaultConvert (Playing, Nothing) = "Can't extract song" defaultConvert _ = "Not Playing" -- |Get an 'MPDHandle' (server has to be running when this is executed) getMPDHandle :: String -- ^The host to connect to -> String -- ^The port to connect to -> IO MPDHandle getMPDHandle h p = MPDHandle h p <$> newIORef Nothing <*> pure defaultConvert -- | Get the 'MPDHandle' with a custom conversion function. You will need to -- import `Monky.MPD` to get the definitions into scope getMPDHandleF :: String -- ^The host to connect to -> String -- ^The port to connect to -> ConvertFun -- ^The function to extract the text -> IO MPDHandle getMPDHandleF h p f = MPDHandle h p <$> newIORef Nothing <*> pure f