import System.Console.Haskeline import System.Console.Haskeline.Completion import System.Environment import Data.Char (isDigit, toLower) import Data.List (isPrefixOf) import Control.Monad.Trans (liftIO) import qualified Network.MPD as M --{{{ MPD/MISC UTIL FUNCS allArtists :: IO (M.Response [M.Artist]) allArtists = M.withMPD M.listArtists allAlbums :: IO (M.Response [M.Album]) allAlbums = M.withMPD $ M.listAlbums Nothing albumSongs x = liftIO $ M.withMPD $ M.find $ M.Album M.=? x artistAlbums :: M.Artist -> IO (M.Response [M.Album]) artistAlbums x = M.withMPD $ M.listAlbums (Just x) addSongs :: [M.Path] -> IO (M.Response ()) addSongs x = M.withMPD $ M.addMany "" x clearPL :: IO (M.Response ()) clearPL = M.withMPD M.clear toggle :: IO (M.Response ()) toggle = do (Right status) <- M.withMPD M.status case M.stState status of M.Playing -> M.withMPD $ M.pause True M.Paused -> M.withMPD $ M.pause False M.Stopped -> M.withMPD $ M.play Nothing playFromPL :: Integer -> IO (M.Response ()) playFromPL n = M.withMPD $ M.play (Just (M.Pos $ n)) fromRight :: Either a b -> b fromRight (Right x) = x removeSpace :: String -> String removeSpace x | last x == ' ' = init x | otherwise = x --}}} --{{{ COMPLETION BUILDING buildComp :: [Char] -> IO [Completion] buildComp s = do (Right a) <- allArtists (Right b) <- allAlbums mapM (return . simpleCompletion) (cut $ a ++ b) where cut x = filter (\y -> isPrefixOf (low s) (low y)) x low x = map toLower x compList :: CompletionFunc IO compList = completeWord Nothing ("\"\'") buildComp hMPDSettings :: Settings IO hMPDSettings = Settings { complete = compList, historyFile = Nothing, autoAddHistory = False } --}}} --{{{ PRINT FUNCTIONS pPrintStats :: InputT IO () pPrintStats = do (Right s) <- liftIO $ M.withMPD M.status putSpace >> outputStrLn " ==| STATUS |==" >> putSpace mapM_ outputStrLn [show $ M.stPlaylistVersion s ,show $ M.stState s ,show $ M.stVolume s ,show $ M.stRepeat s ,show $ M.stRandom s ,show $ M.stPlaylistVersion s ,show $ M.stPlaylistLength s ,show $ M.stSongPos s ,show $ fst $ M.stTime s ,show $ snd $ M.stTime s ] pPrintNumList :: [String] -> Int -> InputT IO () pPrintNumList [] n = return () pPrintNumList (a:as) n = if n < 10 then do outputStrLn (" " ++ (show n) ++ "| " ++ a) pPrintNumList as (n + 1) else do outputStrLn (" " ++ (show n) ++ "| " ++ a) pPrintNumList as (n + 1) putSpace :: InputT IO () putSpace = outputStrLn "" --}}} --{{{ MAIN LOOP argFuncs :: [(String, IO (M.Response()))] argFuncs = [("next", M.withMPD M.next) ,("prev", M.withMPD M.previous) ,("toggle", toggle) ,("stop", M.withMPD M.stop) ,("update", M.withMPD $ M.update []) ] main :: IO () main = do test <- M.withMPD M.ping case test of Right _ -> do args <- getArgs if null args then do hMPDPrefs <- readPrefs ".haskelinepref" runInputTWithPrefs hMPDPrefs hMPDSettings loopPath else do let argAttempt = lookup (head args) argFuncs case argAttempt of Just x -> fmap fromRight x Nothing -> putStrLn "Invalid Argument." fmap fromRight $ M.withMPD M.close Left _ -> putStrLn "Failed to connect to MPD." loopPath :: InputT IO () loopPath = do Right artistList <- liftIO $ allArtists Right albumList <- liftIO $ allAlbums Just input <- getInputLine "" fork (removeSpace input) artistList albumList where fork a b c | a == ":q" = return () | elem a b = artistLoop a | elem a c = albumLoop a | otherwise = do outputStrLn "No matches found." loopPath albumLoop :: M.Album -> InputT IO () albumLoop album = do Right songs <- albumSongs album let songPaths = map M.sgFilePath songs liftIO $ M.withMPD $ M.addMany "" songPaths n <- liftIO $ fmap (M.stPlaylistLength . fromRight) $ M.withMPD M.status liftIO $ playFromPL $ n - (fromIntegral $ length songPaths :: Integer) return () artistLoop :: M.Artist -> InputT IO () artistLoop artist = do Right artistAlbumList <- liftIO $ artistAlbums artist putSpace >> pPrintNumList artistAlbumList 1 >> putSpace Just input <- getInputLine "" if all isDigit input then albumLoop $ artistAlbumList !! ((read input :: Int) - 1) else outputStrLn "Invalid Input." --}}}