packages feed

mushu-0.1.0: app/MPD.hs

module MPD
( currentSong
, togglePlayPause
, fetchPlaylist
, fetchAllSongs
, fetchAllArtists
, fetchArtistAlbums
, fetchArtistAlbumSongs
, fetchStatus
, clearPlaylist
, addArtistToPlaylist
, addAlbumToPlaylist
, addSongToPlaylist
, setVolume
, tag
, mpdReq
) where

import ClassyPrelude

import Control.Exception.Safe (throw)

import Network.MPD
  ( MPD
  , State(..)
  , Status(..)
  , Song(..)
  , Metadata(..)
  , Query
  , Artist
  , Album
  , def
  , withMPD
  , status
  , play
  , pause
  , playlistInfo
  , list
  , search
  , find
  , anything
  , clear
  , findAdd
  , toString
  , (=?), (<&>)
  )
import qualified Network.MPD as M

import Types
import Brick.BChan (BChan(..), writeBChan)

currentSong :: IO (Maybe Song)
currentSong = do
  res <- withMPD M.currentSong
  case res of
    Left err -> print err >> return Nothing
    Right song -> return song

togglePlayPause :: IO ()
togglePlayPause = do
  resStatus <- withMPD status
  case resStatus of
    Left _ -> return ()
    Right st -> do
      case (stState st) of
        Playing -> void $ withMPD $ pause True
        Stopped -> void $ withMPD $ play Nothing
        Paused -> void $ withMPD $ pause False

mpdReq :: MPD [a] -> IO [a]
mpdReq req = do
  res <- withMPD req
  case res of
    Left err -> print ("MPD error: " ++ (show err)) >> return []
    Right r -> return r

fetchAllArtists :: IO [M.Value]
fetchAllArtists = mpdReq $ list Artist Nothing

fetchArtistAlbums :: Artist -> IO (Artist, [Album])
fetchArtistAlbums artist = do
  albums <- mpdReq $ list Album (Just artist)
  return (artist, albums)

fetchArtistAlbumSongs :: Artist -> Album -> IO [Song]
fetchArtistAlbumSongs artist album = mpdReq req
  where req = search (Artist =? artist <&> Album =? album)

fetchAllSongs :: IO [Song]
fetchAllSongs = mpdReq $ search (Artist =? fromString "")
-- fetchAllSongs = mpdReq $ M.find anything

fetchPlaylist :: IO [Song]
fetchPlaylist = mpdReq $ playlistInfo Nothing

fetchStatus :: IO Status
fetchStatus = do
  st <- withMPD status
  case st of
    Left err -> return def
    Right st -> return st

clearPlaylist :: IO ()
clearPlaylist = void $ withMPD clear

toValue = fromString . unpack

addArtistToPlaylist :: Text -> Bool -> IO ()
addArtistToPlaylist artist play = do
  let query = Artist =? toValue artist
  if play then addToPlaylistAndPlay query else addToPlaylist query

addAlbumToPlaylist :: Maybe Text -> Text -> Bool -> IO ()
addAlbumToPlaylist maybeArtist album play = do
  let
    albumQuery = Album =? toValue album
    query = case maybeArtist of
        Just artist -> Artist =? toValue artist <&> albumQuery
        Nothing -> albumQuery
  if play then addToPlaylistAndPlay query else addToPlaylist query

addSongToPlaylist :: Text -> Text -> Bool -> IO ()
addSongToPlaylist album song play = do
  let query = Album =? toValue album <&> Title =? toValue song
  if play then addToPlaylist query else addToPlaylist query

addToPlaylist :: Query -> IO ()
addToPlaylist query = do
  res <- withMPD $ findAdd query
  case res of
    Left err -> throw MPDException
    Right _ -> return ()

addToPlaylistAndPlay :: Query -> IO ()
addToPlaylistAndPlay query = do
  n <- length <$> fetchPlaylist
  void $ addToPlaylist query
  r <- withMPD $ play (Just n)
  return ()

setVolume :: Int -> IO ()
setVolume volume = void $ withMPD $ M.setVolume volume

tag :: Metadata -> Text -> Song -> Text
tag key def song = concat (pack <$> toString <$> findWithDefault [fromString (unpack def)] key (sgTags song))