{- - This module is used to collect a list of similar or - related artists as defined by LastFM. - This list is then used to generate an intelligent playlist. -} module Hmpf.RelatedArtist ( toggleAutogeneration , generation ) where import Data.List import Network.HTTP import Network.URI import Data.Maybe import Hmpf.Util import Hmpf.MPDSession import Hmpf.ApplicationTypes import Control.Concurrent import Control.Monad ( mzero, MonadPlus ) import Hmpf.LCDProc (alert) toggleAutogeneration :: Session Bool toggleAutogeneration = do st <- get if ( generate st ) then do put ( st { generate = False } ) return False else do put ( st { generate = True } ) return True -- Intelligent playlist generation generation :: Session () generation = idle active :: Session () active = do lift (threadDelay 1000000) st <- get if ( generate st ) then do mpd <- status let add = do len <- playlistlength mpd s <- song mpd if( len - s - 2 < 1 ) then return ( related 1 >>= (\i -> if ( (length i) > 0 ) then do command "delete 0" alert ("Added: " ++ ( artist . head $ i ) ) ( title .head $ i ) else return () ) ) else fail "Not at the last track" case add of Nothing -> active Just x -> x >> active else idle idle :: Session () idle = do lift (threadDelay 1000000) st <- get if( generate st ) then do --clear related 5 active else idle url :: String -> String url str = start ++ ( escapeURIString isUnescapedInURI str) ++ end where start = "http://ws.audioscrobbler.com/1.0/artist/" end = "/similar.txt" similarArtists :: String -> Session [(Float,String)] similarArtists a = do result <- lift (simpleHTTP req) case result of Left err -> do return [] Right resp -> do let artists = lines (rspBody resp) f str = let v = takeWhile (/=',') str n = reverse . takeWhile (/=',') . reverse $ str in ( read v , n ) if ( head artists `startsWith` "No artist exists" ) then return [] else return $ map f artists where uri = fromJust . parseURI . url $ a req = Request uri GET [] "" --Add a number of related songs related :: Int -> Session [Song] related num = do st <- status case (playlistlength st ) of Nothing -> return [] Just i -> do Just s <- playlistinfoAt (i-1) sim <- similarArtists . artist $ s if ( null sim ) then return [] else do let as = map snd $ sim lift . putStrLn . show $ as sngs <- takeM 5 (map tracksByArtist as) let snglst = concat . filter (not.null) $ sngs actions = take num . Data.List.repeat . lift $ (pick snglst) xs <- (sequence actions) addSongs xs --return . length $ actions return xs --takeM :: (Monad m , Monad n ) => Int -> [ m (n a) ] -> m [ n a ] takeM :: (Monad m ) => Int -> [ m [a] ] -> m [ [a] ] takeM 0 _ = return [] takeM _ [] = return [] takeM i (x:xs) = do y <- x case y of [] -> takeM i xs _ -> do rest <- takeM (i-1) xs return (y:rest)