{-# LANGUAGE ScopedTypeVariables #-} -- | Response module {-# OPTIONS_HADDOCK hide #-} module Network.Lastfm.Internal ( Format(..) , callAPI, callAPIsigned, (#) , module Network.Lastfm ) where import Control.Applicative ((<$>)) import Control.Arrow ((&&&), second) import Data.Function (on) import Data.List (sortBy) import Codec.Binary.UTF8.String (encodeString) import Data.ByteString.Lazy.Char8 (ByteString) import qualified Data.ByteString.Lazy.Char8 as BS import Data.Digest.Pure.MD5 (md5) import Data.URLEncoded (urlEncode, export) import Network.Curl import Network.Lastfm -- Response format data Format = Format { errorParser ∷ Response → Maybe LastfmError, uriArgument ∷ Maybe (String, String) } -- Send POST query to Lastfm API callAPI ∷ Format → [(String, String)] → Lastfm Response callAPI Format {errorParser = e, uriArgument = arg} = query e . (maybe id (:) arg) . map (second encodeString) -- Send signed POST query to Lastfm API callAPIsigned ∷ Format → Secret → [(String, String)] → Lastfm Response callAPIsigned Format {errorParser = e, uriArgument = arg} (Secret s) xs = query e zs where ys = map (second encodeString) . filter (not . null . snd) $ xs zs = maybe id (:) arg $ ("api_sig", sign ys) : ys sign ∷ [(String, String)] → String sign = show . md5 . BS.pack . (++ s) . concatMap (uncurry (++)) . sortBy (compare `on` fst) query ∷ (ByteString → Maybe LastfmError) → [(String, String)] → IO (Either LastfmError Response) query γ xs = do (status, body) ← (respCurlCode &&& respBody) <$> curlResponse xs return $ case status of CurlOK → case γ body of Nothing → Right body Just n → Left n s → Left $ CurlError s curlResponse ∷ [(String, String)] → IO (CurlResponse_ [(String, String)] ByteString) curlResponse xs = withCurlDo $ curlGetResponse_ "http://ws.audioscrobbler.com/2.0/?" [ CurlPostFields . map (export . urlEncode) $ xs , CurlFailOnError False , CurlUserAgent "Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0 Iceweasel/10.0" , CurlConnectTimeout 10 ] -- Construct query parameter (#) ∷ Argument a ⇒ a → (String, String) (#) x = (key x, value x)