module Utils.Spoty.Types where
import Control.Applicative ((<$>), (<*>))
import Control.Lens (makeFields)
import Control.Monad (MonadPlus(..), mzero)
import Data.Aeson
import Data.Aeson.Types (Parser)
import qualified Data.HashMap.Strict as HM
import qualified Data.Text as T
type URL = T.Text
type SpotID = T.Text
type SpotURI = T.Text
require :: FromJSON a => T.Text -> HM.HashMap T.Text Value -> Parser (Maybe a)
require str obj =
if HM.member str obj
then fmap Just (parseJSON$ Object obj)
else return Nothing
parseStrMap :: MonadPlus m => HM.HashMap k Value -> (k -> T.Text -> a) -> m [a]
parseStrMap vals constr = sequence . flip map (HM.toList vals) $ \e ->
case e of
(key, String val) -> return $constr key val
_ -> mzero
data ExternalID
= ExternalID
{
_idType :: T.Text,
_idIdentifier :: T.Text
}
deriving (Eq, Ord, Show)
makeFields ''ExternalID
instance FromJSON [ExternalID] where
parseJSON (Object v) = parseStrMap v ExternalID
parseJSON _ = mzero
data ExternalURL
= ExternalURL
{
_urlType :: T.Text,
_url :: URL
}
deriving (Eq, Ord, Show)
makeFields ''ExternalURL
instance FromJSON [ExternalURL] where
parseJSON (Object v) = parseStrMap v ExternalURL
parseJSON _ = mzero
data Image
= Image
{
_imageHeight :: Maybe Int,
_imagePath :: URL,
_imageWidth :: Maybe Int
}
deriving (Eq, Ord, Show)
makeFields ''Image
instance FromJSON Image where
parseJSON (Object v) = Image <$>
v .:? "height" <*>
v .: "url" <*>
v .:? "width"
parseJSON _ = mzero
data Paging a
= Paging
{
_pagingHref :: T.Text,
_pagingItems :: [a],
_pagingLimit :: Int,
_pagingNext :: Maybe URL,
_pagingOffset :: Int,
_pagingPrevious :: Maybe URL,
_pagingTotal :: Int
}
deriving (Eq, Ord, Show)
makeFields ''Paging
instance FromJSON a => FromJSON (Paging a) where
parseJSON (Object v) = Paging <$>
v .: "href" <*>
v .: "items" <*>
v .: "limit" <*>
v .:? "next" <*>
v .: "offset" <*>
v .:? "previous" <*>
v .: "total"
parseJSON _ = mzero
data User
= User
{
_userExternalUrls :: [ExternalURL],
_userHref :: URL,
_userSpotifyID :: SpotID,
_userSpotifyURI :: SpotURI
}
deriving (Eq, Ord, Show)
makeFields ''User
instance FromJSON User where
parseJSON (Object v) = User <$>
v .: "external_urls" <*>
v .: "href" <*>
v .: "id" <*>
v .: "uri"
parseJSON _ = mzero
data ArtistDetails
= ArtistDetails
{
_artistGenres :: [T.Text],
_artistImages :: [Image],
_artistPopularity :: Int
}
deriving (Eq, Ord, Show)
makeFields ''ArtistDetails
instance FromJSON ArtistDetails where
parseJSON (Object v) = ArtistDetails <$>
v .: "genres" <*>
v .: "images" <*>
v .: "popularity"
parseJSON _ = mzero
data Artist
= Artist
{
_artistExternalUrls :: [ExternalURL],
_artistHref :: URL,
_artistSpotifyID :: SpotID,
_artistName :: T.Text,
_artistSpotifyURI :: SpotURI,
_artistDetails :: Maybe ArtistDetails
}
deriving (Eq, Ord, Show)
makeFields ''Artist
instance FromJSON Artist where
parseJSON (Object v) = Artist <$>
v .: "external_urls" <*>
v .: "href" <*>
v .: "id" <*>
v .: "name" <*>
v .: "uri" <*>
require "genres" v
parseJSON _ = mzero
data TrackDetails
= TrackDetails
{
_trackAvailableMarkets :: [T.Text],
_trackExternalIDs :: [ExternalID],
_trackPopularity :: Int
}
deriving (Eq, Ord, Show)
makeFields ''TrackDetails
instance FromJSON TrackDetails where
parseJSON (Object v) = TrackDetails <$>
v .: "available_markets" <*>
v .: "external_ids" <*>
v .: "popularity"
parseJSON _ = mzero
data Track
= Track
{
_trackArtists :: [Artist],
_trackDiscNumber :: Int,
_trackDurationMs :: Int,
_trackExplicit :: Bool,
_trackExternalUrls :: [ExternalURL],
_trackHref :: URL,
_trackSpotifyID :: SpotID,
_trackName :: T.Text,
_trackPreviewURL :: URL,
_trackNumber :: Int,
_trackSpotifyURI :: SpotURI,
_trackDetails :: Maybe TrackDetails
}
deriving (Eq, Ord, Show)
makeFields ''Track
instance FromJSON Track where
parseJSON (Object v) = Track <$>
v .: "artists" <*>
v .: "disc_number" <*>
v .: "duration_ms" <*>
v .: "explicit" <*>
v .: "external_urls" <*>
v .: "href" <*>
v .: "id" <*>
v .: "name" <*>
v .: "preview_url" <*>
v .: "track_number" <*>
v .: "uri" <*>
require "available_markets" v
parseJSON _ = mzero
data AlbumDetails
= AlbumDetails
{
_albumArtists :: [Artist],
_albumExternalIDs :: [ExternalID],
_albumGenres :: [T.Text],
_albumPopularity :: Int,
_albumReleaseDate :: T.Text,
_albumReleaseDatePrecision :: T.Text,
_albumTracks :: Paging Track
}
deriving (Eq, Ord, Show)
makeFields ''AlbumDetails
instance FromJSON AlbumDetails where
parseJSON (Object v) = AlbumDetails <$>
v .: "artists" <*>
v .: "external_ids" <*>
v .: "genres" <*>
v .: "popularity" <*>
v .: "release_date" <*>
v .: "release_date_precision" <*>
v .: "tracks"
parseJSON _ = mzero
data Album
= Album
{
_albumType :: T.Text,
_albumAvailableMarkets :: [T.Text],
_albumExternalURLs :: [ExternalURL],
_albumHref :: T.Text,
_albumSpotifyID :: SpotID,
_albumImages :: [Image],
_albumName :: T.Text,
_albumSpotifyURI :: SpotURI,
_albumDetails :: Maybe AlbumDetails
}
deriving (Eq, Ord, Show)
makeFields ''Album
instance FromJSON Album where
parseJSON (Object v) = Album <$>
v .: "album_type" <*>
v .: "available_markets" <*>
v .: "external_urls" <*>
v .: "href" <*>
v .: "id" <*>
v .: "images" <*>
v .: "name" <*>
v .: "uri" <*>
require "artists" v
parseJSON _ = mzero