diff --git a/Network/Lastfm.hs b/Network/Lastfm.hs
deleted file mode 100644
--- a/Network/Lastfm.hs
+++ /dev/null
@@ -1,54 +0,0 @@
-{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}
--- | Response module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm
-  ( Lastfm, Response
-  , callAPI, callAPIsigned
-  , module Network.Lastfm.Types
-  ) where
-
-import Codec.Binary.UTF8.String (encodeString)
-import Control.Applicative ((<$>))
-import Control.Arrow (second)
-import Control.Monad ((<=<))
-import Control.Monad.Error (ErrorT, runErrorT, throwError)
-import Control.Monad.Trans (liftIO)
-import qualified Data.ByteString.Lazy.Char8 as BS
-import Data.Digest.Pure.MD5 (md5)
-import Data.Function (on)
-import Data.List (sortBy)
-import Data.URLEncoded (urlEncode, export)
-import Network.Curl
-import Network.Lastfm.Types
-import Text.XML.Light
-
--- | Type synonym for Lastfm response or error.
-type Lastfm a = IO (Either LastfmError a)
--- | Type synonym for Lastfm response
-type Response = String
-
--- | Low level function. Sends POST query to Lastfm API.
-callAPI :: [(String, String)] -> Lastfm Response
-callAPI = runErrorT . query . map (second encodeString)
-
--- | Low level function. Sends signed POST query to Lastfm API.
-callAPIsigned :: Secret -> [(String, String)] -> Lastfm Response
-callAPIsigned (Secret s) xs = runErrorT $ query zs
-  where ys = map (second encodeString) . filter (not . null . snd) $ xs
-        zs = ("api_sig", sign ys) : ys
-
-        sign :: [(String, String)] -> String
-        sign = show . md5 . BS.pack . (++ s) . concatMap (uncurry (++)) . sortBy (compare `on` fst)
-
-query :: [(String, String)] -> ErrorT LastfmError IO Response
-query xs = do
-  !response <- liftIO $ withCurlDo $ respBody <$> (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"
-                             ]
-                             :: IO CurlResponse)
-  maybe (return response) (throwError . LastfmAPIError . toEnum . (subtract 1)) (getError response)
-  where getError :: String -> Maybe Int
-        getError response = do xml <- parseXMLDoc response
-                               read <$> (findAttr (unqual "code") <=< findChild (unqual "error")) xml
diff --git a/Network/Lastfm/API/Album.hs b/Network/Lastfm/API/Album.hs
deleted file mode 100644
--- a/Network/Lastfm/API/Album.hs
+++ /dev/null
@@ -1,127 +0,0 @@
--- | Album API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.Album
-  ( addTags, getBuyLinks, getInfo, getShouts, getTags
-  , getTopTags, removeTag, search, share
-  ) where
-
-import Control.Arrow ((|||))
-import Network.Lastfm
-
--- | Tag an album using a list of user supplied tags.
---
--- More: <http://www.last.fm/api/show/album.addTags>
-addTags :: (Artist, Album) -> [Tag] -> APIKey -> SessionKey -> Secret -> Lastfm Response
-addTags (artist, album) tags apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "album.addTags")
-  , (#) artist
-  , (#) album
-  , (#) tags
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Get a list of Buy Links for a particular Album. It is required that you supply either the artist and track params or the mbid param.
---
--- More: <http://www.last.fm/api/show/album.getBuylinks>
-getBuyLinks :: Either (Artist, Album) Mbid -> Maybe Autocorrect -> Country -> APIKey -> Lastfm Response
-getBuyLinks a autocorrect country apiKey = callAPI $
-  target a ++
-  [ (#) (Method "album.getBuyLinks")
-  , (#) autocorrect
-  , (#) country
-  , (#) apiKey
-  ]
-
--- | Get the metadata for an album on Last.fm using the album name or a musicbrainz id. See playlist.fetch on how to get the album playlist.
---
--- More: <http://www.last.fm/api/show/album.getInfo>
-getInfo :: Either (Artist, Album) Mbid -> Maybe Autocorrect -> Maybe Language -> Maybe Username -> APIKey -> Lastfm Response
-getInfo a autocorrect lang username apiKey = callAPI $
-  target a ++
-  [ (#) (Method "album.getInfo")
-  , (#) autocorrect
-  , (#) lang
-  , (#) username
-  , (#) apiKey
-  ]
-
--- | Get shouts for this album.
---
--- More: <http://www.last.fm/api/show/album.getShouts>
-getShouts :: Either (Artist, Album) Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getShouts a autocorrect page limit apiKey = callAPI $
-  target a ++
-  [ (#) (Method "album.getShouts")
-  , (#) autocorrect
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get the tags applied by an individual user to an album on Last.fm.
---
--- More: <http://www.last.fm/api/show/album.getTags>
-getTags :: Either (Artist, Album) Mbid -> Maybe Autocorrect -> Either User (SessionKey, Secret) -> APIKey -> Lastfm Response
-getTags a autocorrect b apiKey = case b of
-  Left user -> callAPI $ target a ++ [(#) user] ++ args
-  Right (sessionKey, secret) -> callAPIsigned secret $ target a ++ [(#) sessionKey] ++ args
-  where args =
-          [ (#) (Method "album.getTags")
-          , (#) autocorrect
-          , (#) apiKey
-          ]
-
--- | Get the top tags for an album on Last.fm, ordered by popularity.
---
--- More: <http://www.last.fm/api/show/album.getTopTags>
-getTopTags :: Either (Artist, Album) Mbid -> Maybe Autocorrect -> APIKey -> Lastfm Response
-getTopTags a autocorrect apiKey = callAPI $
-  target a ++
-  [ (#) (Method "album.getTopTags")
-  , (#) autocorrect
-  , (#) apiKey
-  ]
-
--- | Remove a user's tag from an album.
---
--- More: <http://www.last.fm/api/show/album.removeTag>
-removeTag :: Artist -> Album -> Tag -> APIKey -> SessionKey -> Secret -> Lastfm Response
-removeTag artist album tag apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "album.removeTag")
-  , (#) artist
-  , (#) album
-  , (#) tag
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Search for an album by name. Returns album matches sorted by relevance.
---
--- More: <http://www.last.fm/api/show/album.search>
-search :: Album -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-search album page limit apiKey = callAPI
-  [ (#) (Method "album.search")
-  , (#) album
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Share an album with one or more Last.fm users or other friends.
---
--- More: <http://www.last.fm/api/show/album.share>
-share :: Artist -> Album -> Recipient -> Maybe Message -> Maybe Public -> APIKey -> SessionKey -> Secret -> Lastfm Response
-share artist album recipient message public apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "album.share")
-  , (#) artist
-  , (#) album
-  , (#) public
-  , (#) message
-  , (#) recipient
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
-target :: Either (Artist, Album) Mbid -> [(String, String)]
-target = (\(artist, album) -> [(#) artist, (#) album]) ||| return . (#)
diff --git a/Network/Lastfm/API/Artist.hs b/Network/Lastfm/API/Artist.hs
deleted file mode 100644
--- a/Network/Lastfm/API/Artist.hs
+++ /dev/null
@@ -1,236 +0,0 @@
--- | Artist API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.Artist
-  ( addTags, getCorrection, getEvents, getImages, getInfo
-  , getPastEvents, getPodcast, getShouts, getSimilar, getTags, getTopAlbums
-  , getTopFans, getTopTags, getTopTracks, removeTag, search, share, shout
-  ) where
-
-import Control.Arrow ((|||))
-import Network.Lastfm
-
--- | Tag an album using a list of user supplied tags.
---
--- More: <http://www.last.fm/api/show/artist.addTags>
-addTags :: Artist -> [Tag] -> APIKey -> SessionKey -> Secret -> Lastfm Response
-addTags artist tags apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "artist.addTags")
-  , (#) artist
-  , (#) tags
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Use the last.fm corrections data to check whether the supplied artist has a correction to a canonical artist
---
--- More: <http://www.last.fm/api/show/artist.getCorrection>
-getCorrection :: Artist -> APIKey -> Lastfm Response
-getCorrection artist apiKey = callAPI
-  [ (#) (Method "artist.getCorrection")
-  , (#) artist
-  , (#) apiKey
-  ]
-
--- | Get a list of upcoming events for this artist.
---
--- More: <http://www.last.fm/api/show/artist.getEvents>
-getEvents :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> Maybe FestivalsOnly -> APIKey -> Lastfm Response
-getEvents a autocorrect page limit festivalsOnly apiKey = callAPI $
-  target a ++
-  [ (#) (Method "artist.getEvents")
-  , (#) autocorrect
-  , (#) page
-  , (#) limit
-  , (#) festivalsOnly
-  , (#) apiKey
-  ]
-
--- | Get Images for this artist in a variety of sizes.
---
--- More: <http://www.last.fm/api/show/artist.getImages>
-getImages :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> Maybe Order -> APIKey -> Lastfm Response
-getImages a autocorrect page limit order apiKey = callAPI $
-  target a ++
-  [ (#) (Method "artist.getImages")
-  , (#) autocorrect
-  , (#) page
-  , (#) limit
-  , (#) order
-  , (#) apiKey
-  ]
-
--- | Get the metadata for an artist. Includes biography.
---
--- More: <http://www.last.fm/api/show/artist.getInfo>
-getInfo :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Language -> Maybe Username -> APIKey -> Lastfm Response
-getInfo a autocorrect language username apiKey = callAPI $
-  target a ++
-  [ (#) (Method "artist.getInfo")
-  , (#) autocorrect
-  , (#) language
-  , (#) username
-  , (#) apiKey
-  ]
-
--- | Get a paginated list of all the events this artist has played at in the past.
---
--- More: <http://www.last.fm/api/show/artist.getPastEvents>
-getPastEvents :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getPastEvents a autocorrect page limit apiKey = callAPI $
-  target a ++
-  [ (#) (Method "artist.getPastEvents")
-  , (#) autocorrect
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get a podcast of free mp3s based on an artist.
---
--- More: <http://www.last.fm/api/show/artist.getPodcast>
-getPodcast :: Either Artist Mbid -> Maybe Autocorrect -> APIKey -> Lastfm Response
-getPodcast a autocorrect apiKey = callAPI $
-  target a ++
-  [ (#) (Method "artist.getPodcast")
-  , (#) autocorrect
-  , (#) apiKey
-  ]
-
--- | Get shouts for this artist. Also available as an rss feed.
---
--- More: <http://www.last.fm/api/show/artist.getShouts>
-getShouts :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getShouts a autocorrect page limit apiKey = callAPI $
-  target a ++
-  [ (#) (Method "artist.getShouts")
-  , (#) autocorrect
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get all the artists similar to this artist.
---
--- More: <http://www.last.fm/api/show/artist.getSimilar>
-getSimilar :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Limit -> APIKey -> Lastfm Response
-getSimilar a autocorrect limit apiKey = callAPI $
-  target a ++
-  [ (#) (Method "artist.getSimilar")
-  , (#) autocorrect
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get the tags applied by an individual user to an artist on Last.fm. If accessed as an authenticated service /and/ you don't supply a user parameter then this service will return tags for the authenticated user.
---
--- More: <http://www.last.fm/api/show/artist.getTags>
-getTags :: Either Artist Mbid -> Maybe Autocorrect -> Either User (SessionKey, Secret) -> APIKey -> Lastfm Response
-getTags a autocorrect b apiKey = case b of
-  Left user -> callAPI $ target a ++ [(#) user] ++ args
-  Right (sessionKey, secret) -> callAPIsigned secret $ target a ++ [(#) sessionKey] ++ args
-  where args =
-          [ (#) (Method "artist.getTags")
-          , (#) autocorrect
-          , (#) apiKey
-          ]
-
--- | Get the top albums for an artist on Last.fm, ordered by popularity.
---
--- More: <http://www.last.fm/api/show/artist.getTopAlbums>
-getTopAlbums :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getTopAlbums a autocorrect page limit apiKey = callAPI $
-  target a ++
-  [ (#) (Method "artist.getTopAlbums")
-  , (#) autocorrect
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get the top fans for an artist on Last.fm, based on listening data.
---
--- More: <http://www.last.fm/api/show/artist.getTopFans>
-getTopFans :: Either Artist Mbid -> Maybe Autocorrect -> APIKey -> Lastfm Response
-getTopFans a autocorrect apiKey = callAPI $
-  target a ++
-  [ (#) (Method "artist.getTopFans")
-  , (#) autocorrect
-  , (#) apiKey
-  ]
-
--- | Get the top tags for an artist on Last.fm, ordered by popularity.
---
--- More: <http://www.last.fm/api/show/artist.getTopTags>
-getTopTags :: Either Artist Mbid -> Maybe Autocorrect -> APIKey -> Lastfm Response
-getTopTags a autocorrect apiKey = callAPI $
-  target a ++
-  [ (#) (Method "artist.getTopTags")
-  , (#) autocorrect
-  , (#) apiKey
-  ]
-
--- | Get the top tracks by an artist on Last.fm, ordered by popularity.
---
--- More: <http://www.last.fm/api/show/artist.getTopTracks>
-getTopTracks :: Either Artist Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getTopTracks a autocorrect page limit apiKey = callAPI $
-  target a ++
-  [ (#) (Method "artist.getTopTracks")
-  , (#) autocorrect
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Remove a user's tag from an artist.
---
--- More: <http://www.last.fm/api/show/artist.removeTag>
-removeTag :: Artist -> Tag -> APIKey -> SessionKey -> Secret -> Lastfm Response
-removeTag artist tag apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "artist.removeTag")
-  , (#) artist
-  , (#) tag
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Search for an artist by name. Returns artist matches sorted by relevance.
---
--- More: <http://www.last.fm/api/show/artist.search>
-search :: Artist -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-search artist page limit apiKey = callAPI
-  [ (#) (Method "artist.search")
-  , (#) artist
-  , (#) apiKey
-  , (#) page
-  , (#) limit
-  ]
-
--- | Share an artist with Last.fm users or other friends.
---
--- More: <http://www.last.fm/api/show/artist.share>
-share :: Artist -> Recipient -> Maybe Message -> Maybe Public -> APIKey -> SessionKey -> Secret -> Lastfm Response
-share artist recipient message public apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "artist.share")
-  , (#) artist
-  , (#) recipient
-  , (#) apiKey
-  , (#) sessionKey
-  , (#) public
-  , (#) message
-  ]
-
--- | Shout in this artist's shoutbox.
---
--- More: <http://www.last.fm/api/show/artist.shout>
-shout :: Artist -> Message -> APIKey -> SessionKey -> Secret -> Lastfm Response
-shout artist message apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "artist.shout")
-  , (#) artist
-  , (#) message
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
-target :: Either Artist Mbid -> [(String, String)]
-target = return . (#) ||| return . (#)
diff --git a/Network/Lastfm/API/Auth.hs b/Network/Lastfm/API/Auth.hs
deleted file mode 100644
--- a/Network/Lastfm/API/Auth.hs
+++ /dev/null
@@ -1,42 +0,0 @@
--- | Auth API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.Auth
-  ( getMobileSession, getSession, getToken
-  , getAuthorizeTokenLink
-  ) where
-
-import Network.Lastfm
-
--- | Create a web service session for a user. Used for authenticating a user when the password can be inputted by the user. Only suitable for standalone mobile devices.
---
--- More: <http://www.last.fm/api/show/auth.getMobileSession>
-getMobileSession :: Username -> APIKey -> AuthToken -> Lastfm Response
-getMobileSession username apiKey token = callAPI
-  [ (#) (Method "auth.getMobileSession")
-  , (#) username
-  , (#) token
-  , (#) apiKey
-  ]
-
--- | Fetch a session key for a user.
---
--- More: <http://www.last.fm/api/show/auth.getSession>
-getSession :: APIKey -> Token -> Secret -> Lastfm Response
-getSession apiKey token secret = callAPIsigned secret
-  [ (#) (Method "auth.getSession")
-  , (#) apiKey
-  , (#) token
-  ]
-
--- | Fetch an unathorized request token for an API account.
---
--- More: <http://www.last.fm/api/show/auth.getToken>
-getToken :: APIKey -> Lastfm Response
-getToken apiKey = callAPI
-  [ (#) (Method "auth.getToken")
-  , (#) apiKey
-  ]
-
--- | Construct the link to authorize token.
-getAuthorizeTokenLink :: APIKey -> Token -> String
-getAuthorizeTokenLink apiKey token = "http://www.last.fm/api/auth/?api_key=" ++ value apiKey ++ "&token=" ++ value token
diff --git a/Network/Lastfm/API/Chart.hs b/Network/Lastfm/API/Chart.hs
deleted file mode 100644
--- a/Network/Lastfm/API/Chart.hs
+++ /dev/null
@@ -1,52 +0,0 @@
--- | Chart API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.Chart
-  ( getHypedArtists, getHypedTracks, getLovedTracks
-  , getTopArtists, getTopTags, getTopTracks
-  ) where
-
-import Network.Lastfm
-
--- | Get the hyped artists chart.
---
--- More: <http://www.last.fm/api/show/chart.getHypedArtists>
-getHypedArtists :: Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getHypedArtists = get "getHypedArtists"
-
--- | Get the hyped tracks chart.
---
--- More: <http://www.last.fm/api/show/chart.getHypedTracks>
-getHypedTracks :: Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getHypedTracks = get "getHypedTracks"
-
--- | Get the most loved tracks chart.
---
--- More: <http://www.last.fm/api/show/chart.getLovedTracks>
-getLovedTracks :: Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getLovedTracks = get "getLovedTracks"
-
--- | Get the top artists chart.
---
--- More: <http://www.last.fm/api/show/chart.getTopArtists>
-getTopArtists :: Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getTopArtists = get "getTopArtists"
-
--- | Get top tags chart.
---
--- More: <http://www.last.fm/api/show/chart.getTopTags>
-getTopTags :: Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getTopTags = get "getTopTags"
-
--- | Get the top tracks chart.
---
--- More: <http://www.last.fm/api/show/chart.getTopTracks>
-getTopTracks :: Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getTopTracks = get "getTopTracks"
-
-get :: String -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-get method page limit apiKey = callAPI
-  [ (#) (Method $ "chart." ++ method)
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
diff --git a/Network/Lastfm/API/Event.hs b/Network/Lastfm/API/Event.hs
deleted file mode 100644
--- a/Network/Lastfm/API/Event.hs
+++ /dev/null
@@ -1,79 +0,0 @@
--- | Event API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.Event
-  ( attend, getAttendees, getInfo, getShouts, share, shout
-  ) where
-
-import Network.Lastfm
-
--- | Set a user's attendance status for an event.
---
--- More: <http://www.last.fm/api/show/event.attend>
-attend :: Event -> Status -> APIKey -> SessionKey -> Secret -> Lastfm Response
-attend event status apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "event.attend")
-  , (#) event
-  , (#) status
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Get a list of attendees for an event.
---
--- More: <http://www.last.fm/api/show/event.getAttendees>
-getAttendees :: Event -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getAttendees event page limit apiKey = callAPI
-  [ (#) (Method "event.getAttendees")
-  , (#) event
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get the metadata for an event on Last.fm. Includes attendance and lineup information.
---
--- More: <http://www.last.fm/api/show/event.getInfo>
-getInfo :: Event -> APIKey -> Lastfm Response
-getInfo event apiKey = callAPI
-  [ (#) (Method "event.getInfo")
-  , (#) event
-  , (#) apiKey
-  ]
-
--- | Get shouts for this event.
---
--- More: <http://www.last.fm/api/show/event.getShouts>
-getShouts :: Event -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getShouts event page limit apiKey = callAPI
-  [ (#) (Method "event.getShouts")
-  , (#) event
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Share an event with one or more Last.fm users or other friends.
---
--- More: <http://www.last.fm/api/show/event.share>
-share :: Event -> Recipient -> Maybe Message -> Maybe Public -> APIKey -> SessionKey -> Secret -> Lastfm Response
-share event recipient message public apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "event.share")
-  , (#) event
-  , (#) public
-  , (#) message
-  , (#) recipient
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Shout in this event's shoutbox.
---
--- More: <http://www.last.fm/api/show/event.shout>
-shout :: Event -> Message -> APIKey -> SessionKey -> Secret -> Lastfm Response
-shout event message apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "event.shout")
-  , (#) event
-  , (#) message
-  , (#) apiKey
-  , (#) sessionKey
-  ]
diff --git a/Network/Lastfm/API/Geo.hs b/Network/Lastfm/API/Geo.hs
deleted file mode 100644
--- a/Network/Lastfm/API/Geo.hs
+++ /dev/null
@@ -1,122 +0,0 @@
--- | Geo API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.Geo
-  ( getEvents, getMetroArtistChart, getMetroHypeArtistChart, getMetroHypeTrackChart
-  , getMetroTrackChart, getMetroUniqueArtistChart, getMetroUniqueTrackChart
-  , getMetroWeeklyChartlist, getMetros, getTopArtists, getTopTracks
-  ) where
-
-import Network.Lastfm
-
--- | Get all events in a specific location by country or city name.
---
--- More: <http://www.last.fm/api/show/geo.getEvents>
-getEvents :: Maybe Latitude
-          -> Maybe Longitude
-          -> Maybe Location
-          -> Maybe Distance
-          -> Maybe Page
-          -> Maybe Limit
-          -> APIKey
-          -> Lastfm Response
-getEvents latitude longitude location distance page limit apiKey = callAPI
-  [ (#) (Method "geo.getEvents")
-  , (#) latitude
-  , (#) longitude
-  , (#) location
-  , (#) distance
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get a chart of artists for a metro.
---
--- More: <http://www.last.fm/api/show/geo.getMetroArtistChart>
-getMetroArtistChart :: Country -> Metro -> Maybe Start -> Maybe End -> APIKey -> Lastfm Response
-getMetroArtistChart = getMetroChart "geo.getMetroArtistChart"
-
--- | Get a chart of hyped (up and coming) artists for a metro.
---
--- More: <http://www.last.fm/api/show/geo.getMetroHypeArtistChart>
-getMetroHypeArtistChart :: Country -> Metro -> Maybe Start -> Maybe End -> APIKey -> Lastfm Response
-getMetroHypeArtistChart = getMetroChart "geo.getMetroHypeArtistChart"
-
--- | Get a chart of hyped (up and coming) tracks for a metro.
---
--- More: <http://www.last.fm/api/show/geo.getMetroHypeTrackChart>
-getMetroHypeTrackChart :: Country -> Metro -> Maybe Start -> Maybe End -> APIKey -> Lastfm Response
-getMetroHypeTrackChart = getMetroChart "geo.getMetroHypeTrackChart"
-
--- | Get a chart of tracks for a metro.
---
--- More: <http://www.last.fm/api/show/geo.getMetroTrackChart>
-getMetroTrackChart :: Country -> Metro -> Maybe Start -> Maybe End -> APIKey -> Lastfm Response
-getMetroTrackChart = getMetroChart "geo.getMetroTrackChart"
-
--- | Get a chart of the artists which make that metro unique.
---
--- More: <http://www.last.fm/api/show/geo.getMetroUniqueArtistChart>
-getMetroUniqueArtistChart :: Country -> Metro -> Maybe Start -> Maybe End -> APIKey -> Lastfm Response
-getMetroUniqueArtistChart = getMetroChart "geo.getMetroUniqueArtistChart"
-
--- | Get a chart of the tracks which make that metro unique.
---
--- More: <http://www.last.fm/api/show/geo.getMetroUniqueTrackChart>
-getMetroUniqueTrackChart :: Country -> Metro -> Maybe Start -> Maybe End -> APIKey -> Lastfm Response
-getMetroUniqueTrackChart = getMetroChart "geo.getMetroUniqueTrackChart"
-
--- | Get a list of available chart periods for this metro, expressed as date ranges which can be sent to the chart services.
---
--- More: <http://www.last.fm/api/show/geo.getMetroWeeklyChartlist>
-getMetroWeeklyChartlist :: Metro -> APIKey -> Lastfm Response
-getMetroWeeklyChartlist metro apiKey = callAPI
-  [ (#) (Method "geo.getMetroWeeklyChartlist")
-  , (#) metro
-  , (#) apiKey
-  ]
-
--- | Get a list of valid countries and metros for use in the other webservices.
---
--- More: <http://www.last.fm/api/show/geo.getMetros>
-getMetros :: Maybe Country -> APIKey -> Lastfm Response
-getMetros country apiKey = callAPI
-  [ (#) (Method "geo.getMetros")
-  , (#) country
-  , (#) apiKey
-  ]
-
--- | Get the most popular artists on Last.fm by country.
---
--- More: <http://www.last.fm/api/show/geo.getTopArtists>
-getTopArtists :: Country -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getTopArtists country page limit apiKey = callAPI
-  [ (#) (Method "geo.getTopArtists")
-  , (#) country
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get the most popular tracks on Last.fm last week by country.
---
--- More: <http://www.last.fm/api/show/geo.getTopTracks>
-getTopTracks :: Country -> Maybe Location -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getTopTracks country location page limit apiKey = callAPI
-  [ (#) (Method "geo.getTopTracks")
-  , (#) country
-  , (#) location
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
-getMetroChart :: String -> Country -> Metro -> Maybe Start -> Maybe End -> APIKey -> Lastfm Response
-getMetroChart method country metro start end apiKey = callAPI
-  [ (#) (Method method)
-  , (#) country
-  , (#) metro
-  , (#) start
-  , (#) end
-  , (#) apiKey
-  ]
diff --git a/Network/Lastfm/API/Group.hs b/Network/Lastfm/API/Group.hs
deleted file mode 100644
--- a/Network/Lastfm/API/Group.hs
+++ /dev/null
@@ -1,76 +0,0 @@
--- | Group API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.Group
-  ( getHype, getMembers, getWeeklyChartList, getWeeklyAlbumChart, getWeeklyArtistChart, getWeeklyTrackChart
-  ) where
-
-import Network.Lastfm
-
--- | Get the hype list for a group.
---
--- More: <http://www.last.fm/api/show/group.getHype>
-getHype :: Group -> APIKey -> Lastfm Response
-getHype group apiKey = callAPI
-  [ (#) (Method "group.getHype")
-  , (#) group
-  , (#) apiKey
-  ]
-
--- | Get a list of members for this group.
---
--- More: <http://www.last.fm/api/show/group.getMembers>
-getMembers :: Group -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getMembers group page limit apiKey = callAPI
-  [ (#) (Method "group.getMembers")
-  , (#) group
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get an album chart for a group, for a given date range. If no date range is supplied, it will return the most recent album chart for this group.
---
--- More: <http://www.last.fm/api/show/group.getWeeklyAlbumChart>
-getWeeklyChartList :: Group -> APIKey -> Lastfm Response
-getWeeklyChartList group apiKey = callAPI
-  [ (#) (Method "group.getWeeklyChartList")
-  , (#) group
-  , (#) apiKey
-  ]
-
--- | Get an artist chart for a group, for a given date range. If no date range is supplied, it will return the most recent artist chart for this group.
---
--- More: <http://www.last.fm/api/show/group.getWeeklyArtistChart>
-getWeeklyAlbumChart :: Group -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
-getWeeklyAlbumChart group from to apiKey = callAPI
-  [ (#) (Method "group.getWeeklyAlbumChart")
-  , (#) group
-  , (#) from
-  , (#) to
-  , (#) apiKey
-  ]
-
--- | Get a list of available charts for this group, expressed as date ranges which can be sent to the chart services.
---
--- More: <http://www.last.fm/api/show/group.getWeeklyChartList>
-getWeeklyArtistChart :: Group -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
-getWeeklyArtistChart group from to apiKey = callAPI
-  [ (#) (Method "group.getWeeklyArtistChart")
-  , (#) group
-  , (#) from
-  , (#) to
-  , (#) apiKey
-  ]
-
-
--- | Get a track chart for a group, for a given date range. If no date range is supplied, it will return the most recent track chart for this group.
---
--- More: <http://www.last.fm/api/show/group.getWeeklyTrackChart>
-getWeeklyTrackChart :: Group -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
-getWeeklyTrackChart group from to apiKey = callAPI
-  [ (#) (Method "group.getWeeklyTrackChart")
-  , (#) group
-  , (#) from
-  , (#) to
-  , (#) apiKey
-  ]
diff --git a/Network/Lastfm/API/Library.hs b/Network/Lastfm/API/Library.hs
deleted file mode 100644
--- a/Network/Lastfm/API/Library.hs
+++ /dev/null
@@ -1,131 +0,0 @@
--- | Library API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.Library
-  ( addAlbum, addArtist, addTrack, getAlbums, getArtists, getTracks
-  , removeAlbum, removeArtist, removeScrobble, removeTrack
-  ) where
-
-import Control.Monad.Error (runErrorT)
-import Network.Lastfm
-
--- | Add an album or collection of albums to a user's Last.fm library.
---
--- More: <http://www.last.fm/api/show/library.addAlbum>
-addAlbum :: Artist -> Album -> APIKey -> SessionKey -> Secret -> Lastfm Response
-addAlbum artist album apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "library.addAlbum")
-  , (#) artist
-  , (#) album
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Add an artist to a user's Last.fm library.
---
--- More: <http://www.last.fm/api/show/library.addArtist>
-addArtist :: Artist -> APIKey -> SessionKey -> Secret -> Lastfm Response
-addArtist artist apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "library.addArtist")
-  , (#) artist
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Add a track to a user's Last.fm library.
---
--- More: <http://www.last.fm/api/show/library.addTrack>
-addTrack :: Artist -> Track -> APIKey -> SessionKey -> Secret -> Lastfm Response
-addTrack artist track apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "library.addTrack")
-  , (#) artist
-  , (#) track
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | A paginated list of all the albums in a user's library, with play counts and tag counts.
---
--- More: <http://www.last.fm/api/show/library.getAlbums>
-getAlbums :: User -> Maybe Artist -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getAlbums user artist page limit apiKey = callAPI
-  [ (#) (Method "library.getAlbums")
-  , (#) user
-  , (#) artist
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | A paginated list of all the artists in a user's library, with play counts and tag counts.
---
--- More: <http://www.last.fm/api/show/library.getArtists>
-getArtists :: User -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getArtists user page limit apiKey = callAPI
-  [ (#) (Method "library.getArtists")
-  , (#) user
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | A paginated list of all the tracks in a user's library, with play counts and tag counts.
---
--- More: <http://www.last.fm/api/show/library.getTracks>
-getTracks :: User -> Maybe Artist -> Maybe Album -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getTracks user artist album page limit apiKey = callAPI
-  [ (#) (Method "library.getTracks")
-  , (#) user
-  , (#) artist
-  , (#) album
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Remove an album from a user's Last.fm library.
---
--- More: <http://www.last.fm/api/show/library.removeAlbum>
-removeAlbum :: Artist -> Album -> APIKey -> SessionKey -> Secret -> Lastfm Response
-removeAlbum artist album apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "library.removeAlbum")
-  , (#) artist
-  , (#) album
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Remove an artist from a user's Last.fm library.
---
--- More: <http://www.last.fm/api/show/library.removeArtist>
-removeArtist :: Artist -> APIKey -> SessionKey -> Secret -> Lastfm Response
-removeArtist artist apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "library.removeArtist")
-  , (#) artist
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Remove a scrobble from a user's Last.fm library.
---
--- More: <http://www.last.fm/api/show/library.removeScrobble>
-removeScrobble :: Artist -> Track -> Timestamp -> APIKey -> SessionKey -> Secret -> Lastfm Response
-removeScrobble artist track timestamp apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "library.removeScrobble")
-  , (#) artist
-  , (#) track
-  , (#) timestamp
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Remove a track from a user's Last.fm library.
---
--- More: <http://www.last.fm/api/show/library.removeTrack>
-removeTrack :: Artist -> Track -> APIKey -> SessionKey -> Secret -> Lastfm Response
-removeTrack artist track apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "library.removeTrack")
-  , (#) artist
-  , (#) track
-  , (#) apiKey
-  , (#) sessionKey
-  ]
diff --git a/Network/Lastfm/API/Playlist.hs b/Network/Lastfm/API/Playlist.hs
deleted file mode 100644
--- a/Network/Lastfm/API/Playlist.hs
+++ /dev/null
@@ -1,33 +0,0 @@
--- | Playlist API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.Playlist
-  ( addTrack, create
-  ) where
-
-import Control.Monad.Error (runErrorT)
-import Network.Lastfm
-
--- | Add a track to a Last.fm user's playlist.
---
--- More: <http://www.last.fm/api/show/playlist.addTrack>
-addTrack :: Playlist -> Artist -> Track -> APIKey -> SessionKey -> Secret -> Lastfm Response
-addTrack playlist artist track apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "playlist.addTrack")
-  , (#) playlist
-  , (#) artist
-  , (#) track
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Create a Last.fm playlist on behalf of a user.
---
--- More: <http://www.last.fm/api/show/playlist.create>
-create :: Maybe Title -> Maybe Description -> APIKey -> SessionKey -> Secret -> Lastfm Response
-create title description apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "playlist.create")
-  , (#) title
-  , (#) description
-  , (#) apiKey
-  , (#) sessionKey
-  ]
diff --git a/Network/Lastfm/API/Radio.hs b/Network/Lastfm/API/Radio.hs
deleted file mode 100644
--- a/Network/Lastfm/API/Radio.hs
+++ /dev/null
@@ -1,53 +0,0 @@
--- | Radio API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.Radio
-  ( getPlaylist, search, tune
-  ) where
-
-import Control.Monad.Error (runErrorT)
-import Network.Lastfm
-
--- | Fetch new radio content periodically in an XSPF format.
---
--- More: <http://www.last.fm/api/show/radio.getPlaylist>
-getPlaylist :: Maybe Discovery
-            -> Maybe RTP
-            -> Maybe BuyLinks
-            -> Multiplier
-            -> Bitrate
-            -> APIKey
-            -> SessionKey
-            -> Secret
-            -> Lastfm Response
-getPlaylist discovery rtp buylinks multiplier bitrate apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "radio.getPlaylist")
-  , (#) discovery
-  , (#) rtp
-  , (#) buylinks
-  , (#) multiplier
-  , (#) bitrate
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Resolve the name of a resource into a station depending on which resource it is most likely to represent.
---
--- More: <http://www.last.fm/api/show/radio.search>
-search :: Name -> APIKey -> Lastfm Response
-search name apiKey = callAPI
-  [ (#) (Method "radio.search")
-  , (#) name
-  , (#) apiKey
-  ]
-
--- | Tune in to a Last.fm radio station.
---
--- More: <http://www.last.fm/api/show/radio.tune>
-tune :: Maybe Language -> Station -> APIKey -> SessionKey -> Secret -> Lastfm Response
-tune language station apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "radio.tune")
-  , (#) language
-  , (#) station
-  , (#) apiKey
-  , (#) sessionKey
-  ]
diff --git a/Network/Lastfm/API/Tag.hs b/Network/Lastfm/API/Tag.hs
deleted file mode 100644
--- a/Network/Lastfm/API/Tag.hs
+++ /dev/null
@@ -1,110 +0,0 @@
--- | Tag API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.Tag
-  ( getInfo, getSimilar, getTopAlbums, getTopArtists, getTopTags, getTopTracks
-  , getWeeklyArtistChart, getWeeklyChartList, search
-  ) where
-
-import Control.Monad.Error (runErrorT)
-import Network.Lastfm
-
--- | Get the metadata for a tag.
---
--- More: <http://www.last.fm/api/show/tag.getInfo>
-getInfo :: Tag -> Maybe Language -> APIKey -> Lastfm Response
-getInfo tag language apiKey = callAPI
-  [ (#) (Method "tag.getInfo")
-  , (#) tag
-  , (#) language
-  , (#) apiKey
-  ]
-
--- | Search for tags similar to this one. Returns tags ranked by similarity, based on listening data.
---
--- More: <http://www.last.fm/api/show/tag.getSimilar>
-getSimilar :: Tag -> APIKey -> Lastfm Response
-getSimilar tag apiKey = callAPI
-  [ (#) (Method "tag.getSimilar")
-  , (#) tag
-  , (#) apiKey
-  ]
-
--- | Get the top albums tagged by this tag, ordered by tag count.
---
--- More: <http://www.last.fm/api/show/tag.getTopAlbums>
-getTopAlbums :: Tag -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getTopAlbums tag page limit apiKey = callAPI
-  [ (#) (Method "tag.getTopAlbums")
-  , (#) tag
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get the top artists tagged by this tag, ordered by tag count.
---
--- More: <http://www.last.fm/api/show/tag.getTopArtists>
-getTopArtists :: Tag -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getTopArtists tag limit page apiKey = callAPI
-  [ (#) (Method "tag.getTopArtists")
-  , (#) tag
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Fetches the top global tags on Last.fm, sorted by popularity (number of times used).
---
--- More: <http://www.last.fm/api/show/tag.getTopTags>
-getTopTags :: APIKey -> Lastfm Response
-getTopTags apiKey = callAPI
-  [ (#) (Method "tag.getTopArtists")
-  , (#) apiKey
-  ]
-
--- | Get the top tracks tagged by this tag, ordered by tag count.
---
--- More: <http://www.last.fm/api/show/tag.getTopTracks>
-getTopTracks :: Tag -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getTopTracks tag limit page apiKey = callAPI
-  [ (#) (Method "tag.getTopTracks")
-  , (#) tag
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get an artist chart for a tag, for a given date range. If no date range is supplied, it will return the most recent artist chart for this tag.
---
--- More: <http://www.last.fm/api/show/tag.getWeeklyArtistChart>
-getWeeklyArtistChart :: Tag -> Maybe From -> Maybe To -> Maybe Limit -> APIKey -> Lastfm Response
-getWeeklyArtistChart tag from to limit apiKey = callAPI
-  [ (#) (Method "tag.getWeeklyArtistChart")
-  , (#) tag
-  , (#) from
-  , (#) to
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get a list of available charts for this tag, expressed as date ranges which can be sent to the chart services.
---
--- More: <http://www.last.fm/api/show/tag.getWeeklyChartList>
-getWeeklyChartList :: Tag -> APIKey -> Lastfm Response
-getWeeklyChartList tag apiKey = callAPI
-  [ (#) (Method "tag.getWeeklyChartList")
-  , (#) tag
-  , (#) apiKey
-  ]
-
--- | Search for a tag by name. Returns matches sorted by relevance.
---
--- More: <http://www.last.fm/api/show/tag.search>
-search :: Tag -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-search tag page limit apiKey = callAPI
-  [ (#) (Method "tag.search")
-  , (#) tag
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
diff --git a/Network/Lastfm/API/Tasteometer.hs b/Network/Lastfm/API/Tasteometer.hs
deleted file mode 100644
--- a/Network/Lastfm/API/Tasteometer.hs
+++ /dev/null
@@ -1,26 +0,0 @@
--- | Tasteometer API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.Tasteometer
-  ( compare
-  ) where
-
-import Control.Monad.Error (runErrorT)
-import Network.Lastfm
-import Prelude hiding (compare)
-
-(?<) :: Argument a => a -> Int -> (String, String)
-a ?< n = (key a ++ show n, value a)
-
--- | Get a Tasteometer score from two inputs, along with a list of shared artists. If the input is a User some additional information is returned.
---
--- More: <http://www.last.fm/api/show/tasteometer.compare>
-compare :: Value -> Value -> Maybe Limit -> APIKey -> Lastfm Response
-compare value1 value2 limit apiKey = callAPI
-  [ (#) (Method "tasteometer.compare")
-  , (,) "type1" (show value1)
-  , (,) "type2" (show value2)
-  , (?<) value1 1
-  , (?<) value2 2
-  , (#) limit
-  , (#) apiKey
-  ]
diff --git a/Network/Lastfm/API/Track.hs b/Network/Lastfm/API/Track.hs
deleted file mode 100644
--- a/Network/Lastfm/API/Track.hs
+++ /dev/null
@@ -1,277 +0,0 @@
--- | Track API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.Track
-  ( addTags, ban, getBuyLinks, getCorrection, getFingerprintMetadata
-  , getInfo, getShouts, getSimilar, getTags, getTopFans, getTopTags
-  , love, removeTag, scrobble, search, share, unban, unlove, updateNowPlaying
-  ) where
-
-import Control.Arrow ((|||))
-import Network.Lastfm
-
--- | Tag a track using a list of user supplied tags.
---
--- More: <http://www.last.fm/api/show/track.addTags>
-addTags :: Artist -> Track -> [Tag] -> APIKey -> SessionKey -> Secret -> Lastfm Response
-addTags artist track tags apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "track.addTags")
-  , (#) artist
-  , (#) track
-  , (#) tags
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Ban a track for a given user profile.
---
--- More: <http://www.last.fm/api/show/track.ban>
-ban :: Artist -> Track -> APIKey -> SessionKey -> Secret -> Lastfm Response
-ban artist track apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "track.ban")
-  , (#) artist
-  , (#) track
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Get a list of Buy Links for a particular track.
---
--- More: <http://www.last.fm/api/show/track.getBuylinks>
-getBuyLinks :: Either (Artist, Track) Mbid -> Maybe Autocorrect -> Country -> APIKey -> Lastfm Response
-getBuyLinks a autocorrect country apiKey = callAPI $
-  target a ++
-  [ (#) (Method "track.getBuyLinks")
-  , (#) autocorrect
-  , (#) country
-  , (#) apiKey
-  ]
-
--- | Use the last.fm corrections data to check whether the supplied track has a correction to a canonical track.
---
--- More: <http://www.last.fm/api/show/track.getCorrection>
-getCorrection :: Artist -> Track -> APIKey -> Lastfm Response
-getCorrection artist track apiKey = callAPI
-  [ (#) (Method "track.getCorrection")
-  , (#) artist
-  , (#) track
-  , (#) apiKey
-  ]
-
--- | Retrieve track metadata associated with a fingerprint id generated by the Last.fm Fingerprinter. Returns track elements, along with a 'rank' value between 0 and 1 reflecting the confidence for each match.
---
--- More: <http://www.last.fm/api/show/track.getFingerprintMetadata>
-getFingerprintMetadata :: Fingerprint -> APIKey -> Lastfm Response
-getFingerprintMetadata fingerprint apiKey = callAPI
-  [ (#) (Method "track.getFingerprintMetadata")
-  , (#) fingerprint
-  , (#) apiKey
-  ]
-
--- | Get the metadata for a track on Last.fm.
---
--- More: <http://www.last.fm/api/show/track.getInfo>
-getInfo :: Either (Artist, Track) Mbid -> Maybe Autocorrect -> Maybe Username -> APIKey -> Lastfm Response
-getInfo a autocorrect username apiKey = callAPI $
-  target a ++
-  [ (#) (Method "track.getInfo")
-  , (#) autocorrect
-  , (#) username
-  , (#) apiKey
-  ]
-
--- | Get shouts for this track. Also available as an rss feed.
---
--- More: <http://www.last.fm/api/show/track.getShouts>
-getShouts :: Either (Artist, Track) Mbid -> Maybe Autocorrect -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getShouts a autocorrect page limit apiKey = callAPI $
-  target a ++
-  [ (#) (Method "track.getShouts")
-  , (#) autocorrect
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get the similar tracks for this track on Last.fm, based on listening data.
---
--- More: <http://www.last.fm/api/show/track.getSimilar>
-getSimilar :: Either (Artist, Track) Mbid -> Maybe Autocorrect -> Maybe Limit -> APIKey -> Lastfm Response
-getSimilar a autocorrect limit apiKey = callAPI $
-  target a ++
-  [ (#) (Method "track.getSimilar")
-  , (#) autocorrect
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get the tags applied by an individual user to a track on Last.fm.
---
--- More: <http://www.last.fm/api/show/track.getTags>
-getTags :: Either (Artist, Track) Mbid -> Maybe Autocorrect -> Either User (SessionKey, Secret) -> APIKey -> Lastfm Response
-getTags a autocorrect b apiKey = case b of
-  Left user -> callAPI $ target a ++ [(#) user] ++ args
-  Right (sessionKey, secret) -> callAPIsigned secret $ target a ++ [(#) sessionKey] ++ args
-  where args =
-          [ (#) (Method "track.getTags")
-          , (#) autocorrect
-          , (#) apiKey
-          ]
-
--- | Get the top fans for this track on Last.fm, based on listening data.
---
--- More: <http://www.last.fm/api/show/track.getTopFans>
-getTopFans :: Either (Artist, Track) Mbid -> Maybe Autocorrect -> APIKey -> Lastfm Response
-getTopFans a autocorrect apiKey = callAPI $
-  target a ++
-  [ (#) (Method "track.getTopFans")
-  , (#) autocorrect
-  , (#) apiKey
-  ]
-
--- | Get the top tags for this track on Last.fm, ordered by tag count.
---
--- More: <http://www.last.fm/api/show/track.getTopTags>
-getTopTags :: Either (Artist, Track) Mbid -> Maybe Autocorrect -> APIKey -> Lastfm Response
-getTopTags a autocorrect apiKey = callAPI $
-  target a ++
-  [ (#) (Method "track.getTopTags")
-  , (#) autocorrect
-  , (#) apiKey
-  ]
-
--- | Love a track for a user profile.
---
--- More: <http://www.last.fm/api/show/track.love>
-love :: Artist -> Track -> APIKey -> SessionKey -> Secret -> Lastfm Response
-love artist track apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "track.love")
-  , (#) artist
-  , (#) track
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Remove a user's tag from a track.
---
--- More: <http://www.last.fm/api/show/track.removeTag>
-removeTag :: Artist -> Track -> Tag -> APIKey -> SessionKey -> Secret -> Lastfm Response
-removeTag artist track tag apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "track.removeTag")
-  , (#) artist
-  , (#) track
-  , (#) tag
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Used to add a track-play to a user's profile.
---
--- More; <http://www.last.fm/api/show/track.scrobble>
-scrobble :: ( Timestamp, Maybe Album, Artist, Track, Maybe AlbumArtist
-           , Maybe Duration, Maybe StreamId, Maybe ChosenByUser
-           , Maybe Context, Maybe TrackNumber, Maybe Mbid )
-         -> APIKey
-         -> SessionKey
-         -> Secret
-         -> Lastfm Response
-scrobble (timestamp, album, artist, track, albumArtist, duration, streamId, chosenByUser, context, trackNumber, mbid) apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "track.scrobble")
-  , (#) timestamp
-  , (#) artist
-  , (#) track
-  , (#) album
-  , (#) albumArtist
-  , (#) duration
-  , (#) streamId
-  , (#) chosenByUser
-  , (#) context
-  , (#) trackNumber
-  , (#) mbid
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Search for a track by track name. Returns track matches sorted by relevance.
---
--- More: <http://www.last.fm/api/show/track.search>
-search :: Track -> Maybe Page -> Maybe Limit -> Maybe Artist -> APIKey -> Lastfm Response
-search track page limit artist apiKey = callAPI
-  [ (#) (Method "track.search")
-  , (#) track
-  , (#) page
-  , (#) limit
-  , (#) artist
-  , (#) apiKey
-  ]
-
--- | Share a track twith one or more Last.fm users or other friends.
---
--- More: <http://www.last.fm/api/show/track.share>
-share :: Artist -> Track -> Recipient -> Maybe Message -> Maybe Public -> APIKey -> SessionKey -> Secret -> Lastfm Response
-share artist track recipient message public apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "track.share")
-  , (#) artist
-  , (#) track
-  , (#) recipient
-  , (#) public
-  , (#) message
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Unban a track for a user profile.
---
--- More: <http://www.last.fm/api/show/track.unban>
-unban :: Artist -> Track -> APIKey -> SessionKey -> Secret -> Lastfm Response
-unban artist track apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "track.unban")
-  , (#) artist
-  , (#) track
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Unlove a track for a user profile.
---
--- More: <http://www.last.fm/api/show/track.unlove>
-unlove :: Artist -> Track -> APIKey -> SessionKey -> Secret -> Lastfm Response
-unlove artist track apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "track.unlove")
-  , (#) artist
-  , (#) track
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
-
--- | Used to notify Last.fm that a user has started listening to a track. Parameter names are case sensitive.
---
--- More: <http://www.last.fm/api/show/track.updateNowPlaying>
-updateNowPlaying :: Artist
-                 -> Track
-                 -> Maybe Album
-                 -> Maybe AlbumArtist
-                 -> Maybe Context
-                 -> Maybe TrackNumber
-                 -> Maybe Mbid
-                 -> Maybe Duration
-                 -> APIKey
-                 -> SessionKey
-                 -> Secret
-                 -> Lastfm Response
-updateNowPlaying artist track album albumArtist context trackNumber mbid duration apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "track.updateNowPlaying")
-  , (#) artist
-  , (#) track
-  , (#) album
-  , (#) albumArtist
-  , (#) context
-  , (#) trackNumber
-  , (#) mbid
-  , (#) duration
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
-target :: Either (Artist, Track) Mbid -> [(String, String)]
-target = (\(artist, track) -> [(#) artist, (#) track]) ||| return . (#)
diff --git a/Network/Lastfm/API/User.hs b/Network/Lastfm/API/User.hs
deleted file mode 100644
--- a/Network/Lastfm/API/User.hs
+++ /dev/null
@@ -1,321 +0,0 @@
--- | User API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.User
-  ( getArtistTracks, getBannedTracks, getEvents, getFriends, getInfo, getLovedTracks
-  , getNeighbours, getNewReleases, getPastEvents, getPersonalTags, getPlaylists, getRecentStations
-  , getRecentTracks, getRecommendedArtists, getRecommendedEvents, getShouts, getTopAlbums
-  , getTopArtists, getTopTags, getTopTracks, getWeeklyAlbumChart, getWeeklyArtistChart
-  , getWeeklyChartList, getWeeklyTrackChart, shout
-  ) where
-
-import Control.Monad.Error (runErrorT)
-import Network.Lastfm
-
--- | Get a list of tracks by a given artist scrobbled by this user, including scrobble time. Can be limited to specific timeranges, defaults to all time.
---
--- More: <http://www.last.fm/api/show/user.getArtistTracks>
-getArtistTracks :: User -> Artist -> Maybe StartTimestamp -> Maybe EndTimestamp -> Maybe Page -> APIKey -> Lastfm Response
-getArtistTracks user artist startTimestamp endTimestamp page apiKey = callAPI
-  [ (#) (Method "user.getArtistTracks")
-  , (#) user
-  , (#) artist
-  , (#) startTimestamp
-  , (#) page
-  , (#) endTimestamp
-  , (#) apiKey
-  ]
-
--- | Returns the tracks banned by the user.
---
--- More: <http://www.last.fm/api/show/user.getBannedTracks>
-getBannedTracks :: User -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getBannedTracks user page limit apiKey = callAPI
-  [ (#) (Method "user.getBannedTracks")
-  , (#) user
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get a list of upcoming events that this user is attending.
---
--- Mpre: <http://www.last.fm/api/show/user.getEvents>
-getEvents :: User -> Maybe Page -> Maybe Limit -> Maybe FestivalsOnly -> APIKey -> Lastfm Response
-getEvents user page limit festivalsOnly apiKey = callAPI
-  [ (#) (Method "user.getEvents")
-  , (#) user
-  , (#) page
-  , (#) limit
-  , (#) festivalsOnly
-  , (#) apiKey
-  ]
-
--- | Get a list of the user's friends on Last.fm.
---
--- More: <http://www.last.fm/api/show/user.getFriends>
-getFriends :: User -> Maybe RecentTracks -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getFriends user recentTracks page limit apiKey = callAPI
-  [ (#) (Method "user.getFriends")
-  , (#) user
-  , (#) recentTracks
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get information about a user profile.
---
--- More: <http://www.last.fm/api/show/user.getInfo>
-getInfo :: Maybe User -> APIKey -> Lastfm Response
-getInfo user apiKey = callAPI
-  [ (#) (Method "user.getInfo")
-  , (#) user
-  , (#) apiKey
-  ]
-
--- | Get tracks loved by a user.
---
--- More: <http://www.last.fm/api/show/user.getLovedTracks>
-getLovedTracks :: User -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getLovedTracks user page limit apiKey = callAPI
-  [ (#) (Method "user.getLovedTracks")
-  , (#) user
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get a list of a user's neighbours on Last.fm.
---
--- More: <http://www.last.fm/api/show/user.getNeighbours>
-getNeighbours :: User -> Maybe Limit -> APIKey -> Lastfm Response
-getNeighbours user limit apiKey = callAPI
-  [ (#) (Method "user.getNeighbours")
-  , (#) user
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Gets a list of forthcoming releases based on a user's musical taste.
---
--- More: <http://www.last.fm/api/show/user.getNewReleases>
-getNewReleases :: User -> Maybe UseRecs -> APIKey -> Lastfm Response
-getNewReleases user useRecs apiKey = callAPI
-  [ (#) (Method "user.getNewReleases")
-  , (#) user
-  , (#) useRecs
-  , (#) apiKey
-  ]
-
--- | Get a paginated list of all events a user has attended in the past.
---
--- More: <http://www.last.fm/api/show/user.getPastEvents>
-getPastEvents :: User -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getPastEvents user page limit apiKey = callAPI
-  [ (#) (Method "user.getPastEvents")
-  , (#) user
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get the user's personal tags.
---
--- More: <http://www.last.fm/api/show/user.getPersonalTags>
-getPersonalTags :: User
-                -> Tag
-                -> TaggingType
-                -> Maybe Page
-                -> Maybe Limit
-                -> APIKey
-                -> Lastfm Response
-getPersonalTags user tag taggingType page limit apiKey = callAPI
-  [ (#) (Method "user.getPersonalTags")
-  , (#) user
-  , (#) tag
-  , (#) taggingType
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get a list of a user's playlists on Last.fm.
---
--- More: <http://www.last.fm/api/show/user.getPlaylists>
-getPlaylists :: User -> APIKey -> Lastfm Response
-getPlaylists user apiKey = callAPI
-  [ (#) (Method "user.getPlaylists")
-  , (#) user
-  , (#) apiKey
-  ]
-
--- | Get a list of the recent Stations listened to by this user.
---
--- More: <http://www.last.fm/api/show/user.getRecentStations>
-getRecentStations :: User -> Maybe Page -> Maybe Limit -> APIKey -> SessionKey -> Secret -> Lastfm Response
-getRecentStations user page limit apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "user.getRecentStations")
-  , (#) user
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Get a list of the recent tracks listened to by this user. Also includes the currently playing track with the nowplaying="true" attribute if the user is currently listening.
---
--- More: <http://www.last.fm/api/show/user.getRecentTracks>
-getRecentTracks :: User -> Maybe Page -> Maybe Limit -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
-getRecentTracks user page limit from to apiKey = callAPI
-  [ (#) (Method "user.getRecentTracks")
-  , (#) user
-  , (#) page
-  , (#) limit
-  , (#) from
-  , (#) to
-  , (#) apiKey
-  ]
-
--- | Get Last.fm artist recommendations for a user.
---
--- Mpre: <http://www.last.fm/api/show/user.getRecommendedArtists>
-getRecommendedArtists :: Maybe Page -> Maybe Limit -> APIKey -> SessionKey -> Secret -> Lastfm Response
-getRecommendedArtists page limit apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "user.getRecommendedArtists")
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Get a paginated list of all events recommended to a user by Last.fm, based on their listening profile.
---
--- More: <http://www.last.fm/api/show/user.getRecommendedEvents>
-getRecommendedEvents :: Maybe Page -> Maybe Limit -> APIKey -> SessionKey -> Secret -> Lastfm Response
-getRecommendedEvents page limit apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "user.getRecommendedEvents")
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  , (#) sessionKey
-  ]
-
--- | Get shouts for this user. Also available as an rss feed.
---
--- More: <http://www.last.fm/api/show/user.getShouts>
-getShouts :: User -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getShouts user page limit apiKey = callAPI
-  [ (#) (Method "user.getShouts")
-  , (#) user
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get the top albums listened to by a user. You can stipulate a time period. Sends the overall chart by default.
---
--- More: <http://www.last.fm/api/show/user.getTopAlbums>
-getTopAlbums :: User -> Maybe Period -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getTopAlbums user period page limit apiKey = callAPI
-  [ (#) (Method "user.getTopAlbums")
-  , (#) user
-  , (#) period
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get the top artists listened to by a user. You can stipulate a time period. Sends the overall chart by default.
---
--- More: <http://www.last.fm/api/show/user.getTopArtists>
-getTopArtists :: User -> Maybe Period -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getTopArtists user period page limit apiKey = callAPI
-  [ (#) (Method "user.getTopArtists")
-  , (#) user
-  , (#) period
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get the top tags used by this user.
---
--- More: <http://www.last.fm/api/show/user.getTopTags>
-getTopTags :: User -> Maybe Limit -> APIKey -> Lastfm Response
-getTopTags user limit apiKey = callAPI
-  [ (#) (Method "user.getTopTags")
-  , (#) user
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get the top tracks listened to by a user. You can stipulate a time period. Sends the overall chart by default.
---
--- More: <http://www.last.fm/api/show/user.getTopTracks>
-getTopTracks :: User -> Maybe Period -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getTopTracks user period page limit apiKey = callAPI
-  [ (#) (Method "user.getTopTracks")
-  , (#) user
-  , (#) period
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Get an album chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent album chart for this user.
---
--- More: <http://www.last.fm/api/show/user.getWeeklyAlbumChart>
-getWeeklyAlbumChart :: User -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
-getWeeklyAlbumChart user from to apiKey = callAPI
-  [ (#) (Method "user.getWeeklyAlbumChart")
-  , (#) user
-  , (#) from
-  , (#) to
-  , (#) apiKey
-  ]
-
--- | Get an artist chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent artist chart for this user.
---
--- More: <http://www.last.fm/api/show/user.getWeeklyArtistChart>
-getWeeklyArtistChart :: User -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
-getWeeklyArtistChart user from to apiKey = callAPI
-  [ (#) (Method "user.getWeeklyArtistChart")
-  , (#) user
-  , (#) from
-  , (#) to
-  , (#) apiKey
-  ]
-
--- | Get a list of available charts for this user, expressed as date ranges which can be sent to the chart services.
---
--- More: <http://www.last.fm/api/show/user.getWeeklyChartList>
-getWeeklyChartList :: User -> APIKey -> Lastfm Response
-getWeeklyChartList user apiKey = callAPI
-  [ (#) (Method "user.getWeeklyChartList")
-  , (#) user
-  , (#) apiKey
-  ]
-
--- | Get a track chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent track chart for this user.
---
--- More: <http://www.last.fm/api/show/user.getWeeklyTrackChart>
-getWeeklyTrackChart :: User -> Maybe From -> Maybe To -> APIKey -> Lastfm Response
-getWeeklyTrackChart user from to apiKey = callAPI
-  [ (#) (Method "user.getWeeklyTrackChart")
-  , (#) user
-  , (#) from
-  , (#) to
-  , (#) apiKey
-  ]
-
--- | Shout on this user's shoutbox.
---
--- More: <http://www.last.fm/api/show/user.shout>
-shout :: User -> Message -> APIKey -> SessionKey -> Secret -> Lastfm Response
-shout user message apiKey sessionKey secret = callAPIsigned secret
-  [ (#) (Method "user.shout")
-  , (#) user
-  , (#) message
-  , (#) apiKey
-  , (#) sessionKey
-  ]
diff --git a/Network/Lastfm/API/Venue.hs b/Network/Lastfm/API/Venue.hs
deleted file mode 100644
--- a/Network/Lastfm/API/Venue.hs
+++ /dev/null
@@ -1,45 +0,0 @@
--- | Venue API module
-{-# OPTIONS_HADDOCK prune #-}
-module Network.Lastfm.API.Venue
-  ( getEvents, getPastEvents, search
-  ) where
-
-import Control.Monad.Error (runErrorT)
-import Network.Lastfm
-
--- | Get a list of upcoming events at this venue.
---
--- More: <http://www.last.fm/api/show/venue.getEvents>
-getEvents :: Venue -> Maybe FestivalsOnly -> APIKey -> Lastfm Response
-getEvents venue festivalsOnly apiKey = callAPI
-  [ (#) (Method "venue.getEvents")
-  , (#) venue
-  , (#) festivalsOnly
-  , (#) apiKey
-  ]
-
--- | Get a paginated list of all the events held at this venue in the past.
---
--- More: <http://www.last.fm/api/show/venue.getPastEvents>
-getPastEvents :: Venue -> Maybe FestivalsOnly -> Maybe Page -> Maybe Limit -> APIKey -> Lastfm Response
-getPastEvents venue festivalsOnly page limit apiKey = callAPI
-  [ (#) (Method "venue.getPastEvents")
-  , (#) venue
-  , (#) festivalsOnly
-  , (#) page
-  , (#) limit
-  , (#) apiKey
-  ]
-
--- | Search for a venue by venue name.
---
--- More: <http://www.last.fm/api/show/venue.search>
-search :: Venuename -> Maybe Page -> Maybe Limit -> Maybe Country -> APIKey -> Lastfm Response
-search venue page limit country apiKey = callAPI
-  [ (#) (Method "venue.search")
-  , (#) venue
-  , (#) page
-  , (#) limit
-  , (#) country
-  , (#) apiKey
-  ]
diff --git a/Network/Lastfm/Types.hs b/Network/Lastfm/Types.hs
deleted file mode 100644
--- a/Network/Lastfm/Types.hs
+++ /dev/null
@@ -1,253 +0,0 @@
-{-# LANGUAGE FlexibleInstances, OverlappingInstances, TypeSynonymInstances #-}
-module Network.Lastfm.Types where
-
-import Control.Monad.Error (Error)
-import Data.List (intercalate)
-
-newtype Secret = Secret String deriving Show
-
-(#) :: Argument a => a -> (String, String)
-(#) x = (key x, value x)
-
-class Argument a where
-  key :: a -> String
-  value :: a -> String
-
-instance Argument a => Argument (Maybe a) where key = maybe "" key; value = maybe "" value
-instance Argument a => Argument [a] where
-  key (a:_) = key a ++ "s"
-  key [] = ""
-  value = intercalate "," . map value
-
-newtype Album = Album String
-newtype AlbumArtist = AlbumArtist String
-newtype APIKey = APIKey String
-newtype Artist = Artist String
-newtype AuthToken = AuthToken String
-newtype ChosenByUser = ChosenByUser String
-newtype Context = Context String
-newtype Country = Country String
-newtype Description = Description String
-newtype Group = Group String
-newtype Language = Language String
-newtype Latitude = Latitude String
-newtype Location = Location String
-newtype Longitude = Longitude String
-newtype Mbid = Mbid String
-newtype Message = Message String
-newtype Method = Method String
-newtype Metro = Metro String
-newtype Name = Name String
-newtype Recipient = Recipient String
-newtype SessionKey = SessionKey String
-newtype Station = Station String
-newtype StreamId = StreamId String
-newtype Tag = Tag String
-newtype TaggingType = TaggingType String
-newtype Title = Title String
-newtype Token = Token String
-newtype Track = Track String
-newtype User = User String
-newtype Username = Username String
-newtype Venuename = Venuename String
-instance Argument Album where key = const "album"; value (Album a) = a
-instance Argument AlbumArtist where key = const "albumartist"; value (AlbumArtist a) = a
-instance Argument APIKey where key = const "api_key"; value (APIKey a) = a
-instance Argument Artist where key = const "artist"; value (Artist a) = a
-instance Argument AuthToken where key = const "authToken"; value (AuthToken a) = a
-instance Argument ChosenByUser where key = const "chosenByUser"; value (ChosenByUser a) = a
-instance Argument Context where key = const "context"; value (Context a) = a
-instance Argument Country where key = const "country"; value (Country a) = a
-instance Argument Description where key = const "description"; value (Description a) = a
-instance Argument Group where key = const "group"; value (Group a) = a
-instance Argument Language where key = const "lang"; value (Language a) = a
-instance Argument Latitude where key = const "lat"; value (Latitude a) = a
-instance Argument Location where key = const "location"; value (Location a) = a
-instance Argument Longitude where key = const "long"; value (Longitude a) = a
-instance Argument Mbid where key = const "mbid"; value (Mbid a) = a
-instance Argument Message where key = const "message"; value (Message a) = a
-instance Argument Method where key = const "method"; value (Method a) = a
-instance Argument Metro where key = const "metro"; value (Metro a) = a
-instance Argument Name where key = const "name"; value (Name a) = a
-instance Argument Recipient where key = const "recipient"; value (Recipient a) = a
-instance Argument SessionKey where key = const "sk"; value (SessionKey a) = a
-instance Argument Station where key = const "station"; value (Station a) = a
-instance Argument StreamId where key = const "streamId"; value (StreamId a) = a
-instance Argument Tag where key = const "tag"; value (Tag a) = a
-instance Argument TaggingType where key = const "taggingtype"; value (TaggingType a) = a
-instance Argument Title where key = const "title"; value (Title a) = a
-instance Argument Token where key = const "token"; value (Token a) = a
-instance Argument Track where key = const "track"; value (Track a) = a
-instance Argument User where key = const "user"; value (User a) = a
-instance Argument Username where key = const "username"; value (Username a) = a
-instance Argument Venuename where key = const "venue"; value (Venuename a) = a
-
-boolToString :: Bool -> String
-boolToString True = "1"
-boolToString False = "0"
-
-newtype Autocorrect = Autocorrect Bool
-newtype BuyLinks = BuyLinks Bool
-newtype Discovery = Discovery Bool
-newtype FestivalsOnly = FestivalsOnly Bool
-newtype Public = Public Bool
-newtype RecentTracks = RecentTracks Bool
-newtype RTP = RTP Bool
-newtype UseRecs = UseRecs Bool
-instance Argument Autocorrect where key = const "autocorrect"; value (Autocorrect a) = boolToString a
-instance Argument BuyLinks where key = const "buylinks"; value (BuyLinks a) = boolToString a
-instance Argument Discovery where key = const "discovery"; value (Discovery a) = boolToString a
-instance Argument FestivalsOnly where key = const "festivalsonly"; value (FestivalsOnly a) = boolToString a
-instance Argument Public where key = const "public"; value (Public a) = boolToString a
-instance Argument RecentTracks where key = const "recenttracks"; value (RecentTracks a) = boolToString a
-instance Argument RTP where key = const "rtp"; value (RTP a) = boolToString a
-instance Argument UseRecs where key = const "userecs"; value (UseRecs a) = boolToString a
-
-newtype Distance = Distance Int
-newtype Duration = Duration Int
-newtype Event = Event Int
-newtype Limit = Limit Int
-newtype Page = Page Int
-newtype Playlist = Playlist Int
-newtype TrackNumber = TrackNumber Int
-newtype Venue = Venue Int
-instance Argument Distance where key = const "distance"; value (Distance a) = show a
-instance Argument Duration where key = const "duration"; value (Duration a) = show a
-instance Argument Event where key = const "event"; value (Event a) = show a
-instance Argument Limit where key = const "limit"; value (Limit a) = show a
-instance Argument Page where key = const "page"; value (Page a) = show a
-instance Argument Playlist where key = const "playlistID"; value (Playlist a) = show a
-instance Argument TrackNumber where key = const "tracknumber"; value (TrackNumber a) = show a
-instance Argument Venue where key = const "venue"; value (Venue a) = show a
-
-newtype End = End Integer
-newtype EndTimestamp = EndTimestamp Integer
-newtype Fingerprint = Fingerprint Integer
-newtype From = From Integer
-newtype Start = Start Integer
-newtype StartTimestamp = StartTimestamp Integer
-newtype Timestamp = Timestamp Integer
-newtype To = To Integer
-instance Argument End where key = const "end"; value (End a) = show a
-instance Argument EndTimestamp where key = const "endTimestamp"; value (EndTimestamp a) = show a
-instance Argument Fingerprint where key = const "fingerprintid"; value (Fingerprint a) = show a
-instance Argument From where key = const "from"; value (From a) = show a
-instance Argument Start where key = const "start"; value (Start a) = show a
-instance Argument StartTimestamp where key = const "startTimestamp"; value (StartTimestamp a) = show a
-instance Argument Timestamp where key = const "timestamp"; value (Timestamp a) = show a
-instance Argument To where key = const "to"; value (To a) = show a
-
-data Bitrate = B64 | B128
-
-instance Argument Bitrate where
-  key = const "bitrate"
-  value B64 = "64"
-  value B128 = "128"
-
-data Multiplier = M1 | M2
-instance Argument Multiplier where
-  key = const "speed_multiplier"
-  value M1 = "1.0"
-  value M2 = "2.0"
-
-data Order = Popularity | DateAdded
-instance Argument Order where
-  key = const "order"
-  value Popularity = "popularity"
-  value DateAdded  = "dateadded"
-
-data Status = Yes | Maybe | No
-instance Argument Status where
-  key = const "status"
-  value Yes = "0"
-  value Maybe = "1"
-  value No = "2"
-
-data Value = ValueUser User
-           | ValueArtists [Artist]
-instance Show Value where
-  show (ValueUser _)    = "user"
-  show (ValueArtists _) = "artists"
-instance Argument Value where
-  key = const "value"
-  value (ValueUser u)     = value u
-  value (ValueArtists as) = value as
-
-data Period = Week | Quater | HalfYear | Year | Overall
-instance Argument Period where
-  key = const "period"
-  value Week     = "7day"
-  value Quater   = "3month"
-  value HalfYear = "6month"
-  value Year     = "12month"
-  value Overall  = "overall"
-
-data APIError
-  = DoesntExist
-  | InvalidService
-  | InvalidMethod
-  | AuthenticationFailed
-  | InvalidFormat
-  | InvalidParameters
-  | InvalidResource
-  | OperationFailed
-  | InvalidSessionKey
-  | InvalidAPIKey
-  | ServiceOffline
-  | SubscribersOnly
-  | InvalidMethodSignature
-  | TokenHasNotAuthorized
-  | NotForStreaming
-  | TemporaryUnavailable
-  | LoginRequired
-  | TrialExpired
-  | DoesntExistAgain
-  | NotEnoughContent
-  | NotEnoughMembers
-  | NotEnoughFans
-  | NotEnoughNeighbours
-  | NoPeakRadio
-  | RadioNotFound
-  | SuspendedAPIKey
-  | Deprecated
-  | RateLimitExceeded
-    deriving (Enum)
-
-instance Show APIError where
-  show DoesntExist = "DoesntExist: This error does not exist"
-  show InvalidService = "InvalidService: This service does not exist"
-  show InvalidMethod = "InvalidMethod: No method with that name in this package"
-  show AuthenticationFailed = "AuthenticationFailed: You do not have permissions to access the service"
-  show InvalidFormat = "InvalidFormat: This service doesn't exist in that format"
-  show InvalidParameters = "InvalidParameters: Your request is missing a required parameter"
-  show InvalidResource = "InvalidResource: Invalid resource specified"
-  show OperationFailed = "OperationFailed: Something else went wrong"
-  show InvalidSessionKey = "InvalidSessionKey: Please re-authenticate"
-  show InvalidAPIKey = "InvalidAPIKey: You must be granted a valid key by last.fm"
-  show ServiceOffline = "ServiceOffline: This service is temporarily offline. Try again later."
-  show SubscribersOnly  = "SubscribersOnly : This station is only available to paid last.fm subscribers"
-  show InvalidMethodSignature = "InvalidMethodSignature: Invalid method signature supplied"
-  show TokenHasNotAuthorized = "TokenHasNotAuthorized: This token has not been authorized"
-  show NotForStreaming = "NotForStreaming: This item is not available for streaming."
-  show TemporaryUnavailable = "TemporaryUnavailable: The service is temporarily unavailable, please try again."
-  show LoginRequired = "LoginRequired: Login: User requires to be logged in"
-  show TrialExpired = "TrialExpired: This user has no free radio plays left. Subscription required."
-  show DoesntExistAgain = "DoesntExistAgain: This error does not exist"
-  show NotEnoughContent = "NotEnoughContent: There is not enough content to play this station"
-  show NotEnoughMembers = "NotEnoughMembers: This group does not have enough members for radio"
-  show NotEnoughFans = "NotEnoughFans: This artist does not have enough fans for for radio"
-  show NotEnoughNeighbours = "NotEnoughNeighbours: There are not enough neighbours for radio"
-  show NoPeakRadio = "NoPeakRadio: This user is not allowed to listen to radio during peak usage"
-  show RadioNotFound = "RadioNotFound: Radio station not found"
-  show SuspendedAPIKey = "SuspendedAPIKey: Access for your account has been suspended, please contact Last.fm"
-  show Deprecated = "Deprecated: This type of request is no longer supported"
-  show RateLimitExceeded = "RateLimitExceeded: Your IP has made too many requests in a short period"
-
--- Various Lastfm errors.
-data LastfmError
-  = LastfmAPIError APIError -- ^ Internal Lastfm errors
-  | WrapperCallError String String -- ^ Wrapper errors
-    deriving Show
-
-instance Error LastfmError
-
diff --git a/liblastfm.cabal b/liblastfm.cabal
--- a/liblastfm.cabal
+++ b/liblastfm.cabal
@@ -1,19 +1,52 @@
 Name: liblastfm
-Version: 0.0.2.2
-Description: Wrapper to Lastfm API
+Version: 0.0.3.0
+Synopsis: Wrapper to Lastfm API
 License: MIT
 License-file: LICENSE
 Author: Matvey Aksenov, Dmitry Malikov
 Maintainer: Matvey Aksenov <matvey.aksenov@gmail.com>
 Category: Network
-Synopsis: Wrapper to Lastfm API
+Description: Simple but complete wrapper to Lastfm API. Can send some stuff and receive reponses from Lastfm. JSON/XML parsing is an exercise for the user.
 Cabal-Version: >= 1.6
 Build-Type: Simple
 
 Library
-  Build-Depends: base >= 3 && < 5, bytestring, mtl, curl, pureMD5, urlencoded, xml, utf8-string
+  Build-Depends: base >= 3 && < 5, template-haskell == 2.7.*, bytestring == 0.9.*, mtl == 2.*, curl == 1.3.7, pureMD5 == 2.1.*, urlencoded == 0.3.*, aeson == 0.6.*, xml == 1.3.12, utf8-string == 0.3.*
+  HS-Source-Dirs: src
   Exposed-Modules: Network.Lastfm
+                   Network.Lastfm.JSON.Album
+                   Network.Lastfm.JSON.Artist
+                   Network.Lastfm.JSON.Auth
+                   Network.Lastfm.JSON.Chart
+                   Network.Lastfm.JSON.Event
+                   Network.Lastfm.JSON.Geo
+                   Network.Lastfm.JSON.Group
+                   Network.Lastfm.JSON.Library
+                   Network.Lastfm.JSON.Playlist
+                   Network.Lastfm.JSON.Radio
+                   Network.Lastfm.JSON.Tag
+                   Network.Lastfm.JSON.Tasteometer
+                   Network.Lastfm.JSON.Track
+                   Network.Lastfm.JSON.User
+                   Network.Lastfm.JSON.Venue
+                   Network.Lastfm.XML.Album
+                   Network.Lastfm.XML.Artist
+                   Network.Lastfm.XML.Auth
+                   Network.Lastfm.XML.Chart
+                   Network.Lastfm.XML.Event
+                   Network.Lastfm.XML.Geo
+                   Network.Lastfm.XML.Group
+                   Network.Lastfm.XML.Library
+                   Network.Lastfm.XML.Playlist
+                   Network.Lastfm.XML.Radio
+                   Network.Lastfm.XML.Tag
+                   Network.Lastfm.XML.Tasteometer
+                   Network.Lastfm.XML.Track
+                   Network.Lastfm.XML.User
+                   Network.Lastfm.XML.Venue
+  Other-Modules:   Network.Lastfm.TH
                    Network.Lastfm.Types
+                   Network.Lastfm.Error
                    Network.Lastfm.API.Album
                    Network.Lastfm.API.Artist
                    Network.Lastfm.API.Auth
@@ -29,6 +62,8 @@
                    Network.Lastfm.API.Track
                    Network.Lastfm.API.User
                    Network.Lastfm.API.Venue
+  Extensions: UnicodeSyntax
+  GHC-Options: -Wall
 
 source-repository head
   type:     git
diff --git a/src/Network/Lastfm.hs b/src/Network/Lastfm.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm.hs
@@ -0,0 +1,73 @@
+{-# LANGUAGE ScopedTypeVariables, TemplateHaskell #-}
+-- | Response module
+{-# OPTIONS_HADDOCK not-home #-}
+module Network.Lastfm
+  ( Lastfm, Response, ResponseType(..)
+  , callAPI, callAPIsigned
+  , xml, json
+  , module Network.Lastfm.Types
+  ) where
+
+import Codec.Binary.UTF8.String (encodeString)
+import Control.Applicative ((<$>))
+import Control.Arrow (second)
+import Data.ByteString.Lazy.Char8 (ByteString)
+import Data.Digest.Pure.MD5 (md5)
+import Data.Function (on)
+import Data.List (sortBy)
+import Data.URLEncoded (urlEncode, export)
+import Language.Haskell.TH
+import Network.Curl
+import Network.Lastfm.Error
+import Network.Lastfm.Types
+import qualified Data.ByteString.Lazy.Char8 as BS
+
+-- | Type synonym for Lastfm response or error.
+type Lastfm a = IO (Either LastfmError a)
+-- | Type synonym for Lastfm response
+type Response = ByteString
+-- | Desired type of Lastfm response
+data ResponseType = XML | JSON
+
+-- | Low level function. Sends POST query to Lastfm API.
+callAPI ∷ ResponseType → [(String, String)] → Lastfm Response
+callAPI t = query (parseError t) . insertType t . map (second encodeString)
+
+-- | Low level function. Sends signed POST query to Lastfm API.
+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 = curlResponse xs >>= \r →
+  return $ case γ r of
+    Just n → Left n
+    Nothing → Right r
+
+curlResponse ∷ [(String, String)] → IO ByteString
+curlResponse xs = withCurlDo $
+  respBody <$> (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"
+    ] ∷ IO (CurlResponse_ [(String, String)] ByteString))
+
+xml ∷ [String] → Q [Dec]
+xml = mapM func
+  where func xs = funD (mkName xs) [clause [] (normalB $ appE (varE (mkName ("API." ++ xs))) [e| XML |]) []]
+
+json ∷ [String] → Q [Dec]
+json = mapM func
+  where func xs = funD (mkName xs) [clause [] (normalB $ appE (varE (mkName ("API." ++ xs))) [e| JSON |]) []]
diff --git a/src/Network/Lastfm/API/Album.hs b/src/Network/Lastfm/API/Album.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/Album.hs
@@ -0,0 +1,98 @@
+module Network.Lastfm.API.Album
+  ( addTags, getBuyLinks, getInfo, getShouts, getTags
+  , getTopTags, removeTag, search, share
+  ) where
+
+import Control.Arrow ((|||))
+import Network.Lastfm
+
+addTags ∷ ResponseType → (Artist, Album) → [Tag] → APIKey → SessionKey → Secret → Lastfm Response
+addTags t (artist, album) tags apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "album.addTags")
+  , (#) artist
+  , (#) album
+  , (#) tags
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+getBuyLinks ∷ ResponseType → Either (Artist, Album) Mbid → Maybe Autocorrect → Country → APIKey → Lastfm Response
+getBuyLinks t a autocorrect country apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "album.getBuyLinks")
+  , (#) autocorrect
+  , (#) country
+  , (#) apiKey
+  ]
+
+getInfo ∷ ResponseType → Either (Artist, Album) Mbid → Maybe Autocorrect → Maybe Language → Maybe Username → APIKey → Lastfm Response
+getInfo t a autocorrect lang username apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "album.getInfo")
+  , (#) autocorrect
+  , (#) lang
+  , (#) username
+  , (#) apiKey
+  ]
+
+getShouts ∷ ResponseType → Either (Artist, Album) Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getShouts t a autocorrect page limit apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "album.getShouts")
+  , (#) autocorrect
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getTags ∷ ResponseType → Either (Artist, Album) Mbid → Maybe Autocorrect → Either User (SessionKey, Secret) → APIKey → Lastfm Response
+getTags t a autocorrect b apiKey = case b of
+  Left user → callAPI t $ target a ++ [(#) user] ++ args
+  Right (sessionKey, secret) → callAPIsigned t secret $ target a ++ [(#) sessionKey] ++ args
+  where args =
+          [ (#) (Method "album.getTags")
+          , (#) autocorrect
+          , (#) apiKey
+          ]
+
+getTopTags ∷ ResponseType → Either (Artist, Album) Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+getTopTags t a autocorrect apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "album.getTopTags")
+  , (#) autocorrect
+  , (#) apiKey
+  ]
+
+removeTag ∷ ResponseType → Artist → Album → Tag → APIKey → SessionKey → Secret → Lastfm Response
+removeTag t artist album tag apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "album.removeTag")
+  , (#) artist
+  , (#) album
+  , (#) tag
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+search ∷ ResponseType → Album → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+search t album page limit apiKey = callAPI t
+  [ (#) (Method "album.search")
+  , (#) album
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+share ∷ ResponseType → Artist → Album → Recipient → Maybe Message → Maybe Public → APIKey → SessionKey → Secret → Lastfm Response
+share t artist album recipient message public apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "album.share")
+  , (#) artist
+  , (#) album
+  , (#) public
+  , (#) message
+  , (#) recipient
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+target ∷ Either (Artist, Album) Mbid → [(String, String)]
+target = (\(artist, album) → [(#) artist, (#) album]) ||| return . (#)
diff --git a/src/Network/Lastfm/API/Artist.hs b/src/Network/Lastfm/API/Artist.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/Artist.hs
@@ -0,0 +1,180 @@
+module Network.Lastfm.API.Artist
+  ( addTags, getCorrection, getEvents, getImages, getInfo
+  , getPastEvents, getPodcast, getShouts, getSimilar, getTags, getTopAlbums
+  , getTopFans, getTopTags, getTopTracks, removeTag, search, share, shout
+  ) where
+
+import Control.Arrow ((|||))
+import Network.Lastfm
+
+addTags ∷ ResponseType → Artist → [Tag] → APIKey → SessionKey → Secret → Lastfm Response
+addTags t artist tags apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "artist.addTags")
+  , (#) artist
+  , (#) tags
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+getCorrection ∷ ResponseType → Artist → APIKey → Lastfm Response
+getCorrection t artist apiKey = callAPI t
+  [ (#) (Method "artist.getCorrection")
+  , (#) artist
+  , (#) apiKey
+  ]
+
+getEvents ∷ ResponseType → Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → Maybe FestivalsOnly → APIKey → Lastfm Response
+getEvents t a autocorrect page limit festivalsOnly apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "artist.getEvents")
+  , (#) autocorrect
+  , (#) page
+  , (#) limit
+  , (#) festivalsOnly
+  , (#) apiKey
+  ]
+
+getImages ∷ ResponseType → Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → Maybe Order → APIKey → Lastfm Response
+getImages t a autocorrect page limit order apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "artist.getImages")
+  , (#) autocorrect
+  , (#) page
+  , (#) limit
+  , (#) order
+  , (#) apiKey
+  ]
+
+getInfo ∷ ResponseType → Either Artist Mbid → Maybe Autocorrect → Maybe Language → Maybe Username → APIKey → Lastfm Response
+getInfo t a autocorrect language username apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "artist.getInfo")
+  , (#) autocorrect
+  , (#) language
+  , (#) username
+  , (#) apiKey
+  ]
+
+getPastEvents ∷ ResponseType → Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getPastEvents t a autocorrect page limit apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "artist.getPastEvents")
+  , (#) autocorrect
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getPodcast ∷ ResponseType → Either Artist Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+getPodcast t a autocorrect apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "artist.getPodcast")
+  , (#) autocorrect
+  , (#) apiKey
+  ]
+
+getShouts ∷ ResponseType → Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getShouts t a autocorrect page limit apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "artist.getShouts")
+  , (#) autocorrect
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getSimilar ∷ ResponseType → Either Artist Mbid → Maybe Autocorrect → Maybe Limit → APIKey → Lastfm Response
+getSimilar t a autocorrect limit apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "artist.getSimilar")
+  , (#) autocorrect
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getTags ∷ ResponseType → Either Artist Mbid → Maybe Autocorrect → Either User (SessionKey, Secret) → APIKey → Lastfm Response
+getTags t a autocorrect b apiKey = case b of
+  Left user → callAPI t $ target a ++ [(#) user] ++ args
+  Right (sessionKey, secret) → callAPIsigned t secret $ target a ++ [(#) sessionKey] ++ args
+  where args =
+          [ (#) (Method "artist.getTags")
+          , (#) autocorrect
+          , (#) apiKey
+          ]
+
+getTopAlbums ∷ ResponseType → Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getTopAlbums t a autocorrect page limit apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "artist.getTopAlbums")
+  , (#) autocorrect
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getTopFans ∷ ResponseType → Either Artist Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+getTopFans t a autocorrect apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "artist.getTopFans")
+  , (#) autocorrect
+  , (#) apiKey
+  ]
+
+getTopTags ∷ ResponseType → Either Artist Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+getTopTags t a autocorrect apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "artist.getTopTags")
+  , (#) autocorrect
+  , (#) apiKey
+  ]
+
+getTopTracks ∷ ResponseType → Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getTopTracks t a autocorrect page limit apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "artist.getTopTracks")
+  , (#) autocorrect
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+removeTag ∷ ResponseType → Artist → Tag → APIKey → SessionKey → Secret → Lastfm Response
+removeTag t artist tag apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "artist.removeTag")
+  , (#) artist
+  , (#) tag
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+search ∷ ResponseType → Artist → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+search t artist page limit apiKey = callAPI t
+  [ (#) (Method "artist.search")
+  , (#) artist
+  , (#) apiKey
+  , (#) page
+  , (#) limit
+  ]
+
+share ∷ ResponseType → Artist → Recipient → Maybe Message → Maybe Public → APIKey → SessionKey → Secret → Lastfm Response
+share t artist recipient message public apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "artist.share")
+  , (#) artist
+  , (#) recipient
+  , (#) apiKey
+  , (#) sessionKey
+  , (#) public
+  , (#) message
+  ]
+
+shout ∷ ResponseType → Artist → Message → APIKey → SessionKey → Secret → Lastfm Response
+shout t artist message apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "artist.shout")
+  , (#) artist
+  , (#) message
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+target ∷ Either Artist Mbid → [(String, String)]
+target = return . (#) ||| return . (#)
diff --git a/src/Network/Lastfm/API/Auth.hs b/src/Network/Lastfm/API/Auth.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/Auth.hs
@@ -0,0 +1,19 @@
+module Network.Lastfm.API.Auth
+  ( getMobileSession, getSession, getToken
+  , getAuthorizeTokenLink
+  ) where
+
+import Data.Functor ((<$>))
+import Network.Lastfm
+
+getMobileSession ∷ Username → APIKey → AuthToken → Lastfm SessionKey
+getMobileSession username apiKey token = simple <$> callAPI JSON [(#) (Method "auth.getMobileSession"), (#) username, (#) token, (#) apiKey]
+
+getSession ∷ APIKey → Token → Secret → Lastfm SessionKey
+getSession apiKey token secret = simple <$> callAPIsigned JSON secret [(#) (Method "auth.getSession"), (#) apiKey, (#) token]
+
+getToken ∷ APIKey → Lastfm Token
+getToken apiKey = simple <$> callAPI JSON [(#) (Method "auth.getToken"), (#) apiKey]
+
+getAuthorizeTokenLink ∷ APIKey → Token → String
+getAuthorizeTokenLink apiKey token = "http://www.last.fm/api/auth/?api_key=" ++ value apiKey ++ "&token=" ++ value token
diff --git a/src/Network/Lastfm/API/Chart.hs b/src/Network/Lastfm/API/Chart.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/Chart.hs
@@ -0,0 +1,26 @@
+module Network.Lastfm.API.Chart
+  ( getHypedArtists, getHypedTracks, getLovedTracks
+  , getTopArtists, getTopTags, getTopTracks
+  ) where
+
+import Network.Lastfm
+
+getHypedArtists = get "getHypedArtists"
+
+getHypedTracks = get "getHypedTracks"
+
+getLovedTracks = get "getLovedTracks"
+
+getTopArtists = get "getTopArtists"
+
+getTopTags = get "getTopTags"
+
+getTopTracks = get "getTopTracks"
+
+get ∷ String → ResponseType → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+get method t page limit apiKey = callAPI t
+  [ (#) (Method $ "chart." ++ method)
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
diff --git a/src/Network/Lastfm/API/Event.hs b/src/Network/Lastfm/API/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/Event.hs
@@ -0,0 +1,59 @@
+module Network.Lastfm.API.Event
+  ( attend, getAttendees, getInfo, getShouts, share, shout
+  ) where
+
+import Network.Lastfm
+
+attend ∷ ResponseType → Event → Status → APIKey → SessionKey → Secret → Lastfm Response
+attend t event status apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "event.attend")
+  , (#) event
+  , (#) status
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+getAttendees ∷ ResponseType → Event → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getAttendees t event page limit apiKey = callAPI t
+  [ (#) (Method "event.getAttendees")
+  , (#) event
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getInfo ∷ ResponseType → Event → APIKey → Lastfm Response
+getInfo t event apiKey = callAPI t
+  [ (#) (Method "event.getInfo")
+  , (#) event
+  , (#) apiKey
+  ]
+
+getShouts ∷ ResponseType → Event → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getShouts t event page limit apiKey = callAPI t
+  [ (#) (Method "event.getShouts")
+  , (#) event
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+share ∷ ResponseType → Event → Recipient → Maybe Message → Maybe Public → APIKey → SessionKey → Secret → Lastfm Response
+share t event recipient message public apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "event.share")
+  , (#) event
+  , (#) public
+  , (#) message
+  , (#) recipient
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+shout ∷ ResponseType → Event → Message → APIKey → SessionKey → Secret → Lastfm Response
+shout t event message apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "event.shout")
+  , (#) event
+  , (#) message
+  , (#) apiKey
+  , (#) sessionKey
+  ]
diff --git a/src/Network/Lastfm/API/Geo.hs b/src/Network/Lastfm/API/Geo.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/Geo.hs
@@ -0,0 +1,88 @@
+module Network.Lastfm.API.Geo
+  ( getEvents, getMetroArtistChart, getMetroHypeArtistChart, getMetroHypeTrackChart
+  , getMetroTrackChart, getMetroUniqueArtistChart, getMetroUniqueTrackChart
+  , getMetroWeeklyChartlist, getMetros, getTopArtists, getTopTracks
+  ) where
+
+import Network.Lastfm
+
+getEvents ∷ ResponseType
+          → Maybe Latitude
+          → Maybe Longitude
+          → Maybe Location
+          → Maybe Distance
+          → Maybe Page
+          → Maybe Limit
+          → APIKey
+          → Lastfm Response
+getEvents t latitude longitude location distance page limit apiKey = callAPI t
+  [ (#) (Method "geo.getEvents")
+  , (#) latitude
+  , (#) longitude
+  , (#) location
+  , (#) distance
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getMetroArtistChart ∷ ResponseType → Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+getMetroArtistChart = getMetroChart "geo.getMetroArtistChart"
+
+getMetroHypeArtistChart ∷ ResponseType → Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+getMetroHypeArtistChart = getMetroChart "geo.getMetroHypeArtistChart"
+
+getMetroHypeTrackChart ∷ ResponseType → Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+getMetroHypeTrackChart = getMetroChart "geo.getMetroHypeTrackChart"
+
+getMetroTrackChart ∷ ResponseType → Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+getMetroTrackChart = getMetroChart "geo.getMetroTrackChart"
+
+getMetroUniqueArtistChart ∷ ResponseType → Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+getMetroUniqueArtistChart = getMetroChart "geo.getMetroUniqueArtistChart"
+
+getMetroUniqueTrackChart ∷ ResponseType → Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+getMetroUniqueTrackChart = getMetroChart "geo.getMetroUniqueTrackChart"
+
+getMetroWeeklyChartlist ∷ ResponseType → Metro → APIKey → Lastfm Response
+getMetroWeeklyChartlist t metro apiKey = callAPI t
+  [ (#) (Method "geo.getMetroWeeklyChartlist")
+  , (#) metro
+  , (#) apiKey
+  ]
+
+getMetros ∷ ResponseType → Maybe Country → APIKey → Lastfm Response
+getMetros t country apiKey = callAPI t
+  [ (#) (Method "geo.getMetros")
+  , (#) country
+  , (#) apiKey
+  ]
+
+getTopArtists ∷ ResponseType → Country → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getTopArtists t country page limit apiKey = callAPI t
+  [ (#) (Method "geo.getTopArtists")
+  , (#) country
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getTopTracks ∷ ResponseType → Country → Maybe Location → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getTopTracks t country location page limit apiKey = callAPI t
+  [ (#) (Method "geo.getTopTracks")
+  , (#) country
+  , (#) location
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getMetroChart ∷ String → ResponseType → Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+getMetroChart method t country metro start end apiKey = callAPI t
+  [ (#) (Method method)
+  , (#) country
+  , (#) metro
+  , (#) start
+  , (#) end
+  , (#) apiKey
+  ]
diff --git a/src/Network/Lastfm/API/Group.hs b/src/Network/Lastfm/API/Group.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/Group.hs
@@ -0,0 +1,56 @@
+module Network.Lastfm.API.Group
+  ( getHype, getMembers, getWeeklyChartList, getWeeklyAlbumChart, getWeeklyArtistChart, getWeeklyTrackChart
+  ) where
+
+import Network.Lastfm
+
+getHype ∷ ResponseType → Group → APIKey → Lastfm Response
+getHype t group apiKey = callAPI t
+  [ (#) (Method "group.getHype")
+  , (#) group
+  , (#) apiKey
+  ]
+
+getMembers ∷ ResponseType → Group → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getMembers t group page limit apiKey = callAPI t
+  [ (#) (Method "group.getMembers")
+  , (#) group
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getWeeklyChartList ∷ ResponseType → Group → APIKey → Lastfm Response
+getWeeklyChartList t group apiKey = callAPI t
+  [ (#) (Method "group.getWeeklyChartList")
+  , (#) group
+  , (#) apiKey
+  ]
+
+getWeeklyAlbumChart ∷ ResponseType → Group → Maybe From → Maybe To → APIKey → Lastfm Response
+getWeeklyAlbumChart t group from to apiKey = callAPI t
+  [ (#) (Method "group.getWeeklyAlbumChart")
+  , (#) group
+  , (#) from
+  , (#) to
+  , (#) apiKey
+  ]
+
+getWeeklyArtistChart ∷ ResponseType → Group → Maybe From → Maybe To → APIKey → Lastfm Response
+getWeeklyArtistChart t group from to apiKey = callAPI t
+  [ (#) (Method "group.getWeeklyArtistChart")
+  , (#) group
+  , (#) from
+  , (#) to
+  , (#) apiKey
+  ]
+
+
+getWeeklyTrackChart ∷ ResponseType → Group → Maybe From → Maybe To → APIKey → Lastfm Response
+getWeeklyTrackChart t group from to apiKey = callAPI t
+  [ (#) (Method "group.getWeeklyTrackChart")
+  , (#) group
+  , (#) from
+  , (#) to
+  , (#) apiKey
+  ]
diff --git a/src/Network/Lastfm/API/Library.hs b/src/Network/Lastfm/API/Library.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/Library.hs
@@ -0,0 +1,98 @@
+module Network.Lastfm.API.Library
+  ( addAlbum, addArtist, addTrack, getAlbums, getArtists, getTracks
+  , removeAlbum, removeArtist, removeScrobble, removeTrack
+  ) where
+
+import Network.Lastfm
+
+addAlbum ∷ ResponseType → Artist → Album → APIKey → SessionKey → Secret → Lastfm Response
+addAlbum t artist album apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "library.addAlbum")
+  , (#) artist
+  , (#) album
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+addArtist ∷ ResponseType → Artist → APIKey → SessionKey → Secret → Lastfm Response
+addArtist t artist apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "library.addArtist")
+  , (#) artist
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+addTrack ∷ ResponseType → Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+addTrack t artist track apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "library.addTrack")
+  , (#) artist
+  , (#) track
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+getAlbums ∷ ResponseType → User → Maybe Artist → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getAlbums t user artist page limit apiKey = callAPI t
+  [ (#) (Method "library.getAlbums")
+  , (#) user
+  , (#) artist
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getArtists ∷ ResponseType → User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getArtists t user page limit apiKey = callAPI t
+  [ (#) (Method "library.getArtists")
+  , (#) user
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getTracks ∷ ResponseType → User → Maybe Artist → Maybe Album → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getTracks t user artist album page limit apiKey = callAPI t
+  [ (#) (Method "library.getTracks")
+  , (#) user
+  , (#) artist
+  , (#) album
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+removeAlbum ∷ ResponseType → Artist → Album → APIKey → SessionKey → Secret → Lastfm Response
+removeAlbum t artist album apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "library.removeAlbum")
+  , (#) artist
+  , (#) album
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+removeArtist ∷ ResponseType → Artist → APIKey → SessionKey → Secret → Lastfm Response
+removeArtist t artist apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "library.removeArtist")
+  , (#) artist
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+removeScrobble ∷ ResponseType → Artist → Track → Timestamp → APIKey → SessionKey → Secret → Lastfm Response
+removeScrobble t artist track timestamp apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "library.removeScrobble")
+  , (#) artist
+  , (#) track
+  , (#) timestamp
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+removeTrack ∷ ResponseType → Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+removeTrack t artist track apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "library.removeTrack")
+  , (#) artist
+  , (#) track
+  , (#) apiKey
+  , (#) sessionKey
+  ]
diff --git a/src/Network/Lastfm/API/Playlist.hs b/src/Network/Lastfm/API/Playlist.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/Playlist.hs
@@ -0,0 +1,24 @@
+module Network.Lastfm.API.Playlist
+  ( addTrack, create
+  ) where
+
+import Network.Lastfm
+
+addTrack ∷ ResponseType → Playlist → Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+addTrack t playlist artist track apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "playlist.addTrack")
+  , (#) playlist
+  , (#) artist
+  , (#) track
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+create ∷ ResponseType → Maybe Title → Maybe Description → APIKey → SessionKey → Secret → Lastfm Response
+create t title description apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "playlist.create")
+  , (#) title
+  , (#) description
+  , (#) apiKey
+  , (#) sessionKey
+  ]
diff --git a/src/Network/Lastfm/API/Radio.hs b/src/Network/Lastfm/API/Radio.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/Radio.hs
@@ -0,0 +1,42 @@
+module Network.Lastfm.API.Radio
+  ( getPlaylist, search, tune
+  ) where
+
+import Network.Lastfm
+
+getPlaylist ∷ ResponseType
+            → Maybe Discovery
+            → Maybe RTP
+            → Maybe BuyLinks
+            → Multiplier
+            → Bitrate
+            → APIKey
+            → SessionKey
+            → Secret
+            → Lastfm Response
+getPlaylist t discovery rtp buylinks multiplier bitrate apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "radio.getPlaylist")
+  , (#) discovery
+  , (#) rtp
+  , (#) buylinks
+  , (#) multiplier
+  , (#) bitrate
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+search ∷ ResponseType → Name → APIKey → Lastfm Response
+search t name apiKey = callAPI t
+  [ (#) (Method "radio.search")
+  , (#) name
+  , (#) apiKey
+  ]
+
+tune ∷ ResponseType → Maybe Language → Station → APIKey → SessionKey → Secret → Lastfm Response
+tune t language station apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "radio.tune")
+  , (#) language
+  , (#) station
+  , (#) apiKey
+  , (#) sessionKey
+  ]
diff --git a/src/Network/Lastfm/API/Tag.hs b/src/Network/Lastfm/API/Tag.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/Tag.hs
@@ -0,0 +1,80 @@
+module Network.Lastfm.API.Tag
+  ( getInfo, getSimilar, getTopAlbums, getTopArtists, getTopTags, getTopTracks
+  , getWeeklyArtistChart, getWeeklyChartList, search
+  ) where
+
+import Network.Lastfm
+
+getInfo ∷ ResponseType → Tag → Maybe Language → APIKey → Lastfm Response
+getInfo t tag language apiKey = callAPI t
+  [ (#) (Method "tag.getInfo")
+  , (#) tag
+  , (#) language
+  , (#) apiKey
+  ]
+
+getSimilar ∷ ResponseType → Tag → APIKey → Lastfm Response
+getSimilar t tag apiKey = callAPI t
+  [ (#) (Method "tag.getSimilar")
+  , (#) tag
+  , (#) apiKey
+  ]
+
+getTopAlbums ∷ ResponseType → Tag → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getTopAlbums t tag page limit apiKey = callAPI t
+  [ (#) (Method "tag.getTopAlbums")
+  , (#) tag
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getTopArtists ∷ ResponseType → Tag → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getTopArtists t tag limit page apiKey = callAPI t
+  [ (#) (Method "tag.getTopArtists")
+  , (#) tag
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getTopTags ∷ ResponseType → APIKey → Lastfm Response
+getTopTags t apiKey = callAPI t
+  [ (#) (Method "tag.getTopArtists")
+  , (#) apiKey
+  ]
+
+getTopTracks ∷ ResponseType → Tag → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getTopTracks t tag limit page apiKey = callAPI t
+  [ (#) (Method "tag.getTopTracks")
+  , (#) tag
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getWeeklyArtistChart ∷ ResponseType → Tag → Maybe From → Maybe To → Maybe Limit → APIKey → Lastfm Response
+getWeeklyArtistChart t tag from to limit apiKey = callAPI t
+  [ (#) (Method "tag.getWeeklyArtistChart")
+  , (#) tag
+  , (#) from
+  , (#) to
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getWeeklyChartList ∷ ResponseType → Tag → APIKey → Lastfm Response
+getWeeklyChartList t tag apiKey = callAPI t
+  [ (#) (Method "tag.getWeeklyChartList")
+  , (#) tag
+  , (#) apiKey
+  ]
+
+search ∷ ResponseType → Tag → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+search t tag page limit apiKey = callAPI t
+  [ (#) (Method "tag.search")
+  , (#) tag
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
diff --git a/src/Network/Lastfm/API/Tasteometer.hs b/src/Network/Lastfm/API/Tasteometer.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/Tasteometer.hs
@@ -0,0 +1,20 @@
+module Network.Lastfm.API.Tasteometer
+  ( compare
+  ) where
+
+import Network.Lastfm
+import Prelude hiding (compare)
+
+(?<) ∷ Argument a ⇒ a → Int → (String, String)
+a ?< n = (key a ++ show n, value a)
+
+compare ∷ ResponseType → Value → Value → Maybe Limit → APIKey → Lastfm Response
+compare t value1 value2 limit apiKey = callAPI t
+  [ (#) (Method "tasteometer.compare")
+  , (,) "type1" (show value1)
+  , (,) "type2" (show value2)
+  , (?<) value1 1
+  , (?<) value2 2
+  , (#) limit
+  , (#) apiKey
+  ]
diff --git a/src/Network/Lastfm/API/Track.hs b/src/Network/Lastfm/API/Track.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/Track.hs
@@ -0,0 +1,218 @@
+module Network.Lastfm.API.Track
+  ( addTags, ban, getBuyLinks, getCorrection, getFingerprintMetadata
+  , getInfo, getShouts, getSimilar, getTags, getTopFans, getTopTags
+  , love, removeTag, scrobble, search, share, unban, unlove, updateNowPlaying
+  ) where
+
+import Control.Arrow ((|||))
+import Network.Lastfm
+
+addTags ∷ ResponseType → Artist → Track → [Tag] → APIKey → SessionKey → Secret → Lastfm Response
+addTags t artist track tags apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "track.addTags")
+  , (#) artist
+  , (#) track
+  , (#) tags
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+ban ∷ ResponseType → Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+ban t artist track apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "track.ban")
+  , (#) artist
+  , (#) track
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+getBuyLinks ∷ ResponseType → Either (Artist, Track) Mbid → Maybe Autocorrect → Country → APIKey → Lastfm Response
+getBuyLinks t a autocorrect country apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "track.getBuyLinks")
+  , (#) autocorrect
+  , (#) country
+  , (#) apiKey
+  ]
+
+getCorrection ∷ ResponseType → Artist → Track → APIKey → Lastfm Response
+getCorrection t artist track apiKey = callAPI t
+  [ (#) (Method "track.getCorrection")
+  , (#) artist
+  , (#) track
+  , (#) apiKey
+  ]
+
+getFingerprintMetadata ∷ ResponseType → Fingerprint → APIKey → Lastfm Response
+getFingerprintMetadata t fingerprint apiKey = callAPI t
+  [ (#) (Method "track.getFingerprintMetadata")
+  , (#) fingerprint
+  , (#) apiKey
+  ]
+
+getInfo ∷ ResponseType → Either (Artist, Track) Mbid → Maybe Autocorrect → Maybe Username → APIKey → Lastfm Response
+getInfo t a autocorrect username apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "track.getInfo")
+  , (#) autocorrect
+  , (#) username
+  , (#) apiKey
+  ]
+
+getShouts ∷ ResponseType → Either (Artist, Track) Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getShouts t a autocorrect page limit apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "track.getShouts")
+  , (#) autocorrect
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getSimilar ∷ ResponseType → Either (Artist, Track) Mbid → Maybe Autocorrect → Maybe Limit → APIKey → Lastfm Response
+getSimilar t a autocorrect limit apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "track.getSimilar")
+  , (#) autocorrect
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getTags ∷ ResponseType → Either (Artist, Track) Mbid → Maybe Autocorrect → Either User (SessionKey, Secret) → APIKey → Lastfm Response
+getTags t a autocorrect b apiKey = case b of
+  Left user → callAPI t $ target a ++ [(#) user] ++ args
+  Right (sessionKey, secret) → callAPIsigned t secret $ target a ++ [(#) sessionKey] ++ args
+  where args =
+          [ (#) (Method "track.getTags")
+          , (#) autocorrect
+          , (#) apiKey
+          ]
+
+getTopFans ∷ ResponseType → Either (Artist, Track) Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+getTopFans t a autocorrect apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "track.getTopFans")
+  , (#) autocorrect
+  , (#) apiKey
+  ]
+
+getTopTags ∷ ResponseType → Either (Artist, Track) Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+getTopTags t a autocorrect apiKey = callAPI t $
+  target a ++
+  [ (#) (Method "track.getTopTags")
+  , (#) autocorrect
+  , (#) apiKey
+  ]
+
+love ∷ ResponseType → Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+love t artist track apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "track.love")
+  , (#) artist
+  , (#) track
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+removeTag ∷ ResponseType → Artist → Track → Tag → APIKey → SessionKey → Secret → Lastfm Response
+removeTag t artist track tag apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "track.removeTag")
+  , (#) artist
+  , (#) track
+  , (#) tag
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+scrobble ∷ ResponseType → ( Timestamp, Maybe Album, Artist, Track, Maybe AlbumArtist
+           , Maybe Duration, Maybe StreamId, Maybe ChosenByUser
+           , Maybe Context, Maybe TrackNumber, Maybe Mbid )
+         → APIKey
+         → SessionKey
+         → Secret
+         → Lastfm Response
+scrobble t (timestamp, album, artist, track, albumArtist, duration, streamId, chosenByUser, context, trackNumber, mbid) apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "track.scrobble")
+  , (#) timestamp
+  , (#) artist
+  , (#) track
+  , (#) album
+  , (#) albumArtist
+  , (#) duration
+  , (#) streamId
+  , (#) chosenByUser
+  , (#) context
+  , (#) trackNumber
+  , (#) mbid
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+search ∷ ResponseType → Track → Maybe Page → Maybe Limit → Maybe Artist → APIKey → Lastfm Response
+search t track page limit artist apiKey = callAPI t
+  [ (#) (Method "track.search")
+  , (#) track
+  , (#) page
+  , (#) limit
+  , (#) artist
+  , (#) apiKey
+  ]
+
+share ∷ ResponseType → Artist → Track → Recipient → Maybe Message → Maybe Public → APIKey → SessionKey → Secret → Lastfm Response
+share t artist track recipient message public apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "track.share")
+  , (#) artist
+  , (#) track
+  , (#) recipient
+  , (#) public
+  , (#) message
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+unban ∷ ResponseType → Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+unban t artist track apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "track.unban")
+  , (#) artist
+  , (#) track
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+unlove ∷ ResponseType → Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+unlove t artist track apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "track.unlove")
+  , (#) artist
+  , (#) track
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+
+updateNowPlaying ∷ ResponseType → Artist
+                 → Track
+                 → Maybe Album
+                 → Maybe AlbumArtist
+                 → Maybe Context
+                 → Maybe TrackNumber
+                 → Maybe Mbid
+                 → Maybe Duration
+                 → APIKey
+                 → SessionKey
+                 → Secret
+                 → Lastfm Response
+updateNowPlaying t artist track album albumArtist context trackNumber mbid duration apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "track.updateNowPlaying")
+  , (#) artist
+  , (#) track
+  , (#) album
+  , (#) albumArtist
+  , (#) context
+  , (#) trackNumber
+  , (#) mbid
+  , (#) duration
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+target ∷ Either (Artist, Track) Mbid → [(String, String)]
+target = (\(artist, track) → [(#) artist, (#) track]) ||| return . (#)
diff --git a/src/Network/Lastfm/API/User.hs b/src/Network/Lastfm/API/User.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/User.hs
@@ -0,0 +1,244 @@
+module Network.Lastfm.API.User
+  ( getArtistTracks, getBannedTracks, getEvents, getFriends, getInfo, getLovedTracks
+  , getNeighbours, getNewReleases, getPastEvents, getPersonalTags, getPlaylists, getRecentStations
+  , getRecentTracks, getRecommendedArtists, getRecommendedEvents, getShouts, getTopAlbums
+  , getTopArtists, getTopTags, getTopTracks, getWeeklyAlbumChart, getWeeklyArtistChart
+  , getWeeklyChartList, getWeeklyTrackChart, shout
+  ) where
+
+import Network.Lastfm
+
+getArtistTracks ∷ ResponseType → User → Artist → Maybe StartTimestamp → Maybe EndTimestamp → Maybe Page → APIKey → Lastfm Response
+getArtistTracks t user artist startTimestamp endTimestamp page apiKey = callAPI t
+  [ (#) (Method "user.getArtistTracks")
+  , (#) user
+  , (#) artist
+  , (#) startTimestamp
+  , (#) page
+  , (#) endTimestamp
+  , (#) apiKey
+  ]
+
+getBannedTracks ∷ ResponseType → User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getBannedTracks t user page limit apiKey = callAPI t
+  [ (#) (Method "user.getBannedTracks")
+  , (#) user
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getEvents ∷ ResponseType → User → Maybe Page → Maybe Limit → Maybe FestivalsOnly → APIKey → Lastfm Response
+getEvents t user page limit festivalsOnly apiKey = callAPI t
+  [ (#) (Method "user.getEvents")
+  , (#) user
+  , (#) page
+  , (#) limit
+  , (#) festivalsOnly
+  , (#) apiKey
+  ]
+
+getFriends ∷ ResponseType → User → Maybe RecentTracks → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getFriends t user recentTracks page limit apiKey = callAPI t
+  [ (#) (Method "user.getFriends")
+  , (#) user
+  , (#) recentTracks
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getInfo ∷ ResponseType → Maybe User → APIKey → Lastfm Response
+getInfo t user apiKey = callAPI t
+  [ (#) (Method "user.getInfo")
+  , (#) user
+  , (#) apiKey
+  ]
+
+getLovedTracks ∷ ResponseType → User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getLovedTracks t user page limit apiKey = callAPI t
+  [ (#) (Method "user.getLovedTracks")
+  , (#) user
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getNeighbours ∷ ResponseType → User → Maybe Limit → APIKey → Lastfm Response
+getNeighbours t user limit apiKey = callAPI t
+  [ (#) (Method "user.getNeighbours")
+  , (#) user
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getNewReleases ∷ ResponseType → User → Maybe UseRecs → APIKey → Lastfm Response
+getNewReleases t user useRecs apiKey = callAPI t
+  [ (#) (Method "user.getNewReleases")
+  , (#) user
+  , (#) useRecs
+  , (#) apiKey
+  ]
+
+getPastEvents ∷ ResponseType → User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getPastEvents t user page limit apiKey = callAPI t
+  [ (#) (Method "user.getPastEvents")
+  , (#) user
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getPersonalTags ∷ ResponseType
+                → User
+                → Tag
+                → TaggingType
+                → Maybe Page
+                → Maybe Limit
+                → APIKey
+                → Lastfm Response
+getPersonalTags t user tag taggingType page limit apiKey = callAPI t
+  [ (#) (Method "user.getPersonalTags")
+  , (#) user
+  , (#) tag
+  , (#) taggingType
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getPlaylists ∷ ResponseType → User → APIKey → Lastfm Response
+getPlaylists t user apiKey = callAPI t
+  [ (#) (Method "user.getPlaylists")
+  , (#) user
+  , (#) apiKey
+  ]
+
+getRecentStations ∷ ResponseType → User → Maybe Page → Maybe Limit → APIKey → SessionKey → Secret → Lastfm Response
+getRecentStations t user page limit apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "user.getRecentStations")
+  , (#) user
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+getRecentTracks ∷ ResponseType → User → Maybe Page → Maybe Limit → Maybe From → Maybe To → APIKey → Lastfm Response
+getRecentTracks t user page limit from to apiKey = callAPI t
+  [ (#) (Method "user.getRecentTracks")
+  , (#) user
+  , (#) page
+  , (#) limit
+  , (#) from
+  , (#) to
+  , (#) apiKey
+  ]
+
+getRecommendedArtists ∷ ResponseType → Maybe Page → Maybe Limit → APIKey → SessionKey → Secret → Lastfm Response
+getRecommendedArtists t page limit apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "user.getRecommendedArtists")
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+getRecommendedEvents ∷ ResponseType → Maybe Page → Maybe Limit → APIKey → SessionKey → Secret → Lastfm Response
+getRecommendedEvents t page limit apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "user.getRecommendedEvents")
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  , (#) sessionKey
+  ]
+
+getShouts ∷ ResponseType → User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getShouts t user page limit apiKey = callAPI t
+  [ (#) (Method "user.getShouts")
+  , (#) user
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getTopAlbums ∷ ResponseType → User → Maybe Period → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getTopAlbums t user period page limit apiKey = callAPI t
+  [ (#) (Method "user.getTopAlbums")
+  , (#) user
+  , (#) period
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getTopArtists ∷ ResponseType → User → Maybe Period → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getTopArtists t user period page limit apiKey = callAPI t
+  [ (#) (Method "user.getTopArtists")
+  , (#) user
+  , (#) period
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getTopTags ∷ ResponseType → User → Maybe Limit → APIKey → Lastfm Response
+getTopTags t user limit apiKey = callAPI t
+  [ (#) (Method "user.getTopTags")
+  , (#) user
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getTopTracks ∷ ResponseType → User → Maybe Period → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getTopTracks t user period page limit apiKey = callAPI t
+  [ (#) (Method "user.getTopTracks")
+  , (#) user
+  , (#) period
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+getWeeklyAlbumChart ∷ ResponseType → User → Maybe From → Maybe To → APIKey → Lastfm Response
+getWeeklyAlbumChart t user from to apiKey = callAPI t
+  [ (#) (Method "user.getWeeklyAlbumChart")
+  , (#) user
+  , (#) from
+  , (#) to
+  , (#) apiKey
+  ]
+
+getWeeklyArtistChart ∷ ResponseType → User → Maybe From → Maybe To → APIKey → Lastfm Response
+getWeeklyArtistChart t user from to apiKey = callAPI t
+  [ (#) (Method "user.getWeeklyArtistChart")
+  , (#) user
+  , (#) from
+  , (#) to
+  , (#) apiKey
+  ]
+
+getWeeklyChartList ∷ ResponseType → User → APIKey → Lastfm Response
+getWeeklyChartList t user apiKey = callAPI t
+  [ (#) (Method "user.getWeeklyChartList")
+  , (#) user
+  , (#) apiKey
+  ]
+
+getWeeklyTrackChart ∷ ResponseType → User → Maybe From → Maybe To → APIKey → Lastfm Response
+getWeeklyTrackChart t user from to apiKey = callAPI t
+  [ (#) (Method "user.getWeeklyTrackChart")
+  , (#) user
+  , (#) from
+  , (#) to
+  , (#) apiKey
+  ]
+
+shout ∷ ResponseType → User → Message → APIKey → SessionKey → Secret → Lastfm Response
+shout t user message apiKey sessionKey secret = callAPIsigned t secret
+  [ (#) (Method "user.shout")
+  , (#) user
+  , (#) message
+  , (#) apiKey
+  , (#) sessionKey
+  ]
diff --git a/src/Network/Lastfm/API/Venue.hs b/src/Network/Lastfm/API/Venue.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/API/Venue.hs
@@ -0,0 +1,33 @@
+module Network.Lastfm.API.Venue
+  ( getEvents, getPastEvents, search
+  ) where
+
+import Network.Lastfm
+
+getEvents ∷ ResponseType → Venue → Maybe FestivalsOnly → APIKey → Lastfm Response
+getEvents t venue festivalsOnly apiKey = callAPI t
+  [ (#) (Method "venue.getEvents")
+  , (#) venue
+  , (#) festivalsOnly
+  , (#) apiKey
+  ]
+
+getPastEvents ∷ ResponseType → Venue → Maybe FestivalsOnly → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+getPastEvents t venue festivalsOnly page limit apiKey = callAPI t
+  [ (#) (Method "venue.getPastEvents")
+  , (#) venue
+  , (#) festivalsOnly
+  , (#) page
+  , (#) limit
+  , (#) apiKey
+  ]
+
+search ∷ ResponseType → Venuename → Maybe Page → Maybe Limit → Maybe Country → APIKey → Lastfm Response
+search t venue page limit country apiKey = callAPI t
+  [ (#) (Method "venue.search")
+  , (#) venue
+  , (#) page
+  , (#) limit
+  , (#) country
+  , (#) apiKey
+  ]
diff --git a/src/Network/Lastfm/Error.hs b/src/Network/Lastfm/Error.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/Error.hs
@@ -0,0 +1,86 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Network.Lastfm.Error where
+
+import Control.Applicative ((<$>), empty)
+import Control.Monad ((<=<))
+import Control.Monad.Error (Error)
+import Data.Aeson
+import Data.ByteString.Lazy.Char8 (ByteString)
+import Text.XML.Light
+
+data LastfmError
+  = NotUsed -- To avoid subtracting 1 from Lastfm reponses
+  | DoesntExist
+  | InvalidService
+  | InvalidMethod
+  | AuthenticationFailed
+  | InvalidFormat
+  | InvalidParameters
+  | InvalidResource
+  | OperationFailed
+  | InvalidSessionKey
+  | InvalidAPIKey
+  | ServiceOffline
+  | SubscribersOnly
+  | InvalidMethodSignature
+  | TokenHasNotAuthorized
+  | NotForStreaming
+  | TemporaryUnavailable
+  | LoginRequired
+  | TrialExpired
+  | DoesntExistAgain
+  | NotEnoughContent
+  | NotEnoughMembers
+  | NotEnoughFans
+  | NotEnoughNeighbours
+  | NoPeakRadio
+  | RadioNotFound
+  | SuspendedAPIKey
+  | Deprecated
+  | RateLimitExceeded
+    deriving Enum
+
+instance Show LastfmError where
+  show NotUsed = "NotUsed: Internal liblastfm error for convenience"
+  show DoesntExist = "DoesntExist: This error does not exist"
+  show InvalidService = "InvalidService: This service does not exist"
+  show InvalidMethod = "InvalidMethod: No method with that name in this package"
+  show AuthenticationFailed = "AuthenticationFailed: You do not have permissions to access the service"
+  show InvalidFormat = "InvalidFormat: This service doesn't exist in that format"
+  show InvalidParameters = "InvalidParameters: Your request is missing a required parameter"
+  show InvalidResource = "InvalidResource: Invalid resource specified"
+  show OperationFailed = "OperationFailed: Something else went wrong"
+  show InvalidSessionKey = "InvalidSessionKey: Please re-authenticate"
+  show InvalidAPIKey = "InvalidAPIKey: You must be granted a valid key by last.fm"
+  show ServiceOffline = "ServiceOffline: This service is temporarily offline. Try again later."
+  show SubscribersOnly  = "SubscribersOnly : This station is only available to paid last.fm subscribers"
+  show InvalidMethodSignature = "InvalidMethodSignature: Invalid method signature supplied"
+  show TokenHasNotAuthorized = "TokenHasNotAuthorized: This token has not been authorized"
+  show NotForStreaming = "NotForStreaming: This item is not available for streaming."
+  show TemporaryUnavailable = "TemporaryUnavailable: The service is temporarily unavailable, please try again."
+  show LoginRequired = "LoginRequired: Login: User requires to be logged in"
+  show TrialExpired = "TrialExpired: This user has no free radio plays left. Subscription required."
+  show DoesntExistAgain = "DoesntExistAgain: This error does not exist"
+  show NotEnoughContent = "NotEnoughContent: There is not enough content to play this station"
+  show NotEnoughMembers = "NotEnoughMembers: This group does not have enough members for radio"
+  show NotEnoughFans = "NotEnoughFans: This artist does not have enough fans for for radio"
+  show NotEnoughNeighbours = "NotEnoughNeighbours: There are not enough neighbours for radio"
+  show NoPeakRadio = "NoPeakRadio: This user is not allowed to listen to radio during peak usage"
+  show RadioNotFound = "RadioNotFound: Radio station not found"
+  show SuspendedAPIKey = "SuspendedAPIKey: Access for your account has been suspended, please contact Last.fm"
+  show Deprecated = "Deprecated: This type of request is no longer supported"
+  show RateLimitExceeded = "RateLimitExceeded: Your IP has made too many requests in a short period"
+
+instance Error LastfmError
+
+xmlError ∷ ByteString → Maybe LastfmError
+xmlError r = do
+  xml ← parseXMLDoc r
+  toEnum . read <$> (findAttr (unqual "code") <=< findChild (unqual "error")) xml
+
+jsonError ∷ ByteString → Maybe LastfmError
+jsonError = decode
+
+instance FromJSON LastfmError where
+  parseJSON (Object v) = toEnum <$> v .: "error"
+  parseJSON _ = empty
diff --git a/src/Network/Lastfm/JSON/Album.hs b/src/Network/Lastfm/JSON/Album.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/Album.hs
@@ -0,0 +1,57 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Album API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.Album
+  ( addTags, getBuyLinks, getInfo, getShouts, getTags
+  , getTopTags, removeTag, search, share
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Album as API
+
+$(json ["addTags", "getBuyLinks", "getInfo", "getShouts", "getTags", "getTopTags", "removeTag", "search", "share"])
+
+-- | Tag an album using a list of user supplied tags.
+--
+-- More: <http://www.last.fm/api/show/album.addTags>
+addTags ∷ (Artist, Album) → [Tag] → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Get a list of Buy Links for a particular Album. It is required that you supply either the artist and track params or the mbid param.
+--
+-- More: <http://www.last.fm/api/show/album.getBuylinks>
+getBuyLinks ∷ Either (Artist, Album) Mbid → Maybe Autocorrect → Country → APIKey → Lastfm Response
+
+-- | Get the metadata for an album on Last.fm using the album name or a musicbrainz id. See playlist.fetch on how to get the album playlist.
+--
+-- More: <http://www.last.fm/api/show/album.getInfo>
+getInfo ∷ Either (Artist, Album) Mbid → Maybe Autocorrect → Maybe Language → Maybe Username → APIKey → Lastfm Response
+
+-- | Get shouts for this album.
+--
+-- More: <http://www.last.fm/api/show/album.getShouts>
+getShouts ∷ Either (Artist, Album) Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the tags applied by an individual user to an album on Last.fm.
+--
+-- More: <http://www.last.fm/api/show/album.getTags>
+getTags ∷ Either (Artist, Album) Mbid → Maybe Autocorrect → Either User (SessionKey, Secret) → APIKey → Lastfm Response
+
+-- | Get the top tags for an album on Last.fm, ordered by popularity.
+--
+-- More: <http://www.last.fm/api/show/album.getTopTags>
+getTopTags ∷ Either (Artist, Album) Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+
+-- | Remove a user's tag from an album.
+--
+-- More: <http://www.last.fm/api/show/album.removeTag>
+removeTag ∷ Artist → Album → Tag → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Search for an album by name. Returns album matches sorted by relevance.
+--
+-- More: <http://www.last.fm/api/show/album.search>
+search ∷ Album → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Share an album with one or more Last.fm users or other friends.
+--
+-- More: <http://www.last.fm/api/show/album.share>
+share ∷ Artist → Album → Recipient → Maybe Message → Maybe Public → APIKey → SessionKey → Secret → Lastfm Response
diff --git a/src/Network/Lastfm/JSON/Artist.hs b/src/Network/Lastfm/JSON/Artist.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/Artist.hs
@@ -0,0 +1,103 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Artist API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.Artist
+  ( addTags, getCorrection, getEvents, getImages, getInfo
+  , getPastEvents, getPodcast, getShouts, getSimilar, getTags, getTopAlbums
+  , getTopFans, getTopTags, getTopTracks, removeTag, search, share, shout
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Artist as API
+  
+$(json ["addTags", "getCorrection", "getEvents", "getImages", "getInfo", "getPastEvents", "getPodcast", "getShouts", "getSimilar", "getTags", "getTopAlbums", "getTopFans", "getTopTags", "getTopTracks", "removeTag", "search", "share", "shout"])
+
+-- | Tag an album using a list of user supplied tags.
+--
+-- More: <http://www.last.fm/api/show/artist.addTags>
+addTags ∷ Artist → [Tag] → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Use the last.fm corrections data to check whether the supplied artist has a correction to a canonical artist
+--
+-- More: <http://www.last.fm/api/show/artist.getCorrection>
+getCorrection ∷ Artist → APIKey → Lastfm Response
+
+-- | Get a list of upcoming events for this artist.
+--
+-- More: <http://www.last.fm/api/show/artist.getEvents>
+getEvents ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → Maybe FestivalsOnly → APIKey → Lastfm Response
+
+-- | Get Images for this artist in a variety of sizes.
+--
+-- More: <http://www.last.fm/api/show/artist.getImages>
+getImages ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → Maybe Order → APIKey → Lastfm Response
+
+-- | Get the metadata for an artist. Includes biography.
+--
+-- More: <http://www.last.fm/api/show/artist.getInfo>
+getInfo ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Language → Maybe Username → APIKey → Lastfm Response
+
+-- | Get a paginated list of all the events this artist has played at in the past.
+--
+-- More: <http://www.last.fm/api/show/artist.getPastEvents>
+getPastEvents ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get a podcast of free mp3s based on an artist.
+--
+-- More: <http://www.last.fm/api/show/artist.getPodcast>
+getPodcast ∷ Either Artist Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+
+-- | Get shouts for this artist. Also available as an rss feed.
+--
+-- More: <http://www.last.fm/api/show/artist.getShouts>
+getShouts ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get all the artists similar to this artist.
+--
+-- More: <http://www.last.fm/api/show/artist.getSimilar>
+getSimilar ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the tags applied by an individual user to an artist on Last.fm. If accessed as an authenticated service /and/ you don't supply a user parameter then this service will return tags for the authenticated user.
+--
+-- More: <http://www.last.fm/api/show/artist.getTags>
+getTags ∷ Either Artist Mbid → Maybe Autocorrect → Either User (SessionKey, Secret) → APIKey → Lastfm Response
+
+-- | Get the top albums for an artist on Last.fm, ordered by popularity.
+--
+-- More: <http://www.last.fm/api/show/artist.getTopAlbums>
+getTopAlbums ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top fans for an artist on Last.fm, based on listening data.
+--
+-- More: <http://www.last.fm/api/show/artist.getTopFans>
+getTopFans ∷ Either Artist Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+
+-- | Get the top tags for an artist on Last.fm, ordered by popularity.
+--
+-- More: <http://www.last.fm/api/show/artist.getTopTags>
+getTopTags ∷ Either Artist Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+
+-- | Get the top tracks by an artist on Last.fm, ordered by popularity.
+--
+-- More: <http://www.last.fm/api/show/artist.getTopTracks>
+getTopTracks ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Remove a user's tag from an artist.
+--
+-- More: <http://www.last.fm/api/show/artist.removeTag>
+removeTag ∷ Artist → Tag → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Search for an artist by name. Returns artist matches sorted by relevance.
+--
+-- More: <http://www.last.fm/api/show/artist.search>
+search ∷ Artist → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Share an artist with Last.fm users or other friends.
+--
+-- More: <http://www.last.fm/api/show/artist.share>
+share ∷ Artist → Recipient → Maybe Message → Maybe Public → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Shout in this artist's shoutbox.
+--
+-- More: <http://www.last.fm/api/show/artist.shout>
+shout ∷ Artist → Message → APIKey → SessionKey → Secret → Lastfm Response
diff --git a/src/Network/Lastfm/JSON/Auth.hs b/src/Network/Lastfm/JSON/Auth.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/Auth.hs
@@ -0,0 +1,7 @@
+-- | Auth API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.Auth
+  ( module Network.Lastfm.API.Auth
+  ) where
+
+import Network.Lastfm.API.Auth
diff --git a/src/Network/Lastfm/JSON/Chart.hs b/src/Network/Lastfm/JSON/Chart.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/Chart.hs
@@ -0,0 +1,42 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Chart API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.Chart
+  ( getHypedArtists, getHypedTracks, getLovedTracks
+  , getTopArtists, getTopTags, getTopTracks
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Chart as API
+
+$(json ["getHypedArtists", "getHypedTracks", "getLovedTracks", "getTopArtists", "getTopTags", "getTopTracks"])
+
+-- | Get the hyped artists chart.
+--
+-- More: <http://www.last.fm/api/show/chart.getHypedArtists>
+getHypedArtists ∷ Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the hyped tracks chart.
+--
+-- More: <http://www.last.fm/api/show/chart.getHypedTracks>
+getHypedTracks ∷ Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the most loved tracks chart.
+--
+-- More: <http://www.last.fm/api/show/chart.getLovedTracks>
+getLovedTracks ∷ Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top artists chart.
+--
+-- More: <http://www.last.fm/api/show/chart.getTopArtists>
+getTopArtists ∷ Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get top tags chart.
+--
+-- More: <http://www.last.fm/api/show/chart.getTopTags>
+getTopTags ∷ Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top tracks chart.
+--
+-- More: <http://www.last.fm/api/show/chart.getTopTracks>
+getTopTracks ∷ Maybe Page → Maybe Limit → APIKey → Lastfm Response
diff --git a/src/Network/Lastfm/JSON/Event.hs b/src/Network/Lastfm/JSON/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/Event.hs
@@ -0,0 +1,41 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Event API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.Event
+  ( attend, getAttendees, getInfo, getShouts, share, shout
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Event as API
+
+$(json ["attend", "getAttendees", "getInfo", "getShouts", "share", "shout"])
+
+-- | Set a user's attendance status for an event.
+--
+-- More: <http://www.last.fm/api/show/event.attend>
+attend ∷ Event → Status → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Get a list of attendees for an event.
+--
+-- More: <http://www.last.fm/api/show/event.getAttendees>
+getAttendees ∷ Event → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the metadata for an event on Last.fm. Includes attendance and lineup information.
+--
+-- More: <http://www.last.fm/api/show/event.getInfo>
+getInfo ∷ Event → APIKey → Lastfm Response
+
+-- | Get shouts for this event.
+--
+-- More: <http://www.last.fm/api/show/event.getShouts>
+getShouts ∷ Event → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Share an event with one or more Last.fm users or other friends.
+--
+-- More: <http://www.last.fm/api/show/event.share>
+share ∷ Event → Recipient → Maybe Message → Maybe Public → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Shout in this event's shoutbox.
+--
+-- More: <http://www.last.fm/api/show/event.shout>
+shout ∷ Event → Message → APIKey → SessionKey → Secret → Lastfm Response
diff --git a/src/Network/Lastfm/JSON/Geo.hs b/src/Network/Lastfm/JSON/Geo.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/Geo.hs
@@ -0,0 +1,75 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Geo API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.Geo
+  ( getEvents, getMetroArtistChart, getMetroHypeArtistChart, getMetroHypeTrackChart
+  , getMetroTrackChart, getMetroUniqueArtistChart, getMetroUniqueTrackChart
+  , getMetroWeeklyChartlist, getMetros, getTopArtists, getTopTracks
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Geo as API
+
+$(json ["getEvents", "getMetroArtistChart", "getMetroHypeArtistChart", "getMetroHypeTrackChart", "getMetroTrackChart", "getMetroUniqueArtistChart", "getMetroUniqueTrackChart", "getMetroWeeklyChartlist", "getMetros", "getTopArtists", "getTopTracks"])
+
+-- | Get all events in a specific location by country or city name.
+--
+-- More: <http://www.last.fm/api/show/geo.getEvents>
+getEvents ∷ Maybe Latitude
+          → Maybe Longitude
+          → Maybe Location
+          → Maybe Distance
+          → Maybe Page
+          → Maybe Limit
+          → APIKey
+          → Lastfm Response
+
+-- | Get a chart of artists for a metro.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetroArtistChart>
+getMetroArtistChart ∷ Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+
+-- | Get a chart of hyped (up and coming) artists for a metro.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetroHypeArtistChart>
+getMetroHypeArtistChart ∷ Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+
+-- | Get a chart of hyped (up and coming) tracks for a metro.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetroHypeTrackChart>
+getMetroHypeTrackChart ∷ Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+
+-- | Get a chart of tracks for a metro.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetroTrackChart>
+getMetroTrackChart ∷ Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+
+-- | Get a chart of the artists which make that metro unique.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetroUniqueArtistChart>
+getMetroUniqueArtistChart ∷ Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+
+-- | Get a chart of the tracks which make that metro unique.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetroUniqueTrackChart>
+getMetroUniqueTrackChart ∷ Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+
+-- | Get a list of available chart periods for this metro, expressed as date ranges which can be sent to the chart services.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetroWeeklyChartlist>
+getMetroWeeklyChartlist ∷ Metro → APIKey → Lastfm Response
+
+-- | Get a list of valid countries and metros for use in the other webservices.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetros>
+getMetros ∷ Maybe Country → APIKey → Lastfm Response
+
+-- | Get the most popular artists on Last.fm by country.
+--
+-- More: <http://www.last.fm/api/show/geo.getTopArtists>
+getTopArtists ∷ Country → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the most popular tracks on Last.fm last week by country.
+--
+-- More: <http://www.last.fm/api/show/geo.getTopTracks>
+getTopTracks ∷ Country → Maybe Location → Maybe Page → Maybe Limit → APIKey → Lastfm Response
diff --git a/src/Network/Lastfm/JSON/Group.hs b/src/Network/Lastfm/JSON/Group.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/Group.hs
@@ -0,0 +1,42 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Group API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.Group
+  ( getHype, getMembers, getWeeklyChartList, getWeeklyAlbumChart, getWeeklyArtistChart, getWeeklyTrackChart
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Group as API
+
+$(json ["getHype", "getMembers", "getWeeklyChartList", "getWeeklyAlbumChart", "getWeeklyArtistChart", "getWeeklyTrackChart"])
+
+-- | Get the hype list for a group.
+--
+-- More: <http://www.last.fm/api/show/group.getHype>
+getHype ∷ Group → APIKey → Lastfm Response
+
+-- | Get a list of members for this group.
+--
+-- More: <http://www.last.fm/api/show/group.getMembers>
+getMembers ∷ Group → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get an album chart for a group, for a given date range. If no date range is supplied, it will return the most recent album chart for this group.
+--
+-- More: <http://www.last.fm/api/show/group.getWeeklyAlbumChart>
+getWeeklyChartList ∷ Group → APIKey → Lastfm Response
+
+-- | Get an artist chart for a group, for a given date range. If no date range is supplied, it will return the most recent artist chart for this group.
+--
+-- More: <http://www.last.fm/api/show/group.getWeeklyArtistChart>
+getWeeklyAlbumChart ∷ Group → Maybe From → Maybe To → APIKey → Lastfm Response
+
+-- | Get a list of available charts for this group, expressed as date ranges which can be sent to the chart services.
+--
+-- More: <http://www.last.fm/api/show/group.getWeeklyChartList>
+getWeeklyArtistChart ∷ Group → Maybe From → Maybe To → APIKey → Lastfm Response
+
+
+-- | Get a track chart for a group, for a given date range. If no date range is supplied, it will return the most recent track chart for this group.
+--
+-- More: <http://www.last.fm/api/show/group.getWeeklyTrackChart>
+getWeeklyTrackChart ∷ Group → Maybe From → Maybe To → APIKey → Lastfm Response
diff --git a/src/Network/Lastfm/JSON/Library.hs b/src/Network/Lastfm/JSON/Library.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/Library.hs
@@ -0,0 +1,62 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Library API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.Library
+  ( addAlbum, addArtist, addTrack, getAlbums, getArtists, getTracks
+  , removeAlbum, removeArtist, removeScrobble, removeTrack
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Library as API
+  
+$(json ["addAlbum", "addArtist", "addTrack", "getAlbums", "getArtists", "getTracks", "removeAlbum", "removeArtist", "removeScrobble", "removeTrack"])
+
+-- | Add an album or collection of albums to a user's Last.fm library.
+--
+-- More: <http://www.last.fm/api/show/library.addAlbum>
+addAlbum ∷ Artist → Album → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Add an artist to a user's Last.fm library.
+--
+-- More: <http://www.last.fm/api/show/library.addArtist>
+addArtist ∷ Artist → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Add a track to a user's Last.fm library.
+--
+-- More: <http://www.last.fm/api/show/library.addTrack>
+addTrack ∷ Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | A paginated list of all the albums in a user's library, with play counts and tag counts.
+--
+-- More: <http://www.last.fm/api/show/library.getAlbums>
+getAlbums ∷ User → Maybe Artist → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | A paginated list of all the artists in a user's library, with play counts and tag counts.
+--
+-- More: <http://www.last.fm/api/show/library.getArtists>
+getArtists ∷ User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | A paginated list of all the tracks in a user's library, with play counts and tag counts.
+--
+-- More: <http://www.last.fm/api/show/library.getTracks>
+getTracks ∷ User → Maybe Artist → Maybe Album → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Remove an album from a user's Last.fm library.
+--
+-- More: <http://www.last.fm/api/show/library.removeAlbum>
+removeAlbum ∷ Artist → Album → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Remove an artist from a user's Last.fm library.
+--
+-- More: <http://www.last.fm/api/show/library.removeArtist>
+removeArtist ∷ Artist → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Remove a scrobble from a user's Last.fm library.
+--
+-- More: <http://www.last.fm/api/show/library.removeScrobble>
+removeScrobble ∷ Artist → Track → Timestamp → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Remove a track from a user's Last.fm library.
+--
+-- More: <http://www.last.fm/api/show/library.removeTrack>
+removeTrack ∷ Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
diff --git a/src/Network/Lastfm/JSON/Playlist.hs b/src/Network/Lastfm/JSON/Playlist.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/Playlist.hs
@@ -0,0 +1,21 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Playlist API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.Playlist
+  ( addTrack, create
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Playlist as API
+
+$(json ["addTrack", "create"])
+
+-- | Add a track to a Last.fm user's playlist.
+--
+-- More: <http://www.last.fm/api/show/playlist.addTrack>
+addTrack ∷ Playlist → Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Create a Last.fm playlist on behalf of a user.
+--
+-- More: <http://www.last.fm/api/show/playlist.create>
+create ∷ Maybe Title → Maybe Description → APIKey → SessionKey → Secret → Lastfm Response
diff --git a/src/Network/Lastfm/JSON/Radio.hs b/src/Network/Lastfm/JSON/Radio.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/Radio.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Radio API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.Radio
+  ( getPlaylist, search, tune
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Radio as API
+
+$(json ["getPlaylist", "search", "tune"])
+
+-- | Fetch new radio content periodically in an XSPF format.
+--
+-- More: <http://www.last.fm/api/show/radio.getPlaylist>
+getPlaylist ∷ Maybe Discovery
+            → Maybe RTP
+            → Maybe BuyLinks
+            → Multiplier
+            → Bitrate
+            → APIKey
+            → SessionKey
+            → Secret
+            → Lastfm Response
+
+-- | Resolve the name of a resource into a station depending on which resource it is most likely to represent.
+--
+-- More: <http://www.last.fm/api/show/radio.search>
+search ∷ Name → APIKey → Lastfm Response
+
+-- | Tune in to a Last.fm radio station.
+--
+-- More: <http://www.last.fm/api/show/radio.tune>
+tune ∷ Maybe Language → Station → APIKey → SessionKey → Secret → Lastfm Response
diff --git a/src/Network/Lastfm/JSON/Tag.hs b/src/Network/Lastfm/JSON/Tag.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/Tag.hs
@@ -0,0 +1,57 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Tag API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.Tag
+  ( getInfo, getSimilar, getTopAlbums, getTopArtists, getTopTags, getTopTracks
+  , getWeeklyArtistChart, getWeeklyChartList, search
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Tag as API
+
+$(json ["getInfo", "getSimilar", "getTopAlbums", "getTopArtists", "getTopTags", "getTopTracks", "getWeeklyArtistChart", "getWeeklyChartList", "search"])
+
+-- | Get the metadata for a tag.
+--
+-- More: <http://www.last.fm/api/show/tag.getInfo>
+getInfo ∷ Tag → Maybe Language → APIKey → Lastfm Response
+
+-- | Search for tags similar to this one. Returns tags ranked by similarity, based on listening data.
+--
+-- More: <http://www.last.fm/api/show/tag.getSimilar>
+getSimilar ∷ Tag → APIKey → Lastfm Response
+
+-- | Get the top albums tagged by this tag, ordered by tag count.
+--
+-- More: <http://www.last.fm/api/show/tag.getTopAlbums>
+getTopAlbums ∷ Tag → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top artists tagged by this tag, ordered by tag count.
+--
+-- More: <http://www.last.fm/api/show/tag.getTopArtists>
+getTopArtists ∷ Tag → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Fetches the top global tags on Last.fm, sorted by popularity (number of times used).
+--
+-- More: <http://www.last.fm/api/show/tag.getTopTags>
+getTopTags ∷ APIKey → Lastfm Response
+
+-- | Get the top tracks tagged by this tag, ordered by tag count.
+--
+-- More: <http://www.last.fm/api/show/tag.getTopTracks>
+getTopTracks ∷ Tag → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get an artist chart for a tag, for a given date range. If no date range is supplied, it will return the most recent artist chart for this tag.
+--
+-- More: <http://www.last.fm/api/show/tag.getWeeklyArtistChart>
+getWeeklyArtistChart ∷ Tag → Maybe From → Maybe To → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get a list of available charts for this tag, expressed as date ranges which can be sent to the chart services.
+--
+-- More: <http://www.last.fm/api/show/tag.getWeeklyChartList>
+getWeeklyChartList ∷ Tag → APIKey → Lastfm Response
+
+-- | Search for a tag by name. Returns matches sorted by relevance.
+--
+-- More: <http://www.last.fm/api/show/tag.search>
+search ∷ Tag → Maybe Page → Maybe Limit → APIKey → Lastfm Response
diff --git a/src/Network/Lastfm/JSON/Tasteometer.hs b/src/Network/Lastfm/JSON/Tasteometer.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/Tasteometer.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Tasteometer API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.Tasteometer
+  ( compare
+  ) where
+
+import Prelude hiding (compare)
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Tasteometer as API
+
+$(json ["compare"])
+
+-- | Get a Tasteometer score from two inputs, along with a list of shared artists. If the input is a User some additional information is returned.
+--
+-- More: <http://www.last.fm/api/show/tasteometer.compare>
+compare ∷ Value → Value → Maybe Limit → APIKey → Lastfm Response
diff --git a/src/Network/Lastfm/JSON/Track.hs b/src/Network/Lastfm/JSON/Track.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/Track.hs
@@ -0,0 +1,126 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Track API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.Track
+  ( addTags, ban, getBuyLinks, getCorrection, getFingerprintMetadata
+  , getInfo, getShouts, getSimilar, getTags, getTopFans, getTopTags
+  , love, removeTag, scrobble, search, share, unban, unlove, updateNowPlaying
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Track as API
+
+$(json ["addTags", "ban", "getBuyLinks", "getCorrection", "getFingerprintMetadata", "getInfo", "getShouts", "getSimilar", "getTags", "getTopFans", "getTopTags", "love", "removeTag", "scrobble", "search", "share", "unban", "unlove", "updateNowPlaying"])
+
+-- | Tag a track using a list of user supplied tags.
+--
+-- More: <http://www.last.fm/api/show/track.addTags>
+addTags ∷ Artist → Track → [Tag] → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Ban a track for a given user profile.
+--
+-- More: <http://www.last.fm/api/show/track.ban>
+ban ∷ Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Get a list of Buy Links for a particular track.
+--
+-- More: <http://www.last.fm/api/show/track.getBuylinks>
+getBuyLinks ∷ Either (Artist, Track) Mbid → Maybe Autocorrect → Country → APIKey → Lastfm Response
+
+-- | Use the last.fm corrections data to check whether the supplied track has a correction to a canonical track.
+--
+-- More: <http://www.last.fm/api/show/track.getCorrection>
+getCorrection ∷ Artist → Track → APIKey → Lastfm Response
+
+-- | Retrieve track metadata associated with a fingerprint id generated by the Last.fm Fingerprinter. Returns track elements, along with a 'rank' value between 0 and 1 reflecting the confidence for each match.
+--
+-- More: <http://www.last.fm/api/show/track.getFingerprintMetadata>
+getFingerprintMetadata ∷ Fingerprint → APIKey → Lastfm Response
+
+-- | Get the metadata for a track on Last.fm.
+--
+-- More: <http://www.last.fm/api/show/track.getInfo>
+getInfo ∷ Either (Artist, Track) Mbid → Maybe Autocorrect → Maybe Username → APIKey → Lastfm Response
+
+-- | Get shouts for this track. Also available as an rss feed.
+--
+-- More: <http://www.last.fm/api/show/track.getShouts>
+getShouts ∷ Either (Artist, Track) Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the similar tracks for this track on Last.fm, based on listening data.
+--
+-- More: <http://www.last.fm/api/show/track.getSimilar>
+getSimilar ∷ Either (Artist, Track) Mbid → Maybe Autocorrect → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the tags applied by an individual user to a track on Last.fm.
+--
+-- More: <http://www.last.fm/api/show/track.getTags>
+getTags ∷ Either (Artist, Track) Mbid → Maybe Autocorrect → Either User (SessionKey, Secret) → APIKey → Lastfm Response
+
+-- | Get the top fans for this track on Last.fm, based on listening data.
+--
+-- More: <http://www.last.fm/api/show/track.getTopFans>
+getTopFans ∷ Either (Artist, Track) Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+
+-- | Get the top tags for this track on Last.fm, ordered by tag count.
+--
+-- More: <http://www.last.fm/api/show/track.getTopTags>
+getTopTags ∷ Either (Artist, Track) Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+
+-- | Love a track for a user profile.
+--
+-- More: <http://www.last.fm/api/show/track.love>
+love ∷ Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Remove a user's tag from a track.
+--
+-- More: <http://www.last.fm/api/show/track.removeTag>
+removeTag ∷ Artist → Track → Tag → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Used to add a track-play to a user's profile.
+--
+-- More: <http://www.last.fm/api/show/track.scrobble>
+scrobble ∷ ( Timestamp, Maybe Album, Artist, Track, Maybe AlbumArtist
+           , Maybe Duration, Maybe StreamId, Maybe ChosenByUser
+           , Maybe Context, Maybe TrackNumber, Maybe Mbid )
+         → APIKey
+         → SessionKey
+         → Secret
+         → Lastfm Response
+
+-- | Search for a track by track name. Returns track matches sorted by relevance.
+--
+-- More: <http://www.last.fm/api/show/track.search>
+search ∷ Track → Maybe Page → Maybe Limit → Maybe Artist → APIKey → Lastfm Response
+
+-- | Share a track twith one or more Last.fm users or other friends.
+--
+-- More: <http://www.last.fm/api/show/track.share>
+share ∷ Artist → Track → Recipient → Maybe Message → Maybe Public → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Unban a track for a user profile.
+--
+-- More: <http://www.last.fm/api/show/track.unban>
+unban ∷ Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Unlove a track for a user profile.
+--
+-- More: <http://www.last.fm/api/show/track.unlove>
+unlove ∷ Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+
+
+-- | Used to notify Last.fm that a user has started listening to a track. Parameter names are case sensitive.
+--
+-- More: <http://www.last.fm/api/show/track.updateNowPlaying>
+updateNowPlaying ∷ Artist
+                 → Track
+                 → Maybe Album
+                 → Maybe AlbumArtist
+                 → Maybe Context
+                 → Maybe TrackNumber
+                 → Maybe Mbid
+                 → Maybe Duration
+                 → APIKey
+                 → SessionKey
+                 → Secret
+                 → Lastfm Response
diff --git a/src/Network/Lastfm/JSON/User.hs b/src/Network/Lastfm/JSON/User.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/User.hs
@@ -0,0 +1,140 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | User API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.User
+  ( getArtistTracks, getBannedTracks, getEvents, getFriends, getInfo, getLovedTracks
+  , getNeighbours, getNewReleases, getPastEvents, getPersonalTags, getPlaylists, getRecentStations
+  , getRecentTracks, getRecommendedArtists, getRecommendedEvents, getShouts, getTopAlbums
+  , getTopArtists, getTopTags, getTopTracks, getWeeklyAlbumChart, getWeeklyArtistChart
+  , getWeeklyChartList, getWeeklyTrackChart, shout
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.User as API
+
+$(json ["getArtistTracks", "getBannedTracks", "getEvents", "getFriends", "getInfo", "getLovedTracks", "getNeighbours", "getNewReleases", "getPastEvents", "getPersonalTags", "getPlaylists", "getRecentStations", "getRecentTracks", "getRecommendedArtists", "getRecommendedEvents", "getShouts", "getTopAlbums", "getTopArtists", "getTopTags", "getTopTracks", "getWeeklyAlbumChart", "getWeeklyArtistChart", "getWeeklyChartList", "getWeeklyTrackChart", "shout"])
+
+-- | Get a list of tracks by a given artist scrobbled by this user, including scrobble time. Can be limited to specific timeranges, defaults to all time.
+--
+-- More: <http://www.last.fm/api/show/user.getArtistTracks>
+getArtistTracks ∷ User → Artist → Maybe StartTimestamp → Maybe EndTimestamp → Maybe Page → APIKey → Lastfm Response
+
+-- | Returns the tracks banned by the user.
+--
+-- More: <http://www.last.fm/api/show/user.getBannedTracks>
+getBannedTracks ∷ User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get a list of upcoming events that this user is attending.
+--
+-- Mpre: <http://www.last.fm/api/show/user.getEvents>
+getEvents ∷ User → Maybe Page → Maybe Limit → Maybe FestivalsOnly → APIKey → Lastfm Response
+
+-- | Get a list of the user's friends on Last.fm.
+--
+-- More: <http://www.last.fm/api/show/user.getFriends>
+getFriends ∷ User → Maybe RecentTracks → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get information about a user profile.
+--
+-- More: <http://www.last.fm/api/show/user.getInfo>
+getInfo ∷ Maybe User → APIKey → Lastfm Response
+
+-- | Get tracks loved by a user.
+--
+-- More: <http://www.last.fm/api/show/user.getLovedTracks>
+getLovedTracks ∷ User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get a list of a user's neighbours on Last.fm.
+--
+-- More: <http://www.last.fm/api/show/user.getNeighbours>
+getNeighbours ∷ User → Maybe Limit → APIKey → Lastfm Response
+
+-- | Gets a list of forthcoming releases based on a user's musical taste.
+--
+-- More: <http://www.last.fm/api/show/user.getNewReleases>
+getNewReleases ∷ User → Maybe UseRecs → APIKey → Lastfm Response
+
+-- | Get a paginated list of all events a user has attended in the past.
+--
+-- More: <http://www.last.fm/api/show/user.getPastEvents>
+getPastEvents ∷ User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the user's personal tags.
+--
+-- More: <http://www.last.fm/api/show/user.getPersonalTags>
+getPersonalTags ∷ User → Tag → TaggingType → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get a list of a user's playlists on Last.fm.
+--
+-- More: <http://www.last.fm/api/show/user.getPlaylists>
+getPlaylists ∷ User → APIKey → Lastfm Response
+
+-- | Get a list of the recent Stations listened to by this user.
+--
+-- More: <http://www.last.fm/api/show/user.getRecentStations>
+getRecentStations ∷ User → Maybe Page → Maybe Limit → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Get a list of the recent tracks listened to by this user. Also includes the currently playing track with the nowplaying="true" attribute if the user is currently listening.
+--
+-- More: <http://www.last.fm/api/show/user.getRecentTracks>
+getRecentTracks ∷ User → Maybe Page → Maybe Limit → Maybe From → Maybe To → APIKey → Lastfm Response
+
+-- | Get Last.fm artist recommendations for a user.
+--
+-- Mpre: <http://www.last.fm/api/show/user.getRecommendedArtists>
+getRecommendedArtists ∷ Maybe Page → Maybe Limit → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Get a paginated list of all events recommended to a user by Last.fm, based on their listening profile.
+--
+-- More: <http://www.last.fm/api/show/user.getRecommendedEvents>
+getRecommendedEvents ∷ Maybe Page → Maybe Limit → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Get shouts for this user. Also available as an rss feed.
+--
+-- More: <http://www.last.fm/api/show/user.getShouts>
+getShouts ∷ User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top albums listened to by a user. You can stipulate a time period. Sends the overall chart by default.
+--
+-- More: <http://www.last.fm/api/show/user.getTopAlbums>
+getTopAlbums ∷ User → Maybe Period → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top artists listened to by a user. You can stipulate a time period. Sends the overall chart by default.
+--
+-- More: <http://www.last.fm/api/show/user.getTopArtists>
+getTopArtists ∷ User → Maybe Period → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top tags used by this user.
+--
+-- More: <http://www.last.fm/api/show/user.getTopTags>
+getTopTags ∷ User → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top tracks listened to by a user. You can stipulate a time period. Sends the overall chart by default.
+--
+-- More: <http://www.last.fm/api/show/user.getTopTracks>
+getTopTracks ∷ User → Maybe Period → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get an album chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent album chart for this user.
+--
+-- More: <http://www.last.fm/api/show/user.getWeeklyAlbumChart>
+getWeeklyAlbumChart ∷ User → Maybe From → Maybe To → APIKey → Lastfm Response
+
+-- | Get an artist chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent artist chart for this user.
+--
+-- More: <http://www.last.fm/api/show/user.getWeeklyArtistChart>
+getWeeklyArtistChart ∷ User → Maybe From → Maybe To → APIKey → Lastfm Response
+
+-- | Get a list of available charts for this user, expressed as date ranges which can be sent to the chart services.
+--
+-- More: <http://www.last.fm/api/show/user.getWeeklyChartList>
+getWeeklyChartList ∷ User → APIKey → Lastfm Response
+
+-- | Get a track chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent track chart for this user.
+--
+-- More: <http://www.last.fm/api/show/user.getWeeklyTrackChart>
+getWeeklyTrackChart ∷ User → Maybe From → Maybe To → APIKey → Lastfm Response
+
+-- | Shout on this user's shoutbox.
+--
+-- More: <http://www.last.fm/api/show/user.shout>
+shout ∷ User → Message → APIKey → SessionKey → Secret → Lastfm Response
diff --git a/src/Network/Lastfm/JSON/Venue.hs b/src/Network/Lastfm/JSON/Venue.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/JSON/Venue.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Venue API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.JSON.Venue
+  ( getEvents, getPastEvents, search
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Venue as API
+
+$(json ["getEvents", "getPastEvents", "search"])
+
+-- | Get a list of upcoming events at this venue.
+--
+-- More: <http://www.last.fm/api/show/venue.getEvents>
+getEvents ∷ Venue → Maybe FestivalsOnly → APIKey → Lastfm Response
+
+-- | Get a paginated list of all the events held at this venue in the past.
+--
+-- More: <http://www.last.fm/api/show/venue.getPastEvents>
+getPastEvents ∷ Venue → Maybe FestivalsOnly → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Search for a venue by venue name.
+--
+-- More: <http://www.last.fm/api/show/venue.search>
+search ∷ Venuename → Maybe Page → Maybe Limit → Maybe Country → APIKey → Lastfm Response
diff --git a/src/Network/Lastfm/TH.hs b/src/Network/Lastfm/TH.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/TH.hs
@@ -0,0 +1,17 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE ViewPatterns #-}
+module Network.Lastfm.TH where
+
+import Language.Haskell.TH
+
+instances ∷ String → [(String, String)] → Q [Dec]
+instances f = mapM (instanceDeclaration "Argument")
+  where instanceDeclaration (mkName → tc) (mkName → n, m) = instanceD (cxt []) (appT (conT tc) (conT n)) [first, second]
+          where first = funD (mkName "key") [clause [] (normalB [e| const m |]) []]
+                second = let var = mkName "a"
+                             func = mkName f
+                         in funD (mkName "value") [clause [conP n [varP var]] (normalB $ appE (varE func) (varE var)) []] 
+
+newtypes ∷ String → [String] → Q [Dec]
+newtypes (mkName → t) (map mkName → ns) = mapM newtypeDeclaration ns
+  where newtypeDeclaration n = newtypeD (cxt []) n [] (normalC n [strictType notStrict (conT t)]) []
diff --git a/src/Network/Lastfm/Types.hs b/src/Network/Lastfm/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/Types.hs
@@ -0,0 +1,162 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TemplateHaskell #-}
+module Network.Lastfm.Types where
+
+import Control.Applicative ((<$>), empty)
+import Control.Monad (liftM)
+import Data.Aeson ((.:), FromJSON, decode, parseJSON)
+import Data.ByteString.Lazy.Char8 (ByteString)
+import Data.List (intercalate)
+import Data.Maybe (fromJust)
+import qualified Data.Aeson
+
+import Network.Lastfm.TH
+
+newtype Secret = Secret String
+
+$(newtypes "String" ["Album", "AlbumArtist", "APIKey", "Artist", "AuthToken",
+  "Context", "Country", "Description", "Group", "Language", "Latitude",
+  "Location", "Longitude", "Mbid", "Message", "Method", "Metro", "Name",
+  "Recipient", "SessionKey", "Station", "StreamId", "Tag", "TaggingType",
+  "Title", "Token", "Track", "User", "Username", "Venuename", "ChosenByUser"])
+$(newtypes "Bool" ["Autocorrect", "BuyLinks", "Discovery", "FestivalsOnly", "Public", "RecentTracks", "RTP", "UseRecs"])
+$(newtypes "Int" ["Distance", "Duration", "Event", "Limit", "Page", "Playlist", "TrackNumber", "Venue"])
+$(newtypes "Integer" ["End", "EndTimestamp", "Fingerprint", "From", "Start", "StartTimestamp", "Timestamp", "To"])
+
+data Bitrate = B64 | B128
+data Multiplier = M1 | M2
+data Order = Popularity | DateAdded
+data Status = Yes | Maybe | No
+data Value = ValueUser User
+           | ValueArtists [Artist]
+data Period = Week | Quater | HalfYear | Year | Overall
+
+instance Show Value where
+  show (ValueUser _)    = "user"
+  show (ValueArtists _) = "artists"
+
+instance FromJSON Token where
+  parseJSON (Data.Aeson.Object v) = Token <$> v .: "token"
+  parseJSON _ = empty
+instance FromJSON SessionKey where
+  parseJSON (Data.Aeson.Object v) = SessionKey <$> ((v .: "session") >>= (.: "key"))
+  parseJSON _ = empty
+
+simple ∷ (FromJSON a, Monad m) ⇒ m ByteString → m a
+simple = liftM (fromJust . decode)
+
+class Argument a where
+  key ∷ a → String
+  value ∷ a → String
+
+(#) ∷ Argument a ⇒ a → (String, String)
+(#) x = (key x, value x)
+
+instance Argument a ⇒ Argument (Maybe a) where key = maybe "" key; value = maybe "" value
+instance Argument a ⇒ Argument [a] where
+  key (a:_) = key a ++ "s"
+  key [] = ""
+  value = intercalate "," . map value
+
+boolToString ∷ Bool → String
+boolToString True = "1"
+boolToString False = "0"
+
+--instance Argument $first where key = const $second; value ($first a) = $func a
+$(instances "id"
+  [ ("Album","album")
+  , ("AlbumArtist", "albumartist")
+  , ("APIKey", "api_key")
+  , ("Artist", "artist")
+  , ("AuthToken", "authToken")
+  , ("ChosenByUser", "chosenByUser")
+  , ("Context", "context")
+  , ("Country", "country")
+  , ("Description", "description")
+  , ("Group", "group")
+  , ("Language", "lang")
+  , ("Latitude", "lat")
+  , ("Location", "location")
+  , ("Longitude", "long")
+  , ("Mbid", "mbid")
+  , ("Message", "message")
+  , ("Method", "method")
+  , ("Metro", "metro")
+  , ("Name", "name")
+  , ("Recipient", "recipient")
+  , ("SessionKey", "sk")
+  , ("Station", "station")
+  , ("StreamId", "streamId")
+  , ("Tag", "tag")
+  , ("TaggingType", "taggingtype")
+  , ("Title", "title")
+  , ("Token", "token")
+  , ("Track", "track")
+  , ("User", "user")
+  , ("Username", "username")
+  , ("Venuename", "venue")
+  ])
+
+$( instances "boolToString"
+  [ ("Autocorrect", "autocorrect")
+  , ("BuyLinks", "buylinks")
+  , ("Discovery", "discovery")
+  , ("FestivalsOnly", "festivalsonly")
+  , ("Public", "public")
+  , ("RecentTracks", "recenttracks")
+  , ("RTP", "rtp")
+  , ("UseRecs", "userecs")
+  ])
+
+$( instances "show"
+  [ ("Distance", "distance")
+  , ("Duration", "duration")
+  , ("Event", "event")
+  , ("Limit", "limit")
+  , ("Page", "page")
+  , ("Playlist", "playlistID")
+  , ("TrackNumber", "tracknumber")
+  , ("Venue", "venue")
+  , ("End", "end")
+  , ("EndTimestamp", "endTimestamp")
+  , ("Fingerprint", "fingerprintid")
+  , ("From", "from")
+  , ("Start", "start")
+  , ("StartTimestamp", "startTimestamp")
+  , ("Timestamp", "timestamp")
+  , ("To", "to")
+  ])
+
+instance Argument Bitrate where
+  key = const "bitrate"
+  value B64 = "64"
+  value B128 = "128"
+
+instance Argument Multiplier where
+  key = const "speed_multiplier"
+  value M1 = "1.0"
+  value M2 = "2.0"
+
+instance Argument Order where
+  key = const "order"
+  value Popularity = "popularity"
+  value DateAdded  = "dateadded"
+
+instance Argument Status where
+  key = const "status"
+  value Yes = "0"
+  value Maybe = "1"
+  value No = "2"
+
+instance Argument Value where
+  key = const "value"
+  value (ValueUser u)     = value u
+  value (ValueArtists as) = value as
+
+instance Argument Period where
+  key = const "period"
+  value Week     = "7day"
+  value Quater   = "3month"
+  value HalfYear = "6month"
+  value Year     = "12month"
+  value Overall  = "overall"
diff --git a/src/Network/Lastfm/XML/Album.hs b/src/Network/Lastfm/XML/Album.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/Album.hs
@@ -0,0 +1,57 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Album API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.Album
+  ( addTags, getBuyLinks, getInfo, getShouts, getTags
+  , getTopTags, removeTag, search, share
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Album as API
+
+$(xml ["addTags", "getBuyLinks", "getInfo", "getShouts", "getTags", "getTopTags", "removeTag", "search", "share"])
+
+-- | Tag an album using a list of user supplied tags.
+--
+-- More: <http://www.last.fm/api/show/album.addTags>
+addTags ∷ (Artist, Album) → [Tag] → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Get a list of Buy Links for a particular Album. It is required that you supply either the artist and track params or the mbid param.
+--
+-- More: <http://www.last.fm/api/show/album.getBuylinks>
+getBuyLinks ∷ Either (Artist, Album) Mbid → Maybe Autocorrect → Country → APIKey → Lastfm Response
+
+-- | Get the metadata for an album on Last.fm using the album name or a musicbrainz id. See playlist.fetch on how to get the album playlist.
+--
+-- More: <http://www.last.fm/api/show/album.getInfo>
+getInfo ∷ Either (Artist, Album) Mbid → Maybe Autocorrect → Maybe Language → Maybe Username → APIKey → Lastfm Response
+
+-- | Get shouts for this album.
+--
+-- More: <http://www.last.fm/api/show/album.getShouts>
+getShouts ∷ Either (Artist, Album) Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the tags applied by an individual user to an album on Last.fm.
+--
+-- More: <http://www.last.fm/api/show/album.getTags>
+getTags ∷ Either (Artist, Album) Mbid → Maybe Autocorrect → Either User (SessionKey, Secret) → APIKey → Lastfm Response
+
+-- | Get the top tags for an album on Last.fm, ordered by popularity.
+--
+-- More: <http://www.last.fm/api/show/album.getTopTags>
+getTopTags ∷ Either (Artist, Album) Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+
+-- | Remove a user's tag from an album.
+--
+-- More: <http://www.last.fm/api/show/album.removeTag>
+removeTag ∷ Artist → Album → Tag → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Search for an album by name. Returns album matches sorted by relevance.
+--
+-- More: <http://www.last.fm/api/show/album.search>
+search ∷ Album → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Share an album with one or more Last.fm users or other friends.
+--
+-- More: <http://www.last.fm/api/show/album.share>
+share ∷ Artist → Album → Recipient → Maybe Message → Maybe Public → APIKey → SessionKey → Secret → Lastfm Response
diff --git a/src/Network/Lastfm/XML/Artist.hs b/src/Network/Lastfm/XML/Artist.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/Artist.hs
@@ -0,0 +1,103 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Artist API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.Artist
+  ( addTags, getCorrection, getEvents, getImages, getInfo
+  , getPastEvents, getPodcast, getShouts, getSimilar, getTags, getTopAlbums
+  , getTopFans, getTopTags, getTopTracks, removeTag, search, share, shout
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Artist as API
+  
+$(xml ["addTags", "getCorrection", "getEvents", "getImages", "getInfo", "getPastEvents", "getPodcast", "getShouts", "getSimilar", "getTags", "getTopAlbums", "getTopFans", "getTopTags", "getTopTracks", "removeTag", "search", "share", "shout"])
+
+-- | Tag an album using a list of user supplied tags.
+--
+-- More: <http://www.last.fm/api/show/artist.addTags>
+addTags ∷ Artist → [Tag] → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Use the last.fm corrections data to check whether the supplied artist has a correction to a canonical artist
+--
+-- More: <http://www.last.fm/api/show/artist.getCorrection>
+getCorrection ∷ Artist → APIKey → Lastfm Response
+
+-- | Get a list of upcoming events for this artist.
+--
+-- More: <http://www.last.fm/api/show/artist.getEvents>
+getEvents ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → Maybe FestivalsOnly → APIKey → Lastfm Response
+
+-- | Get Images for this artist in a variety of sizes.
+--
+-- More: <http://www.last.fm/api/show/artist.getImages>
+getImages ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → Maybe Order → APIKey → Lastfm Response
+
+-- | Get the metadata for an artist. Includes biography.
+--
+-- More: <http://www.last.fm/api/show/artist.getInfo>
+getInfo ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Language → Maybe Username → APIKey → Lastfm Response
+
+-- | Get a paginated list of all the events this artist has played at in the past.
+--
+-- More: <http://www.last.fm/api/show/artist.getPastEvents>
+getPastEvents ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get a podcast of free mp3s based on an artist.
+--
+-- More: <http://www.last.fm/api/show/artist.getPodcast>
+getPodcast ∷ Either Artist Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+
+-- | Get shouts for this artist. Also available as an rss feed.
+--
+-- More: <http://www.last.fm/api/show/artist.getShouts>
+getShouts ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get all the artists similar to this artist.
+--
+-- More: <http://www.last.fm/api/show/artist.getSimilar>
+getSimilar ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the tags applied by an individual user to an artist on Last.fm. If accessed as an authenticated service /and/ you don't supply a user parameter then this service will return tags for the authenticated user.
+--
+-- More: <http://www.last.fm/api/show/artist.getTags>
+getTags ∷ Either Artist Mbid → Maybe Autocorrect → Either User (SessionKey, Secret) → APIKey → Lastfm Response
+
+-- | Get the top albums for an artist on Last.fm, ordered by popularity.
+--
+-- More: <http://www.last.fm/api/show/artist.getTopAlbums>
+getTopAlbums ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top fans for an artist on Last.fm, based on listening data.
+--
+-- More: <http://www.last.fm/api/show/artist.getTopFans>
+getTopFans ∷ Either Artist Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+
+-- | Get the top tags for an artist on Last.fm, ordered by popularity.
+--
+-- More: <http://www.last.fm/api/show/artist.getTopTags>
+getTopTags ∷ Either Artist Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+
+-- | Get the top tracks by an artist on Last.fm, ordered by popularity.
+--
+-- More: <http://www.last.fm/api/show/artist.getTopTracks>
+getTopTracks ∷ Either Artist Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Remove a user's tag from an artist.
+--
+-- More: <http://www.last.fm/api/show/artist.removeTag>
+removeTag ∷ Artist → Tag → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Search for an artist by name. Returns artist matches sorted by relevance.
+--
+-- More: <http://www.last.fm/api/show/artist.search>
+search ∷ Artist → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Share an artist with Last.fm users or other friends.
+--
+-- More: <http://www.last.fm/api/show/artist.share>
+share ∷ Artist → Recipient → Maybe Message → Maybe Public → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Shout in this artist's shoutbox.
+--
+-- More: <http://www.last.fm/api/show/artist.shout>
+shout ∷ Artist → Message → APIKey → SessionKey → Secret → Lastfm Response
diff --git a/src/Network/Lastfm/XML/Auth.hs b/src/Network/Lastfm/XML/Auth.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/Auth.hs
@@ -0,0 +1,7 @@
+-- | Auth API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.Auth
+  ( module Network.Lastfm.API.Auth
+  ) where
+
+import Network.Lastfm.API.Auth
diff --git a/src/Network/Lastfm/XML/Chart.hs b/src/Network/Lastfm/XML/Chart.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/Chart.hs
@@ -0,0 +1,42 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Chart API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.Chart
+  ( getHypedArtists, getHypedTracks, getLovedTracks
+  , getTopArtists, getTopTags, getTopTracks
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Chart as API
+
+$(xml ["getHypedArtists", "getHypedTracks", "getLovedTracks", "getTopArtists", "getTopTags", "getTopTracks"])
+
+-- | Get the hyped artists chart.
+--
+-- More: <http://www.last.fm/api/show/chart.getHypedArtists>
+getHypedArtists ∷ Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the hyped tracks chart.
+--
+-- More: <http://www.last.fm/api/show/chart.getHypedTracks>
+getHypedTracks ∷ Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the most loved tracks chart.
+--
+-- More: <http://www.last.fm/api/show/chart.getLovedTracks>
+getLovedTracks ∷ Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top artists chart.
+--
+-- More: <http://www.last.fm/api/show/chart.getTopArtists>
+getTopArtists ∷ Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get top tags chart.
+--
+-- More: <http://www.last.fm/api/show/chart.getTopTags>
+getTopTags ∷ Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top tracks chart.
+--
+-- More: <http://www.last.fm/api/show/chart.getTopTracks>
+getTopTracks ∷ Maybe Page → Maybe Limit → APIKey → Lastfm Response
diff --git a/src/Network/Lastfm/XML/Event.hs b/src/Network/Lastfm/XML/Event.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/Event.hs
@@ -0,0 +1,41 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Event API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.Event
+  ( attend, getAttendees, getInfo, getShouts, share, shout
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Event as API
+
+$(xml ["attend", "getAttendees", "getInfo", "getShouts", "share", "shout"])
+
+-- | Set a user's attendance status for an event.
+--
+-- More: <http://www.last.fm/api/show/event.attend>
+attend ∷ Event → Status → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Get a list of attendees for an event.
+--
+-- More: <http://www.last.fm/api/show/event.getAttendees>
+getAttendees ∷ Event → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the metadata for an event on Last.fm. Includes attendance and lineup information.
+--
+-- More: <http://www.last.fm/api/show/event.getInfo>
+getInfo ∷ Event → APIKey → Lastfm Response
+
+-- | Get shouts for this event.
+--
+-- More: <http://www.last.fm/api/show/event.getShouts>
+getShouts ∷ Event → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Share an event with one or more Last.fm users or other friends.
+--
+-- More: <http://www.last.fm/api/show/event.share>
+share ∷ Event → Recipient → Maybe Message → Maybe Public → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Shout in this event's shoutbox.
+--
+-- More: <http://www.last.fm/api/show/event.shout>
+shout ∷ Event → Message → APIKey → SessionKey → Secret → Lastfm Response
diff --git a/src/Network/Lastfm/XML/Geo.hs b/src/Network/Lastfm/XML/Geo.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/Geo.hs
@@ -0,0 +1,75 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Geo API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.Geo
+  ( getEvents, getMetroArtistChart, getMetroHypeArtistChart, getMetroHypeTrackChart
+  , getMetroTrackChart, getMetroUniqueArtistChart, getMetroUniqueTrackChart
+  , getMetroWeeklyChartlist, getMetros, getTopArtists, getTopTracks
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Geo as API
+
+$(xml ["getEvents", "getMetroArtistChart", "getMetroHypeArtistChart", "getMetroHypeTrackChart", "getMetroTrackChart", "getMetroUniqueArtistChart", "getMetroUniqueTrackChart", "getMetroWeeklyChartlist", "getMetros", "getTopArtists", "getTopTracks"])
+
+-- | Get all events in a specific location by country or city name.
+--
+-- More: <http://www.last.fm/api/show/geo.getEvents>
+getEvents ∷ Maybe Latitude
+          → Maybe Longitude
+          → Maybe Location
+          → Maybe Distance
+          → Maybe Page
+          → Maybe Limit
+          → APIKey
+          → Lastfm Response
+
+-- | Get a chart of artists for a metro.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetroArtistChart>
+getMetroArtistChart ∷ Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+
+-- | Get a chart of hyped (up and coming) artists for a metro.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetroHypeArtistChart>
+getMetroHypeArtistChart ∷ Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+
+-- | Get a chart of hyped (up and coming) tracks for a metro.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetroHypeTrackChart>
+getMetroHypeTrackChart ∷ Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+
+-- | Get a chart of tracks for a metro.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetroTrackChart>
+getMetroTrackChart ∷ Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+
+-- | Get a chart of the artists which make that metro unique.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetroUniqueArtistChart>
+getMetroUniqueArtistChart ∷ Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+
+-- | Get a chart of the tracks which make that metro unique.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetroUniqueTrackChart>
+getMetroUniqueTrackChart ∷ Country → Metro → Maybe Start → Maybe End → APIKey → Lastfm Response
+
+-- | Get a list of available chart periods for this metro, expressed as date ranges which can be sent to the chart services.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetroWeeklyChartlist>
+getMetroWeeklyChartlist ∷ Metro → APIKey → Lastfm Response
+
+-- | Get a list of valid countries and metros for use in the other webservices.
+--
+-- More: <http://www.last.fm/api/show/geo.getMetros>
+getMetros ∷ Maybe Country → APIKey → Lastfm Response
+
+-- | Get the most popular artists on Last.fm by country.
+--
+-- More: <http://www.last.fm/api/show/geo.getTopArtists>
+getTopArtists ∷ Country → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the most popular tracks on Last.fm last week by country.
+--
+-- More: <http://www.last.fm/api/show/geo.getTopTracks>
+getTopTracks ∷ Country → Maybe Location → Maybe Page → Maybe Limit → APIKey → Lastfm Response
diff --git a/src/Network/Lastfm/XML/Group.hs b/src/Network/Lastfm/XML/Group.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/Group.hs
@@ -0,0 +1,42 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Group API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.Group
+  ( getHype, getMembers, getWeeklyChartList, getWeeklyAlbumChart, getWeeklyArtistChart, getWeeklyTrackChart
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Group as API
+
+$(xml ["getHype", "getMembers", "getWeeklyChartList", "getWeeklyAlbumChart", "getWeeklyArtistChart", "getWeeklyTrackChart"])
+
+-- | Get the hype list for a group.
+--
+-- More: <http://www.last.fm/api/show/group.getHype>
+getHype ∷ Group → APIKey → Lastfm Response
+
+-- | Get a list of members for this group.
+--
+-- More: <http://www.last.fm/api/show/group.getMembers>
+getMembers ∷ Group → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get an album chart for a group, for a given date range. If no date range is supplied, it will return the most recent album chart for this group.
+--
+-- More: <http://www.last.fm/api/show/group.getWeeklyAlbumChart>
+getWeeklyChartList ∷ Group → APIKey → Lastfm Response
+
+-- | Get an artist chart for a group, for a given date range. If no date range is supplied, it will return the most recent artist chart for this group.
+--
+-- More: <http://www.last.fm/api/show/group.getWeeklyArtistChart>
+getWeeklyAlbumChart ∷ Group → Maybe From → Maybe To → APIKey → Lastfm Response
+
+-- | Get a list of available charts for this group, expressed as date ranges which can be sent to the chart services.
+--
+-- More: <http://www.last.fm/api/show/group.getWeeklyChartList>
+getWeeklyArtistChart ∷ Group → Maybe From → Maybe To → APIKey → Lastfm Response
+
+
+-- | Get a track chart for a group, for a given date range. If no date range is supplied, it will return the most recent track chart for this group.
+--
+-- More: <http://www.last.fm/api/show/group.getWeeklyTrackChart>
+getWeeklyTrackChart ∷ Group → Maybe From → Maybe To → APIKey → Lastfm Response
diff --git a/src/Network/Lastfm/XML/Library.hs b/src/Network/Lastfm/XML/Library.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/Library.hs
@@ -0,0 +1,62 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Library API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.Library
+  ( addAlbum, addArtist, addTrack, getAlbums, getArtists, getTracks
+  , removeAlbum, removeArtist, removeScrobble, removeTrack
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Library as API
+  
+$(xml ["addAlbum", "addArtist", "addTrack", "getAlbums", "getArtists", "getTracks", "removeAlbum", "removeArtist", "removeScrobble", "removeTrack"])
+
+-- | Add an album or collection of albums to a user's Last.fm library.
+--
+-- More: <http://www.last.fm/api/show/library.addAlbum>
+addAlbum ∷ Artist → Album → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Add an artist to a user's Last.fm library.
+--
+-- More: <http://www.last.fm/api/show/library.addArtist>
+addArtist ∷ Artist → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Add a track to a user's Last.fm library.
+--
+-- More: <http://www.last.fm/api/show/library.addTrack>
+addTrack ∷ Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | A paginated list of all the albums in a user's library, with play counts and tag counts.
+--
+-- More: <http://www.last.fm/api/show/library.getAlbums>
+getAlbums ∷ User → Maybe Artist → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | A paginated list of all the artists in a user's library, with play counts and tag counts.
+--
+-- More: <http://www.last.fm/api/show/library.getArtists>
+getArtists ∷ User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | A paginated list of all the tracks in a user's library, with play counts and tag counts.
+--
+-- More: <http://www.last.fm/api/show/library.getTracks>
+getTracks ∷ User → Maybe Artist → Maybe Album → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Remove an album from a user's Last.fm library.
+--
+-- More: <http://www.last.fm/api/show/library.removeAlbum>
+removeAlbum ∷ Artist → Album → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Remove an artist from a user's Last.fm library.
+--
+-- More: <http://www.last.fm/api/show/library.removeArtist>
+removeArtist ∷ Artist → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Remove a scrobble from a user's Last.fm library.
+--
+-- More: <http://www.last.fm/api/show/library.removeScrobble>
+removeScrobble ∷ Artist → Track → Timestamp → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Remove a track from a user's Last.fm library.
+--
+-- More: <http://www.last.fm/api/show/library.removeTrack>
+removeTrack ∷ Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
diff --git a/src/Network/Lastfm/XML/Playlist.hs b/src/Network/Lastfm/XML/Playlist.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/Playlist.hs
@@ -0,0 +1,21 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Playlist API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.Playlist
+  ( addTrack, create
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Playlist as API
+
+$(xml ["addTrack", "create"])
+
+-- | Add a track to a Last.fm user's playlist.
+--
+-- More: <http://www.last.fm/api/show/playlist.addTrack>
+addTrack ∷ Playlist → Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Create a Last.fm playlist on behalf of a user.
+--
+-- More: <http://www.last.fm/api/show/playlist.create>
+create ∷ Maybe Title → Maybe Description → APIKey → SessionKey → Secret → Lastfm Response
diff --git a/src/Network/Lastfm/XML/Radio.hs b/src/Network/Lastfm/XML/Radio.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/Radio.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Radio API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.Radio
+  ( getPlaylist, search, tune
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Radio as API
+
+$(xml ["getPlaylist", "search", "tune"])
+
+-- | Fetch new radio content periodically in an XSPF format.
+--
+-- More: <http://www.last.fm/api/show/radio.getPlaylist>
+getPlaylist ∷ Maybe Discovery
+            → Maybe RTP
+            → Maybe BuyLinks
+            → Multiplier
+            → Bitrate
+            → APIKey
+            → SessionKey
+            → Secret
+            → Lastfm Response
+
+-- | Resolve the name of a resource into a station depending on which resource it is most likely to represent.
+--
+-- More: <http://www.last.fm/api/show/radio.search>
+search ∷ Name → APIKey → Lastfm Response
+
+-- | Tune in to a Last.fm radio station.
+--
+-- More: <http://www.last.fm/api/show/radio.tune>
+tune ∷ Maybe Language → Station → APIKey → SessionKey → Secret → Lastfm Response
diff --git a/src/Network/Lastfm/XML/Tag.hs b/src/Network/Lastfm/XML/Tag.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/Tag.hs
@@ -0,0 +1,57 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Tag API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.Tag
+  ( getInfo, getSimilar, getTopAlbums, getTopArtists, getTopTags, getTopTracks
+  , getWeeklyArtistChart, getWeeklyChartList, search
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Tag as API
+
+$(xml ["getInfo", "getSimilar", "getTopAlbums", "getTopArtists", "getTopTags", "getTopTracks", "getWeeklyArtistChart", "getWeeklyChartList", "search"])
+
+-- | Get the metadata for a tag.
+--
+-- More: <http://www.last.fm/api/show/tag.getInfo>
+getInfo ∷ Tag → Maybe Language → APIKey → Lastfm Response
+
+-- | Search for tags similar to this one. Returns tags ranked by similarity, based on listening data.
+--
+-- More: <http://www.last.fm/api/show/tag.getSimilar>
+getSimilar ∷ Tag → APIKey → Lastfm Response
+
+-- | Get the top albums tagged by this tag, ordered by tag count.
+--
+-- More: <http://www.last.fm/api/show/tag.getTopAlbums>
+getTopAlbums ∷ Tag → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top artists tagged by this tag, ordered by tag count.
+--
+-- More: <http://www.last.fm/api/show/tag.getTopArtists>
+getTopArtists ∷ Tag → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Fetches the top global tags on Last.fm, sorted by popularity (number of times used).
+--
+-- More: <http://www.last.fm/api/show/tag.getTopTags>
+getTopTags ∷ APIKey → Lastfm Response
+
+-- | Get the top tracks tagged by this tag, ordered by tag count.
+--
+-- More: <http://www.last.fm/api/show/tag.getTopTracks>
+getTopTracks ∷ Tag → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get an artist chart for a tag, for a given date range. If no date range is supplied, it will return the most recent artist chart for this tag.
+--
+-- More: <http://www.last.fm/api/show/tag.getWeeklyArtistChart>
+getWeeklyArtistChart ∷ Tag → Maybe From → Maybe To → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get a list of available charts for this tag, expressed as date ranges which can be sent to the chart services.
+--
+-- More: <http://www.last.fm/api/show/tag.getWeeklyChartList>
+getWeeklyChartList ∷ Tag → APIKey → Lastfm Response
+
+-- | Search for a tag by name. Returns matches sorted by relevance.
+--
+-- More: <http://www.last.fm/api/show/tag.search>
+search ∷ Tag → Maybe Page → Maybe Limit → APIKey → Lastfm Response
diff --git a/src/Network/Lastfm/XML/Tasteometer.hs b/src/Network/Lastfm/XML/Tasteometer.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/Tasteometer.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Tasteometer API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.Tasteometer
+  ( compare
+  ) where
+
+import Prelude hiding (compare)
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Tasteometer as API
+
+$(xml ["compare"])
+
+-- | Get a Tasteometer score from two inputs, along with a list of shared artists. If the input is a User some additional information is returned.
+--
+-- More: <http://www.last.fm/api/show/tasteometer.compare>
+compare ∷ Value → Value → Maybe Limit → APIKey → Lastfm Response
diff --git a/src/Network/Lastfm/XML/Track.hs b/src/Network/Lastfm/XML/Track.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/Track.hs
@@ -0,0 +1,126 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Track API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.Track
+  ( addTags, ban, getBuyLinks, getCorrection, getFingerprintMetadata
+  , getInfo, getShouts, getSimilar, getTags, getTopFans, getTopTags
+  , love, removeTag, scrobble, search, share, unban, unlove, updateNowPlaying
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Track as API
+
+$(xml ["addTags", "ban", "getBuyLinks", "getCorrection", "getFingerprintMetadata", "getInfo", "getShouts", "getSimilar", "getTags", "getTopFans", "getTopTags", "love", "removeTag", "scrobble", "search", "share", "unban", "unlove", "updateNowPlaying"])
+
+-- | Tag a track using a list of user supplied tags.
+--
+-- More: <http://www.last.fm/api/show/track.addTags>
+addTags ∷ Artist → Track → [Tag] → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Ban a track for a given user profile.
+--
+-- More: <http://www.last.fm/api/show/track.ban>
+ban ∷ Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Get a list of Buy Links for a particular track.
+--
+-- More: <http://www.last.fm/api/show/track.getBuylinks>
+getBuyLinks ∷ Either (Artist, Track) Mbid → Maybe Autocorrect → Country → APIKey → Lastfm Response
+
+-- | Use the last.fm corrections data to check whether the supplied track has a correction to a canonical track.
+--
+-- More: <http://www.last.fm/api/show/track.getCorrection>
+getCorrection ∷ Artist → Track → APIKey → Lastfm Response
+
+-- | Retrieve track metadata associated with a fingerprint id generated by the Last.fm Fingerprinter. Returns track elements, along with a 'rank' value between 0 and 1 reflecting the confidence for each match.
+--
+-- More: <http://www.last.fm/api/show/track.getFingerprintMetadata>
+getFingerprintMetadata ∷ Fingerprint → APIKey → Lastfm Response
+
+-- | Get the metadata for a track on Last.fm.
+--
+-- More: <http://www.last.fm/api/show/track.getInfo>
+getInfo ∷ Either (Artist, Track) Mbid → Maybe Autocorrect → Maybe Username → APIKey → Lastfm Response
+
+-- | Get shouts for this track. Also available as an rss feed.
+--
+-- More: <http://www.last.fm/api/show/track.getShouts>
+getShouts ∷ Either (Artist, Track) Mbid → Maybe Autocorrect → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the similar tracks for this track on Last.fm, based on listening data.
+--
+-- More: <http://www.last.fm/api/show/track.getSimilar>
+getSimilar ∷ Either (Artist, Track) Mbid → Maybe Autocorrect → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the tags applied by an individual user to a track on Last.fm.
+--
+-- More: <http://www.last.fm/api/show/track.getTags>
+getTags ∷ Either (Artist, Track) Mbid → Maybe Autocorrect → Either User (SessionKey, Secret) → APIKey → Lastfm Response
+
+-- | Get the top fans for this track on Last.fm, based on listening data.
+--
+-- More: <http://www.last.fm/api/show/track.getTopFans>
+getTopFans ∷ Either (Artist, Track) Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+
+-- | Get the top tags for this track on Last.fm, ordered by tag count.
+--
+-- More: <http://www.last.fm/api/show/track.getTopTags>
+getTopTags ∷ Either (Artist, Track) Mbid → Maybe Autocorrect → APIKey → Lastfm Response
+
+-- | Love a track for a user profile.
+--
+-- More: <http://www.last.fm/api/show/track.love>
+love ∷ Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Remove a user's tag from a track.
+--
+-- More: <http://www.last.fm/api/show/track.removeTag>
+removeTag ∷ Artist → Track → Tag → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Used to add a track-play to a user's profile.
+--
+-- More: <http://www.last.fm/api/show/track.scrobble>
+scrobble ∷ ( Timestamp, Maybe Album, Artist, Track, Maybe AlbumArtist
+           , Maybe Duration, Maybe StreamId, Maybe ChosenByUser
+           , Maybe Context, Maybe TrackNumber, Maybe Mbid )
+         → APIKey
+         → SessionKey
+         → Secret
+         → Lastfm Response
+
+-- | Search for a track by track name. Returns track matches sorted by relevance.
+--
+-- More: <http://www.last.fm/api/show/track.search>
+search ∷ Track → Maybe Page → Maybe Limit → Maybe Artist → APIKey → Lastfm Response
+
+-- | Share a track twith one or more Last.fm users or other friends.
+--
+-- More: <http://www.last.fm/api/show/track.share>
+share ∷ Artist → Track → Recipient → Maybe Message → Maybe Public → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Unban a track for a user profile.
+--
+-- More: <http://www.last.fm/api/show/track.unban>
+unban ∷ Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Unlove a track for a user profile.
+--
+-- More: <http://www.last.fm/api/show/track.unlove>
+unlove ∷ Artist → Track → APIKey → SessionKey → Secret → Lastfm Response
+
+
+-- | Used to notify Last.fm that a user has started listening to a track. Parameter names are case sensitive.
+--
+-- More: <http://www.last.fm/api/show/track.updateNowPlaying>
+updateNowPlaying ∷ Artist
+                 → Track
+                 → Maybe Album
+                 → Maybe AlbumArtist
+                 → Maybe Context
+                 → Maybe TrackNumber
+                 → Maybe Mbid
+                 → Maybe Duration
+                 → APIKey
+                 → SessionKey
+                 → Secret
+                 → Lastfm Response
diff --git a/src/Network/Lastfm/XML/User.hs b/src/Network/Lastfm/XML/User.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/User.hs
@@ -0,0 +1,140 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | User API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.User
+  ( getArtistTracks, getBannedTracks, getEvents, getFriends, getInfo, getLovedTracks
+  , getNeighbours, getNewReleases, getPastEvents, getPersonalTags, getPlaylists, getRecentStations
+  , getRecentTracks, getRecommendedArtists, getRecommendedEvents, getShouts, getTopAlbums
+  , getTopArtists, getTopTags, getTopTracks, getWeeklyAlbumChart, getWeeklyArtistChart
+  , getWeeklyChartList, getWeeklyTrackChart, shout
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.User as API
+
+$(xml ["getArtistTracks", "getBannedTracks", "getEvents", "getFriends", "getInfo", "getLovedTracks", "getNeighbours", "getNewReleases", "getPastEvents", "getPersonalTags", "getPlaylists", "getRecentStations", "getRecentTracks", "getRecommendedArtists", "getRecommendedEvents", "getShouts", "getTopAlbums", "getTopArtists", "getTopTags", "getTopTracks", "getWeeklyAlbumChart", "getWeeklyArtistChart", "getWeeklyChartList", "getWeeklyTrackChart", "shout"])
+
+-- | Get a list of tracks by a given artist scrobbled by this user, including scrobble time. Can be limited to specific timeranges, defaults to all time.
+--
+-- More: <http://www.last.fm/api/show/user.getArtistTracks>
+getArtistTracks ∷ User → Artist → Maybe StartTimestamp → Maybe EndTimestamp → Maybe Page → APIKey → Lastfm Response
+
+-- | Returns the tracks banned by the user.
+--
+-- More: <http://www.last.fm/api/show/user.getBannedTracks>
+getBannedTracks ∷ User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get a list of upcoming events that this user is attending.
+--
+-- Mpre: <http://www.last.fm/api/show/user.getEvents>
+getEvents ∷ User → Maybe Page → Maybe Limit → Maybe FestivalsOnly → APIKey → Lastfm Response
+
+-- | Get a list of the user's friends on Last.fm.
+--
+-- More: <http://www.last.fm/api/show/user.getFriends>
+getFriends ∷ User → Maybe RecentTracks → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get information about a user profile.
+--
+-- More: <http://www.last.fm/api/show/user.getInfo>
+getInfo ∷ Maybe User → APIKey → Lastfm Response
+
+-- | Get tracks loved by a user.
+--
+-- More: <http://www.last.fm/api/show/user.getLovedTracks>
+getLovedTracks ∷ User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get a list of a user's neighbours on Last.fm.
+--
+-- More: <http://www.last.fm/api/show/user.getNeighbours>
+getNeighbours ∷ User → Maybe Limit → APIKey → Lastfm Response
+
+-- | Gets a list of forthcoming releases based on a user's musical taste.
+--
+-- More: <http://www.last.fm/api/show/user.getNewReleases>
+getNewReleases ∷ User → Maybe UseRecs → APIKey → Lastfm Response
+
+-- | Get a paginated list of all events a user has attended in the past.
+--
+-- More: <http://www.last.fm/api/show/user.getPastEvents>
+getPastEvents ∷ User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the user's personal tags.
+--
+-- More: <http://www.last.fm/api/show/user.getPersonalTags>
+getPersonalTags ∷ User → Tag → TaggingType → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get a list of a user's playlists on Last.fm.
+--
+-- More: <http://www.last.fm/api/show/user.getPlaylists>
+getPlaylists ∷ User → APIKey → Lastfm Response
+
+-- | Get a list of the recent Stations listened to by this user.
+--
+-- More: <http://www.last.fm/api/show/user.getRecentStations>
+getRecentStations ∷ User → Maybe Page → Maybe Limit → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Get a list of the recent tracks listened to by this user. Also includes the currently playing track with the nowplaying="true" attribute if the user is currently listening.
+--
+-- More: <http://www.last.fm/api/show/user.getRecentTracks>
+getRecentTracks ∷ User → Maybe Page → Maybe Limit → Maybe From → Maybe To → APIKey → Lastfm Response
+
+-- | Get Last.fm artist recommendations for a user.
+--
+-- Mpre: <http://www.last.fm/api/show/user.getRecommendedArtists>
+getRecommendedArtists ∷ Maybe Page → Maybe Limit → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Get a paginated list of all events recommended to a user by Last.fm, based on their listening profile.
+--
+-- More: <http://www.last.fm/api/show/user.getRecommendedEvents>
+getRecommendedEvents ∷ Maybe Page → Maybe Limit → APIKey → SessionKey → Secret → Lastfm Response
+
+-- | Get shouts for this user. Also available as an rss feed.
+--
+-- More: <http://www.last.fm/api/show/user.getShouts>
+getShouts ∷ User → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top albums listened to by a user. You can stipulate a time period. Sends the overall chart by default.
+--
+-- More: <http://www.last.fm/api/show/user.getTopAlbums>
+getTopAlbums ∷ User → Maybe Period → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top artists listened to by a user. You can stipulate a time period. Sends the overall chart by default.
+--
+-- More: <http://www.last.fm/api/show/user.getTopArtists>
+getTopArtists ∷ User → Maybe Period → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top tags used by this user.
+--
+-- More: <http://www.last.fm/api/show/user.getTopTags>
+getTopTags ∷ User → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get the top tracks listened to by a user. You can stipulate a time period. Sends the overall chart by default.
+--
+-- More: <http://www.last.fm/api/show/user.getTopTracks>
+getTopTracks ∷ User → Maybe Period → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Get an album chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent album chart for this user.
+--
+-- More: <http://www.last.fm/api/show/user.getWeeklyAlbumChart>
+getWeeklyAlbumChart ∷ User → Maybe From → Maybe To → APIKey → Lastfm Response
+
+-- | Get an artist chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent artist chart for this user.
+--
+-- More: <http://www.last.fm/api/show/user.getWeeklyArtistChart>
+getWeeklyArtistChart ∷ User → Maybe From → Maybe To → APIKey → Lastfm Response
+
+-- | Get a list of available charts for this user, expressed as date ranges which can be sent to the chart services.
+--
+-- More: <http://www.last.fm/api/show/user.getWeeklyChartList>
+getWeeklyChartList ∷ User → APIKey → Lastfm Response
+
+-- | Get a track chart for a user profile, for a given date range. If no date range is supplied, it will return the most recent track chart for this user.
+--
+-- More: <http://www.last.fm/api/show/user.getWeeklyTrackChart>
+getWeeklyTrackChart ∷ User → Maybe From → Maybe To → APIKey → Lastfm Response
+
+-- | Shout on this user's shoutbox.
+--
+-- More: <http://www.last.fm/api/show/user.shout>
+shout ∷ User → Message → APIKey → SessionKey → Secret → Lastfm Response
diff --git a/src/Network/Lastfm/XML/Venue.hs b/src/Network/Lastfm/XML/Venue.hs
new file mode 100644
--- /dev/null
+++ b/src/Network/Lastfm/XML/Venue.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE TemplateHaskell #-}
+-- | Venue API module
+{-# OPTIONS_HADDOCK prune #-}
+module Network.Lastfm.XML.Venue
+  ( getEvents, getPastEvents, search
+  ) where
+
+import Network.Lastfm
+import qualified Network.Lastfm.API.Venue as API
+
+$(xml ["getEvents", "getPastEvents", "search"])
+
+-- | Get a list of upcoming events at this venue.
+--
+-- More: <http://www.last.fm/api/show/venue.getEvents>
+getEvents ∷ Venue → Maybe FestivalsOnly → APIKey → Lastfm Response
+
+-- | Get a paginated list of all the events held at this venue in the past.
+--
+-- More: <http://www.last.fm/api/show/venue.getPastEvents>
+getPastEvents ∷ Venue → Maybe FestivalsOnly → Maybe Page → Maybe Limit → APIKey → Lastfm Response
+
+-- | Search for a venue by venue name.
+--
+-- More: <http://www.last.fm/api/show/venue.search>
+search ∷ Venuename → Maybe Page → Maybe Limit → Maybe Country → APIKey → Lastfm Response
