import re from apollo_utils.core.constants.dsp import DSP from apollo_utils.core.constants.market import Market from apollo_utils.service.schemas.fields.enum import EnumListField, SplitUniqueListField from apollo_utils.service.schemas.fields.isrc import IsrcExtendedField from apollo_utils.service.schemas.fields.market import MarketField from marshmallow import ValidationError, fields, post_load, validate from server.constants.distributors import DISTRIBUTORS from server.schemas.base.nullable import IntOrNull from server.schemas.base.pagination import PaginationResultMixin, get_pagination_mixin from server.schemas.base.schemas import RequestSchema, Schema def validate_uri(uri: str): if not (re.compile(r"^spotify:track:\d{1}\w{21}$").match(uri) or re.compile(r"^\d{9,10}$").match(uri)): raise ValidationError(f"Broken URI {uri}") class UserFavoritesTrackV0Mixin: uri = fields.Str(validate=validate_uri, required=True) isrc = IsrcExtendedField(required=True) class UserFavoritesTrackV0ResponseMixin: code = fields.Str() status = fields.Str() detail = fields.Str() count = fields.Int() class UserFavoritesTracksV0: class Get: class Response(UserFavoritesTrackV0Mixin, Schema): favorites_id = fields.Int() class Delete: class Request(RequestSchema): isrc = IsrcExtendedField(required=True) class Response(UserFavoritesTrackV0ResponseMixin, Schema): pass class Create: class Request(UserFavoritesTrackV0Mixin, RequestSchema): @post_load def parse_uri(self, data, **kwargs): uri = data["uri"] uri_parts = uri.split(":") try: if uri_parts[0] == DSP.SPOTIFY.value: dsp = DSP.SPOTIFY.value track_id = uri_parts[2] country_code = "global" else: dsp = DSP.APPLE.value track_id = int(uri_parts[0]) country_code = "us" except (IndexError, ValueError): raise ValidationError(f"Broken URI {uri}") data.update({"dsp": dsp, "track_id": track_id, "country_code": country_code}) return data class Response(UserFavoritesTrackV0ResponseMixin, Schema): favorites_id = fields.Int() class UserFavoritesTracksV0Check: class Request(RequestSchema): isrc = SplitUniqueListField(IsrcExtendedField(required=True), validate=validate.Length(min=1, max=100)) class UsersFavoritesTrackV0sDetailed: class Request(RequestSchema, get_pagination_mixin(page_limit=10, max_limit=500)): market = MarketField(validate=validate.Length(max=10, min=2), gl=Market.GLOBAL, missing=Market.GLOBAL) class Response(Schema, PaginationResultMixin): class Item(Schema): favorites_id = fields.Integer() id = fields.Str() uri = fields.Str() vendor = fields.Str() isrc = fields.Str() created_at = fields.Str() streams = fields.Integer(default=0, missing=0) streams_7days_change = fields.Integer(default=0, missing=0) streams_7days_change_rate = fields.Integer(default=0, missing=0) extra_data = fields.Raw() available = fields.Bool() items = fields.List(fields.Nested(Item())) class UsersFavoritesTracksDetailed: class Request(UsersFavoritesTrackV0sDetailed.Request): distributors = EnumListField(DISTRIBUTORS, unify=True, missing=[DISTRIBUTORS.SME], as_enum=True) tag_id = SplitUniqueListField(IntOrNull(allow_none=True, null_to="null")) class Response(Schema, PaginationResultMixin): class Item(UsersFavoritesTrackV0sDetailed.Response.Item): tt_creations_7days_change = fields.Integer(default=0, missing=0) tt_creations_7days_change_rate = fields.Integer(default=0, missing=0) distributed_by = fields.String(default=None) tag_id = fields.Integer(default=None) items = fields.List(fields.Nested(Item()))