From 52a4e3e0c5571284d639b5a2a5d73d0e3e26f450 Mon Sep 17 00:00:00 2001 From: RemixDev Date: Wed, 15 Apr 2020 11:13:55 +0200 Subject: [PATCH] Added support for spotify playlists --- README.md | 1 - deemix/app/downloader.py | 17 +++++++ deemix/app/queuemanager.py | 10 ++++- deemix/utils/spotifyHelper.py | 85 +++++++++++++++++++++++++++++++++-- 4 files changed, 107 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 100eebb..68a5b81 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,6 @@ Run `python server.py` to start just the server
Finish porting all features: - logging - finish the gui -- spotify playlist support - ? Settings not yet implemented: diff --git a/deemix/app/downloader.py b/deemix/app/downloader.py index f3d017a..8e179a8 100644 --- a/deemix/app/downloader.py +++ b/deemix/app/downloader.py @@ -377,6 +377,21 @@ def downloadTrackObj(dz, trackAPI, settings, bitrate, queueItem, extraTrack=None if 'cancel' in queueItem: result['cancel'] = True return result + + if trackAPI['SNG_ID'] == 0: + result['error'] = { + 'message': "Track not available on Deezer!", + } + if 'SNG_TITLE' in trackAPI: + result['error']['data'] = { + 'id': trackAPI['SNG_ID'], + 'title': trackAPI['SNG_TITLE'], + 'mainArtist': {'name': trackAPI['ART_NAME']} + } + if socket: + queueItem['failed'] += 1 + socket.emit("updateQueue", {'uuid': queueItem['uuid'], 'failed': True, 'data': result['error']['data'], 'error': "Track not available on Deezer!"}) + return result # Get the metadata if extraTrack: track = extraTrack @@ -662,6 +677,8 @@ def after_download(tracks, settings, queueItem): if 'cancel' in result: return None if 'error' in result: + if not 'data' in result['error']: + result['error']['data'] = {'id': 0, 'title': 'Unknown', 'mainArtist': {'name': 'Unknown'}} errors += f"{result['error']['data']['id']} | {result['error']['data']['mainArtist']['name']} - {result['error']['data']['title']} | {result['error']['message']}\r\n" if 'searched' in result: searched += result['searched']+"\r\n" diff --git a/deemix/app/queuemanager.py b/deemix/app/queuemanager.py index c3f2796..b4532ad 100644 --- a/deemix/app/queuemanager.py +++ b/deemix/app/queuemanager.py @@ -1,5 +1,5 @@ from deemix.utils.misc import getIDFromLink, getTypeFromLink, getBitrateInt -from deemix.utils.spotifyHelper import get_trackid_spotify, get_albumid_spotify +from deemix.utils.spotifyHelper import get_trackid_spotify, get_albumid_spotify, convert_spotify_playlist from concurrent.futures import ProcessPoolExecutor from deemix.app.downloader import download @@ -146,6 +146,14 @@ def generateQueueItem(dz, url, settings, bitrate=None, albumAPI=None, socket=Non else: print("Album not found on deezer!") result['error'] = "Album not found on deezer!" + elif type == "spotifyplaylist": + if socket: + socket.emit("toast", {'msg': f"Converting spotify tracks to deezer tracks", 'icon': 'loading', 'dismiss': False, 'id': 'spotifyplaylist_'+str(id)}) + result = convert_spotify_playlist(dz, id, settings) + result['bitrate'] = bitrate + result['uuid'] = f"{result['type']}_{id}_{bitrate}" + if socket: + socket.emit("toast", {'msg': f"Spotify playlist converted", 'icon': 'done', 'dismiss': True, 'id': 'spotifyplaylist_'+str(id)}) else: print("URL not supported yet") result['error'] = "URL not supported yet" diff --git a/deemix/utils/spotifyHelper.py b/deemix/utils/spotifyHelper.py index 2e99e32..26948ea 100644 --- a/deemix/utils/spotifyHelper.py +++ b/deemix/utils/spotifyHelper.py @@ -37,11 +37,44 @@ if spotifyEnabled: client_credentials_manager = SpotifyClientCredentials(client_id=credentials['clientId'], client_secret=credentials['clientSecret']) sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager) -def get_trackid_spotify(dz, track_id, fallbackSearch): +def _convert_playlist_structure(spotify_obj): + if len(spotify_obj['images']): + url = spotify_obj['images'][0]['url'] + else: + url = "https://e-cdns-images.dzcdn.net/images/cover/d41d8cd98f00b204e9800998ecf8427e/75x75-000000-80-0-0.jpg" + deezer_obj = { + 'checksum': spotify_obj['snapshot_id'], + 'collaborative': spotify_obj['collaborative'], + 'creation_date': "???-??-??", + 'creator': {'id': spotify_obj['owner']['id'], 'name': spotify_obj['owner']['display_name'], 'tracklist': spotify_obj['owner']['href'], 'type': "user"}, + 'description': spotify_obj['description'], + 'duration': 0, + 'fans': spotify_obj['followers']['total'], + 'id': spotify_obj['id'], + 'is_loved_track': False, + 'link': spotify_obj['external_urls']['spotify'], + 'nb_tracks': spotify_obj['tracks']['total'], + 'picture': url, + 'picture_big': url, + 'picture_medium': url, + 'picture_small': url, + 'picture_xl': url, + 'public': spotify_obj['public'], + 'share': spotify_obj['external_urls']['spotify'], + 'title': spotify_obj['name'], + 'tracklist': spotify_obj['tracks']['href'], + 'type': "playlist" + } + return deezer_obj + +def get_trackid_spotify(dz, track_id, fallbackSearch, spotifyTrack=None): global spotifyEnabled if not spotifyEnabled: return "Not Enabled" - spotify_track = sp.track(track_id) + if not spotifyTrack: + spotify_track = sp.track(track_id) + else: + spotify_track = spotifyTrack dz_track = 0 if 'external_ids' in spotify_track and 'isrc' in spotify_track['external_ids']: try: @@ -71,9 +104,53 @@ def get_albumid_spotify(dz, album_id): dz_album = 0 return dz_album -def convert_spotify_playlist(dz, playlist_id): +def convert_spotify_playlist(dz, playlist_id, settings): global spotifyEnabled if not spotifyEnabled: return "Not Enabled" spotify_playlist = sp.playlist(playlist_id) - print(spotify_playlist) + result = { + 'title': spotify_playlist['name'], + 'artist': spotify_playlist['owner']['display_name'], + 'size': spotify_playlist['tracks']['total'], + 'downloaded': 0, + 'failed': 0, + 'progress': 0, + 'type': 'spotify_playlist', + 'settings': settings or {}, + 'id': playlist_id + } + if len(spotify_playlist['images']): + result['cover'] = spotify_playlist['images'][0]['url'] + else: + result['cover'] = "https://e-cdns-images.dzcdn.net/images/cover/d41d8cd98f00b204e9800998ecf8427e/75x75-000000-80-0-0.jpg" + playlistAPI = _convert_playlist_structure(spotify_playlist) + tracklist = spotify_playlist['tracks']['items'] + result['collection'] = [] + while spotify_playlist['tracks']['next']: + spotify_playlist['tracks'] = sp.next(spotify_playlist['tracks']) + tracklist += spotify_playlist['tracks']['items'] + totalSize = len(tracklist) + for pos, track in enumerate(tracklist, start=1): + trackID = get_trackid_spotify(dz, 0, settings['fallbackSearch'], track['track']) + if trackID == 0: + deezerTrack = { + 'SNG_ID': 0, + 'SNG_TITLE': track['track']['name'], + 'DURATION': 0, + 'MD5_ORIGIN': 0, + 'MEDIA_VERSION': 0, + 'FILESIZE': 0, + 'ALB_TITLE': track['track']['album']['name'], + 'ALB_PICTURE': "", + 'ART_ID': 0, + 'ART_NAME': track['track']['artists'][0]['name'] + } + else: + deezerTrack = dz.get_track_gw(trackID) + deezerTrack['_EXTRA_PLAYLIST'] = playlistAPI + deezerTrack['POSITION'] = pos + deezerTrack['SIZE'] = totalSize + deezerTrack['FILENAME_TEMPLATE'] = settings['playlistTracknameTemplate'] + result['collection'].append(deezerTrack) + return result