Code parity with deemix-js

This commit is contained in:
RemixDev
2021-06-07 20:25:51 +02:00
parent 69c165e2bc
commit 224a62aad2
21 changed files with 715 additions and 555 deletions

View File

@ -10,21 +10,21 @@ class Album:
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.date = None
self.dateString = 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 = None
self.copyright = ""
self.recordType = "album"
self.bitrate = 0
self.rootArtist = None
@ -32,26 +32,29 @@ class Album:
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'):
artistPicture = albumAPI['root_artist']['picture_small']
artistPicture = artistPicture[artistPicture.find('artist/') + 7:-24]
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'],
pic_md5 = artistPicture
albumAPI['root_artist']['id'],
albumAPI['root_artist']['name'],
"Root",
art_pic
)
for artist in albumAPI['contributors']:
@ -60,7 +63,7 @@ class Album:
if isVariousArtists:
self.variousArtists = Artist(
id = artist['id'],
art_id = artist['id'],
name = artist['name'],
role = artist['role']
)
@ -81,10 +84,10 @@ 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(day, month, year)
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')
@ -92,7 +95,8 @@ class Album:
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']:
@ -101,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']]
@ -113,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]
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(day, month, year)
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
@ -138,6 +146,7 @@ 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"""

View File

@ -5,7 +5,7 @@ class Artist:
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.pic = Picture(md5=pic_md5, pic_type="artist")
self.role = role
self.save = True

View File

@ -1,8 +1,8 @@
class Date:
def __init__(self, day="00", month="00", year="XXXX"):
self.year = year
self.month = month
self.day = day
self.month = month
self.year = year
self.fixDayMonth()
# Fix incorrect day month when detectable

View File

@ -1,5 +1,5 @@
class IDownloadObject:
"""DownloadObject interface"""
"""DownloadObject Interface"""
def __init__(self, obj):
self.type = obj['type']
self.id = obj['id']
@ -16,7 +16,6 @@ class IDownloadObject:
self.files = obj.get('files', [])
self.progressNext = 0
self.uuid = f"{self.type}_{self.id}_{self.bitrate}"
self.ack = None
self.__type__ = None
def toDict(self):
@ -35,7 +34,6 @@ class IDownloadObject:
'progress': self.progress,
'errors': self.errors,
'files': self.files,
'ack': self.ack,
'__type__': self.__type__
}
@ -50,16 +48,29 @@ class IDownloadObject:
def getSlimmedDict(self):
light = self.toDict()
propertiesToDelete = ['single', 'collection', 'convertable']
propertiesToDelete = ['single', 'collection', 'plugin', 'conversion_data']
for prop in propertiesToDelete:
if prop in light:
del light[prop]
return light
def updateProgress(self, interface=None):
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 interface: interface.send("updateQueue", {'uuid': self.uuid, 'progress': self.progress})
if listener: listener.send("updateQueue", {'uuid': self.uuid, 'progress': self.progress})
class Single(IDownloadObject):
def __init__(self, obj):
@ -73,13 +84,13 @@ class Single(IDownloadObject):
item['single'] = self.single
return item
def completeTrackProgress(self, interface=None):
def completeTrackProgress(self, listener=None):
self.progressNext = 100
self.updateProgress(interface)
self.updateProgress(listener)
def removeTrackProgress(self, interface=None):
def removeTrackProgress(self, listener=None):
self.progressNext = 0
self.updateProgress(interface)
self.updateProgress(listener)
class Collection(IDownloadObject):
def __init__(self, obj):
@ -92,13 +103,13 @@ class Collection(IDownloadObject):
item['collection'] = self.collection
return item
def completeTrackProgress(self, interface=None):
def completeTrackProgress(self, listener=None):
self.progressNext += (1 / self.size) * 100
self.updateProgress(interface)
self.updateProgress(listener)
def removeTrackProgress(self, interface=None):
def removeTrackProgress(self, listener=None):
self.progressNext -= (1 / self.size) * 100
self.updateProgress(interface)
self.updateProgress(listener)
class Convertable(Collection):
def __init__(self, obj):

View File

@ -19,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"

View File

@ -1,12 +1,9 @@
class Picture:
def __init__(self, md5="", pic_type="", url=None):
def __init__(self, md5="", pic_type=""):
self.md5 = md5
self.type = pic_type
self.staticUrl = url
def generatePictureURL(self, size, pic_format):
if self.staticUrl: return self.staticUrl
def getURL(self, size, pic_format):
url = "https://e-cdns-images.dzcdn.net/images/{}/{}/{size}x{size}".format(
self.type,
self.md5,
@ -23,3 +20,10 @@ class Picture:
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

View File

@ -1,6 +1,6 @@
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):
@ -30,20 +30,17 @@ class Playlist:
picType = url[url.find('images/')+7:]
picType = picType[:picType.find('/')]
md5 = url[url.find(picType+'/') + len(picType)+1:-24]
self.pic = Picture(
md5 = md5,
pic_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(
art_id = playlistAPI['various_artist']['id'],
name = playlistAPI['various_artist']['name'],
role = "Main",
pic_md5 = pic_md5
playlistAPI['various_artist']['id'],
playlistAPI['various_artist']['name'],
"Main",
pic_md5
)
self.mainArtist = self.variousArtists

View File

@ -26,14 +26,14 @@ class Track:
self.duration = 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 = {}
@ -64,7 +64,7 @@ class Track:
self.fallbackID = "0"
if 'FALLBACK' in trackAPI_gw:
self.fallbackID = trackAPI_gw['FALLBACK']['SNG_ID']
self.localTrack = int(self.id) < 0
self.local = int(self.id) < 0
def retriveFilesizes(self, dz):
guest_sid = dz.session.cookies.get('sid')
@ -87,8 +87,8 @@ class Track:
sleep(2)
self.retriveFilesizes(dz)
if len(result_json['error']):
raise APIError(result_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_"):
@ -96,8 +96,8 @@ class Track:
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 and 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,7 +105,7 @@ class Track:
self.parseEssentialData(trackAPI_gw, trackAPI)
if self.localTrack:
if self.local:
self.parseLocalTrackData(trackAPI_gw)
else:
self.retriveFilesizes(dz)
@ -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) # TODO: Change
self.position = trackAPI_gw.get('POSITION')
# Add playlist data if track is in a playlist
@ -178,12 +178,11 @@ class Track:
md5 = trackAPI_gw.get('ALB_PICTURE', ""),
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']]
}
self.date = Date()
self.album.artist = self.artist
self.album.artists = self.artists
self.album.date = self.date
@ -207,14 +206,15 @@ class Track:
self.mainArtist = Artist(
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(day, month, year)
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,7 +249,7 @@ class Track:
return removeFeatures(self.title)
def getFeatTitle(self):
if self.featArtistsString and not "feat." in self.title.lower():
if self.featArtistsString and "feat." not in self.title.lower():
return f"{self.title} ({self.featArtistsString})"
return self.title
@ -259,26 +259,15 @@ class Track:
if 'Featured' in self.artist:
self.featArtistsString = "feat. "+andCommaConcat(self.artist['Featured'])
def applySettings(self, settings, TEMPDIR, embeddedImageFormat):
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)
self.album.embeddedCoverURL = self.playlist.pic.generatePictureURL(settings['embeddedArtworkSize'], embeddedImageFormat)
ext = self.album.embeddedCoverURL[-4:]
if ext[0] != ".": ext = ".jpg" # Check for Spotify images
# TODO: FIX
# self.album.embeddedCoverPath = TEMPDIR / f"pl{trackAPI_gw['_EXTRA_PLAYLIST']['id']}_{settings['embeddedArtworkSize']}{ext}"
else:
if self.album.date: self.date = self.album.date
self.album.embeddedCoverURL = self.album.pic.generatePictureURL(settings['embeddedArtworkSize'], embeddedImageFormat)
ext = self.album.embeddedCoverURL[-4:]
self.album.embeddedCoverPath = TEMPDIR / f"alb{self.album.id}_{settings['embeddedArtworkSize']}{ext}"
self.dateString = self.date.format(settings['dateFormat'])
self.album.dateString = self.album.date.format(settings['dateFormat'])
@ -311,9 +300,8 @@ class Track:
self.album.title = self.album.getCleanTitle()
# Remove (Album Version) from tracks that have that
if settings['removeAlbumVersion']:
if "Album Version" in self.title:
self.title = re.sub(r' ?\(Album Version\)', "", self.title).strip()
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":