liblastfm 0.2.0.0 → 0.3.0.0
raw patch · 22 files changed
+125/−1148 lines, 22 filesdep +semigroupsdep −HUnitdep −attoparsecdep −liblastfmdep ~aesondep ~bytestringPVP ok
version bump matches the API change (PVP)
Dependencies added: semigroups
Dependencies removed: HUnit, attoparsec, liblastfm, test-framework, test-framework-hunit
Dependency ranges changed: aeson, bytestring
API changes (from Hackage documentation)
+ Network.Lastfm.Internal: absorbQuery :: Foldable t => t (Request f b) -> Request f a
+ Network.Lastfm.Internal: indexedWith :: Int -> Request f a -> Request f a
+ Network.Lastfm.Library: albumItem :: Request f (Artist -> Album -> LibraryAlbum)
+ Network.Lastfm.Library: artistItem :: Request f (Artist -> LibraryArtist)
+ Network.Lastfm.Request: data LibraryAlbum
+ Network.Lastfm.Request: data LibraryArtist
+ Network.Lastfm.Request: data Scrobble
+ Network.Lastfm.Track: item :: Request f (Artist -> Track -> Timestamp -> Scrobble)
- Network.Lastfm.Library: addAlbum :: Request f (Artist -> Album -> APIKey -> SessionKey -> Sign)
+ Network.Lastfm.Library: addAlbum :: NonEmpty (Request f LibraryAlbum) -> Request f (APIKey -> SessionKey -> Sign)
- Network.Lastfm.Library: addArtist :: Request f (Artist -> APIKey -> SessionKey -> Sign)
+ Network.Lastfm.Library: addArtist :: NonEmpty (Request f LibraryArtist) -> Request f (APIKey -> SessionKey -> Sign)
- Network.Lastfm.Track: scrobble :: Request f (Artist -> Track -> Timestamp -> APIKey -> SessionKey -> Sign)
+ Network.Lastfm.Track: scrobble :: NonEmpty (Request f Scrobble) -> Request f (APIKey -> SessionKey -> Sign)
Files
- liblastfm.cabal +40/−68
- src/Network/Lastfm.hs +1/−0
- src/Network/Lastfm/Authentication.hs +13/−0
- src/Network/Lastfm/Internal.hs +19/−1
- src/Network/Lastfm/Library.hs +26/−5
- src/Network/Lastfm/Request.hs +6/−3
- src/Network/Lastfm/Track.hs +20/−7
- tests/Album.hs +0/−90
- tests/Artist.hs +0/−140
- tests/Chart.hs +0/−47
- tests/Common.hs +0/−20
- tests/Event.hs +0/−49
- tests/Geo.hs +0/−70
- tests/Group.hs +0/−53
- tests/Library.hs +0/−68
- tests/Playlist.hs +0/−39
- tests/Tag.hs +0/−67
- tests/Tasteometer.hs +0/−34
- tests/Track.hs +0/−132
- tests/User.hs +0/−152
- tests/Venue.hs +0/−35
- tests/json.hs +0/−68
liblastfm.cabal view
@@ -1,5 +1,5 @@ name: liblastfm-version: 0.2.0.0+version: 0.3.0.0 synopsis: Lastfm API interface license: MIT license-file: LICENSE@@ -13,74 +13,46 @@ library default-language: Haskell2010- build-depends: base >= 3 && < 5,- bytestring,- containers >= 0.5,- text,- cereal,- http-conduit >= 1.9,- http-types,- pureMD5,- crypto-api,- network,- contravariant,- void,- aeson+ build-depends:+ aeson,+ base >= 3 && < 5,+ bytestring,+ cereal,+ containers >= 0.5,+ contravariant,+ crypto-api,+ http-conduit >= 1.9,+ http-types,+ network,+ pureMD5,+ semigroups,+ text,+ void hs-source-dirs: src- exposed-modules: Network.Lastfm- Network.Lastfm.Authentication- Network.Lastfm.Album- Network.Lastfm.Artist- Network.Lastfm.Chart- Network.Lastfm.Event- Network.Lastfm.Geo- Network.Lastfm.Group- Network.Lastfm.Library- Network.Lastfm.Playlist- Network.Lastfm.Radio- Network.Lastfm.Tag- Network.Lastfm.Tasteometer- Network.Lastfm.Track- Network.Lastfm.User- Network.Lastfm.Venue- Network.Lastfm.Request- Network.Lastfm.Response- Network.Lastfm.Internal- ghc-options: -Wall- -fno-warn-unused-do-bind- -funbox-strict-fields---test-suite json- build-depends: base >= 3 && < 5,- bytestring >= 0.9 && < 0.11,- attoparsec >= 0.10,- aeson == 0.6.*,- HUnit,- test-framework,- test-framework-hunit,- text,- liblastfm- type: exitcode-stdio-1.0- hs-source-dirs: tests- main-is: json.hs- other-modules: Common- Venue- User- Track- Tasteometer- Tag- Playlist- Library- Group- Geo- Event- Chart- Artist- Album- ghc-options: -Wall- -fno-warn-unused-do-bind- -fno-warn-orphans+ exposed-modules:+ Network.Lastfm+ Network.Lastfm.Album+ Network.Lastfm.Artist+ Network.Lastfm.Authentication+ Network.Lastfm.Chart+ Network.Lastfm.Event+ Network.Lastfm.Geo+ Network.Lastfm.Group+ Network.Lastfm.Internal+ Network.Lastfm.Library+ Network.Lastfm.Playlist+ Network.Lastfm.Radio+ Network.Lastfm.Request+ Network.Lastfm.Response+ Network.Lastfm.Tag+ Network.Lastfm.Tasteometer+ Network.Lastfm.Track+ Network.Lastfm.User+ Network.Lastfm.Venue+ ghc-options:+ -Wall+ -fno-warn-unused-do-bind+ -funbox-strict-fields source-repository head
src/Network/Lastfm.hs view
@@ -1,3 +1,4 @@+-- | Lastfm API interface module Network.Lastfm ( -- * Utilities for constructing requests module Network.Lastfm.Request
src/Network/Lastfm/Authentication.hs view
@@ -12,6 +12,19 @@ -- -- Note that you can use any of them in your -- application despite their names+--+-- How to get session key for yourself for debug with GHCi:+--+-- >>> import Network.Lastfm+-- >>> import Network.Lastfm.Authentication+-- >>> :set -XOverloadedStrings+-- >>> lastfm $ getToken <*> apiKey "__API_KEY__" <* json+-- Just (Object fromList [("token",String "__TOKEN__")])+-- >>> putStrLn . link $ apiKey "__API_KEY__" <* token "__TOKEN__"+-- http://www.last.fm/api/auth/?api_key=__API_KEY__&token=__TOKEN__+-- >>> -- Click that link ^^^+-- >>> lastfm . sign "__SECRET__" $ getSession <*> token "__TOKEN__" <*> apiKey "__API_KEY__" <* json+-- Just (Object fromList [("session",Object fromList [("name",String "__USER__"),("subscriber",String "0"),("key",String "__SESSION_KEY__")])]) module Network.Lastfm.Authentication ( -- * Helpers getToken, getSession, getMobileSession
src/Network/Lastfm/Internal.hs view
@@ -7,6 +7,7 @@ module Network.Lastfm.Internal ( Request(..), Format(..), Ready, Sign , R(..), wrap, unwrap, render, coerce+ , absorbQuery, indexedWith -- * Lenses , host, method, query ) where@@ -99,11 +100,28 @@ wrap = Request . Const . Dual . Endo {-# INLINE wrap #-} - -- | Unwrapping from interesting 'Monoid' ('R' -> 'R') instance unwrap :: Request f a -> R f -> R f unwrap = appEndo . getDual . getConst . unRequest {-# INLINE unwrap #-}+++-- | Absorbing a bunch of queries, useful in batch operations+absorbQuery :: Foldable t => t (Request f b) -> Request f a+absorbQuery rs = wrap $ \r ->+ r { _query = _query r <> foldMap (_query . ($ rempty) . unwrap) rs }+{-# INLINE absorbQuery #-}++-- | Transforming Request to the "array notation"+indexedWith :: Int -> Request f a -> Request f a+indexedWith n r = r <* wrap (\s ->+ s { _query = M.mapKeys (\k -> k <> "[" <> T.pack (show n) <> "]") (_query s) })+{-# INLINE indexedWith #-}++-- | Empty request+rempty :: R f+rempty = R mempty mempty mempty+{-# INLINE rempty #-} -- Miscellaneous instances
src/Network/Lastfm/Library.hs view
@@ -8,30 +8,51 @@ -- import qualified Network.Lastfm.Library as Library -- @ module Network.Lastfm.Library- ( addAlbum, addArtist, addTrack+ ( addAlbum, albumItem, addArtist, artistItem, addTrack , getAlbums, getArtists, getTracks , removeAlbum, removeArtist, removeScrobble, removeTrack ) where import Control.Applicative+import Data.List.NonEmpty (NonEmpty)+import qualified Data.List.NonEmpty as N +import Network.Lastfm.Internal (absorbQuery, indexedWith, wrap) import Network.Lastfm.Request ++ -- | Add an album or collection of albums to a user's Last.fm library -- -- <http://www.last.fm/api/show/library.addAlbum>-addAlbum :: Request f (Artist -> Album -> APIKey -> SessionKey -> Sign)-addAlbum = api "library.addAlbum" <* post+addAlbum :: NonEmpty (Request f LibraryAlbum) -> Request f (APIKey -> SessionKey -> Sign)+addAlbum batch = api "library.addAlbum" <* items <* post+ where+ items = absorbQuery (N.zipWith indexedWith (N.fromList [0..]) batch)+ {-# INLINE items #-} {-# INLINE addAlbum #-} +-- | What artist to add to library?+albumItem :: Request f (Artist -> Album -> LibraryAlbum)+albumItem = wrap id+{-# INLINE albumItem #-} + -- | Add an artist to a user's Last.fm library -- -- <http://www.last.fm/api/show/library.addArtist>-addArtist :: Request f (Artist -> APIKey -> SessionKey -> Sign)-addArtist = api "library.addArtist" <* post+addArtist :: NonEmpty (Request f LibraryArtist) -> Request f (APIKey -> SessionKey -> Sign)+addArtist batch = api "library.addArtist" <* items <* post+ where+ items = absorbQuery (N.zipWith indexedWith (N.fromList [0..]) batch)+ {-# INLINE items #-} {-# INLINE addArtist #-}++-- | What album to add to library?+artistItem :: Request f (Artist -> LibraryArtist)+artistItem = wrap id+{-# INLINE artistItem #-} -- | Add a track to a user's Last.fm library
src/Network/Lastfm/Request.hs view
@@ -27,7 +27,7 @@ , TaggingType, taggingType, UseRecs, useRecs, Venue, venue, VenueName, venueName , Discovery, discovery, RTP, rtp, BuyLinks, buyLinks, Multiplier(..), multiplier , Bitrate(..), bitrate, Name, name, Station, station- , Targeted, comparison+ , Targeted, comparison, Scrobble, LibraryAlbum, LibraryArtist ) where import Control.Applicative@@ -173,6 +173,7 @@ data TaggingType data RecentTracks data UseRecs+data Scrobble data Group data Venue data VenueName@@ -183,6 +184,8 @@ data Discovery data RTP data BuyLinks+data LibraryAlbum+data LibraryArtist -- | Add artist parameter@@ -190,12 +193,12 @@ artist = add "artist" {-# INLINE artist #-} --- | Add artist parameter+-- | Add artists parameter artists :: [Text] -> Request f [Artist] artists = add "artists" {-# INLINE artists #-} --- | Add artist parameter+-- | Add album parameter album :: Text -> Request f Album album = add "album" {-# INLINE album #-}
src/Network/Lastfm/Track.hs view
@@ -12,12 +12,15 @@ ( ArtistTrackOrMBID , addTags, ban, getBuyLinks, getCorrection, getFingerprintMetadata , getInfo, getShouts, getSimilar, getTags, getTopFans- , getTopTags, love, removeTag, scrobble+ , getTopTags, love, removeTag, scrobble, item , search, share, unban, unlove, updateNowPlaying ) where -import Control.Applicative+import Control.Applicative+import Data.List.NonEmpty (NonEmpty)+import qualified Data.List.NonEmpty as N +import Network.Lastfm.Internal (absorbQuery, indexedWith, wrap) import Network.Lastfm.Request @@ -149,15 +152,25 @@ {-# INLINE removeTag #-} --- | Used to add a track-play to a user's profile.+-- | Add played tracks to the user profile. ----- Optional: 'album', 'albumArtist', 'chosenByUser', 'context',--- 'duration', 'mbid', 'streamId', 'trackNumber'+-- Scrobbles 50 first list elements -- -- <http://www.last.fm/api/show/track.scrobble>-scrobble :: Request f (Artist -> Track -> Timestamp -> APIKey -> SessionKey -> Sign)-scrobble = api "track.scrobble" <* post+scrobble :: NonEmpty (Request f Scrobble) -> Request f (APIKey -> SessionKey -> Sign)+scrobble batch = api "track.scrobble" <* items <* post+ where+ items = absorbQuery (N.zipWith indexedWith (N.fromList [0..49]) batch)+ {-# INLINE items #-} {-# INLINE scrobble #-}++-- | What track to scrobble?+--+-- Optional: 'album', 'albumArtist', 'chosenByUser', 'context',+-- 'duration', 'mbid', 'streamId', 'trackNumber'+item :: Request f (Artist -> Track -> Timestamp -> Scrobble)+item = wrap id+{-# INLINE item #-} -- | Search for a track by track name. Returns track matches sorted by relevance.
− tests/Album.hs
@@ -1,90 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module Album (auth, noauth) where--import Data.Aeson.Types-import Network.Lastfm-import Network.Lastfm.Album-import Test.Framework-import Test.Framework.Providers.HUnit--import Common---auth ∷ Request JSON APIKey → Request JSON SessionKey → Secret → [Test]-auth ak sk s =- [ testCase "Album.addTags" testAddTags- , testCase "Album.getTags-authenticated" testGetTagsAuth- , testCase "Album.removeTag" testRemoveTag- , testCase "Album.share" testShare- ]- where- testAddTags = check ok . sign s $- addTags <*> artist "Pink Floyd" <*> album "The Wall" <*> tags ["70s", "awesome", "classic"]- <*> ak <*> sk-- testGetTagsAuth = check gt . sign s $- getTags <*> artist "Pink Floyd" <*> album "The Wall"- <*> ak <* sk-- testRemoveTag = check ok . sign s $- removeTag <*> artist "Pink Floyd" <*> album "The Wall" <*> tag "awesome"- <*> ak <*> sk-- testShare = check ok . sign s $- share <*> album "Jerusalem" <*> artist "Sleep" <*> recipient "liblastfm" <* message "Just listen!"- <*> ak <*> sk---noauth ∷ Request JSON APIKey → [Test]-noauth ak =- [ testCase "Album.getBuyLinks" testGetBuylinks- , testCase "Album.getBuyLinks_mbid" testGetBuylinks_mbid- , testCase "Album.getInfo" testGetInfo- , testCase "Album.getInfo_mbid" testGetInfo_mbid- , testCase "Album.getShouts" testGetShouts- , testCase "Album.getShouts_mbid" testGetShouts_mbid- , testCase "Album.getTags" testGetTags- , testCase "Album.getTags_mbid" testGetTags_mbid- , testCase "Album.getTopTags" testGetTopTags- , testCase "Album.getTopTags_mbid" testGetTopTags_mbid- , testCase "Album.search" testSearch- ]- where- testGetBuylinks = check gbl $- getBuyLinks <*> country "United Kingdom" <*> artist "Pink Floyd" <*> album "The Wall" <*> ak- testGetBuylinks_mbid = check gbl $- getBuyLinks <*> country "United Kingdom" <*> mbid "816abcd3-924a-3565-92b9-7ab750688f34" <*> ak-- testGetInfo = check gi $- getInfo <*> artist "Pink Floyd" <*> album "The Wall" <*> ak- testGetInfo_mbid = check gi $- getInfo <*> mbid "816abcd3-924a-3565-92b9-7ab750688f34" <*> ak-- testGetShouts = check gs $- getShouts <*> artist "Pink Floyd" <*> album "The Wall" <* limit 7 <*> ak- testGetShouts_mbid = check gs $- getShouts <*> mbid "816abcd3-924a-3565-92b9-7ab750688f34" <* limit 7 <*> ak-- testGetTags = check gt $- getTags <*> artist "Pink Floyd" <*> album "The Wall" <* user "liblastfm" <*> ak- testGetTags_mbid = check gt $- getTags <*> mbid "816abcd3-924a-3565-92b9-7ab750688f34" <* user "liblastfm" <*> ak-- testGetTopTags = check gtt $- getTopTags <*> artist "Pink Floyd" <*> album "The Wall" <*> ak- testGetTopTags_mbid = check gtt $- getTopTags <*> mbid "816abcd3-924a-3565-92b9-7ab750688f34" <*> ak-- testSearch = check se $- search <*> album "wall" <* limit 5 <*> ak---gbl, gi, gs, gt, gtt, se ∷ Value → Parser [String]-gbl o = parseJSON o >>= (.: "affiliations") >>= (.: "physicals") >>= (.: "affiliation") >>= mapM (.: "supplierName")-gi o = parseJSON o >>= (.: "album") >>= (.: "toptags") >>= (.: "tag") >>= mapM (.: "name")-gs o = parseJSON o >>= (.: "shouts") >>= (.: "shout") >>= mapM (.: "body")-gt o = parseJSON o >>= (.: "tags") >>= (.: "tag") >>= mapM (.: "name")-gtt o = parseJSON o >>= (.: "toptags") >>= (.: "tag") >>= mapM (.: "count")-se o = parseJSON o >>= (.: "results") >>= (.: "albummatches") >>= (.: "album") >>= mapM (.: "name")
− tests/Artist.hs
@@ -1,140 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module Artist (auth, noauth) where--import Data.Aeson.Types-import Network.Lastfm-import Network.Lastfm.Artist-import Test.Framework-import Test.Framework.Providers.HUnit--import Common---auth ∷ Request JSON APIKey → Request JSON SessionKey → Secret → [Test]-auth ak sk s =- [ testCase "Artist.addTags" testAddTags- , testCase "Artist.getTags-authenticated" testGetTagsAuth- , testCase "Artist.removeTag" testRemoveTag- , testCase "Artist.share" testShare- ]- where- testAddTags = check ok . sign s $- addTags <*> artist "Егор Летов" <*> tags ["russian", "black metal"] <*> ak <*> sk-- testGetTagsAuth = check gt . sign s $- getTags <*> artist "Егор Летов" <*> ak <* sk-- testRemoveTag = check ok . sign s $- removeTag <*> artist "Егор Летов" <*> tag "russian" <*> ak <*> sk-- testShare = check ok . sign s $- share <*> artist "Sleep" <*> recipient "liblastfm" <* message "Just listen!" <*> ak <*> sk---noauth ∷ Request JSON APIKey → [Test]-noauth ak =- [ testCase "Artist.getCorrection" testGetCorrection- , testCase "Artist.getEvents" testGetEvents- , testCase "Artist.getEvents_mbid" testGetEvents_mbid- , testCase "Artist.getInfo" testGetInfo- , testCase "Artist.getInfo_mbid" testGetInfo_mbid- , testCase "Artist.getPastEvents" testGetPastEvents- , testCase "Artist.getPastEvents_mbid" testGetPastEvents_mbid- , testCase "Artist.getPodcast" testGetPodcast- , testCase "Artist.getPodcast_mbid" testGetPodcast_mbid- , testCase "Artist.getShouts" testGetShouts- , testCase "Artist.getShouts_mbid" testGetShouts_mbid- , testCase "Artist.getSimilar" testGetSimilar- , testCase "Artist.getSimilar_mbid" testGetSimilar_mbid- , testCase "Artist.getTags" testGetTags- , testCase "Artist.getTags_mbid" testGetTags_mbid- , testCase "Artist.getTopAlbums" testGetTopAlbums- , testCase "Artist.getTopAlbums_mbid" testGetTopAlbums_mbid- , testCase "Artist.getTopFans" testGetTopFans- , testCase "Artist.getTopFans_mbid" testGetTopFans_mbid- , testCase "Artist.getTopTags" testGetTopTags- , testCase "Artist.getTopTags_mbid" testGetTopTags_mbid- , testCase "Artist.getTopTracks" testGetTopTracks- , testCase "Artist.getTopTracks_mbid" testGetTopTracks_mbid- , testCase "Artist.search" testSearch- ]- where- testGetCorrection = check gc $- getCorrection <*> artist "Meshugah" <*> ak-- testGetEvents = check ge $- getEvents <*> artist "Meshuggah" <* limit 2 <*> ak- testGetEvents_mbid = check ge $- getEvents <*> mbid "cf8b3b8c-118e-4136-8d1d-c37091173413" <* limit 2 <*> ak-- testGetInfo = check gin $- getInfo <*> artist "Meshuggah" <*> ak- testGetInfo_mbid = check gin $- getInfo <*> mbid "cf8b3b8c-118e-4136-8d1d-c37091173413" <*> ak-- testGetPastEvents = check gpe $- getPastEvents <*> artist "Meshuggah" <* autocorrect True <*> ak- testGetPastEvents_mbid = check gpe $- getPastEvents <*> mbid "cf8b3b8c-118e-4136-8d1d-c37091173413" <* autocorrect True <*> ak-- testGetPodcast = check gp $- getPodcast <*> artist "Meshuggah" <*> ak- testGetPodcast_mbid = check gp $- getPodcast <*> mbid "cf8b3b8c-118e-4136-8d1d-c37091173413" <*> ak-- testGetShouts = check gs $- getShouts <*> artist "Meshuggah" <* limit 5 <*> ak- testGetShouts_mbid = check gs $- getShouts <*> mbid "cf8b3b8c-118e-4136-8d1d-c37091173413" <* limit 5 <*> ak-- testGetSimilar = check gsi $- getSimilar <*> artist "Meshuggah" <* limit 3 <*> ak- testGetSimilar_mbid = check gsi $- getSimilar <*> mbid "cf8b3b8c-118e-4136-8d1d-c37091173413" <* limit 3 <*> ak-- testGetTags = check gt $- getTags <*> artist "Егор Летов" <* user "liblastfm" <*> ak- testGetTags_mbid = check gt $- getTags <*> mbid "cfb3d32e-d095-4d63-946d-9daf06932180" <* user "liblastfm" <*> ak-- testGetTopAlbums = check gta $- getTopAlbums <*> artist "Meshuggah" <* limit 3 <*> ak- testGetTopAlbums_mbid = check gta $- getTopAlbums <*> mbid "cf8b3b8c-118e-4136-8d1d-c37091173413" <* limit 3 <*> ak-- testGetTopFans = check gtf $- getTopFans <*> artist "Meshuggah" <*> ak- testGetTopFans_mbid = check gtf $- getTopFans <*> mbid "cf8b3b8c-118e-4136-8d1d-c37091173413" <*> ak-- testGetTopTags = check gtt $- getTopTags <*> artist "Meshuggah" <*> ak- testGetTopTags_mbid = check gtt $- getTopTags <*> mbid "cf8b3b8c-118e-4136-8d1d-c37091173413" <*> ak-- testGetTopTracks = check gttr $- getTopTracks <*> artist "Meshuggah" <* limit 3 <*> ak- testGetTopTracks_mbid = check gttr $- getTopTracks <*> mbid "cf8b3b8c-118e-4136-8d1d-c37091173413" <* limit 3 <*> ak-- testSearch = check se $- search <*> artist "Mesh" <* limit 3 <*> ak---gc, gin, gp ∷ Value → Parser String-ge, gpe, gs, gsi, gt, gta, gtf, gtt, gttr, se ∷ Value → Parser [String]-gc o = parseJSON o >>= (.: "corrections") >>= (.: "correction") >>= (.: "artist") >>= (.: "name")-ge o = parseJSON o >>= (.: "events") >>= (.: "event") >>= mapM (\o' → (o' .: "venue") >>= (.: "name"))-gin o = parseJSON o >>= (.: "artist") >>= (.: "stats") >>= (.: "listeners")-gp o = parseJSON o >>= (.: "rss") >>= (.: "channel") >>= (.: "description")-gpe o = parseJSON o >>= (.: "events") >>= (.: "event") >>= mapM (.: "title")-gs o = parseJSON o >>= (.: "shouts") >>= (.: "shout") >>= mapM (.: "author")-gsi o = parseJSON o >>= (.: "similarartists") >>= (.: "artist") >>= mapM (.: "name")-gt o = parseJSON o >>= (.: "tags") >>= (.: "tag") >>= mapM (.: "name")-gta o = parseJSON o >>= (.: "topalbums") >>= (.: "album") >>= mapM (.: "name")-gtf o = parseJSON o >>= (.: "topfans") >>= (.: "user") >>= mapM (.: "name")-gtt o = parseJSON o >>= (.: "toptags") >>= (.: "tag") >>= mapM (.: "name")-gttr o = parseJSON o >>= (.: "toptracks") >>= (.: "track") >>= mapM (.: "name")-se o = parseJSON o >>= (.: "results") >>= (.: "artistmatches") >>= (.: "artist") >>= mapM (.: "name")
− tests/Chart.hs
@@ -1,47 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module Chart (noauth) where--import Data.Aeson.Types-import Network.Lastfm-import Network.Lastfm.Chart-import Test.Framework-import Test.Framework.Providers.HUnit--import Common---noauth ∷ Request JSON APIKey → [Test]-noauth ak =- [ testCase "Chart.getHypedArtists" testGetHypedArtists- , testCase "Chart.getHypedTracks" testGetHypedTracks- , testCase "Chart.getLovedTracks" testGetLovedTracks- , testCase "Chart.getTopArtists" testGetTopArtists- , testCase "Chart.getTopTags" testGetTopTags- , testCase "Chart.getTopTracks" testGetTopTracks- ]- where- testGetHypedArtists = check ga $- getHypedArtists <* limit 3 <*> ak-- testGetHypedTracks = check gt $- getHypedTracks <* limit 2 <*> ak-- testGetLovedTracks = check gt $- getLovedTracks <* limit 3 <*> ak-- testGetTopArtists = check ga $- getTopArtists <* limit 4 <*> ak-- testGetTopTags = check gta $- getTopTags <* limit 5 <*> ak-- testGetTopTracks = check gt $- getTopTracks <* limit 2 <*> ak---ga, gt, gta ∷ Value → Parser [String]-ga o = parseJSON o >>= (.: "artists") >>= (.: "artist") >>= mapM (.: "name")-gt o = parseJSON o >>= (.: "tracks") >>= (.: "track") >>= mapM (.: "name")-gta o = parseJSON o >>= (.: "tags") >>= (.: "tag") >>= mapM (.: "name")
− tests/Common.hs
@@ -1,20 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module Common where--import Data.Aeson.Types-import Network.Lastfm-import Test.HUnit---check ∷ (Value → Parser a) → Request JSON Ready → Assertion-check p q = do- r ← lastfm q- case parse p `fmap` r of- Just (Success _) → assertBool "success" True- _ → assertFailure $ "Got: " ++ show r---ok ∷ Value → Parser String-ok o = parseJSON o >>= (.: "status")
− tests/Event.hs
@@ -1,49 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module Event (auth, noauth) where--import Data.Aeson.Types-import Network.Lastfm-import Network.Lastfm.Event-import Test.Framework-import Test.Framework.Providers.HUnit--import Common---auth ∷ Request JSON APIKey → Request JSON SessionKey → Secret → [Test]-auth ak sk s =- [ testCase "Event.attend" testAttend- , testCase "Event.share" testShare- ]- where- testAttend = check ok . sign s $- attend <*> event 3142549 <*> status Attending <*> ak <*> sk-- testShare = check ok . sign s $- share <*> event 3142549 <*> recipient "liblastfm" <* message "Just listen!" <*> ak <*> sk---noauth ∷ Request JSON APIKey → [Test]-noauth ak =- [ testCase "Event.getAttendees" testGetAttendees- , testCase "Event.getInfo" testGetInfo- , testCase "Event.getShouts" testGetShouts- ]- where- testGetAttendees = check ga $- getAttendees <*> event 3142549 <* limit 2 <*> ak-- testGetInfo = check gi $- getInfo <*> event 3142549 <*> ak-- testGetShouts = check gs $- getShouts <*> event 3142549 <* limit 1 <*> ak---gi, gs ∷ Value → Parser String-ga ∷ Value → Parser [String]-ga o = parseJSON o >>= (.: "attendees") >>= (.: "user") >>= mapM (.: "name")-gi o = parseJSON o >>= (.: "event") >>= (.: "venue") >>= (.: "location") >>= (.: "city")-gs o = parseJSON o >>= (.: "shouts") >>= (.: "shout") >>= (.: "body")
− tests/Geo.hs
@@ -1,70 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module Geo (noauth) where--import Data.Aeson.Types-import Network.Lastfm-import Network.Lastfm.Geo-import Test.Framework-import Test.Framework.Providers.HUnit--import Common---noauth ∷ Request JSON APIKey → [Test]-noauth ak =- [ testCase "Geo.getEvents" testGetEvents- , testCase "Geo.getMetroArtistChart" testGetMetroArtistChart- , testCase "Geo.getMetroHypeArtistChart" testGetMetroHypeArtistChart- , testCase "Geo.getMetroHypeTrackChart" testGetMetroHypeTrackChart- , testCase "Geo.getMetroTrackChart" testGetMetroTrackChart- , testCase "Geo.getMetroUniqueArtistChart" testGetMetroUniqueArtistChart- , testCase "Geo.getMetroUniqueTrackChart" testGetMetroUniqueTrackChart- , testCase "Geo.getMetroWeeklyChartlist" testGetMetroWeeklyChartlist- , testCase "Geo.getMetros" testGetMetros- , testCase "Geo.getTopArtists" testGetTopArtists- , testCase "Geo.getTopTracks" testGetTopTracks- ]- where- testGetEvents = check ge $- getEvents <* location "Moscow" <* limit 5 <*> ak-- testGetMetroArtistChart = check ga $- getMetroArtistChart <*> metro "Saint Petersburg" <*> country "Russia" <*> ak-- testGetMetroHypeArtistChart = check ga $- getMetroHypeArtistChart <*> metro "New York" <*> country "United States" <*> ak-- testGetMetroHypeTrackChart = check gt $- getMetroHypeTrackChart <*> metro "Moscow" <*> country "Russia" <*> ak-- testGetMetroTrackChart = check gt $- getMetroTrackChart <*> metro "Boston" <*> country "United States" <*> ak-- testGetMetroUniqueArtistChart = check ga $- getMetroUniqueArtistChart <*> metro "Minsk" <*> country "Belarus" <*> ak-- testGetMetroUniqueTrackChart = check gt $- getMetroUniqueTrackChart <*> metro "Moscow" <*> country "Russia" <*> ak-- testGetMetroWeeklyChartlist = check gc $- getMetroWeeklyChartlist <*> metro "Moscow" <*> ak-- testGetMetros = check gm $- getMetros <* country "Russia" <*> ak-- testGetTopArtists = check ga $- getTopArtists <*> country "Belarus" <* limit 3 <*> ak-- testGetTopTracks = check gt $- getTopTracks <*> country "Ukraine" <* limit 2 <*> ak---ga, ge, gm, gt ∷ Value → Parser [String]-gc ∷ Value → Parser [(String, String)]-ga o = parseJSON o >>= (.: "topartists") >>= (.: "artist") >>= mapM (.: "name")-gc o = parseJSON o >>= (.: "weeklychartlist") >>= (.: "chart") >>= mapM (\t → (,) <$> (t .: "from") <*> (t .: "to"))-ge o = parseJSON o >>= (.: "events") >>= (.: "event") >>= mapM (.: "id")-gm o = parseJSON o >>= (.: "metros") >>= (.: "metro") >>= mapM (.: "name")-gt o = parseJSON o >>= (.: "toptracks") >>= (.: "track") >>= mapM (.: "name")
− tests/Group.hs
@@ -1,53 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module Group (noauth) where--import Data.Aeson.Types-import Network.Lastfm-import Network.Lastfm.Group-import Test.Framework-import Test.Framework.Providers.HUnit--import Common---noauth ∷ Request JSON APIKey → [Test]-noauth ak =- [ testCase "Group.getHype" testGetHype- , testCase "Group.getMembers" testGetMembers- , testCase "Group.getWeeklyAlbumChart" testGetWeeklyAlbumChart- , testCase "Group.getWeeklyArtistChart" testGetWeeklyArtistChart- , testCase "Group.getWeeklyChartList" testGetWeeklyChartList- , testCase "Group.getWeeklyTrackChart" testGetWeeklyTrackChart- ]- where- g = "People with no social lives that listen to more music than is healthy who are slightly scared of spiders and can never seem to find a pen"-- testGetHype = check gh $- getHype <*> group g <*> ak-- testGetMembers = check gm $- getMembers <*> group g <* limit 10 <*> ak-- testGetWeeklyAlbumChart = check ga $- getWeeklyAlbumChart <*> group g <*> ak-- testGetWeeklyArtistChart = check gar $- getWeeklyArtistChart <*> group g <*> ak-- testGetWeeklyChartList = check gc $- getWeeklyChartList <*> group g <*> ak-- testGetWeeklyTrackChart = check gt $- getWeeklyTrackChart <*> group g <*> ak---ga, gar, gh, gm, gt ∷ Value → Parser [String]-gc ∷ Value → Parser [(String, String)]-ga o = parseJSON o >>= (.: "weeklyalbumchart") >>= (.: "album") >>= mapM (.: "playcount")-gar o = parseJSON o >>= (.: "weeklyartistchart") >>= (.: "artist") >>= mapM (.: "name")-gc o = parseJSON o >>= (.: "weeklychartlist") >>= (.: "chart") >>= mapM (\t → (,) <$> (t .: "from") <*> (t .: "to"))-gh o = parseJSON o >>= (.: "weeklyartistchart") >>= (.: "artist") >>= mapM (.: "mbid")-gm o = parseJSON o >>= (.: "members") >>= (.: "user") >>= mapM (.: "name")-gt o = parseJSON o >>= (.: "weeklytrackchart") >>= (.: "track") >>= mapM (.: "url")
− tests/Library.hs
@@ -1,68 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module Library (auth, noauth) where--import Data.Aeson.Types-import Network.Lastfm-import Network.Lastfm.Library-import Test.Framework-import Test.Framework.Providers.HUnit--import Common---auth ∷ Request JSON APIKey → Request JSON SessionKey → Secret → [Test]-auth ak sk s =- [ testCase "Library.addAlbum" testAddAlbum- , testCase "Library.addArtist" testAddArtist- , testCase "Library.addTrack" testAddTrack- , testCase "Library.removeAlbum" testRemoveAlbum- , testCase "Library.removeArtist" testRemoveArtist- , testCase "Library.removeTrack" testRemoveTrack- , testCase "Library.removeScrobble" testRemoveScrobble- ]- where- testAddAlbum = check ok . sign s $- addAlbum <*> artist "Franz Ferdinand" <*> album "Franz Ferdinand" <*> ak <*> sk-- testAddArtist = check ok . sign s $- addArtist <*> artist "Mobthrow" <*> ak <*> sk-- testAddTrack = check ok . sign s $- addTrack <*> artist "Eminem" <*> track "Kim" <*> ak <*> sk-- testRemoveAlbum = check ok . sign s $- removeAlbum <*> artist "Franz Ferdinand" <*> album "Franz Ferdinand" <*> ak <*> sk-- testRemoveArtist = check ok . sign s $- removeArtist <*> artist "Burzum" <*> ak <*> sk-- testRemoveTrack = check ok . sign s $- removeTrack <*> artist "Eminem" <*> track "Kim" <*> ak <*> sk-- testRemoveScrobble = check ok . sign s $- removeScrobble <*> artist "Gojira" <*> track "Ocean" <*> timestamp 1328905590 <*> ak <*> sk---noauth ∷ Request JSON APIKey → [Test]-noauth ak =- [ testCase "Library.getAlbums" testGetAlbums- , testCase "Library.getArtists" testGetArtists- , testCase "Library.getTracks" testGetTracks- ]- where- testGetAlbums = check ga $- getAlbums <*> user "smpcln" <* artist "Burzum" <* limit 5 <*> ak-- testGetArtists = check gar $- getArtists <*> user "smpcln" <* limit 7 <*> ak-- testGetTracks = check gt $- getTracks <*> user "smpcln" <* artist "Burzum" <* limit 4 <*> ak---ga, gar, gt ∷ Value → Parser [String]-ga o = parseJSON o >>= (.: "albums") >>= (.: "album") >>= mapM (.: "name")-gar o = parseJSON o >>= (.: "artists") >>= (.: "artist") >>= mapM (.: "name")-gt o = parseJSON o >>= (.: "tracks") >>= (.: "track") >>= mapM (.: "name")
− tests/Playlist.hs
@@ -1,39 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module Playlist (auth) where--import Data.Aeson.Types-import Network.Lastfm-import Network.Lastfm.Playlist-import Network.Lastfm.User-import Test.Framework-import Test.Framework.Providers.HUnit--import Common---auth ∷ Request JSON APIKey → Request JSON SessionKey → Secret → [Test]-auth ak sk s =- [ testCase "Playlist.create" testCreate -- Order matters.- , testCase "Playlist.addTrack" testAddTrack- ]- where- ak' = "29effec263316a1f8a97f753caaa83e0"-- testAddTrack =- do r ← lastfm $ getPlaylists <*> user "liblastfm" <*> apiKey ak' <* json- case parseMaybe pl =<< r of- Nothing → error "M"- Just r' → let pid = read $ head r' in check ok . sign s $- addTrack <*> playlist pid <*> artist "Ruby my dear" <*> track "Chazz" <*> ak <*> sk-- testCreate = check pn . sign s $- create <* title "Awesome playlist" <*> ak <*> sk---pl ∷ Value → Parser [String]-pl o = parseJSON o >>= (.: "playlists") >>= (.: "playlist") >>= mapM (.: "id")--pn ∷ Value → Parser String-pn o = parseJSON o >>= (.: "playlists") >>= (.: "playlist") >>= (.: "title")
− tests/Tag.hs
@@ -1,67 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module Tag (noauth) where--import Data.Aeson.Types-import Network.Lastfm-import Network.Lastfm.Tag-import Test.Framework-import Test.Framework.Providers.HUnit--import Common---noauth ∷ Request JSON APIKey → [Test]-noauth ak =- [ testCase "Tag.getInfo" testGetInfo- , testCase "Tag.getSimilar" testGetSimilar- , testCase "Tag.getTopAlbums" testGetTopAlbums- , testCase "Tag.getTopArtists" testGetTopArtists- , testCase "Tag.getTopTags" testGetTopTags- , testCase "Tag.getTopTracks" testGetTopTracks- , testCase "Tag.getWeeklyArtistChart" testGetWeeklyArtistChart- , testCase "Tag.getWeeklyChartList" testGetWeeklyChartList- , testCase "Tag.search" testSearch- ]- where- testGetInfo = check gi $- getInfo <*> tag "depressive" <*> ak-- testGetSimilar = check gs $- getSimilar <*> tag "depressive" <*> ak-- testGetTopAlbums = check gta $- getTopAlbums <*> tag "depressive" <* limit 2 <*> ak-- testGetTopArtists = check gtar $- getTopArtists <*> tag "depressive" <* limit 3 <*> ak-- testGetTopTags = check gtt $- getTopTags <*> ak-- testGetTopTracks = check gttr $- getTopTracks <*> tag "depressive" <* limit 2 <*> ak-- testGetWeeklyArtistChart = check gwac $- getWeeklyArtistChart <*> tag "depressive" <* limit 3 <*> ak-- testGetWeeklyChartList = check gc $- getWeeklyChartList <*> tag "depressive" <*> ak-- testSearch = check se $- search <*> tag "depressive" <* limit 3 <*> ak---gi ∷ Value → Parser String-gs, gta, gtar, gtt, gttr, gwac, se ∷ Value → Parser [String]-gc ∷ Value → Parser [(String, String)]-gi o = parseJSON o >>= (.: "tag") >>= (.: "taggings")-gc o = parseJSON o >>= (.: "weeklychartlist") >>= (.: "chart") >>= mapM (\t → (,) <$> (t .: "from") <*> (t .: "to"))-gs o = parseJSON o >>= (.: "similartags") >>= (.: "tag") >>= mapM (.: "name")-gta o = parseJSON o >>= (.: "topalbums") >>= (.: "album") >>= mapM (.: "url")-gtar o = parseJSON o >>= (.: "topartists") >>= (.: "artist") >>= mapM (.: "url")-gtt o = parseJSON o >>= (.: "toptags") >>= (.: "tag") >>= mapM (.: "name")-gttr o = parseJSON o >>= (.: "toptracks") >>= (.: "track") >>= mapM (.: "url")-gwac o = parseJSON o >>= (.: "weeklyartistchart") >>= (.: "artist") >>= mapM (.: "name")-se o = parseJSON o >>= (.: "results") >>= (.: "tagmatches") >>= (.: "tag") >>= mapM (.: "name")
− tests/Tasteometer.hs
@@ -1,34 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module Tasteometer (noauth) where--import Data.Aeson.Types-import Network.Lastfm-import qualified Network.Lastfm.Tasteometer as T-import Test.Framework-import Test.Framework.Providers.HUnit--import Common---noauth ∷ Request JSON APIKey → [Test]-noauth ak =- [ testCase "Tasteometer.compare" testCompare- , testCase "Tasteometer.compare'" testCompare'- , testCase "Tasteometer.compare''" testCompare''- , testCase "Tasteometer.compare'''" testCompare'''- ]- where- testCompare = check cs $- T.compare (user "smpcln") (user "MCDOOMDESTROYER") <*> ak- testCompare' = check cs $- T.compare (user "smpcln") (artists ["enduser", "venetian snares"]) <*> ak- testCompare'' = check cs $- T.compare (artists ["enduser", "venetian snares"]) (user "smpcln") <*> ak- testCompare''' = check cs $- T.compare (artists ["enduser", "venetian snares"]) (artists ["enduser", "venetian snares"]) <*> ak---cs ∷ Value → Parser String-cs o = parseJSON o >>= (.: "comparison") >>= (.: "result") >>= (.: "score")
− tests/Track.hs
@@ -1,132 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module Track (auth, noauth) where--import Data.Aeson.Types-import Network.Lastfm-import Network.Lastfm.Track-import Test.Framework-import Test.Framework.Providers.HUnit--import Common---auth ∷ Request JSON APIKey → Request JSON SessionKey → Secret → [Test]-auth ak sk s =- [ testCase "Track.addTags" testAddTags- , testCase "Track.ban" testBan- , testCase "Track.love" testLove- , testCase "Track.removeTag" testRemoveTag- , testCase "Track.share" testShare- , testCase "Track.unban" testUnban- , testCase "Track.unlove" testUnlove- , testCase "Track.scrobble" testScrobble- , testCase "Track.updateNowPlaying" testUpdateNowPlaying- ]- where- testAddTags = check ok . sign s $- addTags <*> artist "Jefferson Airplane" <*> track "White rabbit" <*> tags ["60s", "awesome"] <*> ak <*> sk-- testBan = check ok . sign s $- ban <*> artist "Eminem" <*> track "Kim" <*> ak <*> sk-- testLove = check ok . sign s $- love <*> artist "Gojira" <*> track "Ocean" <*> ak <*> sk-- testRemoveTag = check ok . sign s $- removeTag <*> artist "Jefferson Airplane" <*> track "White rabbit" <*> tag "awesome" <*> ak <*> sk-- testShare = check ok . sign s $- share <*> artist "Led Zeppelin" <*> track "When the Levee Breaks" <*> recipient "liblastfm" <* message "Just listen!" <*> ak <*> sk-- testUnban = check ok . sign s $- unban <*> artist "Eminem" <*> track "Kim" <*> ak <*> sk-- testUnlove = check ok . sign s $- unlove <*> artist "Gojira" <*> track "Ocean" <*> ak <*> sk-- testScrobble = check ss . sign s $- scrobble <*> artist "Gojira" <*> track "Ocean" <*> timestamp 1300000000 <*> ak <*> sk-- testUpdateNowPlaying = check np . sign s $- updateNowPlaying <*> artist "Gojira" <*> track "Ocean" <*> ak <*> sk---noauth ∷ Request JSON APIKey → [Test]-noauth ak =- [ testCase "Track.getBuylinks" testGetBuylinks- , testCase "Track.getCorrection" testGetCorrection- , testCase "Track.getFingerprintMetadata" testGetFingerprintMetadata- , testCase "Track.getInfo" testGetInfo- , testCase "Track.getInfo_mbid" testGetInfo_mbid- , testCase "Track.getShouts" testGetShouts- , testCase "Track.getShouts_mbid" testGetShouts_mbid- , testCase "Track.getSimilar" testGetSimilar- , testCase "Track.getSimilar_mbid" testGetSimilar_mbid- , testCase "Track.getTags" testGetTags- , testCase "Track.getTags_mbid" testGetTags_mbid- , testCase "Track.getTopFans" testGetTopFans- , testCase "Track.getTopFans_mbid" testGetTopFans_mbid- , testCase "Track.getTopTags" testGetTopTags- , testCase "Track.getTopTags_mbid" testGetTopTags_mbid- , testCase "Track.search" testSearch- ]- where- testGetBuylinks = check gbl $- getBuyLinks <*> country "United Kingdom" <*> artist "Pink Floyd" <*> track "Brain Damage" <*> ak-- testGetCorrection = check gc $- getCorrection <*> artist "Pink Ployd" <*> track "Brain Damage" <*> ak-- testGetFingerprintMetadata = check gfm $- getFingerprintMetadata <*> fingerprint 1234 <*> ak-- testGetInfo = check gi $- getInfo <*> artist "Pink Floyd" <*> track "Comfortably Numb" <* username "aswalrus" <*> ak- testGetInfo_mbid = check gi $- getInfo <*> mbid "52d7c9ff-6ae4-48a6-acec-4c1a486f8c92" <* username "aswalrus" <*> ak-- testGetShouts = check gsh $- getShouts <*> artist "Pink Floyd" <*> track "Comfortably Numb" <* limit 7 <*> ak- testGetShouts_mbid = check gsh $- getShouts <*> mbid "52d7c9ff-6ae4-48a6-acec-4c1a486f8c92" <* limit 7 <*> ak-- testGetSimilar = check gsi $- getSimilar <*> artist "Pink Floyd" <*> track "Comfortably Numb" <* limit 4 <*> ak- testGetSimilar_mbid = check gsi $- getSimilar <*> mbid "52d7c9ff-6ae4-48a6-acec-4c1a486f8c92" <* limit 4 <*> ak-- testGetTags = check gt $- getTags <*> artist "Jefferson Airplane" <*> track "White Rabbit" <* user "liblastfm" <*> ak- testGetTags_mbid = check gt $- getTags <*> mbid "001b3337-faf4-421a-a11f-45e0b60a7703" <* user "liblastfm" <*> ak-- testGetTopFans = check gtf $- getTopFans <*> artist "Pink Floyd" <*> track "Comfortably Numb" <*> ak- testGetTopFans_mbid = check gtf $- getTopFans <*> mbid "52d7c9ff-6ae4-48a6-acec-4c1a486f8c92" <*> ak-- testGetTopTags = check gtt $- getTopTags <*> artist "Pink Floyd" <*> track "Comfortably Numb" <*> ak- testGetTopTags_mbid = check gtt $- getTopTags <*> mbid "52d7c9ff-6ae4-48a6-acec-4c1a486f8c92" <*> ak-- testSearch = check s' $- search <*> track "Believe" <* limit 12 <*> ak---gc, gi, gt, ss, np ∷ Value → Parser String-gbl, gfm, gsh, gsi{-, gta-}, gtf, gtt, s' ∷ Value → Parser [String]-gbl o = parseJSON o >>= (.: "affiliations") >>= (.: "downloads") >>= (.: "affiliation") >>= mapM (.: "supplierName")-gc o = parseJSON o >>= (.: "corrections") >>= (.: "correction") >>= (.: "track") >>= (.: "artist") >>= (.: "name")-gfm o = parseJSON o >>= (.: "tracks") >>= (.: "track") >>= mapM (.: "name")-gi o = parseJSON o >>= (.: "track") >>= (.: "userplaycount")-gsh o = parseJSON o >>= (.: "shouts") >>= (.: "shout") >>= mapM (.: "author")-gsi o = parseJSON o >>= (.: "similartracks") >>= (.: "track") >>= mapM (.: "name")-gt o = parseJSON o >>= (.: "tags") >>= (.: "@attr") >>= (.: "track")-gtf o = parseJSON o >>= (.: "topfans") >>= (.: "user") >>= mapM (.: "name")-gtt o = parseJSON o >>= (.: "toptags") >>= (.: "tag") >>= mapM (.: "name")-s' o = parseJSON o >>= (.: "results") >>= (.: "trackmatches") >>= (.: "track") >>= mapM (.: "name")-ss o = parseJSON o >>= (.: "scrobbles") >>= (.: "scrobble") >>= (.: "track") >>= (.: "#text")-np o = parseJSON o >>= (.: "nowplaying") >>= (.: "track") >>= (.: "#text")
− tests/User.hs
@@ -1,152 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module User (auth, noauth) where--import Data.Aeson.Types-import Network.Lastfm-import Network.Lastfm.User-import Test.Framework-import Test.Framework.Providers.HUnit--import Common---auth ∷ Request JSON APIKey → Request JSON SessionKey → Secret → [Test]-auth ak sk s =- [ testCase "User.getRecentStations" testGetRecentStations- , testCase "User.getRecommendedArtists" testGetRecommendedArtists- , testCase "User.getRecommendedEvents" testGetRecommendedEvents- , testCase "User.shout" testShout- ]- where- testGetRecentStations = check grs . sign s $- getRecentStations <*> user "liblastfm" <* limit 10 <*> ak <*> sk-- testGetRecommendedArtists = check gra . sign s $- getRecommendedArtists <* limit 10 <*> ak <*> sk-- testGetRecommendedEvents = check gre . sign s $- getRecommendedEvents <* limit 10 <*> ak <*> sk-- testShout = check ok . sign s $- shout <*> user "liblastfm" <*> message "test message" <*> ak <*> sk---noauth ∷ Request JSON APIKey → [Test]-noauth ak =- [ testCase "User.getArtistTracks" testGetArtistTracks- , testCase "User.getBannedTracks" testGetBannedTracks- , testCase "User.getEvents" testGetEvents- , testCase "User.getFriends" testGetFriends- , testCase "User.getPlayCount" testGetPlayCount- , testCase "User.getGetLovedTracks" testGetLovedTracks- , testCase "User.getNeighbours" testGetNeighbours- , testCase "User.getNewReleases" testGetNewReleases- , testCase "User.getPastEvents" testGetPastEvents- , testCase "User.getPersonalTags" testGetPersonalTags- , testCase "User.getPlaylists" testGetPlaylists- , testCase "User.getRecentTracks" testGetRecentTracks- , testCase "User.getShouts" testGetShouts- , testCase "User.getTopAlbums" testGetTopAlbums- , testCase "User.getTopArtists" testGetTopArtists- , testCase "User.getTopTags" testGetTopTags- , testCase "User.getTopTracks" testGetTopTracks- , testCase "User.getWeeklyAlbumChart" testGetWeeklyAlbumChart- , testCase "User.getWeeklyArtistChart" testGetWeeklyArtistChart- , testCase "User.getWeeklyChartList" testGetWeeklyChartList- , testCase "User.getWeeklyTrackChart" testGetWeeklyTrackChart- ]- where- testGetArtistTracks = check gat $- getArtistTracks <*> user "smpcln" <*> artist "Dvar" <*> ak-- testGetBannedTracks = check gbt $- getBannedTracks <*> user "smpcln" <* limit 10 <*> ak-- testGetEvents = check ge $- getEvents <*> user "chansonnier" <* limit 5 <*> ak-- testGetFriends = check gf $- getFriends <*> user "smpcln" <* limit 10 <*> ak-- testGetPlayCount = check gpc $- getInfo <*> user "smpcln" <*> ak-- testGetLovedTracks = check glt $- getLovedTracks <*> user "smpcln" <* limit 10 <*> ak-- testGetNeighbours = check gn $- getNeighbours <*> user "smpcln" <* limit 10 <*> ak-- testGetNewReleases = check gnr $- getNewReleases <*> user "rj" <*> ak-- testGetPastEvents = check gpe $- getPastEvents <*> user "mokele" <* limit 5 <*> ak-- testGetPersonalTags = check gpt $- getPersonalTags <*> user "crackedcore" <*> tag "rhythmic noise" <*> taggingType "artist" <* limit 10 <*> ak-- testGetPlaylists = check gp $- getPlaylists <*> user "mokele" <*> ak-- testGetRecentTracks = check grt $- getRecentTracks <*> user "smpcln" <* limit 10 <*> ak-- testGetShouts = check gs $- getShouts <*> user "smpcln" <* limit 2 <*> ak-- testGetTopAlbums = check gtal $- getTopAlbums <*> user "smpcln" <* limit 5 <*> ak-- testGetTopArtists = check gtar $- getTopArtists <*> user "smpcln" <* limit 5 <*> ak-- testGetTopTags = check gtta $- getTopTags <*> user "smpcln" <* limit 10 <*> ak-- testGetTopTracks = check gttr $- getTopTracks <*> user "smpcln" <* limit 10 <*> ak-- testGetWeeklyAlbumChart = check gwalc $- getWeeklyAlbumChart <*> user "smpcln" <*> ak-- testGetWeeklyArtistChart = check gwarc $- getWeeklyArtistChart <*> user "smpcln" <*> ak-- testGetWeeklyChartList = check gwcl $- getWeeklyChartList <*> user "smpcln" <*> ak-- testGetWeeklyTrackChart = check gwtc $- getWeeklyTrackChart <*> user "smpcln" <*> ak---gpc ∷ Value → Parser String-gat, gbt, ge, gf, glt, gn, gnr, gp, gpe, gpt, gra, gre, grs, grt, gs, gtal, gtar, gtta, gttr, gwalc, gwarc, gwcl, gwtc ∷ Value → Parser [String]-gat o = parseJSON o >>= (.: "artisttracks") >>= (.: "track") >>= mapM (.: "name")-gbt o = parseJSON o >>= (.: "bannedtracks") >>= (.: "track") >>= mapM (.: "name")-ge o = parseJSON o >>= (.: "events") >>= (.: "event") >>= mapM (.: "venue") >>= mapM (.: "url")-gf o = parseJSON o >>= (.: "friends") >>= (.: "user") >>= mapM (.: "name")-glt o = parseJSON o >>= (.: "lovedtracks") >>= (.: "track") >>= mapM (.: "name")-gn o = parseJSON o >>= (.: "neighbours") >>= (.: "user") >>= mapM (.: "name")-gnr o = parseJSON o >>= (.: "albums") >>= (.: "album") >>= mapM (.: "url")-gp o = parseJSON o >>= (.: "playlists") >>= (.: "playlist") >>= mapM (.: "title")-gpc o = parseJSON o >>= (.: "user") >>= (.: "playcount")-gpe o = parseJSON o >>= (.: "events") >>= (.: "event") >>= mapM (.: "url")-gpt o = parseJSON o >>= (.: "taggings") >>= (.: "artists") >>= (.: "artist") >>= mapM (.: "name")-gra o = parseJSON o >>= (.: "recommendations") >>= (.: "artist") >>= mapM (.: "name")-gre o = do- m <- parseJSON o >>= (.: "events")- (m .: "event" >>= mapM (.: "url")) <|> (m .: "event" >>= fmap return . (.: "url"))-grs o = parseJSON o >>= (.: "recentstations") >>= (.: "station") >>= mapM (.: "name")-grt o = parseJSON o >>= (.: "recenttracks") >>= (.: "track") >>= mapM (.: "name")-gs o = parseJSON o >>= (.: "shouts") >>= (.: "shout") >>= mapM (.: "body")-gtal o = parseJSON o >>= (.: "topalbums") >>= (.: "album") >>= mapM (.: "artist") >>= mapM (.: "name")-gtar o = parseJSON o >>= (.: "topartists") >>= (.: "artist") >>= mapM (.: "name")-gtta o = parseJSON o >>= (.: "toptags") >>= (.: "tag") >>= mapM (.: "name")-gttr o = parseJSON o >>= (.: "toptracks") >>= (.: "track") >>= mapM (.: "url")-gwalc o = parseJSON o >>= (.: "weeklyalbumchart") >>= (.: "album") >>= mapM (.: "url")-gwarc o = parseJSON o >>= (.: "weeklyartistchart") >>= (.: "artist") >>= mapM (.: "url")-gwcl o = take 5 `fmap` (parseJSON o >>= (.: "weeklychartlist") >>= (.: "chart") >>= mapM (.: "from"))-gwtc o = parseJSON o >>= (.: "weeklytrackchart") >>= (.: "track") >>= mapM (.: "url")
− tests/Venue.hs
@@ -1,35 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module Venue (noauth) where--import Data.Aeson.Types-import Network.Lastfm-import Network.Lastfm.Venue-import Test.Framework-import Test.Framework.Providers.HUnit--import Common---noauth ∷ Request JSON APIKey → [Test]-noauth ak =- [ testCase "Venue.getEvents" testGetEvents- , testCase "Venue.getPastEvents" testGetPastEvents- , testCase "Venue.search" testSearch- ]- where- testGetEvents = check ge $- getEvents <*> venue 9163107 <*> ak-- testGetPastEvents = check gpe $- getPastEvents <*> venue 9163107 <* limit 2 <*> ak-- testSearch = check se $- search <*> venueName "Arena" <*> ak---ge, gpe, se ∷ Value → Parser [String]-ge o = parseJSON o >>= (.: "events") >>= (.: "event") >>= mapM (\t → (t .: "venue") >>= (.: "name"))-gpe o = parseJSON o >>= (.: "events") >>= (.: "event") >>= mapM (.: "title")-se o = parseJSON o >>= (.: "results") >>= (.: "venuematches") >>= (.: "venue") >>= mapM (.: "id")
− tests/json.hs
@@ -1,68 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE UnicodeSyntax #-}-module Main where--import Control.Applicative-import Data.Monoid-import System.Exit (ExitCode(ExitFailure), exitWith)--import qualified Data.ByteString.Lazy as B-import Data.Aeson-import Data.Text (Text)-import Network.Lastfm-import Test.Framework--import qualified Album as Album-import qualified Artist as Artist-import qualified Chart as Chart-import qualified Event as Event-import qualified Geo as Geo-import qualified Group as Group-import qualified Library as Library-import qualified Playlist as Playlist-import qualified Tag as Tag-import qualified Tasteometer as Tasteometer-import qualified Track as Track-import qualified User as User-import qualified Venue as Venue---main ∷ IO ()-main =- do keys ← B.readFile "tests/lastfm-keys.json"- case decode keys of- Just (Keys ak sk s) →- defaultMainWithOpts (auth <> noauth) (mempty { ropt_threads = Just 20 })- where- auth = mconcat . map (\f → f (apiKey ak) (sessionKey sk) (Secret s)) $- [ Album.auth- , Artist.auth- , Event.auth- , Library.auth- , Playlist.auth- , Track.auth- , User.auth- ]- noauth = mconcat . map (\f → f (apiKey ak)) $- [ Album.noauth- , Artist.noauth- , Chart.noauth- , Event.noauth- , Geo.noauth- , Group.noauth- , Library.noauth- , Tag.noauth- , Tasteometer.noauth- , Track.noauth- , User.noauth- , Venue.noauth- ]- Nothing → exitWith (ExitFailure 1)---data Keys = Keys Text Text Text---instance FromJSON Keys where- parseJSON (Object o) = Keys <$> (o .: "APIKey") <*> (o .: "SessionKey") <*> (o .: "Secret")- parseJSON _ = empty