Made the refactoring work

This commit is contained in:
RemixDev 2020-08-15 23:03:05 +02:00
parent 4cfdc4872d
commit 34263c150f
14 changed files with 171 additions and 190 deletions

View File

@ -1,36 +1,25 @@
#!/usr/bin/env python3
import click
import deemix.app.cli as app
from deemix.app.settings import initSettings
from deemix.app.cli import cli
from os.path import isfile
import random
import string
def randomString(stringLength=8):
letters = string.ascii_lowercase
return ''.join(random.choice(letters) for i in range(stringLength))
@click.command()
@click.option('-b', '--bitrate', default=None, help='Overwrites the default bitrate selected')
@click.option('-l', '--local', is_flag=True, help='Downloads in a local folder insted of using the default')
@click.argument('url', nargs=-1, required=True)
def download(bitrate, local, url):
settings = initSettings()
if local:
settings['downloadLocation'] = randomString(12)
click.echo("Using a local download folder: "+settings['downloadLocation'])
app = cli(local)
app.login()
url = list(url)
if isfile(url[0]):
filename = url[0]
with open(filename) as f:
url = f.readlines()
app.downloadLink(url, settings, bitrate)
app.downloadLink(url, bitrate)
click.echo("All done!")
if local:
click.echo(settings['downloadLocation']) #folder name output
click.echo(app.set.settings['downloadLocation']) #folder name output
if __name__ == '__main__':
download()

View File

@ -477,37 +477,37 @@ class Deezer:
for track in data:
item = {
'id': track['SNG_ID'],
'title': track['SNG_TITLE'],
'link': 'https://www.deezer.com/track/'+str(track['SNG_ID']),
'duration': track['DURATION'],
'rank': track['RANK_SNG'],
'explicit_lyrics': int(track['EXPLICIT_LYRICS']) > 0,
'explicit_content_lyrics': track['EXPLICIT_TRACK_CONTENT']['EXPLICIT_COVER_STATUS'],
'explicit_content_cover': track['EXPLICIT_TRACK_CONTENT']['EXPLICIT_LYRICS_STATUS'],
'time_add': track['DATE_ADD'],
'album': {
'id': track['ALB_ID'],
'title': track['ALB_TITLE'],
'cover': 'https://api.deezer.com/album/'+str(track['ALB_ID'])+'/image',
'cover_small': 'https://e-cdns-images.dzcdn.net/images/cover/'+str(track['ALB_PICTURE'])+'/56x56-000000-80-0-0.jpg',
'cover_medium': 'https://e-cdns-images.dzcdn.net/images/cover/'+str(track['ALB_PICTURE'])+'/250x250-000000-80-0-0.jpg',
'cover_big': 'https://e-cdns-images.dzcdn.net/images/cover/'+str(track['ALB_PICTURE'])+'/500x500-000000-80-0-0.jpg',
'cover_xl': 'https://e-cdns-images.dzcdn.net/images/cover/'+str(track['ALB_PICTURE'])+'/1000x1000-000000-80-0-0.jpg',
'tracklist': 'https://api.deezer.com/album/'+str(track['ALB_ID'])+'/tracks',
'type': 'album'
},
'artist': {
'id': track['ART_ID'],
'name': track['ART_NAME'],
'picture': 'https://api.deezer.com/artist/'+str(track['ART_ID'])+'/image',
'picture_small': 'https://e-cdns-images.dzcdn.net/images/artist/'+str(track['ART_PICTURE'])+'/56x56-000000-80-0-0.jpg',
'picture_medium': 'https://e-cdns-images.dzcdn.net/images/artist/'+str(track['ART_PICTURE'])+'/250x250-000000-80-0-0.jpg',
'picture_big': 'https://e-cdns-images.dzcdn.net/images/artist/'+str(track['ART_PICTURE'])+'/500x500-000000-80-0-0.jpg',
'picture_xl': 'https://e-cdns-images.dzcdn.net/images/artist/'+str(track['ART_PICTURE'])+'/1000x1000-000000-80-0-0.jpg',
'tracklist': 'https://api.deezer.com/artist/'+str(track['ART_ID'])+'/top?limit=50',
'type': 'artist'
},
'type': 'track'
'title': track['SNG_TITLE'],
'link': 'https://www.deezer.com/track/'+str(track['SNG_ID']),
'duration': track['DURATION'],
'rank': track['RANK_SNG'],
'explicit_lyrics': int(track['EXPLICIT_LYRICS']) > 0,
'explicit_content_lyrics': track['EXPLICIT_TRACK_CONTENT']['EXPLICIT_COVER_STATUS'],
'explicit_content_cover': track['EXPLICIT_TRACK_CONTENT']['EXPLICIT_LYRICS_STATUS'],
'time_add': track['DATE_ADD'],
'album': {
'id': track['ALB_ID'],
'title': track['ALB_TITLE'],
'cover': 'https://api.deezer.com/album/'+str(track['ALB_ID'])+'/image',
'cover_small': 'https://e-cdns-images.dzcdn.net/images/cover/'+str(track['ALB_PICTURE'])+'/56x56-000000-80-0-0.jpg',
'cover_medium': 'https://e-cdns-images.dzcdn.net/images/cover/'+str(track['ALB_PICTURE'])+'/250x250-000000-80-0-0.jpg',
'cover_big': 'https://e-cdns-images.dzcdn.net/images/cover/'+str(track['ALB_PICTURE'])+'/500x500-000000-80-0-0.jpg',
'cover_xl': 'https://e-cdns-images.dzcdn.net/images/cover/'+str(track['ALB_PICTURE'])+'/1000x1000-000000-80-0-0.jpg',
'tracklist': 'https://api.deezer.com/album/'+str(track['ALB_ID'])+'/tracks',
'type': 'album'
},
'artist': {
'id': track['ART_ID'],
'name': track['ART_NAME'],
'picture': 'https://api.deezer.com/artist/'+str(track['ART_ID'])+'/image',
'picture_small': 'https://e-cdns-images.dzcdn.net/images/artist/'+str(track['ART_PICTURE'])+'/56x56-000000-80-0-0.jpg',
'picture_medium': 'https://e-cdns-images.dzcdn.net/images/artist/'+str(track['ART_PICTURE'])+'/250x250-000000-80-0-0.jpg',
'picture_big': 'https://e-cdns-images.dzcdn.net/images/artist/'+str(track['ART_PICTURE'])+'/500x500-000000-80-0-0.jpg',
'picture_xl': 'https://e-cdns-images.dzcdn.net/images/artist/'+str(track['ART_PICTURE'])+'/1000x1000-000000-80-0-0.jpg',
'tracklist': 'https://api.deezer.com/artist/'+str(track['ART_ID'])+'/top?limit=50',
'type': 'artist'
},
'type': 'track'
}
result.append(item)
return result

View File

@ -2,11 +2,11 @@
from deemix.api.deezer import Deezer
from deemix.app.settings import Settings
from deemix.app.queuemanager import QueueManager
from deemix.app.spotify import SpotifyHelper
from deemix.app.spotifyhelper import SpotifyHelper
class deemix:
def __init__(self):
self.set = Settings()
def __init__(self, configFolder=None):
self.set = Settings(configFolder)
self.dz = Deezer()
self.sp = SpotifyHelper()
self.sp = SpotifyHelper(configFolder)
self.qm = QueueManager()

View File

@ -1,43 +1,47 @@
#!/usr/bin/env python3
import os.path as path
import string
import random
from os import mkdir
from deemix.utils import localpaths
from deemix.api.deezer import Deezer
from deemix.app.queuemanager import addToQueue
from deemix.app.spotify import SpotifyHelper
from deemix.app import deemix
dz = Deezer()
sp = SpotifyHelper()
def randomString(stringLength=8):
letters = string.ascii_lowercase
return ''.join(random.choice(letters) for i in range(stringLength))
class cli(deemix):
def __init__(self, local, configFolder=None):
super().__init__(configFolder)
if local:
self.set.settings['downloadLocation'] = randomString(12)
print("Using a local download folder: "+settings['downloadLocation'])
def requestValidArl():
while True:
arl = input("Paste here your arl:")
if dz.login_via_arl(arl):
break
return arl
def downloadLink(self, url, bitrate=None):
for link in url:
if ';' in link:
for l in link.split(";"):
self.qm.addToQueue(self.dz, self.sp, l, self.set.settings, bitrate)
else:
self.qm.addToQueue(self.dz, self.sp, link, self.set.settings, bitrate)
def requestValidArl(self):
while True:
arl = input("Paste here your arl:")
if self.dz.login_via_arl(arl):
break
return arl
def login():
configFolder = localpaths.getConfigFolder()
if not path.isdir(configFolder):
mkdir(configFolder)
if path.isfile(path.join(configFolder, '.arl')):
with open(path.join(configFolder, '.arl'), 'r') as f:
arl = f.readline().rstrip("\n")
if not dz.login_via_arl(arl):
arl = requestValidArl()
else:
arl = requestValidArl()
with open(path.join(configFolder, '.arl'), 'w') as f:
f.write(arl)
def downloadLink(url, settings, bitrate=None):
for link in url:
if ';' in link:
for l in link.split(";"):
addToQueue(dz, sp, l, settings, bitrate)
def login(self):
configFolder = self.set.configFolder
if not path.isdir(configFolder):
mkdir(configFolder)
if path.isfile(path.join(configFolder, '.arl')):
with open(path.join(configFolder, '.arl'), 'r') as f:
arl = f.readline().rstrip("\n")
if not self.dz.login_via_arl(arl):
arl = self.requestValidArl()
else:
addToQueue(dz, sp, link, settings, bitrate)
arl = self.requestValidArl()
with open(path.join(configFolder, '.arl'), 'w') as f:
f.write(arl)

View File

@ -11,7 +11,7 @@ from tempfile import gettempdir
from time import sleep
from deemix.app.queueitem import QIConvertable, QISingle, QICollection
from deemix.app.Track import Track
from deemix.app.track import Track
from deemix.utils.misc import changeCase
from deemix.utils.pathtemplates import generateFilename, generateFilepath, settingsRegexAlbum, settingsRegexArtist, settingsRegexPlaylistFile
from deemix.api.deezer import USER_AGENT_HEADER
@ -46,8 +46,8 @@ errorMessages = {
'wrongBitrate': "Track not found at desired bitrate.",
'wrongBitrateNoAlternative': "Track not found at desired bitrate and no alternative found!",
'no360RA': "Track is not available in Reality Audio 360.",
'notAvailable': "Track not available on deezer's servers!"
'notAvailableNoAlternative': "Track not available on deezer's servers and no alternative found!",
'notAvailable': "Track not available on deezer's servers!",
'notAvailableNoAlternative': "Track not available on deezer's servers and no alternative found!"
}
def after_download(tracks, settings, queueItem):
@ -168,8 +168,10 @@ class DownloadJob:
def __init__(self, dz, sp, queueItem, interface=None):
self.dz = dz
self.sp = sp
self.queueItem = queueItem
self.interface = interface
if isinstance(queueItem, QIConvertable):
self.sp.convert_spotify_playlist(self.dz, queueItem, interface=self.interface)
self.queueItem = queueItem
self.settings = queueItem.settings
self.bitrate = queueItem.bitrate
self.downloadPercentage = 0
@ -177,8 +179,6 @@ class DownloadJob:
self.extrasPath = self.settings['downloadLocation']
def start(self):
if isinstance(self.queueItem, QIConvertable):
self.sp.convert_spotify_playlist(self.dz, self.queueItem, self.settings, interface=self.interface)
if isinstance(self.queueItem, QISingle):
result = self.downloadWrapper(self.queueItem.single)
if result:
@ -215,15 +215,15 @@ class DownloadJob:
)
if self.queueItem.cancel: raise DownloadCancelled
if self.MD5 == '':
if track.MD5 == '':
if track.fallbackId != "0":
logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not yet encoded, using fallback id")
newTrack = self.dz.get_track_gw(track.fallbackId)
track.parseEssentialData(self.dz, newTrack)
return self.download(trackAPI_gw, track)
elif not track.searched and self.settings['fallbackSearch']:
logger.warn(f"[{self.mainArtist['name']} - {self.title}] Track not yet encoded, searching for alternative")
searchedId = self.dz.get_track_from_metadata(self.mainArtist['name'], self.title, self.album['title'])
logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not yet encoded, searching for alternative")
searchedId = self.dz.get_track_from_metadata(track.mainArtist['name'], track.title, track.album['title'])
if searchedId != 0:
newTrack = self.dz.get_track_gw(searchedId)
track.parseEssentialData(self.dz, newTrack)
@ -242,8 +242,8 @@ class DownloadJob:
track.parseEssentialData(self.dz, newTrack)
return self.download(trackAPI_gw, track)
elif not track.searched and self.settings['fallbackSearch']:
logger.warn(f"[{self.mainArtist['name']} - {self.title}] Track not found at desired bitrate, searching for alternative")
searchedId = self.dz.get_track_from_metadata(self.mainArtist['name'], self.title, self.album['title'])
logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not found at desired bitrate, searching for alternative")
searchedId = self.dz.get_track_from_metadata(track.mainArtist['name'], track.title, track.album['title'])
if searchedId != 0:
newTrack = self.dz.get_track_gw(searchedId)
track.parseEssentialData(self.dz, newTrack)
@ -261,8 +261,7 @@ class DownloadJob:
track.trackNumber = track.position
track.discNumber = "1"
track.album = {**track.album, **track.playlist}
track.album['picPath'] = os.path.join(TEMPDIR,
f"pl{trackAPI_gw['_EXTRA_PLAYLIST']['id']}_{settings['embeddedArtworkSize']}.jpg")
track.album['picPath'] = os.path.join(TEMPDIR, f"pl{trackAPI_gw['_EXTRA_PLAYLIST']['id']}_{self.settings['embeddedArtworkSize']}.jpg")
else:
if track.album['date']:
track.date = track.album['date']
@ -271,10 +270,11 @@ class DownloadJob:
self.settings['embeddedArtworkSize'], self.settings['embeddedArtworkSize'],
f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg'
)
track.album['picPath'] = os.path.join(TEMPDIR, f"alb{track.album['id']}_{self.settings['embeddedArtworkSize']}.jpg")
track.album['bitrate'] = selectedFormat
track.dateString = formatDate(track.date, settings['dateFormat'])
track.album['dateString'] = formatDate(track.album['date'], settings['dateFormat'])
track.dateString = formatDate(track.date, self.settings['dateFormat'])
track.album['dateString'] = formatDate(track.album['date'], self.settings['dateFormat'])
# Check if user wants the feat in the title
# 0 => do not change
@ -320,11 +320,6 @@ class DownloadJob:
if self.queueItem.cancel: raise DownloadCancelled
# Download and cache coverart
if self.settings['tags']['savePlaylistAsCompilation'] and track.playlist:
else:
track.album['picPath'] = os.path.join(TEMPDIR,
f"alb{track.album['id']}_{settings['embeddedArtworkSize']}.jpg")
logger.info(f"[{track.mainArtist['name']} - {track.title}] Getting the album cover")
track.album['picPath'] = downloadImage(track.album['picUrl'], track.album['picPath'])
@ -418,7 +413,7 @@ class DownloadJob:
if not trackAlreadyDownloaded or self.settings['overwriteFile'] == 'y':
logger.info(f"[{track.mainArtist['name']} - {track.title}] Downloading the track")
track.downloadUrl = dz.get_track_stream_url(track.id, track.MD5, track.mediaVersion, track.selectedFormat)
track.downloadUrl = self.dz.get_track_stream_url(track.id, track.MD5, track.mediaVersion, track.selectedFormat)
def downloadMusic(track, trackAPI_gw):
try:
@ -435,8 +430,8 @@ class DownloadJob:
track.parseEssentialData(self.dz, newTrack)
return False
elif not track.searched and self.settings['fallbackSearch']:
logger.warn(f"[{self.mainArtist['name']} - {self.title}] Track not available, searching for alternative")
searchedId = self.dz.get_track_from_metadata(self.mainArtist['name'], self.title, self.album['title'])
logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not available, searching for alternative")
searchedId = self.dz.get_track_from_metadata(track.mainArtist['name'], track.title, track.album['title'])
if searchedId != 0:
newTrack = self.dz.get_track_gw(searchedId)
track.parseEssentialData(self.dz, newTrack)
@ -460,7 +455,7 @@ class DownloadJob:
try:
trackDownloaded = downloadMusic(track, trackAPI_gw)
except DownloadFailed as e:
raise DownloadFailed
raise e
except Exception as e:
raise e
@ -468,7 +463,7 @@ class DownloadJob:
return self.download(trackAPI_gw, track)
else:
logger.info(f"[{track.mainArtist['name']} - {track.title}] Skipping track as it's already downloaded")
trackCompletePercentage(trackAPI, queueItem, interface)
self.completeTrackPercentage()
# Adding tags
if (not trackAlreadyDownloaded or self.settings['overwriteFile'] in ['t', 'y']) and not track.localTrack:
@ -482,10 +477,10 @@ class DownloadJob:
remove(writepath)
logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not available in FLAC, falling back if necessary")
self.removeTrackPercentage(trackAPI, queueItem, interface)
track.formats['FILESIZE_FLAC'] = "0"
track.filesizes['FILESIZE_FLAC'] = "0"
return self.download(trackAPI_gw, track)
if track.searched:
result['searched'] = f'{track.mainArtist['name']} - {track.title}'
result['searched'] = f"{track.mainArtist['name']} - {track.title}"
logger.info(f"[{track.mainArtist['name']} - {track.title}] Track download completed")
self.queueItem.downloaded += 1
@ -533,16 +528,16 @@ class DownloadJob:
return error_num # fallback is enabled and loop went through all formats
def stream_track(self, stream, track, trackAPI):
def streamTrack(self, stream, track, trackAPI):
if self.queueItem.cancel: raise DownloadCancelled
try:
request = get(track.downloadUrl, headers=dz.http_headers, stream=True, timeout=30)
request = get(track.downloadUrl, headers=self.dz.http_headers, stream=True, timeout=30)
except ConnectionError:
sleep(2)
return stream_track(dz, track, stream, trackAPI, queueItem, interface)
return self.streamTrack(stream, track, trackAPI)
request.raise_for_status()
blowfish_key = str.encode(dz._get_blowfish_key(str(track.id)))
blowfish_key = str.encode(self.dz._get_blowfish_key(str(track.id)))
complete = int(request.headers["Content-Length"])
chunkLength = 0
percentage = 0
@ -585,9 +580,9 @@ class DownloadJob:
def downloadWrapper(self, trackAPI_gw):
track = {
'id': queueItem.single['SNG_ID'],
'title': queueItem.single['SNG_TITLE'] + (queueItem.single['VERSION'] if 'VERSION' in queueItem.single and queueItem.single['VERSION'] and not queueItem.single['VERSION'] in queueItem.single['SNG_TITLE'] else ""),
'mainArtist': {'name': queueItem.single['ART_NAME']}
'id': trackAPI_gw['SNG_ID'],
'title': trackAPI_gw['SNG_TITLE'] + (trackAPI_gw['VERSION'] if 'VERSION' in trackAPI_gw and trackAPI_gw['VERSION'] and not trackAPI_gw['VERSION'] in trackAPI_gw['SNG_TITLE'] else ""),
'artist': trackAPI_gw['ART_NAME']
}
try:
@ -595,14 +590,14 @@ class DownloadJob:
except DownloadCancelled:
return None
except DownloadFailed as error:
logger.error(f"[{track['mainArtist']['name']} - {track['title']}] {error.message}")
logger.error(f"[{track['artist']} - {track['title']}] {error.message}")
result = {'error': {
'message': error.message,
'errid': error.errid,
'data': track
}}
except Exception as e:
logger.exception(str(e))
logger.exception(f"[{track['artist']} - {track['title']}] {str(e)}")
result = {'error': {
'message': str(e),
'data': track
@ -611,10 +606,10 @@ class DownloadJob:
if 'error' in result:
self.completeTrackPercentage()
self.queueItem.failed += 1
self.queueItem.errors.append(error.message)
if interface:
self.queueItem.errors.append(result['error']['message'])
if self.interface:
error = result['error']
interface.send("updateQueue", {
self.interface.send("updateQueue", {
'uuid': self.queueItem.uuid,
'failed': True,
'data': error['data'],

View File

@ -4,43 +4,43 @@ class QueueItem:
def __init__(self, id=None, bitrate=None, title=None, artist=None, cover=None, size=None, type=None, settings=None, queueItemList=None):
if queueItemList:
self.title = queueItemList['title']
self.artist = queueItemList['artist']
self.cover = queueItemList['cover']
self.size = queueItemList['size']
self.type = queueItemList['type']
self.id = queueItemList['id']
self.bitrate = queueItemList['bitrate']
self.artist = queueItemList['artist']
self.cover = queueItemList['cover']
self.size = queueItemList['size']
self.type = queueItemList['type']
self.id = queueItemList['id']
self.bitrate = queueItemList['bitrate']
self.settings = queueItemList['settings']
else:
self.title = title
self.artist = artist
self.cover = cover
self.size = size
self.type = type
self.id = id
self.bitrate = bitrate
self.artist = artist
self.cover = cover
self.size = size
self.type = type
self.id = id
self.bitrate = bitrate
self.settings = settings
self.downloaded = 0
self.failed = 0
self.downloaded = 0
self.failed = 0
self.errors = []
self.progress = 0
self.uuid = f"{self.type}_{self.id}_{self.bitrate}"
self.progress = 0
self.uuid = f"{self.type}_{self.id}_{self.bitrate}"
self.cancel = False
def toDict(self):
return {
'title': self.title,
'artist': self.artist,
'cover': self.cover,
'size': self.size,
'downloaded': self.downloaded,
'failed': self.failed,
'artist': self.artist,
'cover': self.cover,
'size': self.size,
'downloaded': self.downloaded,
'failed': self.failed,
'errors': self.errors,
'progress': self.progress,
'type': self.type,
'id': self.id,
'bitrate': self.bitrate,
'uuid': self.uuid
'progress': self.progress,
'type': self.type,
'id': self.id,
'bitrate': self.bitrate,
'uuid': self.uuid
}
def getResettedItem(self):
@ -87,13 +87,13 @@ class QICollection(QueueItem):
queueItem['collection'] = self.collection
return queueItem
class QIConvertable(QueueItem):
class QIConvertable(QICollection):
def __init__(self, id=None, bitrate=None, title=None, artist=None, cover=None, size=None, type=None, settings=None, extra=None, queueItemList=None):
if queueItemList:
super().__init__(queueItemList=queueItemList)
self.extra = queueItemList['_EXTRA']
else:
super().__init__(id, bitrate, title, artist, cover, size, type, settings)
super().__init__(id, bitrate, title, artist, cover, size, type, settings, [])
self.extra = extra
def toDict(self):

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
from deemix.app.downloader import download
from deemix.app.downloadjob import DownloadJob
from deemix.utils.misc import getIDFromLink, getTypeFromLink, getBitrateInt
from deemix.api.deezer import APIError
from spotipy.exceptions import SpotifyException
@ -35,7 +35,7 @@ class QueueManager:
if 'id' in trackAPI and 'title' in trackAPI:
id = trackAPI['id']
else:
return QueueError(url, "Track ISRC is not available on deezer", "ISRCnotOnDeezer")
except APIError as e:
e = json.loads(str(e))
return QueueError(url, f"Wrong URL: {e['type']+': ' if 'type' in e else ''}{e['message'] if 'message' in e else ''}")
@ -303,7 +303,7 @@ class QueueManager:
try:
playlist = sp.generate_playlist_queueitem(dz, id, settings)
playlist['bitrate'] = bitrate
playlist.bitrate = bitrate
return playlist
except SpotifyException as e:
return QueueError(url, "Wrong URL: "+e.msg[e.msg.find('\n')+2:])
@ -317,12 +317,14 @@ class QueueManager:
if interface:
interface.send("loginNeededToDownload")
return False
def parseLink(link):
link = link.strip()
if link == "":
return False
logger.info("Generating queue item for: "+link)
return self.generateQueueItem(dz, sp, link, settings, bitrate, interface=interface)
if type(url) is list:
queueItem = []
for link in url:
@ -339,6 +341,7 @@ class QueueManager:
queueItem = parseLink(url)
if not queueItem:
return False
if type(queueItem) is list:
ogLen = len(self.queue)
for x in queueItem:
@ -369,6 +372,7 @@ class QueueManager:
logger.info(f"[{queueItem.uuid}] Added to queue.")
self.queue.append(queueItem.uuid)
self.queueList[queueItem.uuid] = queueItem
self.nextItem(dz, sp, interface)
return True
@ -383,7 +387,7 @@ class QueueManager:
if interface:
interface.send("startDownload", self.currentItem)
logger.info(f"[{self.currentItem}] Started downloading.")
download(dz, sp, self.queueList[self.currentItem], interface)
DownloadJob(dz, sp, self.queueList[self.currentItem]).start()
self.afterDownload(dz, sp, interface)
def afterDownload(self, dz, sp, interface):

View File

@ -213,7 +213,7 @@ class SpotifyHelper:
if not 'explicit' in playlistAPI:
playlistAPI['explicit'] = False
extra['playlistAPI'] = playlistAPI
return QICollection(
return QIConvertable(
playlist_id,
0,
spotify_playlist['name'],
@ -225,7 +225,7 @@ class SpotifyHelper:
extra,
)
def convert_spotify_playlist(self, dz, item, settings, interface=None):
def convert_spotify_playlist(self, dz, queueItem, interface=None):
convertPercentage = 0
lastPercentage = 0
if path.isfile(path.join(self.configFolder, 'spotifyCache.json')):
@ -234,13 +234,13 @@ class SpotifyHelper:
else:
cache = {'tracks': {}, 'albums': {}}
if interface:
interface.send("startConversion", item.uuid)
interface.send("startConversion", queueItem.uuid)
collection = []
for pos, track in enumerate(item.extra['unconverted'], start=1):
for pos, track in enumerate(queueItem.extra['unconverted'], start=1):
if str(track['id']) in cache['tracks']:
trackID = cache['tracks'][str(track['id'])]
else:
trackID = self.get_trackid_spotify(dz, 0, settings['fallbackSearch'], track)
trackID = self.get_trackid_spotify(dz, 0, queueItem.settings['fallbackSearch'], track)
cache['tracks'][str(track['id'])] = trackID
if trackID == 0:
deezerTrack = {
@ -257,35 +257,25 @@ class SpotifyHelper:
}
else:
deezerTrack = dz.get_track_gw(trackID)
deezerTrack['_EXTRA_PLAYLIST'] = item.extra['playlistAPI']
deezerTrack['_EXTRA_PLAYLIST'] = queueItem.extra['playlistAPI']
deezerTrack['POSITION'] = pos
deezerTrack['SIZE'] = item.size
deezerTrack['FILENAME_TEMPLATE'] = settings['playlistTracknameTemplate']
deezerTrack['SIZE'] = queueItem.size
deezerTrack['FILENAME_TEMPLATE'] = queueItem.settings['playlistTracknameTemplate']
collection.append(deezerTrack)
convertPercentage = (pos / item.size) * 100
print(convertPercentage)
convertPercentage = (pos / queueItem.size) * 100
if round(convertPercentage) != lastPercentage and round(convertPercentage) % 2 == 0:
lastPercentage = round(convertPercentage)
if interface:
interface.send("updateQueue", {'uuid': item.uuid, 'conversion': lastPercentage})
interface.send("updateQueue", {'uuid': queueItem.uuid, 'conversion': lastPercentage})
queueItem.extra = None
queueItem.collection = collection
item = QICollection(
item.id,
item.bitrate,
item.title,
item.artist,
item.cover,
item.size,
item.type,
item.settings,
collection,
)
with open(path.join(self.configFolder, 'spotifyCache.json'), 'w') as spotifyCache:
json.dump(cache, spotifyCache)
if interface:
interface.send("startDownload", item['uuid'])
interface.send("startDownload", queueItem.uuid)
def get_user_playlists(self, user):
if not self.spotifyEnabled:

View File

@ -13,7 +13,7 @@ class Track:
self.title = trackAPI_gw['SNG_TITLE'].strip()
if 'VERSION' in trackAPI_gw and trackAPI_gw['VERSION'] and not trackAPI_gw['VERSION'] in trackAPI_gw['SNG_TITLE']:
track.title += " " + trackAPI_gw['VERSION'].strip()
self.title += " " + trackAPI_gw['VERSION'].strip()
self.position = None
if 'POSITION' in trackAPI_gw:
@ -87,7 +87,7 @@ class Track:
self.album['bitrate'] = 0
self.album['dateString'] = None
self.artistsString
self.artistsString = ""
def parseEssentialData(self, dz, trackAPI_gw):
self.id = trackAPI_gw['SNG_ID']
@ -97,7 +97,7 @@ class Track:
self.fallbackId = "0"
if 'FALLBACK' in trackAPI_gw:
self.fallbackId = trackAPI_gw['FALLBACK']['SNG_ID']
self.formats = dz.get_track_filesizes(track["id"])
self.filesizes = dz.get_track_filesizes(self.id)
def parseLocalTrackData(self, trackAPI_gw):
self.album = {
@ -160,7 +160,7 @@ class Track:
self.trackNumber = trackAPI_gw['TRACK_NUMBER']
self.contributors = trackAPI_gw['SNG_CONTRIBUTORS']
track.lyrics = {
self.lyrics = {
'id': None,
'unsync': None,
'sync': None
@ -184,13 +184,13 @@ class Track:
self.lyrics['sync'] += lastTimestamp
self.lyrics['sync'] += trackAPI_gw["LYRICS"]["LYRICS_SYNC_JSON"][i]["line"] + "\r\n"
track.mainArtist = {
self.mainArtist = {
'id': trackAPI_gw['ART_ID'],
'name': trackAPI_gw['ART_NAME'],
'pic': None
}
if 'ART_PICTURE' in trackAPI_gw:
track.mainArtist['pic'] = trackAPI_gw['ART_PICTURE']
self.mainArtist['pic'] = trackAPI_gw['ART_PICTURE']
self.date = None
if 'PHYSICAL_RELEASE_DATE' in trackAPI_gw:
@ -261,7 +261,7 @@ class Track:
if 'copyright' in albumAPI:
self.copyright = albumAPI['copyright']
if not track.album['pic']:
if not self.album['pic']:
self.album['pic'] = albumAPI['cover_small'][albumAPI['cover_small'].find('cover/') + 6:-24]
if 'genres' in albumAPI and 'data' in albumAPI['genres'] and len(albumAPI['genres']['data']) > 0:

View File

@ -50,7 +50,6 @@ def andCommaConcat(lst):
result = ""
for i, art in enumerate(lst):
result += art
track['commaArtistsString'] += art
if tot != i + 1:
if tot - 1 == i + 1:
result += " & "

View File

@ -130,10 +130,10 @@ def generateFilepath(track, trackAPI, settings):
def settingsRegex(filename, track, settings, playlist=None):
filename = filename.replace("%title%", fixName(track.title, settings['illegalCharacterReplacer']))
filename = filename.replace("%artist%", fixName(track.mainArtist['name'], settings['illegalCharacterReplacer']))
filename = filename.replace("%artists%", fixName(track.commaArtistsString, settings['illegalCharacterReplacer']))
filename = filename.replace("%artists%", fixName(", ".join(track.artists), settings['illegalCharacterReplacer']))
filename = filename.replace("%allartists%", fixName(track.artistsString, settings['illegalCharacterReplacer']))
filename = filename.replace("%mainartists%", fixName(track.mainArtistsString, settings['illegalCharacterReplacer']))
filename = filename.replace("%featartists%", fixName('('+track.featArtistsString+')', settings['illegalCharacterReplacer']) if 'featArtistsString' in track else "")
filename = filename.replace("%featartists%", fixName('('+track.featArtistsString+')', settings['illegalCharacterReplacer']) if track.featArtistsString else "")
filename = filename.replace("%album%", fixName(track.album['title'], settings['illegalCharacterReplacer']))
filename = filename.replace("%albumartist%",
fixName(track.album['mainArtist']['name'], settings['illegalCharacterReplacer']))

View File

@ -75,7 +75,7 @@ def tagID3(stream, track, save):
if save['copyright']:
tag.add(TCOP(text=track.copyright))
if save['savePlaylistAsCompilation'] and "playlist" in track:
if save['savePlaylistAsCompilation'] and track.playlist:
tag.add(TCMP(text="1"))
if save['cover'] and track.album['picPath']:
@ -155,7 +155,7 @@ def tagFLAC(stream, track, save):
if save['copyright']:
tag["COPYRIGHT"] = track.copyright
if save['savePlaylistAsCompilation'] and "playlist" in track:
if save['savePlaylistAsCompilation'] and track.playlist:
tag["COMPILATION"] = "1"
if save['cover'] and track.album['picPath']: