from server.constants import DEFAULT_IMAGE_SIZE, DSP def parse_apple_track_meta(track: dict, image_size: int = DEFAULT_IMAGE_SIZE) -> dict: """Original Apple API format -> unified format. Original format: { "id": "1633956893", "type": "songs", "href": "/v1/catalog/jp/songs/1633956893", "attributes": { "albumName": "Emotional Creature", "genreNames": [ "オルタナティブ", "ミュージック" ], "trackNumber": 1, "durationInMillis": 221000, "releaseDate": "2022-06-09", "isrc": "USQE92100257", "artwork": { "width": 3000, "height": 3000, "url": "https://is3-ssl.mzstatic.com/image/thumb/Music122/v4/47/49/f3/4749f340-ad43-3f73-7e06-24d3f1b27536/4580789485473.png/{w}x{h}bb.jpg", "bgColor": "202020", "textColor1": "aea6f6", "textColor2": "b68ef6", "textColor3": "918bcb", "textColor4": "9878cb" }, "composerName": "Lili Trifilio, Anthony Vaccaro, Jon Alvarado & Matt Henkels", "playParams": { "id": "1633956893", "kind": "song" }, "url": "https://music.apple.com/jp/album/entropy/1633956892?i=1633956893", "discNumber": 1, "hasLyrics": true, "isAppleDigitalMaster": true, "name": "Entropy", "previews": [ { "url": "https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview122/v4/8b/8a/b8/8b8ab889-334c-bdd9-6419-2d22aedd883b/mzaf_5194841074403978881.plus.aac.p.m4a" } ], "artistName": "Beach Bunny" }, "relationships": { "albums": { "href": "/v1/catalog/jp/songs/1633956893/albums", "data": [ { "id": "1633956892", "type": "albums", "href": "/v1/catalog/jp/albums/1633956892" } ] }, "artists": { "href": "/v1/catalog/jp/songs/1633956893/artists", "data": [ { "id": "1147783278", "type": "artists", "href": "/v1/catalog/jp/artists/1147783278" } ] } } } Unified result format: { "album_ids": [ "1633956892" ], "artists": [ { "id": "1147783278", "name": "Beach Bunny" } ], "id": "1615585008", "uri": "1615585008", "image": "https://is3-ssl.mzstatic.com/image/thumb/Music122/v4/47/49/f3/4749f340-ad43-3f73-7e06-24d3f1b27536/4580789485473.png/640x640bb.jpg", "isrc": "USQE92100257", "name": "Entropy", "release_date": "2022-06-09", "vendor": "apple" } """ track_attrs = track.get("attributes", {}) image_url = track_attrs.get("artwork", {}).get("url") if image_url and image_size: image_url = image_url.format(w=image_size, h=image_size) albums = track["relationships"].get("albums", {}).get("data", []) artists = track["relationships"].get("artists", {}).get("data", []) track_id = track.get("id") return { "id": track_id, "vendor": DSP.APPLE.value, "isrc": track_attrs.get("isrc"), "uri": track_id, "name": track_attrs.get("name"), "release_date": track_attrs.get("releaseDate"), "image": image_url, "album_ids": [a["id"] for a in albums], "artists": [ {"id": artist.get("id"), "uri": artist.get("id"), "name": artist.get("attributes", {}).get("name")} for artist in artists ], } def parse_spotify_track_meta(track: dict, image_size: int = DEFAULT_IMAGE_SIZE) -> dict: """Original Spotify API format -> unified format. Original format: { "album": { "album_type": "album", "total_tracks": 12, "available_markets": ["AR", "AU", ...] "external_urls": { "spotify": "https://open.spotify.com/album/0lw68yx3MhKflWFqCsGkIs" }, "href": "https://api.spotify.com/v1/albums/0lw68yx3MhKflWFqCsGkIs", "id": "0lw68yx3MhKflWFqCsGkIs", "images": [ { "url": "https://i.scdn.co/image/ab67616d0000b27328933b808bfb4cbbd0385400", "height": 640, "width": 640 }, { "url": "https://i.scdn.co/image/ab67616d00001e0228933b808bfb4cbbd0385400", "height": 300, "width": 300 }, { "url": "https://i.scdn.co/image/ab67616d0000485128933b808bfb4cbbd0385400", "height": 64, "width": 64 } ], "name": "Black Holes and Revelations", "release_date": "2006-06-19", "release_date_precision": "day", "type": "album", "uri": "spotify:album:0lw68yx3MhKflWFqCsGkIs", "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/12Chz98pHFMPJEknJQMWvI" }, "href": "https://api.spotify.com/v1/artists/12Chz98pHFMPJEknJQMWvI", "id": "12Chz98pHFMPJEknJQMWvI", "name": "Muse", "type": "artist", "uri": "spotify:artist:12Chz98pHFMPJEknJQMWvI" } ] }, "artists": [ { "external_urls": { "spotify": "https://open.spotify.com/artist/12Chz98pHFMPJEknJQMWvI" }, "href": "https://api.spotify.com/v1/artists/12Chz98pHFMPJEknJQMWvI", "id": "12Chz98pHFMPJEknJQMWvI", "name": "Muse", "type": "artist", "uri": "spotify:artist:12Chz98pHFMPJEknJQMWvI" } ], "available_markets": ["AR", "AU", ...], "disc_number": 1, "duration_ms": 366213, "explicit": false, "external_ids": { "isrc": "GBAHT0500600" }, "external_urls": { "spotify": "https://open.spotify.com/track/7ouMYWpwJ422jRcDASZB7P" }, "href": "https://api.spotify.com/v1/tracks/7ouMYWpwJ422jRcDASZB7P", "id": "7ouMYWpwJ422jRcDASZB7P", "name": "Knights of Cydonia", "popularity": 69, "preview_url": "https://p.scdn.co/mp3-preview/8196f1d0cb4c14a5a5bd1ab078c6893b30dab102?cid=b2e1273dc5b74aa8ac2ce522030bdb68", "track_number": 11, "type": "track", "uri": "spotify:track:7ouMYWpwJ422jRcDASZB7P", "is_local": false } Unified result format: { "album_ids": [ "0lw68yx3MhKflWFqCsGkIs" ], "artists": [ { "id": "12Chz98pHFMPJEknJQMWvI", "name": "Muse", "uri": "spotify:artist:12Chz98pHFMPJEknJQMWvI" } ], "id": "7ouMYWpwJ422jRcDASZB7P", "name": "Knights of Cydonia", "uri": "spotify:track:7ouMYWpwJ422jRcDASZB7P", "image": "https://i.scdn.co/image/ab67616d0000b27328933b808bfb4cbbd0385400", "isrc": "GBAHT0500600", "release_date": "2006-06-19", "vendor": "spotify" } """ return { "id": track.get("id"), "uri": track.get("uri"), "vendor": DSP.SPOTIFY.value, "isrc": track.get("external_ids", {}).get("isrc"), "name": track.get("name"), "release_date": track.get("album", {}).get("release_date"), "image": next( (image for image in track.get("album", {}).get("images", []) if image["height"] == image_size), {}, ).get("url"), "album_ids": [track.get("album", {}).get("id")], "artists": [ {"id": artist.get("id"), "name": artist.get("name"), "uri": artist.get("uri")} for artist in track.get("artists", []) ], } _DSP_TO_PARSER = {DSP.APPLE.value: parse_apple_track_meta, DSP.SPOTIFY.value: parse_spotify_track_meta} def parse_dsp_track_meta(dsp: str, track: dict, image_size: int = DEFAULT_IMAGE_SIZE) -> dict: parser = _DSP_TO_PARSER.get(dsp) if not parser: raise ValueError( f"parse_dsp_track_meta got unsupported dsp={dsp}. Available options are: {_DSP_TO_PARSER.keys()}" ) return parser(track, image_size=image_size)