Cleaned up downloadjob.py

This commit is contained in:
RemixDev 2020-10-02 18:57:23 +02:00
parent 66be97bec4
commit 431a558467
2 changed files with 113 additions and 105 deletions

View File

@ -1,5 +1,8 @@
import eventlet import eventlet
from eventlet.green.subprocess import call as execute from eventlet.green.subprocess import call as execute
requests = eventlet.import_patched('requests')
get = requests.get
request_exception = requests.exceptions
from os.path import sep as pathSep from os.path import sep as pathSep
from pathlib import Path from pathlib import Path
@ -7,10 +10,6 @@ from shlex import quote
import re import re
import errno import errno
requests = eventlet.import_patched('requests')
get = requests.get
request_exception = requests.exceptions
from ssl import SSLError from ssl import SSLError
from os import makedirs from os import makedirs
from tempfile import gettempdir from tempfile import gettempdir
@ -30,8 +29,7 @@ logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('deemix') logger = logging.getLogger('deemix')
TEMPDIR = Path(gettempdir()) / 'deemix-imgs' TEMPDIR = Path(gettempdir()) / 'deemix-imgs'
if not TEMPDIR.is_dir(): if not TEMPDIR.is_dir(): makedirs(TEMPDIR)
makedirs(TEMPDIR)
extensions = { extensions = {
9: '.flac', 9: '.flac',
@ -117,11 +115,13 @@ class DownloadJob:
self.playlistURLs = [] self.playlistURLs = []
def start(self): def start(self):
if not self.queueItem.cancel: if self.queueItem.cancel:
self.interface.send('currentItemCancelled', self.queueItem.uuid)
self.interface.send("removedFromQueue", self.queueItem.uuid)
return None
if isinstance(self.queueItem, QISingle): if isinstance(self.queueItem, QISingle):
result = self.downloadWrapper(self.queueItem.single) result = self.downloadWrapper(self.queueItem.single)
if result: if result: self.singleAfterDownload(result)
self.singleAfterDownload(result)
elif isinstance(self.queueItem, QICollection): elif isinstance(self.queueItem, QICollection):
tracks = [None] * len(self.queueItem.collection) tracks = [None] * len(self.queueItem.collection)
pool = eventlet.GreenPool(size=self.settings['queueConcurrency']) pool = eventlet.GreenPool(size=self.settings['queueConcurrency'])
@ -129,32 +129,28 @@ class DownloadJob:
tracks[pos] = pool.spawn(self.downloadWrapper, track) tracks[pos] = pool.spawn(self.downloadWrapper, track)
pool.waitall() pool.waitall()
self.collectionAfterDownload(tracks) self.collectionAfterDownload(tracks)
if self.interface: if self.interface: self.interface.send("finishDownload", self.queueItem.uuid)
if self.queueItem.cancel:
self.interface.send('currentItemCancelled', self.queueItem.uuid)
self.interface.send("removedFromQueue", self.queueItem.uuid)
else:
self.interface.send("finishDownload", self.queueItem.uuid)
return self.extrasPath return self.extrasPath
def singleAfterDownload(self, result): def singleAfterDownload(self, result):
if not self.extrasPath: if not self.extrasPath: self.extrasPath = Path(self.settings['downloadLocation'])
self.extrasPath = Path(self.settings['downloadLocation'])
# Save Album Cover # Save Album Cover
if self.settings['saveArtwork'] and 'albumPath' in result: if self.settings['saveArtwork'] and 'albumPath' in result:
for image in result['albumURLs']: for image in result['albumURLs']:
downloadImage(image['url'], result['albumPath'] / f"{result['albumFilename']}.{image['ext']}", self.settings['overwriteFile']) downloadImage(image['url'], result['albumPath'] / f"{result['albumFilename']}.{image['ext']}", self.settings['overwriteFile'])
# Save Artist Artwork # Save Artist Artwork
if self.settings['saveArtworkArtist'] and 'artistPath' in result: if self.settings['saveArtworkArtist'] and 'artistPath' in result:
for image in result['artistURLs']: for image in result['artistURLs']:
downloadImage(image['url'], result['artistPath'] / f"{result['artistFilename']}.{image['ext']}", self.settings['overwriteFile']) downloadImage(image['url'], result['artistPath'] / f"{result['artistFilename']}.{image['ext']}", self.settings['overwriteFile'])
# Create searched logfile # Create searched logfile
if self.settings['logSearched'] and 'searched' in result: if self.settings['logSearched'] and 'searched' in result:
with open(self.extrasPath / 'searched.txt', 'wb+') as f: with open(self.extrasPath / 'searched.txt', 'wb+') as f:
orig = f.read().decode('utf-8') orig = f.read().decode('utf-8')
if not result['searched'] in orig: if not result['searched'] in orig:
if orig != "": if orig != "": orig += "\r\n"
orig += "\r\n"
orig += result['searched'] + "\r\n" orig += result['searched'] + "\r\n"
f.write(orig.encode('utf-8')) f.write(orig.encode('utf-8'))
# Execute command after download # Execute command after download
@ -162,56 +158,58 @@ class DownloadJob:
execute(self.settings['executeCommand'].replace("%folder%", quote(str(self.extrasPath))).replace("%filename%", quote(result['filename'])), shell=True) execute(self.settings['executeCommand'].replace("%folder%", quote(str(self.extrasPath))).replace("%filename%", quote(result['filename'])), shell=True)
def collectionAfterDownload(self, tracks): def collectionAfterDownload(self, tracks):
if not self.extrasPath: if not self.extrasPath: self.extrasPath = Path(self.settings['downloadLocation'])
self.extrasPath = Path(self.settings['downloadLocation'])
playlist = [None] * len(tracks) playlist = [None] * len(tracks)
errors = "" errors = ""
searched = "" searched = ""
for index in range(len(tracks)): for i in range(len(tracks)):
result = tracks[index].wait() result = tracks[i].wait()
# Check if queue is cancelled if not result: return None # Check if item is cancelled
if not result:
return None
# Log errors to file # Log errors to file
if 'error' in result: if result.get('error'):
if not 'data' in result['error']: if not result['error'].get('data'): result['error']['data'] = {'id': "0", 'title': 'Unknown', 'artist': 'Unknown'}
result['error']['data'] = {'id': "0", 'title': 'Unknown', 'artist': 'Unknown'}
errors += f"{result['error']['data']['id']} | {result['error']['data']['artist']} - {result['error']['data']['title']} | {result['error']['message']}\r\n" errors += f"{result['error']['data']['id']} | {result['error']['data']['artist']} - {result['error']['data']['title']} | {result['error']['message']}\r\n"
# Log searched to file # Log searched to file
if 'searched' in result: if 'searched' in result: searched += result['searched'] + "\r\n"
searched += result['searched'] + "\r\n"
# Save Album Cover # Save Album Cover
if self.settings['saveArtwork'] and 'albumPath' in result: if self.settings['saveArtwork'] and 'albumPath' in result:
for image in result['albumURLs']: for image in result['albumURLs']:
downloadImage(image['url'], result['albumPath'] / f"{result['albumFilename']}.{image['ext']}", self.settings['overwriteFile']) downloadImage(image['url'], result['albumPath'] / f"{result['albumFilename']}.{image['ext']}", self.settings['overwriteFile'])
# Save Artist Artwork # Save Artist Artwork
if self.settings['saveArtworkArtist'] and 'artistPath' in result: if self.settings['saveArtworkArtist'] and 'artistPath' in result:
for image in result['artistURLs']: for image in result['artistURLs']:
downloadImage(image['url'], result['artistPath'] / f"{result['artistFilename']}.{image['ext']}", self.settings['overwriteFile']) downloadImage(image['url'], result['artistPath'] / f"{result['artistFilename']}.{image['ext']}", self.settings['overwriteFile'])
# Save filename for playlist file # Save filename for playlist file
playlist[index] = "" playlist[i] = result.get('filename', "")
if 'filename' in result:
playlist[index] = result['filename']
# Create errors logfile # Create errors logfile
if self.settings['logErrors'] and errors != "": if self.settings['logErrors'] and errors != "":
with open(self.extrasPath / 'errors.txt', 'wb') as f: with open(self.extrasPath / 'errors.txt', 'wb') as f:
f.write(errors.encode('utf-8')) f.write(errors.encode('utf-8'))
# Create searched logfile # Create searched logfile
if self.settings['logSearched'] and searched != "": if self.settings['logSearched'] and searched != "":
with open(self.extrasPath / 'searched.txt', 'wb') as f: with open(self.extrasPath / 'searched.txt', 'wb') as f:
f.write(searched.encode('utf-8')) f.write(searched.encode('utf-8'))
# Save Playlist Artwork # Save Playlist Artwork
if self.settings['saveArtwork'] and self.playlistCoverName and not self.settings['tags']['savePlaylistAsCompilation']: if self.settings['saveArtwork'] and self.playlistCoverName and not self.settings['tags']['savePlaylistAsCompilation']:
for image in self.playlistURLs: for image in self.playlistURLs:
downloadImage(image['url'], self.extrasPath / f"{self.playlistCoverName}.{image['ext']}", self.settings['overwriteFile']) downloadImage(image['url'], self.extrasPath / f"{self.playlistCoverName}.{image['ext']}", self.settings['overwriteFile'])
# Create M3U8 File # Create M3U8 File
if self.settings['createM3U8File']: if self.settings['createM3U8File']:
filename = settingsRegexPlaylistFile(self.settings['playlistFilenameTemplate'], self.queueItem, self.settings) or "playlist" filename = settingsRegexPlaylistFile(self.settings['playlistFilenameTemplate'], self.queueItem, self.settings) or "playlist"
with open(self.extrasPath / f'{filename}.m3u8', 'wb') as f: with open(self.extrasPath / f'{filename}.m3u8', 'wb') as f:
for line in playlist: for line in playlist:
f.write((line + "\n").encode('utf-8')) f.write((line + "\n").encode('utf-8'))
# Execute command after download # Execute command after download
if self.settings['executeCommand'] != "": if self.settings['executeCommand'] != "":
execute(self.settings['executeCommand'].replace("%folder%", quote(str(self.extrasPath))), shell=True) execute(self.settings['executeCommand'].replace("%folder%", quote(str(self.extrasPath))), shell=True)
@ -219,9 +217,7 @@ class DownloadJob:
def download(self, trackAPI_gw, track=None): def download(self, trackAPI_gw, track=None):
result = {} result = {}
if self.queueItem.cancel: raise DownloadCancelled if self.queueItem.cancel: raise DownloadCancelled
if trackAPI_gw['SNG_ID'] == "0": raise DownloadFailed("notOnDeezer")
if trackAPI_gw['SNG_ID'] == "0":
raise DownloadFailed("notOnDeezer")
# Create Track object # Create Track object
if not track: if not track:
@ -237,6 +233,7 @@ class DownloadJob:
raise DownloadError('albumDoesntExsists') raise DownloadError('albumDoesntExsists')
if self.queueItem.cancel: raise DownloadCancelled if self.queueItem.cancel: raise DownloadCancelled
# Check if track not yet encoded
if track.MD5 == '': if track.MD5 == '':
if track.fallbackId != "0": if track.fallbackId != "0":
logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not yet encoded, using fallback id") logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not yet encoded, using fallback id")
@ -266,8 +263,9 @@ class DownloadJob:
else: else:
raise DownloadFailed("notEncoded") raise DownloadFailed("notEncoded")
try:
selectedFormat = self.getPreferredBitrate(track) selectedFormat = self.getPreferredBitrate(track)
if selectedFormat == -100: except PreferredBitrateNotFound:
if track.fallbackId != "0": if track.fallbackId != "0":
logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not found at desired bitrate, using fallback id") logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not found at desired bitrate, using fallback id")
newTrack = self.dz.get_track_gw(track.fallbackId) newTrack = self.dz.get_track_gw(track.fallbackId)
@ -295,10 +293,13 @@ class DownloadJob:
raise DownloadFailed("wrongBitrateNoAlternative") raise DownloadFailed("wrongBitrateNoAlternative")
else: else:
raise DownloadFailed("wrongBitrate") raise DownloadFailed("wrongBitrate")
elif selectedFormat == -200: except TrackNot360:
raise DownloadFailed("no360RA") raise DownloadFailed("no360RA")
track.selectedFormat = selectedFormat track.selectedFormat = selectedFormat
imageQuality = f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg'
if self.settings['embeddedArtworkPNG']: imageQuality = 'none-100-0-0.png'
if self.settings['tags']['savePlaylistAsCompilation'] and track.playlist: if self.settings['tags']['savePlaylistAsCompilation'] and track.playlist:
track.trackNumber = track.position track.trackNumber = track.position
track.discNumber = "1" track.discNumber = "1"
@ -308,23 +309,25 @@ class DownloadJob:
track.playlist['picType'], track.playlist['picType'],
track.playlist['pic'], track.playlist['pic'],
self.settings['embeddedArtworkSize'], self.settings['embeddedArtworkSize'], self.settings['embeddedArtworkSize'], self.settings['embeddedArtworkSize'],
'none-100-0-0.png' if self.settings['embeddedArtworkPNG'] else f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg' imageQuality
) )
else: else:
track.playlist['picUrl'] = track.playlist['pic'] track.playlist['picUrl'] = track.playlist['pic']
ext = track.playlist['picUrl'][-4:] ext = track.playlist['picUrl'][-4:]
if ext[0] != ".": if ext[0] != ".": ext = ".jpg"
ext = ".jpg"
track.album['picPath'] = TEMPDIR / f"pl{trackAPI_gw['_EXTRA_PLAYLIST']['id']}_{self.settings['embeddedArtworkSize']}{ext}" track.album['picPath'] = TEMPDIR / f"pl{trackAPI_gw['_EXTRA_PLAYLIST']['id']}_{self.settings['embeddedArtworkSize']}{ext}"
else: else:
if track.album['date']: if track.album['date']: track.date = track.album['date']
track.date = track.album['date']
track.album['picUrl'] = "https://e-cdns-images.dzcdn.net/images/cover/{}/{}x{}-{}".format( track.album['picUrl'] = "https://e-cdns-images.dzcdn.net/images/cover/{}/{}x{}-{}".format(
track.album['pic'], track.album['pic'],
self.settings['embeddedArtworkSize'], self.settings['embeddedArtworkSize'], self.settings['embeddedArtworkSize'], self.settings['embeddedArtworkSize'],
'none-100-0-0.png' if self.settings['embeddedArtworkPNG'] else f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg' imageQuality
) )
track.album['picPath'] = TEMPDIR / f"alb{track.album['id']}_{self.settings['embeddedArtworkSize']}{track.album['picUrl'][-4:]}" track.album['picPath'] = TEMPDIR / f"alb{track.album['id']}_{self.settings['embeddedArtworkSize']}{track.album['picUrl'][-4:]}"
track.album['bitrate'] = selectedFormat track.album['bitrate'] = selectedFormat
track.dateString = formatDate(track.date, self.settings['dateFormat']) track.dateString = formatDate(track.date, self.settings['dateFormat'])
@ -393,17 +396,16 @@ class DownloadJob:
track.album['picType'], track.album['picType'],
track.album['pic'], track.album['pic'],
self.settings['localArtworkSize'], self.settings['localArtworkSize'], self.settings['localArtworkSize'], self.settings['localArtworkSize'],
'none-100-0-0.png' if format == "png" else f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg' imageQuality
) )
else: else:
url = track.album['pic'] url = track.album['pic']
if format != "jpg": if format != "jpg": continue
continue
else: else:
url = "https://e-cdns-images.dzcdn.net/images/cover/{}/{}x{}-{}".format( url = "https://e-cdns-images.dzcdn.net/images/cover/{}/{}x{}-{}".format(
track.album['pic'], track.album['pic'],
self.settings['localArtworkSize'], self.settings['localArtworkSize'], self.settings['localArtworkSize'], self.settings['localArtworkSize'],
'none-100-0-0.png' if format == "png" else f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg' imageQuality
) )
result['albumURLs'].append({'url': url, 'ext': format}) result['albumURLs'].append({'url': url, 'ext': format})
result['albumPath'] = coverPath result['albumPath'] = coverPath
@ -418,12 +420,14 @@ class DownloadJob:
if track.album['mainArtist']['pic'] != "": if track.album['mainArtist']['pic'] != "":
url = "https://e-cdns-images.dzcdn.net/images/artist/{}/{}x{}-{}".format( url = "https://e-cdns-images.dzcdn.net/images/artist/{}/{}x{}-{}".format(
track.album['mainArtist']['pic'], self.settings['localArtworkSize'], self.settings['localArtworkSize'], track.album['mainArtist']['pic'], self.settings['localArtworkSize'], self.settings['localArtworkSize'],
'none-100-0-0.png' if format == "png" else f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg') imageQuality
elif format == "jpg": )
elif format == "jpg": # Blank artist image is not available in PNG
url = "https://e-cdns-images.dzcdn.net/images/artist//{}x{}-{}".format( url = "https://e-cdns-images.dzcdn.net/images/artist//{}x{}-{}".format(
self.settings['localArtworkSize'], self.settings['localArtworkSize'], f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg') self.settings['localArtworkSize'], self.settings['localArtworkSize'],
if url: f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg'
result['artistURLs'].append({'url': url, 'ext': format}) )
if url: result['artistURLs'].append({'url': url, 'ext': format})
result['artistPath'] = artistPath result['artistPath'] = artistPath
result['artistFilename'] = f"{settingsRegexArtist(self.settings['artistImageTemplate'], track.album['mainArtist'], self.settings)}" result['artistFilename'] = f"{settingsRegexArtist(self.settings['artistImageTemplate'], track.album['mainArtist'], self.settings)}"
@ -444,13 +448,16 @@ class DownloadJob:
f.write(track.lyrics['sync'].encode('utf-8')) f.write(track.lyrics['sync'].encode('utf-8'))
trackAlreadyDownloaded = writepath.is_file() trackAlreadyDownloaded = writepath.is_file()
# Don't overwrite and don't mind extension
if not trackAlreadyDownloaded and self.settings['overwriteFile'] == 'e': if not trackAlreadyDownloaded and self.settings['overwriteFile'] == 'e':
exts = ['.mp3', '.flac', '.opus', '.m4a'] exts = ['.mp3', '.flac', '.opus', '.m4a']
baseFilename = str(filepath / filename) baseFilename = str(filepath / filename)
for ext in exts: for ext in exts:
trackAlreadyDownloaded = Path(baseFilename+ext).is_file() trackAlreadyDownloaded = Path(baseFilename+ext).is_file()
if trackAlreadyDownloaded: if trackAlreadyDownloaded: break
break
# Don't overwrite and keep both files
if trackAlreadyDownloaded and self.settings['overwriteFile'] == 'b': if trackAlreadyDownloaded and self.settings['overwriteFile'] == 'b':
baseFilename = str(filepath / filename) baseFilename = str(filepath / filename)
i = 1 i = 1
@ -461,7 +468,6 @@ class DownloadJob:
trackAlreadyDownloaded = False trackAlreadyDownloaded = False
writepath = Path(currentFilename) writepath = Path(currentFilename)
if extrasPath: if extrasPath:
if not self.extrasPath: self.extrasPath = extrasPath if not self.extrasPath: self.extrasPath = extrasPath
result['filename'] = str(writepath)[len(str(extrasPath))+ len(pathSep):] result['filename'] = str(writepath)[len(str(extrasPath))+ len(pathSep):]
@ -476,7 +482,7 @@ class DownloadJob:
track.playlist['picType'], track.playlist['picType'],
track.playlist['pic'], track.playlist['pic'],
self.settings['localArtworkSize'], self.settings['localArtworkSize'], self.settings['localArtworkSize'], self.settings['localArtworkSize'],
'none-100-0-0.png' if format == "png" else f'000000-{self.settings["jpegImageQuality"]}-0-0.jpg' imageQuality
) )
self.playlistURLs.append({'url': url, 'ext': format}) self.playlistURLs.append({'url': url, 'ext': format})
else: else:
@ -548,13 +554,10 @@ class DownloadJob:
try: try:
trackDownloaded = downloadMusic(track, trackAPI_gw) trackDownloaded = downloadMusic(track, trackAPI_gw)
except DownloadFailed as e:
raise e
except Exception as e: except Exception as e:
raise e raise e
if not trackDownloaded: if not trackDownloaded: return self.download(trackAPI_gw, track)
return self.download(trackAPI_gw, track)
else: else:
logger.info(f"[{track.mainArtist['name']} - {track.title}] Skipping track as it's already downloaded") logger.info(f"[{track.mainArtist['name']} - {track.title}] Skipping track as it's already downloaded")
self.completeTrackPercentage() self.completeTrackPercentage()
@ -574,9 +577,8 @@ class DownloadJob:
track.filesizes['FILESIZE_FLAC'] = "0" track.filesizes['FILESIZE_FLAC'] = "0"
track.filesizes['FILESIZE_FLAC_TESTED'] = True track.filesizes['FILESIZE_FLAC_TESTED'] = True
return self.download(trackAPI_gw, track) return self.download(trackAPI_gw, track)
if track.searched:
result['searched'] = f"{track.mainArtist['name']} - {track.title}"
if track.searched: result['searched'] = f"{track.mainArtist['name']} - {track.title}"
logger.info(f"[{track.mainArtist['name']} - {track.title}] Track download completed\n{str(writepath)}") logger.info(f"[{track.mainArtist['name']} - {track.title}] Track download completed\n{str(writepath)}")
self.queueItem.downloaded += 1 self.queueItem.downloaded += 1
self.queueItem.files.append(str(writepath)) self.queueItem.files.append(str(writepath))
@ -586,10 +588,9 @@ class DownloadJob:
return result return result
def getPreferredBitrate(self, track): def getPreferredBitrate(self, track):
if track.localTrack: if track.localTrack: return 0
return 0
fallback = self.settings['fallbackBitrate'] shouldFallback = self.settings['fallbackBitrate']
falledBack = False falledBack = False
formats_non_360 = { formats_non_360 = {
@ -603,30 +604,34 @@ class DownloadJob:
13: "MP4_RA1", 13: "MP4_RA1",
} }
if not fallback: is360format = int(self.bitrate) in formats_360
error_num = -100
if not shouldFallback:
formats = formats_360 formats = formats_360
formats.update(formats_non_360) formats.update(formats_non_360)
elif int(self.bitrate) in formats_360: elif is360format:
error_num = -200
formats = formats_360 formats = formats_360
else: else:
error_num = 8
formats = formats_non_360 formats = formats_non_360
for format_num, format in formats.items(): for formatNumber, formatName in formats.items():
if format_num <= int(self.bitrate): if formatNumber <= int(self.bitrate):
if f"FILESIZE_{format}" in track.filesizes: if f"FILESIZE_{formatName}" in track.filesizes:
if int(track.filesizes[f"FILESIZE_{format}"]) != 0: if int(track.filesizes[f"FILESIZE_{formatName}"]) != 0: return formatNumber
return format_num if not track.filesizes[f"FILESIZE_{formatName}_TESTED"]:
elif not track.filesizes[f"FILESIZE_{format}_TESTED"]: request = requests.head(
request = requests.head(self.dz.get_track_stream_url(track.id, track.MD5, track.mediaVersion, format_num), headers={'User-Agent': USER_AGENT_HEADER}, timeout=30) self.dz.get_track_stream_url(track.id, track.MD5, track.mediaVersion, formatNumber),
headers={'User-Agent': USER_AGENT_HEADER},
timeout=30
)
try: try:
request.raise_for_status() request.raise_for_status()
return format_num return formatNumber
except request_exception.HTTPError: # if the format is not available, Deezer returns a 403 error except request_exception.HTTPError: # if the format is not available, Deezer returns a 403 error
pass pass
if fallback: if not shouldFallback:
raise PreferredBitrateNotFound
else:
if not falledBack: if not falledBack:
falledBack = True falledBack = True
logger.info(f"[{track.mainArtist['name']} - {track.title}] Fallback to lower bitrate") logger.info(f"[{track.mainArtist['name']} - {track.title}] Fallback to lower bitrate")
@ -640,18 +645,14 @@ class DownloadJob:
'artist': track.mainArtist['name'] 'artist': track.mainArtist['name']
}, },
}) })
continue if is360format: raise TrackNot360
else: return 8
return error_num
return error_num # fallback is enabled and loop went through all formats
def streamTrack(self, stream, track, start=0): def streamTrack(self, stream, track, start=0):
if self.queueItem.cancel: raise DownloadCancelled if self.queueItem.cancel: raise DownloadCancelled
headers=dict(self.dz.http_headers) headers=dict(self.dz.http_headers)
if range != 0: if range != 0: headers['Range'] = f'bytes={start}-'
headers['Range'] = f'bytes={start}-'
chunkLength = start chunkLength = start
percentage = 0 percentage = 0
@ -664,8 +665,7 @@ class DownloadJob:
blowfish_key = str.encode(self.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"]) complete = int(request.headers["Content-Length"])
if complete == 0: if complete == 0: raise DownloadEmpty
raise DownloadEmpty
if start != 0: if start != 0:
responseRange = request.headers["Content-Range"] responseRange = request.headers["Content-Range"]
logger.info(f'{itemName} downloading range {responseRange}') logger.info(f'{itemName} downloading range {responseRange}')
@ -687,7 +687,6 @@ class DownloadJob:
else: else:
chunkProgres = (len(chunk) / (complete + start)) / self.queueItem.size * 100 chunkProgres = (len(chunk) / (complete + start)) / self.queueItem.size * 100
self.downloadPercentage += chunkProgres self.downloadPercentage += chunkProgres
self.updatePercentage() self.updatePercentage()
except SSLError as e: except SSLError as e:
@ -701,8 +700,7 @@ class DownloadJob:
if round(self.downloadPercentage) != self.lastPercentage and round(self.downloadPercentage) % 2 == 0: if round(self.downloadPercentage) != self.lastPercentage and round(self.downloadPercentage) % 2 == 0:
self.lastPercentage = round(self.downloadPercentage) self.lastPercentage = round(self.downloadPercentage)
self.queueItem.progress = self.lastPercentage self.queueItem.progress = self.lastPercentage
if self.interface: if self.interface: self.interface.send("updateQueue", {'uuid': self.queueItem.uuid, 'progress': self.lastPercentage})
self.interface.send("updateQueue", {'uuid': self.queueItem.uuid, 'progress': self.lastPercentage})
def completeTrackPercentage(self): def completeTrackPercentage(self):
if isinstance(self.queueItem, QISingle): if isinstance(self.queueItem, QISingle):
@ -721,9 +719,11 @@ class DownloadJob:
def downloadWrapper(self, trackAPI_gw): def downloadWrapper(self, trackAPI_gw):
track = { track = {
'id': trackAPI_gw['SNG_ID'], '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 ""), 'title': trackAPI_gw['SNG_TITLE'].strip(),
'artist': trackAPI_gw['ART_NAME'] 'artist': trackAPI_gw['ART_NAME']
} }
if trackAPI_gw.get('VERSION') and trackAPI_gw['VERSION'] not in trackAPI_gw['SNG_TITLE']:
track['title'] += f" {trackAPI_gw['VERSION']}".strip()
try: try:
result = self.download(trackAPI_gw) result = self.download(trackAPI_gw)
@ -772,3 +772,9 @@ class DownloadCancelled(DownloadError):
class DownloadEmpty(DownloadError): class DownloadEmpty(DownloadError):
pass pass
class PreferredBitrateNotFound(DownloadError):
pass
class TrackNot360(DownloadError):
pass

View File

@ -53,7 +53,9 @@ class QueueManager:
trackAPI_gw['SINGLE_TRACK'] = True trackAPI_gw['SINGLE_TRACK'] = True
title = f"{trackAPI_gw['SNG_TITLE']} {trackAPI_gw.get('VERSION', '')}".strip() title = trackAPI_gw['SNG_TITLE'].strip()
if trackAPI_gw.get('VERSION') and trackAPI_gw['VERSION'] not in trackAPI_gw['SNG_TITLE']:
title += f" {trackAPI_gw['VERSION']}".strip()
explicit = bool(int(trackAPI_gw.get('EXPLICIT_LYRICS', 0))) explicit = bool(int(trackAPI_gw.get('EXPLICIT_LYRICS', 0)))
return QISingle( return QISingle(