{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeFamilies #-} -- | A generic interface to online radio services module Radio ( SongMeta(..) , Radio(..) , getLordDir , getPidFile , getLogFile , getStateFile , writeLog ) where import Codec.Binary.UTF8.String (encodeString) import Control.Applicative ((<$>)) import Control.Concurrent.MVar import Control.Monad (when) import Data.Aeson (FromJSON, Value) import qualified Data.ByteString.Char8 as C import Network.MPD hiding (play, Value) import qualified Network.MPD as MPD import System.Directory (getHomeDirectory) import System.IO.Unsafe (unsafePerformIO) import System.Log.FastLogger eof = unsafePerformIO newEmptyMVar data SongMeta = SongMeta { artist :: String , album :: String , title :: String } class FromJSON a => Radio a where data Param a :: * parsePlaylist :: Value -> [a] getPlaylist :: Param a -> IO [a] songUrl :: Param a -> a -> IO String songMeta :: a -> SongMeta tagged :: a -> Bool play :: Logger -> Param a -> [a] -> IO () play logger reqData [] = getPlaylist reqData >>= play logger reqData play logger reqData (x:xs) = do surl <- songUrl reqData x print surl when (surl /= "") $ do let song = artist (songMeta x) ++ " - " ++ title (songMeta x) writeLog logger song getStateFile >>= flip writeFile song mpdLoad $ Path $ C.pack surl takeMVar eof -- Finished play logger reqData xs mpdLoad :: Path -> IO () mpdLoad path = do withMPD $ do clear add path withMPD $ MPD.play Nothing mpdPlay mpdPlay :: IO () mpdPlay = do withMPD $ idle [PlayerS] -- This will block until paused/finished. st <- withMPD status let st' = fmap stState st print st' if st' == Right Stopped then putMVar eof () else mpdPlay getLordDir :: IO FilePath getLordDir = (++ "/.lord") <$> getHomeDirectory getPidFile :: IO FilePath getPidFile = (++ "/lord.pid") <$> getLordDir getLogFile :: IO FilePath getLogFile = (++ "/lord.log") <$> getLordDir getStateFile :: IO FilePath getStateFile = (++ "/lordstate") <$> getLordDir formatLogMessage :: IO ZonedDate -> String -> IO [LogStr] formatLogMessage getdate msg = do now <- getdate return [ LB now , LB " : " , LS $ encodeString msg , LB "\n" ] writeLog :: Logger -> String -> IO () writeLog l msg = formatLogMessage (loggerDate l) msg >>= loggerPutStr l