Merge refactoring (#4)
Removed saveDownloadQueue and tagsLanguage from lib settings Revert embedded cover change Fixed bitrate fallback check Use overwriteFile setting when downloading embedded covers Fixed bitrate fallback not working Fixed some issues to make the lib work Implemented spotify plugin back Better handling of albums upcs Fixed queue item not cancelling correctly Code parity with deemix-js Code cleanup with pylint Even more rework on the library More work on the library (WIP) Total rework of the library (WIP) Some rework done on types Added start queue function Made nextitem work on a thread Removed dz as first parameter Started queuemanager refactoring Removed eventlet Co-authored-by: RemixDev <RemixDev64@gmail.com> Reviewed-on: https://git.freezer.life/RemixDev/deemix-py/pulls/4 Co-Authored-By: RemixDev <remixdev@noreply.localhost> Co-Committed-By: RemixDev <remixdev@noreply.localhost>
This commit is contained in:
@ -4,47 +4,57 @@ from deemix.utils import removeDuplicateArtists, removeFeatures
|
||||
from deemix.types.Artist import Artist
|
||||
from deemix.types.Date import Date
|
||||
from deemix.types.Picture import Picture
|
||||
from deemix import VARIOUS_ARTISTS
|
||||
from deemix.types import VARIOUS_ARTISTS
|
||||
|
||||
class Album:
|
||||
def __init__(self, id="0", title="", pic_md5=""):
|
||||
self.id = id
|
||||
def __init__(self, alb_id="0", title="", pic_md5=""):
|
||||
self.id = alb_id
|
||||
self.title = title
|
||||
self.pic = Picture(md5=pic_md5, type="cover")
|
||||
self.pic = Picture(pic_md5, "cover")
|
||||
self.artist = {"Main": []}
|
||||
self.artists = []
|
||||
self.mainArtist = None
|
||||
self.dateString = None
|
||||
self.barcode = "Unknown"
|
||||
self.date = None
|
||||
self.date = Date()
|
||||
self.dateString = ""
|
||||
self.trackTotal = "0"
|
||||
self.discTotal = "0"
|
||||
self.embeddedCoverPath = None
|
||||
self.embeddedCoverURL = None
|
||||
self.embeddedCoverPath = ""
|
||||
self.embeddedCoverURL = ""
|
||||
self.explicit = False
|
||||
self.genre = []
|
||||
self.barcode = "Unknown"
|
||||
self.label = "Unknown"
|
||||
self.copyright = ""
|
||||
self.recordType = "album"
|
||||
self.rootArtist = None
|
||||
self.trackTotal = "0"
|
||||
self.bitrate = 0
|
||||
self.rootArtist = None
|
||||
self.variousArtists = None
|
||||
|
||||
self.playlistId = None
|
||||
self.owner = None
|
||||
self.isPlaylist = False
|
||||
|
||||
def parseAlbum(self, albumAPI):
|
||||
self.title = albumAPI['title']
|
||||
|
||||
# Getting artist image ID
|
||||
# ex: https://e-cdns-images.dzcdn.net/images/artist/f2bc007e9133c946ac3c3907ddc5d2ea/56x56-000000-80-0-0.jpg
|
||||
artistPicture = albumAPI['artist']['picture_small']
|
||||
artistPicture = artistPicture[artistPicture.find('artist/') + 7:-24]
|
||||
art_pic = albumAPI['artist']['picture_small']
|
||||
art_pic = art_pic[art_pic.find('artist/') + 7:-24]
|
||||
self.mainArtist = Artist(
|
||||
id = albumAPI['artist']['id'],
|
||||
name = albumAPI['artist']['name'],
|
||||
pic_md5 = artistPicture
|
||||
albumAPI['artist']['id'],
|
||||
albumAPI['artist']['name'],
|
||||
"Main",
|
||||
art_pic
|
||||
)
|
||||
if albumAPI.get('root_artist'):
|
||||
art_pic = albumAPI['root_artist']['picture_small']
|
||||
art_pic = art_pic[art_pic.find('artist/') + 7:-24]
|
||||
self.rootArtist = Artist(
|
||||
id = albumAPI['root_artist']['id'],
|
||||
name = albumAPI['root_artist']['name']
|
||||
albumAPI['root_artist']['id'],
|
||||
albumAPI['root_artist']['name'],
|
||||
"Root",
|
||||
art_pic
|
||||
)
|
||||
|
||||
for artist in albumAPI['contributors']:
|
||||
@ -53,7 +63,7 @@ class Album:
|
||||
|
||||
if isVariousArtists:
|
||||
self.variousArtists = Artist(
|
||||
id = artist['id'],
|
||||
art_id = artist['id'],
|
||||
name = artist['name'],
|
||||
role = artist['role']
|
||||
)
|
||||
@ -74,18 +84,19 @@ class Album:
|
||||
self.label = albumAPI.get('label', self.label)
|
||||
self.explicit = bool(albumAPI.get('explicit_lyrics', False))
|
||||
if 'release_date' in albumAPI:
|
||||
day = albumAPI["release_date"][8:10]
|
||||
month = albumAPI["release_date"][5:7]
|
||||
year = albumAPI["release_date"][0:4]
|
||||
self.date = Date(year, month, day)
|
||||
self.date.day = albumAPI["release_date"][8:10]
|
||||
self.date.month = albumAPI["release_date"][5:7]
|
||||
self.date.year = albumAPI["release_date"][0:4]
|
||||
self.date.fixDayMonth()
|
||||
|
||||
self.discTotal = albumAPI.get('nb_disk')
|
||||
self.copyright = albumAPI.get('copyright')
|
||||
|
||||
if not self.pic.md5:
|
||||
if self.pic.md5 == "":
|
||||
# Getting album cover MD5
|
||||
# ex: https://e-cdns-images.dzcdn.net/images/cover/2e018122cb56986277102d2041a592c8/56x56-000000-80-0-0.jpg
|
||||
self.pic.md5 = albumAPI['cover_small'][albumAPI['cover_small'].find('cover/') + 6:-24]
|
||||
alb_pic = albumAPI['cover_small']
|
||||
self.pic.md5 = alb_pic[alb_pic.find('cover/') + 6:-24]
|
||||
|
||||
if albumAPI.get('genres') and len(albumAPI['genres'].get('data', [])) > 0:
|
||||
for genre in albumAPI['genres']['data']:
|
||||
@ -94,8 +105,9 @@ class Album:
|
||||
def parseAlbumGW(self, albumAPI_gw):
|
||||
self.title = albumAPI_gw['ALB_TITLE']
|
||||
self.mainArtist = Artist(
|
||||
id = albumAPI_gw['ART_ID'],
|
||||
name = albumAPI_gw['ART_NAME']
|
||||
art_id = albumAPI_gw['ART_ID'],
|
||||
name = albumAPI_gw['ART_NAME'],
|
||||
role = "Main"
|
||||
)
|
||||
|
||||
self.artists = [albumAPI_gw['ART_NAME']]
|
||||
@ -106,13 +118,16 @@ class Album:
|
||||
explicitLyricsStatus = albumAPI_gw.get('EXPLICIT_ALBUM_CONTENT', {}).get('EXPLICIT_LYRICS_STATUS', LyricsStatus.UNKNOWN)
|
||||
self.explicit = explicitLyricsStatus in [LyricsStatus.EXPLICIT, LyricsStatus.PARTIALLY_EXPLICIT]
|
||||
|
||||
if not self.pic.md5:
|
||||
self.addExtraAlbumGWData(albumAPI_gw)
|
||||
|
||||
def addExtraAlbumGWData(self, albumAPI_gw):
|
||||
if self.pic.md5 == "":
|
||||
self.pic.md5 = albumAPI_gw['ALB_PICTURE']
|
||||
if 'PHYSICAL_RELEASE_DATE' in albumAPI_gw:
|
||||
day = albumAPI_gw["PHYSICAL_RELEASE_DATE"][8:10]
|
||||
month = albumAPI_gw["PHYSICAL_RELEASE_DATE"][5:7]
|
||||
year = albumAPI_gw["PHYSICAL_RELEASE_DATE"][0:4]
|
||||
self.date = Date(year, month, day)
|
||||
self.date.day = albumAPI_gw["PHYSICAL_RELEASE_DATE"][8:10]
|
||||
self.date.month = albumAPI_gw["PHYSICAL_RELEASE_DATE"][5:7]
|
||||
self.date.year = albumAPI_gw["PHYSICAL_RELEASE_DATE"][0:4]
|
||||
self.date.fixDayMonth()
|
||||
|
||||
def makePlaylistCompilation(self, playlist):
|
||||
self.variousArtists = playlist.variousArtists
|
||||
@ -131,10 +146,12 @@ class Album:
|
||||
self.playlistId = playlist.playlistId
|
||||
self.owner = playlist.owner
|
||||
self.pic = playlist.pic
|
||||
self.isPlaylist = True
|
||||
|
||||
def removeDuplicateArtists(self):
|
||||
"""Removes duplicate artists for both artist array and artists dict"""
|
||||
(self.artist, self.artists) = removeDuplicateArtists(self.artist, self.artists)
|
||||
|
||||
# Removes featuring from the album name
|
||||
def getCleanTitle(self):
|
||||
"""Removes featuring from the album name"""
|
||||
return removeFeatures(self.title)
|
||||
|
@ -1,12 +1,12 @@
|
||||
from deemix.types.Picture import Picture
|
||||
from deemix import VARIOUS_ARTISTS
|
||||
from deemix.types import VARIOUS_ARTISTS
|
||||
|
||||
class Artist:
|
||||
def __init__(self, id="0", name="", pic_md5="", role=""):
|
||||
self.id = str(id)
|
||||
def __init__(self, art_id="0", name="", role="", pic_md5=""):
|
||||
self.id = str(art_id)
|
||||
self.name = name
|
||||
self.pic = Picture(md5=pic_md5, type="artist")
|
||||
self.role = ""
|
||||
self.pic = Picture(md5=pic_md5, pic_type="artist")
|
||||
self.role = role
|
||||
self.save = True
|
||||
|
||||
def isVariousArtists(self):
|
||||
|
@ -1,8 +1,8 @@
|
||||
class Date(object):
|
||||
def __init__(self, year="XXXX", month="00", day="00"):
|
||||
self.year = year
|
||||
self.month = month
|
||||
class Date:
|
||||
def __init__(self, day="00", month="00", year="XXXX"):
|
||||
self.day = day
|
||||
self.month = month
|
||||
self.year = year
|
||||
self.fixDayMonth()
|
||||
|
||||
# Fix incorrect day month when detectable
|
||||
|
126
deemix/types/DownloadObjects.py
Normal file
126
deemix/types/DownloadObjects.py
Normal file
@ -0,0 +1,126 @@
|
||||
class IDownloadObject:
|
||||
"""DownloadObject Interface"""
|
||||
def __init__(self, obj):
|
||||
self.type = obj['type']
|
||||
self.id = obj['id']
|
||||
self.bitrate = obj['bitrate']
|
||||
self.title = obj['title']
|
||||
self.artist = obj['artist']
|
||||
self.cover = obj['cover']
|
||||
self.explicit = obj.get('explicit', False)
|
||||
self.size = obj.get('size', 0)
|
||||
self.downloaded = obj.get('downloaded', 0)
|
||||
self.failed = obj.get('failed', 0)
|
||||
self.progress = obj.get('progress', 0)
|
||||
self.errors = obj.get('errors', [])
|
||||
self.files = obj.get('files', [])
|
||||
self.progressNext = 0
|
||||
self.uuid = f"{self.type}_{self.id}_{self.bitrate}"
|
||||
self.isCanceled = False
|
||||
self.__type__ = None
|
||||
|
||||
def toDict(self):
|
||||
return {
|
||||
'type': self.type,
|
||||
'id': self.id,
|
||||
'bitrate': self.bitrate,
|
||||
'uuid': self.uuid,
|
||||
'title': self.title,
|
||||
'artist': self.artist,
|
||||
'cover': self.cover,
|
||||
'explicit': self.explicit,
|
||||
'size': self.size,
|
||||
'downloaded': self.downloaded,
|
||||
'failed': self.failed,
|
||||
'progress': self.progress,
|
||||
'errors': self.errors,
|
||||
'files': self.files,
|
||||
'__type__': self.__type__
|
||||
}
|
||||
|
||||
def getResettedDict(self):
|
||||
item = self.toDict()
|
||||
item['downloaded'] = 0
|
||||
item['failed'] = 0
|
||||
item['progress'] = 0
|
||||
item['errors'] = []
|
||||
item['files'] = []
|
||||
return item
|
||||
|
||||
def getSlimmedDict(self):
|
||||
light = self.toDict()
|
||||
propertiesToDelete = ['single', 'collection', 'plugin', 'conversion_data']
|
||||
for prop in propertiesToDelete:
|
||||
if prop in light:
|
||||
del light[prop]
|
||||
return light
|
||||
|
||||
def getEssentialDict(self):
|
||||
return {
|
||||
'type': self.type,
|
||||
'id': self.id,
|
||||
'bitrate': self.bitrate,
|
||||
'uuid': self.uuid,
|
||||
'title': self.title,
|
||||
'artist': self.artist,
|
||||
'cover': self.cover,
|
||||
'explicit': self.explicit,
|
||||
'size': self.size
|
||||
}
|
||||
|
||||
def updateProgress(self, listener=None):
|
||||
if round(self.progressNext) != self.progress and round(self.progressNext) % 2 == 0:
|
||||
self.progress = round(self.progressNext)
|
||||
if listener: listener.send("updateQueue", {'uuid': self.uuid, 'progress': self.progress})
|
||||
|
||||
class Single(IDownloadObject):
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj)
|
||||
self.size = 1
|
||||
self.single = obj['single']
|
||||
self.__type__ = "Single"
|
||||
|
||||
def toDict(self):
|
||||
item = super().toDict()
|
||||
item['single'] = self.single
|
||||
return item
|
||||
|
||||
def completeTrackProgress(self, listener=None):
|
||||
self.progressNext = 100
|
||||
self.updateProgress(listener)
|
||||
|
||||
def removeTrackProgress(self, listener=None):
|
||||
self.progressNext = 0
|
||||
self.updateProgress(listener)
|
||||
|
||||
class Collection(IDownloadObject):
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj)
|
||||
self.collection = obj['collection']
|
||||
self.__type__ = "Collection"
|
||||
|
||||
def toDict(self):
|
||||
item = super().toDict()
|
||||
item['collection'] = self.collection
|
||||
return item
|
||||
|
||||
def completeTrackProgress(self, listener=None):
|
||||
self.progressNext += (1 / self.size) * 100
|
||||
self.updateProgress(listener)
|
||||
|
||||
def removeTrackProgress(self, listener=None):
|
||||
self.progressNext -= (1 / self.size) * 100
|
||||
self.updateProgress(listener)
|
||||
|
||||
class Convertable(Collection):
|
||||
def __init__(self, obj):
|
||||
super().__init__(obj)
|
||||
self.plugin = obj['plugin']
|
||||
self.conversion_data = obj['conversion_data']
|
||||
self.__type__ = "Convertable"
|
||||
|
||||
def toDict(self):
|
||||
item = super().toDict()
|
||||
item['plugin'] = self.plugin
|
||||
item['conversion_data'] = self.conversion_data
|
||||
return item
|
@ -1,19 +1,17 @@
|
||||
class Lyrics:
|
||||
def __init__(self, id="0"):
|
||||
self.id = id
|
||||
self.sync = None
|
||||
self.unsync = None
|
||||
self.syncID3 = None
|
||||
def __init__(self, lyr_id="0"):
|
||||
self.id = lyr_id
|
||||
self.sync = ""
|
||||
self.unsync = ""
|
||||
self.syncID3 = []
|
||||
|
||||
def parseLyrics(self, lyricsAPI):
|
||||
self.unsync = lyricsAPI.get("LYRICS_TEXT")
|
||||
if "LYRICS_SYNC_JSON" in lyricsAPI:
|
||||
syncLyricsJson = lyricsAPI["LYRICS_SYNC_JSON"]
|
||||
self.sync = ""
|
||||
self.syncID3 = []
|
||||
timestamp = ""
|
||||
milliseconds = 0
|
||||
for line in range(len(syncLyricsJson)):
|
||||
for line, _ in enumerate(syncLyricsJson):
|
||||
if syncLyricsJson[line]["line"] != "":
|
||||
timestamp = syncLyricsJson[line]["lrc_timestamp"]
|
||||
milliseconds = int(syncLyricsJson[line]["milliseconds"])
|
||||
@ -21,6 +19,6 @@ class Lyrics:
|
||||
else:
|
||||
notEmptyLine = line + 1
|
||||
while syncLyricsJson[notEmptyLine]["line"] == "":
|
||||
notEmptyLine = notEmptyLine + 1
|
||||
notEmptyLine += 1
|
||||
timestamp = syncLyricsJson[notEmptyLine]["lrc_timestamp"]
|
||||
self.sync += timestamp + syncLyricsJson[line]["line"] + "\r\n"
|
||||
|
@ -1,27 +1,29 @@
|
||||
class Picture:
|
||||
def __init__(self, md5="", type=None, url=None):
|
||||
def __init__(self, md5="", pic_type=""):
|
||||
self.md5 = md5
|
||||
self.type = type
|
||||
self.url = url
|
||||
self.type = pic_type
|
||||
|
||||
def generatePictureURL(self, size, format):
|
||||
if self.url: return self.url
|
||||
if format.startswith("jpg"):
|
||||
if '-' in format:
|
||||
quality = format[4:]
|
||||
else:
|
||||
quality = 80
|
||||
format = 'jpg'
|
||||
return "https://e-cdns-images.dzcdn.net/images/{}/{}/{}x{}-{}".format(
|
||||
self.type,
|
||||
self.md5,
|
||||
size, size,
|
||||
f'000000-{quality}-0-0.jpg'
|
||||
)
|
||||
if format == 'png':
|
||||
return "https://e-cdns-images.dzcdn.net/images/{}/{}/{}x{}-{}".format(
|
||||
self.type,
|
||||
self.md5,
|
||||
size, size,
|
||||
'none-100-0-0.png'
|
||||
)
|
||||
def getURL(self, size, pic_format):
|
||||
url = "https://e-cdns-images.dzcdn.net/images/{}/{}/{size}x{size}".format(
|
||||
self.type,
|
||||
self.md5,
|
||||
size=size
|
||||
)
|
||||
|
||||
if pic_format.startswith("jpg"):
|
||||
quality = 80
|
||||
if '-' in pic_format:
|
||||
quality = pic_format[4:]
|
||||
pic_format = 'jpg'
|
||||
return url + f'-000000-{quality}-0-0.jpg'
|
||||
if pic_format == 'png':
|
||||
return url + '-none-100-0-0.png'
|
||||
|
||||
return url+'.jpg'
|
||||
|
||||
class StaticPicture:
|
||||
def __init__(self, url):
|
||||
self.staticURL = url
|
||||
|
||||
def getURL(self):
|
||||
return self.staticURL
|
||||
|
@ -1,20 +1,9 @@
|
||||
from deemix.types.Artist import Artist
|
||||
from deemix.types.Date import Date
|
||||
from deemix.types.Picture import Picture
|
||||
from deemix.types.Picture import Picture, StaticPicture
|
||||
|
||||
class Playlist:
|
||||
def __init__(self, playlistAPI):
|
||||
if 'various_artist' in playlistAPI:
|
||||
playlistAPI['various_artist']['role'] = "Main"
|
||||
self.variousArtists = Artist(
|
||||
id = playlistAPI['various_artist']['id'],
|
||||
name = playlistAPI['various_artist']['name'],
|
||||
pic_md5 = playlistAPI['various_artist']['picture_small'][
|
||||
playlistAPI['various_artist']['picture_small'].find('artist/') + 7:-24],
|
||||
role = playlistAPI['various_artist']['role']
|
||||
)
|
||||
self.mainArtist = self.variousArtists
|
||||
|
||||
self.id = "pl_" + str(playlistAPI['id'])
|
||||
self.title = playlistAPI['title']
|
||||
self.rootArtist = None
|
||||
@ -30,19 +19,28 @@ class Playlist:
|
||||
year = playlistAPI["creation_date"][0:4]
|
||||
month = playlistAPI["creation_date"][5:7]
|
||||
day = playlistAPI["creation_date"][8:10]
|
||||
self.date = Date(year, month, day)
|
||||
self.date = Date(day, month, year)
|
||||
|
||||
self.discTotal = "1"
|
||||
self.playlistId = playlistAPI['id']
|
||||
self.playlistID = playlistAPI['id']
|
||||
self.owner = playlistAPI['creator']
|
||||
|
||||
if 'dzcdn.net' in playlistAPI['picture_small']:
|
||||
url = playlistAPI['picture_small']
|
||||
picType = url[url.find('images/')+7:]
|
||||
picType = picType[:picType.find('/')]
|
||||
md5 = url[url.find(picType+'/') + len(picType)+1:-24]
|
||||
self.pic = Picture(
|
||||
md5 = md5,
|
||||
type = picType
|
||||
)
|
||||
self.pic = Picture(md5, picType)
|
||||
else:
|
||||
self.pic = Picture(url = playlistAPI['picture_xl'])
|
||||
self.pic = StaticPicture(playlistAPI['picture_xl'])
|
||||
|
||||
if 'various_artist' in playlistAPI:
|
||||
pic_md5 = playlistAPI['various_artist']['picture_small']
|
||||
pic_md5 = pic_md5[pic_md5.find('artist/') + 7:-24]
|
||||
self.variousArtists = Artist(
|
||||
playlistAPI['various_artist']['id'],
|
||||
playlistAPI['various_artist']['name'],
|
||||
"Main",
|
||||
pic_md5
|
||||
)
|
||||
self.mainArtist = self.variousArtists
|
||||
|
@ -1,38 +1,39 @@
|
||||
import eventlet
|
||||
requests = eventlet.import_patched('requests')
|
||||
from time import sleep
|
||||
import re
|
||||
import requests
|
||||
|
||||
import logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger('deemix')
|
||||
|
||||
from deezer.gw import APIError as gwAPIError
|
||||
from deezer.gw import GWAPIError
|
||||
from deezer.api import APIError
|
||||
from deemix.utils import removeFeatures, andCommaConcat, removeDuplicateArtists, generateReplayGainString
|
||||
|
||||
from deemix.utils import removeFeatures, andCommaConcat, removeDuplicateArtists, generateReplayGainString, changeCase
|
||||
|
||||
from deemix.types.Album import Album
|
||||
from deemix.types.Artist import Artist
|
||||
from deemix.types.Date import Date
|
||||
from deemix.types.Picture import Picture
|
||||
from deemix.types.Playlist import Playlist
|
||||
from deemix.types.Lyrics import Lyrics
|
||||
from deemix import VARIOUS_ARTISTS
|
||||
from deemix.types import VARIOUS_ARTISTS
|
||||
|
||||
from deemix.settings import FeaturesOption
|
||||
|
||||
class Track:
|
||||
def __init__(self, id="0", name=""):
|
||||
self.id = id
|
||||
def __init__(self, sng_id="0", name=""):
|
||||
self.id = sng_id
|
||||
self.title = name
|
||||
self.MD5 = ""
|
||||
self.mediaVersion = ""
|
||||
self.duration = 0
|
||||
self.fallbackId = "0"
|
||||
self.fallbackID = "0"
|
||||
self.filesizes = {}
|
||||
self.localTrack = False
|
||||
self.local = False
|
||||
self.mainArtist = None
|
||||
self.artist = {"Main": []}
|
||||
self.artists = []
|
||||
self.album = None
|
||||
self.trackNumber = "0"
|
||||
self.discNumber = "0"
|
||||
self.date = None
|
||||
self.date = Date()
|
||||
self.lyrics = None
|
||||
self.bpm = 0
|
||||
self.contributors = {}
|
||||
@ -45,7 +46,7 @@ class Track:
|
||||
self.searched = False
|
||||
self.selectedFormat = 0
|
||||
self.singleDownload = False
|
||||
self.dateString = None
|
||||
self.dateString = ""
|
||||
self.artistsString = ""
|
||||
self.mainArtistsString = ""
|
||||
self.featArtistsString = ""
|
||||
@ -60,14 +61,14 @@ class Track:
|
||||
else:
|
||||
raise MD5NotFound
|
||||
self.mediaVersion = trackAPI_gw['MEDIA_VERSION']
|
||||
self.fallbackId = "0"
|
||||
self.fallbackID = "0"
|
||||
if 'FALLBACK' in trackAPI_gw:
|
||||
self.fallbackId = trackAPI_gw['FALLBACK']['SNG_ID']
|
||||
self.localTrack = int(self.id) < 0
|
||||
self.fallbackID = trackAPI_gw['FALLBACK']['SNG_ID']
|
||||
self.local = int(self.id) < 0
|
||||
|
||||
def retriveFilesizes(self, dz):
|
||||
guest_sid = dz.session.cookies.get('sid')
|
||||
try:
|
||||
guest_sid = dz.session.cookies.get('sid')
|
||||
site = requests.post(
|
||||
"https://api.deezer.com/1.0/gateway.php",
|
||||
params={
|
||||
@ -83,21 +84,20 @@ class Track:
|
||||
)
|
||||
result_json = site.json()
|
||||
except:
|
||||
eventlet.sleep(2)
|
||||
return self.retriveFilesizes(dz)
|
||||
sleep(2)
|
||||
self.retriveFilesizes(dz)
|
||||
if len(result_json['error']):
|
||||
raise APIError(json.dumps(result_json['error']))
|
||||
response = result_json.get("results")
|
||||
raise TrackError(result_json.dumps(result_json['error']))
|
||||
response = result_json.get("results", {})
|
||||
filesizes = {}
|
||||
for key, value in response.items():
|
||||
if key.startswith("FILESIZE_"):
|
||||
filesizes[key] = value
|
||||
filesizes[key] = int(value)
|
||||
filesizes[key+"_TESTED"] = False
|
||||
self.filesizes = filesizes
|
||||
|
||||
def parseData(self, dz, id=None, trackAPI_gw=None, trackAPI=None, albumAPI_gw=None, albumAPI=None, playlistAPI=None):
|
||||
if id:
|
||||
if not trackAPI_gw: trackAPI_gw = dz.gw.get_track_with_fallback(id)
|
||||
def parseData(self, dz, track_id=None, trackAPI_gw=None, trackAPI=None, albumAPI_gw=None, albumAPI=None, playlistAPI=None):
|
||||
if track_id and not trackAPI_gw: trackAPI_gw = dz.gw.get_track_with_fallback(track_id)
|
||||
elif not trackAPI_gw: raise NoDataToParse
|
||||
if not trackAPI:
|
||||
try: trackAPI = dz.api.get_track(trackAPI_gw['SNG_ID'])
|
||||
@ -105,21 +105,21 @@ class Track:
|
||||
|
||||
self.parseEssentialData(trackAPI_gw, trackAPI)
|
||||
|
||||
if self.localTrack:
|
||||
if self.local:
|
||||
self.parseLocalTrackData(trackAPI_gw)
|
||||
else:
|
||||
self.retriveFilesizes(dz)
|
||||
|
||||
self.parseTrackGW(trackAPI_gw)
|
||||
|
||||
# Get Lyrics data
|
||||
if not "LYRICS" in trackAPI_gw and self.lyrics.id != "0":
|
||||
try: trackAPI_gw["LYRICS"] = dz.gw.get_track_lyrics(self.id)
|
||||
except gwAPIError: self.lyrics.id = "0"
|
||||
except GWAPIError: self.lyrics.id = "0"
|
||||
if self.lyrics.id != "0": self.lyrics.parseLyrics(trackAPI_gw["LYRICS"])
|
||||
|
||||
# Parse Album data
|
||||
# Parse Album Data
|
||||
self.album = Album(
|
||||
id = trackAPI_gw['ALB_ID'],
|
||||
alb_id = trackAPI_gw['ALB_ID'],
|
||||
title = trackAPI_gw['ALB_TITLE'],
|
||||
pic_md5 = trackAPI_gw.get('ALB_PICTURE')
|
||||
)
|
||||
@ -132,7 +132,7 @@ class Track:
|
||||
# Get album_gw Data
|
||||
if not albumAPI_gw:
|
||||
try: albumAPI_gw = dz.gw.get_album(self.album.id)
|
||||
except gwAPIError: albumAPI_gw = None
|
||||
except GWAPIError: albumAPI_gw = None
|
||||
|
||||
if albumAPI:
|
||||
self.album.parseAlbum(albumAPI)
|
||||
@ -147,6 +147,7 @@ class Track:
|
||||
raise AlbumDoesntExists
|
||||
|
||||
# Fill missing data
|
||||
if albumAPI_gw: self.album.addExtraAlbumGWData(albumAPI_gw)
|
||||
if self.album.date and not self.date: self.date = self.album.date
|
||||
if not self.album.discTotal: self.album.discTotal = albumAPI_gw.get('NUMBER_DISK', "1")
|
||||
if not self.copyright: self.copyright = albumAPI_gw['COPYRIGHT']
|
||||
@ -157,10 +158,9 @@ class Track:
|
||||
self.title = ' '.join(self.title.split())
|
||||
|
||||
# Make sure there is at least one artist
|
||||
if not len(self.artist['Main']):
|
||||
if len(self.artist['Main']) == 0:
|
||||
self.artist['Main'] = [self.mainArtist['name']]
|
||||
|
||||
self.singleDownload = trackAPI_gw.get('SINGLE_TRACK', False)
|
||||
self.position = trackAPI_gw.get('POSITION')
|
||||
|
||||
# Add playlist data if track is in a playlist
|
||||
@ -176,9 +176,9 @@ class Track:
|
||||
self.album = Album(title=trackAPI_gw['ALB_TITLE'])
|
||||
self.album.pic = Picture(
|
||||
md5 = trackAPI_gw.get('ALB_PICTURE', ""),
|
||||
type = "cover"
|
||||
pic_type = "cover"
|
||||
)
|
||||
self.mainArtist = Artist(name=trackAPI_gw['ART_NAME'])
|
||||
self.mainArtist = Artist(name=trackAPI_gw['ART_NAME'], role="Main")
|
||||
self.artists = [trackAPI_gw['ART_NAME']]
|
||||
self.artist = {
|
||||
'Main': [trackAPI_gw['ART_NAME']]
|
||||
@ -187,12 +187,11 @@ class Track:
|
||||
self.album.artists = self.artists
|
||||
self.album.date = self.date
|
||||
self.album.mainArtist = self.mainArtist
|
||||
self.date = Date()
|
||||
|
||||
def parseTrackGW(self, trackAPI_gw):
|
||||
self.title = trackAPI_gw['SNG_TITLE'].strip()
|
||||
if trackAPI_gw.get('VERSION') and not trackAPI_gw['VERSION'] in trackAPI_gw['SNG_TITLE']:
|
||||
self.title += " " + trackAPI_gw['VERSION'].strip()
|
||||
if trackAPI_gw.get('VERSION') and not trackAPI_gw['VERSION'].strip() in self.title:
|
||||
self.title += f" {trackAPI_gw['VERSION'].strip()}"
|
||||
|
||||
self.discNumber = trackAPI_gw.get('DISK_NUMBER')
|
||||
self.explicit = bool(int(trackAPI_gw.get('EXPLICIT_LYRICS', "0")))
|
||||
@ -205,16 +204,17 @@ class Track:
|
||||
self.lyrics = Lyrics(trackAPI_gw.get('LYRICS_ID', "0"))
|
||||
|
||||
self.mainArtist = Artist(
|
||||
id = trackAPI_gw['ART_ID'],
|
||||
art_id = trackAPI_gw['ART_ID'],
|
||||
name = trackAPI_gw['ART_NAME'],
|
||||
role = "Main",
|
||||
pic_md5 = trackAPI_gw.get('ART_PICTURE')
|
||||
)
|
||||
|
||||
if 'PHYSICAL_RELEASE_DATE' in trackAPI_gw:
|
||||
day = trackAPI_gw["PHYSICAL_RELEASE_DATE"][8:10]
|
||||
month = trackAPI_gw["PHYSICAL_RELEASE_DATE"][5:7]
|
||||
year = trackAPI_gw["PHYSICAL_RELEASE_DATE"][0:4]
|
||||
self.date = Date(year, month, day)
|
||||
self.date.day = trackAPI_gw["PHYSICAL_RELEASE_DATE"][8:10]
|
||||
self.date.month = trackAPI_gw["PHYSICAL_RELEASE_DATE"][5:7]
|
||||
self.date.year = trackAPI_gw["PHYSICAL_RELEASE_DATE"][0:4]
|
||||
self.date.fixDayMonth()
|
||||
|
||||
def parseTrack(self, trackAPI):
|
||||
self.bpm = trackAPI['bpm']
|
||||
@ -249,8 +249,8 @@ class Track:
|
||||
return removeFeatures(self.title)
|
||||
|
||||
def getFeatTitle(self):
|
||||
if self.featArtistsString and not "(feat." in self.title.lower():
|
||||
return self.title + " ({})".format(self.featArtistsString)
|
||||
if self.featArtistsString and "feat." not in self.title.lower():
|
||||
return f"{self.title} ({self.featArtistsString})"
|
||||
return self.title
|
||||
|
||||
def generateMainFeatStrings(self):
|
||||
@ -259,9 +259,81 @@ class Track:
|
||||
if 'Featured' in self.artist:
|
||||
self.featArtistsString = "feat. "+andCommaConcat(self.artist['Featured'])
|
||||
|
||||
def applySettings(self, settings):
|
||||
|
||||
# Check if should save the playlist as a compilation
|
||||
if self.playlist and settings['tags']['savePlaylistAsCompilation']:
|
||||
self.trackNumber = self.position
|
||||
self.discNumber = "1"
|
||||
self.album.makePlaylistCompilation(self.playlist)
|
||||
else:
|
||||
if self.album.date: self.date = self.album.date
|
||||
|
||||
self.dateString = self.date.format(settings['dateFormat'])
|
||||
self.album.dateString = self.album.date.format(settings['dateFormat'])
|
||||
if self.playlist: self.playlist.dateString = self.playlist.date.format(settings['dateFormat'])
|
||||
|
||||
# Check various artist option
|
||||
if settings['albumVariousArtists'] and self.album.variousArtists:
|
||||
artist = self.album.variousArtists
|
||||
isMainArtist = artist.role == "Main"
|
||||
|
||||
if artist.name not in self.album.artists:
|
||||
self.album.artists.insert(0, artist.name)
|
||||
|
||||
if isMainArtist or artist.name not in self.album.artist['Main'] and not isMainArtist:
|
||||
if artist.role not in self.album.artist:
|
||||
self.album.artist[artist.role] = []
|
||||
self.album.artist[artist.role].insert(0, artist.name)
|
||||
self.album.mainArtist.save = not self.album.mainArtist.isVariousArtists() or settings['albumVariousArtists'] and self.album.mainArtist.isVariousArtists()
|
||||
|
||||
# Check removeDuplicateArtists
|
||||
if settings['removeDuplicateArtists']: self.removeDuplicateArtists()
|
||||
|
||||
# Check if user wants the feat in the title
|
||||
if str(settings['featuredToTitle']) == FeaturesOption.REMOVE_TITLE:
|
||||
self.title = self.getCleanTitle()
|
||||
elif str(settings['featuredToTitle']) == FeaturesOption.MOVE_TITLE:
|
||||
self.title = self.getFeatTitle()
|
||||
elif str(settings['featuredToTitle']) == FeaturesOption.REMOVE_TITLE_ALBUM:
|
||||
self.title = self.getCleanTitle()
|
||||
self.album.title = self.album.getCleanTitle()
|
||||
|
||||
# Remove (Album Version) from tracks that have that
|
||||
if settings['removeAlbumVersion'] and "Album Version" in self.title:
|
||||
self.title = re.sub(r' ?\(Album Version\)', "", self.title).strip()
|
||||
|
||||
# Change Title and Artists casing if needed
|
||||
if settings['titleCasing'] != "nothing":
|
||||
self.title = changeCase(self.title, settings['titleCasing'])
|
||||
if settings['artistCasing'] != "nothing":
|
||||
self.mainArtist.name = changeCase(self.mainArtist.name, settings['artistCasing'])
|
||||
for i, artist in enumerate(self.artists):
|
||||
self.artists[i] = changeCase(artist, settings['artistCasing'])
|
||||
for art_type in self.artist:
|
||||
for i, artist in enumerate(self.artist[art_type]):
|
||||
self.artist[art_type][i] = changeCase(artist, settings['artistCasing'])
|
||||
self.generateMainFeatStrings()
|
||||
|
||||
# Generate artist tag
|
||||
if settings['tags']['multiArtistSeparator'] == "default":
|
||||
if str(settings['featuredToTitle']) == FeaturesOption.MOVE_TITLE:
|
||||
self.artistsString = ", ".join(self.artist['Main'])
|
||||
else:
|
||||
self.artistsString = ", ".join(self.artists)
|
||||
elif settings['tags']['multiArtistSeparator'] == "andFeat":
|
||||
self.artistsString = self.mainArtistsString
|
||||
if self.featArtistsString and str(settings['featuredToTitle']) != FeaturesOption.MOVE_TITLE:
|
||||
self.artistsString += " " + self.featArtistsString
|
||||
else:
|
||||
separator = settings['tags']['multiArtistSeparator']
|
||||
if str(settings['featuredToTitle']) == FeaturesOption.MOVE_TITLE:
|
||||
self.artistsString = separator.join(self.artist['Main'])
|
||||
else:
|
||||
self.artistsString = separator.join(self.artists)
|
||||
|
||||
class TrackError(Exception):
|
||||
"""Base class for exceptions in this module."""
|
||||
pass
|
||||
|
||||
class AlbumDoesntExists(TrackError):
|
||||
pass
|
||||
|
@ -1,7 +1 @@
|
||||
from deemix.types.Date import Date
|
||||
from deemix.types.Picture import Picture
|
||||
from deemix.types.Lyrics import Lyrics
|
||||
from deemix.types.Album import Album
|
||||
from deemix.types.Artist import Artist
|
||||
from deemix.types.Playlist import Playlist
|
||||
from deemix.types.Track import Track
|
||||
VARIOUS_ARTISTS = "5080"
|
||||
|
Reference in New Issue
Block a user