Refactoring
This commit is contained in:
		@ -3,3 +3,4 @@
 | 
				
			|||||||
__version__ = "2.0.11"
 | 
					__version__ = "2.0.11"
 | 
				
			||||||
USER_AGENT_HEADER = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) " \
 | 
					USER_AGENT_HEADER = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) " \
 | 
				
			||||||
                    "Chrome/79.0.3945.130 Safari/537.36"
 | 
					                    "Chrome/79.0.3945.130 Safari/537.36"
 | 
				
			||||||
 | 
					VARIOUS_ARTISTS = "5080"
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@ from tempfile import gettempdir
 | 
				
			|||||||
from urllib3.exceptions import SSLError as u3SSLError
 | 
					from urllib3.exceptions import SSLError as u3SSLError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from deemix.app.queueitem import QISingle, QICollection
 | 
					from deemix.app.queueitem import QISingle, QICollection
 | 
				
			||||||
from deemix.app.track import Track, AlbumDoesntExists
 | 
					from deemix.types.Track import Track, AlbumDoesntExists
 | 
				
			||||||
from deemix.utils import changeCase
 | 
					from deemix.utils import changeCase
 | 
				
			||||||
from deemix.utils.pathtemplates import generateFilename, generateFilepath, settingsRegexAlbum, settingsRegexArtist, settingsRegexPlaylistFile
 | 
					from deemix.utils.pathtemplates import generateFilename, generateFilepath, settingsRegexAlbum, settingsRegexArtist, settingsRegexPlaylistFile
 | 
				
			||||||
from deezer import TrackFormats
 | 
					from deezer import TrackFormats
 | 
				
			||||||
@ -93,39 +93,6 @@ def downloadImage(url, path, overwrite=OverwriteOption.DONT_OVERWRITE):
 | 
				
			|||||||
    else:
 | 
					    else:
 | 
				
			||||||
        return path
 | 
					        return path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def generatePictureURL(pic, size, format):
 | 
					 | 
				
			||||||
    if pic['url']: return pic['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(
 | 
					 | 
				
			||||||
            pic['type'],
 | 
					 | 
				
			||||||
            pic['md5'],
 | 
					 | 
				
			||||||
            size, size,
 | 
					 | 
				
			||||||
            f'000000-{quality}-0-0.jpg'
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
    if format == 'png':
 | 
					 | 
				
			||||||
        return "https://e-cdns-images.dzcdn.net/images/{}/{}/{}x{}-{}".format(
 | 
					 | 
				
			||||||
            pic['type'],
 | 
					 | 
				
			||||||
            pic['md5'],
 | 
					 | 
				
			||||||
            size, size,
 | 
					 | 
				
			||||||
            'none-100-0-0.png'
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def formatDate(date, template):
 | 
					 | 
				
			||||||
    elements = {
 | 
					 | 
				
			||||||
        'year': ['YYYY', 'YY', 'Y'],
 | 
					 | 
				
			||||||
        'month': ['MM', 'M'],
 | 
					 | 
				
			||||||
        'day': ['DD', 'D']
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for element, placeholders in elements.items():
 | 
					 | 
				
			||||||
        for placeholder in placeholders:
 | 
					 | 
				
			||||||
            if placeholder in template:
 | 
					 | 
				
			||||||
                template = template.replace(placeholder, str(date[element]))
 | 
					 | 
				
			||||||
    return template
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DownloadJob:
 | 
					class DownloadJob:
 | 
				
			||||||
    def __init__(self, dz, queueItem, interface=None):
 | 
					    def __init__(self, dz, queueItem, interface=None):
 | 
				
			||||||
@ -251,10 +218,12 @@ class DownloadJob:
 | 
				
			|||||||
        if not track:
 | 
					        if not track:
 | 
				
			||||||
            logger.info(f"[{trackAPI_gw['ART_NAME']} - {trackAPI_gw['SNG_TITLE']}] Getting the tags")
 | 
					            logger.info(f"[{trackAPI_gw['ART_NAME']} - {trackAPI_gw['SNG_TITLE']}] Getting the tags")
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                track = Track(self.dz,
 | 
					                track = Track().parseData(
 | 
				
			||||||
 | 
					                    dz=self.dz,
 | 
				
			||||||
                    trackAPI_gw=trackAPI_gw,
 | 
					                    trackAPI_gw=trackAPI_gw,
 | 
				
			||||||
                    trackAPI=trackAPI_gw['_EXTRA_TRACK'] if '_EXTRA_TRACK' in trackAPI_gw else None,
 | 
					                    trackAPI=trackAPI_gw['_EXTRA_TRACK'] if '_EXTRA_TRACK' in trackAPI_gw else None,
 | 
				
			||||||
                              albumAPI=trackAPI_gw['_EXTRA_ALBUM'] if '_EXTRA_ALBUM' in trackAPI_gw else None
 | 
					                    albumAPI=trackAPI_gw['_EXTRA_ALBUM'] if '_EXTRA_ALBUM' in trackAPI_gw else None,
 | 
				
			||||||
 | 
					                    playlistAPI = trackAPI_gw['_EXTRA_PLAYLIST'] if '_EXTRA_PLAYLIST' in trackAPI_gw else None
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            except AlbumDoesntExists:
 | 
					            except AlbumDoesntExists:
 | 
				
			||||||
                raise DownloadError('albumDoesntExists')
 | 
					                raise DownloadError('albumDoesntExists')
 | 
				
			||||||
@ -263,16 +232,18 @@ class DownloadJob:
 | 
				
			|||||||
        # Check if track not yet encoded
 | 
					        # Check if track not yet encoded
 | 
				
			||||||
        if track.MD5 == '':
 | 
					        if track.MD5 == '':
 | 
				
			||||||
            if track.fallbackId != "0":
 | 
					            if track.fallbackId != "0":
 | 
				
			||||||
                logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not yet encoded, using fallback id")
 | 
					                logger.warn(f"[{track.mainArtist.name} - {track.title}] Track not yet encoded, using fallback id")
 | 
				
			||||||
                newTrack = self.dz.gw.get_track_with_fallback(track.fallbackId)
 | 
					                newTrack = self.dz.gw.get_track_with_fallback(track.fallbackId)
 | 
				
			||||||
                track.parseEssentialData(self.dz, newTrack)
 | 
					                track.parseEssentialData(newTrack)
 | 
				
			||||||
 | 
					                track.retriveFilesizes(self.dz)
 | 
				
			||||||
                return self.download(trackAPI_gw, track)
 | 
					                return self.download(trackAPI_gw, track)
 | 
				
			||||||
            elif not track.searched and self.settings['fallbackSearch']:
 | 
					            elif not track.searched and self.settings['fallbackSearch']:
 | 
				
			||||||
                logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not yet encoded, searching for alternative")
 | 
					                logger.warn(f"[{track.mainArtist.name} - {track.title}] Track not yet encoded, searching for alternative")
 | 
				
			||||||
                searchedId = self.dz.api.get_track_id_from_metadata(track.mainArtist['name'], track.title, track.album['title'])
 | 
					                searchedId = self.dz.api.get_track_id_from_metadata(track.mainArtist.name, track.title, track.album.title)
 | 
				
			||||||
                if searchedId != "0":
 | 
					                if searchedId != "0":
 | 
				
			||||||
                    newTrack = self.dz.gw.get_track_with_fallback(searchedId)
 | 
					                    newTrack = self.dz.gw.get_track_with_fallback(searchedId)
 | 
				
			||||||
                    track.parseEssentialData(self.dz, newTrack)
 | 
					                    track.parseEssentialData(newTrack)
 | 
				
			||||||
 | 
					                    track.retriveFilesizes(self.dz)
 | 
				
			||||||
                    track.searched = True
 | 
					                    track.searched = True
 | 
				
			||||||
                    if self.interface:
 | 
					                    if self.interface:
 | 
				
			||||||
                        self.interface.send('queueUpdate', {
 | 
					                        self.interface.send('queueUpdate', {
 | 
				
			||||||
@ -281,7 +252,7 @@ class DownloadJob:
 | 
				
			|||||||
                            'data': {
 | 
					                            'data': {
 | 
				
			||||||
                                'id': track.id,
 | 
					                                'id': track.id,
 | 
				
			||||||
                                'title': track.title,
 | 
					                                'title': track.title,
 | 
				
			||||||
                                'artist': track.mainArtist['name']
 | 
					                                'artist': track.mainArtist.name
 | 
				
			||||||
                            },
 | 
					                            },
 | 
				
			||||||
                        })
 | 
					                        })
 | 
				
			||||||
                    return self.download(trackAPI_gw, track)
 | 
					                    return self.download(trackAPI_gw, track)
 | 
				
			||||||
@ -295,16 +266,18 @@ class DownloadJob:
 | 
				
			|||||||
            selectedFormat = self.getPreferredBitrate(track)
 | 
					            selectedFormat = self.getPreferredBitrate(track)
 | 
				
			||||||
        except PreferredBitrateNotFound:
 | 
					        except PreferredBitrateNotFound:
 | 
				
			||||||
            if track.fallbackId != "0":
 | 
					            if track.fallbackId != "0":
 | 
				
			||||||
                logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not found at desired bitrate, using fallback id")
 | 
					                logger.warn(f"[{track.mainArtist.name} - {track.title}] Track not found at desired bitrate, using fallback id")
 | 
				
			||||||
                newTrack = self.dz.gw.get_track_with_fallback(track.fallbackId)
 | 
					                newTrack = self.dz.gw.get_track_with_fallback(track.fallbackId)
 | 
				
			||||||
                track.parseEssentialData(self.dz, newTrack)
 | 
					                track.parseEssentialData(newTrack)
 | 
				
			||||||
 | 
					                track.retriveFilesizes(self.dz)
 | 
				
			||||||
                return self.download(trackAPI_gw, track)
 | 
					                return self.download(trackAPI_gw, track)
 | 
				
			||||||
            elif not track.searched and self.settings['fallbackSearch']:
 | 
					            elif not track.searched and self.settings['fallbackSearch']:
 | 
				
			||||||
                logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not found at desired bitrate, searching for alternative")
 | 
					                logger.warn(f"[{track.mainArtist.name} - {track.title}] Track not found at desired bitrate, searching for alternative")
 | 
				
			||||||
                searchedId = self.dz.api.get_track_id_from_metadata(track.mainArtist['name'], track.title, track.album['title'])
 | 
					                searchedId = self.dz.api.get_track_id_from_metadata(track.mainArtist.name, track.title, track.album.title)
 | 
				
			||||||
                if searchedId != "0":
 | 
					                if searchedId != "0":
 | 
				
			||||||
                    newTrack = self.dz.gw.get_track_with_fallback(searchedId)
 | 
					                    newTrack = self.dz.gw.get_track_with_fallback(searchedId)
 | 
				
			||||||
                    track.parseEssentialData(self.dz, newTrack)
 | 
					                    track.parseEssentialData(newTrack)
 | 
				
			||||||
 | 
					                    track.retriveFilesizes(self.dz)
 | 
				
			||||||
                    track.searched = True
 | 
					                    track.searched = True
 | 
				
			||||||
                    if self.interface:
 | 
					                    if self.interface:
 | 
				
			||||||
                        self.interface.send('queueUpdate', {
 | 
					                        self.interface.send('queueUpdate', {
 | 
				
			||||||
@ -313,7 +286,7 @@ class DownloadJob:
 | 
				
			|||||||
                            'data': {
 | 
					                            'data': {
 | 
				
			||||||
                                'id': track.id,
 | 
					                                'id': track.id,
 | 
				
			||||||
                                'title': track.title,
 | 
					                                'title': track.title,
 | 
				
			||||||
                                'artist': track.mainArtist['name']
 | 
					                                'artist': track.mainArtist.name
 | 
				
			||||||
                            },
 | 
					                            },
 | 
				
			||||||
                        })
 | 
					                        })
 | 
				
			||||||
                    return self.download(trackAPI_gw, track)
 | 
					                    return self.download(trackAPI_gw, track)
 | 
				
			||||||
@ -324,7 +297,7 @@ class DownloadJob:
 | 
				
			|||||||
        except TrackNot360:
 | 
					        except TrackNot360:
 | 
				
			||||||
            raise DownloadFailed("no360RA")
 | 
					            raise DownloadFailed("no360RA")
 | 
				
			||||||
        track.selectedFormat = selectedFormat
 | 
					        track.selectedFormat = selectedFormat
 | 
				
			||||||
        track.album['bitrate'] = selectedFormat
 | 
					        track.album.bitrate = selectedFormat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Generate covers URLs
 | 
					        # Generate covers URLs
 | 
				
			||||||
        embeddedImageFormat = f'jpg-{self.settings["jpegImageQuality"]}'
 | 
					        embeddedImageFormat = f'jpg-{self.settings["jpegImageQuality"]}'
 | 
				
			||||||
@ -333,37 +306,37 @@ class DownloadJob:
 | 
				
			|||||||
        if self.settings['tags']['savePlaylistAsCompilation'] and track.playlist:
 | 
					        if self.settings['tags']['savePlaylistAsCompilation'] and track.playlist:
 | 
				
			||||||
            track.trackNumber = track.position
 | 
					            track.trackNumber = track.position
 | 
				
			||||||
            track.discNumber = "1"
 | 
					            track.discNumber = "1"
 | 
				
			||||||
            track.album = {**track.album, **track.playlist}
 | 
					            track.album.makePlaylistCompilation(track.playlist)
 | 
				
			||||||
            track.album['embeddedCoverURL'] = generatePictureURL(track.playlist['pic'], self.settings['embeddedArtworkSize'], embeddedImageFormat)
 | 
					            track.album.embeddedCoverURL = track.playlist.pic.generatePictureURL(self.settings['embeddedArtworkSize'], embeddedImageFormat)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ext = track.album['embeddedCoverURL'][-4:]
 | 
					            ext = track.album.embeddedCoverURL[-4:]
 | 
				
			||||||
            if ext[0] != ".": ext = ".jpg" # Check for Spotify images
 | 
					            if ext[0] != ".": ext = ".jpg" # Check for Spotify images
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            track.album['embeddedCoverPath'] = TEMPDIR / f"pl{trackAPI_gw['_EXTRA_PLAYLIST']['id']}_{self.settings['embeddedArtworkSize']}{ext}"
 | 
					            track.album.embeddedCoverPath = TEMPDIR / f"pl{trackAPI_gw['_EXTRA_PLAYLIST']['id']}_{self.settings['embeddedArtworkSize']}{ext}"
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            if track.album['date']: track.date = track.album['date']
 | 
					            if track.album.date: track.date = track.album.date
 | 
				
			||||||
            track.album['embeddedCoverURL'] = generatePictureURL(track.album['pic'], self.settings['embeddedArtworkSize'], embeddedImageFormat)
 | 
					            track.album.embeddedCoverURL = track.album.pic.generatePictureURL(self.settings['embeddedArtworkSize'], embeddedImageFormat)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ext = track.album['embeddedCoverURL'][-4:]
 | 
					            ext = track.album.embeddedCoverURL[-4:]
 | 
				
			||||||
            track.album['embeddedCoverPath'] = TEMPDIR / f"alb{track.album['id']}_{self.settings['embeddedArtworkSize']}{ext}"
 | 
					            track.album.embeddedCoverPath = TEMPDIR / f"alb{track.album.id}_{self.settings['embeddedArtworkSize']}{ext}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        track.dateString = formatDate(track.date, self.settings['dateFormat'])
 | 
					        track.dateString = track.date.format(self.settings['dateFormat'])
 | 
				
			||||||
        track.album['dateString'] = formatDate(track.album['date'], self.settings['dateFormat'])
 | 
					        track.album.dateString = track.album.date.format(self.settings['dateFormat'])
 | 
				
			||||||
        if track.playlist: track.playlist['dateString'] = formatDate(track.playlist['date'], self.settings['dateFormat'])
 | 
					        if track.playlist: track.playlist.dateString = track.playlist.date.format(self.settings['dateFormat'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Check various artist option
 | 
					        # Check various artist option
 | 
				
			||||||
        if self.settings['albumVariousArtists'] and track.album['variousArtists']:
 | 
					        if self.settings['albumVariousArtists'] and track.album.variousArtists:
 | 
				
			||||||
            artist = track.album['variousArtists']
 | 
					            artist = track.album.variousArtists
 | 
				
			||||||
            isMainArtist = artist['role'] == "Main"
 | 
					            isMainArtist = artist.role == "Main"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if artist['name'] not in track.album['artists']:
 | 
					            if artist.name not in track.album.artists:
 | 
				
			||||||
                track.album['artists'].insert(0, artist['name'])
 | 
					                track.album.artists.insert(0, artist.name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if isMainArtist or artist['name'] not in track.album['artist']['Main'] and not isMainArtist:
 | 
					            if isMainArtist or artist.name not in track.album.artist['Main'] and not isMainArtist:
 | 
				
			||||||
                if not artist['role'] in track.album['artist']:
 | 
					                if not artist.role in track.album.artist:
 | 
				
			||||||
                    track.album['artist'][artist['role']] = []
 | 
					                    track.album.artist[artist.role] = []
 | 
				
			||||||
                track.album['artist'][artist['role']].insert(0, artist['name'])
 | 
					                track.album.artist[artist.role].insert(0, artist.name)
 | 
				
			||||||
        track.album['mainArtist']['save'] = not track.album['mainArtist']['isVariousArtists'] or self.settings['albumVariousArtists'] and track.album['mainArtist']['isVariousArtists']
 | 
					        track.album.mainArtist.save = not track.album.mainArtist.isVariousArtists() or self.settings['albumVariousArtists'] and track.album.mainArtist.isVariousArtists()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Check removeDuplicateArtists
 | 
					        # Check removeDuplicateArtists
 | 
				
			||||||
        if self.settings['removeDuplicateArtists']: track.removeDuplicateArtists()
 | 
					        if self.settings['removeDuplicateArtists']: track.removeDuplicateArtists()
 | 
				
			||||||
@ -375,7 +348,7 @@ class DownloadJob:
 | 
				
			|||||||
            track.title = track.getFeatTitle()
 | 
					            track.title = track.getFeatTitle()
 | 
				
			||||||
        elif str(self.settings['featuredToTitle']) == FeaturesOption.REMOVE_TITLE_ALBUM:
 | 
					        elif str(self.settings['featuredToTitle']) == FeaturesOption.REMOVE_TITLE_ALBUM:
 | 
				
			||||||
            track.title = track.getCleanTitle()
 | 
					            track.title = track.getCleanTitle()
 | 
				
			||||||
            track.album['title'] = track.getCleanAlbumTitle()
 | 
					            track.album.title = track.album.getCleanTitle()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Remove (Album Version) from tracks that have that
 | 
					        # Remove (Album Version) from tracks that have that
 | 
				
			||||||
        if self.settings['removeAlbumVersion']:
 | 
					        if self.settings['removeAlbumVersion']:
 | 
				
			||||||
@ -386,7 +359,7 @@ class DownloadJob:
 | 
				
			|||||||
        if self.settings['titleCasing'] != "nothing":
 | 
					        if self.settings['titleCasing'] != "nothing":
 | 
				
			||||||
            track.title = changeCase(track.title, self.settings['titleCasing'])
 | 
					            track.title = changeCase(track.title, self.settings['titleCasing'])
 | 
				
			||||||
        if self.settings['artistCasing'] != "nothing":
 | 
					        if self.settings['artistCasing'] != "nothing":
 | 
				
			||||||
            track.mainArtist['name'] = changeCase(track.mainArtist['name'], self.settings['artistCasing'])
 | 
					            track.mainArtist.name = changeCase(track.mainArtist.name, self.settings['artistCasing'])
 | 
				
			||||||
            for i, artist in enumerate(track.artists):
 | 
					            for i, artist in enumerate(track.artists):
 | 
				
			||||||
                track.artists[i] = changeCase(artist, self.settings['artistCasing'])
 | 
					                track.artists[i] = changeCase(artist, self.settings['artistCasing'])
 | 
				
			||||||
            for type in track.artist:
 | 
					            for type in track.artist:
 | 
				
			||||||
@ -418,8 +391,8 @@ class DownloadJob:
 | 
				
			|||||||
        if self.queueItem.cancel: raise DownloadCancelled
 | 
					        if self.queueItem.cancel: raise DownloadCancelled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Download and cache coverart
 | 
					        # Download and cache coverart
 | 
				
			||||||
        logger.info(f"[{track.mainArtist['name']} - {track.title}] Getting the album cover")
 | 
					        logger.info(f"[{track.mainArtist.name} - {track.title}] Getting the album cover")
 | 
				
			||||||
        track.album['embeddedCoverPath'] = downloadImage(track.album['embeddedCoverURL'], track.album['embeddedCoverPath'])
 | 
					        track.album.embeddedCoverPath = downloadImage(track.album.embeddedCoverURL, track.album.embeddedCoverPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Save local album art
 | 
					        # Save local album art
 | 
				
			||||||
        if coverPath:
 | 
					        if coverPath:
 | 
				
			||||||
@ -428,10 +401,10 @@ class DownloadJob:
 | 
				
			|||||||
                if format in ["png","jpg"]:
 | 
					                if format in ["png","jpg"]:
 | 
				
			||||||
                    extendedFormat = format
 | 
					                    extendedFormat = format
 | 
				
			||||||
                    if extendedFormat == "jpg": extendedFormat += f"-{self.settings['jpegImageQuality']}"
 | 
					                    if extendedFormat == "jpg": extendedFormat += f"-{self.settings['jpegImageQuality']}"
 | 
				
			||||||
                    url = generatePictureURL(track.album['pic'], self.settings['localArtworkSize'], extendedFormat)
 | 
					                    url = track.album.pic.generatePictureURL(self.settings['localArtworkSize'], extendedFormat)
 | 
				
			||||||
                    if self.settings['tags']['savePlaylistAsCompilation'] \
 | 
					                    if self.settings['tags']['savePlaylistAsCompilation'] \
 | 
				
			||||||
                        and track.playlist \
 | 
					                        and track.playlist \
 | 
				
			||||||
                        and track.playlist['pic']['url'] \
 | 
					                        and track.playlist.pic.url \
 | 
				
			||||||
                        and not format.startswith("jpg"):
 | 
					                        and not format.startswith("jpg"):
 | 
				
			||||||
                            continue
 | 
					                            continue
 | 
				
			||||||
                    result['albumURLs'].append({'url': url, 'ext': format})
 | 
					                    result['albumURLs'].append({'url': url, 'ext': format})
 | 
				
			||||||
@ -445,11 +418,11 @@ class DownloadJob:
 | 
				
			|||||||
                if format in ["png","jpg"]:
 | 
					                if format in ["png","jpg"]:
 | 
				
			||||||
                    extendedFormat = format
 | 
					                    extendedFormat = format
 | 
				
			||||||
                    if extendedFormat == "jpg": extendedFormat += f"-{self.settings['jpegImageQuality']}"
 | 
					                    if extendedFormat == "jpg": extendedFormat += f"-{self.settings['jpegImageQuality']}"
 | 
				
			||||||
                    url = generatePictureURL(track.album['mainArtist']['pic'], self.settings['localArtworkSize'], extendedFormat)
 | 
					                    url = track.album.mainArtist.pic.generatePictureURL(self.settings['localArtworkSize'], extendedFormat)
 | 
				
			||||||
                    if track.album['mainArtist']['pic']['md5'] == "" and not format.startswith("jpg"): continue
 | 
					                    if track.album.mainArtist.pic.md5 == "" and not format.startswith("jpg"): continue
 | 
				
			||||||
                    result['artistURLs'].append({'url': url, 'ext': format})
 | 
					                    result['artistURLs'].append({'url': url, 'ext': format})
 | 
				
			||||||
            result['artistPath'] = artistPath
 | 
					            result['artistPath'] = artistPath
 | 
				
			||||||
            result['artistFilename'] = f"{settingsRegexArtist(self.settings['artistImageTemplate'], track.album['mainArtist'], self.settings, rootArtist=track.album['rootArtist'])}"
 | 
					            result['artistFilename'] = f"{settingsRegexArtist(self.settings['artistImageTemplate'], track.album.mainArtist, self.settings, rootArtist=track.album.rootArtist)}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Save playlist cover
 | 
					        # Save playlist cover
 | 
				
			||||||
        if track.playlist:
 | 
					        if track.playlist:
 | 
				
			||||||
@ -458,14 +431,12 @@ class DownloadJob:
 | 
				
			|||||||
                    if format in ["png","jpg"]:
 | 
					                    if format in ["png","jpg"]:
 | 
				
			||||||
                        extendedFormat = format
 | 
					                        extendedFormat = format
 | 
				
			||||||
                        if extendedFormat == "jpg": extendedFormat += f"-{self.settings['jpegImageQuality']}"
 | 
					                        if extendedFormat == "jpg": extendedFormat += f"-{self.settings['jpegImageQuality']}"
 | 
				
			||||||
                        url = generatePictureURL(track.playlist['pic'], self.settings['localArtworkSize'], extendedFormat)
 | 
					                        url = track.playlist.pic.generatePictureURL(self.settings['localArtworkSize'], extendedFormat)
 | 
				
			||||||
                        if track.playlist['pic']['url'] and not format.startswith("jpg"): continue
 | 
					                        if track.playlist.pic.url and not format.startswith("jpg"): continue
 | 
				
			||||||
                        self.playlistURLs.append({'url': url, 'ext': format})
 | 
					                        self.playlistURLs.append({'url': url, 'ext': format})
 | 
				
			||||||
            if not self.playlistCoverName:
 | 
					            if not self.playlistCoverName:
 | 
				
			||||||
                track.playlist['id'] = "pl_" + str(trackAPI_gw['_EXTRA_PLAYLIST']['id'])
 | 
					                track.playlist.bitrate = selectedFormat
 | 
				
			||||||
                track.playlist['genre'] = ["Compilation", ]
 | 
					                track.playlist.dateString = track.playlist.date.format(self.settings['dateFormat'])
 | 
				
			||||||
                track.playlist['bitrate'] = selectedFormat
 | 
					 | 
				
			||||||
                track.playlist['dateString'] = formatDate(track.playlist['date'], self.settings['dateFormat'])
 | 
					 | 
				
			||||||
                self.playlistCoverName = f"{settingsRegexAlbum(self.settings['coverImageTemplate'], track.playlist, self.settings, track.playlist)}"
 | 
					                self.playlistCoverName = f"{settingsRegexAlbum(self.settings['coverImageTemplate'], track.playlist, self.settings, track.playlist)}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Remove subfolders from filename and add it to filepath
 | 
					        # Remove subfolders from filename and add it to filepath
 | 
				
			||||||
@ -510,7 +481,7 @@ class DownloadJob:
 | 
				
			|||||||
            result['filename'] = str(writepath)[len(str(extrasPath))+ len(pathSep):]
 | 
					            result['filename'] = str(writepath)[len(str(extrasPath))+ len(pathSep):]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not trackAlreadyDownloaded or self.settings['overwriteFile'] == OverwriteOption.OVERWRITE:
 | 
					        if not trackAlreadyDownloaded or self.settings['overwriteFile'] == OverwriteOption.OVERWRITE:
 | 
				
			||||||
            logger.info(f"[{track.mainArtist['name']} - {track.title}] Downloading the track")
 | 
					            logger.info(f"[{track.mainArtist.name} - {track.title}] Downloading the track")
 | 
				
			||||||
            track.downloadUrl = generateStreamURL(track.id, track.MD5, track.mediaVersion, track.selectedFormat)
 | 
					            track.downloadUrl = generateStreamURL(track.id, track.MD5, track.mediaVersion, track.selectedFormat)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            def downloadMusic(track, trackAPI_gw):
 | 
					            def downloadMusic(track, trackAPI_gw):
 | 
				
			||||||
@ -523,16 +494,18 @@ class DownloadJob:
 | 
				
			|||||||
                except (request_exception.HTTPError, DownloadEmpty):
 | 
					                except (request_exception.HTTPError, DownloadEmpty):
 | 
				
			||||||
                    if writepath.is_file(): writepath.unlink()
 | 
					                    if writepath.is_file(): writepath.unlink()
 | 
				
			||||||
                    if track.fallbackId != "0":
 | 
					                    if track.fallbackId != "0":
 | 
				
			||||||
                        logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not available, using fallback id")
 | 
					                        logger.warn(f"[{track.mainArtist.name} - {track.title}] Track not available, using fallback id")
 | 
				
			||||||
                        newTrack = self.dz.gw.get_track_with_fallback(track.fallbackId)
 | 
					                        newTrack = self.dz.gw.get_track_with_fallback(track.fallbackId)
 | 
				
			||||||
                        track.parseEssentialData(self.dz, newTrack)
 | 
					                        track.parseEssentialData(newTrack)
 | 
				
			||||||
 | 
					                        track.retriveFilesizes(self.dz)
 | 
				
			||||||
                        return False
 | 
					                        return False
 | 
				
			||||||
                    elif not track.searched and self.settings['fallbackSearch']:
 | 
					                    elif not track.searched and self.settings['fallbackSearch']:
 | 
				
			||||||
                        logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not available, searching for alternative")
 | 
					                        logger.warn(f"[{track.mainArtist.name} - {track.title}] Track not available, searching for alternative")
 | 
				
			||||||
                        searchedId = self.dz.api.get_track_id_from_metadata(track.mainArtist['name'], track.title, track.album['title'])
 | 
					                        searchedId = self.dz.api.get_track_id_from_metadata(track.mainArtist.name, track.title, track.album.title)
 | 
				
			||||||
                        if searchedId != "0":
 | 
					                        if searchedId != "0":
 | 
				
			||||||
                            newTrack = self.dz.gw.get_track_with_fallback(searchedId)
 | 
					                            newTrack = self.dz.gw.get_track_with_fallback(searchedId)
 | 
				
			||||||
                            track.parseEssentialData(self.dz, newTrack)
 | 
					                            track.parseEssentialData(newTrack)
 | 
				
			||||||
 | 
					                            track.retriveFilesizes(self.dz)
 | 
				
			||||||
                            track.searched = True
 | 
					                            track.searched = True
 | 
				
			||||||
                            if self.interface:
 | 
					                            if self.interface:
 | 
				
			||||||
                                self.interface.send('queueUpdate', {
 | 
					                                self.interface.send('queueUpdate', {
 | 
				
			||||||
@ -541,7 +514,7 @@ class DownloadJob:
 | 
				
			|||||||
                                    'data': {
 | 
					                                    'data': {
 | 
				
			||||||
                                        'id': track.id,
 | 
					                                        'id': track.id,
 | 
				
			||||||
                                        'title': track.title,
 | 
					                                        'title': track.title,
 | 
				
			||||||
                                        'artist': track.mainArtist['name']
 | 
					                                        'artist': track.mainArtist.name
 | 
				
			||||||
                                    },
 | 
					                                    },
 | 
				
			||||||
                                })
 | 
					                                })
 | 
				
			||||||
                            return False
 | 
					                            return False
 | 
				
			||||||
@ -551,7 +524,7 @@ class DownloadJob:
 | 
				
			|||||||
                        raise DownloadFailed("notAvailable")
 | 
					                        raise DownloadFailed("notAvailable")
 | 
				
			||||||
                except (request_exception.ConnectionError, request_exception.ChunkedEncodingError) as e:
 | 
					                except (request_exception.ConnectionError, request_exception.ChunkedEncodingError) as e:
 | 
				
			||||||
                    if writepath.is_file(): writepath.unlink()
 | 
					                    if writepath.is_file(): writepath.unlink()
 | 
				
			||||||
                    logger.warn(f"[{track.mainArtist['name']} - {track.title}] Error while downloading the track, trying again in 5s...")
 | 
					                    logger.warn(f"[{track.mainArtist.name} - {track.title}] Error while downloading the track, trying again in 5s...")
 | 
				
			||||||
                    eventlet.sleep(5)
 | 
					                    eventlet.sleep(5)
 | 
				
			||||||
                    return downloadMusic(track, trackAPI_gw)
 | 
					                    return downloadMusic(track, trackAPI_gw)
 | 
				
			||||||
                except OSError as e:
 | 
					                except OSError as e:
 | 
				
			||||||
@ -559,11 +532,11 @@ class DownloadJob:
 | 
				
			|||||||
                        raise DownloadFailed("noSpaceLeft")
 | 
					                        raise DownloadFailed("noSpaceLeft")
 | 
				
			||||||
                    else:
 | 
					                    else:
 | 
				
			||||||
                        if writepath.is_file(): writepath.unlink()
 | 
					                        if writepath.is_file(): writepath.unlink()
 | 
				
			||||||
                        logger.exception(f"[{track.mainArtist['name']} - {track.title}] Error while downloading the track, you should report this to the developers: {str(e)}")
 | 
					                        logger.exception(f"[{track.mainArtist.name} - {track.title}] Error while downloading the track, you should report this to the developers: {str(e)}")
 | 
				
			||||||
                        raise e
 | 
					                        raise e
 | 
				
			||||||
                except Exception as e:
 | 
					                except Exception as e:
 | 
				
			||||||
                    if writepath.is_file(): writepath.unlink()
 | 
					                    if writepath.is_file(): writepath.unlink()
 | 
				
			||||||
                    logger.exception(f"[{track.mainArtist['name']} - {track.title}] Error while downloading the track, you should report this to the developers: {str(e)}")
 | 
					                    logger.exception(f"[{track.mainArtist.name} - {track.title}] Error while downloading the track, you should report this to the developers: {str(e)}")
 | 
				
			||||||
                    raise e
 | 
					                    raise e
 | 
				
			||||||
                return True
 | 
					                return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -574,12 +547,12 @@ class DownloadJob:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if not trackDownloaded: return self.download(trackAPI_gw, track)
 | 
					            if not trackDownloaded: return self.download(trackAPI_gw, track)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            logger.info(f"[{track.mainArtist['name']} - {track.title}] Skipping track as it's already downloaded")
 | 
					            logger.info(f"[{track.mainArtist.name} - {track.title}] Skipping track as it's already downloaded")
 | 
				
			||||||
            self.completeTrackPercentage()
 | 
					            self.completeTrackPercentage()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Adding tags
 | 
					        # Adding tags
 | 
				
			||||||
        if (not trackAlreadyDownloaded or self.settings['overwriteFile'] in [OverwriteOption.ONLY_TAGS, OverwriteOption.OVERWRITE]) and not track.localTrack:
 | 
					        if (not trackAlreadyDownloaded or self.settings['overwriteFile'] in [OverwriteOption.ONLY_TAGS, OverwriteOption.OVERWRITE]) and not track.localTrack:
 | 
				
			||||||
            logger.info(f"[{track.mainArtist['name']} - {track.title}] Applying tags to the track")
 | 
					            logger.info(f"[{track.mainArtist.name} - {track.title}] Applying tags to the track")
 | 
				
			||||||
            if track.selectedFormat in [TrackFormats.MP3_320, TrackFormats.MP3_128, TrackFormats.DEFAULT]:
 | 
					            if track.selectedFormat in [TrackFormats.MP3_320, TrackFormats.MP3_128, TrackFormats.DEFAULT]:
 | 
				
			||||||
                tagID3(writepath, track, self.settings['tags'])
 | 
					                tagID3(writepath, track, self.settings['tags'])
 | 
				
			||||||
            elif track.selectedFormat ==  TrackFormats.FLAC:
 | 
					            elif track.selectedFormat ==  TrackFormats.FLAC:
 | 
				
			||||||
@ -587,14 +560,14 @@ class DownloadJob:
 | 
				
			|||||||
                    tagFLAC(writepath, track, self.settings['tags'])
 | 
					                    tagFLAC(writepath, track, self.settings['tags'])
 | 
				
			||||||
                except (FLACNoHeaderError, FLACError):
 | 
					                except (FLACNoHeaderError, FLACError):
 | 
				
			||||||
                    if writepath.is_file(): writepath.unlink()
 | 
					                    if writepath.is_file(): writepath.unlink()
 | 
				
			||||||
                    logger.warn(f"[{track.mainArtist['name']} - {track.title}] Track not available in FLAC, falling back if necessary")
 | 
					                    logger.warn(f"[{track.mainArtist.name} - {track.title}] Track not available in FLAC, falling back if necessary")
 | 
				
			||||||
                    self.removeTrackPercentage()
 | 
					                    self.removeTrackPercentage()
 | 
				
			||||||
                    track.filesizes['FILESIZE_FLAC'] = "0"
 | 
					                    track.filesizes['FILESIZE_FLAC'] = "0"
 | 
				
			||||||
                    track.filesizes['FILESIZE_FLAC_TESTED'] = True
 | 
					                    track.filesizes['FILESIZE_FLAC_TESTED'] = True
 | 
				
			||||||
                    return self.download(trackAPI_gw, track)
 | 
					                    return self.download(trackAPI_gw, track)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if track.searched: result['searched'] = f"{track.mainArtist['name']} - {track.title}"
 | 
					        if track.searched: result['searched'] = f"{track.mainArtist.name} - {track.title}"
 | 
				
			||||||
        logger.info(f"[{track.mainArtist['name']} - {track.title}] Track download completed\n{str(writepath)}")
 | 
					        logger.info(f"[{track.mainArtist.name} - {track.title}] Track download completed\n{str(writepath)}")
 | 
				
			||||||
        self.queueItem.downloaded += 1
 | 
					        self.queueItem.downloaded += 1
 | 
				
			||||||
        self.queueItem.files.append(str(writepath))
 | 
					        self.queueItem.files.append(str(writepath))
 | 
				
			||||||
        self.queueItem.extrasPath = str(self.extrasPath)
 | 
					        self.queueItem.extrasPath = str(self.extrasPath)
 | 
				
			||||||
@ -649,7 +622,7 @@ class DownloadJob:
 | 
				
			|||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    if not falledBack:
 | 
					                    if not falledBack:
 | 
				
			||||||
                        falledBack = True
 | 
					                        falledBack = True
 | 
				
			||||||
                        logger.info(f"[{track.mainArtist['name']} - {track.title}] Fallback to lower bitrate")
 | 
					                        logger.info(f"[{track.mainArtist.name} - {track.title}] Fallback to lower bitrate")
 | 
				
			||||||
                        if self.interface:
 | 
					                        if self.interface:
 | 
				
			||||||
                            self.interface.send('queueUpdate', {
 | 
					                            self.interface.send('queueUpdate', {
 | 
				
			||||||
                                'uuid': self.queueItem.uuid,
 | 
					                                'uuid': self.queueItem.uuid,
 | 
				
			||||||
@ -657,7 +630,7 @@ class DownloadJob:
 | 
				
			|||||||
                                'data': {
 | 
					                                'data': {
 | 
				
			||||||
                                    'id': track.id,
 | 
					                                    'id': track.id,
 | 
				
			||||||
                                    'title': track.title,
 | 
					                                    'title': track.title,
 | 
				
			||||||
                                    'artist': track.mainArtist['name']
 | 
					                                    'artist': track.mainArtist.name
 | 
				
			||||||
                                },
 | 
					                                },
 | 
				
			||||||
                            })
 | 
					                            })
 | 
				
			||||||
        if is360format: raise TrackNot360
 | 
					        if is360format: raise TrackNot360
 | 
				
			||||||
@ -671,7 +644,7 @@ class DownloadJob:
 | 
				
			|||||||
        chunkLength = start
 | 
					        chunkLength = start
 | 
				
			||||||
        percentage = 0
 | 
					        percentage = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        itemName = f"[{track.mainArtist['name']} - {track.title}]"
 | 
					        itemName = f"[{track.mainArtist.name} - {track.title}]"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            with self.dz.session.get(track.downloadUrl, headers=headers, stream=True, timeout=10) as request:
 | 
					            with self.dz.session.get(track.downloadUrl, headers=headers, stream=True, timeout=10) as request:
 | 
				
			||||||
 | 
				
			|||||||
@ -1,476 +0,0 @@
 | 
				
			|||||||
import eventlet
 | 
					 | 
				
			||||||
requests = eventlet.import_patched('requests')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import logging
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from deezer.gw import APIError as gwAPIError, LyricsStatus
 | 
					 | 
				
			||||||
from deezer.api import APIError
 | 
					 | 
				
			||||||
from deemix.utils import removeFeatures, andCommaConcat, uniqueArray, generateReplayGainString
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
logging.basicConfig(level=logging.INFO)
 | 
					 | 
				
			||||||
logger = logging.getLogger('deemix')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VARIOUS_ARTISTS = 5080
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Track:
 | 
					 | 
				
			||||||
    def __init__(self, dz, trackAPI_gw, trackAPI=None, albumAPI_gw=None, albumAPI=None):
 | 
					 | 
				
			||||||
        self.parseEssentialData(dz, 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()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.position = trackAPI_gw.get('POSITION')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.localTrack = int(self.id) < 0
 | 
					 | 
				
			||||||
        if self.localTrack:
 | 
					 | 
				
			||||||
            self.parseLocalTrackData(trackAPI_gw)
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            self.parseData(dz, trackAPI_gw, trackAPI, albumAPI_gw, albumAPI)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Make sure there is at least one artist
 | 
					 | 
				
			||||||
        if not 'Main' in self.artist:
 | 
					 | 
				
			||||||
            self.artist['Main'] = [self.mainArtist['name']]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Fix incorrect day month when detectable
 | 
					 | 
				
			||||||
        if int(self.date['month']) > 12:
 | 
					 | 
				
			||||||
            monthTemp = self.date['month']
 | 
					 | 
				
			||||||
            self.date['month'] = self.date['day']
 | 
					 | 
				
			||||||
            self.date['day'] = monthTemp
 | 
					 | 
				
			||||||
        if int(self.album['date']['month']) > 12:
 | 
					 | 
				
			||||||
            monthTemp = self.album['date']['month']
 | 
					 | 
				
			||||||
            self.album['date']['month'] = self.album['date']['day']
 | 
					 | 
				
			||||||
            self.album['date']['day'] = monthTemp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Add playlist data if track is in a playlist
 | 
					 | 
				
			||||||
        self.playlist = None
 | 
					 | 
				
			||||||
        if "_EXTRA_PLAYLIST" in trackAPI_gw:
 | 
					 | 
				
			||||||
            self.parsePlaylistData(trackAPI_gw["_EXTRA_PLAYLIST"])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.singleDownload = trackAPI_gw.get('SINGLE_TRACK', False)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.generateMainFeatStrings()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Bits useful for later
 | 
					 | 
				
			||||||
        self.searched = False
 | 
					 | 
				
			||||||
        self.selectedFormat = 0
 | 
					 | 
				
			||||||
        self.dateString = None
 | 
					 | 
				
			||||||
        self.album['embeddedCoverURL'] = None
 | 
					 | 
				
			||||||
        self.album['embeddedCoverPath'] = None
 | 
					 | 
				
			||||||
        self.album['bitrate'] = 0
 | 
					 | 
				
			||||||
        self.album['dateString'] = None
 | 
					 | 
				
			||||||
        self.artistsString = ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def parseEssentialData(self, dz, trackAPI_gw):
 | 
					 | 
				
			||||||
        self.id = trackAPI_gw['SNG_ID']
 | 
					 | 
				
			||||||
        self.duration = trackAPI_gw['DURATION']
 | 
					 | 
				
			||||||
        self.MD5 = trackAPI_gw['MD5_ORIGIN']
 | 
					 | 
				
			||||||
        self.mediaVersion = trackAPI_gw['MEDIA_VERSION']
 | 
					 | 
				
			||||||
        self.fallbackId = "0"
 | 
					 | 
				
			||||||
        if 'FALLBACK' in trackAPI_gw:
 | 
					 | 
				
			||||||
            self.fallbackId = trackAPI_gw['FALLBACK']['SNG_ID']
 | 
					 | 
				
			||||||
        if int(self.id) > 0:
 | 
					 | 
				
			||||||
            self.filesizes = self.getFilesizes(dz)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def parseLocalTrackData(self, trackAPI_gw):
 | 
					 | 
				
			||||||
        # Local tracks has only the trackAPI_gw page and
 | 
					 | 
				
			||||||
        # contains only the tags provided by the file
 | 
					 | 
				
			||||||
        self.album = {
 | 
					 | 
				
			||||||
            'id': "0",
 | 
					 | 
				
			||||||
            'title': trackAPI_gw['ALB_TITLE'],
 | 
					 | 
				
			||||||
            'pic': {
 | 
					 | 
				
			||||||
                'md5': trackAPI_gw.get('ALB_PICTURE', ""),
 | 
					 | 
				
			||||||
                'type': "cover",
 | 
					 | 
				
			||||||
                'url': None
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        self.mainArtist = {
 | 
					 | 
				
			||||||
            'id': "0",
 | 
					 | 
				
			||||||
            'name': trackAPI_gw['ART_NAME'],
 | 
					 | 
				
			||||||
            'pic': {
 | 
					 | 
				
			||||||
                'md5': "",
 | 
					 | 
				
			||||||
                'type': "artist",
 | 
					 | 
				
			||||||
                'url': None
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        self.artists = [trackAPI_gw['ART_NAME']]
 | 
					 | 
				
			||||||
        self.artist = {
 | 
					 | 
				
			||||||
            'Main': [trackAPI_gw['ART_NAME']]
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        self.date = {
 | 
					 | 
				
			||||||
            'day': "00",
 | 
					 | 
				
			||||||
            'month': "00",
 | 
					 | 
				
			||||||
            'year': "XXXX"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        # Defaulting all the missing data
 | 
					 | 
				
			||||||
        self.ISRC = ""
 | 
					 | 
				
			||||||
        self.album['artist'] = self.artist
 | 
					 | 
				
			||||||
        self.album['artists'] = self.artists
 | 
					 | 
				
			||||||
        self.album['barcode'] = "Unknown"
 | 
					 | 
				
			||||||
        self.album['date'] = self.date
 | 
					 | 
				
			||||||
        self.album['discTotal'] = "0"
 | 
					 | 
				
			||||||
        self.album['explicit'] = False
 | 
					 | 
				
			||||||
        self.album['genre'] = []
 | 
					 | 
				
			||||||
        self.album['label'] = "Unknown"
 | 
					 | 
				
			||||||
        self.album['mainArtist'] = self.mainArtist
 | 
					 | 
				
			||||||
        self.album['mainArtist']['isVariousArtists'] = False
 | 
					 | 
				
			||||||
        self.album['variousArtists'] = None
 | 
					 | 
				
			||||||
        self.album['rootArtist'] = None
 | 
					 | 
				
			||||||
        self.album['recordType'] = "album"
 | 
					 | 
				
			||||||
        self.album['trackTotal'] = "0"
 | 
					 | 
				
			||||||
        self.bpm = 0
 | 
					 | 
				
			||||||
        self.contributors = {}
 | 
					 | 
				
			||||||
        self.copyright = ""
 | 
					 | 
				
			||||||
        self.discNumber = "0"
 | 
					 | 
				
			||||||
        self.explicit = False
 | 
					 | 
				
			||||||
        self.lyrics = {}
 | 
					 | 
				
			||||||
        self.replayGain = ""
 | 
					 | 
				
			||||||
        self.trackNumber = "0"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def parseData(self, dz, trackAPI_gw, trackAPI, albumAPI_gw, albumAPI):
 | 
					 | 
				
			||||||
        self.discNumber = trackAPI_gw.get('DISK_NUMBER')
 | 
					 | 
				
			||||||
        self.explicit = bool(int(trackAPI_gw.get('EXPLICIT_LYRICS', "0")))
 | 
					 | 
				
			||||||
        self.copyright = trackAPI_gw.get('COPYRIGHT')
 | 
					 | 
				
			||||||
        self.replayGain = ""
 | 
					 | 
				
			||||||
        if 'GAIN' in trackAPI_gw: self.replayGain = generateReplayGainString(trackAPI_gw['GAIN'])
 | 
					 | 
				
			||||||
        self.ISRC = trackAPI_gw.get('ISRC')
 | 
					 | 
				
			||||||
        self.trackNumber = trackAPI_gw['TRACK_NUMBER']
 | 
					 | 
				
			||||||
        self.contributors = trackAPI_gw['SNG_CONTRIBUTORS']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.lyrics = {
 | 
					 | 
				
			||||||
            'id': int(trackAPI_gw.get('LYRICS_ID', "0")),
 | 
					 | 
				
			||||||
            'unsync': None,
 | 
					 | 
				
			||||||
            'sync': None,
 | 
					 | 
				
			||||||
            'syncID3': None
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if not "LYRICS" in trackAPI_gw and self.lyrics['id'] != 0:
 | 
					 | 
				
			||||||
            logger.info(f"[{trackAPI_gw['ART_NAME']} - {self.title}] Getting lyrics")
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                trackAPI_gw["LYRICS"] = dz.gw.get_track_lyrics(self.id)
 | 
					 | 
				
			||||||
            except gwAPIError:
 | 
					 | 
				
			||||||
                self.lyrics['id'] = 0
 | 
					 | 
				
			||||||
        if self.lyrics['id'] != 0:
 | 
					 | 
				
			||||||
            self.lyrics['unsync'] = trackAPI_gw["LYRICS"].get("LYRICS_TEXT")
 | 
					 | 
				
			||||||
            if "LYRICS_SYNC_JSON" in trackAPI_gw["LYRICS"]:
 | 
					 | 
				
			||||||
                syncLyricsJson = trackAPI_gw["LYRICS"]["LYRICS_SYNC_JSON"]
 | 
					 | 
				
			||||||
                self.lyrics['sync'] = ""
 | 
					 | 
				
			||||||
                self.lyrics['syncID3'] = []
 | 
					 | 
				
			||||||
                timestamp = ""
 | 
					 | 
				
			||||||
                milliseconds = 0
 | 
					 | 
				
			||||||
                for line in range(len(syncLyricsJson)):
 | 
					 | 
				
			||||||
                    if syncLyricsJson[line]["line"] != "":
 | 
					 | 
				
			||||||
                        timestamp = syncLyricsJson[line]["lrc_timestamp"]
 | 
					 | 
				
			||||||
                        milliseconds = int(syncLyricsJson[line]["milliseconds"])
 | 
					 | 
				
			||||||
                        self.lyrics['syncID3'].append((syncLyricsJson[line]["line"], milliseconds))
 | 
					 | 
				
			||||||
                    else:
 | 
					 | 
				
			||||||
                        notEmptyLine = line + 1
 | 
					 | 
				
			||||||
                        while syncLyricsJson[notEmptyLine]["line"] == "":
 | 
					 | 
				
			||||||
                            notEmptyLine = notEmptyLine + 1
 | 
					 | 
				
			||||||
                        timestamp = syncLyricsJson[notEmptyLine]["lrc_timestamp"]
 | 
					 | 
				
			||||||
                    self.lyrics['sync'] += timestamp + syncLyricsJson[line]["line"] + "\r\n"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.mainArtist = {
 | 
					 | 
				
			||||||
            'id': trackAPI_gw['ART_ID'],
 | 
					 | 
				
			||||||
            'name': trackAPI_gw['ART_NAME'],
 | 
					 | 
				
			||||||
            'pic': {
 | 
					 | 
				
			||||||
                'md5': trackAPI_gw.get('ART_PICTURE'),
 | 
					 | 
				
			||||||
                'type': "artist",
 | 
					 | 
				
			||||||
                'url': None
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.date = None
 | 
					 | 
				
			||||||
        if 'PHYSICAL_RELEASE_DATE' in trackAPI_gw:
 | 
					 | 
				
			||||||
            self.date = {
 | 
					 | 
				
			||||||
                '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.album = {
 | 
					 | 
				
			||||||
            'id': trackAPI_gw['ALB_ID'],
 | 
					 | 
				
			||||||
            'title': trackAPI_gw['ALB_TITLE'],
 | 
					 | 
				
			||||||
            'pic': {
 | 
					 | 
				
			||||||
                'md5': trackAPI_gw.get('ALB_PICTURE'),
 | 
					 | 
				
			||||||
                'type': "cover",
 | 
					 | 
				
			||||||
                'url': None
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            'barcode': "Unknown",
 | 
					 | 
				
			||||||
            'label': "Unknown",
 | 
					 | 
				
			||||||
            'explicit': False,
 | 
					 | 
				
			||||||
            'date': None,
 | 
					 | 
				
			||||||
            'genre': []
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Try the public API first (as it has more data)
 | 
					 | 
				
			||||||
        if not albumAPI:
 | 
					 | 
				
			||||||
            logger.info(f"[{self.mainArtist['name']} - {self.title}] Getting album infos")
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                albumAPI = dz.api.get_album(self.album['id'])
 | 
					 | 
				
			||||||
            except APIError:
 | 
					 | 
				
			||||||
                albumAPI = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.album['variousArtists'] = None
 | 
					 | 
				
			||||||
        if albumAPI:
 | 
					 | 
				
			||||||
            self.album['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]
 | 
					 | 
				
			||||||
            self.album['mainArtist'] = {
 | 
					 | 
				
			||||||
                'id': albumAPI['artist']['id'],
 | 
					 | 
				
			||||||
                'name': albumAPI['artist']['name'],
 | 
					 | 
				
			||||||
                'pic': {
 | 
					 | 
				
			||||||
                    'md5': artistPicture,
 | 
					 | 
				
			||||||
                    'type': "artist",
 | 
					 | 
				
			||||||
                    'url': None
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            self.album['rootArtist'] = albumAPI.get('root_artist', None)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            self.album['artist'] = {'Main': []}
 | 
					 | 
				
			||||||
            self.album['artists'] = []
 | 
					 | 
				
			||||||
            for artist in albumAPI['contributors']:
 | 
					 | 
				
			||||||
                isVariousArtists = artist['id'] == VARIOUS_ARTISTS
 | 
					 | 
				
			||||||
                isMainArtist = artist['role'] == "Main"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if isVariousArtists:
 | 
					 | 
				
			||||||
                    self.album['variousArtists'] = artist
 | 
					 | 
				
			||||||
                    continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if artist['name'] not in self.album['artists']:
 | 
					 | 
				
			||||||
                    self.album['artists'].append(artist['name'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if isMainArtist or artist['name'] not in self.album['artist']['Main'] and not isMainArtist:
 | 
					 | 
				
			||||||
                    if not artist['role'] in self.album['artist']:
 | 
					 | 
				
			||||||
                        self.album['artist'][artist['role']] = []
 | 
					 | 
				
			||||||
                    self.album['artist'][artist['role']].append(artist['name'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            self.album['trackTotal'] = albumAPI['nb_tracks']
 | 
					 | 
				
			||||||
            self.album['recordType'] = albumAPI['record_type']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            self.album['barcode'] = albumAPI.get('upc', self.album['barcode'])
 | 
					 | 
				
			||||||
            self.album['label'] = albumAPI.get('label', self.album['label'])
 | 
					 | 
				
			||||||
            self.album['explicit'] = bool(albumAPI.get('explicit_lyrics', False))
 | 
					 | 
				
			||||||
            if 'release_date' in albumAPI:
 | 
					 | 
				
			||||||
                self.album['date'] = {
 | 
					 | 
				
			||||||
                    'day': albumAPI["release_date"][8:10],
 | 
					 | 
				
			||||||
                    'month': albumAPI["release_date"][5:7],
 | 
					 | 
				
			||||||
                    'year': albumAPI["release_date"][0:4]
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            self.album['discTotal'] = albumAPI.get('nb_disk', "1")
 | 
					 | 
				
			||||||
            self.copyright = albumAPI.get('copyright')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if not self.album['pic']['md5']:
 | 
					 | 
				
			||||||
                # Getting album cover MD5
 | 
					 | 
				
			||||||
                # ex: https://e-cdns-images.dzcdn.net/images/cover/2e018122cb56986277102d2041a592c8/56x56-000000-80-0-0.jpg
 | 
					 | 
				
			||||||
                self.album['pic']['md5'] = albumAPI['cover_small'][albumAPI['cover_small'].find('cover/') + 6:-24]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if albumAPI.get('genres') and len(albumAPI['genres'].get('data', [])) > 0:
 | 
					 | 
				
			||||||
                for genre in albumAPI['genres']['data']:
 | 
					 | 
				
			||||||
                    self.album['genre'].append(genre['name'])
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            if not albumAPI_gw:
 | 
					 | 
				
			||||||
                logger.info(f"[{self.mainArtist['name']} - {self.title}] Getting more album infos")
 | 
					 | 
				
			||||||
                try:
 | 
					 | 
				
			||||||
                    albumAPI_gw = dz.gw.get_album(self.album['id'])
 | 
					 | 
				
			||||||
                except gwAPIError:
 | 
					 | 
				
			||||||
                    albumAPI_gw = None
 | 
					 | 
				
			||||||
                    raise AlbumDoesntExists
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            self.album['title'] = albumAPI_gw['ALB_TITLE']
 | 
					 | 
				
			||||||
            self.album['mainArtist'] = {
 | 
					 | 
				
			||||||
                'id': albumAPI_gw['ART_ID'],
 | 
					 | 
				
			||||||
                'name': albumAPI_gw['ART_NAME'],
 | 
					 | 
				
			||||||
                'pic': {
 | 
					 | 
				
			||||||
                    'md5': "",
 | 
					 | 
				
			||||||
                    'type': "artist",
 | 
					 | 
				
			||||||
                    'url': None
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            self.album['rootArtist'] = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # albumAPI_gw doesn't contain the artist cover
 | 
					 | 
				
			||||||
            # Getting artist image ID
 | 
					 | 
				
			||||||
            # ex: https://e-cdns-images.dzcdn.net/images/artist/f2bc007e9133c946ac3c3907ddc5d2ea/56x56-000000-80-0-0.jpg
 | 
					 | 
				
			||||||
            logger.info(f"[{self.mainArtist['name']} - {self.title}] Getting artist picture fallback")
 | 
					 | 
				
			||||||
            artistAPI = dz.api.get_artist(self.album['mainArtist']['id'])
 | 
					 | 
				
			||||||
            self.album['mainArtist']['pic']['md5'] = artistAPI['picture_small'][artistAPI['picture_small'].find('artist/') + 7:-24]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            self.album['artists'] = [albumAPI_gw['ART_NAME']]
 | 
					 | 
				
			||||||
            self.album['trackTotal'] = albumAPI_gw['NUMBER_TRACK']
 | 
					 | 
				
			||||||
            self.album['discTotal'] = albumAPI_gw['NUMBER_DISK']
 | 
					 | 
				
			||||||
            self.album['recordType'] = "album"
 | 
					 | 
				
			||||||
            self.album['label'] = albumAPI_gw.get('LABEL_NAME', self.album['label'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            explicitLyricsStatus = albumAPI_gw.get('EXPLICIT_ALBUM_CONTENT', {}).get('EXPLICIT_LYRICS_STATUS', LyricsStatus.UNKNOWN)
 | 
					 | 
				
			||||||
            self.album['explicit'] = explicitLyricsStatus in [LyricsStatus.EXPLICIT, LyricsStatus.PARTIALLY_EXPLICIT]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if not self.album['pic']['md5']:
 | 
					 | 
				
			||||||
                self.album['pic']['md5'] = albumAPI_gw['ALB_PICTURE']
 | 
					 | 
				
			||||||
            if 'PHYSICAL_RELEASE_DATE' in albumAPI_gw:
 | 
					 | 
				
			||||||
                self.album['date'] = {
 | 
					 | 
				
			||||||
                    '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.album['mainArtist']['isVariousArtists'] = self.album['mainArtist']['id'] == VARIOUS_ARTISTS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if self.album['date'] and not self.date:
 | 
					 | 
				
			||||||
            self.date = self.album['date']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if not trackAPI:
 | 
					 | 
				
			||||||
            logger.info(f"[{self.mainArtist['name']} - {self.title}] Getting extra track infos")
 | 
					 | 
				
			||||||
            trackAPI = dz.api.get_track(self.id)
 | 
					 | 
				
			||||||
        self.bpm = trackAPI['bpm']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if not self.replayGain and 'gain' in trackAPI:
 | 
					 | 
				
			||||||
            self.replayGain = generateReplayGainString(trackAPI['gain'])
 | 
					 | 
				
			||||||
        if not self.explicit:
 | 
					 | 
				
			||||||
            self.explicit = trackAPI['explicit_lyrics']
 | 
					 | 
				
			||||||
        if not self.discNumber:
 | 
					 | 
				
			||||||
            self.discNumber = trackAPI['disk_number']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.artist = {'Main': []}
 | 
					 | 
				
			||||||
        self.artists = []
 | 
					 | 
				
			||||||
        for artist in trackAPI['contributors']:
 | 
					 | 
				
			||||||
            isVariousArtists = artist['id'] == VARIOUS_ARTISTS
 | 
					 | 
				
			||||||
            isMainArtist = artist['role'] == "Main"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if len(trackAPI['contributors']) > 1 and isVariousArtists:
 | 
					 | 
				
			||||||
                continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if artist['name'] not in self.artists:
 | 
					 | 
				
			||||||
                self.artists.append(artist['name'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if isMainArtist or artist['name'] not in self.artist['Main'] and not isMainArtist:
 | 
					 | 
				
			||||||
                if not artist['role'] in self.artist:
 | 
					 | 
				
			||||||
                    self.artist[artist['role']] = []
 | 
					 | 
				
			||||||
                self.artist[artist['role']].append(artist['name'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if not self.album['discTotal']:
 | 
					 | 
				
			||||||
            if not albumAPI_gw:
 | 
					 | 
				
			||||||
                logger.info(f"[{self.mainArtist['name']} - {self.title}] Getting more album infos")
 | 
					 | 
				
			||||||
                albumAPI_gw = dz.gw.get_album(self.album['id'])
 | 
					 | 
				
			||||||
            self.album['discTotal'] = albumAPI_gw['NUMBER_DISK']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if not self.copyright:
 | 
					 | 
				
			||||||
            if not albumAPI_gw:
 | 
					 | 
				
			||||||
                logger.info(f"[{self.mainArtist['name']} - {self.title}] Getting more album infos")
 | 
					 | 
				
			||||||
                albumAPI_gw = dz.gw.get_album(self.album['id'])
 | 
					 | 
				
			||||||
            self.copyright = albumAPI_gw['COPYRIGHT']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def parsePlaylistData(self, playlist):
 | 
					 | 
				
			||||||
        self.playlist = {}
 | 
					 | 
				
			||||||
        playlist['various_artist']['role'] = "Main"
 | 
					 | 
				
			||||||
        if 'dzcdn.net' in playlist['picture_small']:
 | 
					 | 
				
			||||||
            url = playlist['picture_small']
 | 
					 | 
				
			||||||
            picType = url[url.find('images/')+7:]
 | 
					 | 
				
			||||||
            picType = picType[:picType.find('/')]
 | 
					 | 
				
			||||||
            self.playlist['pic'] = {
 | 
					 | 
				
			||||||
                'md5': url[url.find(picType+'/') + len(picType)+1:-24],
 | 
					 | 
				
			||||||
                'type': picType,
 | 
					 | 
				
			||||||
                'url': None
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            self.playlist['pic'] = {
 | 
					 | 
				
			||||||
                'md5': None,
 | 
					 | 
				
			||||||
                'type': None,
 | 
					 | 
				
			||||||
                'url': playlist['picture_xl']
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        self.playlist['title'] = playlist['title']
 | 
					 | 
				
			||||||
        self.playlist['mainArtist'] = {
 | 
					 | 
				
			||||||
            'id': playlist['various_artist']['id'],
 | 
					 | 
				
			||||||
            'name': playlist['various_artist']['name'],
 | 
					 | 
				
			||||||
            'isVariousArtists': True,
 | 
					 | 
				
			||||||
            'pic': {
 | 
					 | 
				
			||||||
                'md5': playlist['various_artist']['picture_small'][
 | 
					 | 
				
			||||||
                       playlist['various_artist']['picture_small'].find('artist/') + 7:-24],
 | 
					 | 
				
			||||||
                'type': "artist",
 | 
					 | 
				
			||||||
                'url': None
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        self.playlist['rootArtist'] = None
 | 
					 | 
				
			||||||
        self.playlist['artist'] = {"Main": []}
 | 
					 | 
				
			||||||
        self.playlist['artists'] = []
 | 
					 | 
				
			||||||
        self.playlist['variousArtists'] = playlist['various_artist']
 | 
					 | 
				
			||||||
        self.playlist['trackTotal'] = playlist['nb_tracks']
 | 
					 | 
				
			||||||
        self.playlist['recordType'] = "compile"
 | 
					 | 
				
			||||||
        self.playlist['barcode'] = ""
 | 
					 | 
				
			||||||
        self.playlist['label'] = ""
 | 
					 | 
				
			||||||
        self.playlist['explicit'] = playlist['explicit']
 | 
					 | 
				
			||||||
        self.playlist['date'] = {
 | 
					 | 
				
			||||||
            'day': playlist["creation_date"][8:10],
 | 
					 | 
				
			||||||
            'month': playlist["creation_date"][5:7],
 | 
					 | 
				
			||||||
            'year': playlist["creation_date"][0:4]
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        self.playlist['discTotal'] = "1"
 | 
					 | 
				
			||||||
        self.playlist['playlistId'] = playlist['id']
 | 
					 | 
				
			||||||
        self.playlist['owner'] = playlist['creator']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def removeDuplicateArtists(self):
 | 
					 | 
				
			||||||
        self.artists = uniqueArray(self.artists)
 | 
					 | 
				
			||||||
        for role in self.artist.keys():
 | 
					 | 
				
			||||||
            self.artist[role] = uniqueArray(self.artist[role])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.album['artists'] = uniqueArray(self.album['artists'])
 | 
					 | 
				
			||||||
        for role in self.album['artist'].keys():
 | 
					 | 
				
			||||||
            self.album['artist'][role] = uniqueArray(self.album['artist'][role])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Removes featuring from the title
 | 
					 | 
				
			||||||
    def getCleanTitle(self):
 | 
					 | 
				
			||||||
        return removeFeatures(self.title)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Removes featuring from the album name
 | 
					 | 
				
			||||||
    def getCleanAlbumTitle(self):
 | 
					 | 
				
			||||||
        return removeFeatures(self.album['title'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def getFeatTitle(self):
 | 
					 | 
				
			||||||
        if self.featArtistsString and not "(feat." in self.title.lower():
 | 
					 | 
				
			||||||
            return self.title + " ({})".format(self.featArtistsString)
 | 
					 | 
				
			||||||
        return self.title
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def generateMainFeatStrings(self):
 | 
					 | 
				
			||||||
        self.mainArtistsString = andCommaConcat(self.artist['Main'])
 | 
					 | 
				
			||||||
        self.featArtistsString = ""
 | 
					 | 
				
			||||||
        if 'Featured' in self.artist:
 | 
					 | 
				
			||||||
            self.featArtistsString = "feat. "+andCommaConcat(self.artist['Featured'])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def getFilesizes(self, dz):
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            guest_sid = dz.session.cookies.get('sid')
 | 
					 | 
				
			||||||
            site = requests.post(
 | 
					 | 
				
			||||||
                "https://api.deezer.com/1.0/gateway.php",
 | 
					 | 
				
			||||||
                params={
 | 
					 | 
				
			||||||
                    'api_key': "4VCYIJUCDLOUELGD1V8WBVYBNVDYOXEWSLLZDONGBBDFVXTZJRXPR29JRLQFO6ZE",
 | 
					 | 
				
			||||||
                    'sid': guest_sid,
 | 
					 | 
				
			||||||
                    'input': '3',
 | 
					 | 
				
			||||||
                    'output': '3',
 | 
					 | 
				
			||||||
                    'method': 'song_getData'
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                timeout=30,
 | 
					 | 
				
			||||||
                json={'sng_id': self.id},
 | 
					 | 
				
			||||||
                headers=dz.http_headers
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
            result_json = site.json()
 | 
					 | 
				
			||||||
        except:
 | 
					 | 
				
			||||||
            eventlet.sleep(2)
 | 
					 | 
				
			||||||
            return self.getFilesizes(dz)
 | 
					 | 
				
			||||||
        if len(result_json['error']):
 | 
					 | 
				
			||||||
            raise APIError(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+"_TESTED"] = False
 | 
					 | 
				
			||||||
        return filesizes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TrackError(Exception):
 | 
					 | 
				
			||||||
    """Base class for exceptions in this module."""
 | 
					 | 
				
			||||||
    pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class AlbumDoesntExists(TrackError):
 | 
					 | 
				
			||||||
    pass
 | 
					 | 
				
			||||||
							
								
								
									
										140
									
								
								deemix/types/Album.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								deemix/types/Album.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,140 @@
 | 
				
			|||||||
 | 
					from deezer.gw import LyricsStatus
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from deemix.utils import removeDuplicateArtists
 | 
				
			||||||
 | 
					from deemix.types.Artist import Artist
 | 
				
			||||||
 | 
					from deemix.types.Date import Date
 | 
				
			||||||
 | 
					from deemix.types.Picture import Picture
 | 
				
			||||||
 | 
					from deemix import VARIOUS_ARTISTS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Album:
 | 
				
			||||||
 | 
					    def __init__(self, id="0", title="", pic_md5=""):
 | 
				
			||||||
 | 
					        self.id = id
 | 
				
			||||||
 | 
					        self.title = title
 | 
				
			||||||
 | 
					        self.pic = Picture(md5=pic_md5, type="cover")
 | 
				
			||||||
 | 
					        self.artist = {"Main": []}
 | 
				
			||||||
 | 
					        self.artists = []
 | 
				
			||||||
 | 
					        self.mainArtist = None
 | 
				
			||||||
 | 
					        self.dateString = None
 | 
				
			||||||
 | 
					        self.barcode = "Unknown"
 | 
				
			||||||
 | 
					        self.date = None
 | 
				
			||||||
 | 
					        self.discTotal = "0"
 | 
				
			||||||
 | 
					        self.embeddedCoverPath = None
 | 
				
			||||||
 | 
					        self.embeddedCoverURL = None
 | 
				
			||||||
 | 
					        self.explicit = False
 | 
				
			||||||
 | 
					        self.genre = []
 | 
				
			||||||
 | 
					        self.label = "Unknown"
 | 
				
			||||||
 | 
					        self.recordType = "album"
 | 
				
			||||||
 | 
					        self.rootArtist = None
 | 
				
			||||||
 | 
					        self.trackTotal = "0"
 | 
				
			||||||
 | 
					        self.bitrate = 0
 | 
				
			||||||
 | 
					        self.variousArtists = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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]
 | 
				
			||||||
 | 
					        self.mainArtist = Artist(
 | 
				
			||||||
 | 
					            id = albumAPI['artist']['id'],
 | 
				
			||||||
 | 
					            name = albumAPI['artist']['name'],
 | 
				
			||||||
 | 
					            pic_md5 = artistPicture
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        if albumAPI.get('root_artist'):
 | 
				
			||||||
 | 
					            self.rootArtist = Artist(
 | 
				
			||||||
 | 
					                id = albumAPI['root_artist']['id'],
 | 
				
			||||||
 | 
					                name = albumAPI['root_artist']['name']
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for artist in albumAPI['contributors']:
 | 
				
			||||||
 | 
					            isVariousArtists = str(artist['id']) == VARIOUS_ARTISTS
 | 
				
			||||||
 | 
					            isMainArtist = artist['role'] == "Main"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if isVariousArtists:
 | 
				
			||||||
 | 
					                self.variousArtists = Artist(
 | 
				
			||||||
 | 
					                    id = artist['id'],
 | 
				
			||||||
 | 
					                    name = artist['name'],
 | 
				
			||||||
 | 
					                    role = artist['role']
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if artist['name'] not in self.artists:
 | 
				
			||||||
 | 
					                self.artists.append(artist['name'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if isMainArtist or artist['name'] not in self.artist['Main'] and not isMainArtist:
 | 
				
			||||||
 | 
					                if not artist['role'] in self.artist:
 | 
				
			||||||
 | 
					                    self.artist[artist['role']] = []
 | 
				
			||||||
 | 
					                self.artist[artist['role']].append(artist['name'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.trackTotal = albumAPI['nb_tracks']
 | 
				
			||||||
 | 
					        self.recordType = albumAPI['record_type']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.barcode = albumAPI.get('upc', self.barcode)
 | 
				
			||||||
 | 
					        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.discTotal = albumAPI.get('nb_disk')
 | 
				
			||||||
 | 
					        self.copyright = albumAPI.get('copyright')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not 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]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if albumAPI.get('genres') and len(albumAPI['genres'].get('data', [])) > 0:
 | 
				
			||||||
 | 
					            for genre in albumAPI['genres']['data']:
 | 
				
			||||||
 | 
					                self.genre.append(genre['name'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def parseAlbumGW(self, albumAPI_gw):
 | 
				
			||||||
 | 
					        self.title = albumAPI_gw['ALB_TITLE']
 | 
				
			||||||
 | 
					        self.mainArtist = Artist(
 | 
				
			||||||
 | 
					            id = albumAPI_gw['ART_ID'],
 | 
				
			||||||
 | 
					            name = albumAPI_gw['ART_NAME']
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.artists = [albumAPI_gw['ART_NAME']]
 | 
				
			||||||
 | 
					        self.trackTotal = albumAPI_gw['NUMBER_TRACK']
 | 
				
			||||||
 | 
					        self.discTotal = albumAPI_gw['NUMBER_DISK']
 | 
				
			||||||
 | 
					        self.label = albumAPI_gw.get('LABEL_NAME', self.label)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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.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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def makePlaylistCompilation(self, playlist):
 | 
				
			||||||
 | 
					        self.variousArtists = playlist.variousArtists
 | 
				
			||||||
 | 
					        self.mainArtist = playlist.mainArtist
 | 
				
			||||||
 | 
					        self.title = playlist.title
 | 
				
			||||||
 | 
					        self.rootArtist = playlist.rootArtist
 | 
				
			||||||
 | 
					        self.artist = playlist.artist
 | 
				
			||||||
 | 
					        self.artists = playlist.artists
 | 
				
			||||||
 | 
					        self.trackTotal = playlist.trackTotal
 | 
				
			||||||
 | 
					        self.recordType = playlist.recordType
 | 
				
			||||||
 | 
					        self.barcode = playlist.barcode
 | 
				
			||||||
 | 
					        self.label = playlist.label
 | 
				
			||||||
 | 
					        self.explicit = playlist.explicit
 | 
				
			||||||
 | 
					        self.date = playlist.date
 | 
				
			||||||
 | 
					        self.discTotal = playlist.discTotal
 | 
				
			||||||
 | 
					        self.playlistId = playlist.playlistId
 | 
				
			||||||
 | 
					        self.owner = playlist.owner
 | 
				
			||||||
 | 
					        self.pic = playlist.pic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def removeDuplicateArtists(self):
 | 
				
			||||||
 | 
					        (self.artist, self.artists) = removeDuplicateArtists(self.artist, self.artists)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Removes featuring from the album name
 | 
				
			||||||
 | 
					    def getCleanTitle(self):
 | 
				
			||||||
 | 
					        return removeFeatures(self.title)
 | 
				
			||||||
							
								
								
									
										13
									
								
								deemix/types/Artist.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								deemix/types/Artist.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					from deemix.types.Picture import Picture
 | 
				
			||||||
 | 
					from deemix import VARIOUS_ARTISTS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Artist:
 | 
				
			||||||
 | 
					    def __init__(self, id="0", name="", pic_md5="", role=""):
 | 
				
			||||||
 | 
					        self.id = str(id)
 | 
				
			||||||
 | 
					        self.name = name
 | 
				
			||||||
 | 
					        self.pic = Picture(md5=pic_md5, type="artist")
 | 
				
			||||||
 | 
					        self.role = ""
 | 
				
			||||||
 | 
					        self.save = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def isVariousArtists(self):
 | 
				
			||||||
 | 
					        return self.id == VARIOUS_ARTISTS
 | 
				
			||||||
							
								
								
									
										25
									
								
								deemix/types/Date.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								deemix/types/Date.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					class Date(object):
 | 
				
			||||||
 | 
					    def __init__(self, year="XXXX", month="00", day="00"):
 | 
				
			||||||
 | 
					        self.year = year
 | 
				
			||||||
 | 
					        self.month = month
 | 
				
			||||||
 | 
					        self.day = day
 | 
				
			||||||
 | 
					        self.fixDayMonth()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Fix incorrect day month when detectable
 | 
				
			||||||
 | 
					    def fixDayMonth(self):
 | 
				
			||||||
 | 
					        if int(self.month) > 12:
 | 
				
			||||||
 | 
					            monthTemp = self.month
 | 
				
			||||||
 | 
					            self.month = self.day
 | 
				
			||||||
 | 
					            self.day = monthTemp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def format(self, template):
 | 
				
			||||||
 | 
					        elements = {
 | 
				
			||||||
 | 
					            'year': ['YYYY', 'YY', 'Y'],
 | 
				
			||||||
 | 
					            'month': ['MM', 'M'],
 | 
				
			||||||
 | 
					            'day': ['DD', 'D']
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for element, placeholders in elements.items():
 | 
				
			||||||
 | 
					            for placeholder in placeholders:
 | 
				
			||||||
 | 
					                if placeholder in template:
 | 
				
			||||||
 | 
					                    template = template.replace(placeholder, str(getattr(self, element)))
 | 
				
			||||||
 | 
					        return template
 | 
				
			||||||
							
								
								
									
										26
									
								
								deemix/types/Lyrics.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								deemix/types/Lyrics.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					class Lyrics:
 | 
				
			||||||
 | 
					    def __init__(self, id="0"):
 | 
				
			||||||
 | 
					        self.id = id
 | 
				
			||||||
 | 
					        self.sync = None
 | 
				
			||||||
 | 
					        self.unsync = None
 | 
				
			||||||
 | 
					        self.syncID3 = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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)):
 | 
				
			||||||
 | 
					                if syncLyricsJson[line]["line"] != "":
 | 
				
			||||||
 | 
					                    timestamp = syncLyricsJson[line]["lrc_timestamp"]
 | 
				
			||||||
 | 
					                    milliseconds = int(syncLyricsJson[line]["milliseconds"])
 | 
				
			||||||
 | 
					                    self.syncID3.append((syncLyricsJson[line]["line"], milliseconds))
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    notEmptyLine = line + 1
 | 
				
			||||||
 | 
					                    while syncLyricsJson[notEmptyLine]["line"] == "":
 | 
				
			||||||
 | 
					                        notEmptyLine = notEmptyLine + 1
 | 
				
			||||||
 | 
					                    timestamp = syncLyricsJson[notEmptyLine]["lrc_timestamp"]
 | 
				
			||||||
 | 
					                self.sync += timestamp + syncLyricsJson[line]["line"] + "\r\n"
 | 
				
			||||||
							
								
								
									
										27
									
								
								deemix/types/Picture.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								deemix/types/Picture.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					class Picture:
 | 
				
			||||||
 | 
					    def __init__(self, md5="", type=None, url=None):
 | 
				
			||||||
 | 
					        self.md5 = md5
 | 
				
			||||||
 | 
					        self.type = type
 | 
				
			||||||
 | 
					        self.url = url
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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'
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
							
								
								
									
										48
									
								
								deemix/types/Playlist.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								deemix/types/Playlist.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					from deemix.types.Artist import Artist
 | 
				
			||||||
 | 
					from deemix.types.Date import Date
 | 
				
			||||||
 | 
					from deemix.types.Picture import Picture
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					        self.artist = {"Main": []}
 | 
				
			||||||
 | 
					        self.artists = []
 | 
				
			||||||
 | 
					        self.trackTotal = playlistAPI['nb_tracks']
 | 
				
			||||||
 | 
					        self.recordType = "compile"
 | 
				
			||||||
 | 
					        self.barcode = ""
 | 
				
			||||||
 | 
					        self.label = ""
 | 
				
			||||||
 | 
					        self.explicit = playlistAPI['explicit']
 | 
				
			||||||
 | 
					        self.genre = ["Compilation", ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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.discTotal = "1"
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.pic = Picture(url = playlistAPI['picture_xl'])
 | 
				
			||||||
							
								
								
									
										269
									
								
								deemix/types/Track.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										269
									
								
								deemix/types/Track.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,269 @@
 | 
				
			|||||||
 | 
					import eventlet
 | 
				
			||||||
 | 
					requests = eventlet.import_patched('requests')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					logging.basicConfig(level=logging.INFO)
 | 
				
			||||||
 | 
					logger = logging.getLogger('deemix')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from deezer.gw import APIError as gwAPIError
 | 
				
			||||||
 | 
					from deezer.api import APIError
 | 
				
			||||||
 | 
					from deemix.utils import removeFeatures, andCommaConcat, removeDuplicateArtists, generateReplayGainString
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Track:
 | 
				
			||||||
 | 
					    def __init__(self, id="0", name=""):
 | 
				
			||||||
 | 
					        self.id = id
 | 
				
			||||||
 | 
					        self.title = name
 | 
				
			||||||
 | 
					        self.MD5 = ""
 | 
				
			||||||
 | 
					        self.mediaVersion = ""
 | 
				
			||||||
 | 
					        self.duration = 0
 | 
				
			||||||
 | 
					        self.fallbackId = "0"
 | 
				
			||||||
 | 
					        self.filesizes = {}
 | 
				
			||||||
 | 
					        self.localTrack = False
 | 
				
			||||||
 | 
					        self.mainArtist = None
 | 
				
			||||||
 | 
					        self.artist = {"Main": []}
 | 
				
			||||||
 | 
					        self.artists = []
 | 
				
			||||||
 | 
					        self.album = None
 | 
				
			||||||
 | 
					        self.trackNumber = "0"
 | 
				
			||||||
 | 
					        self.discNumber = "0"
 | 
				
			||||||
 | 
					        self.date = None
 | 
				
			||||||
 | 
					        self.lyrics = None
 | 
				
			||||||
 | 
					        self.bpm = 0
 | 
				
			||||||
 | 
					        self.contributors = {}
 | 
				
			||||||
 | 
					        self.copyright = ""
 | 
				
			||||||
 | 
					        self.explicit = False
 | 
				
			||||||
 | 
					        self.ISRC = ""
 | 
				
			||||||
 | 
					        self.replayGain = ""
 | 
				
			||||||
 | 
					        self.playlist = None
 | 
				
			||||||
 | 
					        self.position = None
 | 
				
			||||||
 | 
					        self.searched = False
 | 
				
			||||||
 | 
					        self.selectedFormat = 0
 | 
				
			||||||
 | 
					        self.singleDownload = False
 | 
				
			||||||
 | 
					        self.dateString = None
 | 
				
			||||||
 | 
					        self.artistsString = ""
 | 
				
			||||||
 | 
					        self.mainArtistsString = ""
 | 
				
			||||||
 | 
					        self.featArtistsString = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def parseEssentialData(self, trackAPI_gw, trackAPI=None):
 | 
				
			||||||
 | 
					        self.id = str(trackAPI_gw['SNG_ID'])
 | 
				
			||||||
 | 
					        self.duration = trackAPI_gw['DURATION']
 | 
				
			||||||
 | 
					        self.MD5 = trackAPI_gw.get('MD5_ORIGIN')
 | 
				
			||||||
 | 
					        if not self.MD5:
 | 
				
			||||||
 | 
					            if trackAPI and trackAPI.get('md5_origin'):
 | 
				
			||||||
 | 
					                self.MD5 = trackAPI['md5_origin']
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                raise MD5NotFound
 | 
				
			||||||
 | 
					        self.mediaVersion = trackAPI_gw['MEDIA_VERSION']
 | 
				
			||||||
 | 
					        self.fallbackId = "0"
 | 
				
			||||||
 | 
					        if 'FALLBACK' in trackAPI_gw:
 | 
				
			||||||
 | 
					            self.fallbackId = trackAPI_gw['FALLBACK']['SNG_ID']
 | 
				
			||||||
 | 
					        self.localTrack = int(self.id) < 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def retriveFilesizes(self, dz):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            guest_sid = dz.session.cookies.get('sid')
 | 
				
			||||||
 | 
					            site = requests.post(
 | 
				
			||||||
 | 
					                "https://api.deezer.com/1.0/gateway.php",
 | 
				
			||||||
 | 
					                params={
 | 
				
			||||||
 | 
					                    'api_key': "4VCYIJUCDLOUELGD1V8WBVYBNVDYOXEWSLLZDONGBBDFVXTZJRXPR29JRLQFO6ZE",
 | 
				
			||||||
 | 
					                    'sid': guest_sid,
 | 
				
			||||||
 | 
					                    'input': '3',
 | 
				
			||||||
 | 
					                    'output': '3',
 | 
				
			||||||
 | 
					                    'method': 'song_getData'
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                timeout=30,
 | 
				
			||||||
 | 
					                json={'sng_id': self.id},
 | 
				
			||||||
 | 
					                headers=dz.http_headers
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            result_json = site.json()
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            eventlet.sleep(2)
 | 
				
			||||||
 | 
					            return self.retriveFilesizes(dz)
 | 
				
			||||||
 | 
					        if len(result_json['error']):
 | 
				
			||||||
 | 
					            raise APIError(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+"_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)
 | 
				
			||||||
 | 
					        elif not trackAPI_gw: raise NoDataToParse
 | 
				
			||||||
 | 
					        if not trackAPI:
 | 
				
			||||||
 | 
					            try: trackAPI = dz.api.get_track(trackAPI_gw['SNG_ID'])
 | 
				
			||||||
 | 
					            except APIError: trackAPI = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.parseEssentialData(trackAPI_gw, trackAPI)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.localTrack:
 | 
				
			||||||
 | 
					            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"
 | 
				
			||||||
 | 
					            if self.lyrics.id != "0": self.lyrics.parseLyrics(trackAPI_gw["LYRICS"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Parse Album data
 | 
				
			||||||
 | 
					            self.album = Album(
 | 
				
			||||||
 | 
					                id = trackAPI_gw['ALB_ID'],
 | 
				
			||||||
 | 
					                title = trackAPI_gw['ALB_TITLE'],
 | 
				
			||||||
 | 
					                pic_md5 = trackAPI_gw.get('ALB_PICTURE')
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Get album Data
 | 
				
			||||||
 | 
					            if not albumAPI:
 | 
				
			||||||
 | 
					                try: albumAPI = dz.api.get_album(self.album.id)
 | 
				
			||||||
 | 
					                except APIError: albumAPI = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Get album_gw Data
 | 
				
			||||||
 | 
					            if not albumAPI_gw:
 | 
				
			||||||
 | 
					                try: albumAPI_gw = dz.gw.get_album(self.album.id)
 | 
				
			||||||
 | 
					                except gwAPIError: albumAPI_gw = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if albumAPI:
 | 
				
			||||||
 | 
					                self.album.parseAlbum(albumAPI)
 | 
				
			||||||
 | 
					            elif albumAPI_gw:
 | 
				
			||||||
 | 
					                self.album.parseAlbumGW(albumAPI_gw)
 | 
				
			||||||
 | 
					                # albumAPI_gw doesn't contain the artist cover
 | 
				
			||||||
 | 
					                # Getting artist image ID
 | 
				
			||||||
 | 
					                # ex: https://e-cdns-images.dzcdn.net/images/artist/f2bc007e9133c946ac3c3907ddc5d2ea/56x56-000000-80-0-0.jpg
 | 
				
			||||||
 | 
					                artistAPI = dz.api.get_artist(self.album.mainArtist.id)
 | 
				
			||||||
 | 
					                self.album.mainArtist.pic.md5 = artistAPI['picture_small'][artistAPI['picture_small'].find('artist/') + 7:-24]
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                raise AlbumDoesntExists
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Fill missing data
 | 
				
			||||||
 | 
					            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']
 | 
				
			||||||
 | 
					            self.parseTrack(trackAPI)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Make sure there is at least one artist
 | 
				
			||||||
 | 
					        if not len(self.artist['Main']):
 | 
				
			||||||
 | 
					            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
 | 
				
			||||||
 | 
					        if playlistAPI: self.playlist = Playlist(playlistAPI)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.generateMainFeatStrings()
 | 
				
			||||||
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def parseLocalTrackData(self, trackAPI_gw):
 | 
				
			||||||
 | 
					        # Local tracks has only the trackAPI_gw page and
 | 
				
			||||||
 | 
					        # contains only the tags provided by the file
 | 
				
			||||||
 | 
					        self.title = trackAPI_gw['SNG_TITLE']
 | 
				
			||||||
 | 
					        self.album = Album(title=trackAPI_gw['ALB_TITLE'])
 | 
				
			||||||
 | 
					        self.album.pic = Picture(
 | 
				
			||||||
 | 
					            md5 = trackAPI_gw.get('ALB_PICTURE', ""),
 | 
				
			||||||
 | 
					            type = "cover"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.mainArtist = Artist(name=trackAPI_gw['ART_NAME'])
 | 
				
			||||||
 | 
					        self.artists = [trackAPI_gw['ART_NAME']]
 | 
				
			||||||
 | 
					        self.artist = {
 | 
				
			||||||
 | 
					            'Main': [trackAPI_gw['ART_NAME']]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        self.album.artist = self.artist
 | 
				
			||||||
 | 
					        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()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.discNumber = trackAPI_gw.get('DISK_NUMBER')
 | 
				
			||||||
 | 
					        self.explicit = bool(int(trackAPI_gw.get('EXPLICIT_LYRICS', "0")))
 | 
				
			||||||
 | 
					        self.copyright = trackAPI_gw.get('COPYRIGHT')
 | 
				
			||||||
 | 
					        if 'GAIN' in trackAPI_gw: self.replayGain = generateReplayGainString(trackAPI_gw['GAIN'])
 | 
				
			||||||
 | 
					        self.ISRC = trackAPI_gw.get('ISRC')
 | 
				
			||||||
 | 
					        self.trackNumber = trackAPI_gw['TRACK_NUMBER']
 | 
				
			||||||
 | 
					        self.contributors = trackAPI_gw['SNG_CONTRIBUTORS']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.lyrics = Lyrics(trackAPI_gw.get('LYRICS_ID', "0"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.mainArtist = Artist(
 | 
				
			||||||
 | 
					            id = trackAPI_gw['ART_ID'],
 | 
				
			||||||
 | 
					            name = trackAPI_gw['ART_NAME'],
 | 
				
			||||||
 | 
					            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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def parseTrack(self, trackAPI):
 | 
				
			||||||
 | 
					        self.bpm = trackAPI['bpm']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not self.replayGain and 'gain' in trackAPI:
 | 
				
			||||||
 | 
					            self.replayGain = generateReplayGainString(trackAPI['gain'])
 | 
				
			||||||
 | 
					        if not self.explicit:
 | 
				
			||||||
 | 
					            self.explicit = trackAPI['explicit_lyrics']
 | 
				
			||||||
 | 
					        if not self.discNumber:
 | 
				
			||||||
 | 
					            self.discNumber = trackAPI['disk_number']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for artist in trackAPI['contributors']:
 | 
				
			||||||
 | 
					            isVariousArtists = str(artist['id']) == VARIOUS_ARTISTS
 | 
				
			||||||
 | 
					            isMainArtist = artist['role'] == "Main"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if len(trackAPI['contributors']) > 1 and isVariousArtists:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if artist['name'] not in self.artists:
 | 
				
			||||||
 | 
					                self.artists.append(artist['name'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if isMainArtist or artist['name'] not in self.artist['Main'] and not isMainArtist:
 | 
				
			||||||
 | 
					                if not artist['role'] in self.artist:
 | 
				
			||||||
 | 
					                    self.artist[artist['role']] = []
 | 
				
			||||||
 | 
					                self.artist[artist['role']].append(artist['name'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def removeDuplicateArtists(self):
 | 
				
			||||||
 | 
					        (self.artist, self.artists) = removeDuplicateArtists(self.artist, self.artists)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Removes featuring from the title
 | 
				
			||||||
 | 
					    def getCleanTitle(self):
 | 
				
			||||||
 | 
					        return removeFeatures(self.title)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getFeatTitle(self):
 | 
				
			||||||
 | 
					        if self.featArtistsString and not "(feat." in self.title.lower():
 | 
				
			||||||
 | 
					            return self.title + " ({})".format(self.featArtistsString)
 | 
				
			||||||
 | 
					        return self.title
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def generateMainFeatStrings(self):
 | 
				
			||||||
 | 
					        self.mainArtistsString = andCommaConcat(self.artist['Main'])
 | 
				
			||||||
 | 
					        self.featArtistsString = ""
 | 
				
			||||||
 | 
					        if 'Featured' in self.artist:
 | 
				
			||||||
 | 
					            self.featArtistsString = "feat. "+andCommaConcat(self.artist['Featured'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TrackError(Exception):
 | 
				
			||||||
 | 
					    """Base class for exceptions in this module."""
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AlbumDoesntExists(TrackError):
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MD5NotFound(TrackError):
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NoDataToParse(TrackError):
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
							
								
								
									
										7
									
								
								deemix/types/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								deemix/types/__init__.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					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
 | 
				
			||||||
@ -122,6 +122,12 @@ def uniqueArray(arr):
 | 
				
			|||||||
                del arr[iRest]
 | 
					                del arr[iRest]
 | 
				
			||||||
    return arr
 | 
					    return arr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def removeDuplicateArtists(artist, artists):
 | 
				
			||||||
 | 
					    artists = uniqueArray(artists)
 | 
				
			||||||
 | 
					    for role in artist.keys():
 | 
				
			||||||
 | 
					        artist[role] = uniqueArray(artist[role])
 | 
				
			||||||
 | 
					    return (artist, artists)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def checkFolder(folder):
 | 
					def checkFolder(folder):
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        os.makedirs(folder, exist_ok=True)
 | 
					        os.makedirs(folder, exist_ok=True)
 | 
				
			||||||
 | 
				
			|||||||
@ -85,7 +85,7 @@ def generateFilepath(track, settings):
 | 
				
			|||||||
        (settings['createArtistFolder'] and track.playlist and settings['tags']['savePlaylistAsCompilation']) or
 | 
					        (settings['createArtistFolder'] and track.playlist and settings['tags']['savePlaylistAsCompilation']) or
 | 
				
			||||||
        (settings['createArtistFolder'] and track.playlist and settings['createStructurePlaylist'])
 | 
					        (settings['createArtistFolder'] and track.playlist and settings['createStructurePlaylist'])
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
        filepath = filepath / settingsRegexArtist(settings['artistNameTemplate'], track.album['mainArtist'], settings, rootArtist=track.album['rootArtist'])
 | 
					        filepath = filepath / settingsRegexArtist(settings['artistNameTemplate'], track.album.mainArtist, settings, rootArtist=track.album.rootArtist)
 | 
				
			||||||
        artistPath = filepath
 | 
					        artistPath = filepath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (settings['createAlbumFolder'] and
 | 
					    if (settings['createAlbumFolder'] and
 | 
				
			||||||
@ -102,7 +102,7 @@ def generateFilepath(track, settings):
 | 
				
			|||||||
        extrasPath = filepath
 | 
					        extrasPath = filepath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (
 | 
					    if (
 | 
				
			||||||
            int(track.album['discTotal']) > 1 and (
 | 
					            int(track.album.discTotal) > 1 and (
 | 
				
			||||||
            (settings['createAlbumFolder'] and settings['createCDFolder']) and
 | 
					            (settings['createAlbumFolder'] and settings['createCDFolder']) and
 | 
				
			||||||
            (not track.singleDownload or (track.singleDownload and settings['createSingleFolder'])) and
 | 
					            (not track.singleDownload or (track.singleDownload and settings['createSingleFolder'])) and
 | 
				
			||||||
            (not track.playlist or
 | 
					            (not track.playlist or
 | 
				
			||||||
@ -117,7 +117,7 @@ def generateFilepath(track, settings):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def settingsRegex(filename, track, settings):
 | 
					def settingsRegex(filename, track, settings):
 | 
				
			||||||
    filename = filename.replace("%title%", fixName(track.title, settings['illegalCharacterReplacer']))
 | 
					    filename = filename.replace("%title%", fixName(track.title, settings['illegalCharacterReplacer']))
 | 
				
			||||||
    filename = filename.replace("%artist%", fixName(track.mainArtist['name'], settings['illegalCharacterReplacer']))
 | 
					    filename = filename.replace("%artist%", fixName(track.mainArtist.name, settings['illegalCharacterReplacer']))
 | 
				
			||||||
    filename = filename.replace("%artists%", fixName(", ".join(track.artists), settings['illegalCharacterReplacer']))
 | 
					    filename = filename.replace("%artists%", fixName(", ".join(track.artists), settings['illegalCharacterReplacer']))
 | 
				
			||||||
    filename = filename.replace("%allartists%", fixName(track.artistsString, settings['illegalCharacterReplacer']))
 | 
					    filename = filename.replace("%allartists%", fixName(track.artistsString, settings['illegalCharacterReplacer']))
 | 
				
			||||||
    filename = filename.replace("%mainartists%", fixName(track.mainArtistsString, settings['illegalCharacterReplacer']))
 | 
					    filename = filename.replace("%mainartists%", fixName(track.mainArtistsString, settings['illegalCharacterReplacer']))
 | 
				
			||||||
@ -125,92 +125,92 @@ def settingsRegex(filename, track, settings):
 | 
				
			|||||||
        filename = filename.replace("%featartists%", fixName('('+track.featArtistsString+')', settings['illegalCharacterReplacer']))
 | 
					        filename = filename.replace("%featartists%", fixName('('+track.featArtistsString+')', settings['illegalCharacterReplacer']))
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        filename = filename.replace("%featartists%", '')
 | 
					        filename = filename.replace("%featartists%", '')
 | 
				
			||||||
    filename = filename.replace("%album%", fixName(track.album['title'], settings['illegalCharacterReplacer']))
 | 
					    filename = filename.replace("%album%", fixName(track.album.title, settings['illegalCharacterReplacer']))
 | 
				
			||||||
    filename = filename.replace("%albumartist%", fixName(track.album['mainArtist']['name'], settings['illegalCharacterReplacer']))
 | 
					    filename = filename.replace("%albumartist%", fixName(track.album.mainArtist.name, settings['illegalCharacterReplacer']))
 | 
				
			||||||
    filename = filename.replace("%tracknumber%", pad(track.trackNumber, track.album['trackTotal'], settings))
 | 
					    filename = filename.replace("%tracknumber%", pad(track.trackNumber, track.album.trackTotal, settings))
 | 
				
			||||||
    filename = filename.replace("%tracktotal%", str(track.album['trackTotal']))
 | 
					    filename = filename.replace("%tracktotal%", str(track.album.trackTotal))
 | 
				
			||||||
    filename = filename.replace("%discnumber%", str(track.discNumber))
 | 
					    filename = filename.replace("%discnumber%", str(track.discNumber))
 | 
				
			||||||
    filename = filename.replace("%disctotal%", str(track.album['discTotal']))
 | 
					    filename = filename.replace("%disctotal%", str(track.album.discTotal))
 | 
				
			||||||
    if len(track.album['genre']) > 0:
 | 
					    if len(track.album.genre) > 0:
 | 
				
			||||||
        filename = filename.replace("%genre%",
 | 
					        filename = filename.replace("%genre%",
 | 
				
			||||||
                                    fixName(track.album['genre'][0], settings['illegalCharacterReplacer']))
 | 
					                                    fixName(track.album.genre[0], settings['illegalCharacterReplacer']))
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        filename = filename.replace("%genre%", "Unknown")
 | 
					        filename = filename.replace("%genre%", "Unknown")
 | 
				
			||||||
    filename = filename.replace("%year%", str(track.date['year']))
 | 
					    filename = filename.replace("%year%", str(track.date.year))
 | 
				
			||||||
    filename = filename.replace("%date%", track.dateString)
 | 
					    filename = filename.replace("%date%", track.dateString)
 | 
				
			||||||
    filename = filename.replace("%bpm%", str(track.bpm))
 | 
					    filename = filename.replace("%bpm%", str(track.bpm))
 | 
				
			||||||
    filename = filename.replace("%label%", fixName(track.album['label'], settings['illegalCharacterReplacer']))
 | 
					    filename = filename.replace("%label%", fixName(track.album.label, settings['illegalCharacterReplacer']))
 | 
				
			||||||
    filename = filename.replace("%isrc%", track.ISRC)
 | 
					    filename = filename.replace("%isrc%", track.ISRC)
 | 
				
			||||||
    filename = filename.replace("%upc%", track.album['barcode'])
 | 
					    filename = filename.replace("%upc%", track.album.barcode)
 | 
				
			||||||
    filename = filename.replace("%explicit%", "(Explicit)" if track.explicit else "")
 | 
					    filename = filename.replace("%explicit%", "(Explicit)" if track.explicit else "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    filename = filename.replace("%track_id%", str(track.id))
 | 
					    filename = filename.replace("%track_id%", str(track.id))
 | 
				
			||||||
    filename = filename.replace("%album_id%", str(track.album['id']))
 | 
					    filename = filename.replace("%album_id%", str(track.album.id))
 | 
				
			||||||
    filename = filename.replace("%artist_id%", str(track.mainArtist['id']))
 | 
					    filename = filename.replace("%artist_id%", str(track.mainArtist.id))
 | 
				
			||||||
    if track.playlist:
 | 
					    if track.playlist:
 | 
				
			||||||
        filename = filename.replace("%playlist_id%", str(track.playlist['playlistId']))
 | 
					        filename = filename.replace("%playlist_id%", str(track.playlist.playlistId))
 | 
				
			||||||
        filename = filename.replace("%position%", pad(track.position, track.playlist['trackTotal'], settings))
 | 
					        filename = filename.replace("%position%", pad(track.position, track.playlist.trackTotal, settings))
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        filename = filename.replace("%playlist_id%", '')
 | 
					        filename = filename.replace("%playlist_id%", '')
 | 
				
			||||||
        filename = filename.replace("%position%", pad(track.trackNumber, track.album['trackTotal'], settings))
 | 
					        filename = filename.replace("%position%", pad(track.trackNumber, track.album.trackTotal, settings))
 | 
				
			||||||
    filename = filename.replace('\\', pathSep).replace('/', pathSep)
 | 
					    filename = filename.replace('\\', pathSep).replace('/', pathSep)
 | 
				
			||||||
    return antiDot(fixLongName(filename))
 | 
					    return antiDot(fixLongName(filename))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def settingsRegexAlbum(foldername, album, settings, playlist=None):
 | 
					def settingsRegexAlbum(foldername, album, settings, playlist=None):
 | 
				
			||||||
    if playlist and settings['tags']['savePlaylistAsCompilation']:
 | 
					    if playlist and settings['tags']['savePlaylistAsCompilation']:
 | 
				
			||||||
        foldername = foldername.replace("%album_id%", "pl_" + str(playlist['playlistId']))
 | 
					        foldername = foldername.replace("%album_id%", "pl_" + str(playlist.playlistId))
 | 
				
			||||||
        foldername = foldername.replace("%genre%", "Compile")
 | 
					        foldername = foldername.replace("%genre%", "Compile")
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        foldername = foldername.replace("%album_id%", str(album['id']))
 | 
					        foldername = foldername.replace("%album_id%", str(album.id))
 | 
				
			||||||
        if len(album['genre']) > 0:
 | 
					        if len(album.genre) > 0:
 | 
				
			||||||
            foldername = foldername.replace("%genre%", fixName(album['genre'][0], settings['illegalCharacterReplacer']))
 | 
					            foldername = foldername.replace("%genre%", fixName(album.genre[0], settings['illegalCharacterReplacer']))
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            foldername = foldername.replace("%genre%", "Unknown")
 | 
					            foldername = foldername.replace("%genre%", "Unknown")
 | 
				
			||||||
    foldername = foldername.replace("%album%", fixName(album['title'], settings['illegalCharacterReplacer']))
 | 
					    foldername = foldername.replace("%album%", fixName(album.title, settings['illegalCharacterReplacer']))
 | 
				
			||||||
    foldername = foldername.replace("%artist%", fixName(album['mainArtist']['name'], settings['illegalCharacterReplacer']))
 | 
					    foldername = foldername.replace("%artist%", fixName(album.mainArtist.name, settings['illegalCharacterReplacer']))
 | 
				
			||||||
    foldername = foldername.replace("%artist_id%", str(album['mainArtist']['id']))
 | 
					    foldername = foldername.replace("%artist_id%", str(album.mainArtist.id))
 | 
				
			||||||
    if album['rootArtist']:
 | 
					    if album.rootArtist:
 | 
				
			||||||
        foldername = foldername.replace("%root_artist%", fixName(album['rootArtist']['name'], settings['illegalCharacterReplacer']))
 | 
					        foldername = foldername.replace("%root_artist%", fixName(album.rootArtist.name, settings['illegalCharacterReplacer']))
 | 
				
			||||||
        foldername = foldername.replace("%root_artist_id%", str(album['rootArtist']['id']))
 | 
					        foldername = foldername.replace("%root_artist_id%", str(album.rootArtist.id))
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        foldername = foldername.replace("%root_artist%", fixName(album['mainArtist']['name'], settings['illegalCharacterReplacer']))
 | 
					        foldername = foldername.replace("%root_artist%", fixName(album.mainArtist.name, settings['illegalCharacterReplacer']))
 | 
				
			||||||
        foldername = foldername.replace("%root_artist_id%", str(album['mainArtist']['id']))
 | 
					        foldername = foldername.replace("%root_artist_id%", str(album.mainArtist.id))
 | 
				
			||||||
    foldername = foldername.replace("%tracktotal%", str(album['trackTotal']))
 | 
					    foldername = foldername.replace("%tracktotal%", str(album.trackTotal))
 | 
				
			||||||
    foldername = foldername.replace("%disctotal%", str(album['discTotal']))
 | 
					    foldername = foldername.replace("%disctotal%", str(album.discTotal))
 | 
				
			||||||
    foldername = foldername.replace("%type%", fixName(album['recordType'].capitalize(), settings['illegalCharacterReplacer']))
 | 
					    foldername = foldername.replace("%type%", fixName(album.recordType.capitalize(), settings['illegalCharacterReplacer']))
 | 
				
			||||||
    foldername = foldername.replace("%upc%", album['barcode'])
 | 
					    foldername = foldername.replace("%upc%", album.barcode)
 | 
				
			||||||
    foldername = foldername.replace("%explicit%", "(Explicit)" if album['explicit'] else "")
 | 
					    foldername = foldername.replace("%explicit%", "(Explicit)" if album.explicit else "")
 | 
				
			||||||
    foldername = foldername.replace("%label%", fixName(album['label'], settings['illegalCharacterReplacer']))
 | 
					    foldername = foldername.replace("%label%", fixName(album.label, settings['illegalCharacterReplacer']))
 | 
				
			||||||
    foldername = foldername.replace("%year%", str(album['date']['year']))
 | 
					    foldername = foldername.replace("%year%", str(album.date.year))
 | 
				
			||||||
    foldername = foldername.replace("%date%", album['dateString'])
 | 
					    foldername = foldername.replace("%date%", album.dateString)
 | 
				
			||||||
    foldername = foldername.replace("%bitrate%", bitrateLabels[int(album['bitrate'])])
 | 
					    foldername = foldername.replace("%bitrate%", bitrateLabels[int(album.bitrate)])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    foldername = foldername.replace('\\', pathSep).replace('/', pathSep)
 | 
					    foldername = foldername.replace('\\', pathSep).replace('/', pathSep)
 | 
				
			||||||
    return antiDot(fixLongName(foldername))
 | 
					    return antiDot(fixLongName(foldername))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def settingsRegexArtist(foldername, artist, settings, rootArtist=None):
 | 
					def settingsRegexArtist(foldername, artist, settings, rootArtist=None):
 | 
				
			||||||
    foldername = foldername.replace("%artist%", fixName(artist['name'], settings['illegalCharacterReplacer']))
 | 
					    foldername = foldername.replace("%artist%", fixName(artist.name, settings['illegalCharacterReplacer']))
 | 
				
			||||||
    foldername = foldername.replace("%artist_id%", str(artist['id']))
 | 
					    foldername = foldername.replace("%artist_id%", str(artist.id))
 | 
				
			||||||
    if rootArtist:
 | 
					    if rootArtist:
 | 
				
			||||||
        foldername = foldername.replace("%root_artist%", fixName(rootArtist['name'], settings['illegalCharacterReplacer']))
 | 
					        foldername = foldername.replace("%root_artist%", fixName(rootArtist.name, settings['illegalCharacterReplacer']))
 | 
				
			||||||
        foldername = foldername.replace("%root_artist_id%", str(rootArtist['id']))
 | 
					        foldername = foldername.replace("%root_artist_id%", str(rootArtist.id))
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        foldername = foldername.replace("%root_artist%", fixName(artist['name'], settings['illegalCharacterReplacer']))
 | 
					        foldername = foldername.replace("%root_artist%", fixName(artist.name, settings['illegalCharacterReplacer']))
 | 
				
			||||||
        foldername = foldername.replace("%root_artist_id%", str(artist['id']))
 | 
					        foldername = foldername.replace("%root_artist_id%", str(artist.id))
 | 
				
			||||||
    foldername = foldername.replace('\\', pathSep).replace('/', pathSep)
 | 
					    foldername = foldername.replace('\\', pathSep).replace('/', pathSep)
 | 
				
			||||||
    return antiDot(fixLongName(foldername))
 | 
					    return antiDot(fixLongName(foldername))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def settingsRegexPlaylist(foldername, playlist, settings):
 | 
					def settingsRegexPlaylist(foldername, playlist, settings):
 | 
				
			||||||
    foldername = foldername.replace("%playlist%", fixName(playlist['title'], settings['illegalCharacterReplacer']))
 | 
					    foldername = foldername.replace("%playlist%", fixName(playlist.title, settings['illegalCharacterReplacer']))
 | 
				
			||||||
    foldername = foldername.replace("%playlist_id%", fixName(playlist['playlistId'], settings['illegalCharacterReplacer']))
 | 
					    foldername = foldername.replace("%playlist_id%", fixName(playlist.playlistId, settings['illegalCharacterReplacer']))
 | 
				
			||||||
    foldername = foldername.replace("%owner%", fixName(playlist['owner']['name'], settings['illegalCharacterReplacer']))
 | 
					    foldername = foldername.replace("%owner%", fixName(playlist.owner['name'], settings['illegalCharacterReplacer']))
 | 
				
			||||||
    foldername = foldername.replace("%owner_id%", str(playlist['owner']['id']))
 | 
					    foldername = foldername.replace("%owner_id%", str(playlist.owner['id']))
 | 
				
			||||||
    foldername = foldername.replace("%year%", str(playlist['date']['year']))
 | 
					    foldername = foldername.replace("%year%", str(playlist.date.year))
 | 
				
			||||||
    foldername = foldername.replace("%date%", str(playlist['dateString']))
 | 
					    foldername = foldername.replace("%date%", str(playlist.dateString))
 | 
				
			||||||
    foldername = foldername.replace("%explicit%", "(Explicit)" if playlist['explicit'] else "")
 | 
					    foldername = foldername.replace("%explicit%", "(Explicit)" if playlist.explicit else "")
 | 
				
			||||||
    foldername = foldername.replace('\\', pathSep).replace('/', pathSep)
 | 
					    foldername = foldername.replace('\\', pathSep).replace('/', pathSep)
 | 
				
			||||||
    return antiDot(fixLongName(foldername))
 | 
					    return antiDot(fixLongName(foldername))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,7 @@ def tagID3(stream, track, save):
 | 
				
			|||||||
            tag.add(TPE1(text=track.artists))
 | 
					            tag.add(TPE1(text=track.artists))
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            if save['multiArtistSeparator'] == "nothing":
 | 
					            if save['multiArtistSeparator'] == "nothing":
 | 
				
			||||||
                tag.add(TPE1(text=track.mainArtist['name']))
 | 
					                tag.add(TPE1(text=track.mainArtist.name))
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                tag.add(TPE1(text=track.artistsString))
 | 
					                tag.add(TPE1(text=track.artistsString))
 | 
				
			||||||
            # Tag ARTISTS is added to keep the multiartist support when using a non standard tagging method
 | 
					            # Tag ARTISTS is added to keep the multiartist support when using a non standard tagging method
 | 
				
			||||||
@ -28,56 +28,56 @@ def tagID3(stream, track, save):
 | 
				
			|||||||
            tag.add(TXXX(desc="ARTISTS", text=track.artists))
 | 
					            tag.add(TXXX(desc="ARTISTS", text=track.artists))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if save['album']:
 | 
					    if save['album']:
 | 
				
			||||||
        tag.add(TALB(text=track.album['title']))
 | 
					        tag.add(TALB(text=track.album.title))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if save['albumArtist'] and len(track.album['artists']):
 | 
					    if save['albumArtist'] and len(track.album.artists):
 | 
				
			||||||
        if save['singleAlbumArtist'] and track.album['mainArtist']['save']:
 | 
					        if save['singleAlbumArtist'] and track.album.mainArtist.save:
 | 
				
			||||||
            tag.add(TPE2(text=track.album['mainArtist']['name']))
 | 
					            tag.add(TPE2(text=track.album.mainArtist.name))
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            tag.add(TPE2(text=track.album['artists']))
 | 
					            tag.add(TPE2(text=track.album.artists))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if save['trackNumber']:
 | 
					    if save['trackNumber']:
 | 
				
			||||||
        trackNumber = str(track.trackNumber)
 | 
					        trackNumber = str(track.trackNumber)
 | 
				
			||||||
        if save['trackTotal']:
 | 
					        if save['trackTotal']:
 | 
				
			||||||
            trackNumber += "/" + str(track.album['trackTotal'])
 | 
					            trackNumber += "/" + str(track.album.trackTotal)
 | 
				
			||||||
        tag.add(TRCK(text=trackNumber))
 | 
					        tag.add(TRCK(text=trackNumber))
 | 
				
			||||||
    if save['discNumber']:
 | 
					    if save['discNumber']:
 | 
				
			||||||
        discNumber = str(track.discNumber)
 | 
					        discNumber = str(track.discNumber)
 | 
				
			||||||
        if save['discTotal']:
 | 
					        if save['discTotal']:
 | 
				
			||||||
            discNumber += "/" + str(track.album['discTotal'])
 | 
					            discNumber += "/" + str(track.album.discTotal)
 | 
				
			||||||
        tag.add(TPOS(text=discNumber))
 | 
					        tag.add(TPOS(text=discNumber))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if save['genre']:
 | 
					    if save['genre']:
 | 
				
			||||||
        tag.add(TCON(text=track.album['genre']))
 | 
					        tag.add(TCON(text=track.album.genre))
 | 
				
			||||||
    if save['year']:
 | 
					    if save['year']:
 | 
				
			||||||
        tag.add(TYER(text=str(track.date['year'])))
 | 
					        tag.add(TYER(text=str(track.date.year)))
 | 
				
			||||||
    if save['date']:
 | 
					    if save['date']:
 | 
				
			||||||
        # Referencing ID3 standard
 | 
					        # Referencing ID3 standard
 | 
				
			||||||
        # https://id3.org/id3v2.3.0#TDAT
 | 
					        # https://id3.org/id3v2.3.0#TDAT
 | 
				
			||||||
        # The 'Date' frame is a numeric string in the DDMM format.
 | 
					        # The 'Date' frame is a numeric string in the DDMM format.
 | 
				
			||||||
        tag.add(TDAT(text=str(track.date['day']) + str(track.date['month'])))
 | 
					        tag.add(TDAT(text=str(track.date.day) + str(track.date.month)))
 | 
				
			||||||
    if save['length']:
 | 
					    if save['length']:
 | 
				
			||||||
        tag.add(TLEN(text=str(int(track.duration)*1000)))
 | 
					        tag.add(TLEN(text=str(int(track.duration)*1000)))
 | 
				
			||||||
    if save['bpm']:
 | 
					    if save['bpm']:
 | 
				
			||||||
        tag.add(TBPM(text=str(track.bpm)))
 | 
					        tag.add(TBPM(text=str(track.bpm)))
 | 
				
			||||||
    if save['label']:
 | 
					    if save['label']:
 | 
				
			||||||
        tag.add(TPUB(text=track.album['label']))
 | 
					        tag.add(TPUB(text=track.album.label))
 | 
				
			||||||
    if save['isrc']:
 | 
					    if save['isrc']:
 | 
				
			||||||
        tag.add(TSRC(text=track.ISRC))
 | 
					        tag.add(TSRC(text=track.ISRC))
 | 
				
			||||||
    if save['barcode']:
 | 
					    if save['barcode']:
 | 
				
			||||||
        tag.add(TXXX(desc="BARCODE", text=track.album['barcode']))
 | 
					        tag.add(TXXX(desc="BARCODE", text=track.album.barcode))
 | 
				
			||||||
    if save['explicit']:
 | 
					    if save['explicit']:
 | 
				
			||||||
        tag.add(TXXX(desc="ITUNESADVISORY", text= "1" if track.explicit else "0" ))
 | 
					        tag.add(TXXX(desc="ITUNESADVISORY", text= "1" if track.explicit else "0" ))
 | 
				
			||||||
    if save['replayGain']:
 | 
					    if save['replayGain']:
 | 
				
			||||||
        tag.add(TXXX(desc="REPLAYGAIN_TRACK_GAIN", text=track.replayGain))
 | 
					        tag.add(TXXX(desc="REPLAYGAIN_TRACK_GAIN", text=track.replayGain))
 | 
				
			||||||
    if track.lyrics['unsync'] and save['lyrics']:
 | 
					    if track.lyrics.unsync and save['lyrics']:
 | 
				
			||||||
        tag.add(USLT(text=track.lyrics['unsync']))
 | 
					        tag.add(USLT(text=track.lyrics.unsync))
 | 
				
			||||||
    if track.lyrics['syncID3'] and save['syncedLyrics']:
 | 
					    if track.lyrics.syncID3 and save['syncedLyrics']:
 | 
				
			||||||
        # Referencing ID3 standard
 | 
					        # Referencing ID3 standard
 | 
				
			||||||
        # https://id3.org/id3v2.3.0#sec4.10
 | 
					        # https://id3.org/id3v2.3.0#sec4.10
 | 
				
			||||||
        # Type:   1  => is lyrics
 | 
					        # Type:   1  => is lyrics
 | 
				
			||||||
        # Format: 2  => Absolute time, 32 bit sized, using milliseconds as unit
 | 
					        # Format: 2  => Absolute time, 32 bit sized, using milliseconds as unit
 | 
				
			||||||
        tag.add(SYLT(Encoding.UTF8, type=1, format=2, text=track.lyrics['syncID3']))
 | 
					        tag.add(SYLT(Encoding.UTF8, type=1, format=2, text=track.lyrics.syncID3))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    involved_people = []
 | 
					    involved_people = []
 | 
				
			||||||
    for role in track.contributors:
 | 
					    for role in track.contributors:
 | 
				
			||||||
@ -91,24 +91,24 @@ def tagID3(stream, track, save):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if save['copyright']:
 | 
					    if save['copyright']:
 | 
				
			||||||
        tag.add(TCOP(text=track.copyright))
 | 
					        tag.add(TCOP(text=track.copyright))
 | 
				
			||||||
    if save['savePlaylistAsCompilation'] and track.playlist or track.album['recordType'] == "compile":
 | 
					    if save['savePlaylistAsCompilation'] and track.playlist or track.album.recordType == "compile":
 | 
				
			||||||
        tag.add(TCMP(text="1"))
 | 
					        tag.add(TCMP(text="1"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if save['source']:
 | 
					    if save['source']:
 | 
				
			||||||
        tag.add(TXXX(desc="SOURCE", text='Deezer'))
 | 
					        tag.add(TXXX(desc="SOURCE", text='Deezer'))
 | 
				
			||||||
        tag.add(TXXX(desc="SOURCEID", text=str(track.id)))
 | 
					        tag.add(TXXX(desc="SOURCEID", text=str(track.id)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if save['cover'] and track.album['embeddedCoverPath']:
 | 
					    if save['cover'] and track.album.embeddedCoverPath:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        descEncoding = Encoding.LATIN1
 | 
					        descEncoding = Encoding.LATIN1
 | 
				
			||||||
        if save['coverDescriptionUTF8']:
 | 
					        if save['coverDescriptionUTF8']:
 | 
				
			||||||
            descEncoding = Encoding.UTF8
 | 
					            descEncoding = Encoding.UTF8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mimeType = 'image/jpeg'
 | 
					        mimeType = 'image/jpeg'
 | 
				
			||||||
        if str(track.album['embeddedCoverPath']).endswith('png'):
 | 
					        if str(track.album.embeddedCoverPath).endswith('png'):
 | 
				
			||||||
            mimeType = 'image/png'
 | 
					            mimeType = 'image/png'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with open(track.album['embeddedCoverPath'], 'rb') as f:
 | 
					        with open(track.album.embeddedCoverPath, 'rb') as f:
 | 
				
			||||||
            tag.add(APIC(descEncoding, mimeType, PictureType.COVER_FRONT, desc='cover', data=f.read()))
 | 
					            tag.add(APIC(descEncoding, mimeType, PictureType.COVER_FRONT, desc='cover', data=f.read()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tag.save( stream,
 | 
					    tag.save( stream,
 | 
				
			||||||
@ -131,7 +131,7 @@ def tagFLAC(stream, track, save):
 | 
				
			|||||||
            tag["ARTIST"] = track.artists
 | 
					            tag["ARTIST"] = track.artists
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            if save['multiArtistSeparator'] == "nothing":
 | 
					            if save['multiArtistSeparator'] == "nothing":
 | 
				
			||||||
                tag["ARTIST"] = track.mainArtist['name']
 | 
					                tag["ARTIST"] = track.mainArtist.name
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                tag["ARTIST"] = track.artistsString
 | 
					                tag["ARTIST"] = track.artistsString
 | 
				
			||||||
            # Tag ARTISTS is added to keep the multiartist support when using a non standard tagging method
 | 
					            # Tag ARTISTS is added to keep the multiartist support when using a non standard tagging method
 | 
				
			||||||
@ -139,24 +139,24 @@ def tagFLAC(stream, track, save):
 | 
				
			|||||||
            tag["ARTISTS"] = track.artists
 | 
					            tag["ARTISTS"] = track.artists
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if save['album']:
 | 
					    if save['album']:
 | 
				
			||||||
        tag["ALBUM"] = track.album['title']
 | 
					        tag["ALBUM"] = track.album.title
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if save['albumArtist'] and len(track.album['artists']):
 | 
					    if save['albumArtist'] and len(track.album.artists):
 | 
				
			||||||
        if save['singleAlbumArtist'] and track.album['mainArtist']['save']:
 | 
					        if save['singleAlbumArtist'] and track.album.mainArtist.save:
 | 
				
			||||||
            tag["ALBUMARTIST"] = track.album['mainArtist']['name']
 | 
					            tag["ALBUMARTIST"] = track.album.mainArtist.name
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            tag["ALBUMARTIST"] = track.album['artists']
 | 
					            tag["ALBUMARTIST"] = track.album.artists
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if save['trackNumber']:
 | 
					    if save['trackNumber']:
 | 
				
			||||||
        tag["TRACKNUMBER"] = str(track.trackNumber)
 | 
					        tag["TRACKNUMBER"] = str(track.trackNumber)
 | 
				
			||||||
    if save['trackTotal']:
 | 
					    if save['trackTotal']:
 | 
				
			||||||
        tag["TRACKTOTAL"] = str(track.album['trackTotal'])
 | 
					        tag["TRACKTOTAL"] = str(track.album.trackTotal)
 | 
				
			||||||
    if save['discNumber']:
 | 
					    if save['discNumber']:
 | 
				
			||||||
        tag["DISCNUMBER"] = str(track.discNumber)
 | 
					        tag["DISCNUMBER"] = str(track.discNumber)
 | 
				
			||||||
    if save['discTotal']:
 | 
					    if save['discTotal']:
 | 
				
			||||||
        tag["DISCTOTAL"] = str(track.album['discTotal'])
 | 
					        tag["DISCTOTAL"] = str(track.album.discTotal)
 | 
				
			||||||
    if save['genre']:
 | 
					    if save['genre']:
 | 
				
			||||||
        tag["GENRE"] = track.album['genre']
 | 
					        tag["GENRE"] = track.album.genre
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # YEAR tag is not suggested as a standard tag
 | 
					    # YEAR tag is not suggested as a standard tag
 | 
				
			||||||
    # Being YEAR already contained in DATE will only use DATE instead
 | 
					    # Being YEAR already contained in DATE will only use DATE instead
 | 
				
			||||||
@ -164,24 +164,24 @@ def tagFLAC(stream, track, save):
 | 
				
			|||||||
    if save['date']:
 | 
					    if save['date']:
 | 
				
			||||||
        tag["DATE"] = track.dateString
 | 
					        tag["DATE"] = track.dateString
 | 
				
			||||||
    elif save['year']:
 | 
					    elif save['year']:
 | 
				
			||||||
        tag["DATE"] = str(track.date['year'])
 | 
					        tag["DATE"] = str(track.date.year)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if save['length']:
 | 
					    if save['length']:
 | 
				
			||||||
        tag["LENGTH"] = str(int(track.duration)*1000)
 | 
					        tag["LENGTH"] = str(int(track.duration)*1000)
 | 
				
			||||||
    if save['bpm']:
 | 
					    if save['bpm']:
 | 
				
			||||||
        tag["BPM"] = str(track.bpm)
 | 
					        tag["BPM"] = str(track.bpm)
 | 
				
			||||||
    if save['label']:
 | 
					    if save['label']:
 | 
				
			||||||
        tag["PUBLISHER"] = track.album['label']
 | 
					        tag["PUBLISHER"] = track.album.label
 | 
				
			||||||
    if save['isrc']:
 | 
					    if save['isrc']:
 | 
				
			||||||
        tag["ISRC"] = track.ISRC
 | 
					        tag["ISRC"] = track.ISRC
 | 
				
			||||||
    if save['barcode']:
 | 
					    if save['barcode']:
 | 
				
			||||||
        tag["BARCODE"] = track.album['barcode']
 | 
					        tag["BARCODE"] = track.album.barcode
 | 
				
			||||||
    if save['explicit']:
 | 
					    if save['explicit']:
 | 
				
			||||||
        tag["ITUNESADVISORY"] = "1" if track.explicit else "0"
 | 
					        tag["ITUNESADVISORY"] = "1" if track.explicit else "0"
 | 
				
			||||||
    if save['replayGain']:
 | 
					    if save['replayGain']:
 | 
				
			||||||
        tag["REPLAYGAIN_TRACK_GAIN"] = track.replayGain
 | 
					        tag["REPLAYGAIN_TRACK_GAIN"] = track.replayGain
 | 
				
			||||||
    if track.lyrics['unsync'] and save['lyrics']:
 | 
					    if track.lyrics.unsync and save['lyrics']:
 | 
				
			||||||
        tag["LYRICS"] = track.lyrics['unsync']
 | 
					        tag["LYRICS"] = track.lyrics.unsync
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for role in track.contributors:
 | 
					    for role in track.contributors:
 | 
				
			||||||
        if role in ['author', 'engineer', 'mixer', 'producer', 'writer', 'composer']:
 | 
					        if role in ['author', 'engineer', 'mixer', 'producer', 'writer', 'composer']:
 | 
				
			||||||
@ -192,20 +192,20 @@ def tagFLAC(stream, track, save):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if save['copyright']:
 | 
					    if save['copyright']:
 | 
				
			||||||
        tag["COPYRIGHT"] = track.copyright
 | 
					        tag["COPYRIGHT"] = track.copyright
 | 
				
			||||||
    if save['savePlaylistAsCompilation'] and track.playlist or track.album['recordType'] == "compile":
 | 
					    if save['savePlaylistAsCompilation'] and track.playlist or track.album.recordType == "compile":
 | 
				
			||||||
        tag["COMPILATION"] = "1"
 | 
					        tag["COMPILATION"] = "1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if save['source']:
 | 
					    if save['source']:
 | 
				
			||||||
        tag["SOURCE"] = 'Deezer'
 | 
					        tag["SOURCE"] = 'Deezer'
 | 
				
			||||||
        tag["SOURCEID"] = str(track.id)
 | 
					        tag["SOURCEID"] = str(track.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if save['cover'] and track.album['embeddedCoverPath']:
 | 
					    if save['cover'] and track.album.embeddedCoverPath:
 | 
				
			||||||
        image = Picture()
 | 
					        image = Picture()
 | 
				
			||||||
        image.type = PictureType.COVER_FRONT
 | 
					        image.type = PictureType.COVER_FRONT
 | 
				
			||||||
        image.mime = 'image/jpeg'
 | 
					        image.mime = 'image/jpeg'
 | 
				
			||||||
        if str(track.album['embeddedCoverPath']).endswith('png'):
 | 
					        if str(track.album.embeddedCoverPath).endswith('png'):
 | 
				
			||||||
            image.mime = 'image/png'
 | 
					            image.mime = 'image/png'
 | 
				
			||||||
        with open(track.album['embeddedCoverPath'], 'rb') as f:
 | 
					        with open(track.album.embeddedCoverPath, 'rb') as f:
 | 
				
			||||||
            image.data = f.read()
 | 
					            image.data = f.read()
 | 
				
			||||||
        tag.add_picture(image)
 | 
					        tag.add_picture(image)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user