Added Spotify credentials to settings tab

Reworked how spotify features work so now it doesn't require restart on 
config change
This commit is contained in:
RemixDev 2020-04-16 10:37:02 +02:00
parent 5ce63b8d5f
commit c15b7189e4
5 changed files with 199 additions and 175 deletions

View File

@ -3,11 +3,13 @@ from deemix.api.deezer import Deezer
import deemix.utils.localpaths as localpaths import deemix.utils.localpaths as localpaths
from deemix.utils.misc import getIDFromLink, getTypeFromLink, getBitrateInt from deemix.utils.misc import getIDFromLink, getTypeFromLink, getBitrateInt
from deemix.app.queuemanager import addToQueue from deemix.app.queuemanager import addToQueue
from deemix.app.spotify import SpotifyHelper
from os import system as execute from os import system as execute
import os.path as path import os.path as path
from os import mkdir from os import mkdir
dz = Deezer() dz = Deezer()
sp = SpotifyHelper()
def requestValidArl(): def requestValidArl():
while True: while True:
@ -31,4 +33,4 @@ def login():
f.write(arl) f.write(arl)
def downloadLink(url, settings, bitrate=None): def downloadLink(url, settings, bitrate=None):
addToQueue(dz, url, settings, bitrate) addToQueue(dz, sp, url, settings, bitrate)

View File

@ -3,7 +3,6 @@ from deemix.api.deezer import APIError, USER_AGENT_HEADER
from deemix.utils.taggers import tagID3, tagFLAC from deemix.utils.taggers import tagID3, tagFLAC
from deemix.utils.pathtemplates import generateFilename, generateFilepath, settingsRegexAlbum, settingsRegexArtist from deemix.utils.pathtemplates import generateFilename, generateFilepath, settingsRegexAlbum, settingsRegexArtist
from deemix.utils.misc import changeCase from deemix.utils.misc import changeCase
from deemix.utils.spotifyHelper import get_trackid_spotify, get_albumid_spotify
import os.path import os.path
from os import makedirs, remove from os import makedirs, remove
from requests import get from requests import get

View File

@ -1,5 +1,4 @@
from deemix.utils.misc import getIDFromLink, getTypeFromLink, getBitrateInt from deemix.utils.misc import getIDFromLink, getTypeFromLink, getBitrateInt
from deemix.utils.spotifyHelper import get_trackid_spotify, get_albumid_spotify, convert_spotify_playlist
from concurrent.futures import ProcessPoolExecutor from concurrent.futures import ProcessPoolExecutor
from deemix.app.downloader import download from deemix.app.downloader import download
@ -27,7 +26,7 @@ if its an album/playlist
collection collection
""" """
def generateQueueItem(dz, url, settings, bitrate=None, albumAPI=None, interface=None): def generateQueueItem(dz, sp, url, settings, bitrate=None, albumAPI=None, interface=None):
forcedBitrate = getBitrateInt(bitrate) forcedBitrate = getBitrateInt(bitrate)
bitrate = forcedBitrate if forcedBitrate else settings['maxBitrate'] bitrate = forcedBitrate if forcedBitrate else settings['maxBitrate']
type = getTypeFromLink(url) type = getTypeFromLink(url)
@ -65,7 +64,7 @@ def generateQueueItem(dz, url, settings, bitrate=None, albumAPI=None, interface=
albumAPI['nb_disk'] = albumAPI_gw['NUMBER_DISK'] albumAPI['nb_disk'] = albumAPI_gw['NUMBER_DISK']
albumAPI['copyright'] = albumAPI_gw['COPYRIGHT'] albumAPI['copyright'] = albumAPI_gw['COPYRIGHT']
if albumAPI['nb_tracks'] == 1: if albumAPI['nb_tracks'] == 1:
return generateQueueItem(dz, f"https://www.deezer.com/track/{albumAPI['tracks']['data'][0]['id']}", settings, bitrate, albumAPI) return generateQueueItem(dz, sp, f"https://www.deezer.com/track/{albumAPI['tracks']['data'][0]['id']}", settings, bitrate, albumAPI)
tracksArray = dz.get_album_tracks_gw(id) tracksArray = dz.get_album_tracks_gw(id)
result['title'] = albumAPI['title'] result['title'] = albumAPI['title']
@ -121,37 +120,46 @@ def generateQueueItem(dz, url, settings, bitrate=None, albumAPI=None, interface=
artistAPITracks = dz.get_artist_albums(id) artistAPITracks = dz.get_artist_albums(id)
albumList = [] albumList = []
for album in artistAPITracks['data']: for album in artistAPITracks['data']:
albumList.append(generateQueueItem(dz, album['link'], settings, bitrate)) albumList.append(generateQueueItem(dz, sp, album['link'], settings, bitrate))
if interface: if interface:
interface.send("toast", {'msg': f"Added {artistAPI['name']} albums to queue", 'icon': 'done', 'dismiss': True, 'id': 'artist_'+str(artistAPI['id'])}) interface.send("toast", {'msg': f"Added {artistAPI['name']} albums to queue", 'icon': 'done', 'dismiss': True, 'id': 'artist_'+str(artistAPI['id'])})
return albumList return albumList
elif type == "spotifytrack": elif type == "spotifytrack":
track_id = get_trackid_spotify(dz, id, settings['fallbackSearch'])
result = {} result = {}
if track_id == "Not Enabled": if not sp.spotifyEnabled:
print("Spotify Features is not setted up correctly.") print("Spotify Features is not setted up correctly.")
result['error'] = "Spotify Features is not setted up correctly." result['error'] = "Spotify Features is not setted up correctly."
elif track_id != 0: return result
return generateQueueItem(dz, f'https://www.deezer.com/track/{track_id}', settings, bitrate) track_id = sp.get_trackid_spotify(dz, id, settings['fallbackSearch'])
if track_id != 0:
return generateQueueItem(dz, sp, f'https://www.deezer.com/track/{track_id}', settings, bitrate)
else: else:
print("Track not found on deezer!") print("Track not found on deezer!")
result['error'] = "Track not found on deezer!" result['error'] = "Track not found on deezer!"
elif type == "spotifyalbum": elif type == "spotifyalbum":
album_id = get_albumid_spotify(dz, id) result = {}
if album_id == "Not Enabled": if not sp.spotifyEnabled:
print("Spotify Features is not setted up correctly.") print("Spotify Features is not setted up correctly.")
result['error'] = "Spotify Features is not setted up correctly." result['error'] = "Spotify Features is not setted up correctly."
elif album_id != 0: return result
return generateQueueItem(dz, f'https://www.deezer.com/album/{album_id}', settings, bitrate) album_id = sp.get_albumid_spotify(dz, id)
if album_id != 0:
return generateQueueItem(dz, sp, f'https://www.deezer.com/album/{album_id}', settings, bitrate)
else: else:
print("Album not found on deezer!") print("Album not found on deezer!")
result['error'] = "Album not found on deezer!" result['error'] = "Album not found on deezer!"
elif type == "spotifyplaylist": elif type == "spotifyplaylist":
result = {}
if not sp.spotifyEnabled:
print("Spotify Features is not setted up correctly.")
result['error'] = "Spotify Features is not setted up correctly."
return result
if interface: if interface:
interface.send("toast", {'msg': f"Converting spotify tracks to deezer tracks", 'icon': 'loading', 'dismiss': False, 'id': 'spotifyplaylist_'+str(id)}) interface.send("toast", {'msg': f"Converting spotify tracks to deezer tracks", 'icon': 'loading', 'dismiss': False, 'id': 'spotifyplaylist_'+str(id)})
result = convert_spotify_playlist(dz, id, settings) playlist = sp.convert_spotify_playlist(dz, id, settings)
result['bitrate'] = bitrate playlist['bitrate'] = bitrate
result['uuid'] = f"{result['type']}_{id}_{bitrate}" playlist['uuid'] = f"{result['type']}_{id}_{bitrate}"
result = playlist
if interface: if interface:
interface.send("toast", {'msg': f"Spotify playlist converted", 'icon': 'done', 'dismiss': True, 'id': 'spotifyplaylist_'+str(id)}) interface.send("toast", {'msg': f"Spotify playlist converted", 'icon': 'done', 'dismiss': True, 'id': 'spotifyplaylist_'+str(id)})
else: else:
@ -159,11 +167,11 @@ def generateQueueItem(dz, url, settings, bitrate=None, albumAPI=None, interface=
result['error'] = "URL not supported yet" result['error'] = "URL not supported yet"
return result return result
def addToQueue(dz, url, settings, bitrate=None, interface=None): def addToQueue(dz, sp, url, settings, bitrate=None, interface=None):
global currentItem, queueList, queue global currentItem, queueList, queue
if not dz.logged_in: if not dz.logged_in:
return "Not logged in" return "Not logged in"
queueItem = generateQueueItem(dz, url, settings, bitrate, interface=interface) queueItem = generateQueueItem(dz, sp, url, settings, bitrate, interface=interface)
if type(queueItem) is list: if type(queueItem) is list:
for x in queueItem: for x in queueItem:
if 'error' in x: if 'error' in x:

171
deemix/app/spotify.py Normal file
View File

@ -0,0 +1,171 @@
#!/usr/bin/env python3
import os.path as path
from os import mkdir, rmdir
import json
import deemix.utils.localpaths as localpaths
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
class SpotifyHelper:
def __init__(self):
self.credentials = {}
self.spotifyEnabled = False
self.sp = None
self.initCredentials()
def initCredentials(self):
configFolder = localpaths.getConfigFolder()
if not path.isdir(configFolder):
mkdir(configFolder)
if not path.isfile(path.join(configFolder, 'authCredentials.json')):
with open(path.join(configFolder, 'authCredentials.json'), 'w') as f:
json.dump({'clientId': "", 'clientSecret': ""}, f, indent=2)
with open(path.join(configFolder, 'authCredentials.json'), 'r') as credentialsFile:
self.credentials = json.load(credentialsFile)
self.checkCredentials()
def checkCredentials(self):
if self.credentials['clientId'] == "" or self.credentials['clientSecret'] == "":
spotifyEnabled = False
else:
try:
self.createSpotifyConnection()
self.sp.user_playlists('spotify')
self.spotifyEnabled = True
except Exception as e:
self.spotifyEnabled = False
return self.spotifyEnabled
def getCredentials(self):
return self.credentials
def setCredentials(self, spotifyCredentials):
configFolder = localpaths.getConfigFolder()
with open(path.join(configFolder, 'authCredentials.json'), 'w') as f:
json.dump(spotifyCredentials, f, indent=2)
self.credentials = spotifyCredentials
self.checkCredentials()
def createSpotifyConnection(self):
client_credentials_manager = SpotifyClientCredentials(client_id=self.credentials['clientId'], client_secret=self.credentials['clientSecret'])
self.sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
def _convert_playlist_structure(self, 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(self, dz, track_id, fallbackSearch, spotifyTrack=None):
if not self.spotifyEnabled:
raise spotifyFeaturesNotEnabled
if not spotifyTrack:
spotify_track = self.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:
dz_track = dz.get_track_by_ISRC(spotify_track['external_ids']['isrc'])
dz_track = dz_track['id'] if 'id' in dz_track else 0
except:
dz_track = dz.get_track_from_metadata(spotify_track['artists'][0]['name'], spotify_track['name'], spotify_track['album']['name']) if fallbackSearch else 0
elif fallbackSearch:
dz_track = dz.get_track_from_metadata(spotify_track['artists'][0]['name'], spotify_track['name'], spotify_track['album']['name'])
return dz_track
def get_albumid_spotify(self, dz, album_id):
if not self.spotifyEnabled:
raise spotifyFeaturesNotEnabled
spotify_album = self.sp.album(album_id)
dz_album = 0
if 'external_ids' in spotify_album and 'upc' in spotify_album['external_ids']:
try:
dz_album = dz.get_album_by_UPC(spotify_album['external_ids']['upc'])
dz_album = dz_album['id'] if 'id' in dz_album else 0
except:
try:
dz_album = dz.get_album_by_UPC(int(spotify_album['external_ids']['upc']))
dz_album = dz_album['id'] if 'id' in dz_album else 0
except:
dz_album = 0
return dz_album
def convert_spotify_playlist(self, sp, dz, playlist_id, settings):
if not self.spotifyEnabled:
raise spotifyFeaturesNotEnabled
spotify_playlist = self.sp.playlist(playlist_id)
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 = self._convert_playlist_structure(spotify_playlist)
tracklist = spotify_playlist['tracks']['items']
result['collection'] = []
while spotify_playlist['tracks']['next']:
spotify_playlist['tracks'] = self.sp.next(spotify_playlist['tracks'])
tracklist += spotify_playlist['tracks']['items']
totalSize = len(tracklist)
for pos, track in enumerate(tracklist, start=1):
trackID = self.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
class spotifyFeaturesNotEnabled(Exception):
pass

View File

@ -1,156 +0,0 @@
#!/usr/bin/env python3
import os.path as path
from os import mkdir, rmdir
import json
import deemix.utils.localpaths as localpaths
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
credentials = {}
spotifyEnabled = False
def getCredentials():
global credentials
global spotifyEnabled
configFolder = localpaths.getConfigFolder()
if not path.isdir(configFolder):
mkdir(configFolder)
if not path.isfile(path.join(configFolder, 'authCredentials.json')):
with open(path.join(configFolder, 'authCredentials.json'), 'w') as f:
json.dump({'clientId': "", 'clientSecret': ""}, f, indent=2)
with open(path.join(configFolder, 'authCredentials.json'), 'r') as credentialsFile:
credentials = json.load(credentialsFile)
checkCredentials()
def checkCredentials():
global credentials
global spotifyEnabled
if credentials['clientId'] == "" or credentials['clientSecret'] == "":
spotifyEnabled = False
else:
spotifyEnabled = True
getCredentials()
if spotifyEnabled:
client_credentials_manager = SpotifyClientCredentials(client_id=credentials['clientId'], client_secret=credentials['clientSecret'])
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
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"
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:
dz_track = dz.get_track_by_ISRC(spotify_track['external_ids']['isrc'])
dz_track = dz_track['id'] if 'id' in dz_track else 0
except:
dz_track = dz.get_track_from_metadata(spotify_track['artists'][0]['name'], spotify_track['name'], spotify_track['album']['name']) if fallbackSearch else 0
elif fallbackSearch:
dz_track = dz.get_track_from_metadata(spotify_track['artists'][0]['name'], spotify_track['name'], spotify_track['album']['name'])
return dz_track
def get_albumid_spotify(dz, album_id):
global spotifyEnabled
if not spotifyEnabled:
return "Not Enabled"
spotify_album = sp.album(album_id)
dz_album = 0
if 'external_ids' in spotify_album and 'upc' in spotify_album['external_ids']:
try:
dz_album = dz.get_album_by_UPC(spotify_album['external_ids']['upc'])
dz_album = dz_album['id'] if 'id' in dz_album else 0
except:
try:
dz_album = dz.get_album_by_UPC(int(spotify_album['external_ids']['upc']))
dz_album = dz_album['id'] if 'id' in dz_album else 0
except:
dz_album = 0
return dz_album
def convert_spotify_playlist(dz, playlist_id, settings):
global spotifyEnabled
if not spotifyEnabled:
return "Not Enabled"
spotify_playlist = sp.playlist(playlist_id)
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