Merge branch 'master' of TrDex/deemix into master
This commit is contained in:
commit
a3d42b82b3
|
@ -6,6 +6,7 @@ __pycache__
|
||||||
/dist
|
/dist
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
|
/venv/
|
||||||
.env.local
|
.env.local
|
||||||
.env.*.local
|
.env.*.local
|
||||||
|
|
||||||
|
@ -21,4 +22,4 @@ yarn-error.log*
|
||||||
*.ntvs*
|
*.ntvs*
|
||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import click
|
import click
|
||||||
|
|
||||||
import deemix.app.cli as app
|
import deemix.app.cli as app
|
||||||
from deemix.app.settings import initSettings
|
from deemix.app.settings import initSettings
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option('-b', '--bitrate', default=None, help='Overwrites the default bitrate selected')
|
@click.option('-b', '--bitrate', default=None, help='Overwrites the default bitrate selected')
|
||||||
@click.argument('url')
|
@click.argument('url')
|
||||||
def download(bitrate, url):
|
def download(bitrate, url):
|
||||||
settings = initSettings()
|
settings = initSettings()
|
||||||
app.login()
|
app.login()
|
||||||
app.downloadLink(url, settings, bitrate)
|
app.downloadLink(url, settings, bitrate)
|
||||||
click.echo("All done!")
|
click.echo("All done!")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
download()
|
download()
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
#Empty File
|
# Empty File
|
||||||
|
|
|
@ -1,332 +1,343 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import binascii
|
import binascii
|
||||||
|
import time
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from Cryptodome.Cipher import Blowfish, AES
|
||||||
from Cryptodome.Hash import MD5
|
from Cryptodome.Hash import MD5
|
||||||
from Cryptodome.Util.Padding import pad
|
from Cryptodome.Util.Padding import pad
|
||||||
|
|
||||||
from Cryptodome.Cipher import Blowfish, AES
|
USER_AGENT_HEADER = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) " \
|
||||||
import requests
|
"Chrome/79.0.3945.130 Safari/537.36"
|
||||||
|
|
||||||
import time
|
|
||||||
|
|
||||||
USER_AGENT_HEADER = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"
|
|
||||||
|
|
||||||
|
|
||||||
class Deezer:
|
class Deezer:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.api_url = "http://www.deezer.com/ajax/gw-light.php"
|
self.api_url = "http://www.deezer.com/ajax/gw-light.php"
|
||||||
self.legacy_api_url = "https://api.deezer.com/"
|
self.legacy_api_url = "https://api.deezer.com/"
|
||||||
self.http_headers = {
|
self.http_headers = {
|
||||||
"User-Agent": USER_AGENT_HEADER
|
"User-Agent": USER_AGENT_HEADER
|
||||||
}
|
}
|
||||||
self.album_pictures_host = "https://e-cdns-images.dzcdn.net/images/cover/"
|
self.album_pictures_host = "https://e-cdns-images.dzcdn.net/images/cover/"
|
||||||
self.artist_pictures_host = "https://e-cdns-images.dzcdn.net/images/artist/"
|
self.artist_pictures_host = "https://e-cdns-images.dzcdn.net/images/artist/"
|
||||||
self.user = {}
|
self.user = {}
|
||||||
self.session = requests.Session()
|
self.session = requests.Session()
|
||||||
self.logged_in = False
|
self.logged_in = False
|
||||||
self.session.post("http://www.deezer.com/", headers=self.http_headers)
|
self.session.post("http://www.deezer.com/", headers=self.http_headers)
|
||||||
self.sid = self.session.cookies.get('sid')
|
self.sid = self.session.cookies.get('sid')
|
||||||
|
|
||||||
def get_token(self):
|
def get_token(self):
|
||||||
token_data = self.gw_api_call('deezer.getUserData')
|
token_data = self.gw_api_call('deezer.getUserData')
|
||||||
return token_data["results"]["checkForm"]
|
return token_data["results"]["checkForm"]
|
||||||
|
|
||||||
def get_track_md5(self, sng_id):
|
def get_track_md5(self, sng_id):
|
||||||
try:
|
try:
|
||||||
site = self.session.post(
|
site = self.session.post(
|
||||||
"https://api.deezer.com/1.0/gateway.php",
|
"https://api.deezer.com/1.0/gateway.php",
|
||||||
params={
|
params={
|
||||||
'api_key': "4VCYIJUCDLOUELGD1V8WBVYBNVDYOXEWSLLZDONGBBDFVXTZJRXPR29JRLQFO6ZE",
|
'api_key': "4VCYIJUCDLOUELGD1V8WBVYBNVDYOXEWSLLZDONGBBDFVXTZJRXPR29JRLQFO6ZE",
|
||||||
'sid': self.sid,
|
'sid': self.sid,
|
||||||
'input': '3',
|
'input': '3',
|
||||||
'output': '3',
|
'output': '3',
|
||||||
'method': 'song_getData'
|
'method': 'song_getData'
|
||||||
},
|
},
|
||||||
timeout=30,
|
timeout=30,
|
||||||
json={'sng_id': sng_id},
|
json={'sng_id': sng_id},
|
||||||
headers=self.http_headers
|
headers=self.http_headers
|
||||||
)
|
)
|
||||||
except:
|
except:
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
return self.get_track_md5(sng_id)
|
return self.get_track_md5(sng_id)
|
||||||
response = site.json()
|
response = site.json()
|
||||||
return response['results']['PUID']
|
return response['results']['PUID']
|
||||||
|
|
||||||
def gw_api_call(self, method, args={}):
|
def gw_api_call(self, method, args=None):
|
||||||
try:
|
if args is None:
|
||||||
result = self.session.post(
|
args = {}
|
||||||
self.api_url,
|
try:
|
||||||
params={
|
result = self.session.post(
|
||||||
'api_version': "1.0",
|
self.api_url,
|
||||||
'api_token': 'null' if method == 'deezer.getUserData' else self.get_token(),
|
params={
|
||||||
'input': '3',
|
'api_version': "1.0",
|
||||||
'method': method
|
'api_token': 'null' if method == 'deezer.getUserData' else self.get_token(),
|
||||||
},
|
'input': '3',
|
||||||
timeout=30,
|
'method': method
|
||||||
json=args,
|
},
|
||||||
headers=self.http_headers
|
timeout=30,
|
||||||
)
|
json=args,
|
||||||
except:
|
headers=self.http_headers
|
||||||
time.sleep(2)
|
)
|
||||||
return self.gw_api_call(method, args)
|
except:
|
||||||
return result.json()
|
time.sleep(2)
|
||||||
|
return self.gw_api_call(method, args)
|
||||||
|
return result.json()
|
||||||
|
|
||||||
def api_call(self, method, args={}):
|
def api_call(self, method, args=None):
|
||||||
try:
|
if args is None:
|
||||||
result = self.session.get(
|
args = {}
|
||||||
self.legacy_api_url + method,
|
try:
|
||||||
params=args,
|
result = self.session.get(
|
||||||
headers=self.http_headers,
|
self.legacy_api_url + method,
|
||||||
timeout=30
|
params=args,
|
||||||
)
|
headers=self.http_headers,
|
||||||
result_json = result.json()
|
timeout=30
|
||||||
except:
|
)
|
||||||
time.sleep(2)
|
result_json = result.json()
|
||||||
return self.api_call(method, args)
|
except:
|
||||||
if 'error' in result_json.keys():
|
time.sleep(2)
|
||||||
raise APIError()
|
return self.api_call(method, args)
|
||||||
return result_json
|
if 'error' in result_json.keys():
|
||||||
|
raise APIError()
|
||||||
|
return result_json
|
||||||
|
|
||||||
def login(self, email, password, re_captcha_token):
|
def login(self, email, password, re_captcha_token):
|
||||||
check_form_login = self.gw_api_call("deezer.getUserData")
|
check_form_login = self.gw_api_call("deezer.getUserData")
|
||||||
login = self.session.post(
|
login = self.session.post(
|
||||||
"https://www.deezer.com/ajax/action.php",
|
"https://www.deezer.com/ajax/action.php",
|
||||||
data={
|
data={
|
||||||
'type': 'login',
|
'type': 'login',
|
||||||
'mail': email,
|
'mail': email,
|
||||||
'password': password,
|
'password': password,
|
||||||
'checkFormLogin': check_form_login['results']['checkFormLogin'],
|
'checkFormLogin': check_form_login['results']['checkFormLogin'],
|
||||||
'reCaptchaToken': re_captcha_token
|
'reCaptchaToken': re_captcha_token
|
||||||
},
|
},
|
||||||
headers={'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', **self.http_headers}
|
headers={'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', **self.http_headers}
|
||||||
)
|
)
|
||||||
if 'success' not in login.text:
|
if 'success' not in login.text:
|
||||||
self.logged_in = False
|
self.logged_in = False
|
||||||
return False
|
return False
|
||||||
user_data = self.gw_api_call("deezer.getUserData")
|
user_data = self.gw_api_call("deezer.getUserData")
|
||||||
self.user = {
|
self.user = {
|
||||||
'email': email,
|
'email': email,
|
||||||
'id': user_data["results"]["USER"]["USER_ID"],
|
'id': user_data["results"]["USER"]["USER_ID"],
|
||||||
'name': user_data["results"]["USER"]["BLOG_NAME"],
|
'name': user_data["results"]["USER"]["BLOG_NAME"],
|
||||||
'picture': user_data["results"]["USER"]["USER_PICTURE"] if "USER_PICTURE" in user_data["results"][
|
'picture': user_data["results"]["USER"]["USER_PICTURE"] if "USER_PICTURE" in user_data["results"][
|
||||||
"USER"] else ""
|
"USER"] else ""
|
||||||
}
|
}
|
||||||
self.logged_in = True
|
self.logged_in = True
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def login_via_arl(self, arl):
|
def login_via_arl(self, arl):
|
||||||
cookie_obj = requests.cookies.create_cookie(
|
cookie_obj = requests.cookies.create_cookie(
|
||||||
domain='deezer.com',
|
domain='deezer.com',
|
||||||
name='arl',
|
name='arl',
|
||||||
value=arl,
|
value=arl,
|
||||||
path="/",
|
path="/",
|
||||||
rest={'HttpOnly': True}
|
rest={'HttpOnly': True}
|
||||||
)
|
)
|
||||||
self.session.cookies.set_cookie(cookie_obj)
|
self.session.cookies.set_cookie(cookie_obj)
|
||||||
user_data = self.gw_api_call("deezer.getUserData")
|
user_data = self.gw_api_call("deezer.getUserData")
|
||||||
if user_data["results"]["USER"]["USER_ID"] == 0:
|
if user_data["results"]["USER"]["USER_ID"] == 0:
|
||||||
self.logged_in = False
|
self.logged_in = False
|
||||||
return 0
|
return 0
|
||||||
self.user = {
|
self.user = {
|
||||||
'id': user_data["results"]["USER"]["USER_ID"],
|
'id': user_data["results"]["USER"]["USER_ID"],
|
||||||
'name': user_data["results"]["USER"]["BLOG_NAME"],
|
'name': user_data["results"]["USER"]["BLOG_NAME"],
|
||||||
'picture': user_data["results"]["USER"]["USER_PICTURE"] if "USER_PICTURE" in user_data["results"][
|
'picture': user_data["results"]["USER"]["USER_PICTURE"] if "USER_PICTURE" in user_data["results"][
|
||||||
"USER"] else ""
|
"USER"] else ""
|
||||||
}
|
}
|
||||||
self.logged_in = True
|
self.logged_in = True
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def get_track_gw(self, sng_id):
|
def get_track_gw(self, sng_id):
|
||||||
if int(sng_id) < 0:
|
if int(sng_id) < 0:
|
||||||
body = self.gw_api_call('song.getData', {'sng_id': sng_id})
|
body = self.gw_api_call('song.getData', {'sng_id': sng_id})
|
||||||
else:
|
else:
|
||||||
body = self.gw_api_call('deezer.pageTrack', {'sng_id': sng_id})
|
body = self.gw_api_call('deezer.pageTrack', {'sng_id': sng_id})
|
||||||
if 'LYRICS' in body['results']:
|
if 'LYRICS' in body['results']:
|
||||||
body['results']['DATA']['LYRICS'] = body['results']['LYRICS']
|
body['results']['DATA']['LYRICS'] = body['results']['LYRICS']
|
||||||
body['results'] = body['results']['DATA']
|
body['results'] = body['results']['DATA']
|
||||||
return body['results']
|
return body['results']
|
||||||
|
|
||||||
def get_tracks_gw(self, ids):
|
def get_tracks_gw(self, ids):
|
||||||
tracks_array = []
|
tracks_array = []
|
||||||
body = self.gw_api_call('song.getListData', {'sng_ids': ids})
|
body = self.gw_api_call('song.getListData', {'sng_ids': ids})
|
||||||
errors = 0
|
errors = 0
|
||||||
for i in range(len(ids)):
|
for i in range(len(ids)):
|
||||||
if ids[i] != 0:
|
if ids[i] != 0:
|
||||||
tracks_array.append(body['results']['data'][i - errors])
|
tracks_array.append(body['results']['data'][i - errors])
|
||||||
else:
|
else:
|
||||||
errors += 1
|
errors += 1
|
||||||
tracks_array.append({
|
tracks_array.append({
|
||||||
'SNG_ID': 0,
|
'SNG_ID': 0,
|
||||||
'SNG_TITLE': '',
|
'SNG_TITLE': '',
|
||||||
'DURATION': 0,
|
'DURATION': 0,
|
||||||
'MD5_ORIGIN': 0,
|
'MD5_ORIGIN': 0,
|
||||||
'MEDIA_VERSION': 0,
|
'MEDIA_VERSION': 0,
|
||||||
'FILESIZE': 0,
|
'FILESIZE': 0,
|
||||||
'ALB_TITLE': "",
|
'ALB_TITLE': "",
|
||||||
'ALB_PICTURE': "",
|
'ALB_PICTURE': "",
|
||||||
'ART_ID': 0,
|
'ART_ID': 0,
|
||||||
'ART_NAME': ""
|
'ART_NAME': ""
|
||||||
})
|
})
|
||||||
return tracks_array
|
return tracks_array
|
||||||
|
|
||||||
def get_album_gw(self, alb_id):
|
def get_album_gw(self, alb_id):
|
||||||
return self.gw_api_call('album.getData', {'alb_id': alb_id})['results']
|
return self.gw_api_call('album.getData', {'alb_id': alb_id})['results']
|
||||||
|
|
||||||
def get_album_tracks_gw(self, alb_id):
|
def get_album_tracks_gw(self, alb_id):
|
||||||
tracks_array = []
|
tracks_array = []
|
||||||
body = self.gw_api_call('song.getListByAlbum', {'alb_id': alb_id, 'nb': -1})
|
body = self.gw_api_call('song.getListByAlbum', {'alb_id': alb_id, 'nb': -1})
|
||||||
for track in body['results']['data']:
|
for track in body['results']['data']:
|
||||||
_track = track
|
_track = track
|
||||||
_track['position'] = body['results']['data'].index(track)
|
_track['position'] = body['results']['data'].index(track)
|
||||||
tracks_array.append(_track)
|
tracks_array.append(_track)
|
||||||
return tracks_array
|
return tracks_array
|
||||||
|
|
||||||
def get_artist_gw(self, art_id):
|
def get_artist_gw(self, art_id):
|
||||||
return self.gw_api_call('deezer.pageArtist', {'art_id': art_id})
|
return self.gw_api_call('deezer.pageArtist', {'art_id': art_id})
|
||||||
|
|
||||||
def get_playlist_gw(self, playlist_id):
|
def get_playlist_gw(self, playlist_id):
|
||||||
return self.gw_api_call('deezer.pagePlaylist', {'playlist_id': playlist_id})
|
return self.gw_api_call('deezer.pagePlaylist', {'playlist_id': playlist_id})
|
||||||
|
|
||||||
def get_playlist_tracks_gw(self, playlist_id):
|
def get_playlist_tracks_gw(self, playlist_id):
|
||||||
tracks_array = []
|
tracks_array = []
|
||||||
body = self.gw_api_call('playlist.getSongs', {'playlist_id': playlist_id, 'nb': -1})
|
body = self.gw_api_call('playlist.getSongs', {'playlist_id': playlist_id, 'nb': -1})
|
||||||
for track in body['results']['data']:
|
for track in body['results']['data']:
|
||||||
track['position'] = body['results']['data'].index(track)
|
track['position'] = body['results']['data'].index(track)
|
||||||
tracks_array.append(track)
|
tracks_array.append(track)
|
||||||
return tracks_array
|
return tracks_array
|
||||||
|
|
||||||
def get_artist_toptracks_gw(self, art_id):
|
def get_artist_toptracks_gw(self, art_id):
|
||||||
tracks_array = []
|
tracks_array = []
|
||||||
body = self.gw_api_call('artist.getTopTrack', {'art_id': art_id, 'nb': 100})
|
body = self.gw_api_call('artist.getTopTrack', {'art_id': art_id, 'nb': 100})
|
||||||
for track in body['results']['data']:
|
for track in body['results']['data']:
|
||||||
track['position'] = body['results']['data'].index(track)
|
track['position'] = body['results']['data'].index(track)
|
||||||
tracks_array.append(track)
|
tracks_array.append(track)
|
||||||
return tracks_array
|
return tracks_array
|
||||||
|
|
||||||
def search_main_gw(self, term):
|
def search_main_gw(self, term):
|
||||||
results = self.gw_api_call('deezer.pageSearch', {"query": term, "start": 0, "nb": 40, "suggest": True, "artist_suggest": True, "top_tracks": True})['results']
|
results = self.gw_api_call('deezer.pageSearch',
|
||||||
order = []
|
{"query": term, "start": 0, "nb": 40, "suggest": True, "artist_suggest": True,
|
||||||
for x in results['ORDER']:
|
"top_tracks": True})['results']
|
||||||
if x in ['TOP_RESULT', 'TRACK', 'ALBUM', 'ARTIST', 'PLAYLIST']:
|
order = []
|
||||||
order.append(x)
|
for x in results['ORDER']:
|
||||||
results['ORDER'] = order
|
if x in ['TOP_RESULT', 'TRACK', 'ALBUM', 'ARTIST', 'PLAYLIST']:
|
||||||
return results
|
order.append(x)
|
||||||
|
results['ORDER'] = order
|
||||||
|
return results
|
||||||
|
|
||||||
def search_gw(self, term, type, start, nb=20):
|
def search_gw(self, term, type, start, nb=20):
|
||||||
return self.gw_api_call('search.music', {"query": term, "filter":"ALL", "output":type, "start": start, "nb": nb})['results']
|
return \
|
||||||
|
self.gw_api_call('search.music',
|
||||||
|
{"query": term, "filter": "ALL", "output": type, "start": start, "nb": nb})[
|
||||||
|
'results']
|
||||||
|
|
||||||
def get_lyrics_gw(self, sng_id):
|
def get_lyrics_gw(self, sng_id):
|
||||||
return self.gw_api_call('song.getLyrics', {'sng_id': sng_id})["results"]
|
return self.gw_api_call('song.getLyrics', {'sng_id': sng_id})["results"]
|
||||||
|
|
||||||
def get_user_playlist(self, user_id):
|
def get_user_playlist(self, user_id):
|
||||||
return self.api_call('user/' + str(user_id) + '/playlists', {'limit': -1})
|
return self.api_call('user/' + str(user_id) + '/playlists', {'limit': -1})
|
||||||
|
|
||||||
def get_track(self, user_id):
|
def get_track(self, user_id):
|
||||||
return self.api_call('track/' + str(user_id))
|
return self.api_call('track/' + str(user_id))
|
||||||
|
|
||||||
def get_track_by_ISRC(self, isrc):
|
def get_track_by_ISRC(self, isrc):
|
||||||
return self.api_call('track/isrc:' + isrc)
|
return self.api_call('track/isrc:' + isrc)
|
||||||
|
|
||||||
def get_charts_top_country(self):
|
def get_charts_top_country(self):
|
||||||
return self.get_user_playlist('637006841')
|
return self.get_user_playlist('637006841')
|
||||||
|
|
||||||
def get_playlist(self, playlist_id):
|
def get_playlist(self, playlist_id):
|
||||||
return self.api_call('playlist/' + str(playlist_id))
|
return self.api_call('playlist/' + str(playlist_id))
|
||||||
|
|
||||||
def get_playlist_tracks(self, playlist_id):
|
def get_playlist_tracks(self, playlist_id):
|
||||||
return self.api_call('playlist/' + str(playlist_id) + '/tracks', {'limit': -1})
|
return self.api_call('playlist/' + str(playlist_id) + '/tracks', {'limit': -1})
|
||||||
|
|
||||||
def get_album(self, album_id):
|
def get_album(self, album_id):
|
||||||
return self.api_call('album/' + str(album_id))
|
return self.api_call('album/' + str(album_id))
|
||||||
|
|
||||||
def get_album_by_UPC(self, upc):
|
def get_album_by_UPC(self, upc):
|
||||||
return self.api_call('album/upc:' + str(upc))
|
return self.api_call('album/upc:' + str(upc))
|
||||||
|
|
||||||
def get_album_tracks(self, album_id):
|
def get_album_tracks(self, album_id):
|
||||||
return self.api_call('album/' + str(album_id) + '/tracks', {'limit': -1})
|
return self.api_call('album/' + str(album_id) + '/tracks', {'limit': -1})
|
||||||
|
|
||||||
def get_artist(self, artist_id):
|
def get_artist(self, artist_id):
|
||||||
return self.api_call('artist/' + str(artist_id))
|
return self.api_call('artist/' + str(artist_id))
|
||||||
|
|
||||||
def get_artist_albums(self, artist_id):
|
def get_artist_albums(self, artist_id):
|
||||||
return self.api_call('artist/' + str(artist_id) + '/albums', {'limit': -1})
|
return self.api_call('artist/' + str(artist_id) + '/albums', {'limit': -1})
|
||||||
|
|
||||||
def search(self, term, search_type, limit=30):
|
def search(self, term, search_type, limit=30):
|
||||||
return self.api_call('search/' + search_type, {'q': term, 'limit': limit})
|
return self.api_call('search/' + search_type, {'q': term, 'limit': limit})
|
||||||
|
|
||||||
def decrypt_track(self, track_id, input, output):
|
def decrypt_track(self, track_id, input, output):
|
||||||
response = open(input, 'rb')
|
response = open(input, 'rb')
|
||||||
outfile = open(output, 'wb')
|
outfile = open(output, 'wb')
|
||||||
blowfish_key = str.encode(self._get_blowfish_key(str(track_id)))
|
blowfish_key = str.encode(self._get_blowfish_key(str(track_id)))
|
||||||
i = 0
|
i = 0
|
||||||
while True:
|
while True:
|
||||||
chunk = response.read(2048)
|
chunk = response.read(2048)
|
||||||
if not chunk:
|
if not chunk:
|
||||||
break
|
break
|
||||||
if (i % 3) == 0 and len(chunk) == 2048:
|
if (i % 3) == 0 and len(chunk) == 2048:
|
||||||
chunk = Blowfish.new(blowfish_key, Blowfish.MODE_CBC, b"\x00\x01\x02\x03\x04\x05\x06\x07").decrypt(chunk)
|
chunk = Blowfish.new(blowfish_key, Blowfish.MODE_CBC, b"\x00\x01\x02\x03\x04\x05\x06\x07").decrypt(
|
||||||
outfile.write(chunk)
|
chunk)
|
||||||
i += 1
|
outfile.write(chunk)
|
||||||
|
i += 1
|
||||||
|
|
||||||
def stream_track(self, track_id, url, stream):
|
def stream_track(self, track_id, url, stream):
|
||||||
try:
|
try:
|
||||||
request = requests.get(url, headers=self.http_headers, stream=True, timeout=30)
|
request = requests.get(url, headers=self.http_headers, stream=True, timeout=30)
|
||||||
except:
|
except:
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
return self.stream_track(track_id, url, stream)
|
return self.stream_track(track_id, url, stream)
|
||||||
request.raise_for_status()
|
request.raise_for_status()
|
||||||
blowfish_key = str.encode(self._get_blowfish_key(str(track_id)))
|
blowfish_key = str.encode(self._get_blowfish_key(str(track_id)))
|
||||||
i = 0
|
i = 0
|
||||||
for chunk in request.iter_content(2048):
|
for chunk in request.iter_content(2048):
|
||||||
if (i % 3) == 0 and len(chunk) == 2048:
|
if (i % 3) == 0 and len(chunk) == 2048:
|
||||||
chunk = Blowfish.new(blowfish_key, Blowfish.MODE_CBC, b"\x00\x01\x02\x03\x04\x05\x06\x07").decrypt(chunk)
|
chunk = Blowfish.new(blowfish_key, Blowfish.MODE_CBC, b"\x00\x01\x02\x03\x04\x05\x06\x07").decrypt(
|
||||||
stream.write(chunk)
|
chunk)
|
||||||
i += 1
|
stream.write(chunk)
|
||||||
|
i += 1
|
||||||
|
|
||||||
def _md5(self, data):
|
def _md5(self, data):
|
||||||
h = MD5.new()
|
h = MD5.new()
|
||||||
h.update(str.encode(data) if isinstance(data, str) else data)
|
h.update(str.encode(data) if isinstance(data, str) else data)
|
||||||
return h.hexdigest()
|
return h.hexdigest()
|
||||||
|
|
||||||
def _get_blowfish_key(self, trackId):
|
def _get_blowfish_key(self, trackId):
|
||||||
SECRET = 'g4el58wc' + '0zvf9na1'
|
SECRET = 'g4el58wc' + '0zvf9na1'
|
||||||
idMd5 = self._md5(trackId)
|
idMd5 = self._md5(trackId)
|
||||||
bfKey = ""
|
bfKey = ""
|
||||||
for i in range(16):
|
for i in range(16):
|
||||||
bfKey += chr(ord(idMd5[i]) ^ ord(idMd5[i + 16]) ^ ord(SECRET[i]))
|
bfKey += chr(ord(idMd5[i]) ^ ord(idMd5[i + 16]) ^ ord(SECRET[i]))
|
||||||
return bfKey
|
return bfKey
|
||||||
|
|
||||||
def get_track_stream_url(self, sng_id, md5, media_version, format):
|
def get_track_stream_url(self, sng_id, md5, media_version, format):
|
||||||
urlPart = b'\xa4'.join(
|
urlPart = b'\xa4'.join(
|
||||||
[str.encode(md5), str.encode(str(format)), str.encode(str(sng_id)), str.encode(str(media_version))])
|
[str.encode(md5), str.encode(str(format)), str.encode(str(sng_id)), str.encode(str(media_version))])
|
||||||
md5val = self._md5(urlPart)
|
md5val = self._md5(urlPart)
|
||||||
step2 = str.encode(md5val) + b'\xa4' + urlPart + b'\xa4'
|
step2 = str.encode(md5val) + b'\xa4' + urlPart + b'\xa4'
|
||||||
step2 = pad(step2, 16)
|
step2 = pad(step2, 16)
|
||||||
urlPart = binascii.hexlify(AES.new(b'jo6aey6haid2Teih', AES.MODE_ECB).encrypt(step2))
|
urlPart = binascii.hexlify(AES.new(b'jo6aey6haid2Teih', AES.MODE_ECB).encrypt(step2))
|
||||||
return "https://e-cdns-proxy-" + md5[0] + ".dzcdn.net/mobile/1/" + urlPart.decode("utf-8")
|
return "https://e-cdns-proxy-" + md5[0] + ".dzcdn.net/mobile/1/" + urlPart.decode("utf-8")
|
||||||
|
|
||||||
def get_track_from_metadata(self, artist, track, album):
|
def get_track_from_metadata(self, artist, track, album):
|
||||||
artist = artist.replace("–","-").replace("’", "'")
|
artist = artist.replace("–", "-").replace("’", "'")
|
||||||
track = track.replace("–","-").replace("’", "'")
|
track = track.replace("–", "-").replace("’", "'")
|
||||||
album = album.replace("–","-").replace("’", "'")
|
album = album.replace("–", "-").replace("’", "'")
|
||||||
|
|
||||||
resp = self.search(f'artist:"{artist}" track:"{track}" album:"{album}"', "track", 1)
|
resp = self.search(f'artist:"{artist}" track:"{track}" album:"{album}"', "track", 1)
|
||||||
if len(resp['data'])>0:
|
if len(resp['data']) > 0:
|
||||||
return resp['data'][0]['id']
|
return resp['data'][0]['id']
|
||||||
resp = self.search(f'artist:"{artist}" track:"{track}"', "track", 1)
|
resp = self.search(f'artist:"{artist}" track:"{track}"', "track", 1)
|
||||||
if len(resp['data'])>0:
|
if len(resp['data']) > 0:
|
||||||
return resp['data'][0]['id']
|
return resp['data'][0]['id']
|
||||||
if "(" in track and ")" in track and track.find("(") < track.find(")"):
|
if "(" in track and ")" in track and track.find("(") < track.find(")"):
|
||||||
resp = self.search(f'artist:"{artist}" track:"{track[:track.find("(")]}"', "track", 1)
|
resp = self.search(f'artist:"{artist}" track:"{track[:track.find("(")]}"', "track", 1)
|
||||||
if len(resp['data'])>0:
|
if len(resp['data']) > 0:
|
||||||
return resp['data'][0]['id']
|
return resp['data'][0]['id']
|
||||||
elif " - " in track:
|
elif " - " in track:
|
||||||
resp = self.search(f'artist:"{artist}" track:"{track[:track.find(" - ")]}"', "track", 1)
|
resp = self.search(f'artist:"{artist}" track:"{track[:track.find(" - ")]}"', "track", 1)
|
||||||
if len(resp['data'])>0:
|
if len(resp['data']) > 0:
|
||||||
return resp['data'][0]['id']
|
return resp['data'][0]['id']
|
||||||
else:
|
else:
|
||||||
return 0
|
return 0
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
class APIError(Exception):
|
class APIError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,36 +1,38 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from deemix.api.deezer import Deezer
|
|
||||||
import deemix.utils.localpaths as localpaths
|
|
||||||
from deemix.utils.misc import getIDFromLink, getTypeFromLink, getBitrateInt
|
|
||||||
from deemix.app.queuemanager import addToQueue
|
|
||||||
from deemix.app.spotify import SpotifyHelper
|
|
||||||
from os import system as execute
|
|
||||||
import os.path as path
|
import os.path as path
|
||||||
from os import mkdir
|
from os import mkdir
|
||||||
|
|
||||||
|
import deemix.utils.localpaths as localpaths
|
||||||
|
from deemix.api.deezer import Deezer
|
||||||
|
from deemix.app.queuemanager import addToQueue
|
||||||
|
from deemix.app.spotify import SpotifyHelper
|
||||||
|
|
||||||
dz = Deezer()
|
dz = Deezer()
|
||||||
sp = SpotifyHelper()
|
sp = SpotifyHelper()
|
||||||
|
|
||||||
|
|
||||||
def requestValidArl():
|
def requestValidArl():
|
||||||
while True:
|
while True:
|
||||||
arl = input("Paste here your arl:")
|
arl = input("Paste here your arl:")
|
||||||
if dz.login_via_arl(arl):
|
if dz.login_via_arl(arl):
|
||||||
break
|
break
|
||||||
return arl
|
return arl
|
||||||
|
|
||||||
|
|
||||||
def login():
|
def login():
|
||||||
configFolder = localpaths.getConfigFolder()
|
configFolder = localpaths.getConfigFolder()
|
||||||
if not path.isdir(configFolder):
|
if not path.isdir(configFolder):
|
||||||
mkdir(configFolder)
|
mkdir(configFolder)
|
||||||
if path.isfile(path.join(configFolder, '.arl')):
|
if path.isfile(path.join(configFolder, '.arl')):
|
||||||
with open(path.join(configFolder, '.arl'), 'r') as f:
|
with open(path.join(configFolder, '.arl'), 'r') as f:
|
||||||
arl = f.read()
|
arl = f.read()
|
||||||
if not dz.login_via_arl(arl):
|
if not dz.login_via_arl(arl):
|
||||||
arl = requestValidArl()
|
arl = requestValidArl()
|
||||||
else:
|
else:
|
||||||
arl = requestValidArl()
|
arl = requestValidArl()
|
||||||
with open(path.join(configFolder, '.arl'), 'w') as f:
|
with open(path.join(configFolder, '.arl'), 'w') as f:
|
||||||
f.write(arl)
|
f.write(arl)
|
||||||
|
|
||||||
|
|
||||||
def downloadLink(url, settings, bitrate=None):
|
def downloadLink(url, settings, bitrate=None):
|
||||||
addToQueue(dz, sp, url, settings, bitrate)
|
addToQueue(dz, sp, url, settings, bitrate)
|
||||||
|
|
|
@ -1,69 +1,69 @@
|
||||||
{
|
{
|
||||||
"downloadLocation": "",
|
"downloadLocation": "",
|
||||||
"tracknameTemplate": "%artist% - %title%",
|
"tracknameTemplate": "%artist% - %title%",
|
||||||
"albumTracknameTemplate": "%tracknumber% - %title%",
|
"albumTracknameTemplate": "%tracknumber% - %title%",
|
||||||
"playlistTracknameTemplate": "%position% - %artist% - %title%",
|
"playlistTracknameTemplate": "%position% - %artist% - %title%",
|
||||||
"createPlaylistFolder": true,
|
"createPlaylistFolder": true,
|
||||||
"playlistNameTemplate": "%playlist%",
|
"playlistNameTemplate": "%playlist%",
|
||||||
"createArtistFolder": false,
|
"createArtistFolder": false,
|
||||||
"artistNameTemplate": "%artist%",
|
"artistNameTemplate": "%artist%",
|
||||||
"createAlbumFolder": true,
|
"createAlbumFolder": true,
|
||||||
"albumNameTemplate": "%artist% - %album%",
|
"albumNameTemplate": "%artist% - %album%",
|
||||||
"createCDFolder": true,
|
"createCDFolder": true,
|
||||||
"createStructurePlaylist": false,
|
"createStructurePlaylist": false,
|
||||||
"createSingleFolder": false,
|
"createSingleFolder": false,
|
||||||
"padTracks": true,
|
"padTracks": true,
|
||||||
"paddingSize": "0",
|
"paddingSize": "0",
|
||||||
"illegalCharacterReplacer": "_",
|
"illegalCharacterReplacer": "_",
|
||||||
"queueConcurrency": 3,
|
"queueConcurrency": 3,
|
||||||
"maxBitrate": "3",
|
"maxBitrate": "3",
|
||||||
"fallbackBitrate": true,
|
"fallbackBitrate": true,
|
||||||
"fallbackSearch": false,
|
"fallbackSearch": false,
|
||||||
"logErrors": true,
|
"logErrors": true,
|
||||||
"logSearched": false,
|
"logSearched": false,
|
||||||
"createM3U8File": false,
|
"createM3U8File": false,
|
||||||
"syncedLyrics": false,
|
"syncedLyrics": false,
|
||||||
"embeddedArtworkSize": 800,
|
"embeddedArtworkSize": 800,
|
||||||
"localArtworkSize": 1400,
|
"localArtworkSize": 1400,
|
||||||
"saveArtwork": true,
|
"saveArtwork": true,
|
||||||
"coverImageTemplate": "cover",
|
"coverImageTemplate": "cover",
|
||||||
"saveArtworkArtist": false,
|
"saveArtworkArtist": false,
|
||||||
"artistImageTemplate": "folder",
|
"artistImageTemplate": "folder",
|
||||||
"PNGcovers": false,
|
"PNGcovers": false,
|
||||||
"jpegImageQuality": 80,
|
"jpegImageQuality": 80,
|
||||||
"dateFormat": "Y-M-D",
|
"dateFormat": "Y-M-D",
|
||||||
"removeAlbumVersion": false,
|
"removeAlbumVersion": false,
|
||||||
"featuredToTitle": "0",
|
"featuredToTitle": "0",
|
||||||
"titleCasing": "nothing",
|
"titleCasing": "nothing",
|
||||||
"artistCasing": "nothing",
|
"artistCasing": "nothing",
|
||||||
"executeCommand": "",
|
"executeCommand": "",
|
||||||
"tags": {
|
"tags": {
|
||||||
"title": true,
|
"title": true,
|
||||||
"artist": true,
|
"artist": true,
|
||||||
"album": true,
|
"album": true,
|
||||||
"cover": true,
|
"cover": true,
|
||||||
"trackNumber": true,
|
"trackNumber": true,
|
||||||
"trackTotal": false,
|
"trackTotal": false,
|
||||||
"discNumber": true,
|
"discNumber": true,
|
||||||
"discTotal": false,
|
"discTotal": false,
|
||||||
"albumArtist": true,
|
"albumArtist": true,
|
||||||
"genre": true,
|
"genre": true,
|
||||||
"year": true,
|
"year": true,
|
||||||
"date": true,
|
"date": true,
|
||||||
"explicit": false,
|
"explicit": false,
|
||||||
"isrc": true,
|
"isrc": true,
|
||||||
"length": true,
|
"length": true,
|
||||||
"barcode": true,
|
"barcode": true,
|
||||||
"bpm": true,
|
"bpm": true,
|
||||||
"replayGain": false,
|
"replayGain": false,
|
||||||
"label": true,
|
"label": true,
|
||||||
"lyrics": false,
|
"lyrics": false,
|
||||||
"copyright": false,
|
"copyright": false,
|
||||||
"composer": false,
|
"composer": false,
|
||||||
"involvedPeople": false,
|
"involvedPeople": false,
|
||||||
"savePlaylistAsCompilation": false,
|
"savePlaylistAsCompilation": false,
|
||||||
"useNullSeparator": false,
|
"useNullSeparator": false,
|
||||||
"saveID3v1": true,
|
"saveID3v1": true,
|
||||||
"multitagSeparator": "default"
|
"multitagSeparator": "default"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,5 @@
|
||||||
from deemix.utils.misc import getIDFromLink, getTypeFromLink, getBitrateInt
|
|
||||||
from concurrent.futures import ProcessPoolExecutor
|
|
||||||
from deemix.app.downloader import download
|
from deemix.app.downloader import download
|
||||||
|
from deemix.utils.misc import getIDFromLink, getTypeFromLink, getBitrateInt
|
||||||
|
|
||||||
queue = []
|
queue = []
|
||||||
queueList = {}
|
queueList = {}
|
||||||
|
@ -26,244 +25,264 @@ if its an album/playlist
|
||||||
collection
|
collection
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def generateQueueItem(dz, sp, url, settings, bitrate=None, albumAPI=None, interface=None):
|
def generateQueueItem(dz, sp, url, settings, bitrate=None, albumAPI=None, interface=None):
|
||||||
forcedBitrate = getBitrateInt(bitrate)
|
forcedBitrate = getBitrateInt(bitrate)
|
||||||
bitrate = forcedBitrate if forcedBitrate else settings['maxBitrate']
|
bitrate = forcedBitrate if forcedBitrate else settings['maxBitrate']
|
||||||
type = getTypeFromLink(url)
|
type = getTypeFromLink(url)
|
||||||
id = getIDFromLink(url, type)
|
id = getIDFromLink(url, type)
|
||||||
result = {}
|
result = {}
|
||||||
if type == None or id == None:
|
if type == None or id == None:
|
||||||
print("URL not recognized")
|
print("URL not recognized")
|
||||||
result['error'] = "URL not recognized"
|
result['error'] = "URL not recognized"
|
||||||
elif type == "track":
|
elif type == "track":
|
||||||
trackAPI = dz.get_track_gw(id)
|
trackAPI = dz.get_track_gw(id)
|
||||||
if albumAPI:
|
if albumAPI:
|
||||||
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
|
||||||
|
|
||||||
result['title'] = trackAPI['SNG_TITLE']
|
result['title'] = trackAPI['SNG_TITLE']
|
||||||
if 'VERSION' in trackAPI and trackAPI['VERSION']:
|
if 'VERSION' in trackAPI and trackAPI['VERSION']:
|
||||||
result['title'] += " " + trackAPI['VERSION']
|
result['title'] += " " + trackAPI['VERSION']
|
||||||
result['artist'] = trackAPI['ART_NAME']
|
result['artist'] = trackAPI['ART_NAME']
|
||||||
result['cover'] = f"https://e-cdns-images.dzcdn.net/images/cover/{trackAPI['ALB_PICTURE']}/75x75-000000-80-0-0.jpg"
|
result[
|
||||||
result['size'] = 1
|
'cover'] = f"https://e-cdns-images.dzcdn.net/images/cover/{trackAPI['ALB_PICTURE']}/75x75-000000-80-0-0.jpg"
|
||||||
result['downloaded'] = 0
|
result['size'] = 1
|
||||||
result['failed'] = 0
|
result['downloaded'] = 0
|
||||||
result['progress'] = 0
|
result['failed'] = 0
|
||||||
result['type'] = 'track'
|
result['progress'] = 0
|
||||||
result['id'] = id
|
result['type'] = 'track'
|
||||||
result['bitrate'] = bitrate
|
result['id'] = id
|
||||||
result['uuid'] = f"{result['type']}_{id}_{bitrate}"
|
result['bitrate'] = bitrate
|
||||||
result['settings'] = settings or {}
|
result['uuid'] = f"{result['type']}_{id}_{bitrate}"
|
||||||
result['single'] = trackAPI
|
result['settings'] = settings or {}
|
||||||
|
result['single'] = trackAPI
|
||||||
|
|
||||||
elif type == "album":
|
elif type == "album":
|
||||||
albumAPI = dz.get_album(id)
|
albumAPI = dz.get_album(id)
|
||||||
albumAPI_gw = dz.get_album_gw(id)
|
albumAPI_gw = dz.get_album_gw(id)
|
||||||
albumAPI['nb_disk'] = albumAPI_gw['NUMBER_DISK']
|
albumAPI['nb_disk'] = albumAPI_gw['NUMBER_DISK']
|
||||||
albumAPI['copyright'] = albumAPI_gw['COPYRIGHT']
|
albumAPI['copyright'] = albumAPI_gw['COPYRIGHT']
|
||||||
if albumAPI['nb_tracks'] == 1:
|
if albumAPI['nb_tracks'] == 1:
|
||||||
return generateQueueItem(dz, sp, f"https://www.deezer.com/track/{albumAPI['tracks']['data'][0]['id']}", settings, bitrate, albumAPI)
|
return generateQueueItem(dz, sp, f"https://www.deezer.com/track/{albumAPI['tracks']['data'][0]['id']}",
|
||||||
tracksArray = dz.get_album_tracks_gw(id)
|
settings, bitrate, albumAPI)
|
||||||
|
tracksArray = dz.get_album_tracks_gw(id)
|
||||||
|
|
||||||
result['title'] = albumAPI['title']
|
result['title'] = albumAPI['title']
|
||||||
result['artist'] = albumAPI['artist']['name']
|
result['artist'] = albumAPI['artist']['name']
|
||||||
result['cover'] = albumAPI['cover_small'][:-24]+'/75x75-000000-80-0-0.jpg'
|
result['cover'] = albumAPI['cover_small'][:-24] + '/75x75-000000-80-0-0.jpg'
|
||||||
result['size'] = albumAPI['nb_tracks']
|
result['size'] = albumAPI['nb_tracks']
|
||||||
result['downloaded'] = 0
|
result['downloaded'] = 0
|
||||||
result['failed'] = 0
|
result['failed'] = 0
|
||||||
result['progress'] = 0
|
result['progress'] = 0
|
||||||
result['type'] = 'album'
|
result['type'] = 'album'
|
||||||
result['id'] = id
|
result['id'] = id
|
||||||
result['bitrate'] = bitrate
|
result['bitrate'] = bitrate
|
||||||
result['uuid'] = f"{result['type']}_{id}_{bitrate}"
|
result['uuid'] = f"{result['type']}_{id}_{bitrate}"
|
||||||
result['settings'] = settings or {}
|
result['settings'] = settings or {}
|
||||||
totalSize = len(tracksArray)
|
totalSize = len(tracksArray)
|
||||||
result['collection'] = []
|
result['collection'] = []
|
||||||
for pos, trackAPI in enumerate(tracksArray, start=1):
|
for pos, trackAPI in enumerate(tracksArray, start=1):
|
||||||
trackAPI['_EXTRA_ALBUM'] = albumAPI
|
trackAPI['_EXTRA_ALBUM'] = albumAPI
|
||||||
trackAPI['POSITION'] = pos
|
trackAPI['POSITION'] = pos
|
||||||
trackAPI['SIZE'] = totalSize
|
trackAPI['SIZE'] = totalSize
|
||||||
trackAPI['FILENAME_TEMPLATE'] = settings['albumTracknameTemplate']
|
trackAPI['FILENAME_TEMPLATE'] = settings['albumTracknameTemplate']
|
||||||
result['collection'].append(trackAPI)
|
result['collection'].append(trackAPI)
|
||||||
|
|
||||||
elif type == "playlist":
|
elif type == "playlist":
|
||||||
playlistAPI = dz.get_playlist(id)
|
playlistAPI = dz.get_playlist(id)
|
||||||
playlistTracksAPI = dz.get_playlist_tracks_gw(id)
|
playlistTracksAPI = dz.get_playlist_tracks_gw(id)
|
||||||
playlistAPI['various_artist'] = dz.get_artist(5080)
|
playlistAPI['various_artist'] = dz.get_artist(5080)
|
||||||
|
|
||||||
result['title'] = playlistAPI['title']
|
result['title'] = playlistAPI['title']
|
||||||
result['artist'] = playlistAPI['creator']['name']
|
result['artist'] = playlistAPI['creator']['name']
|
||||||
result['cover'] = playlistAPI['picture_small'][:-24]+'/75x75-000000-80-0-0.jpg'
|
result['cover'] = playlistAPI['picture_small'][:-24] + '/75x75-000000-80-0-0.jpg'
|
||||||
result['size'] = playlistAPI['nb_tracks']
|
result['size'] = playlistAPI['nb_tracks']
|
||||||
result['downloaded'] = 0
|
result['downloaded'] = 0
|
||||||
result['failed'] = 0
|
result['failed'] = 0
|
||||||
result['progress'] = 0
|
result['progress'] = 0
|
||||||
result['type'] = 'playlist'
|
result['type'] = 'playlist'
|
||||||
result['id'] = id
|
result['id'] = id
|
||||||
result['bitrate'] = bitrate
|
result['bitrate'] = bitrate
|
||||||
result['uuid'] = f"{result['type']}_{id}_{bitrate}"
|
result['uuid'] = f"{result['type']}_{id}_{bitrate}"
|
||||||
result['settings'] = settings or {}
|
result['settings'] = settings or {}
|
||||||
totalSize = len(playlistTracksAPI)
|
totalSize = len(playlistTracksAPI)
|
||||||
result['collection'] = []
|
result['collection'] = []
|
||||||
for pos, trackAPI in enumerate(playlistTracksAPI, start=1):
|
for pos, trackAPI in enumerate(playlistTracksAPI, start=1):
|
||||||
trackAPI['_EXTRA_PLAYLIST'] = playlistAPI
|
trackAPI['_EXTRA_PLAYLIST'] = playlistAPI
|
||||||
trackAPI['POSITION'] = pos
|
trackAPI['POSITION'] = pos
|
||||||
trackAPI['SIZE'] = totalSize
|
trackAPI['SIZE'] = totalSize
|
||||||
trackAPI['FILENAME_TEMPLATE'] = settings['playlistTracknameTemplate']
|
trackAPI['FILENAME_TEMPLATE'] = settings['playlistTracknameTemplate']
|
||||||
result['collection'].append(trackAPI)
|
result['collection'].append(trackAPI)
|
||||||
|
|
||||||
|
elif type == "artist":
|
||||||
|
artistAPI = dz.get_artist(id)
|
||||||
|
if interface:
|
||||||
|
interface.send("toast",
|
||||||
|
{'msg': f"Adding {artistAPI['name']} albums to queue", 'icon': 'loading', 'dismiss': False,
|
||||||
|
'id': 'artist_' + str(artistAPI['id'])})
|
||||||
|
artistAPITracks = dz.get_artist_albums(id)
|
||||||
|
albumList = []
|
||||||
|
for album in artistAPITracks['data']:
|
||||||
|
albumList.append(generateQueueItem(dz, sp, album['link'], settings, bitrate))
|
||||||
|
if interface:
|
||||||
|
interface.send("toast",
|
||||||
|
{'msg': f"Added {artistAPI['name']} albums to queue", 'icon': 'done', 'dismiss': True,
|
||||||
|
'id': 'artist_' + str(artistAPI['id'])})
|
||||||
|
return albumList
|
||||||
|
elif type == "spotifytrack":
|
||||||
|
result = {}
|
||||||
|
if not sp.spotifyEnabled:
|
||||||
|
print("Spotify Features is not setted up correctly.")
|
||||||
|
result['error'] = "Spotify Features is not setted up correctly."
|
||||||
|
return result
|
||||||
|
track_id = sp.get_trackid_spotify(dz, id, settings['fallbackSearch'])
|
||||||
|
if track_id != 0:
|
||||||
|
return generateQueueItem(dz, sp, f'https://www.deezer.com/track/{track_id}', settings, bitrate)
|
||||||
|
else:
|
||||||
|
print("Track not found on deezer!")
|
||||||
|
result['error'] = "Track not found on deezer!"
|
||||||
|
elif type == "spotifyalbum":
|
||||||
|
result = {}
|
||||||
|
if not sp.spotifyEnabled:
|
||||||
|
print("Spotify Features is not setted up correctly.")
|
||||||
|
result['error'] = "Spotify Features is not setted up correctly."
|
||||||
|
return result
|
||||||
|
album_id = sp.get_albumid_spotify(dz, id)
|
||||||
|
if album_id != 0:
|
||||||
|
return generateQueueItem(dz, sp, f'https://www.deezer.com/album/{album_id}', settings, bitrate)
|
||||||
|
else:
|
||||||
|
print("Album not found on deezer!")
|
||||||
|
result['error'] = "Album not found on deezer!"
|
||||||
|
elif type == "spotifyplaylist":
|
||||||
|
result = {}
|
||||||
|
if not sp.spotifyEnabled:
|
||||||
|
print("Spotify Features is not setted up correctly.")
|
||||||
|
result['error'] = "Spotify Features is not setted up correctly."
|
||||||
|
return result
|
||||||
|
if interface:
|
||||||
|
interface.send("toast",
|
||||||
|
{'msg': f"Converting spotify tracks to deezer tracks", 'icon': 'loading', 'dismiss': False,
|
||||||
|
'id': 'spotifyplaylist_' + str(id)})
|
||||||
|
playlist = sp.convert_spotify_playlist(dz, id, settings)
|
||||||
|
playlist['bitrate'] = bitrate
|
||||||
|
playlist['uuid'] = f"{playlist['type']}_{id}_{bitrate}"
|
||||||
|
result = playlist
|
||||||
|
if interface:
|
||||||
|
interface.send("toast", {'msg': f"Spotify playlist converted", 'icon': 'done', 'dismiss': True,
|
||||||
|
'id': 'spotifyplaylist_' + str(id)})
|
||||||
|
else:
|
||||||
|
print("URL not supported yet")
|
||||||
|
result['error'] = "URL not supported yet"
|
||||||
|
return result
|
||||||
|
|
||||||
elif type == "artist":
|
|
||||||
artistAPI = dz.get_artist(id)
|
|
||||||
if interface:
|
|
||||||
interface.send("toast", {'msg': f"Adding {artistAPI['name']} albums to queue", 'icon': 'loading', 'dismiss': False, 'id': 'artist_'+str(artistAPI['id'])})
|
|
||||||
artistAPITracks = dz.get_artist_albums(id)
|
|
||||||
albumList = []
|
|
||||||
for album in artistAPITracks['data']:
|
|
||||||
albumList.append(generateQueueItem(dz, sp, album['link'], settings, bitrate))
|
|
||||||
if interface:
|
|
||||||
interface.send("toast", {'msg': f"Added {artistAPI['name']} albums to queue", 'icon': 'done', 'dismiss': True, 'id': 'artist_'+str(artistAPI['id'])})
|
|
||||||
return albumList
|
|
||||||
elif type == "spotifytrack":
|
|
||||||
result = {}
|
|
||||||
if not sp.spotifyEnabled:
|
|
||||||
print("Spotify Features is not setted up correctly.")
|
|
||||||
result['error'] = "Spotify Features is not setted up correctly."
|
|
||||||
return result
|
|
||||||
track_id = sp.get_trackid_spotify(dz, id, settings['fallbackSearch'])
|
|
||||||
if track_id != 0:
|
|
||||||
return generateQueueItem(dz, sp, f'https://www.deezer.com/track/{track_id}', settings, bitrate)
|
|
||||||
else:
|
|
||||||
print("Track not found on deezer!")
|
|
||||||
result['error'] = "Track not found on deezer!"
|
|
||||||
elif type == "spotifyalbum":
|
|
||||||
result = {}
|
|
||||||
if not sp.spotifyEnabled:
|
|
||||||
print("Spotify Features is not setted up correctly.")
|
|
||||||
result['error'] = "Spotify Features is not setted up correctly."
|
|
||||||
return result
|
|
||||||
album_id = sp.get_albumid_spotify(dz, id)
|
|
||||||
if album_id != 0:
|
|
||||||
return generateQueueItem(dz, sp, f'https://www.deezer.com/album/{album_id}', settings, bitrate)
|
|
||||||
else:
|
|
||||||
print("Album not found on deezer!")
|
|
||||||
result['error'] = "Album not found on deezer!"
|
|
||||||
elif type == "spotifyplaylist":
|
|
||||||
result = {}
|
|
||||||
if not sp.spotifyEnabled:
|
|
||||||
print("Spotify Features is not setted up correctly.")
|
|
||||||
result['error'] = "Spotify Features is not setted up correctly."
|
|
||||||
return result
|
|
||||||
if interface:
|
|
||||||
interface.send("toast", {'msg': f"Converting spotify tracks to deezer tracks", 'icon': 'loading', 'dismiss': False, 'id': 'spotifyplaylist_'+str(id)})
|
|
||||||
playlist = sp.convert_spotify_playlist(dz, id, settings)
|
|
||||||
playlist['bitrate'] = bitrate
|
|
||||||
playlist['uuid'] = f"{playlist['type']}_{id}_{bitrate}"
|
|
||||||
result = playlist
|
|
||||||
if interface:
|
|
||||||
interface.send("toast", {'msg': f"Spotify playlist converted", 'icon': 'done', 'dismiss': True, 'id': 'spotifyplaylist_'+str(id)})
|
|
||||||
else:
|
|
||||||
print("URL not supported yet")
|
|
||||||
result['error'] = "URL not supported yet"
|
|
||||||
return result
|
|
||||||
|
|
||||||
def addToQueue(dz, sp, url, settings, bitrate=None, interface=None):
|
def addToQueue(dz, sp, url, settings, bitrate=None, interface=None):
|
||||||
global currentItem, queueList, queue
|
global currentItem, queueList, queue
|
||||||
if not dz.logged_in:
|
if not dz.logged_in:
|
||||||
return "Not logged in"
|
return "Not logged in"
|
||||||
queueItem = generateQueueItem(dz, sp, url, settings, bitrate, interface=interface)
|
queueItem = generateQueueItem(dz, sp, url, settings, bitrate, interface=interface)
|
||||||
if type(queueItem) is list:
|
if type(queueItem) is list:
|
||||||
for x in queueItem:
|
for x in queueItem:
|
||||||
if 'error' in x:
|
if 'error' in x:
|
||||||
continue
|
continue
|
||||||
if x['uuid'] in list(queueList.keys()):
|
if x['uuid'] in list(queueList.keys()):
|
||||||
print("Already in queue!")
|
print("Already in queue!")
|
||||||
continue
|
continue
|
||||||
if interface:
|
if interface:
|
||||||
interface.send("addedToQueue", x)
|
interface.send("addedToQueue", x)
|
||||||
queue.append(x['uuid'])
|
queue.append(x['uuid'])
|
||||||
queueList[x['uuid']] = x
|
queueList[x['uuid']] = x
|
||||||
else:
|
else:
|
||||||
if 'error' in queueItem:
|
if 'error' in queueItem:
|
||||||
if interface:
|
if interface:
|
||||||
interface.send("toast", {'msg': queueItem['error'], 'icon': 'error'})
|
interface.send("toast", {'msg': queueItem['error'], 'icon': 'error'})
|
||||||
return False
|
return False
|
||||||
if queueItem['uuid'] in list(queueList.keys()):
|
if queueItem['uuid'] in list(queueList.keys()):
|
||||||
print("Already in queue!")
|
print("Already in queue!")
|
||||||
if interface:
|
if interface:
|
||||||
interface.send("toast", {'msg': f"{queueItem['title']} is already in queue!", 'icon': 'playlist_add_check'})
|
interface.send("toast",
|
||||||
return False
|
{'msg': f"{queueItem['title']} is already in queue!", 'icon': 'playlist_add_check'})
|
||||||
if interface:
|
return False
|
||||||
interface.send("addedToQueue", queueItem)
|
if interface:
|
||||||
interface.send("toast", {'msg': f"{queueItem['title']} added to queue", 'icon': 'playlist_add'})
|
interface.send("addedToQueue", queueItem)
|
||||||
queue.append(queueItem['uuid'])
|
interface.send("toast", {'msg': f"{queueItem['title']} added to queue", 'icon': 'playlist_add'})
|
||||||
queueList[queueItem['uuid']] = queueItem
|
queue.append(queueItem['uuid'])
|
||||||
nextItem(dz, interface)
|
queueList[queueItem['uuid']] = queueItem
|
||||||
return True
|
nextItem(dz, interface)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def nextItem(dz, interface=None):
|
def nextItem(dz, interface=None):
|
||||||
global currentItem, queueList, queue
|
global currentItem, queueList, queue
|
||||||
if currentItem != "":
|
if currentItem != "":
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
if len(queue)>0:
|
if len(queue) > 0:
|
||||||
currentItem = queue.pop(0)
|
currentItem = queue.pop(0)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
if interface:
|
if interface:
|
||||||
interface.send("startDownload", currentItem)
|
interface.send("startDownload", currentItem)
|
||||||
result = download(dz, queueList[currentItem], interface)
|
result = download(dz, queueList[currentItem], interface)
|
||||||
callbackQueueDone(result)
|
callbackQueueDone(result)
|
||||||
|
|
||||||
|
|
||||||
def callbackQueueDone(result):
|
def callbackQueueDone(result):
|
||||||
global currentItem, queueList, queueComplete
|
global currentItem, queueList, queueComplete
|
||||||
if 'cancel' in queueList[currentItem]:
|
if 'cancel' in queueList[currentItem]:
|
||||||
del queueList[currentItem]
|
del queueList[currentItem]
|
||||||
else:
|
else:
|
||||||
queueComplete.append(currentItem)
|
queueComplete.append(currentItem)
|
||||||
currentItem = ""
|
currentItem = ""
|
||||||
nextItem(result['dz'], result['interface'])
|
nextItem(result['dz'], result['interface'])
|
||||||
|
|
||||||
|
|
||||||
def getQueue():
|
def getQueue():
|
||||||
global currentItem, queueList, queue, queueComplete
|
global currentItem, queueList, queue, queueComplete
|
||||||
return (queue, queueComplete, queueList, currentItem)
|
return (queue, queueComplete, queueList, currentItem)
|
||||||
|
|
||||||
|
|
||||||
def removeFromQueue(uuid, interface=None):
|
def removeFromQueue(uuid, interface=None):
|
||||||
global currentItem, queueList, queue, queueComplete
|
global currentItem, queueList, queue, queueComplete
|
||||||
if uuid == currentItem:
|
if uuid == currentItem:
|
||||||
if interface:
|
if interface:
|
||||||
interface.send('toast', {'msg': "Cancelling current item.", 'icon':'loading', 'dismiss': False, 'id':'cancelling_'+uuid})
|
interface.send('toast', {'msg': "Cancelling current item.", 'icon': 'loading', 'dismiss': False,
|
||||||
queueList[uuid]['cancel'] = True
|
'id': 'cancelling_' + uuid})
|
||||||
elif uuid in queue:
|
queueList[uuid]['cancel'] = True
|
||||||
queue.remove(uuid)
|
elif uuid in queue:
|
||||||
del queueList[uuid]
|
queue.remove(uuid)
|
||||||
if interface:
|
del queueList[uuid]
|
||||||
interface.send("removedFromQueue", uuid)
|
if interface:
|
||||||
elif uuid in queueComplete:
|
interface.send("removedFromQueue", uuid)
|
||||||
queueComplete.remove(uuid)
|
elif uuid in queueComplete:
|
||||||
del queueList[uuid]
|
queueComplete.remove(uuid)
|
||||||
if interface:
|
del queueList[uuid]
|
||||||
interface.send("removedFromQueue", uuid)
|
if interface:
|
||||||
|
interface.send("removedFromQueue", uuid)
|
||||||
|
|
||||||
|
|
||||||
def cancelAllDownloads(interface=None):
|
def cancelAllDownloads(interface=None):
|
||||||
global currentItem, queueList, queue, queueComplete
|
global currentItem, queueList, queue, queueComplete
|
||||||
queue = []
|
queue = []
|
||||||
queueComplete = []
|
queueComplete = []
|
||||||
if currentItem != "":
|
if currentItem != "":
|
||||||
if interface:
|
if interface:
|
||||||
interface.send('toast', {'msg': "Cancelling current item.", 'icon':'loading', 'dismiss': False, 'id':'cancelling_'+currentItem})
|
interface.send('toast', {'msg': "Cancelling current item.", 'icon': 'loading', 'dismiss': False,
|
||||||
queueList[currentItem]['cancel'] = True
|
'id': 'cancelling_' + currentItem})
|
||||||
for uuid in list(queueList.keys()):
|
queueList[currentItem]['cancel'] = True
|
||||||
if uuid != currentItem:
|
for uuid in list(queueList.keys()):
|
||||||
del queueList[uuid]
|
if uuid != currentItem:
|
||||||
if interface:
|
del queueList[uuid]
|
||||||
interface.send("removedAllDownloads", currentItem)
|
if interface:
|
||||||
|
interface.send("removedAllDownloads", currentItem)
|
||||||
|
|
||||||
|
|
||||||
def removeFinishedDownloads(interface=None):
|
def removeFinishedDownloads(interface=None):
|
||||||
global queueList, queueComplete
|
global queueList, queueComplete
|
||||||
for uuid in queueComplete:
|
for uuid in queueComplete:
|
||||||
del queueList[uuid]
|
del queueList[uuid]
|
||||||
queueComplete = []
|
queueComplete = []
|
||||||
if interface:
|
if interface:
|
||||||
interface.send("removedFinishedDownloads")
|
interface.send("removedFinishedDownloads")
|
||||||
|
|
|
@ -1,57 +1,61 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import os.path as path
|
|
||||||
from os import mkdir, rmdir
|
|
||||||
import json
|
import json
|
||||||
|
import os.path as path
|
||||||
|
from os import mkdir
|
||||||
|
|
||||||
import deemix.utils.localpaths as localpaths
|
import deemix.utils.localpaths as localpaths
|
||||||
|
|
||||||
settings = {}
|
settings = {}
|
||||||
defaultSettings = {}
|
defaultSettings = {}
|
||||||
|
|
||||||
|
|
||||||
def initSettings():
|
def initSettings():
|
||||||
global settings
|
global settings
|
||||||
global defaultSettings
|
global defaultSettings
|
||||||
currentFolder = path.abspath(path.dirname(__file__))
|
currentFolder = path.abspath(path.dirname(__file__))
|
||||||
configFolder = localpaths.getConfigFolder()
|
configFolder = localpaths.getConfigFolder()
|
||||||
if not path.isdir(configFolder):
|
if not path.isdir(configFolder):
|
||||||
mkdir(configFolder)
|
mkdir(configFolder)
|
||||||
with open(path.join(currentFolder, 'default.json'), 'r') as d:
|
with open(path.join(currentFolder, 'default.json'), 'r') as d:
|
||||||
defaultSettings = json.load(d)
|
defaultSettings = json.load(d)
|
||||||
if not path.isfile(path.join(configFolder, 'config.json')):
|
if not path.isfile(path.join(configFolder, 'config.json')):
|
||||||
with open(path.join(configFolder, 'config.json'), 'w') as f:
|
with open(path.join(configFolder, 'config.json'), 'w') as f:
|
||||||
json.dump(defaultSettings, f, indent=2)
|
json.dump(defaultSettings, f, indent=2)
|
||||||
with open(path.join(configFolder, 'config.json'), 'r') as configFile:
|
with open(path.join(configFolder, 'config.json'), 'r') as configFile:
|
||||||
settings = json.load(configFile)
|
settings = json.load(configFile)
|
||||||
settingsCheck()
|
settingsCheck()
|
||||||
if settings['downloadLocation'] == "":
|
if settings['downloadLocation'] == "":
|
||||||
settings['downloadLocation'] = path.join(localpaths.getHomeFolder(), 'deemix Music')
|
settings['downloadLocation'] = path.join(localpaths.getHomeFolder(), 'deemix Music')
|
||||||
saveSettings(settings)
|
saveSettings(settings)
|
||||||
if not path.isdir(settings['downloadLocation']):
|
if not path.isdir(settings['downloadLocation']):
|
||||||
mkdir(settings['downloadLocation'])
|
mkdir(settings['downloadLocation'])
|
||||||
return settings
|
return settings
|
||||||
|
|
||||||
|
|
||||||
def getSettings():
|
def getSettings():
|
||||||
global settings
|
global settings
|
||||||
return settings
|
return settings
|
||||||
|
|
||||||
|
|
||||||
def saveSettings(newSettings):
|
def saveSettings(newSettings):
|
||||||
global settings
|
global settings
|
||||||
settings = newSettings
|
settings = newSettings
|
||||||
with open(path.join(localpaths.getConfigFolder(), 'config.json'), 'w') as configFile:
|
with open(path.join(localpaths.getConfigFolder(), 'config.json'), 'w') as configFile:
|
||||||
json.dump(settings, configFile, indent=2)
|
json.dump(settings, configFile, indent=2)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def settingsCheck():
|
def settingsCheck():
|
||||||
global settings
|
global settings
|
||||||
global defaultSettings
|
global defaultSettings
|
||||||
changes = 0
|
changes = 0
|
||||||
for x in defaultSettings:
|
for x in defaultSettings:
|
||||||
if not x in settings or type(settings[x]) != type(defaultSettings[x]):
|
if not x in settings or type(settings[x]) != type(defaultSettings[x]):
|
||||||
settings[x] = defaultSettings[x]
|
settings[x] = defaultSettings[x]
|
||||||
changes+=1
|
changes += 1
|
||||||
for x in defaultSettings['tags']:
|
for x in defaultSettings['tags']:
|
||||||
if not x in settings['tags'] or type(settings['tags'][x]) != type(defaultSettings['tags'][x]):
|
if not x in settings['tags'] or type(settings['tags'][x]) != type(defaultSettings['tags'][x]):
|
||||||
settings['tags'][x] = defaultSettings['tags'][x]
|
settings['tags'][x] = defaultSettings['tags'][x]
|
||||||
changes+=1
|
changes += 1
|
||||||
if changes > 0:
|
if changes > 0:
|
||||||
saveSettings(settings)
|
saveSettings(settings)
|
||||||
|
|
|
@ -1,172 +1,179 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import os.path as path
|
|
||||||
from os import mkdir, rmdir
|
|
||||||
import json
|
import json
|
||||||
|
import os.path as path
|
||||||
import deemix.utils.localpaths as localpaths
|
from os import mkdir
|
||||||
|
|
||||||
import spotipy
|
import spotipy
|
||||||
from spotipy.oauth2 import SpotifyClientCredentials
|
from spotipy.oauth2 import SpotifyClientCredentials
|
||||||
|
|
||||||
|
import deemix.utils.localpaths as localpaths
|
||||||
|
|
||||||
|
|
||||||
class SpotifyHelper:
|
class SpotifyHelper:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.credentials = {}
|
self.credentials = {}
|
||||||
self.spotifyEnabled = False
|
self.spotifyEnabled = False
|
||||||
self.sp = None
|
self.sp = None
|
||||||
self.initCredentials()
|
self.initCredentials()
|
||||||
|
|
||||||
def initCredentials(self):
|
def initCredentials(self):
|
||||||
configFolder = localpaths.getConfigFolder()
|
configFolder = localpaths.getConfigFolder()
|
||||||
if not path.isdir(configFolder):
|
if not path.isdir(configFolder):
|
||||||
mkdir(configFolder)
|
mkdir(configFolder)
|
||||||
if not path.isfile(path.join(configFolder, 'authCredentials.json')):
|
if not path.isfile(path.join(configFolder, 'authCredentials.json')):
|
||||||
with open(path.join(configFolder, 'authCredentials.json'), 'w') as f:
|
with open(path.join(configFolder, 'authCredentials.json'), 'w') as f:
|
||||||
json.dump({'clientId': "", 'clientSecret': ""}, f, indent=2)
|
json.dump({'clientId': "", 'clientSecret': ""}, f, indent=2)
|
||||||
with open(path.join(configFolder, 'authCredentials.json'), 'r') as credentialsFile:
|
with open(path.join(configFolder, 'authCredentials.json'), 'r') as credentialsFile:
|
||||||
self.credentials = json.load(credentialsFile)
|
self.credentials = json.load(credentialsFile)
|
||||||
self.checkCredentials()
|
self.checkCredentials()
|
||||||
|
|
||||||
def checkCredentials(self):
|
def checkCredentials(self):
|
||||||
if self.credentials['clientId'] == "" or self.credentials['clientSecret'] == "":
|
if self.credentials['clientId'] == "" or self.credentials['clientSecret'] == "":
|
||||||
spotifyEnabled = False
|
spotifyEnabled = False
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
self.createSpotifyConnection()
|
self.createSpotifyConnection()
|
||||||
self.sp.user_playlists('spotify')
|
self.sp.user_playlists('spotify')
|
||||||
self.spotifyEnabled = True
|
self.spotifyEnabled = True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.spotifyEnabled = False
|
self.spotifyEnabled = False
|
||||||
return self.spotifyEnabled
|
return self.spotifyEnabled
|
||||||
|
|
||||||
def getCredentials(self):
|
def getCredentials(self):
|
||||||
return self.credentials
|
return self.credentials
|
||||||
|
|
||||||
def setCredentials(self, spotifyCredentials):
|
def setCredentials(self, spotifyCredentials):
|
||||||
configFolder = localpaths.getConfigFolder()
|
configFolder = localpaths.getConfigFolder()
|
||||||
with open(path.join(configFolder, 'authCredentials.json'), 'w') as f:
|
with open(path.join(configFolder, 'authCredentials.json'), 'w') as f:
|
||||||
json.dump(spotifyCredentials, f, indent=2)
|
json.dump(spotifyCredentials, f, indent=2)
|
||||||
self.credentials = spotifyCredentials
|
self.credentials = spotifyCredentials
|
||||||
self.checkCredentials()
|
self.checkCredentials()
|
||||||
|
|
||||||
def createSpotifyConnection(self):
|
def createSpotifyConnection(self):
|
||||||
client_credentials_manager = SpotifyClientCredentials(client_id=self.credentials['clientId'], client_secret=self.credentials['clientSecret'])
|
client_credentials_manager = SpotifyClientCredentials(client_id=self.credentials['clientId'],
|
||||||
self.sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
client_secret=self.credentials['clientSecret'])
|
||||||
|
self.sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)
|
||||||
|
|
||||||
def _convert_playlist_structure(self, spotify_obj):
|
def _convert_playlist_structure(self, spotify_obj):
|
||||||
if len(spotify_obj['images']):
|
if len(spotify_obj['images']):
|
||||||
url = spotify_obj['images'][0]['url']
|
url = spotify_obj['images'][0]['url']
|
||||||
else:
|
else:
|
||||||
url = "https://e-cdns-images.dzcdn.net/images/cover/d41d8cd98f00b204e9800998ecf8427e/75x75-000000-80-0-0.jpg"
|
url = "https://e-cdns-images.dzcdn.net/images/cover/d41d8cd98f00b204e9800998ecf8427e/75x75-000000-80-0-0.jpg"
|
||||||
deezer_obj = {
|
deezer_obj = {
|
||||||
'checksum': spotify_obj['snapshot_id'],
|
'checksum': spotify_obj['snapshot_id'],
|
||||||
'collaborative': spotify_obj['collaborative'],
|
'collaborative': spotify_obj['collaborative'],
|
||||||
'creation_date': "????-00-00",
|
'creation_date': "????-00-00",
|
||||||
'creator': {'id': spotify_obj['owner']['id'], 'name': spotify_obj['owner']['display_name'], 'tracklist': spotify_obj['owner']['href'], 'type': "user"},
|
'creator': {'id': spotify_obj['owner']['id'], 'name': spotify_obj['owner']['display_name'],
|
||||||
'description': spotify_obj['description'],
|
'tracklist': spotify_obj['owner']['href'], 'type': "user"},
|
||||||
'duration': 0,
|
'description': spotify_obj['description'],
|
||||||
'fans': spotify_obj['followers']['total'],
|
'duration': 0,
|
||||||
'id': spotify_obj['id'],
|
'fans': spotify_obj['followers']['total'],
|
||||||
'is_loved_track': False,
|
'id': spotify_obj['id'],
|
||||||
'link': spotify_obj['external_urls']['spotify'],
|
'is_loved_track': False,
|
||||||
'nb_tracks': spotify_obj['tracks']['total'],
|
'link': spotify_obj['external_urls']['spotify'],
|
||||||
'picture': url,
|
'nb_tracks': spotify_obj['tracks']['total'],
|
||||||
'picture_big': url,
|
'picture': url,
|
||||||
'picture_medium': url,
|
'picture_big': url,
|
||||||
'picture_small': url,
|
'picture_medium': url,
|
||||||
'picture_xl': url,
|
'picture_small': url,
|
||||||
'public': spotify_obj['public'],
|
'picture_xl': url,
|
||||||
'share': spotify_obj['external_urls']['spotify'],
|
'public': spotify_obj['public'],
|
||||||
'title': spotify_obj['name'],
|
'share': spotify_obj['external_urls']['spotify'],
|
||||||
'tracklist': spotify_obj['tracks']['href'],
|
'title': spotify_obj['name'],
|
||||||
'type': "playlist"
|
'tracklist': spotify_obj['tracks']['href'],
|
||||||
}
|
'type': "playlist"
|
||||||
return deezer_obj
|
}
|
||||||
|
return deezer_obj
|
||||||
|
|
||||||
def get_trackid_spotify(self, dz, track_id, fallbackSearch, spotifyTrack=None):
|
def get_trackid_spotify(self, dz, track_id, fallbackSearch, spotifyTrack=None):
|
||||||
if not self.spotifyEnabled:
|
if not self.spotifyEnabled:
|
||||||
raise spotifyFeaturesNotEnabled
|
raise spotifyFeaturesNotEnabled
|
||||||
if not spotifyTrack:
|
if not spotifyTrack:
|
||||||
spotify_track = self.sp.track(track_id)
|
spotify_track = self.sp.track(track_id)
|
||||||
else:
|
else:
|
||||||
spotify_track = spotifyTrack
|
spotify_track = spotifyTrack
|
||||||
dz_track = 0
|
dz_track = 0
|
||||||
if 'external_ids' in spotify_track and 'isrc' in spotify_track['external_ids']:
|
if 'external_ids' in spotify_track and 'isrc' in spotify_track['external_ids']:
|
||||||
try:
|
try:
|
||||||
dz_track = dz.get_track_by_ISRC(spotify_track['external_ids']['isrc'])
|
dz_track = dz.get_track_by_ISRC(spotify_track['external_ids']['isrc'])
|
||||||
dz_track = dz_track['id'] if 'id' in dz_track else 0
|
dz_track = dz_track['id'] if 'id' in dz_track else 0
|
||||||
except:
|
except:
|
||||||
dz_track = dz.get_track_from_metadata(spotify_track['artists'][0]['name'], spotify_track['name'], spotify_track['album']['name']) if fallbackSearch else 0
|
dz_track = dz.get_track_from_metadata(spotify_track['artists'][0]['name'], spotify_track['name'],
|
||||||
elif fallbackSearch:
|
spotify_track['album']['name']) if fallbackSearch else 0
|
||||||
dz_track = dz.get_track_from_metadata(spotify_track['artists'][0]['name'], spotify_track['name'], spotify_track['album']['name'])
|
elif fallbackSearch:
|
||||||
return dz_track
|
dz_track = dz.get_track_from_metadata(spotify_track['artists'][0]['name'], spotify_track['name'],
|
||||||
|
spotify_track['album']['name'])
|
||||||
|
return dz_track
|
||||||
|
|
||||||
def get_albumid_spotify(self, dz, album_id):
|
def get_albumid_spotify(self, dz, album_id):
|
||||||
if not self.spotifyEnabled:
|
if not self.spotifyEnabled:
|
||||||
raise spotifyFeaturesNotEnabled
|
raise spotifyFeaturesNotEnabled
|
||||||
spotify_album = self.sp.album(album_id)
|
spotify_album = self.sp.album(album_id)
|
||||||
dz_album = 0
|
dz_album = 0
|
||||||
if 'external_ids' in spotify_album and 'upc' in spotify_album['external_ids']:
|
if 'external_ids' in spotify_album and 'upc' in spotify_album['external_ids']:
|
||||||
try:
|
try:
|
||||||
dz_album = dz.get_album_by_UPC(spotify_album['external_ids']['upc'])
|
dz_album = dz.get_album_by_UPC(spotify_album['external_ids']['upc'])
|
||||||
dz_album = dz_album['id'] if 'id' in dz_album else 0
|
dz_album = dz_album['id'] if 'id' in dz_album else 0
|
||||||
except:
|
except:
|
||||||
try:
|
try:
|
||||||
dz_album = dz.get_album_by_UPC(int(spotify_album['external_ids']['upc']))
|
dz_album = dz.get_album_by_UPC(int(spotify_album['external_ids']['upc']))
|
||||||
dz_album = dz_album['id'] if 'id' in dz_album else 0
|
dz_album = dz_album['id'] if 'id' in dz_album else 0
|
||||||
except:
|
except:
|
||||||
dz_album = 0
|
dz_album = 0
|
||||||
return dz_album
|
return dz_album
|
||||||
|
|
||||||
|
def convert_spotify_playlist(self, dz, playlist_id, settings):
|
||||||
|
if not self.spotifyEnabled:
|
||||||
|
raise spotifyFeaturesNotEnabled
|
||||||
|
spotify_playlist = self.sp.playlist(playlist_id)
|
||||||
|
result = {
|
||||||
|
'title': spotify_playlist['name'],
|
||||||
|
'artist': spotify_playlist['owner']['display_name'],
|
||||||
|
'size': spotify_playlist['tracks']['total'],
|
||||||
|
'downloaded': 0,
|
||||||
|
'failed': 0,
|
||||||
|
'progress': 0,
|
||||||
|
'type': 'spotify_playlist',
|
||||||
|
'settings': settings or {},
|
||||||
|
'id': playlist_id
|
||||||
|
}
|
||||||
|
if len(spotify_playlist['images']):
|
||||||
|
result['cover'] = spotify_playlist['images'][0]['url']
|
||||||
|
else:
|
||||||
|
result[
|
||||||
|
'cover'] = "https://e-cdns-images.dzcdn.net/images/cover/d41d8cd98f00b204e9800998ecf8427e/75x75-000000-80-0-0.jpg"
|
||||||
|
playlistAPI = self._convert_playlist_structure(spotify_playlist)
|
||||||
|
playlistAPI['various_artist'] = dz.get_artist(5080)
|
||||||
|
tracklist = spotify_playlist['tracks']['items']
|
||||||
|
result['collection'] = []
|
||||||
|
while spotify_playlist['tracks']['next']:
|
||||||
|
spotify_playlist['tracks'] = self.sp.next(spotify_playlist['tracks'])
|
||||||
|
tracklist += spotify_playlist['tracks']['items']
|
||||||
|
totalSize = len(tracklist)
|
||||||
|
for pos, track in enumerate(tracklist, start=1):
|
||||||
|
trackID = self.get_trackid_spotify(dz, 0, settings['fallbackSearch'], track['track'])
|
||||||
|
if trackID == 0:
|
||||||
|
deezerTrack = {
|
||||||
|
'SNG_ID': 0,
|
||||||
|
'SNG_TITLE': track['track']['name'],
|
||||||
|
'DURATION': 0,
|
||||||
|
'MD5_ORIGIN': 0,
|
||||||
|
'MEDIA_VERSION': 0,
|
||||||
|
'FILESIZE': 0,
|
||||||
|
'ALB_TITLE': track['track']['album']['name'],
|
||||||
|
'ALB_PICTURE': "",
|
||||||
|
'ART_ID': 0,
|
||||||
|
'ART_NAME': track['track']['artists'][0]['name']
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
deezerTrack = dz.get_track_gw(trackID)
|
||||||
|
deezerTrack['_EXTRA_PLAYLIST'] = playlistAPI
|
||||||
|
deezerTrack['POSITION'] = pos
|
||||||
|
deezerTrack['SIZE'] = totalSize
|
||||||
|
deezerTrack['FILENAME_TEMPLATE'] = settings['playlistTracknameTemplate']
|
||||||
|
result['collection'].append(deezerTrack)
|
||||||
|
return result
|
||||||
|
|
||||||
def convert_spotify_playlist(self, dz, playlist_id, settings):
|
|
||||||
if not self.spotifyEnabled:
|
|
||||||
raise spotifyFeaturesNotEnabled
|
|
||||||
spotify_playlist = self.sp.playlist(playlist_id)
|
|
||||||
result = {
|
|
||||||
'title': spotify_playlist['name'],
|
|
||||||
'artist': spotify_playlist['owner']['display_name'],
|
|
||||||
'size': spotify_playlist['tracks']['total'],
|
|
||||||
'downloaded': 0,
|
|
||||||
'failed': 0,
|
|
||||||
'progress': 0,
|
|
||||||
'type': 'spotify_playlist',
|
|
||||||
'settings': settings or {},
|
|
||||||
'id': playlist_id
|
|
||||||
}
|
|
||||||
if len(spotify_playlist['images']):
|
|
||||||
result['cover'] = spotify_playlist['images'][0]['url']
|
|
||||||
else:
|
|
||||||
result['cover'] = "https://e-cdns-images.dzcdn.net/images/cover/d41d8cd98f00b204e9800998ecf8427e/75x75-000000-80-0-0.jpg"
|
|
||||||
playlistAPI = self._convert_playlist_structure(spotify_playlist)
|
|
||||||
playlistAPI['various_artist'] = dz.get_artist(5080)
|
|
||||||
tracklist = spotify_playlist['tracks']['items']
|
|
||||||
result['collection'] = []
|
|
||||||
while spotify_playlist['tracks']['next']:
|
|
||||||
spotify_playlist['tracks'] = self.sp.next(spotify_playlist['tracks'])
|
|
||||||
tracklist += spotify_playlist['tracks']['items']
|
|
||||||
totalSize = len(tracklist)
|
|
||||||
for pos, track in enumerate(tracklist, start=1):
|
|
||||||
trackID = self.get_trackid_spotify(dz, 0, settings['fallbackSearch'], track['track'])
|
|
||||||
if trackID == 0:
|
|
||||||
deezerTrack = {
|
|
||||||
'SNG_ID': 0,
|
|
||||||
'SNG_TITLE': track['track']['name'],
|
|
||||||
'DURATION': 0,
|
|
||||||
'MD5_ORIGIN': 0,
|
|
||||||
'MEDIA_VERSION': 0,
|
|
||||||
'FILESIZE': 0,
|
|
||||||
'ALB_TITLE': track['track']['album']['name'],
|
|
||||||
'ALB_PICTURE': "",
|
|
||||||
'ART_ID': 0,
|
|
||||||
'ART_NAME': track['track']['artists'][0]['name']
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
deezerTrack = dz.get_track_gw(trackID)
|
|
||||||
deezerTrack['_EXTRA_PLAYLIST'] = playlistAPI
|
|
||||||
deezerTrack['POSITION'] = pos
|
|
||||||
deezerTrack['SIZE'] = totalSize
|
|
||||||
deezerTrack['FILENAME_TEMPLATE'] = settings['playlistTracknameTemplate']
|
|
||||||
result['collection'].append(deezerTrack)
|
|
||||||
return result
|
|
||||||
|
|
||||||
class spotifyFeaturesNotEnabled(Exception):
|
class spotifyFeaturesNotEnabled(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import sys
|
|
||||||
import os.path as path
|
import os.path as path
|
||||||
|
import sys
|
||||||
from os import getenv
|
from os import getenv
|
||||||
|
|
||||||
userdata = ""
|
userdata = ""
|
||||||
homedata = path.expanduser("~")
|
homedata = path.expanduser("~")
|
||||||
|
|
||||||
if getenv("APPDATA"):
|
if getenv("APPDATA"):
|
||||||
userdata = getenv("APPDATA") + path.sep + "deemix" + path.sep
|
userdata = getenv("APPDATA") + path.sep + "deemix" + path.sep
|
||||||
elif sys.platform.startswith('darwin'):
|
elif sys.platform.startswith('darwin'):
|
||||||
userdata = homedata + '/Library/Application Support/deemix/'
|
userdata = homedata + '/Library/Application Support/deemix/'
|
||||||
elif getenv("XDG_CONFIG_HOME"):
|
elif getenv("XDG_CONFIG_HOME"):
|
||||||
userdata = getenv("XDG_CONFIG_HOME") + '/deemix/';
|
userdata = getenv("XDG_CONFIG_HOME") + '/deemix/';
|
||||||
else:
|
else:
|
||||||
userdata = homedata + '/.config/deemix/';
|
userdata = homedata + '/.config/deemix/';
|
||||||
|
|
||||||
|
|
||||||
def getHomeFolder():
|
def getHomeFolder():
|
||||||
return homedata
|
return homedata
|
||||||
|
|
||||||
|
|
||||||
def getConfigFolder():
|
def getConfigFolder():
|
||||||
return userdata
|
return userdata
|
||||||
|
|
|
@ -1,94 +1,98 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
def getBitrateInt(txt):
|
def getBitrateInt(txt):
|
||||||
txt = str(txt)
|
txt = str(txt)
|
||||||
if txt in ['flac', 'lossless', '9']:
|
if txt in ['flac', 'lossless', '9']:
|
||||||
return 9
|
return 9
|
||||||
elif txt in ['mp3', '320', '3']:
|
elif txt in ['mp3', '320', '3']:
|
||||||
return 3
|
return 3
|
||||||
elif txt in ['128', '1']:
|
elif txt in ['128', '1']:
|
||||||
return 1
|
return 1
|
||||||
elif txt in ['360', '360_hq', '15']:
|
elif txt in ['360', '360_hq', '15']:
|
||||||
return 15
|
return 15
|
||||||
elif txt in ['360_mq', '14']:
|
elif txt in ['360_mq', '14']:
|
||||||
return 14
|
return 14
|
||||||
elif txt in ['360_lq', '13']:
|
elif txt in ['360_lq', '13']:
|
||||||
return 13
|
return 13
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def changeCase(string, type):
|
def changeCase(string, type):
|
||||||
if type == "lower":
|
if type == "lower":
|
||||||
return string.lower()
|
return string.lower()
|
||||||
elif type == "upper":
|
elif type == "upper":
|
||||||
return string.upper()
|
return string.upper()
|
||||||
elif type == "start":
|
elif type == "start":
|
||||||
string = string.split(" ")
|
string = string.split(" ")
|
||||||
res = []
|
res = []
|
||||||
for index, value in enumerate(string):
|
for index, value in enumerate(string):
|
||||||
res.append(value[0].upper() + value[0:].lower())
|
res.append(value[0].upper() + value[0:].lower())
|
||||||
res = " ".join(res)
|
res = " ".join(res)
|
||||||
return res
|
return res
|
||||||
elif type == "sentence":
|
elif type == "sentence":
|
||||||
res = string[0].upper() + string[0:].lower()
|
res = string[0].upper() + string[0:].lower()
|
||||||
return res
|
return res
|
||||||
else:
|
else:
|
||||||
return string
|
return string
|
||||||
|
|
||||||
|
|
||||||
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("/"):
|
if link.endswith("/"):
|
||||||
link = link[:-1]
|
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":
|
||||||
return link[link.find("/playlist/") + 10:]
|
return link[link.find("/playlist/") + 10:]
|
||||||
if type == "spotifytrack":
|
if type == "spotifytrack":
|
||||||
return link[link.find("/track/") + 7:]
|
return link[link.find("/track/") + 7:]
|
||||||
if type == "spotifyalbum":
|
if type == "spotifyalbum":
|
||||||
return link[link.find("/album/") + 7:]
|
return link[link.find("/album/") + 7:]
|
||||||
elif link.startswith("spotify:"):
|
elif link.startswith("spotify:"):
|
||||||
if type == "spotifyplaylist":
|
if type == "spotifyplaylist":
|
||||||
return link[link.find("playlist:") + 9:]
|
return link[link.find("playlist:") + 9:]
|
||||||
if type == "spotifytrack":
|
if type == "spotifytrack":
|
||||||
return link[link.find("track:") + 6:]
|
return link[link.find("track:") + 6:]
|
||||||
if type == "spotifyalbum":
|
if type == "spotifyalbum":
|
||||||
return link[link.find("album:") + 6:]
|
return link[link.find("album:") + 6:]
|
||||||
elif type == "artisttop":
|
elif type == "artisttop":
|
||||||
return re.search(r"\/artist\/(\d+)\/top_track", link)[1]
|
return re.search(r"\/artist\/(\d+)\/top_track", link)[1]
|
||||||
else:
|
else:
|
||||||
return link[link.rfind("/") + 1:]
|
return link[link.rfind("/") + 1:]
|
||||||
|
|
||||||
|
|
||||||
def getTypeFromLink(link):
|
def getTypeFromLink(link):
|
||||||
type = ''
|
type = ''
|
||||||
if 'spotify' in link:
|
if 'spotify' in link:
|
||||||
type = 'spotify'
|
type = 'spotify'
|
||||||
if 'playlist' in link:
|
if 'playlist' in link:
|
||||||
type += 'playlist'
|
type += 'playlist'
|
||||||
elif 'track' in link:
|
elif 'track' in link:
|
||||||
type += 'track'
|
type += 'track'
|
||||||
elif 'album' in link:
|
elif 'album' in link:
|
||||||
type += 'album'
|
type += 'album'
|
||||||
elif 'deezer' in link:
|
elif 'deezer' in link:
|
||||||
if '/track' in link:
|
if '/track' in link:
|
||||||
type = 'track'
|
type = 'track'
|
||||||
elif '/playlist' in link:
|
elif '/playlist' in link:
|
||||||
type = 'playlist'
|
type = 'playlist'
|
||||||
elif '/album' in link:
|
elif '/album' in link:
|
||||||
type = 'album'
|
type = 'album'
|
||||||
elif re.search("\/artist\/(\d+)\/top_track", link):
|
elif re.search("\/artist\/(\d+)\/top_track", link):
|
||||||
type = 'artisttop'
|
type = 'artisttop'
|
||||||
elif '/artist' in link:
|
elif '/artist' in link:
|
||||||
type = 'artist'
|
type = 'artist'
|
||||||
return type
|
return type
|
||||||
|
|
||||||
|
|
||||||
def isValidLink(text):
|
def isValidLink(text):
|
||||||
if text.lower().startswith("http"):
|
if text.lower().startswith("http"):
|
||||||
if "deezer.com" in text.lower() or "open.spotify.com" in text.lower():
|
if "deezer.com" in text.lower() or "open.spotify.com" in text.lower():
|
||||||
return True
|
return True
|
||||||
elif text.lower().startswith("spotify:"):
|
elif text.lower().startswith("spotify:"):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -3,166 +3,194 @@ import re
|
||||||
from os.path import sep as pathSep
|
from os.path import sep as pathSep
|
||||||
|
|
||||||
bitrateLabels = {
|
bitrateLabels = {
|
||||||
15: "360 HQ",
|
15: "360 HQ",
|
||||||
14: "360 MQ",
|
14: "360 MQ",
|
||||||
13: "360 LQ",
|
13: "360 LQ",
|
||||||
9: "FLAC",
|
9: "FLAC",
|
||||||
3: "320",
|
3: "320",
|
||||||
1: "128",
|
1: "128",
|
||||||
8: "128"
|
8: "128"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def fixName(txt, char='_'):
|
def fixName(txt, char='_'):
|
||||||
txt = str(txt)
|
txt = str(txt)
|
||||||
txt = re.sub(r'[\0\/\\:*?"<>|]', char, txt)
|
txt = re.sub(r'[\0\/\\:*?"<>|]', char, txt)
|
||||||
return txt
|
return txt
|
||||||
|
|
||||||
|
|
||||||
def fixLongName(name):
|
def fixLongName(name):
|
||||||
if pathSep in name:
|
if pathSep in name:
|
||||||
name2 = name.split(pathSep)
|
name2 = name.split(pathSep)
|
||||||
name = ""
|
name = ""
|
||||||
for txt in name2:
|
for txt in name2:
|
||||||
txt = txt[:200]
|
txt = txt[:200]
|
||||||
name += txt+pathSep
|
name += txt + pathSep
|
||||||
name = name[:-1]
|
name = name[:-1]
|
||||||
else:
|
else:
|
||||||
name = name[:200]
|
name = name[:200]
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
|
||||||
def antiDot(string):
|
def antiDot(string):
|
||||||
while string[-1:] == "." or string[-1:] == " " or string[-1:] == "\n":
|
while string[-1:] == "." or string[-1:] == " " or string[-1:] == "\n":
|
||||||
string = string[:-1]
|
string = string[:-1]
|
||||||
if len(string) < 1:
|
if len(string) < 1:
|
||||||
string = "dot"
|
string = "dot"
|
||||||
return string
|
return string
|
||||||
|
|
||||||
|
|
||||||
def pad(num, max, dopad=True):
|
def pad(num, max, dopad=True):
|
||||||
paddingsize = len(str(max))
|
paddingsize = len(str(max))
|
||||||
if dopad:
|
if dopad:
|
||||||
return str(num).zfill(paddingsize)
|
return str(num).zfill(paddingsize)
|
||||||
else:
|
else:
|
||||||
return str(num)
|
return str(num)
|
||||||
|
|
||||||
|
|
||||||
def generateFilename(track, trackAPI, settings):
|
def generateFilename(track, trackAPI, settings):
|
||||||
if trackAPI['FILENAME_TEMPLATE'] == "":
|
if trackAPI['FILENAME_TEMPLATE'] == "":
|
||||||
filename = "%artist% - %title%"
|
filename = "%artist% - %title%"
|
||||||
else:
|
else:
|
||||||
filename = trackAPI['FILENAME_TEMPLATE']
|
filename = trackAPI['FILENAME_TEMPLATE']
|
||||||
return settingsRegex(filename, track, settings, trackAPI['_EXTRA_PLAYLIST'] if '_EXTRA_PLAYLIST' in trackAPI else None)
|
return settingsRegex(filename, track, settings,
|
||||||
|
trackAPI['_EXTRA_PLAYLIST'] if '_EXTRA_PLAYLIST' in trackAPI else None)
|
||||||
|
|
||||||
|
|
||||||
def generateFilepath(track, trackAPI, settings):
|
def generateFilepath(track, trackAPI, settings):
|
||||||
filepath = settings['downloadLocation']
|
filepath = settings['downloadLocation']
|
||||||
if filepath[-1:] != pathSep:
|
if filepath[-1:] != pathSep:
|
||||||
filepath += pathSep
|
filepath += pathSep
|
||||||
artistPath = None
|
artistPath = None
|
||||||
coverPath = None
|
coverPath = None
|
||||||
extrasPath = None
|
extrasPath = None
|
||||||
|
|
||||||
if settings['createPlaylistFolder'] and '_EXTRA_PLAYLIST' in trackAPI and not settings['tags']['savePlaylistAsCompilation']:
|
if settings['createPlaylistFolder'] and '_EXTRA_PLAYLIST' in trackAPI and not settings['tags'][
|
||||||
filepath += antiDot(settingsRegexPlaylist(settings['playlistNameTemplate'], trackAPI['_EXTRA_PLAYLIST'], settings)) + pathSep
|
'savePlaylistAsCompilation']:
|
||||||
|
filepath += antiDot(
|
||||||
|
settingsRegexPlaylist(settings['playlistNameTemplate'], trackAPI['_EXTRA_PLAYLIST'], settings)) + pathSep
|
||||||
|
|
||||||
if '_EXTRA_PLAYLIST' in trackAPI and not settings['tags']['savePlaylistAsCompilation']:
|
if '_EXTRA_PLAYLIST' in trackAPI and not settings['tags']['savePlaylistAsCompilation']:
|
||||||
extrasPath = filepath
|
extrasPath = filepath
|
||||||
|
|
||||||
if (
|
if (
|
||||||
settings['createArtistFolder'] and not '_EXTRA_PLAYLIST' in trackAPI or
|
settings['createArtistFolder'] and not '_EXTRA_PLAYLIST' in trackAPI or
|
||||||
(settings['createArtistFolder'] and '_EXTRA_PLAYLIST' in trackAPI and settings['tags']['savePlaylistAsCompilation']) or
|
(settings['createArtistFolder'] and '_EXTRA_PLAYLIST' in trackAPI and settings['tags'][
|
||||||
(settings['createArtistFolder'] and '_EXTRA_PLAYLIST' in trackAPI and settings['createStructurePlaylist'])
|
'savePlaylistAsCompilation']) or
|
||||||
):
|
(settings['createArtistFolder'] and '_EXTRA_PLAYLIST' in trackAPI and settings['createStructurePlaylist'])
|
||||||
if (int(track['id'])<0 and not 'mainArtist' in track['album']):
|
):
|
||||||
track['album']['mainArtist'] = track['mainArtist']
|
if (int(track['id']) < 0 and not 'mainArtist' in track['album']):
|
||||||
filepath += antiDot(settingsRegexArtist(settings['artistNameTemplate'], track['album']['mainArtist'], settings)) + pathSep
|
track['album']['mainArtist'] = track['mainArtist']
|
||||||
artistPath = filepath
|
filepath += antiDot(
|
||||||
|
settingsRegexArtist(settings['artistNameTemplate'], track['album']['mainArtist'], settings)) + pathSep
|
||||||
|
artistPath = filepath
|
||||||
|
|
||||||
if (settings['createAlbumFolder'] and
|
if (settings['createAlbumFolder'] and
|
||||||
(not 'SINGLE_TRACK' in trackAPI or ('SINGLE_TRACK' in trackAPI and settings['createSingleFolder'])) and
|
(not 'SINGLE_TRACK' in trackAPI or ('SINGLE_TRACK' in trackAPI and settings['createSingleFolder'])) and
|
||||||
(not '_EXTRA_PLAYLIST' in trackAPI or ('_EXTRA_PLAYLIST' in trackAPI and settings['tags']['savePlaylistAsCompilation']) or ('_EXTRA_PLAYLIST' in trackAPI and settings['createStructurePlaylist']))
|
(not '_EXTRA_PLAYLIST' in trackAPI or (
|
||||||
):
|
'_EXTRA_PLAYLIST' in trackAPI and settings['tags']['savePlaylistAsCompilation']) or (
|
||||||
filepath += antiDot(settingsRegexAlbum(settings['albumNameTemplate'], track['album'], settings, trackAPI)) + pathSep
|
'_EXTRA_PLAYLIST' in trackAPI and settings['createStructurePlaylist']))
|
||||||
coverPath = filepath
|
):
|
||||||
|
filepath += antiDot(
|
||||||
|
settingsRegexAlbum(settings['albumNameTemplate'], track['album'], settings, trackAPI)) + pathSep
|
||||||
|
coverPath = filepath
|
||||||
|
|
||||||
if not ('_EXTRA_PLAYLIST' in trackAPI and not settings['tags']['savePlaylistAsCompilation']):
|
if not ('_EXTRA_PLAYLIST' in trackAPI and not settings['tags']['savePlaylistAsCompilation']):
|
||||||
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 'SINGLE_TRACK' in trackAPI or ('SINGLE_TRACK' in trackAPI and settings['createSingleFolder'])) and
|
(not 'SINGLE_TRACK' in trackAPI or ('SINGLE_TRACK' in trackAPI and settings['createSingleFolder'])) and
|
||||||
(not '_EXTRA_PLAYLIST' in trackAPI or ('_EXTRA_PLAYLIST' in trackAPI and settings['tags']['savePlaylistAsCompilation']) or ('_EXTRA_PLAYLIST' in trackAPI and settings['createStructurePlaylist']))
|
(not '_EXTRA_PLAYLIST' in trackAPI or (
|
||||||
)):
|
'_EXTRA_PLAYLIST' in trackAPI and settings['tags']['savePlaylistAsCompilation']) or (
|
||||||
filepath += 'CD' + str(track['discNumber']) + pathSep
|
'_EXTRA_PLAYLIST' in trackAPI and settings['createStructurePlaylist']))
|
||||||
|
)):
|
||||||
|
filepath += 'CD' + str(track['discNumber']) + pathSep
|
||||||
|
|
||||||
|
return (filepath, artistPath, coverPath, extrasPath)
|
||||||
|
|
||||||
return (filepath, artistPath, coverPath, extrasPath)
|
|
||||||
|
|
||||||
def settingsRegex(filename, track, settings, playlist=None):
|
def settingsRegex(filename, track, settings, playlist=None):
|
||||||
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(track['mainArtistsString'], settings['illegalCharacterReplacer']))
|
filename = filename.replace("%artists%", fixName(track['mainArtistsString'], settings['illegalCharacterReplacer']))
|
||||||
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%",
|
||||||
filename = filename.replace("%tracknumber%", pad(track['trackNumber'], track['album']['trackTotal'] if int(settings['paddingSize']) == 0 else 10 ** (int(settings['paddingSize'])-1), settings['padTracks']))
|
fixName(track['album']['mainArtist']['name'], settings['illegalCharacterReplacer']))
|
||||||
filename = filename.replace("%tracktotal%", str(track['album']['trackTotal']))
|
filename = filename.replace("%tracknumber%", pad(track['trackNumber'], track['album']['trackTotal'] if int(
|
||||||
filename = filename.replace("%discnumber%", str(track['discNumber']))
|
settings['paddingSize']) == 0 else 10 ** (int(settings['paddingSize']) - 1), settings['padTracks']))
|
||||||
filename = filename.replace("%disctotal%", str(track['album']['discTotal']))
|
filename = filename.replace("%tracktotal%", str(track['album']['trackTotal']))
|
||||||
if len(track['album']['genre'])>0:
|
filename = filename.replace("%discnumber%", str(track['discNumber']))
|
||||||
filename = filename.replace("%genre%", fixName(track['album']['genre'][0], settings['illegalCharacterReplacer']))
|
filename = filename.replace("%disctotal%", str(track['album']['discTotal']))
|
||||||
else:
|
if len(track['album']['genre']) > 0:
|
||||||
filename = filename.replace("%genre%", "Unknown")
|
filename = filename.replace("%genre%",
|
||||||
filename = filename.replace("%year%", str(track['date']['year']))
|
fixName(track['album']['genre'][0], settings['illegalCharacterReplacer']))
|
||||||
filename = filename.replace("%date%", track['dateString'])
|
else:
|
||||||
filename = filename.replace("%bpm%", str(track['bpm']))
|
filename = filename.replace("%genre%", "Unknown")
|
||||||
filename = filename.replace("%label%", fixName(track['album']['label'], settings['illegalCharacterReplacer']))
|
filename = filename.replace("%year%", str(track['date']['year']))
|
||||||
filename = filename.replace("%isrc%", track['ISRC'])
|
filename = filename.replace("%date%", track['dateString'])
|
||||||
filename = filename.replace("%upc%", track['album']['barcode'])
|
filename = filename.replace("%bpm%", str(track['bpm']))
|
||||||
filename = filename.replace("%explicit%", "(Explicit)" if track['explicit'] else "")
|
filename = filename.replace("%label%", fixName(track['album']['label'], settings['illegalCharacterReplacer']))
|
||||||
|
filename = filename.replace("%isrc%", track['ISRC'])
|
||||||
|
filename = filename.replace("%upc%", track['album']['barcode'])
|
||||||
|
filename = filename.replace("%explicit%", "(Explicit)" if track['explicit'] else "")
|
||||||
|
|
||||||
|
filename = filename.replace("%track_id%", str(track['id']))
|
||||||
|
filename = filename.replace("%album_id%", str(track['album']['id']))
|
||||||
|
filename = filename.replace("%artist_id%", str(track['mainArtist']['id']))
|
||||||
|
if playlist:
|
||||||
|
filename = filename.replace("%playlist_id%", str(playlist['id']))
|
||||||
|
filename = filename.replace("%position%", pad(track['position'], playlist['nb_tracks'] if int(
|
||||||
|
settings['paddingSize']) == 0 else 10 ** (int(settings['paddingSize']) - 1), settings['padTracks']))
|
||||||
|
else:
|
||||||
|
filename = filename.replace("%position%", pad(track['trackNumber'], track['album']['trackTotal'] if int(
|
||||||
|
settings['paddingSize']) == 0 else 10 ** (int(settings['paddingSize']) - 1), settings['padTracks']))
|
||||||
|
filename = filename.replace('\\', pathSep).replace('/', pathSep)
|
||||||
|
return antiDot(fixLongName(filename))
|
||||||
|
|
||||||
filename = filename.replace("%track_id%", str(track['id']))
|
|
||||||
filename = filename.replace("%album_id%", str(track['album']['id']))
|
|
||||||
filename = filename.replace("%artist_id%", str(track['mainArtist']['id']))
|
|
||||||
if playlist:
|
|
||||||
filename = filename.replace("%playlist_id%", str(playlist['id']))
|
|
||||||
filename = filename.replace("%position%", pad(track['position'], playlist['nb_tracks'] if int(settings['paddingSize']) == 0 else 10 ** (int(settings['paddingSize'])-1), settings['padTracks']))
|
|
||||||
else:
|
|
||||||
filename = filename.replace("%position%", pad(track['trackNumber'], track['album']['trackTotal'] if int(settings['paddingSize']) == 0 else 10 ** (int(settings['paddingSize'])-1), settings['padTracks']))
|
|
||||||
filename = filename.replace('\\', pathSep).replace('/', pathSep)
|
|
||||||
return antiDot(fixLongName(filename))
|
|
||||||
|
|
||||||
def settingsRegexAlbum(foldername, album, settings, trackAPI):
|
def settingsRegexAlbum(foldername, album, settings, trackAPI):
|
||||||
if trackAPI and '_EXTRA_PLAYLIST' in trackAPI and settings['tags']['savePlaylistAsCompilation']:
|
if trackAPI and '_EXTRA_PLAYLIST' in trackAPI and settings['tags']['savePlaylistAsCompilation']:
|
||||||
foldername = foldername.replace("%album_id%", "pl_"+str(trackAPI['_EXTRA_PLAYLIST']['id']))
|
foldername = foldername.replace("%album_id%", "pl_" + str(trackAPI['_EXTRA_PLAYLIST']['id']))
|
||||||
else:
|
else:
|
||||||
foldername = foldername.replace("%album_id%", str(album['id']))
|
foldername = foldername.replace("%album_id%", str(album['id']))
|
||||||
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%",
|
||||||
foldername = foldername.replace("%artist_id%", str(album['mainArtist']['id']))
|
fixName(album['mainArtist']['name'], settings['illegalCharacterReplacer']))
|
||||||
foldername = foldername.replace("%tracktotal%", str(album['trackTotal']))
|
foldername = foldername.replace("%artist_id%", str(album['mainArtist']['id']))
|
||||||
foldername = foldername.replace("%disctotal%", str(album['discTotal']))
|
foldername = foldername.replace("%tracktotal%", str(album['trackTotal']))
|
||||||
foldername = foldername.replace("%type%", fixName(album['recordType'][0].upper()+album['recordType'][1:].lower(), settings['illegalCharacterReplacer']))
|
foldername = foldername.replace("%disctotal%", str(album['discTotal']))
|
||||||
foldername = foldername.replace("%upc%", album['barcode'])
|
foldername = foldername.replace("%type%", fixName(album['recordType'][0].upper() + album['recordType'][1:].lower(),
|
||||||
foldername = foldername.replace("%label%", fixName(album['label'], settings['illegalCharacterReplacer']))
|
settings['illegalCharacterReplacer']))
|
||||||
if len(album['genre']) > 0:
|
foldername = foldername.replace("%upc%", album['barcode'])
|
||||||
foldername = foldername.replace("%genre%", fixName(album['genre'][0], settings['illegalCharacterReplacer']))
|
foldername = foldername.replace("%label%", fixName(album['label'], settings['illegalCharacterReplacer']))
|
||||||
else:
|
if len(album['genre']) > 0:
|
||||||
foldername = foldername.replace("%genre%", "Unknown")
|
foldername = foldername.replace("%genre%", fixName(album['genre'][0], settings['illegalCharacterReplacer']))
|
||||||
foldername = foldername.replace("%year%", str(album['date']['year']))
|
else:
|
||||||
foldername = foldername.replace("%date%", album['dateString'])
|
foldername = foldername.replace("%genre%", "Unknown")
|
||||||
foldername = foldername.replace("%bitrate%", bitrateLabels[int(album['bitrate'])])
|
foldername = foldername.replace("%year%", str(album['date']['year']))
|
||||||
|
foldername = foldername.replace("%date%", album['dateString'])
|
||||||
|
foldername = foldername.replace("%bitrate%", bitrateLabels[int(album['bitrate'])])
|
||||||
|
|
||||||
|
foldername = foldername.replace('\\', pathSep).replace('/', pathSep)
|
||||||
|
return antiDot(fixLongName(foldername))
|
||||||
|
|
||||||
foldername = foldername.replace('\\', pathSep).replace('/', pathSep)
|
|
||||||
return antiDot(fixLongName(foldername))
|
|
||||||
|
|
||||||
def settingsRegexArtist(foldername, artist, settings):
|
def settingsRegexArtist(foldername, artist, settings):
|
||||||
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']))
|
||||||
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['id'], settings['illegalCharacterReplacer']))
|
foldername = foldername.replace("%playlist_id%", fixName(playlist['id'], settings['illegalCharacterReplacer']))
|
||||||
foldername = foldername.replace("%owner%", fixName(playlist['creator']['name'], settings['illegalCharacterReplacer']))
|
foldername = foldername.replace("%owner%",
|
||||||
foldername = foldername.replace("%owner_id%", str(playlist['creator']['id']))
|
fixName(playlist['creator']['name'], settings['illegalCharacterReplacer']))
|
||||||
foldername = foldername.replace("%year%", str(playlist['creation_date'][:4]))
|
foldername = foldername.replace("%owner_id%", str(playlist['creator']['id']))
|
||||||
foldername = foldername.replace("%date%", str(playlist['creation_date'][:10]))
|
foldername = foldername.replace("%year%", str(playlist['creation_date'][:4]))
|
||||||
foldername = foldername.replace('\\', pathSep).replace('/', pathSep)
|
foldername = foldername.replace("%date%", str(playlist['creation_date'][:10]))
|
||||||
return antiDot(fixLongName(foldername))
|
foldername = foldername.replace('\\', pathSep).replace('/', pathSep)
|
||||||
|
return antiDot(fixLongName(foldername))
|
||||||
|
|
|
@ -1,135 +1,139 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from mutagen.flac import FLAC, Picture
|
from mutagen.flac import FLAC, Picture
|
||||||
from mutagen.id3 import ID3, ID3NoHeaderError, TXXX, TIT2, TPE1, TALB, TPE2, TRCK, TPOS, TCON, TYER, TDAT, TLEN, TBPM, \
|
from mutagen.id3 import ID3, ID3NoHeaderError, TXXX, TIT2, TPE1, TALB, TPE2, TRCK, TPOS, TCON, TYER, TDAT, TLEN, TBPM, \
|
||||||
TPUB, TSRC, USLT, APIC, IPLS, TCOM, TCOP, TCMP
|
TPUB, TSRC, USLT, APIC, IPLS, TCOM, TCOP, TCMP
|
||||||
|
|
||||||
|
|
||||||
def tagID3(stream, track, save):
|
def tagID3(stream, track, save):
|
||||||
try:
|
try:
|
||||||
tag = ID3(stream)
|
tag = ID3(stream)
|
||||||
except ID3NoHeaderError:
|
except ID3NoHeaderError:
|
||||||
tag = ID3()
|
tag = ID3()
|
||||||
|
|
||||||
if save['title']:
|
if save['title']:
|
||||||
tag.add(TIT2(text=track['title']))
|
tag.add(TIT2(text=track['title']))
|
||||||
if save['artist']:
|
if save['artist']:
|
||||||
if save['multitagSeparator'] != "default":
|
if save['multitagSeparator'] != "default":
|
||||||
tag.add(TPE1(text=track['artistsString']))
|
tag.add(TPE1(text=track['artistsString']))
|
||||||
tag.add(TXXX(desc="ARTISTS", text=track['artists']))
|
tag.add(TXXX(desc="ARTISTS", text=track['artists']))
|
||||||
else:
|
else:
|
||||||
tag.add(TPE1(text=track['artists']))
|
tag.add(TPE1(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']:
|
if save['albumArtist']:
|
||||||
tag.add(TPE2(text=track['album']['artists']))
|
tag.add(TPE2(text=track['album']['artists']))
|
||||||
if save['trackNumber']:
|
if save['trackNumber']:
|
||||||
tag.add(TRCK(text=str(track['trackNumber'])+("/"+str(track['album']['trackTotal']) if save['trackTotal'] else "")))
|
tag.add(TRCK(
|
||||||
if save['discNumber']:
|
text=str(track['trackNumber']) + ("/" + str(track['album']['trackTotal']) if save['trackTotal'] else "")))
|
||||||
tag.add(TPOS(text=str(track['discNumber'])+("/"+str(track['album']['discTotal']) if save['discTotal'] else "")))
|
if save['discNumber']:
|
||||||
if save['genre']:
|
tag.add(
|
||||||
tag.add(TCON(text=track['album']['genre']))
|
TPOS(text=str(track['discNumber']) + ("/" + str(track['album']['discTotal']) if save['discTotal'] else "")))
|
||||||
if save['year']:
|
if save['genre']:
|
||||||
tag.add(TYER(text=str(track['date']['year'])))
|
tag.add(TCON(text=track['album']['genre']))
|
||||||
if save['date']:
|
if save['year']:
|
||||||
tag.add(TDAT(text=str(track['date']['month']) + str(track['date']['day'])))
|
tag.add(TYER(text=str(track['date']['year'])))
|
||||||
if save['length']:
|
if save['date']:
|
||||||
tag.add(TLEN(text=str(track['duration'])))
|
tag.add(TDAT(text=str(track['date']['month']) + str(track['date']['day'])))
|
||||||
if save['bpm']:
|
if save['length']:
|
||||||
tag.add(TBPM(text=str(track['bpm'])))
|
tag.add(TLEN(text=str(track['duration'])))
|
||||||
if save['label']:
|
if save['bpm']:
|
||||||
tag.add(TPUB(text=track['album']['label']))
|
tag.add(TBPM(text=str(track['bpm'])))
|
||||||
if save['isrc']:
|
if save['label']:
|
||||||
tag.add(TSRC(text=track['ISRC']))
|
tag.add(TPUB(text=track['album']['label']))
|
||||||
if save['barcode']:
|
if save['isrc']:
|
||||||
tag.add(TXXX(desc="BARCODE", text=track['album']['barcode']))
|
tag.add(TSRC(text=track['ISRC']))
|
||||||
if save['explicit']:
|
if save['barcode']:
|
||||||
tag.add(TXXX(desc="ITUNESADVISORY", text="1" if track['explicit'] else "0"))
|
tag.add(TXXX(desc="BARCODE", text=track['album']['barcode']))
|
||||||
if save['replayGain']:
|
if save['explicit']:
|
||||||
tag.add(TXXX(desc="REPLAYGAIN_TRACK_GAIN", text=track['replayGain']))
|
tag.add(TXXX(desc="ITUNESADVISORY", text="1" if track['explicit'] else "0"))
|
||||||
if 'unsync' in track['lyrics'] and save['lyrics']:
|
if save['replayGain']:
|
||||||
tag.add(USLT(text=track['lyrics']['unsync']))
|
tag.add(TXXX(desc="REPLAYGAIN_TRACK_GAIN", text=track['replayGain']))
|
||||||
involved_people = []
|
if 'unsync' in track['lyrics'] and save['lyrics']:
|
||||||
for role in track['contributors']:
|
tag.add(USLT(text=track['lyrics']['unsync']))
|
||||||
if role in ['author', 'engineer', 'mixer', 'producer', 'writer']:
|
involved_people = []
|
||||||
for person in track['contributors'][role]:
|
for role in track['contributors']:
|
||||||
involved_people.append([role, person])
|
if role in ['author', 'engineer', 'mixer', 'producer', 'writer']:
|
||||||
elif role == 'composer' and save['composer']:
|
for person in track['contributors'][role]:
|
||||||
tag.add(TCOM(text=track['contributors']['composer']))
|
involved_people.append([role, person])
|
||||||
if len(involved_people) > 0 and save['involvedPeople']:
|
elif role == 'composer' and save['composer']:
|
||||||
tag.add(IPLS(people=involved_people))
|
tag.add(TCOM(text=track['contributors']['composer']))
|
||||||
if save['copyright']:
|
if len(involved_people) > 0 and save['involvedPeople']:
|
||||||
tag.add(TCOP(text=track['copyright']))
|
tag.add(IPLS(people=involved_people))
|
||||||
if save['savePlaylistAsCompilation']:
|
if save['copyright']:
|
||||||
tag.add(TCMP(text="1"))
|
tag.add(TCOP(text=track['copyright']))
|
||||||
if save['cover'] and track['album']['picPath']:
|
if save['savePlaylistAsCompilation']:
|
||||||
with open(track['album']['picPath'], 'rb') as f:
|
tag.add(TCMP(text="1"))
|
||||||
tag.add(APIC(3, 'image/jpeg' if track['album']['picPath'].endswith('jpg') else 'image/png', 3, data=f.read()))
|
if save['cover'] and track['album']['picPath']:
|
||||||
|
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 save['saveID3v1'] else 0, v2_version=3, v23_sep=None if save['useNullSeparator'] 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):
|
def tagFLAC(stream, track, save):
|
||||||
tag = FLAC(stream)
|
tag = FLAC(stream)
|
||||||
|
|
||||||
if save['title']:
|
if save['title']:
|
||||||
tag["TITLE"] = track['title']
|
tag["TITLE"] = track['title']
|
||||||
if save['artist']:
|
if save['artist']:
|
||||||
if save['multitagSeparator'] != "default":
|
if save['multitagSeparator'] != "default":
|
||||||
tag["ARTIST"] = track['artistsString']
|
tag["ARTIST"] = track['artistsString']
|
||||||
tag["ARTISTS"] = track['artists']
|
tag["ARTISTS"] = track['artists']
|
||||||
else:
|
else:
|
||||||
tag["ARTIST"] = track['artists']
|
tag["ARTIST"] = track['artists']
|
||||||
if save['album']:
|
if save['album']:
|
||||||
tag["ALBUM"] = track['album']['title']
|
tag["ALBUM"] = track['album']['title']
|
||||||
if save['albumArtist']:
|
if save['albumArtist']:
|
||||||
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']
|
||||||
if save['year']:
|
if save['year']:
|
||||||
tag["YEAR"] = str(track['date']['year'])
|
tag["YEAR"] = str(track['date']['year'])
|
||||||
if save['date']:
|
if save['date']:
|
||||||
tag["DATE"] = track['dateString']
|
tag["DATE"] = track['dateString']
|
||||||
if save['length']:
|
if save['length']:
|
||||||
tag["LENGTH"] = str(track['duration'])
|
tag["LENGTH"] = str(track['duration'])
|
||||||
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 'unsync' in track['lyrics'] and save['lyrics']:
|
if 'unsync' in track['lyrics'] 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']:
|
||||||
if save['involvedPeople'] and role != 'composer' or role == 'composer' and save['composer']:
|
if save['involvedPeople'] and role != 'composer' or role == 'composer' and save['composer']:
|
||||||
tag[role] = track['contributors'][role]
|
tag[role] = track['contributors'][role]
|
||||||
elif role == 'musicpublisher' and save['involvedPeople']:
|
elif role == 'musicpublisher' and save['involvedPeople']:
|
||||||
tag["ORGANIZATION"] = track['contributors']['musicpublisher']
|
tag["ORGANIZATION"] = track['contributors']['musicpublisher']
|
||||||
if save['copyright']:
|
if save['copyright']:
|
||||||
tag["COPYRIGHT"] = track['copyright']
|
tag["COPYRIGHT"] = track['copyright']
|
||||||
if save['savePlaylistAsCompilation']:
|
if save['savePlaylistAsCompilation']:
|
||||||
tag["COMPILATION"] = "1"
|
tag["COMPILATION"] = "1"
|
||||||
|
|
||||||
if save['cover'] and track['album']['picPath']:
|
if save['cover'] and track['album']['picPath']:
|
||||||
image = Picture()
|
image = Picture()
|
||||||
image.type = 3
|
image.type = 3
|
||||||
image.mime = 'image/jpeg' if track['album']['picPath'].endswith('jpg') else 'image/png'
|
image.mime = 'image/jpeg' if track['album']['picPath'].endswith('jpg') else 'image/png'
|
||||||
with open(track['album']['picPath'], 'rb') as f:
|
with open(track['album']['picPath'], 'rb') as f:
|
||||||
image.data = f.read()
|
image.data = f.read()
|
||||||
tag.add_picture(image)
|
tag.add_picture(image)
|
||||||
|
|
||||||
tag.save(deleteid3=True)
|
tag.save(deleteid3=True)
|
||||||
|
|
Loading…
Reference in New Issue