Skip to content

Commit

Permalink
Merge pull request #154 from metabrainz/apple-playlists-tracks
Browse files Browse the repository at this point in the history
LB-1700: Get all tracks for apple music playlist
  • Loading branch information
mayhem authored Jan 10, 2025
2 parents a0aac57 + a82eaa3 commit 6c677a9
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 8 deletions.
2 changes: 1 addition & 1 deletion troi/playlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ class RecordingsFromMusicServiceElement(Element):
def __init__(self, token=None, playlist_id=None, music_service=None, apple_user_token=None):
"""
Args:
playlist_id: id of the Spotify playlist to be used for creating the playlist element
playlist_id: id of the playlist to be used for creating the playlist element
token: the Spotify token to fetch the playlist tracks
music_service: the name of the music service to be used for fetching the playlist data
apple_music_token (optional): the user token for Apple Music API
Expand Down
6 changes: 1 addition & 5 deletions troi/tools/apple_lookup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,7 @@ def get_tracks_from_apple_playlist(developer_token, user_token, playlist_id):
""" Get tracks from the Apple Music playlist.
"""
apple = AppleMusicAPI(developer_token, user_token)
response = apple.get_playlist_tracks(playlist_id)

tracks = response["data"][0]["relationships"]["tracks"]["data"]
name = response["data"][0]["attributes"]["name"]
description = response["data"][0]["attributes"].get("description", {}).get("standard", "")
tracks, name, description = apple.get_playlist_tracks(playlist_id)

mapped_tracks = [
{
Expand Down
41 changes: 39 additions & 2 deletions troi/tools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,45 @@ def playlist_add_tracks(self, playlist_id, track_ids):

def get_playlist_tracks(self, playlist_id):
url = f"{APPLE_MUSIC_URL}/me/library/playlists/{playlist_id}?include=tracks"
response = self.session.get(url, headers=self.headers)
return response.json()
response = self.session.get(url, headers=self.headers).json()
tracks = response["data"][0]["relationships"]["tracks"]["data"]
total_tracks_count = response["data"][0]["relationships"]["tracks"]["meta"]["total"]
playlist_name = response["data"][0]["attributes"]["name"]
playlist_description = response["data"][0]["attributes"].get(
"description", {}).get("standard", "")

# apple music returns only the first 100 tracks with "/playlists/{playlist_id}?include=tracks"
# and we need to fetch the rest of the tracks using the "playlists/{playlist_id}/tracks" endpoint
if len(tracks) < total_tracks_count:
offset = len(tracks)
# endpoint returns 100 tracks per call max -> run iteratively with an offset until there are no more tracks
while True:
url = f"{APPLE_MUSIC_URL}/me/library/playlists/{playlist_id}/tracks?limit=100&offset={offset}"
response = self.session.get(url, headers=self.headers).json()
try:
if "errors" in response:
# https: // developer.apple.com/documentation/applemusicapi/errorsresponse
error_objects = response["errors"]
for error_object in error_objects:
error_message = error_object["detail"] if "detail" in error_object else error_object["title"]
logger.error(
f"Error code {error_object['status']}: {error_message}")
break

tracks_data = response["data"]
tracks.extend(tracks_data) if tracks_data else None

if len(tracks_data) == 0 or len(tracks) == total_tracks_count:
break
# set new offset for the next loop
offset = offset + len(tracks_data)
except KeyError as err:
# No data returned from API call, could be an error, do nothing
logger.error(
"Failed to fetch Apple playlist tracks: %s, ignoring error..." % err)
break

return tracks, playlist_name, playlist_description


class SoundCloudException(Exception):
Expand Down

0 comments on commit 6c677a9

Please sign in to comment.