Made the refactoring work
This commit is contained in:
parent
4cfdc4872d
commit
34263c150f
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'],
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
|
@ -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:
|
|
@ -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:
|
|
@ -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 += " & "
|
||||
|
|
|
@ -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']))
|
||||
|
|
|
@ -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']:
|
||||
|
|
Loading…
Reference in New Issue