Implemented socket.io
Started work on darkmode Implemented queue system Started work on download tab
This commit is contained in:
parent
4b2d9a15f9
commit
b6956f6f6c
|
@ -268,7 +268,11 @@ class Deezer:
|
|||
i += 1
|
||||
|
||||
def stream_track(self, track_id, url, stream):
|
||||
request = requests.get(url, headers=self.http_headers, stream=True)
|
||||
try:
|
||||
request = requests.get(url, headers=self.http_headers, stream=True, timeout=30)
|
||||
except:
|
||||
time.sleep(2)
|
||||
return self.stream_track(track_id, url, stream)
|
||||
request.raise_for_status()
|
||||
blowfish_key = str.encode(self._get_blowfish_key(str(track_id)))
|
||||
i = 0
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from deemix.api.deezer import Deezer
|
||||
import deemix.utils.localpaths as localpaths
|
||||
from deemix.utils.misc import getIDFromLink, getTypeFromLink, getBitrateInt
|
||||
from deemix.app.downloader import download_track, download_album, download_playlist, download_artist, download_spotifytrack, download_spotifyalbum
|
||||
from deemix.app.queuemanager import addToQueue
|
||||
from os import system as execute
|
||||
import os.path as path
|
||||
from os import mkdir
|
||||
|
@ -31,26 +31,4 @@ def login():
|
|||
f.write(arl)
|
||||
|
||||
def downloadLink(url, settings, bitrate=None):
|
||||
forcedBitrate = getBitrateInt(bitrate)
|
||||
type = getTypeFromLink(url)
|
||||
id = getIDFromLink(url, type)
|
||||
folder = settings['downloadLocation']
|
||||
if type == None or id == None:
|
||||
print("URL not recognized")
|
||||
if type == "track":
|
||||
folder = download_track(dz, id, settings, forcedBitrate)
|
||||
elif type == "album":
|
||||
folder = download_album(dz, id, settings, forcedBitrate)
|
||||
elif type == "playlist":
|
||||
folder = download_playlist(dz, id, settings, forcedBitrate)
|
||||
elif type == "artist":
|
||||
download_artist(dz, id, settings, forcedBitrate)
|
||||
elif type == "spotifytrack":
|
||||
folder = download_spotifytrack(dz, id, settings, forcedBitrate)
|
||||
elif type == "spotifyalbum":
|
||||
folder = download_spotifyalbum(dz, id, settings, forcedBitrate)
|
||||
else:
|
||||
print("URL not supported yet")
|
||||
return None
|
||||
if settings['executeCommand'] != "":
|
||||
execute(settings['executeCommand'].replace("%folder%", folder))
|
||||
addToQueue(dz, url, settings, bitrate)
|
||||
|
|
|
@ -329,7 +329,7 @@ def getTrackData(dz, trackAPI_gw, trackAPI = None, albumAPI_gw = None, albumAPI
|
|||
|
||||
return track
|
||||
|
||||
def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack=None):
|
||||
def downloadTrackObj(dz, trackAPI, settings, bitrate, uuid, extraTrack=None, socket=None):
|
||||
result = {}
|
||||
# Get the metadata
|
||||
if extraTrack:
|
||||
|
@ -348,7 +348,7 @@ def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack=
|
|||
if not 'MD5_ORIGIN' in trackNew:
|
||||
trackNew['MD5_ORIGIN'] = dz.get_track_md5(trackNew['SNG_ID'])
|
||||
track = parseEssentialTrackData(track, trackNew)
|
||||
return downloadTrackObj(dz, trackAPI, settings, extraTrack=track)
|
||||
return downloadTrackObj(dz, trackAPI, settings, bitrate, uuid, extraTrack=track, socket=socket)
|
||||
elif not 'searched' in track and settings['fallbackSearch']:
|
||||
print("Track not yet encoded, searching for alternative")
|
||||
searchedId = dz.get_track_from_metadata(track['mainArtist']['name'], track['title'], track['album']['title'])
|
||||
|
@ -358,7 +358,7 @@ def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack=
|
|||
trackNew['MD5_ORIGIN'] = dz.get_track_md5(trackNew['SNG_ID'])
|
||||
track = parseEssentialTrackData(track, trackNew)
|
||||
track['searched'] = True
|
||||
return downloadTrackObj(dz, trackAPI, settings, extraTrack=track)
|
||||
return downloadTrackObj(dz, trackAPI, settings, bitrate, uuid, extraTrack=track, socket=socket)
|
||||
else:
|
||||
print("ERROR: Track not yet encoded and no alternative found!")
|
||||
result['error'] = {
|
||||
|
@ -375,7 +375,6 @@ def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack=
|
|||
return result
|
||||
|
||||
# Get the selected bitrate
|
||||
bitrate = overwriteBitrate if overwriteBitrate else settings['maxBitrate']
|
||||
(format, filesize) = getPreferredBitrate(track['filesize'], bitrate, settings['fallbackBitrate'])
|
||||
if format == -100:
|
||||
print("ERROR: Track not found at desired bitrate. Enable fallback to lower bitrates to fix this issue.")
|
||||
|
@ -471,14 +470,14 @@ def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack=
|
|||
if track['selectedFormat'] == 9 and settings['fallbackBitrate']:
|
||||
print("Track not available in flac, trying mp3")
|
||||
track['filesize']['flac'] = 0
|
||||
return downloadTrackObj(dz, trackAPI, settings, extraTrack=track)
|
||||
return downloadTrackObj(dz, trackAPI, settings, bitrate, uuid, extraTrack=track, socket=socket)
|
||||
elif track['fallbackId'] != 0:
|
||||
print("Track not available, using fallback id")
|
||||
trackNew = dz.get_track_gw(track['fallbackId'])
|
||||
if not 'MD5_ORIGIN' in trackNew:
|
||||
trackNew['MD5_ORIGIN'] = dz.get_track_md5(trackNew['SNG_ID'])
|
||||
track = parseEssentialTrackData(track, trackNew)
|
||||
return downloadTrackObj(dz, trackAPI, settings, extraTrack=track)
|
||||
return downloadTrackObj(dz, trackAPI, settings, bitrate, uuid, extraTrack=track, socket=socket)
|
||||
elif not 'searched' in track and settings['fallbackSearch']:
|
||||
print("Track not available, searching for alternative")
|
||||
searchedId = dz.get_track_from_metadata(track['mainArtist']['name'], track['title'], track['album']['title'])
|
||||
|
@ -488,7 +487,7 @@ def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack=
|
|||
trackNew['MD5_ORIGIN'] = dz.get_track_md5(trackNew['SNG_ID'])
|
||||
track = parseEssentialTrackData(track, trackNew)
|
||||
track['searched'] = True
|
||||
return downloadTrackObj(dz, trackAPI, settings, extraTrack=track)
|
||||
return downloadTrackObj(dz, trackAPI, settings, bitrate, uuid, extraTrack=track, socket=socket)
|
||||
else:
|
||||
print("ERROR: Track not available on deezer's servers and no alternative found!")
|
||||
result['error'] = {
|
||||
|
@ -510,8 +509,29 @@ def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack=
|
|||
if 'searched' in track:
|
||||
result['searched'] = f'{track["mainArtist"]["name"]} - {track["title"]}'
|
||||
print("Done!")
|
||||
if socket:
|
||||
socket.emit("updateQueue", {'uuid': uuid, 'downloaded': True})
|
||||
return result
|
||||
|
||||
def download(dz, queueItem, socket=None):
|
||||
settings = queueItem['settings']
|
||||
bitrate = queueItem['bitrate']
|
||||
if 'single' in queueItem:
|
||||
result = downloadTrackObj(dz, queueItem['single'], settings, bitrate, queueItem['uuid'], socket=socket)
|
||||
download_path = after_download_single(result, settings)
|
||||
elif 'collection' in queueItem:
|
||||
print("Downloading collection")
|
||||
playlist = [None] * len(queueItem['collection'])
|
||||
with ThreadPoolExecutor(settings['queueConcurrency']) as executor:
|
||||
for pos, track in enumerate(queueItem['collection'], start=0):
|
||||
playlist[pos] = executor.submit(downloadTrackObj, dz, track, settings, bitrate, queueItem['uuid'], socket=socket)
|
||||
download_path = after_download(playlist, settings)
|
||||
return {
|
||||
'dz': dz,
|
||||
'socket': socket,
|
||||
'download_path': download_path
|
||||
}
|
||||
|
||||
def after_download(tracks, settings):
|
||||
extrasPath = None
|
||||
playlist = [None] * len(tracks)
|
||||
|
@ -558,72 +578,3 @@ def after_download_single(track, settings):
|
|||
return track['extrasPath']
|
||||
else:
|
||||
return None
|
||||
|
||||
def download_track(dz, id, settings, overwriteBitrate=False):
|
||||
trackAPI = dz.get_track_gw(id)
|
||||
trackAPI['FILENAME_TEMPLATE'] = settings['tracknameTemplate']
|
||||
trackAPI['SINGLE_TRACK'] = True
|
||||
result = downloadTrackObj(dz, trackAPI, settings, overwriteBitrate)
|
||||
return after_download_single(result, settings)
|
||||
|
||||
def download_spotifytrack(dz, id, settings, overwriteBitrate=False):
|
||||
track_id = get_trackid_spotify(dz, id, settings['fallbackSearch'])
|
||||
if track_id == "Not Enabled":
|
||||
print("Spotify Features is not setted up correctly.")
|
||||
if track_id != 0:
|
||||
return download_track(dz, track_id, settings, overwriteBitrate)
|
||||
else:
|
||||
print("Track not found on deezer!")
|
||||
return None
|
||||
|
||||
def download_album(dz, id, settings, overwriteBitrate=False):
|
||||
albumAPI = dz.get_album(id)
|
||||
albumAPI_gw = dz.get_album_gw(id)
|
||||
albumAPI['nb_disk'] = albumAPI_gw['NUMBER_DISK']
|
||||
albumAPI['copyright'] = albumAPI_gw['COPYRIGHT']
|
||||
if albumAPI['nb_tracks'] == 1:
|
||||
trackAPI = dz.get_track_gw(albumAPI['tracks']['data'][0]['id'])
|
||||
trackAPI['_EXTRA_ALBUM'] = albumAPI
|
||||
trackAPI['FILENAME_TEMPLATE'] = settings['tracknameTemplate']
|
||||
trackAPI['SINGLE_TRACK'] = True
|
||||
result = downloadTrackObj(dz, trackAPI, settings, overwriteBitrate)
|
||||
return after_download_single(result, settings)
|
||||
else:
|
||||
tracksArray = dz.get_album_tracks_gw(id)
|
||||
playlist = [None] * len(tracksArray)
|
||||
with ThreadPoolExecutor(settings['queueConcurrency']) as executor:
|
||||
for pos, trackAPI in enumerate(tracksArray, start=1):
|
||||
trackAPI['_EXTRA_ALBUM'] = albumAPI
|
||||
trackAPI['POSITION'] = pos
|
||||
trackAPI['FILENAME_TEMPLATE'] = settings['albumTracknameTemplate']
|
||||
playlist[pos-1] = executor.submit(downloadTrackObj, dz, trackAPI, settings, overwriteBitrate)
|
||||
|
||||
return after_download(playlist, settings)
|
||||
|
||||
def download_spotifyalbum(dz, id, settings, overwriteBitrate=False):
|
||||
album_id = get_albumid_spotify(dz, id)
|
||||
if album_id == "Not Enabled":
|
||||
print("Spotify Features is not setted up correctly.")
|
||||
if album_id != 0:
|
||||
return download_album(dz, album_id, settings, overwriteBitrate)
|
||||
else:
|
||||
print("Album not found on deezer!")
|
||||
return None
|
||||
|
||||
def download_artist(dz, id, settings, overwriteBitrate=False):
|
||||
artistAPI = dz.get_artist_albums(id)
|
||||
for album in artistAPI['data']:
|
||||
print(f"Album: {album['title']}")
|
||||
download_album(dz, album['id'], settings, overwriteBitrate)
|
||||
|
||||
def download_playlist(dz, id, settings, overwriteBitrate=False):
|
||||
playlistAPI = dz.get_playlist(id)
|
||||
playlistTracksAPI = dz.get_playlist_tracks_gw(id)
|
||||
playlist = [None] * len(playlistTracksAPI)
|
||||
with ThreadPoolExecutor(settings['queueConcurrency']) as executor:
|
||||
for pos, trackAPI in enumerate(playlistTracksAPI, start=1):
|
||||
trackAPI['_EXTRA_PLAYLIST'] = playlistAPI
|
||||
trackAPI['POSITION'] = pos
|
||||
trackAPI['FILENAME_TEMPLATE'] = settings['playlistTracknameTemplate']
|
||||
playlist[pos-1] = executor.submit(downloadTrackObj, dz, trackAPI, settings, overwriteBitrate)
|
||||
return after_download(playlist, settings)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
from deemix.api.deezer import Deezer
|
||||
import deemix.utils.localpaths as localpaths
|
||||
from deemix.utils.misc import getIDFromLink, getTypeFromLink, getBitrateInt, isValidLink
|
||||
from deemix.app.downloader import download_track, download_album, download_playlist, download_artist, download_spotifytrack, download_spotifyalbum
|
||||
from deemix.app.queuemanager import addToQueue
|
||||
from deemix.app.settings import initSettings
|
||||
from os import system as execute
|
||||
import os.path as path
|
||||
|
@ -43,28 +42,9 @@ def mainSearch(term):
|
|||
def search(term, type, start, nb):
|
||||
return dz.search_gw(term, type, start, nb)
|
||||
|
||||
def addToQueue_link(url, bitrate=None, socket=None):
|
||||
addToQueue(dz, url, settings, bitrate, socket)
|
||||
|
||||
def downloadLink(url, bitrate=None):
|
||||
global settings
|
||||
forcedBitrate = getBitrateInt(bitrate)
|
||||
type = getTypeFromLink(url)
|
||||
id = getIDFromLink(url, type)
|
||||
folder = settings['downloadLocation']
|
||||
if type == None or id == None:
|
||||
print("URL not recognized")
|
||||
if type == "track":
|
||||
folder = download_track(dz, id, settings, forcedBitrate)
|
||||
elif type == "album":
|
||||
folder = download_album(dz, id, settings, forcedBitrate)
|
||||
elif type == "playlist":
|
||||
folder = download_playlist(dz, id, settings, forcedBitrate)
|
||||
elif type == "artist":
|
||||
download_artist(dz, id, settings, forcedBitrate)
|
||||
elif type == "spotifytrack":
|
||||
folder = download_spotifytrack(dz, id, settings, forcedBitrate)
|
||||
elif type == "spotifyalbum":
|
||||
folder = download_spotifyalbum(dz, id, settings, forcedBitrate)
|
||||
else:
|
||||
print("URL not supported yet")
|
||||
return None
|
||||
if settings['executeCommand'] != "":
|
||||
execute(settings['executeCommand'].replace("%folder%", folder))
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
from deemix.utils.misc import getIDFromLink, getTypeFromLink, getBitrateInt
|
||||
from deemix.utils.spotifyHelper import get_trackid_spotify, get_albumid_spotify
|
||||
from concurrent.futures import ProcessPoolExecutor
|
||||
from deemix.app.downloader import download
|
||||
|
||||
queue = []
|
||||
queueList = {}
|
||||
currentItem = ""
|
||||
currentJob = None
|
||||
|
||||
"""
|
||||
queueItem base structure
|
||||
title
|
||||
artist
|
||||
cover
|
||||
size
|
||||
downloaded
|
||||
failed
|
||||
progress
|
||||
type
|
||||
id
|
||||
bitrate
|
||||
uuid: type+id+bitrate
|
||||
if its a single track
|
||||
single
|
||||
if its an album/playlist
|
||||
collection
|
||||
"""
|
||||
|
||||
def generateQueueItem(dz, url, settings, bitrate=None, albumAPI=None):
|
||||
forcedBitrate = getBitrateInt(bitrate)
|
||||
bitrate = forcedBitrate if forcedBitrate else settings['maxBitrate']
|
||||
type = getTypeFromLink(url)
|
||||
id = getIDFromLink(url, type)
|
||||
result = {}
|
||||
if type == None or id == None:
|
||||
print("URL not recognized")
|
||||
result['error'] = "URL not recognized"
|
||||
elif type == "track":
|
||||
trackAPI = dz.get_track_gw(id)
|
||||
if albumAPI:
|
||||
trackAPI['_EXTRA_ALBUM'] = albumAPI
|
||||
trackAPI['FILENAME_TEMPLATE'] = settings['tracknameTemplate']
|
||||
trackAPI['SINGLE_TRACK'] = True
|
||||
|
||||
result['title'] = trackAPI['SNG_TITLE']
|
||||
if 'VERSION' in trackAPI and trackAPI['VERSION']:
|
||||
result['title'] += " " + trackAPI['VERSION']
|
||||
result['artist'] = trackAPI['ART_NAME']
|
||||
result['cover'] = f"https://e-cdns-images.dzcdn.net/images/cover/{trackAPI['ART_PICTURE']}/128x128-000000-80-0-0.jpg"
|
||||
result['size'] = 1
|
||||
result['downloaded'] = 0
|
||||
result['failed'] = 0
|
||||
result['progress'] = 0
|
||||
result['type'] = 'track'
|
||||
result['id'] = id
|
||||
result['bitrate'] = bitrate
|
||||
result['uuid'] = f"{result['type']}:{id}:{bitrate}"
|
||||
result['settings'] = settings or {}
|
||||
result['single'] = trackAPI
|
||||
|
||||
elif type == "album":
|
||||
albumAPI = dz.get_album(id)
|
||||
albumAPI_gw = dz.get_album_gw(id)
|
||||
albumAPI['nb_disk'] = albumAPI_gw['NUMBER_DISK']
|
||||
albumAPI['copyright'] = albumAPI_gw['COPYRIGHT']
|
||||
if albumAPI['nb_tracks'] == 1:
|
||||
return generateQueueItem(dz, f"https://www.deezer.com/track/{albumAPI['tracks']['data'][0]['id']}", settings, bitrate, albumAPI)
|
||||
tracksArray = dz.get_album_tracks_gw(id)
|
||||
|
||||
result['title'] = albumAPI['title']
|
||||
result['artist'] = albumAPI['artist']['name']
|
||||
result['cover'] = albumAPI['cover_small'][:-24]+'/128x128-000000-80-0-0.jpg'
|
||||
result['size'] = albumAPI['nb_tracks']
|
||||
result['downloaded'] = 0
|
||||
result['failed'] = 0
|
||||
result['progress'] = 0
|
||||
result['type'] = 'album'
|
||||
result['id'] = id
|
||||
result['bitrate'] = bitrate
|
||||
result['uuid'] = f"{result['type']}:{id}:{bitrate}"
|
||||
result['settings'] = settings or {}
|
||||
result['collection'] = []
|
||||
for pos, trackAPI in enumerate(tracksArray, start=1):
|
||||
trackAPI['_EXTRA_ALBUM'] = albumAPI
|
||||
trackAPI['POSITION'] = pos
|
||||
trackAPI['FILENAME_TEMPLATE'] = settings['albumTracknameTemplate']
|
||||
result['collection'].append(trackAPI)
|
||||
|
||||
elif type == "playlist":
|
||||
playlistAPI = dz.get_playlist(id)
|
||||
playlistTracksAPI = dz.get_playlist_tracks_gw(id)
|
||||
|
||||
result['title'] = playlistAPI['title']
|
||||
result['artist'] = playlistAPI['creator']['name']
|
||||
result['cover'] = playlistAPI['picture_small'][:-24]+'/128x128-000000-80-0-0.jpg'
|
||||
result['size'] = playlistAPI['nb_tracks']
|
||||
result['downloaded'] = 0
|
||||
result['failed'] = 0
|
||||
result['progress'] = 0
|
||||
result['type'] = 'playlist'
|
||||
result['id'] = id
|
||||
result['bitrate'] = bitrate
|
||||
result['uuid'] = f"{result['type']}:{id}:{bitrate}"
|
||||
result['settings'] = settings or {}
|
||||
result['collection'] = []
|
||||
for pos, trackAPI in enumerate(playlistTracksAPI, start=1):
|
||||
trackAPI['_EXTRA_PLAYLIST'] = playlistAPI
|
||||
trackAPI['POSITION'] = pos
|
||||
trackAPI['FILENAME_TEMPLATE'] = settings['playlistTracknameTemplate']
|
||||
result['collection'].append(trackAPI)
|
||||
|
||||
elif type == "artist":
|
||||
artistAPI = dz.get_artist_albums(id)
|
||||
albumList = []
|
||||
for album in artistAPI['data']:
|
||||
albumList.append(generateQueueItem(dz, album['link'], settings, bitrate))
|
||||
return albumList
|
||||
elif type == "spotifytrack":
|
||||
track_id = get_trackid_spotify(dz, id, settings['fallbackSearch'])
|
||||
result = {}
|
||||
if track_id == "Not Enabled":
|
||||
print("Spotify Features is not setted up correctly.")
|
||||
result['error'] = "Spotify Features is not setted up correctly."
|
||||
elif track_id != 0:
|
||||
return generateQueueItem(dz, f'https://www.deezer.com/track/{track_id}', settings, bitrate)
|
||||
else:
|
||||
print("Track not found on deezer!")
|
||||
result['error'] = "Track not found on deezer!"
|
||||
elif type == "spotifyalbum":
|
||||
album_id = get_albumid_spotify(dz, id)
|
||||
if album_id == "Not Enabled":
|
||||
print("Spotify Features is not setted up correctly.")
|
||||
result['error'] = "Spotify Features is not setted up correctly."
|
||||
elif album_id != 0:
|
||||
return generateQueueItem(dz, f'https://www.deezer.com/album/{track_id}', settings, bitrate)
|
||||
else:
|
||||
print("Album not found on deezer!")
|
||||
result['error'] = "Album not found on deezer!"
|
||||
else:
|
||||
print("URL not supported yet")
|
||||
result['error'] = "URL not supported yet"
|
||||
return result
|
||||
|
||||
def addToQueue(dz, url, settings, bitrate=None, socket=None):
|
||||
global currentItem, currentJob, queueList, queue
|
||||
queueItem = generateQueueItem(dz, url, settings, bitrate)
|
||||
if 'error' in queueItem:
|
||||
if socket:
|
||||
socket.emit("message", queueItem['error'])
|
||||
return None
|
||||
if queueItem['uuid'] in list(queueList.keys()):
|
||||
print("Already in queue!")
|
||||
if socket:
|
||||
socket.emit("message", "Already in queue!")
|
||||
return None
|
||||
if type(queueItem) is list:
|
||||
for x in queueItem:
|
||||
if socket:
|
||||
socket.emit("addedToQueue", x)
|
||||
queue.append(x['uuid'])
|
||||
queueList[x['uuid']] = x
|
||||
else:
|
||||
if socket:
|
||||
socket.emit("addedToQueue", queueItem)
|
||||
queue.append(queueItem['uuid'])
|
||||
queueList[queueItem['uuid']] = queueItem
|
||||
nextItem(dz, socket)
|
||||
|
||||
def nextItem(dz, socket=None):
|
||||
global currentItem, currentJob, queueList, queue
|
||||
if currentItem != "":
|
||||
return None
|
||||
else:
|
||||
if len(queue)>0:
|
||||
currentItem = queue.pop(0)
|
||||
else:
|
||||
return None
|
||||
if socket:
|
||||
socket.emit("message", f"Started downloading {currentItem}")
|
||||
result = download(dz, queueList[currentItem], socket)
|
||||
callbackQueueDone(result)
|
||||
|
||||
def callbackQueueDone(result):
|
||||
global currentItem, currentJob, queueList, queue
|
||||
result['socket']
|
||||
del queueList[currentItem]
|
||||
currentItem = ""
|
||||
nextItem(result['dz'], result['socket'])
|
|
@ -5,3 +5,4 @@ requests
|
|||
spotipy
|
||||
pywebview
|
||||
flask
|
||||
flask-socketio
|
||||
|
|
Loading…
Reference in New Issue