module Network.Lastfm.Internal
( ResponseType(..)
, callAPI, callAPIsigned, xml, json, (#)
, 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
import Network.Lastfm.Error
import Network.Lastfm.TH
callAPI ∷ ResponseType → [(String, String)] → Lastfm Response
callAPI t = query (parseError t) . insertType t . map (second encodeString)
callAPIsigned ∷ ResponseType → Secret → [(String, String)] → Lastfm Response
callAPIsigned t (Secret s) xs = query (parseError t) zs
where
ys = map (second encodeString) . filter (not . null . snd) $ xs
zs = insertType t $ ("api_sig", sign ys) : ys
sign ∷ [(String, String)] → String
sign = show . md5 . BS.pack . (++ s) . concatMap (uncurry (++)) . sortBy (compare `on` fst)
insertType ∷ ResponseType → [(String, String)] → [(String, String)]
insertType XML = id
insertType JSON = (("format", "json") :)
parseError ∷ ResponseType → ByteString → Maybe LastfmError
parseError XML = xmlError
parseError JSON = jsonError
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
]
(#) ∷ Argument a ⇒ a → (String, String)
(#) x = (key x, value x)