Implemented search fallback
This commit is contained in:
parent
a7d16afa41
commit
d9ae3f3289
|
@ -5,11 +5,10 @@ Run `python -m deemix --help` to see how to use the app
|
||||||
# TODO
|
# TODO
|
||||||
Finish porting all features:
|
Finish porting all features:
|
||||||
- logging
|
- logging
|
||||||
|
- gui
|
||||||
- ?
|
- ?
|
||||||
|
|
||||||
Settings not yet implemented:
|
Settings not yet implemented:
|
||||||
- fallbackSearch (off by default)
|
|
||||||
- logSearched
|
|
||||||
- savePlaylistAsCompilation
|
- savePlaylistAsCompilation
|
||||||
- removeAlbumVersion
|
- removeAlbumVersion
|
||||||
- moveFeaturedToTitle
|
- moveFeaturedToTitle
|
||||||
|
|
|
@ -81,6 +81,29 @@ def getPreferredBitrate(filesize, bitrate, fallback=True):
|
||||||
break
|
break
|
||||||
return (selectedFormat, selectedFilesize)
|
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):
|
def parseEssentialTrackData(track, trackAPI):
|
||||||
track['id'] = trackAPI['SNG_ID']
|
track['id'] = trackAPI['SNG_ID']
|
||||||
track['duration'] = trackAPI['DURATION']
|
track['duration'] = trackAPI['DURATION']
|
||||||
|
@ -340,12 +363,29 @@ def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack=
|
||||||
print('Downloading: {} - {}'.format(track['mainArtist']['name'], track['title']))
|
print('Downloading: {} - {}'.format(track['mainArtist']['name'], track['title']))
|
||||||
if track['MD5'] == '':
|
if track['MD5'] == '':
|
||||||
if track['fallbackId'] != 0:
|
if track['fallbackId'] != 0:
|
||||||
print("Track not available, using fallback id")
|
print("Track not yet encoded, using fallback id")
|
||||||
trackNew = dz.get_track_gw(track['fallbackId'])
|
trackNew = dz.get_track_gw(track['fallbackId'])
|
||||||
if not 'MD5_ORIGIN' in trackNew:
|
if not 'MD5_ORIGIN' in trackNew:
|
||||||
trackNew['MD5_ORIGIN'] = dz.get_track_md5(trackNew['SNG_ID'])
|
trackNew['MD5_ORIGIN'] = dz.get_track_md5(trackNew['SNG_ID'])
|
||||||
track = parseEssentialTrackData(track, trackNew)
|
track = parseEssentialTrackData(track, trackNew)
|
||||||
return downloadTrackObj(dz, trackAPI, settings, extraTrack=track)
|
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'])
|
||||||
|
if searchedId != 0:
|
||||||
|
trackNew = dz.get_track_gw(searchedId)
|
||||||
|
if not 'MD5_ORIGIN' in trackNew:
|
||||||
|
trackNew['MD5_ORIGIN'] = dz.get_track_md5(trackNew['SNG_ID'])
|
||||||
|
track = parseEssentialTrackData(track, trackNew)
|
||||||
|
track['searched'] = True
|
||||||
|
return downloadTrackObj(dz, trackAPI, settings, extraTrack=track)
|
||||||
|
else:
|
||||||
|
print("ERROR: Track not yet encoded and no alternative found!")
|
||||||
|
result['error'] = {
|
||||||
|
'message': "Track not yet encoded and no alternative found!",
|
||||||
|
'data': track
|
||||||
|
}
|
||||||
|
return result
|
||||||
else:
|
else:
|
||||||
print("ERROR: Track not yet encoded!")
|
print("ERROR: Track not yet encoded!")
|
||||||
result['error'] = {
|
result['error'] = {
|
||||||
|
@ -435,6 +475,23 @@ def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack=
|
||||||
trackNew['MD5_ORIGIN'] = dz.get_track_md5(trackNew['SNG_ID'])
|
trackNew['MD5_ORIGIN'] = dz.get_track_md5(trackNew['SNG_ID'])
|
||||||
track = parseEssentialTrackData(track, trackNew)
|
track = parseEssentialTrackData(track, trackNew)
|
||||||
return downloadTrackObj(dz, trackAPI, settings, extraTrack=track)
|
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'])
|
||||||
|
if searchedId != 0:
|
||||||
|
trackNew = dz.get_track_gw(searchedId)
|
||||||
|
if not 'MD5_ORIGIN' in trackNew:
|
||||||
|
trackNew['MD5_ORIGIN'] = dz.get_track_md5(trackNew['SNG_ID'])
|
||||||
|
track = parseEssentialTrackData(track, trackNew)
|
||||||
|
track['searched'] = True
|
||||||
|
return downloadTrackObj(dz, trackAPI, settings, extraTrack=track)
|
||||||
|
else:
|
||||||
|
print("ERROR: Track not available on deezer's servers and no alternative found!")
|
||||||
|
result['error'] = {
|
||||||
|
'message': "Track not available on deezer's servers and no alternative found!",
|
||||||
|
'data': track
|
||||||
|
}
|
||||||
|
return result
|
||||||
else:
|
else:
|
||||||
print("ERROR: Track not available on deezer's servers!")
|
print("ERROR: Track not available on deezer's servers!")
|
||||||
result['error'] = {
|
result['error'] = {
|
||||||
|
@ -446,6 +503,8 @@ def downloadTrackObj(dz, trackAPI, settings, overwriteBitrate=False, extraTrack=
|
||||||
tagID3(writepath, track, settings['tags'], settings['saveID3v1'], settings['useNullSeparator'])
|
tagID3(writepath, track, settings['tags'], settings['saveID3v1'], settings['useNullSeparator'])
|
||||||
elif track['selectedFormat'] == 9:
|
elif track['selectedFormat'] == 9:
|
||||||
tagFLAC(writepath, track, settings['tags'])
|
tagFLAC(writepath, track, settings['tags'])
|
||||||
|
if 'searched' in track:
|
||||||
|
result['searched'] = f'{track["mainArtist"]["name"]} - {track["title"]}'
|
||||||
print("Done!")
|
print("Done!")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -453,10 +512,13 @@ def after_download(tracks, settings):
|
||||||
extrasPath = None
|
extrasPath = None
|
||||||
playlist = [None] * len(tracks)
|
playlist = [None] * len(tracks)
|
||||||
errors = ""
|
errors = ""
|
||||||
|
searched = ""
|
||||||
for index in range(len(tracks)):
|
for index in range(len(tracks)):
|
||||||
result = tracks[index].result()
|
result = tracks[index].result()
|
||||||
if 'error' in result:
|
if 'error' in result:
|
||||||
errors += f"{result['error']['data']['id']} | {result['error']['data']['mainArtist']['name']} - {result['error']['data']['title']} | {result['error']['message']}\r\n"
|
errors += f"{result['error']['data']['id']} | {result['error']['data']['mainArtist']['name']} - {result['error']['data']['title']} | {result['error']['message']}\r\n"
|
||||||
|
if 'searched' in result:
|
||||||
|
searched += result['searched']+"\r\n"
|
||||||
if not extrasPath and 'extrasPath' in result:
|
if not extrasPath and 'extrasPath' in result:
|
||||||
extrasPath = result['extrasPath']
|
extrasPath = result['extrasPath']
|
||||||
if settings['saveArtwork'] and result['albumPath']:
|
if settings['saveArtwork'] and result['albumPath']:
|
||||||
|
@ -470,21 +532,36 @@ def after_download(tracks, settings):
|
||||||
if settings['logErrors'] and extrasPath and errors != "":
|
if settings['logErrors'] and extrasPath and errors != "":
|
||||||
with open(os.path.join(extrasPath, 'errors.txt'), 'w') as f:
|
with open(os.path.join(extrasPath, 'errors.txt'), 'w') as f:
|
||||||
f.write(errors)
|
f.write(errors)
|
||||||
|
if settings['logSearched'] and extrasPath and searched != "":
|
||||||
|
with open(os.path.join(extrasPath, 'searched.txt'), 'w') as f:
|
||||||
|
f.write(searched)
|
||||||
if settings['createM3U8File'] and extrasPath:
|
if settings['createM3U8File'] and extrasPath:
|
||||||
with open(os.path.join(extrasPath, 'playlist.m3u8'), 'w') as f:
|
with open(os.path.join(extrasPath, 'playlist.m3u8'), 'w') as f:
|
||||||
for line in playlist:
|
for line in playlist:
|
||||||
f.write(line+"\n")
|
f.write(line+"\n")
|
||||||
return extrasPath
|
return extrasPath
|
||||||
|
|
||||||
|
def after_download_single(track, settings):
|
||||||
|
if settings['logSearched'] and 'extrasPath' in result and 'searched' in result:
|
||||||
|
with open(os.path.join(result['extrasPath'], 'searched.txt'), 'w+') as f:
|
||||||
|
orig = f.read()
|
||||||
|
if not result['searched'] in orig:
|
||||||
|
if orig != "":
|
||||||
|
orig += "\r\n"
|
||||||
|
orig += result['searched']+"\r\n"
|
||||||
|
f.write(orig)
|
||||||
|
if 'extrasPath' in result:
|
||||||
|
return result['extrasPath']
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def download_track(dz, id, settings, overwriteBitrate=False):
|
def download_track(dz, id, settings, overwriteBitrate=False):
|
||||||
trackAPI = dz.get_track_gw(id)
|
trackAPI = dz.get_track_gw(id)
|
||||||
trackAPI['FILENAME_TEMPLATE'] = settings['tracknameTemplate']
|
trackAPI['FILENAME_TEMPLATE'] = settings['tracknameTemplate']
|
||||||
trackAPI['SINGLE_TRACK'] = True
|
trackAPI['SINGLE_TRACK'] = True
|
||||||
result = downloadTrackObj(dz, trackAPI, settings, overwriteBitrate)
|
result = downloadTrackObj(dz, trackAPI, settings, overwriteBitrate)
|
||||||
if 'extrasPath' in result:
|
return after_download_single(result, settings)
|
||||||
return result['extrasPath']
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def download_album(dz, id, settings, overwriteBitrate=False):
|
def download_album(dz, id, settings, overwriteBitrate=False):
|
||||||
albumAPI = dz.get_album(id)
|
albumAPI = dz.get_album(id)
|
||||||
|
@ -496,7 +573,8 @@ def download_album(dz, id, settings, overwriteBitrate=False):
|
||||||
trackAPI['_EXTRA_ALBUM'] = albumAPI
|
trackAPI['_EXTRA_ALBUM'] = albumAPI
|
||||||
trackAPI['FILENAME_TEMPLATE'] = settings['tracknameTemplate']
|
trackAPI['FILENAME_TEMPLATE'] = settings['tracknameTemplate']
|
||||||
trackAPI['SINGLE_TRACK'] = True
|
trackAPI['SINGLE_TRACK'] = True
|
||||||
downloadTrackObj(dz, trackAPI, settings, overwriteBitrate)
|
result = downloadTrackObj(dz, trackAPI, settings, overwriteBitrate)
|
||||||
|
return after_download_single(result, settings)
|
||||||
else:
|
else:
|
||||||
tracksArray = dz.get_album_tracks_gw(id)
|
tracksArray = dz.get_album_tracks_gw(id)
|
||||||
playlist = [None] * len(tracksArray)
|
playlist = [None] * len(tracksArray)
|
||||||
|
|
|
@ -21,6 +21,8 @@ def getBitrateInt(txt):
|
||||||
def getIDFromLink(link, type):
|
def getIDFromLink(link, type):
|
||||||
if '?' in link:
|
if '?' in link:
|
||||||
link = link[:link.find('?')]
|
link = link[:link.find('?')]
|
||||||
|
if link.endswith("/"):
|
||||||
|
link = link[:-1]
|
||||||
|
|
||||||
if link.startswith("http") and 'open.spotify.com/' in link:
|
if link.startswith("http") and 'open.spotify.com/' in link:
|
||||||
if type == "spotifyplaylist":
|
if type == "spotifyplaylist":
|
||||||
|
|
Loading…
Reference in New Issue