diff --git a/README.md b/README.md index 9210fcf..e928f88 100644 --- a/README.md +++ b/README.md @@ -11,5 +11,3 @@ Finish porting all features: Settings not yet implemented: - savePlaylistAsCompilation -- titleCasing -- artistCasing diff --git a/deemix/api/deezer.py b/deemix/api/deezer.py index e4c9336..350d3de 100755 --- a/deemix/api/deezer.py +++ b/deemix/api/deezer.py @@ -310,6 +310,29 @@ class Deezer: urlPart = self._ecb_crypt(b'jo6aey6haid2Teih', step2) return "https://e-cdns-proxy-" + md5[0] + ".dzcdn.net/mobile/1/" + urlPart.decode("utf-8") + def get_track_from_metadata(self, artist, track, album): + artist = artist.replace("–","-").replace("’", "'") + track = track.replace("–","-").replace("’", "'") + album = album.replace("–","-").replace("’", "'") + + resp = self.search(f'artist:"{artist}" track:"{track}" album:"{album}"', "track", 1) + if len(resp['data'])>0: + return resp['data'][0]['id'] + resp = self.search(f'artist:"{artist}" track:"{track}"', "track", 1) + if len(resp['data'])>0: + return resp['data'][0]['id'] + if "(" in track and ")" in track and track.find("(") < track.find(")"): + resp = self.search(f'artist:"{artist}" track:"{track[:track.find("(")]}"', "track", 1) + if len(resp['data'])>0: + return resp['data'][0]['id'] + elif " - " in track: + resp = self.search(f'artist:"{artist}" track:"{track[:track.find(" - ")]}"', "track", 1) + if len(resp['data'])>0: + return resp['data'][0]['id'] + else: + return 0 + return 0 + class APIError(Exception): pass diff --git a/deemix/app/default.json b/deemix/app/default.json index 5ed38f9..b14953f 100644 --- a/deemix/app/default.json +++ b/deemix/app/default.json @@ -30,13 +30,10 @@ "saveArtworkArtist": false, "artistImageTemplate": "folder", "PNGcovers": false, - "multitagSeparator": "default", "dateFormat": "Y-M-D", "savePlaylistAsCompilation": false, "removeAlbumVersion": false, "featuredToTitle": "0", - "useNullSeparator": false, - "saveID3v1": true, "titleCasing": "nothing", "artistCasing": "nothing", "executeCommand": "", @@ -63,6 +60,9 @@ "lyrics": false, "copyright": false, "composer": false, - "involvedPeople": false + "involvedPeople": false, + "useNullSeparator": false, + "saveID3v1": true, + "multitagSeparator": "default" } } diff --git a/deemix/app/downloader.py b/deemix/app/downloader.py index 616a71a..3819fc7 100644 --- a/deemix/app/downloader.py +++ b/deemix/app/downloader.py @@ -82,29 +82,6 @@ def getPreferredBitrate(filesize, bitrate, fallback=True): break return (selectedFormat, selectedFilesize) -def convertMetadata2Deezer(dz, artist, track, album): - artist = artist.replace("–","-").replace("’", "'") - track = track.replace("–","-").replace("’", "'") - album = album.replace("–","-").replace("’", "'") - - resp = dz.search(f'artist:"{artist}" track:"{track}" album:"{album}"', "track", 1) - if len(resp['data'])>0: - return resp['data'][0]['id'] - resp = dz.search(f'artist:"{artist}" track:"{track}"', "track", 1) - if len(resp['data'])>0: - return resp['data'][0]['id'] - if "(" in track and ")" in track and track.find("(") < track.find(")"): - resp = dz.search(f'artist:"{artist}" track:"{track[:track.find("(")]}"', "track", 1) - if len(resp['data'])>0: - return resp['data'][0]['id'] - elif " - " in track: - resp = dz.search(f'artist:"{artist}" track:"{track[:track.find(" - ")]}"', "track", 1) - if len(resp['data'])>0: - return resp['data'][0]['id'] - else: - return 0 - return 0 - def parseEssentialTrackData(track, trackAPI): track['id'] = trackAPI['SNG_ID'] track['duration'] = trackAPI['DURATION'] @@ -372,7 +349,7 @@ def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack= return downloadTrackObj(dz, trackAPI, settings, extraTrack=track) elif not 'searched' in track and settings['fallbackSearch']: print("Track not yet encoded, searching for alternative") - searchedId = convertMetadata2Deezer(dz, track['mainArtist']['name'], track['title'], track['album']['title']) + searchedId = dz.get_track_from_metadata(track['mainArtist']['name'], track['title'], track['album']['title']) if searchedId != 0: trackNew = dz.get_track_gw(searchedId) if not 'MD5_ORIGIN' in trackNew: @@ -433,6 +410,25 @@ def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack= if "Album Version" in track['title']: track['title'] = re.sub(r' ?\(Album Version\)', "", track['title']).strip() + # Generate artist tag if needed + if settings['tags']['multitagSeparator'] != "default": + if settings['tags']['multitagSeparator'] == "andFeat": + track['artistsString'] = track['mainArtistsString'] + if 'featArtistsString' in track and settings['featuredToTitle'] != "2": + track['artistsString'] += " "+track['featArtistsString'] + else: + track['artistsString'] = settings['tags']['multitagSeparator'].join(track['artists']) + else: + track['artistsString'] = ", ".join(track['artists']) + + # Change Title and Artists casing if needed + if settings['titleCasing'] != "nothing": + tags['title'] = changeCase(tags['title'], settings['titleCasing']) + if settings['artistCasing'] != "nothing": + track['artistsString'] = changeCase(track['artistsString'], settings['artistCasing']) + for i, artist in enumerate(track['artists']): + track['artists'][i] = changeCase(artist, settings['artistCasing']) + # Generate filename and filepath from metadata filename = generateFilename(track, trackAPI, settings) (filepath, artistPath, coverPath, extrasPath) = generateFilepath(track, trackAPI, settings) @@ -464,15 +460,6 @@ def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack= result['extrasPath'] = extrasPath result['playlistPosition'] = writepath[len(extrasPath):] - # Generate artist tag if needed - if settings['multitagSeparator'] != "default": - if settings['multitagSeparator'] == "andFeat": - track['artistsString'] = track['mainArtistsString'] - if 'featArtistsString' in track and settings['featuredToTitle'] != "2": - track['artistsString'] += " "+track['featArtistsString'] - else: - track['artistsString'] = settings['multitagSeparator'].join(track['artists']) - track['downloadUrl'] = dz.get_track_stream_url(track['id'], track['MD5'], track['mediaVersion'], track['selectedFormat']) try: with open(writepath, 'wb') as stream: @@ -492,7 +479,7 @@ def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack= return downloadTrackObj(dz, trackAPI, settings, extraTrack=track) elif not 'searched' in track and settings['fallbackSearch']: print("Track not available, searching for alternative") - searchedId = convertMetadata2Deezer(dz, track['mainArtist']['name'], track['title'], track['album']['title']) + searchedId = dz.get_track_from_metadata(track['mainArtist']['name'], track['title'], track['album']['title']) if searchedId != 0: trackNew = dz.get_track_gw(searchedId) if not 'MD5_ORIGIN' in trackNew: @@ -515,7 +502,7 @@ def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack= } return result if track['selectedFormat'] in [3, 1, 8]: - tagID3(writepath, track, settings['tags'], settings['saveID3v1'], settings['useNullSeparator']) + tagID3(writepath, track, settings['tags']) elif track['selectedFormat'] == 9: tagFLAC(writepath, track, settings['tags']) if 'searched' in track: diff --git a/deemix/utils/misc.py b/deemix/utils/misc.py index a2a38ff..1f7ab5c 100644 --- a/deemix/utils/misc.py +++ b/deemix/utils/misc.py @@ -18,6 +18,25 @@ def getBitrateInt(txt): else: return None +def changeCase(string, type): + if type == "lower": + return string.lower() + elif type == "upper": + return string.upper() + elif type == "start": + string = string.split(" ") + res = [] + for index, value in enumerate(string): + res.append(value[0].upper() + value[0:].lower()) + }) + res = " ".join(res) + return res + elif type == "sentence": + res = string[0].upper() + string[0:].lower() + return res + else: + return string + def getIDFromLink(link, type): if '?' in link: link = link[:link.find('?')] diff --git a/deemix/utils/pathtemplates.py b/deemix/utils/pathtemplates.py index c7a21f9..484c049 100644 --- a/deemix/utils/pathtemplates.py +++ b/deemix/utils/pathtemplates.py @@ -29,12 +29,12 @@ def fixLongName(name): name = name[:200] return name -def antiDot(str): - while str[-1:] == "." or str[-1:] == " " or str[-1:] == "\n": - str = str[:-1] - if len(str) < 1: - str = "dot" - return str +def antiDot(string): + while string[-1:] == "." or string[-1:] == " " or string[-1:] == "\n": + string = string[:-1] + if len(string) < 1: + string = "dot" + return string def pad(num, max, dopad=True): paddingsize = len(str(max)) @@ -97,6 +97,7 @@ def generateFilepath(track, trackAPI, settings): def settingsRegex(filename, track, settings, playlist=None): filename = filename.replace("%title%", fixName(track['title'], settings['illegalCharacterReplacer'])) filename = filename.replace("%artist%", fixName(track['mainArtist']['name'], settings['illegalCharacterReplacer'])) + filename = filename.replace("%artists%", fixName(track['artistString'], 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("%tracknumber%", pad(track['trackNumber'], track['album']['trackTotal'] if int(settings['paddingSize']) == 0 else 10 ** (int(settings['paddingSize'])-1), settings['padTracks'])) diff --git a/deemix/utils/taggers.py b/deemix/utils/taggers.py index b54d86e..581386e 100644 --- a/deemix/utils/taggers.py +++ b/deemix/utils/taggers.py @@ -4,7 +4,7 @@ from mutagen.id3 import ID3, ID3NoHeaderError, TXXX, TIT2, TPE1, TALB, TPE2, TRC TPUB, TSRC, USLT, APIC, IPLS, TCOM, TCOP -def tagID3(stream, track, save, id3v1=False, nullSeparator=True): +def tagID3(stream, track, save): try: tag = ID3(stream) except ID3NoHeaderError: @@ -13,7 +13,7 @@ def tagID3(stream, track, save, id3v1=False, nullSeparator=True): if save['title']: tag.add(TIT2(text=track['title'])) if save['artist']: - if 'artistsString' in track: + if save['multitagSeparator'] != "default": tag.add(TPE1(text=track['artistsString'])) tag.add(TXXX(desc="ARTISTS", text=track['artists'])) else: @@ -62,7 +62,7 @@ def tagID3(stream, track, save, id3v1=False, nullSeparator=True): with open(track['album']['picPath'], 'rb') as f: tag.add(APIC(3, 'image/jpeg' if track['album']['picPath'].endswith('jpg') else 'image/png', 3, data=f.read())) - tag.save(stream, v1=2 if id3v1 else 0, v2_version=3, v23_sep=None if nullSeparator else '/') + tag.save(stream, v1=2 if save['saveID3v1'] else 0, v2_version=3, v23_sep=None if save['useNullSeparator'] else ' / ') def tagFLAC(stream, track, save): @@ -71,7 +71,7 @@ def tagFLAC(stream, track, save): if save['title']: tag["TITLE"] = track['title'] if save['artist']: - if 'artistsString' in track: + if save['multitagSeparator'] != "default": tag["ARTIST"] = track['artistsString'] tag["ARTISTS"] = track['artists'] else: