from marshmallow import Schema, fields, validate from marshmallow.validate import Range, OneOf, Length from server.core.schemas import BaseSchema, BaseSchemaV4, GenreSchema, CountrySchema from server.dna.constants import ARTIST from server.artist.constants import COUNTRIES_LIST_SLUG_NAME from server.track.constants import GENRES_LIST_SLUG_NAME # Response Schemas ===================================================================================================== class TikTokArtistDiscoveryBaseResponseSchema(Schema): label = fields.String() code2 = fields.String() tiktok_user = fields.Integer() followers = fields.Integer() likes = fields.Integer() videos = fields.Integer() id = fields.String(attribute="user_id") user_name = fields.String() avg_duration = fields.Decimal(2, as_string=True) mentions = fields.Integer() followers_change = fields.Integer() # TODO: All date fields should be converted via Date field latest_release_date = fields.String() class TikTokArtistDiscoveryResultsResponseSchema(TikTokArtistDiscoveryBaseResponseSchema): followers_chart = fields.List(fields.Integer()) likes_chart = fields.List(fields.Integer()) last_chart_date = fields.String() class TikTokArtistDiscoveryResponseSchema(TikTokArtistDiscoveryBaseResponseSchema): chart_data = fields.List(fields.Integer()) chart_type = fields.String(validate=OneOf(["FOLLOWERS", "LIKES"])) class YoutubeArtistDiscoveryBaseResponseSchema(Schema): channel_id = fields.String() views = fields.Integer() videos = fields.Integer() subscribers = fields.Integer() comments = fields.Integer() avg_duration = fields.Decimal(2, as_string=True) subscribers_change = fields.Integer() # TODO: All date fields should be converted via Date field latest_release_date = fields.String() class YoutubeArtistDiscoveryResponseSchema(YoutubeArtistDiscoveryBaseResponseSchema): chart_data = fields.List(fields.Integer()) chart_type = fields.String(validate=OneOf(["SUBSCRIBERS", "VIEWS"])) class YoutubeArtistDiscoveryResultsResponseSchema(YoutubeArtistDiscoveryBaseResponseSchema): subscribers_chart = fields.List(fields.Integer()) views_chart = fields.List(fields.Integer()) last_chart_date = fields.String() class SpotifyArtistDiscoveryBaseResponseSchema(Schema): latest_release_date = fields.String() followers = fields.Integer() popularity = fields.Integer() listeners = fields.Integer() listeners_change = fields.Integer() tracks = fields.Integer() class SpotifyArtistDiscoveryResponseSchema(SpotifyArtistDiscoveryBaseResponseSchema): chart_data = fields.List(fields.Integer()) chart_type = fields.String(validate=OneOf(["FOLLOWERS", "LISTENERS", "POPULARITY"])) class SpotifyArtistDiscoveryResultsResponseSchema(SpotifyArtistDiscoveryBaseResponseSchema): followers_chart = fields.List(fields.Integer()) listeners_chart = fields.List(fields.Integer()) popularity_chart = fields.List(fields.Integer()) last_chart_date = fields.String() class SoundCloudArtistDiscoveryBaseResponseSchema(Schema): latest_release_date = fields.String() followers = fields.Integer() followers_change = fields.Integer() plays = fields.Integer() tracks = fields.Integer() likes = fields.Integer() comments = fields.Integer() class SoundCloudArtistDiscoveryResponseSchema(SoundCloudArtistDiscoveryBaseResponseSchema): chart_data = fields.List(fields.Integer()) chart_type = fields.String(validate=OneOf(["FOLLOWERS", "PLAYS", "LIKES", "COMMENTS"])) class SoundCloudArtistDiscoveryResultsResponseSchema(SoundCloudArtistDiscoveryBaseResponseSchema): followers_chart = fields.List(fields.Integer()) comments_chart = fields.List(fields.Integer()) likes_chart = fields.List(fields.Integer()) plays_chart = fields.List(fields.Integer()) last_chart_date = fields.String() class ArtistDiscoveryResponseSchema(Schema): id = fields.String() name = fields.String() label = fields.String() image_url = fields.URL() artwork_url = fields.URL() artwork_url_alt = fields.URL() is_signed = fields.Boolean() country = fields.Nested(CountrySchema) genres = fields.List(fields.Nested(GenreSchema)) tiktok = fields.Nested(TikTokArtistDiscoveryResponseSchema) youtube = fields.Nested(YoutubeArtistDiscoveryResponseSchema) spotify = fields.Nested(SpotifyArtistDiscoveryResponseSchema) soundcloud = fields.Nested(SoundCloudArtistDiscoveryResponseSchema) class ArtistDiscoveryResultsResponseSchema(ArtistDiscoveryResponseSchema): tiktok = fields.Nested(TikTokArtistDiscoveryResultsResponseSchema) youtube = fields.Nested(YoutubeArtistDiscoveryResultsResponseSchema) spotify = fields.Nested(SpotifyArtistDiscoveryResultsResponseSchema) soundcloud = fields.Nested(SoundCloudArtistDiscoveryResultsResponseSchema) class ArtistSearchByNameDataResponseSchema(Schema): name = fields.String() artwork_url = fields.String() artwork_url_alt = fields.String() score = fields.Float() class ArtistSearchByNameResponseSchema(Schema): entity_id = fields.String() entity_type = fields.String(validate=OneOf([ARTIST])) data = fields.Nested(ArtistSearchByNameDataResponseSchema) class ArtistDiscoveryCountResponseSchema(Schema): total_count = fields.Integer() class SpotifyTracksResponseSchema(Schema): spotify_track_id = fields.String() cm_track_id = fields.Integer() release_date = fields.String() popularity = fields.Integer() class SoundCloudTracksResponseSchema(Schema): cm_track_id = fields.Integer() release_date = fields.String() soundcloud_id = fields.Integer() plays = fields.Integer() class SpotifyAlbumResponseSchema(Schema): artwork_url = fields.Url() release_date = fields.Date() class VideosTiktokResponseSchema(Schema): video_id = fields.String() username = fields.String() description = fields.String() views = fields.Integer() likes = fields.Integer() class VideosYoutubeResponseSchema(Schema): video_id = fields.String() title = fields.String() youtube_channel_id = fields.String() views = fields.Integer() likes = fields.Integer() class ArtistServiceUrlResponseSchema(Schema): url = fields.Url() class ArtistServiceResponseSchema(Schema): name = fields.String() items = fields.List(fields.Nested(ArtistServiceUrlResponseSchema)) class ExternalLinksResponseSchema(Schema): group_name = fields.String() items = fields.List(fields.Nested(ArtistServiceResponseSchema)) class ArtistServiceResponseSchemaV4(Schema): name = fields.String() items = fields.List(fields.Nested(ArtistServiceUrlResponseSchema)) class TrackExternalLinksResponseSchemaV4(BaseSchemaV4): header = fields.List(fields.Nested(ArtistServiceResponseSchemaV4)) class ArtistExternalLinksResponseSchemaV4(TrackExternalLinksResponseSchemaV4): streaming_services = fields.List(fields.Nested(ArtistServiceResponseSchema)) social_media = fields.List(fields.Nested(ArtistServiceResponseSchema)) extra = fields.List(fields.Nested(ArtistServiceResponseSchema)) # TikTok Request Schemas =============================================================================================== class TikTokArtistDiscoveryCountRequestSchema(BaseSchema): min_followers = fields.Integer(allow_none=True) max_followers = fields.Integer(allow_none=True) min_videos = fields.Integer(allow_none=True) max_videos = fields.Integer(allow_none=True) min_avg_duration = fields.Integer(allow_none=True) max_avg_duration = fields.Integer(allow_none=True) min_mentions = fields.Integer(allow_none=True) max_mentions = fields.Integer(allow_none=True) min_likes = fields.Integer(allow_none=True) max_likes = fields.Integer(allow_none=True) min_latest_release_days = fields.TimeDelta(precision=fields.TimeDelta.DAYS, allow_none=True) chart_type = fields.String(load_default="FOLLOWERS", validate=OneOf(["FOLLOWERS", "LIKES"])) # Youtube Request Schemas ============================================================================================== class YouTubeArtistDiscoveryCountRequestSchema(BaseSchema): min_subscribers = fields.Integer(allow_none=True) max_subscribers = fields.Integer(allow_none=True) min_videos = fields.Integer(allow_none=True) max_videos = fields.Integer(allow_none=True) min_views = fields.Integer(allow_none=True) max_views = fields.Integer(allow_none=True) min_latest_release_days = fields.TimeDelta(precision=fields.TimeDelta.DAYS, allow_none=True) chart_type = fields.String(load_default="SUBSCRIBERS", validate=OneOf(["VIEWS", "SUBSCRIBERS"])) # Spotify Request Schemas ============================================================================================== class SpotifyArtistDiscoveryCountRequestSchema(BaseSchema): min_followers = fields.Integer(allow_none=True) max_followers = fields.Integer(allow_none=True) min_tracks = fields.Integer(allow_none=True) max_tracks = fields.Integer(allow_none=True) min_listeners = fields.Integer(allow_none=True) max_listeners = fields.Integer(allow_none=True) min_popularity = fields.Integer(allow_none=True) max_popularity = fields.Integer(allow_none=True) min_latest_release_days = fields.TimeDelta(precision=fields.TimeDelta.DAYS, allow_none=True) chart_type = fields.String(load_default="FOLLOWERS", validate=OneOf(["FOLLOWERS", "LISTENERS", "POPULARITY"])) # SoundCloud Request Schemas ========================================================================================== class SoundCloudArtistDiscoveryCountRequestSchema(BaseSchema): min_followers = fields.Integer(allow_none=True) max_followers = fields.Integer(allow_none=True) min_tracks = fields.Integer(allow_none=True) max_tracks = fields.Integer(allow_none=True) min_plays = fields.Integer(allow_none=True) max_plays = fields.Integer(allow_none=True) min_likes = fields.Integer(allow_none=True) max_likes = fields.Integer(allow_none=True) min_comments = fields.Integer(allow_none=True) max_comments = fields.Integer(allow_none=True) min_latest_release_days = fields.TimeDelta(precision=fields.TimeDelta.DAYS, allow_none=True) chart_type = fields.String(load_default="FOLLOWERS", validate=OneOf(["FOLLOWERS", "PLAYS", "LIKES", "COMMENTS"])) # Search Request Schemas =============================================================================================== class ArtistDiscoveryCountRequestSchema(BaseSchema): tiktok = fields.Nested(TikTokArtistDiscoveryCountRequestSchema) youtube = fields.Nested(YouTubeArtistDiscoveryCountRequestSchema) spotify = fields.Nested(SpotifyArtistDiscoveryCountRequestSchema) soundcloud = fields.Nested(SoundCloudArtistDiscoveryCountRequestSchema) countries = fields.List( fields.String(), allow_none=True, validate=[validate.Length(min=1), validate.ContainsOnly(COUNTRIES_LIST_SLUG_NAME)], ) genres = fields.List( fields.String(), allow_none=True, validate=[validate.Length(min=1), validate.ContainsOnly(GENRES_LIST_SLUG_NAME)], ) class ArtistDiscoveryRequestSchema(ArtistDiscoveryCountRequestSchema): limit = fields.Integer(validate=Range(min=1, max=100), load_default=100) offset = fields.Integer(validate=Range(min=0), load_default=0) class ArtistSearchByNameRequestSchema(BaseSchema): limit = fields.Integer(validate=Range(min=1, max=40), load_default=40) offset = fields.Integer(validate=Range(min=0, max=14), load_default=0) name = fields.String(validate=Length(min=1, max=255))