freesound 0.2.0 → 0.3.0
raw patch · 20 files changed
+546/−456 lines, 20 filesdep +containersdep +hspec-corePVP ok
version bump matches the API change (PVP)
Dependencies added: containers, hspec-core
API changes (from Hackage documentation)
- Sound.Freesound: data Resource a
- Sound.Freesound: getBookmarkCategories :: Detail -> Freesound [Category]
- Sound.Freesound: getPacks :: Detail -> Freesound Packs
- Sound.Freesound: getResource :: (FromJSON a) => Resource a -> Freesound a
- Sound.Freesound: getSimilar :: Pagination -> Detail -> Freesound Sounds
- Sound.Freesound: getSimilar_ :: Detail -> Freesound Sounds
- Sound.Freesound: getSounds :: Pagination -> Detail -> Freesound Sounds
- Sound.Freesound: getSounds_ :: Detail -> Freesound Sounds
- Sound.Freesound: getURI :: URI -> Freesound ByteString
- Sound.Freesound: getUser :: (User a) => a -> Freesound Detail
- Sound.Freesound: search :: Pagination -> Sorting -> Filters -> Query -> Freesound Sounds
- Sound.Freesound: search_ :: Query -> Freesound Sounds
- Sound.Freesound.Bookmark: category :: Category -> Text
- Sound.Freesound.Bookmark: data Bookmark
- Sound.Freesound.Bookmark: data Category
- Sound.Freesound.Bookmark: getSounds :: Category -> Freesound [Bookmark]
- Sound.Freesound.Bookmark: instance Data.Aeson.Types.Class.FromJSON Sound.Freesound.Bookmark.Bookmark
- Sound.Freesound.Bookmark: instance Data.Aeson.Types.Class.FromJSON Sound.Freesound.Bookmark.Category
- Sound.Freesound.Bookmark: instance GHC.Classes.Eq Sound.Freesound.Bookmark.Bookmark
- Sound.Freesound.Bookmark: instance GHC.Classes.Eq Sound.Freesound.Bookmark.Category
- Sound.Freesound.Bookmark: instance GHC.Show.Show Sound.Freesound.Bookmark.Bookmark
- Sound.Freesound.Bookmark: instance GHC.Show.Show Sound.Freesound.Bookmark.Category
- Sound.Freesound.Bookmark: name :: Bookmark -> Text
- Sound.Freesound.Bookmark: sound :: Bookmark -> Summary
- Sound.Freesound.Bookmark: sounds :: Category -> Resource [Bookmark]
- Sound.Freesound.Bookmark: url :: Category -> URI
- Sound.Freesound.List: class Elem a
- Sound.Freesound.List: elemsFieldName :: Elem a => a -> Text
- Sound.Freesound.List: instance (Sound.Freesound.List.Elem a, Data.Aeson.Types.Class.FromJSON a) => Data.Aeson.Types.Class.FromJSON (Sound.Freesound.List.List a)
- Sound.Freesound.Pack: class Pack a
- Sound.Freesound.Pack: data Detail
- Sound.Freesound.Pack: data Summary
- Sound.Freesound.Pack: getSounds :: (Pack a) => Pagination -> a -> Freesound Sounds
- Sound.Freesound.Pack: getSounds_ :: (Pack a) => a -> Freesound Sounds
- Sound.Freesound.Pack: ref :: Pack a => a -> Resource ()
- Sound.Freesound.Pack: type Packs = List Summary
- Sound.Freesound.Search: [resultsPerPage] :: Pagination -> Int
- Sound.Freesound.Search.Filter: avgRating :: Numerical Double -> Filters
- Sound.Freesound.Search.Filter: bitdepth :: Numerical Integer -> Filters
- Sound.Freesound.Search.Filter: bitrate :: Numerical Integer -> Filters
- Sound.Freesound.Search.Filter: channels :: Numerical Integer -> Filters
- Sound.Freesound.Search.Filter: comment :: Text -> Filters
- Sound.Freesound.Search.Filter: comments :: Numerical Integer -> Filters
- Sound.Freesound.Search.Filter: created :: Text -> Filters
- Sound.Freesound.Search.Filter: data Filters
- Sound.Freesound.Search.Filter: description :: Text -> Filters
- Sound.Freesound.Search.Filter: duration :: Numerical Double -> Filters
- Sound.Freesound.Search.Filter: fileType :: FileType -> Filters
- Sound.Freesound.Search.Filter: filesize :: Numerical Integer -> Filters
- Sound.Freesound.Search.Filter: id :: Numerical SoundId -> Filters
- Sound.Freesound.Search.Filter: instance Data.Default.Class.Default Sound.Freesound.Search.Filter.Filters
- Sound.Freesound.Search.Filter: instance GHC.Base.Monoid Sound.Freesound.Search.Filter.Filters
- Sound.Freesound.Search.Filter: instance GHC.Classes.Eq Sound.Freesound.Search.Filter.F_Bool
- Sound.Freesound.Search.Filter: instance GHC.Classes.Eq Sound.Freesound.Search.Filter.Filter
- Sound.Freesound.Search.Filter: instance GHC.Classes.Eq Sound.Freesound.Search.Filter.License
- Sound.Freesound.Search.Filter: instance GHC.Show.Show Sound.Freesound.Search.Filter.F_Bool
- Sound.Freesound.Search.Filter: instance GHC.Show.Show Sound.Freesound.Search.Filter.Filter
- Sound.Freesound.Search.Filter: instance GHC.Show.Show Sound.Freesound.Search.Filter.Filters
- Sound.Freesound.Search.Filter: instance GHC.Show.Show Sound.Freesound.Search.Filter.License
- Sound.Freesound.Search.Filter: instance Network.HTTP.Types.QueryLike.QueryValueLike Sound.Freesound.Search.Filter.F_Bool
- Sound.Freesound.Search.Filter: instance Network.HTTP.Types.QueryLike.QueryValueLike Sound.Freesound.Search.Filter.Filter
- Sound.Freesound.Search.Filter: instance Network.HTTP.Types.QueryLike.QueryValueLike Sound.Freesound.Search.Filter.Filters
- Sound.Freesound.Search.Filter: instance Network.HTTP.Types.QueryLike.QueryValueLike Sound.Freesound.Search.Filter.License
- Sound.Freesound.Search.Filter: isGeotagged :: Bool -> Filters
- Sound.Freesound.Search.Filter: isRemix :: Bool -> Filters
- Sound.Freesound.Search.Filter: license :: License -> Filters
- Sound.Freesound.Search.Filter: md5 :: Text -> Filters
- Sound.Freesound.Search.Filter: numDownloads :: Numerical Integer -> Filters
- Sound.Freesound.Search.Filter: numRatings :: Numerical Integer -> Filters
- Sound.Freesound.Search.Filter: originalFilename :: Text -> Filters
- Sound.Freesound.Search.Filter: pack :: Text -> Filters
- Sound.Freesound.Search.Filter: samplerate :: Numerical Integer -> Filters
- Sound.Freesound.Search.Filter: tag :: Text -> Filters
- Sound.Freesound.Search.Filter: username :: Text -> Filters
- Sound.Freesound.Search.Filter: wasRemixed :: Bool -> Filters
- Sound.Freesound.Search.Numerical: between :: Ord a => a -> a -> Numerical a
- Sound.Freesound.Search.Numerical: data Numerical a
- Sound.Freesound.Search.Numerical: equals :: a -> Numerical a
- Sound.Freesound.Search.Numerical: greaterThan :: a -> Numerical a
- Sound.Freesound.Search.Numerical: instance GHC.Classes.Eq a => GHC.Classes.Eq (Sound.Freesound.Search.Numerical.Numerical a)
- Sound.Freesound.Search.Numerical: instance GHC.Show.Show a => GHC.Show.Show (Sound.Freesound.Search.Numerical.Numerical a)
- Sound.Freesound.Search.Numerical: instance Sound.Freesound.Search.Numerical.NumericalQueryValue Data.Time.Clock.UTC.UTCTime
- Sound.Freesound.Search.Numerical: instance Sound.Freesound.Search.Numerical.NumericalQueryValue GHC.Integer.Type.Integer
- Sound.Freesound.Search.Numerical: instance Sound.Freesound.Search.Numerical.NumericalQueryValue GHC.Types.Double
- Sound.Freesound.Search.Numerical: instance Sound.Freesound.Search.Numerical.NumericalQueryValue Sound.Freesound.Sound.Type.SoundId
- Sound.Freesound.Search.Numerical: instance Sound.Freesound.Search.Numerical.NumericalQueryValue a => Network.HTTP.Types.QueryLike.QueryValueLike (Sound.Freesound.Search.Numerical.Numerical a)
- Sound.Freesound.Search.Numerical: lessThan :: a -> Numerical a
- Sound.Freesound.Search.Query: (&) :: Query -> Query -> Query
- Sound.Freesound.Search.Query: data Query
- Sound.Freesound.Search.Query: exclude :: Text -> Query
- Sound.Freesound.Search.Query: include :: Text -> Query
- Sound.Freesound.Search.Query: instance GHC.Classes.Eq Sound.Freesound.Search.Query.Query
- Sound.Freesound.Search.Query: instance GHC.Classes.Eq Sound.Freesound.Search.Query.Term
- Sound.Freesound.Search.Query: instance GHC.Show.Show Sound.Freesound.Search.Query.Query
- Sound.Freesound.Search.Query: instance GHC.Show.Show Sound.Freesound.Search.Query.Term
- Sound.Freesound.Search.Query: instance Network.HTTP.Types.QueryLike.QueryValueLike Sound.Freesound.Search.Query.Query
- Sound.Freesound.Sound: data SoundId
- Sound.Freesound.Sound: getSimilar :: Pagination -> Detail -> Freesound Sounds
- Sound.Freesound.Sound: getSimilar_ :: Detail -> Freesound Sounds
- Sound.Freesound.Sound: search :: Pagination -> Sorting -> Filters -> Query -> Freesound Sounds
- Sound.Freesound.Sound: search_ :: Query -> Freesound Sounds
- Sound.Freesound.Sound: type Sounds = List Summary
- Sound.Freesound.User: about :: Detail -> Maybe Text
- Sound.Freesound.User: bookmarkCategories :: Detail -> Resource Categories
- Sound.Freesound.User: class User a
- Sound.Freesound.User: data Detail
- Sound.Freesound.User: data Summary
- Sound.Freesound.User: dateJoined :: Detail -> Text
- Sound.Freesound.User: firstName :: Detail -> Maybe Text
- Sound.Freesound.User: getBookmarkCategories :: Detail -> Freesound [Category]
- Sound.Freesound.User: getPacks :: Detail -> Freesound Packs
- Sound.Freesound.User: getSounds :: Pagination -> Detail -> Freesound Sounds
- Sound.Freesound.User: getSounds_ :: Detail -> Freesound Sounds
- Sound.Freesound.User: getUser :: (User a) => a -> Freesound Detail
- Sound.Freesound.User: homePage :: Detail -> Maybe Text
- Sound.Freesound.User: lastName :: Detail -> Maybe Text
- Sound.Freesound.User: name :: User a => a -> Text
- Sound.Freesound.User: packs :: Detail -> Resource (List Summary)
- Sound.Freesound.User: ref :: User a => a -> Resource Detail
- Sound.Freesound.User: signature :: Detail -> Maybe Text
- Sound.Freesound.User: sounds :: Detail -> Resource (List Summary)
- Sound.Freesound.User: url :: User a => a -> URI
+ Sound.Freesound: Resource :: URI -> Resource a
+ Sound.Freesound: download :: URI -> Freesound ByteString
+ Sound.Freesound: downloadToFile :: FilePath -> URI -> Freesound ()
+ Sound.Freesound: get :: (FromJSON a) => Resource a -> Freesound a
+ Sound.Freesound: newtype Resource a
+ Sound.Freesound.Bookmark: BookmarkCategory :: URI -> Text -> Int -> Resource (List Summary) -> BookmarkCategory
+ Sound.Freesound.Bookmark: [name] :: BookmarkCategory -> Text
+ Sound.Freesound.Bookmark: [numSounds] :: BookmarkCategory -> Int
+ Sound.Freesound.Bookmark: [sounds] :: BookmarkCategory -> Resource (List Summary)
+ Sound.Freesound.Bookmark: [url] :: BookmarkCategory -> URI
+ Sound.Freesound.Bookmark: data BookmarkCategory
+ Sound.Freesound.Bookmark: instance Data.Aeson.Types.Class.FromJSON Sound.Freesound.Bookmark.BookmarkCategory
+ Sound.Freesound.Bookmark: instance GHC.Classes.Eq Sound.Freesound.Bookmark.BookmarkCategory
+ Sound.Freesound.Bookmark: instance GHC.Show.Show Sound.Freesound.Bookmark.BookmarkCategory
+ Sound.Freesound.Comment: Comment :: Text -> Text -> UTCTime -> Comment
+ Sound.Freesound.Comment: [comment] :: Comment -> Text
+ Sound.Freesound.Comment: [created] :: Comment -> UTCTime
+ Sound.Freesound.Comment: [username] :: Comment -> Text
+ Sound.Freesound.Comment: data Comment
+ Sound.Freesound.Comment: instance Data.Aeson.Types.Class.FromJSON Sound.Freesound.Comment.Comment
+ Sound.Freesound.Comment: instance GHC.Classes.Eq Sound.Freesound.Comment.Comment
+ Sound.Freesound.Comment: instance GHC.Show.Show Sound.Freesound.Comment.Comment
+ Sound.Freesound.List: instance Data.Aeson.Types.Class.FromJSON a => Data.Aeson.Types.Class.FromJSON (Sound.Freesound.List.List a)
+ Sound.Freesound.Pack: data Pack
+ Sound.Freesound.Pack: description :: Pack -> Text
+ Sound.Freesound.Pack: id :: Pack -> PackId
+ Sound.Freesound.Pack: numSounds :: Pack -> Int
+ Sound.Freesound.Search: (&) :: Query -> Query -> Query
+ Sound.Freesound.Search: [pageSize] :: Pagination -> Int
+ Sound.Freesound.Search: avgRating :: Numerical Double -> Filters
+ Sound.Freesound.Search: between :: Ord a => a -> a -> Numerical a
+ Sound.Freesound.Search: bitdepth :: Numerical Integer -> Filters
+ Sound.Freesound.Search: bitrate :: Numerical Integer -> Filters
+ Sound.Freesound.Search: channels :: Numerical Integer -> Filters
+ Sound.Freesound.Search: comment :: Text -> Filters
+ Sound.Freesound.Search: comments :: Numerical Integer -> Filters
+ Sound.Freesound.Search: created :: Text -> Filters
+ Sound.Freesound.Search: data Filters
+ Sound.Freesound.Search: data Numerical a
+ Sound.Freesound.Search: data Query
+ Sound.Freesound.Search: description :: Text -> Filters
+ Sound.Freesound.Search: duration :: Numerical Double -> Filters
+ Sound.Freesound.Search: equals :: a -> Numerical a
+ Sound.Freesound.Search: exclude :: Text -> Query
+ Sound.Freesound.Search: fileType :: FileType -> Filters
+ Sound.Freesound.Search: filesize :: Numerical Integer -> Filters
+ Sound.Freesound.Search: greaterThan :: a -> Numerical a
+ Sound.Freesound.Search: id :: Numerical SoundId -> Filters
+ Sound.Freesound.Search: include :: Text -> Query
+ Sound.Freesound.Search: isGeotagged :: Bool -> Filters
+ Sound.Freesound.Search: isRemix :: Bool -> Filters
+ Sound.Freesound.Search: lessThan :: a -> Numerical a
+ Sound.Freesound.Search: license :: License -> Filters
+ Sound.Freesound.Search: md5 :: Text -> Filters
+ Sound.Freesound.Search: numDownloads :: Numerical Integer -> Filters
+ Sound.Freesound.Search: numRatings :: Numerical Integer -> Filters
+ Sound.Freesound.Search: originalFilename :: Text -> Filters
+ Sound.Freesound.Search: pack :: Text -> Filters
+ Sound.Freesound.Search: samplerate :: Numerical Integer -> Filters
+ Sound.Freesound.Search: search :: Pagination -> Sorting -> Filters -> Query -> Freesound (List Summary)
+ Sound.Freesound.Search: search_ :: Query -> Freesound (List Summary)
+ Sound.Freesound.Search: tag :: Text -> Filters
+ Sound.Freesound.Search: username :: Text -> Filters
+ Sound.Freesound.Search: wasRemixed :: Bool -> Filters
+ Sound.Freesound.Sound: GeoTag :: Double -> Double -> GeoTag
+ Sound.Freesound.Sound: SoundId :: Integer -> SoundId
+ Sound.Freesound.Sound: [latitude] :: GeoTag -> Double
+ Sound.Freesound.Sound: [longitude] :: GeoTag -> Double
+ Sound.Freesound.Sound: [soundIdToInteger] :: SoundId -> Integer
+ Sound.Freesound.Sound: data GeoTag
+ Sound.Freesound.Sound: newtype SoundId
+ Sound.Freesound.Sound: soundById :: SoundId -> Freesound Detail
+ Sound.Freesound.Sound: soundDetail :: Summary -> Freesound Detail
+ Sound.Freesound.User: Avatar :: URI -> URI -> URI -> Avatar
+ Sound.Freesound.User: User :: URI -> Text -> Maybe Text -> Maybe URI -> Maybe Avatar -> UTCTime -> Int -> Resource (List Summary) -> Int -> Resource (List Pack) -> Int -> Int -> Resource (List BookmarkCategory) -> User
+ Sound.Freesound.User: [about] :: User -> Maybe Text
+ Sound.Freesound.User: [avatar] :: User -> Maybe Avatar
+ Sound.Freesound.User: [bookmarkCategories] :: User -> Resource (List BookmarkCategory)
+ Sound.Freesound.User: [dateJoined] :: User -> UTCTime
+ Sound.Freesound.User: [homepage] :: User -> Maybe URI
+ Sound.Freesound.User: [large] :: Avatar -> URI
+ Sound.Freesound.User: [medium] :: Avatar -> URI
+ Sound.Freesound.User: [numComments] :: User -> Int
+ Sound.Freesound.User: [numPacks] :: User -> Int
+ Sound.Freesound.User: [numPosts] :: User -> Int
+ Sound.Freesound.User: [numSounds] :: User -> Int
+ Sound.Freesound.User: [packs] :: User -> Resource (List Pack)
+ Sound.Freesound.User: [small] :: Avatar -> URI
+ Sound.Freesound.User: [sounds] :: User -> Resource (List Summary)
+ Sound.Freesound.User: [url] :: User -> URI
+ Sound.Freesound.User: [username] :: User -> Text
+ Sound.Freesound.User: data Avatar
+ Sound.Freesound.User: data User
+ Sound.Freesound.User: instance Data.Aeson.Types.Class.FromJSON Sound.Freesound.User.Avatar
+ Sound.Freesound.User: instance Data.Aeson.Types.Class.FromJSON Sound.Freesound.User.User
+ Sound.Freesound.User: instance GHC.Classes.Eq Sound.Freesound.User.Avatar
+ Sound.Freesound.User: instance GHC.Classes.Eq Sound.Freesound.User.User
+ Sound.Freesound.User: instance GHC.Show.Show Sound.Freesound.User.Avatar
+ Sound.Freesound.User: instance GHC.Show.Show Sound.Freesound.User.User
- Sound.Freesound: getUserByName :: Text -> Freesound Detail
+ Sound.Freesound: getUserByName :: Text -> Freesound User
- Sound.Freesound.List: getNext :: (Elem a, FromJSON a) => List a -> Freesound (Maybe (List a))
+ Sound.Freesound.List: getNext :: FromJSON a => List a -> Freesound (Maybe (List a))
- Sound.Freesound.List: getPrevious :: (Elem a, FromJSON a) => List a -> Freesound (Maybe (List a))
+ Sound.Freesound.List: getPrevious :: FromJSON a => List a -> Freesound (Maybe (List a))
- Sound.Freesound.Pack: created :: Pack a => a -> Text
+ Sound.Freesound.Pack: created :: Pack -> UTCTime
- Sound.Freesound.Pack: name :: Pack a => a -> Text
+ Sound.Freesound.Pack: name :: Pack -> Text
- Sound.Freesound.Pack: numDownloads :: Pack a => a -> Integer
+ Sound.Freesound.Pack: numDownloads :: Pack -> Int
- Sound.Freesound.Pack: sounds :: Pack a => a -> Resource (List Summary)
+ Sound.Freesound.Pack: sounds :: Pack -> Resource (List Summary)
- Sound.Freesound.Pack: url :: Pack a => a -> URI
+ Sound.Freesound.Pack: url :: Pack -> URI
- Sound.Freesound.Pack: username :: Detail -> Text
+ Sound.Freesound.Pack: username :: Pack -> Text
- Sound.Freesound.Sound: comments :: Detail -> Resource ()
+ Sound.Freesound.Sound: comments :: Detail -> Resource (List Comment)
- Sound.Freesound.Sound: created :: Detail -> Text
+ Sound.Freesound.Sound: created :: Detail -> UTCTime
- Sound.Freesound.Sound: pack :: Detail -> Maybe (Resource ())
+ Sound.Freesound.Sound: pack :: Detail -> Maybe (Resource Pack)
- Sound.Freesound.User: getUserByName :: Text -> Freesound Detail
+ Sound.Freesound.User: getUserByName :: Text -> Freesound User
Files
- freesound.cabal +14/−7
- src/Sound/Freesound.hs +10/−27
- src/Sound/Freesound/API.hs +24/−28
- src/Sound/Freesound/Bookmark.hs +15/−35
- src/Sound/Freesound/Bookmark/Internal.hs +0/−24
- src/Sound/Freesound/Comment.hs +26/−0
- src/Sound/Freesound/List.hs +6/−11
- src/Sound/Freesound/Pack.hs +19/−20
- src/Sound/Freesound/Pack/Type.hs +33/−65
- src/Sound/Freesound/Search.hs +35/−7
- src/Sound/Freesound/Search/Query.hs +29/−14
- src/Sound/Freesound/Sound.hs +12/−45
- src/Sound/Freesound/Sound/Type.hs +43/−40
- src/Sound/Freesound/Time.hs +15/−0
- src/Sound/Freesound/User.hs +60/−46
- src/Sound/Freesound/User/Type.hs +0/−85
- test/Sound/Freesound/SearchSpec.hs +23/−0
- test/Sound/Freesound/SoundSpec.hs +71/−0
- test/Sound/Freesound/Test.hs +45/−2
- test/Sound/Freesound/UserSpec.hs +66/−0
freesound.cabal view
@@ -1,5 +1,5 @@ name: freesound-version: 0.2.0+version: 0.3.0 synopsis: Access the Freesound Project database description: Access the Freesound Project database. The Freesound Project is a collaborative database of Creative Commons@@ -17,7 +17,7 @@ stability: experimental homepage: https://github.com/kaoskorobase/freesound bug-reports: https://github.com/kaoskorobase/freesound/issues-tested-with: GHC == 6.10.1, GHC == 6.10.4, GHC == 6.12.1, GHC == 7.10.3+tested-with: GHC == 7.8, GHC == 7.10 build-type: Simple cabal-version: >= 1.8 @@ -31,19 +31,19 @@ library exposed-modules: Sound.Freesound Sound.Freesound.Bookmark+ Sound.Freesound.Comment Sound.Freesound.List Sound.Freesound.Pack Sound.Freesound.Search- Sound.Freesound.Search.Filter- Sound.Freesound.Search.Numerical- Sound.Freesound.Search.Query Sound.Freesound.Sound Sound.Freesound.User other-modules: Sound.Freesound.API- Sound.Freesound.Bookmark.Internal Sound.Freesound.Pack.Type+ Sound.Freesound.Search.Filter+ Sound.Freesound.Search.Numerical+ Sound.Freesound.Search.Query Sound.Freesound.Sound.Type- Sound.Freesound.User.Type+ Sound.Freesound.Time build-depends: base >= 3 && < 5 , aeson >= 0.6 , blaze-builder >= 0.3@@ -73,7 +73,14 @@ hs-source-dirs: test main-is: Spec.hs other-modules: Sound.Freesound.Test+ Sound.Freesound.SearchSpec+ Sound.Freesound.SoundSpec+ Sound.Freesound.UserSpec build-depends: base == 4.*+ , aeson >= 0.6+ , bytestring >= 0.9+ , containers , data-default , freesound , hspec+ , hspec-core
src/Sound/Freesound.hs view
@@ -7,32 +7,15 @@ -- -- > import qualified Network.HTTP.Conduit as HTTP -module Sound.Freesound-(- -- * Searching- module Sound.Freesound.Search-, module Sound.Freesound.Search.Query-, module Sound.Freesound.List- -- * Users-, getUser-, getUserByName-, getBookmarkCategories-, getSounds-, getSounds_-, getPacks- -- * Sounds-, search-, search_-, getSimilar-, getSimilar_- -- * Freesound API monad-, module Sound.Freesound.API-)-where+module Sound.Freesound (+ -- * Freesound API monad+ module Sound.Freesound.API+ -- * Result lists+ , module Sound.Freesound.List+ -- * Users+ , getUserByName+) where -import Sound.Freesound.API (Freesound, runFreesound, APIKey, apiKeyFromString)+import Sound.Freesound.API (Freesound, runFreesound, APIKey, apiKeyFromString, get, download, downloadToFile) import Sound.Freesound.List-import Sound.Freesound.Search-import Sound.Freesound.Search.Query-import Sound.Freesound.User-import Sound.Freesound.Sound+import Sound.Freesound.User (getUserByName)
src/Sound/Freesound/API.hs view
@@ -7,20 +7,21 @@ , runFreesound -- , request , URI-, getURI-, Resource+, download+, downloadToFile+, Resource(..) , resourceURI , appendQuery-, getResource+, get ) where import qualified Blaze.ByteString.Builder as Builder import qualified Blaze.ByteString.Builder.Char8 as Builder-import Control.Monad (liftM, mzero) import Control.Monad.IO.Class (MonadIO, liftIO) import qualified Control.Monad.Reader as R import Control.Lens-import Data.Aeson as J+import Data.Aeson+import Data.Aeson.Types (typeMismatch) import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy.Char8 as BL import Data.Text (Text)@@ -64,23 +65,31 @@ newtype URI = URI URI.URI deriving (Eq, Show) instance FromJSON URI where- parseJSON (String v) = maybe mzero return (parseURI' (T.unpack v))- parseJSON _ = mzero+ parseJSON (String v) =+ maybe (fail "Couldn't parse URI")+ return+ (parseURI' (T.unpack v))+ parseJSON v = typeMismatch "URI" v -- | Cover up for Freesound sloppiness. parseURI' :: String -> Maybe URI parseURI' = fmap URI . URI.parseURI . URI.escapeURIString URI.isAllowedInURI -- | Download the data referred to by a URI.-getURI :: URI -> Freesound BL.ByteString-getURI (URI u) = do+download :: URI -> Freesound BL.ByteString+download (URI u) = do s <- R.asks session APIKey k <- R.asks apiKey let opts = HTTP.defaults & HTTP.header "Authorization" .~ ["Token " `BS.append` k] u' = URI.uriToString id u ""+ -- liftIO $ print u' r <- liftIO $ Session.getWith opts s u' return $ r ^. HTTP.responseBody +-- | Download the data referred to by a URI to a file.+downloadToFile :: FilePath -> URI -> Freesound ()+downloadToFile path uri = liftIO . BL.writeFile path =<< download uri+ -- | Resource URI. newtype Resource a = Resource URI deriving (Eq, FromJSON, Show) @@ -93,19 +102,12 @@ $ HTTP.parseQuery (BS.pack (URI.uriQuery u)) ++ HTTP.toQuery q --- | Create a query item for the API key.--- apiKeyQuery :: Freesound HTTP.Query--- apiKeyQuery = do--- k <- Freesound $ R.asks apiKey--- return $ [("api_key", Just k)]---- | Download the resource referred to by a URI.-getResource :: (FromJSON a) => Resource a -> Freesound a-getResource (Resource u) = do- -- q <- apiKeyQuery- -- let Resource u = appendQuery q r- liftM (handle . J.eitherDecode) $ getURI u- where handle = either (\e -> error $ "Internal error (getResource): JSON decoding failed: " ++ e) id+-- | Get the resource referred to by a URI.+get :: (FromJSON a) => Resource a -> Freesound a+get (Resource u) = do+ handle . eitherDecode <$> download u+ -- TODO: Proper error handling+ where handle = either (\e -> error $ "JSON decoding failed: " ++ e) id -- | The base URI of the Freesound API. baseURI :: Builder.Builder@@ -120,9 +122,3 @@ . mappend baseURI . HTTP.encodePath path $ query---- | Perform an HTTP request given the method, a URI and an optional body and return the response body as a Conduit source.--- request :: Monad m => HTTP.Method -> URI -> Maybe (C.Source m BS.ByteString) -> FreesoundT m (C.ResumableSource m BS.ByteString)--- request method (URI uri) body = do--- f <- FreesoundT $ R.asks httpRequest--- lift $ f method uri body
src/Sound/Freesound/Bookmark.hs view
@@ -1,50 +1,30 @@ {-# LANGUAGE CPP, OverloadedStrings #-} module Sound.Freesound.Bookmark (- Bookmark-, sound-, name-, Category-, category-, url-, sounds-, getSounds+ BookmarkCategory(..) ) where -import Control.Monad (mzero) import Data.Aeson import Data.Text (Text)-import Sound.Freesound.API (Freesound, Resource, URI, getResource)+import Sound.Freesound.API (Resource, URI)+import Sound.Freesound.List (List) import qualified Sound.Freesound.Sound.Type as Sound #if __GLASGOW_HASKELL__ < 710 import Control.Applicative #endif -data Bookmark = Bookmark {- sound :: Sound.Summary-, name :: Text-} deriving (Eq, Show)--instance FromJSON Bookmark where- parseJSON j@(Object v) =- Bookmark- <$> parseJSON j- <*> v .: "bookmark_name"- parseJSON _ = mzero--data Category = Category {- category :: Text-, url :: URI-, sounds :: Resource [Bookmark]+data BookmarkCategory = BookmarkCategory {+ url :: URI+ , name :: Text+ , numSounds :: Int+ , sounds :: Resource (List Sound.Summary) } deriving (Eq, Show) -instance FromJSON Category where+instance FromJSON BookmarkCategory where parseJSON (Object v) =- Category- <$> v .: "name"- <*> v .: "url"- <*> v .: "sounds"- parseJSON _ = mzero--getSounds :: Category -> Freesound [Bookmark]-getSounds = getResource . sounds+ BookmarkCategory+ <$> v .: "url"+ <*> v .: "name"+ <*> v .: "num_sounds"+ <*> v .: "sounds"+ parseJSON _ = fail "Couldn't parse BookmarkCategory"
− src/Sound/Freesound/Bookmark/Internal.hs
@@ -1,24 +0,0 @@-{-# LANGUAGE CPP, OverloadedStrings #-}-module Sound.Freesound.Bookmark.Internal (- Categories(..)-) where--import Control.Monad (mzero)-import Data.Aeson-import Sound.Freesound.Bookmark--#if __GLASGOW_HASKELL__ < 710-import Control.Applicative-#endif--data Categories = Categories {- numCategories :: Int-, categories :: [Category]-} deriving (Eq, Show)--instance FromJSON Categories where- parseJSON (Object v) =- Categories- <$> v .: "num_results"- <*> v .: "categories"- parseJSON _ = mzero
+ src/Sound/Freesound/Comment.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE CPP, OverloadedStrings #-}+module Sound.Freesound.Comment (+ Comment(..)+) where++import Data.Aeson (FromJSON(..), Value(..), (.:))+import Data.Aeson.Types (typeMismatch)+import Data.Text (Text)+import Sound.Freesound.Time++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative+#endif++data Comment = Comment {+ username :: Text+ , comment :: Text+ , created :: UTCTime+ } deriving (Eq, Show)++instance FromJSON Comment where+ parseJSON (Object v) =+ Comment <$> v .: "username"+ <*> v .: "comment"+ <*> (toUTCTime <$> (v .: "created"))+ parseJSON v = typeMismatch "Comment" v
src/Sound/Freesound/List.hs view
@@ -1,7 +1,6 @@ {-# LANGUAGE CPP, OverloadedStrings, ScopedTypeVariables #-} module Sound.Freesound.List ( List-, Elem(..) , elems , numElems , previous@@ -12,8 +11,7 @@ import Control.Monad (liftM, mzero) import Data.Aeson-import Data.Text (Text)-import Sound.Freesound.API (Freesound, Resource, getResource)+import Sound.Freesound.API (Freesound, Resource, get) #if __GLASGOW_HASKELL__ < 710 import Control.Applicative@@ -26,10 +24,7 @@ , next :: Maybe (Resource (List a)) } deriving (Eq, Show) -class Elem a where- elemsFieldName :: a -> Text--instance (Elem a, FromJSON a) => FromJSON (List a) where+instance FromJSON a => FromJSON (List a) where parseJSON (Object v) = List <$> v .: "results"@@ -38,8 +33,8 @@ <*> v .:? "next" parseJSON _ = mzero -getPrevious :: (Elem a, FromJSON a) => List a -> Freesound (Maybe (List a))-getPrevious = maybe (return Nothing) (liftM Just . getResource) . previous+getPrevious :: FromJSON a => List a -> Freesound (Maybe (List a))+getPrevious = maybe (return Nothing) (liftM Just . get) . previous -getNext :: (Elem a, FromJSON a) => List a -> Freesound (Maybe (List a))-getNext = maybe (return Nothing) (liftM Just . getResource) . next+getNext :: FromJSON a => List a -> Freesound (Maybe (List a))+getNext = maybe (return Nothing) (liftM Just . get) . next
src/Sound/Freesound/Pack.hs view
@@ -1,24 +1,23 @@ module Sound.Freesound.Pack (- Pack(..)-, Packs-, Summary-, Detail-, username-, getSounds-, getSounds_+ Pack+ , id+ , url+ , description+ , created+ , name+ , username+ , numSounds+ , sounds+ , numDownloads ) where -import Data.Default (def)-import Sound.Freesound.API (Freesound, appendQuery, getResource)-import Sound.Freesound.List (List)-import Sound.Freesound.Pack.Type-import Sound.Freesound.Search (Pagination)-import Sound.Freesound.Sound (Sounds)--type Packs = List Summary--getSounds :: (Pack a) => Pagination -> a -> Freesound Sounds-getSounds p = getResource . appendQuery p . sounds+import Prelude hiding (id)+import Sound.Freesound.API+import Sound.Freesound.List (List)+import Sound.Freesound.Pack.Type hiding (sounds)+import qualified Sound.Freesound.Pack.Type as Pack+import qualified Sound.Freesound.Sound as Sound -getSounds_ :: (Pack a) => a -> Freesound Sounds-getSounds_ = getSounds def+-- ^ The URI for a list of sounds in the pack.+sounds :: Pack -> Resource (List Sound.Summary)+sounds = Resource . Pack.sounds
src/Sound/Freesound/Pack/Type.hs view
@@ -1,78 +1,46 @@ {-# LANGUAGE CPP, OverloadedStrings #-}-module Sound.Freesound.Pack.Type where+module Sound.Freesound.Pack.Type (+ Pack(..)+) where -import Control.Monad (mzero) import Data.Aeson (FromJSON(..), Value(..), (.:))+import Data.Aeson.Types (typeMismatch) import Data.Text (Text)-import Sound.Freesound.API (Resource, URI)-import Sound.Freesound.List (List, Elem(..))-import qualified Sound.Freesound.Sound as Sound+import Sound.Freesound.API (URI)+import Sound.Freesound.Time #if __GLASGOW_HASKELL__ < 710 import Control.Applicative #endif -class Pack a where- -- | The URI for this resource.- ref :: a -> Resource ()- -- | The URL for this pack’s page on the Freesound website.- url :: a -> URI- -- | The API URI for the pack’s sound collection.- sounds :: a -> Resource (List Sound.Summary)- -- | The pack’s name.- name :: a -> Text- -- | The date when the pack was created.- created :: a -> Text- -- | The number of times the pack was downloaded.- numDownloads :: a -> Integer--data Summary = Summary {- pack_ref :: Resource () -- ^ The URI for this resource.-, pack_url :: URI -- ^ The URL for this pack’s page on the Freesound website.-, pack_sounds :: Resource (List Sound.Summary) -- ^ The API URI for the pack’s sound collection.-, pack_name :: Text -- ^ The pack’s name.-, pack_created :: Text -- ^ The date when the pack was created.-, pack_num_downloads :: Integer -- ^ The number of times the pack was downloaded.-} deriving (Eq, Show)--instance Pack Summary where- ref = pack_ref- url = pack_url- sounds = pack_sounds- name = pack_name- created = pack_created- numDownloads = pack_num_downloads--instance FromJSON Summary where- parseJSON (Object o) =- Summary- <$> o .: "ref"- <*> o .: "url"- <*> o .: "sounds"- <*> o .: "name"- <*> o .: "created"- <*> o .: "num_downloads"- parseJSON _ = mzero+newtype PackId = PackId Integer deriving (Eq, Ord, Show) -instance Elem Summary where- elemsFieldName _ = "packs"+instance FromJSON PackId where+ parseJSON (Number i) = return $ PackId (truncate i)+ parseJSON v = typeMismatch "PackId" v -data Detail = Detail {- summary :: Summary-, username :: Text -- ^ A JSON object with the user’s username, url, and ref.+data Pack = Pack {+ id :: PackId -- ^ The unique identifier of this pack.+ , url :: URI -- ^ The URI for this pack on the Freesound website.+ , description :: Text -- ^ The description the user gave to the pack (if any).+ , created :: UTCTime -- ^ The date when the pack was created (e.g. “2014-04-16T20:07:11.145”).+ , name :: Text -- ^ The name user gave to the pack.+ , username :: Text -- ^ Username of the creator of the pack.+ , numSounds :: Int -- ^ The number of sounds in the pack.+ , sounds :: URI -- ^ The URI for a list of sounds in the pack. Plain URI in order to break module dependency cycle.+ , numDownloads :: Int -- ^ The number of times this pack has been downloaded. } deriving (Eq, Show) -instance Pack Detail where- ref = ref . summary- url = url . summary- sounds = sounds . summary- name = name . summary- created = created . summary- numDownloads = numDownloads . summary--instance FromJSON Detail where- parseJSON v@(Object o) =- Detail- <$> parseJSON v- <*> o .: "username"- parseJSON _ = mzero+instance FromJSON Pack where+ parseJSON (Object v) =+ Pack+ <$> v .: "id"+ <*> v .: "url"+ <*> v .: "description"+ <*> (toUTCTime <$> (v .: "created"))+ <*> v .: "name"+ <*> v .: "username"+ <*> v .: "num_sounds"+ <*> v .: "sounds"+ <*> v .: "num_downloads"+ parseJSON v = typeMismatch "Pack" v
src/Sound/Freesound/Search.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP, OverloadedStrings #-} module Sound.Freesound.Search ( SortMethod(..) , SortDirection(..)@@ -9,15 +9,27 @@ , module Sound.Freesound.Search.Filter , module Sound.Freesound.Search.Numerical , module Sound.Freesound.Search.Query+ , search+ , search_ ) where import qualified Data.ByteString.Char8 as BS-import Data.Default (Default(..))-import Network.HTTP.Types.QueryLike (QueryLike(..), QueryValueLike(..))+import Data.Default (Default) import Sound.Freesound.Search.Filter import Sound.Freesound.Search.Numerical import Sound.Freesound.Search.Query+import qualified Data.ByteString as B+import Data.Default (def)+import qualified Data.Text as T+import Network.HTTP.Types.QueryLike (QueryLike(..), QueryValueLike(..))+import Sound.Freesound.List (List)+import Sound.Freesound.Sound.Type+import Sound.Freesound.API (Freesound, get, resourceURI) +#if __GLASGOW_HASKELL__ < 710+import Control.Applicative+#endif+ data SortMethod = Duration | Created | Downloads | Rating deriving (Eq, Show) data SortDirection = Ascending | Descending deriving (Eq, Show) data Sorting = Unsorted | SortedBy SortMethod SortDirection deriving (Eq, Show)@@ -44,7 +56,7 @@ data Pagination = Pagination { page :: Int-, resultsPerPage :: Int+, pageSize :: Int } deriving (Eq, Show) instance Default Pagination where@@ -53,7 +65,23 @@ instance QueryLike Pagination where toQuery a = toQuery [ if page def == page a then Nothing- else Just (BS.pack "p", show (page a + 1))- , if resultsPerPage def == resultsPerPage a+ else Just (BS.pack "page", show (page a + 1))+ , if pageSize def == pageSize a then Nothing- else Just (BS.pack "sounds_per_page", show (resultsPerPage a)) ]+ else Just (BS.pack "page_size", show (pageSize a)) ]++search :: Pagination -> Sorting -> Filters -> Query -> Freesound (List Summary)+search p s fs q =+ get+ $ resourceURI+ [ "search", "text" ]+ (toQuery p ++ toQuery [ pair "query" q+ , pair "filter" fs+ , pair "sort" s ])+ -- TODO: group_by_pack (changes response type)+ where+ pair :: QueryValueLike a => T.Text -> a -> Maybe (T.Text, B.ByteString)+ pair k a = (,) <$> pure k <*> toQueryValue a++search_ :: Query -> Freesound (List Summary)+search_ = search def def def
src/Sound/Freesound/Search/Query.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} module Sound.Freesound.Search.Query ( Query , include@@ -5,23 +6,40 @@ , (&) ) where -import Data.Char (isSpace)-import Data.Text (Text)-import qualified Data.Text as Text-import Network.HTTP.Types.QueryLike (QueryValueLike(..))+import Data.Char (isSpace)+import Data.Default (Default(..))+import Data.String (IsString(..))+import Data.Text (Text)+import qualified Data.Text as T+import Network.HTTP.Types.QueryLike (QueryValueLike(..)) +#if __GLASGOW_HASKELL__ < 710+import Data.Monoid+#endif++data Term = Include Text | Exclude Text deriving (Eq, Show)+ newtype Query = Query [Term] deriving (Eq, Show) +instance Monoid Query where+ mempty = Query []+ mappend (Query xs) (Query ys) = Query (xs ++ ys)++instance Default Query where+ def = mempty++instance IsString Query where+ fromString [] = mempty+ fromString s = include (T.pack s)+ instance QueryValueLike Query where- toQueryValue (Query ts) = toQueryValue $ Text.unwords (map f ts)+ toQueryValue (Query ts) = toQueryValue $ T.unwords (map f ts) where quote t- | Text.any isSpace t = Text.cons '"' (Text.snoc t '"')+ | T.any isSpace t = T.cons '"' (T.snoc t '"') | otherwise = t- f (Include t) = Text.cons '+' (quote t)- f (Exclude t) = Text.cons '-' (quote t)--data Term = Include Text | Exclude Text deriving (Eq, Show)+ f (Include t) = T.cons '+' (quote t)+ f (Exclude t) = T.cons '-' (quote t) include :: Text -> Query include string = Query [Include string]@@ -29,8 +47,5 @@ exclude :: Text -> Query exclude string = Query [Exclude string] -append :: Query -> Query -> Query-append (Query xs) (Query ys) = Query (xs ++ ys)- (&) :: Query -> Query -> Query-(&) = append+(&) = mappend
src/Sound/Freesound/Sound.hs view
@@ -1,11 +1,11 @@ {-# LANGUAGE CPP, OverloadedStrings #-} module Sound.Freesound.Sound (- SoundId+ SoundId(..) , FileType(..)+ , GeoTag(..) , Sound(..) , Summary , Detail- , Sounds , url , description , geotag@@ -35,51 +35,18 @@ -- , analysis , analysisStats , analysisFrames-- , search- , search_- , getSimilar- , getSimilar_+ , soundById+ , soundDetail ) where -import Data.Default (def) import qualified Data.Text as T-import Network.HTTP.Types.QueryLike (toQuery, toQueryValue)-import Sound.Freesound.List (List)-import Sound.Freesound.Search (Filters, Pagination, Query, Sorting)-import Sound.Freesound.Sound.Type-import Sound.Freesound.API (Freesound, appendQuery, getResource, resourceURI)--#if __GLASGOW_HASKELL__ < 710-import Control.Applicative-#endif--type Sounds = List Summary--search :: Pagination -> Sorting -> Filters -> Query -> Freesound Sounds-search p s fs q =- getResource- $ resourceURI- [ "search", "text" ]- (toQuery p ++ toQuery [ ("q"::T.Text, toQueryValue q)- , ("f", toQueryValue fs)- , ("s", toQueryValue s) ])--search_ :: Query -> Freesound Sounds-search_ = search def def def---- | Search for sounds in a certain coordinate region.--- geotagged :: ...---- | Content based search.--- contentSearch :: ...---- Missing: distance field in the response-getSimilar :: Pagination -> Detail -> Freesound Sounds-getSimilar p = getResource . appendQuery p . similarSounds+import Sound.Freesound.API (Freesound, get, resourceURI)+import Sound.Freesound.Sound.Type as Sound -getSimilar_ :: Detail -> Freesound Sounds-getSimilar_ = getSimilar def+-- | Get a sound by id.+soundById :: SoundId -> Freesound Detail+soundById (SoundId i) = get $ resourceURI ["sounds", T.pack (show i)] [] --- getAnalysisStats--- getAnalysisFrames+-- | Get detailed sound information from its summary.+soundDetail :: Summary -> Freesound Detail+soundDetail = soundById . Sound.id
src/Sound/Freesound/Sound/Type.hs view
@@ -2,25 +2,27 @@ module Sound.Freesound.Sound.Type where import Control.Monad (mzero)-import Data.Aeson (FromJSON(..), Value(..), (.:), (.:?))+import Data.Aeson (FromJSON(..), Value(..), (.:), (.:?), decodeStrict) import qualified Data.ByteString.Char8 as BS import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.Encoding as T import Network.HTTP.Types.QueryLike (QueryValueLike(..)) import Prelude hiding (id) import Sound.Freesound.API (Resource, URI)-import Sound.Freesound.List (List, Elem(..))+import Sound.Freesound.Comment (Comment)+import Sound.Freesound.List (List)+import Sound.Freesound.Pack.Type (Pack)+import Sound.Freesound.Time -- import qualified Sound.Freesound.User.Type as User #if __GLASGOW_HASKELL__ < 710 import Control.Applicative #endif -newtype SoundId = SoundId Integer+newtype SoundId = SoundId { soundIdToInteger :: Integer } deriving (Eq, Ord, Show) -soundIdToInteger :: SoundId -> Integer-soundIdToInteger (SoundId i) = i- instance FromJSON SoundId where parseJSON (Number i) = return $ SoundId (truncate i) parseJSON _ = mzero@@ -111,35 +113,35 @@ parseJSON _ = fail "Couldn't parse Images" data Detail = Detail {- sound_id :: SoundId -- ^ The sound’s unique identifier.- , url :: URI -- ^ The URI for this sound on the Freesound website.- , sound_name :: Text -- ^ The name user gave to the sound.- , sound_tags :: [Text] -- ^ An array of tags the user gave to the sound.- , description :: Text -- ^ The description the user gave to the sound.- , geotag :: Maybe GeoTag -- ^ Latitude and longitude of the geotag (only for sounds that have been geotagged).- , created :: Text -- ^ The date of when the sound was uploaded.- , sound_license :: License -- ^ The license under which the sound is available to you.- , fileType :: FileType -- ^ The type of sound (wav, aif, mp3, etc.).- , channels :: Int -- ^ The number of channels.- , filesize :: Integer -- ^ The size of the file in bytes.- , bitrate :: Int -- ^ The bit rate of the sound.- , bitdepth :: Int -- ^ The bit depth of the sound.- , duration :: Double -- ^ The duration of the sound in seconds.- , samplerate :: Int -- ^ The samplerate of the sound.- , sound_username :: Text -- ^ The username of the uploader of the sound.- , pack :: Maybe (Resource ()) -- ^ If the sound is part of a pack, this URI points to that pack’s API resource.- , download :: URI -- ^ The URI for retrieving the original sound.- , bookmark :: URI -- ^ The URI for bookmarking the sound.- , previews :: Previews -- ^ Dictionary containing the URIs for mp3 and ogg versions of the sound. The dictionary includes the fields preview-hq-mp3 and preview-lq-mp3 (for ~128kbps quality and ~64kbps quality mp3 respectively), and preview-hq-ogg and preview-lq-ogg (for ~192kbps quality and ~80kbps quality ogg respectively).- , images :: Images -- ^ Dictionary including the URIs for spectrogram and waveform visualizations of the sound. The dinctionary includes the fields waveform_l and waveform_m (for large and medium waveform images respectively), and spectral_l and spectral_m (for large and medium spectrogram images respectively).- , numDownloads :: Integer -- ^ The number of times the sound was downloaded.- , avgRating :: Double -- ^ The average rating of the sound.- , numRatings :: Integer -- ^ The number of times the sound was rated.- , rate :: URI -- ^ The URI for rating the sound.- , comments :: Resource () -- ^ The URI of a paginated list of the comments of the sound.- , numComments :: Integer -- ^ The number of comments.- , comment :: URI -- ^ The URI to comment the sound.- , similarSounds :: Resource (List Summary) -- ^ URI pointing to the similarity resource (to get a list of similar sounds).+ sound_id :: SoundId -- ^ The sound’s unique identifier.+ , url :: URI -- ^ The URI for this sound on the Freesound website.+ , sound_name :: Text -- ^ The name user gave to the sound.+ , sound_tags :: [Text] -- ^ An array of tags the user gave to the sound.+ , description :: Text -- ^ The description the user gave to the sound.+ , geotag :: Maybe GeoTag -- ^ Latitude and longitude of the geotag (only for sounds that have been geotagged).+ , created :: UTCTime -- ^ The date of when the sound was uploaded.+ , sound_license :: License -- ^ The license under which the sound is available to you.+ , fileType :: FileType -- ^ The type of sound (wav, aif, mp3, etc.).+ , channels :: Int -- ^ The number of channels.+ , filesize :: Integer -- ^ The size of the file in bytes.+ , bitrate :: Int -- ^ The bit rate of the sound.+ , bitdepth :: Int -- ^ The bit depth of the sound.+ , duration :: Double -- ^ The duration of the sound in seconds.+ , samplerate :: Int -- ^ The samplerate of the sound.+ , sound_username :: Text -- ^ The username of the uploader of the sound.+ , pack :: Maybe (Resource Pack) -- ^ If the sound is part of a pack, this URI points to that pack’s API resource.+ , download :: URI -- ^ The URI for retrieving the original sound.+ , bookmark :: URI -- ^ The URI for bookmarking the sound.+ , previews :: Previews -- ^ Dictionary containing the URIs for mp3 and ogg versions of the sound. The dictionary includes the fields preview-hq-mp3 and preview-lq-mp3 (for ~128kbps quality and ~64kbps quality mp3 respectively), and preview-hq-ogg and preview-lq-ogg (for ~192kbps quality and ~80kbps quality ogg respectively).+ , images :: Images -- ^ Dictionary including the URIs for spectrogram and waveform visualizations of the sound. The dinctionary includes the fields waveform_l and waveform_m (for large and medium waveform images respectively), and spectral_l and spectral_m (for large and medium spectrogram images respectively).+ , numDownloads :: Integer -- ^ The number of times the sound was downloaded.+ , avgRating :: Double -- ^ The average rating of the sound.+ , numRatings :: Integer -- ^ The number of times the sound was rated.+ , rate :: URI -- ^ The URI for rating the sound.+ , comments :: Resource (List Comment) -- ^ The URI of a paginated list of the comments of the sound.+ , numComments :: Integer -- ^ The number of comments.+ , comment :: URI -- ^ The URI to comment the sound.+ , similarSounds :: Resource (List Summary) -- ^ URI pointing to the similarity resource (to get a list of similar sounds). -- , analysis :: Maybe , analysisStats :: Resource () -- ^ URI pointing to the complete analysis results of the sound. , analysisFrames :: Resource () -- ^ The URI for retrieving a JSON file with analysis information for each frame of the sound.@@ -154,7 +156,7 @@ <*> v .: "tags" <*> v .: "description" <*> v .:? "geotag"- <*> v .: "created"+ <*> (toUTCTime <$> (v .: "created")) <*> v .: "license" <*> v .: "type" <*> v .: "channels"@@ -213,9 +215,6 @@ username = summary_username license = summary_license -instance Elem Summary where- elemsFieldName _ = "sounds"- -- | Coordinate data GeoTag = GeoTag { latitude :: Double@@ -223,5 +222,9 @@ } deriving (Eq, Show) instance FromJSON GeoTag where- parseJSON (String _) = pure (GeoTag 0 0)+ parseJSON (String s) = do+ let coords = T.concat ["[", T.intercalate "," (T.splitOn " " s), "]"]+ case decodeStrict (T.encodeUtf8 coords) of+ Just [lat, lon] -> return $ GeoTag lat lon+ _ -> fail "Couldn't parse GeoTag" parseJSON _ = fail "Couldn't parse GeoTag"
+ src/Sound/Freesound/Time.hs view
@@ -0,0 +1,15 @@+module Sound.Freesound.Time (+ Time+ , toUTCTime+ , UTCTime+) where++import Data.Aeson+import qualified Data.Text as T+import Data.Time (UTCTime)++newtype Time = Time { toUTCTime :: UTCTime } deriving (Eq, Show)++instance FromJSON Time where+ parseJSON (String s) = Time `fmap` parseJSON (String (T.snoc s 'Z'))+ parseJSON _ = fail "Couldn't parse time"
src/Sound/Freesound/User.hs view
@@ -1,58 +1,72 @@+{-# LANGUAGE CPP, OverloadedStrings #-} module Sound.Freesound.User ( User(..)-, Summary-, Detail-, sounds-, packs-, firstName-, lastName-, about-, homePage-, signature-, dateJoined-, bookmarkCategories-, getUser+, Avatar(..) , getUserByName-, getBookmarkCategories-, getSounds-, getSounds_-, getPacks ) where -import Control.Monad (liftM)-import Data.Default (def)+import Control.Monad (join)+import Data.Aeson (FromJSON(..), Value(..), (.:), (.:?)) import Data.Text (Text)-import qualified Data.Text as T-import Sound.Freesound.API (Freesound, appendQuery, getResource, resourceURI)-import qualified Sound.Freesound.Bookmark as Bookmark-import qualified Sound.Freesound.Bookmark.Internal as Bookmark-import Sound.Freesound.Pack (Packs)-import Sound.Freesound.Search (Pagination)-import Sound.Freesound.Sound (Sounds)-import Sound.Freesound.User.Type---- | Get detailed information about a user.-getUser :: (User a) => a -> Freesound Detail-getUser = getResource . ref+import Sound.Freesound.API (Freesound, Resource, URI, get, resourceURI)+import Sound.Freesound.Bookmark (BookmarkCategory)+import Sound.Freesound.List (List)+import Sound.Freesound.Pack (Pack)+import qualified Sound.Freesound.Sound as Sound+import Sound.Freesound.Time --- | Get information about a user by name.-getUserByName :: Text -> Freesound Detail-getUserByName t = getResource $ resourceURI [ T.pack "people", t ] []+#if __GLASGOW_HASKELL__ < 710+import Control.Applicative+#endif --- | Retrieve a list of a user's bookmark categories.-getBookmarkCategories :: Detail -> Freesound [Bookmark.Category]-getBookmarkCategories = liftM Bookmark.categories . getResource . bookmarkCategories+data Avatar = Avatar {+ small :: URI+ , medium :: URI+ , large :: URI+ } deriving (Eq, Show) --- | Retrieve a user's sounds.--- This is broken: the response doesn't contain the User.-getSounds :: Pagination -> Detail -> Freesound Sounds-getSounds p = getResource . appendQuery p . sounds+instance FromJSON Avatar where+ parseJSON (Object v) =+ Avatar <$> v .: "small"+ <*> v .: "medium"+ <*> v .: "large"+ parseJSON _ = fail "Couldn't parse Avatar" --- | Retrieve a user's sounds.+-- | User of the Freesound database.+data User = User {+ url :: URI -- ^ The URI for this users' profile on the Freesound website.+ , username :: Text -- ^ The username.+ , about :: Maybe Text -- ^ The 'about' text of users' profile (if indicated).+ , homepage :: Maybe URI -- ^ The URI of users' homepage outside Freesound (if indicated).+ , avatar :: Maybe Avatar -- ^ The user's avatar image (if indicated).+ , dateJoined :: UTCTime -- ^ The date when the user joined Freesound.+ , numSounds :: Int -- ^ The number of sounds uploaded by the user.+ , sounds :: Resource (List Sound.Summary) -- ^ The API URI for this user’s sound collection.+ , numPacks :: Int -- ^ The number of packs by the user.+ , packs :: Resource (List Pack) -- ^ The API URI for this user’s pack collection.+ , numPosts :: Int -- ^ The number of forum posts by the user.+ , numComments :: Int -- ^ The number of comments that user made in other users' sounds.+ , bookmarkCategories :: Resource (List BookmarkCategory) -- ^ The URI for a list of bookmark categories by the user.+} deriving (Eq, Show) -getSounds_ :: Detail -> Freesound Sounds-getSounds_ = getSounds def+instance FromJSON User where+ parseJSON (Object v) =+ User+ <$> v .: "url"+ <*> v .: "username"+ <*> (join <$> (v .:? "about"))+ <*> (join <$> (v .:? "homepage"))+ <*> (join <$> (v .:? "avatar"))+ <*> (toUTCTime <$> (v .: "date_joined"))+ <*> v .: "num_sounds"+ <*> v .: "sounds"+ <*> v .: "num_packs"+ <*> v .: "packs"+ <*> v .: "num_posts"+ <*> v .: "num_comments"+ <*> v .: "bookmark_categories"+ parseJSON _ = fail "Couldn't parse User" --- | Retrieve a user's packs.-getPacks :: Detail -> Freesound Packs-getPacks = getResource . packs+-- | Get information about a user by name.+getUserByName :: Text -> Freesound User+getUserByName u = get $ resourceURI [ "users", u ] []
− src/Sound/Freesound/User/Type.hs
@@ -1,85 +0,0 @@-{-# LANGUAGE CPP, OverloadedStrings #-}-module Sound.Freesound.User.Type where--import Control.Monad (mzero)-import Data.Aeson (FromJSON(..), Value(..), (.:))-import Data.Text (Text)-import qualified Data.Text as T-import Sound.Freesound.API (Resource, URI)-import qualified Sound.Freesound.Bookmark.Internal as Bookmark-import Sound.Freesound.List (List)-import qualified Sound.Freesound.Pack.Type as Pack-import qualified Sound.Freesound.Sound.Type as Sound--#if __GLASGOW_HASKELL__ < 710-import Control.Applicative-#endif---- | User of the Freesound database.-class User a where- -- | The user’s username.- name :: a -> Text- -- | The URI for this resource.- ref :: a -> Resource Detail- -- | The profile page for the user on the Freesound website.- url :: a -> URI---- | User of the Freesound database.-data Summary = Summary {- user_name :: Text -- ^ The user’s username.-, user_ref :: Resource Detail -- ^ The URI for this resource.-, user_url :: URI -- ^ The profile page for the user on the Freesound website.-} deriving (Eq, Show)--instance User Summary where- name = user_name- ref = user_ref- url = user_url--instance FromJSON Summary where- parseJSON (Object v) =- Summary- <$> v .: "username"- <*> v .: "ref"- <*> v .: "url"- parseJSON _ = mzero--data Detail = Detail {- summary :: Summary -- ^ Summary.-, sounds :: Resource (List Sound.Summary) -- ^ The API URI for this user’s sound collection.-, packs :: Resource (List Pack.Summary) -- ^ The API URI for this user’s pack collection.-, firstName :: Maybe Text -- ^ The user’s first name, possibly empty.-, lastName :: Maybe Text -- ^ The user’s last name, possibly empty.-, about :: Maybe Text -- ^ A small text the user wrote about himself.--- FIXME: homePage :: Maybe Data-, homePage :: Maybe Text -- ^ The user’s homepage, possibly empty.-, signature :: Maybe Text -- ^ The user’s signature, possibly empty.-, dateJoined :: Text -- ^ The date the user joined Freesound.-, bookmarkCategories :: Resource Bookmark.Categories-} deriving (Eq, Show)--instance User Detail where- name = name . summary- ref = ref . summary- url = url . summary--textToMaybe :: Maybe Text -> Maybe Text-textToMaybe Nothing = Nothing-textToMaybe (Just s)- | T.null s = Nothing- | otherwise = Just s--instance FromJSON Detail where- parseJSON j@(Object v) =- Detail- <$> parseJSON j- <*> v .: "sounds"- <*> v .: "packs"- <*> (textToMaybe <$> (v .: "first_name"))- <*> (textToMaybe <$> (v .: "last_name"))- <*> (textToMaybe <$> (v .: "about"))- <*> (textToMaybe <$> (v .: "home_page"))- <*> (textToMaybe <$> (v .: "signature"))- <*> v .: "date_joined"- <*> v .: "bookmark_categories"- parseJSON _ = mzero
+ test/Sound/Freesound/SearchSpec.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE OverloadedStrings #-}+module Sound.Freesound.SearchSpec (spec) where++import Data.Default (def)+import Sound.Freesound+import Sound.Freesound.Search+import qualified Sound.Freesound.Sound as Sound+import Sound.Freesound.Test+import Test.Hspec++spec :: Spec+spec = do+ describe "search" $ do+ it "searches" $ do+ let p s = Sound.username s == "k0s"+ && Sound.name s == "Spiffy Spank"+ fs (anySatisfy p =<< search_ (include "spank")) `shouldReturn` True+ it "filters by user name" $ do+ let p s = Sound.username s == "k0s"+ fs (allSatisfy p =<< search def def (username "k0s") (include "spank")) `shouldReturn` True+ it "paginates" $ do+ l <- fs $ search (Pagination 0 1) def def ""+ length (elems l) `shouldBe` 1
+ test/Sound/Freesound/SoundSpec.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE CPP, OverloadedStrings #-}+module Sound.Freesound.SoundSpec (spec) where++import qualified Data.ByteString.Lazy as BL+import Data.List (find)+import Data.Maybe (fromJust)+import Sound.Freesound+import qualified Sound.Freesound.Comment as Comment+import qualified Sound.Freesound.Pack as Pack+import Sound.Freesound.Search+import qualified Sound.Freesound.Sound as Sound+import Sound.Freesound.Test+import Test.Hspec++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative+#endif++spiffySpankId :: Sound.SoundId+spiffySpankId = Sound.SoundId 167068++spiffySpank :: Freesound Sound.Detail+spiffySpank = Sound.soundById spiffySpankId++nokia_2600_warmup :: Freesound Sound.Detail+nokia_2600_warmup = Sound.soundById (Sound.SoundId 330864)++spec :: Spec+spec = do+ describe "Spiffy Spank" $ do+ it "can be retrieved by id" $ do+ s <- fs spiffySpank+ Sound.name s `shouldBe` "Spiffy Spank"+ it "has the correct creation date" $ do+ s <- fs spiffySpank+ Sound.created s `shouldBe` read "2012-10-10 15:24:33.328 UTC"+ it "has the correct file type" $ do+ s <- fs spiffySpank+ Sound.fileType s `shouldBe` Sound.WAV+ it "can be recovered from its summary" $ do+ Just info <- find (\s -> Sound.id s == spiffySpankId)+ <$> (fs $ getAll =<< search_ (include "Spiffy Spank"))+ (s, s') <- fs $ (,) <$> Sound.soundDetail info <*> spiffySpank+ s `shouldBe` s'+ it "has no geotag" $ do+ Sound.geotag <$> fs spiffySpank `shouldReturn` Nothing+ it "is not part of a pack" $ do+ Sound.pack <$> fs spiffySpank `shouldReturn` Nothing+ describe "nokia_2600_warmup" $ do+ it "has the correct geotag" $ do+ Sound.geotag <$> fs nokia_2600_warmup+ `shouldReturn` Just (Sound.GeoTag 41.4151829276 2.16533660889)+ it "is part of pack \"Nokia 2600\"" $ do+ r <- Sound.pack <$> fs nokia_2600_warmup+ r `shouldNotBe` Nothing+ p <- fs . get . fromJust $ r+ Pack.name p `shouldBe` "Nokia 2600"+ unlessCI $ do+ it "can be downloaded" $ do+ b <- fs $ download . Sound.download =<< nokia_2600_warmup+ b' <- BL.readFile "test/data/330864__k0s__nokia-2600-warmup.wav"+ b `shouldBe` b'+ describe "Nokia_2600_Silence.wav" $ do+ it "should have a lovely comment" $ do+ s <- fs . Sound.soundById $ Sound.SoundId 231519+ l <- fs . get . Sound.comments $ s+ let c = Comment.Comment {+ Comment.username = "toiletrolltube"+ , Comment.comment = "I love this sort of stuff, very useful indeed thanks."+ , Comment.created = read "2014-03-29 03:15:55.948 UTC" }+ fs (anySatisfy (==c) l) `shouldReturn` True
test/Sound/Freesound/Test.hs view
@@ -1,9 +1,52 @@ module Sound.Freesound.Test (- fs+ fs+ , anySatisfy+ , allSatisfy+ , getAll+ , unlessCI ) where +import Data.Aeson (FromJSON) import Sound.Freesound-import System.Environment (getEnv)+import qualified Sound.Freesound.List as L+import System.Environment (getEnv, lookupEnv)+import Test.Hspec.Core.Spec fs :: Freesound a -> IO a fs a = flip runFreesound a =<< apiKeyFromString `fmap` getEnv "FREESOUND_API_KEY"++anySatisfy :: (FromJSON a) => (a -> Bool) -> List a -> Freesound Bool+anySatisfy p l = do+ if any p (elems l)+ then return True+ else do+ n <- getNext l+ case n of+ Nothing -> return False+ Just l' -> anySatisfy p l'++allSatisfy :: (FromJSON a) => (a -> Bool) -> List a -> Freesound Bool+allSatisfy p l = do+ if all p (elems l)+ then do+ n <- getNext l+ case n of+ Nothing -> return True+ Just l' -> allSatisfy p l'+ else return False++getAll :: (FromJSON a) => List a -> Freesound [a]+getAll l =+ case L.next l of+ Nothing -> return $ L.elems l+ Just n -> do+ xs <- getAll =<< get n+ return $ L.elems l ++ xs++-- | Emit spec only when _not_ running on the CI server.+unlessCI :: SpecWith () -> SpecWith ()+unlessCI action = do+ e <- runIO $ lookupEnv "CI"+ case e of+ Nothing -> action+ _ -> return ()
+ test/Sound/Freesound/UserSpec.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE CPP, OverloadedStrings #-}+module Sound.Freesound.UserSpec (spec) where++import Data.Default (def)+import Data.List (find)+import Data.Maybe (fromJust)+import qualified Data.Set as Set+import Sound.Freesound+import qualified Sound.Freesound.Bookmark as Bookmark+import qualified Sound.Freesound.Pack as Pack+import Sound.Freesound.Search+import qualified Sound.Freesound.Sound as Sound+import qualified Sound.Freesound.User as User+import Sound.Freesound.Test+import Test.Hspec++#if __GLASGOW_HASKELL__ < 710+import Control.Applicative+#endif++k0s :: Freesound User.User+k0s = User.getUserByName "k0s"++spec :: Spec+spec = do+ describe "k0s" $ do+ it "can be retrieved by name" $ do+ u <- fs k0s+ User.username u `shouldBe` "k0s"+ it "has the correct date" $ do+ u <- fs k0s+ User.dateJoined u `shouldBe` read "2007-02-02 17:32:34 UTC"+ it "has the correct number of sounds" $ do+ u <- fs k0s+ sounds <- fs $ get $ User.sounds u+ numElems sounds `shouldBe` User.numSounds u+ it "has the correct set of sounds" $ do+ sounds <- fs $ getAll =<< get . User.sounds =<< k0s+ sounds' <- fs $ getAll =<< search def def (username "k0s") def+ Set.fromList (map Sound.id sounds) `shouldBe` Set.fromList (map Sound.id sounds')+ it "has a pack called \"Nokia 2600\" containing 2 sounds" $ do+ u <- fs k0s+ l <- fs . get . User.packs $ u+ numElems l `shouldSatisfy` (>=1)+ r <- fs $ find (\p -> Pack.name p == "Nokia 2600") <$> getAll l+ r `shouldNotBe` Nothing+ let p = fromJust r+ Pack.numSounds p `shouldBe` 2+ Pack.username p `shouldBe` User.username u+ sounds <- fs . get . Pack.sounds $ p+ numElems sounds `shouldBe` 2+ length (elems sounds) `shouldBe` 2+ it "has haskell-freesound bookmark category" $ do+ l <- fs $ get . User.bookmarkCategories =<< k0s+ -- More than one category+ numElems l `shouldSatisfy` (>=1)+ -- Test bookmark category+ b <- fs $ find (\b -> Bookmark.name b == "haskell-freesound-tests") <$> getAll l+ b `shouldNotBe` Nothing+ -- Number of sounds in category+ Bookmark.numSounds (fromJust b) `shouldBe` 1+ sounds <- fs . get . Bookmark.sounds . fromJust $ b+ numElems sounds `shouldBe` 1+ -- Correct sound in category+ elems sounds `shouldSatisfy` (not.null)+ Sound.id (head (elems sounds)) `shouldBe` Sound.SoundId 250719