Restructure and fixed issues
This commit is contained in:
parent
e29bf188b2
commit
f8d8f08417
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env python3
|
||||
#Empty File
|
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env python3
|
||||
import wx
|
||||
from deemix.ui.MainFrame import MainFrame
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = wx.App()
|
||||
frame = MainFrame()
|
||||
app.MainLoop()
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env python3
|
||||
#Empty File
|
|
@ -0,0 +1,309 @@
|
|||
#!/usr/bin/env python3
|
||||
from urllib.request import urlopen
|
||||
import requests
|
||||
import json
|
||||
import re
|
||||
|
||||
import hashlib
|
||||
import pyaes
|
||||
import binascii
|
||||
import blowfish
|
||||
|
||||
class Deezer:
|
||||
def __init__(self):
|
||||
self.api_url = "http://www.deezer.com/ajax/gw-light.php"
|
||||
self.legacy_api_url = "https://api.deezer.com/"
|
||||
self.http_headers = {
|
||||
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"
|
||||
}
|
||||
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.user = {}
|
||||
self.session = requests.Session()
|
||||
self.logged_in = False
|
||||
self.session.post("http://www.deezer.com/", headers=self.http_headers)
|
||||
self.sid = self.session.cookies.get_dict()['sid']
|
||||
|
||||
def get_token(self):
|
||||
tokenData = self.gw_api_call('deezer.getUserData')
|
||||
return tokenData["results"]["checkForm"]
|
||||
|
||||
def get_track_MD5(self, id):
|
||||
site = self.session.post("https://api.deezer.com/1.0/gateway.php",
|
||||
params = {
|
||||
'api_key' : "4VCYIJUCDLOUELGD1V8WBVYBNVDYOXEWSLLZDONGBBDFVXTZJRXPR29JRLQFO6ZE",
|
||||
'sid' : self.sid,
|
||||
'input' : '3',
|
||||
'output': '3',
|
||||
'method' : 'song_getData'
|
||||
},
|
||||
data = json.dumps({'sng_id': id}),
|
||||
headers = self.http_headers
|
||||
)
|
||||
response = json.loads(site.text)
|
||||
return response['results']['PUID']
|
||||
|
||||
def gw_api_call(self, method, args={}):
|
||||
result = self.session.post(
|
||||
self.api_url,
|
||||
params = {
|
||||
'api_version' : "1.0",
|
||||
'api_token' : 'null' if method == 'deezer.getUserData' else self.get_token(),
|
||||
'input' : '3',
|
||||
'method' : method
|
||||
},
|
||||
data = json.dumps(args),
|
||||
headers = self.http_headers
|
||||
)
|
||||
result = json.loads(result.text)
|
||||
return result
|
||||
|
||||
def api_call(self, method, args={}):
|
||||
result = self.session.get(
|
||||
self.legacy_api_url+method,
|
||||
params = args,
|
||||
headers = self.http_headers
|
||||
)
|
||||
result_json = json.loads(result.text)
|
||||
if 'error' in result_json.keys():
|
||||
raise APIError()
|
||||
return result_json
|
||||
|
||||
def login(self, email, password, reCaptchaToken):
|
||||
checkFormLogin = self.gw_api_call("deezer.getUserData")
|
||||
login = self.session.post(
|
||||
"https://www.deezer.com/ajax/action.php",
|
||||
data={
|
||||
'type':'login',
|
||||
'mail':email,
|
||||
'password':password,
|
||||
'checkFormLogin':checkFormLogin['results']['checkFormLogin'],
|
||||
'reCaptchaToken': reCaptchaToken
|
||||
},
|
||||
headers = {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}.update(self.http_headers)
|
||||
)
|
||||
if not 'success' in login.text:
|
||||
self.logged_in = False
|
||||
return False
|
||||
userData = self.gw_api_call("deezer.getUserData")
|
||||
self.user = {
|
||||
'email': email,
|
||||
'id': userData["results"]["USER"]["USER_ID"],
|
||||
'name': userData["results"]["USER"]["BLOG_NAME"],
|
||||
'picture': userData["results"]["USER"]["USER_PICTURE"] if "USER_PICTURE" in userData["results"]["USER"] else ""
|
||||
}
|
||||
self.logged_in = True
|
||||
return True
|
||||
|
||||
def login_via_arl(self, arl):
|
||||
cookie_obj = requests.cookies.create_cookie(
|
||||
domain='deezer.com',
|
||||
name='arl',
|
||||
value=arl,
|
||||
path="/",
|
||||
rest={'HttpOnly': True}
|
||||
)
|
||||
self.session.cookies.set_cookie(cookie_obj)
|
||||
userData = self.gw_api_call("deezer.getUserData")
|
||||
if (userData["results"]["USER"]["USER_ID"] == 0):
|
||||
self.logged_in = False
|
||||
return False
|
||||
self.user = {
|
||||
'id': userData["results"]["USER"]["USER_ID"],
|
||||
'name': userData["results"]["USER"]["BLOG_NAME"],
|
||||
'picture': userData["results"]["USER"]["USER_PICTURE"] if "USER_PICTURE" in userData["results"]["USER"] else ""
|
||||
}
|
||||
self.logged_in = True
|
||||
return True
|
||||
|
||||
def get_track_gw(self, id):
|
||||
if (int(id)<0):
|
||||
body = self.gw_api_call('song.getData', {'sng_id': id})
|
||||
else:
|
||||
body = self.gw_api_call('deezer.pageTrack', {'sng_id': id})
|
||||
if 'LYRICS' in body['results']:
|
||||
body['results']['DATA']['LYRICS'] = body['results']['LYRICS']
|
||||
body['results'] = body['results']['DATA']
|
||||
return body['results']
|
||||
|
||||
def get_tracks_gw(self, ids):
|
||||
tracksArray = []
|
||||
body = self.gw_api_call('song.getListData', {'sng_ids': ids})
|
||||
errors = 0
|
||||
for i in range(len(ids)):
|
||||
if ids[i] != 0:
|
||||
tracksArray.append(body['results']['data'][i-errors])
|
||||
else:
|
||||
errors += 1
|
||||
tracksArray.append({
|
||||
'SNG_ID': 0,
|
||||
'SNG_TITLE': '',
|
||||
'DURATION': 0,
|
||||
'MD5_ORIGIN': 0,
|
||||
'MEDIA_VERSION': 0,
|
||||
'FILESIZE': 0,
|
||||
'ALB_TITLE': "",
|
||||
'ALB_PICTURE': "",
|
||||
'ART_ID': 0,
|
||||
'ART_NAME': ""
|
||||
})
|
||||
return tracksArray
|
||||
|
||||
def get_album_gw(self, id):
|
||||
body = self.gw_api_call('album.getData', {'alb_id': id})
|
||||
return body['results']
|
||||
|
||||
def get_album_tracks_gw(self, id):
|
||||
tracksArray = []
|
||||
body = self.gw_api_call('song.getListByAlbum', {'alb_id': id, 'nb': -1})
|
||||
for track in body['results']['data']:
|
||||
_track = track
|
||||
_track['position'] = body['results']['data'].index(track)
|
||||
tracksArray.append(_track)
|
||||
return tracksArray
|
||||
|
||||
def get_artist_gw(self, id):
|
||||
body = self.gw_api_call('deezer.pageArtist', {'art_id': id})
|
||||
return body
|
||||
|
||||
def get_playlist_gw(self, id):
|
||||
body = self.gw_api_call('deezer.pagePlaylist', {'playlist_id': id})
|
||||
return body
|
||||
|
||||
def get_playlist_tracks_gw(self, id):
|
||||
tracksArray = []
|
||||
body = self.gw_api_call('playlist.getSongs', {'playlist_id': id, 'nb': -1})
|
||||
for track in body['results']['data']:
|
||||
_track = track
|
||||
_track['position'] = body['results']['data'].index(track)
|
||||
tracksArray.append(_track)
|
||||
return tracksArray
|
||||
|
||||
def get_artist_toptracks_gw(self, id):
|
||||
tracksArray = []
|
||||
body = self.gw_api_call('artist.getTopTrack', {'art_id': id, 'nb': 100})
|
||||
for track in body['results']['data']:
|
||||
_track = track
|
||||
_track['position'] = body['results']['data'].index(track)
|
||||
tracksArray.append(_track)
|
||||
return tracksArray
|
||||
|
||||
def get_lyrics_gw(self, id):
|
||||
body = self.gw_api_call('song.getLyrics', {'sng_id': id})
|
||||
lyr = {}
|
||||
lyr['unsyncLyrics'] = {
|
||||
'description': "",
|
||||
'lyrics': body["results"]["LYRICS_TEXT"]
|
||||
}
|
||||
lyr['syncLyrics'] = ""
|
||||
for i in range(len(body["results"]["LYRICS_SYNC_JSON"])):
|
||||
if "lrc_timestamp" in body["results"]["LYRICS_SYNC_JSON"][i]:
|
||||
lyr['syncLyrics'] += body["results"]["LYRICS_SYNC_JSON"][i]["lrc_timestamp"] + body["results"]["LYRICS_SYNC_JSON"][i]["line"]+"\r\n"
|
||||
elif i+1 < len(body["results"]["LYRICS_SYNC_JSON"]):
|
||||
lyr['syncLyrics'] += body["results"]["LYRICS_SYNC_JSON"][i+1]["lrc_timestamp"] + body["results"]["LYRICS_SYNC_JSON"][i]["line"]+"\r\n"
|
||||
return lyr
|
||||
|
||||
def get_user_playlist(self, id):
|
||||
body = self.api_call('user/'+str(id)+'/playlists', {'limit': -1})
|
||||
return body
|
||||
|
||||
def get_track(self, id):
|
||||
body = self.api_call('track/'+str(id))
|
||||
return body
|
||||
|
||||
def get_track_by_ISRC(self, isrc):
|
||||
body = self.api_call('track/isrc:'+isrc)
|
||||
return body
|
||||
|
||||
def get_charts_top_country(self):
|
||||
return self.get_user_playlist('637006841')
|
||||
|
||||
def get_playlist(self, id):
|
||||
body = self.api_call('playlist/'+str(id))
|
||||
return body
|
||||
|
||||
def get_playlist_tracks(self, id):
|
||||
body = self.api_call('playlist/'+str(id)+'/tracks', {'limit': -1})
|
||||
return body
|
||||
|
||||
def get_album(self, id):
|
||||
body = self.api_call('album/'+str(id))
|
||||
return body
|
||||
|
||||
def get_album_by_UPC(self, upc):
|
||||
body = self.api_call('album/upc:'+str(upc))
|
||||
|
||||
def get_album_tracks(self, id):
|
||||
body = self.api_call('album/'+str(id)+'/tracks', {'limit': -1})
|
||||
return body
|
||||
|
||||
def get_artist(self, id):
|
||||
body = self.api_call('artist/'+str(id))
|
||||
return body
|
||||
|
||||
def get_artist_albums(self, id):
|
||||
body = self.api_call('artist/'+str(id)+'/albums', {'limit': -1})
|
||||
return body
|
||||
|
||||
def search(self, term, type, limit = 30):
|
||||
body = self.api_call('search/'+type, {'q': term, 'limit': limit})
|
||||
return body
|
||||
|
||||
def decrypt_track(self, trackId, input, output):
|
||||
response = open(input, 'rb')
|
||||
outfile = open(output, 'wb')
|
||||
cipher = blowfish.Cipher(str.encode(self._get_blowfish_key(str(trackId))))
|
||||
i=0
|
||||
while True:
|
||||
chunk = response.read(2048)
|
||||
if not chunk:
|
||||
break
|
||||
if (i % 3)==0 and len(chunk)==2048:
|
||||
chunk = b"".join(cipher.decrypt_cbc(chunk,b"\x00\x01\x02\x03\x04\x05\x06\x07"))
|
||||
outfile.write(chunk)
|
||||
i += 1
|
||||
|
||||
def stream_track(self, trackId, url, stream):
|
||||
response = urlopen(url)
|
||||
cipher = blowfish.Cipher(str.encode(self._get_blowfish_key(str(trackId))))
|
||||
i=0
|
||||
while True:
|
||||
chunk = response.read(2048)
|
||||
if not chunk:
|
||||
break
|
||||
if (i % 3)==0 and len(chunk)==2048:
|
||||
chunk = b"".join(cipher.decrypt_cbc(chunk,b"\x00\x01\x02\x03\x04\x05\x06\x07"))
|
||||
stream.write(chunk)
|
||||
i += 1
|
||||
|
||||
def _md5(self, data):
|
||||
h=hashlib.new("md5")
|
||||
h.update(str.encode(data) if isinstance(data, str) else data)
|
||||
return h.hexdigest()
|
||||
|
||||
def _ecb_crypt(self, key, data):
|
||||
res = b''
|
||||
for x in range(int(len(data)/16)):
|
||||
res += binascii.hexlify(pyaes.AESModeOfOperationECB(key).encrypt(data[:16]))
|
||||
data = data[16:]
|
||||
return res
|
||||
|
||||
def _get_blowfish_key(self, trackId):
|
||||
SECRET = 'g4el58wc'+'0zvf9na1'
|
||||
idMd5 = self._md5(trackId)
|
||||
bfKey = ""
|
||||
for i in range(16):
|
||||
bfKey += chr(ord(idMd5[i]) ^ ord(idMd5[i+16]) ^ ord(SECRET[i]))
|
||||
return bfKey
|
||||
|
||||
def get_track_stream_url(self, sng_id, md5, media_version, format):
|
||||
urlPart = b'\xa4'.join([str.encode(md5), str.encode(str(format)), str.encode(str(sng_id)), str.encode(str(media_version))])
|
||||
md5val = self._md5(urlPart)
|
||||
step2 = str.encode(md5val)+b'\xa4'+urlPart+b'\xa4'
|
||||
while len(step2)%16 > 0:
|
||||
step2 += b'.'
|
||||
urlPart = self._ecb_crypt(b'jo6aey6haid2Teih', step2)
|
||||
return "https://e-cdns-proxy-" + md5[0] + ".dzcdn.net/mobile/1/" + urlPart.decode("utf-8")
|
||||
|
||||
class APIError(Exception):
|
||||
pass
|
|
@ -0,0 +1,264 @@
|
|||
#!/usr/bin/env python3
|
||||
from deemix.api.deezer import Deezer, APIError
|
||||
from deemix.utils.taggers import tagID3, tagFLAC
|
||||
import json
|
||||
import re
|
||||
|
||||
extensions = {
|
||||
9: '.flac',
|
||||
3: '.mp3',
|
||||
1: '.mp3',
|
||||
8: '.mp3',
|
||||
15: '.mp4',
|
||||
14: '.mp4',
|
||||
13: '.mp4'
|
||||
}
|
||||
|
||||
dz = Deezer()
|
||||
|
||||
def getIDFromLink(link, type):
|
||||
if '?' in link:
|
||||
link = link[:link.find('?')]
|
||||
|
||||
if link.startswith("http") and 'open.spotify.com/' in link:
|
||||
if type == "spotifyplaylist":
|
||||
return link[link.find("/playlist/")+10]
|
||||
if type == "spotifytrack":
|
||||
return link[link.find("/track/")+7]
|
||||
if type == "spotifyalbum":
|
||||
return link[link.find("/album/")+7]
|
||||
elif link.startswith("spotify:"):
|
||||
if type == "spotifyplaylist":
|
||||
return link[link.find("playlist:")+9]
|
||||
if type == "spotifytrack":
|
||||
return link[link.find("track:")+6]
|
||||
if type == "spotifyalbum":
|
||||
return link[link.find("album:")+6]
|
||||
elif type == "artisttop":
|
||||
return re.search("\/artist\/(\d+)\/top_track",link)[1]
|
||||
else:
|
||||
return link[link.rfind("/")+1:]
|
||||
|
||||
def getTypeFromLink(link):
|
||||
type = ''
|
||||
if 'spotify' in link:
|
||||
type = 'spotify'
|
||||
if 'playlist' in link:
|
||||
type += 'playlist'
|
||||
elif 'track' in link:
|
||||
type += 'track'
|
||||
elif 'album' in link:
|
||||
type += 'album'
|
||||
elif 'deezer' in link:
|
||||
if '/track' in link:
|
||||
type = 'track'
|
||||
elif '/playlist' in link:
|
||||
type = 'playlist'
|
||||
elif '/album' in link:
|
||||
type = 'album'
|
||||
elif re.search("\/artist\/(\d+)\/top_track",link):
|
||||
type = 'artisttop'
|
||||
elif '/artist' in link:
|
||||
type = 'artist'
|
||||
return type
|
||||
|
||||
def getTrackData(id):
|
||||
if not id:
|
||||
return None
|
||||
trackAPI = dz.get_track_gw(id)
|
||||
if not 'MD5_ORIGIN' in trackAPI:
|
||||
trackAPI['MD5_ORIGIN'] = dz.get_track_MD5(id)
|
||||
|
||||
track = {}
|
||||
track['id'] = trackAPI['SNG_ID']
|
||||
track['title'] = trackAPI['SNG_TITLE']
|
||||
if trackAPI['VERSION']:
|
||||
track['title'] += " "+trackAPI['VERSION']
|
||||
track['duration'] = trackAPI['DURATION']
|
||||
track['MD5'] = trackAPI['MD5_ORIGIN']
|
||||
track['mediaVersion'] = trackAPI['MEDIA_VERSION']
|
||||
|
||||
if int(track['id'])<0:
|
||||
track['filesize'] = trackAPI['FILESIZE']
|
||||
track['album'] = {}
|
||||
track['album']['id'] = 0
|
||||
track['album']['title'] = trackAPI['ALB_TITLE']
|
||||
if 'ALB_PICTURE' in trackAPI:
|
||||
track['album']['pic'] = trackAPI['ALB_PICTURE']
|
||||
track['mainArtist'] = {}
|
||||
track['mainArtist']['id'] = 0
|
||||
track['mainArtist']['name'] = trackAPI['ART_NAME']
|
||||
track['artistArray'] = [trackAPI['ART_NAME']]
|
||||
track['date'] = {
|
||||
'day': 0,
|
||||
'month': 0,
|
||||
'year': 0
|
||||
}
|
||||
track['localTrack'] = True
|
||||
return track
|
||||
|
||||
track['filesize'] = {}
|
||||
track['filesize']['default'] = int(trackAPI['FILESIZE']) if 'FILESIZE' in trackAPI else None
|
||||
track['filesize']['mp3_128'] = int(trackAPI['FILESIZE_MP3_128']) if 'FILESIZE_MP3_128' in trackAPI else None
|
||||
track['filesize']['mp3_320'] = int(trackAPI['FILESIZE_MP3_320']) if 'FILESIZE_MP3_320' in trackAPI else None
|
||||
track['filesize']['flac'] = int(trackAPI['FILESIZE_FLAC']) if 'FILESIZE_FLAC' in trackAPI else None
|
||||
track['filesize']['mp4_ra1'] = int(trackAPI['FILESIZE_MP4_RA1']) if 'FILESIZE_MP4_RA1' in trackAPI else None
|
||||
track['filesize']['mp4_ra2'] = int(trackAPI['FILESIZE_MP4_RA2']) if 'FILESIZE_MP4_RA2' in trackAPI else None
|
||||
track['filesize']['mp4_ra3'] = int(trackAPI['FILESIZE_MP4_RA3']) if 'FILESIZE_MP4_RA3' in trackAPI else None
|
||||
|
||||
if 'DISK_NUMBER' in trackAPI:
|
||||
track['discNumber'] = trackAPI['DISK_NUMBER']
|
||||
if 'EXPLICIT_LYRICS' in trackAPI:
|
||||
track['explicit'] = trackAPI['EXPLICIT_LYRICS'] != "0"
|
||||
if 'COPYRIGHT' in trackAPI:
|
||||
track['copyright'] = trackAPI['COPYRIGHT']
|
||||
track['replayGain'] = "{0:.2f} dB".format((float(trackAPI['GAIN']) + 18.4) * -1)
|
||||
track['ISRC'] = trackAPI['ISRC']
|
||||
track['trackNumber'] = trackAPI['TRACK_NUMBER']
|
||||
if 'FALLBACK' in trackAPI:
|
||||
track['fallbackId'] = trackAPI['FALLBACK']['SNG_ID']
|
||||
else:
|
||||
track['fallbackId'] = 0
|
||||
track['contributors'] = trackAPI['SNG_CONTRIBUTORS']
|
||||
|
||||
track['lyrics'] = {}
|
||||
if 'LYRICS_ID' in trackAPI:
|
||||
track['lyrics']['id'] = trackAPI['LYRICS_ID']
|
||||
if "LYRICS" in trackAPI:
|
||||
if "LYRICS_TEXT" in trackAPI["LYRICS"]:
|
||||
track['lyrics']['unsync'] = trackAPI["LYRICS"]["LYRICS_TEXT"]
|
||||
if "LYRICS_SYNC_JSON" in trackAPI["LYRICS"]:
|
||||
track['lyrics']['sync'] = ""
|
||||
for i in range(len(trackAPI["LYRICS"]["LYRICS_SYNC_JSON"])):
|
||||
if "lrc_timestamp" in trackAPI["LYRICS"]["LYRICS_SYNC_JSON"][i]:
|
||||
track['lyrics']['sync'] += trackAPI["LYRICS"]["LYRICS_SYNC_JSON"][i]["lrc_timestamp"] + trackAPI["LYRICS"]["LYRICS_SYNC_JSON"][i]["line"]+"\r\n"
|
||||
elif i+1 < len(trackAPI["LYRICS"]["LYRICS_SYNC_JSON"]):
|
||||
track['lyrics']['sync'] += trackAPI["LYRICS"]["LYRICS_SYNC_JSON"][i+1]["lrc_timestamp"] + trackAPI["LYRICS"]["LYRICS_SYNC_JSON"][i]["line"]+"\r\n"
|
||||
|
||||
track['mainArtist'] = {}
|
||||
track['mainArtist']['id'] = trackAPI['ART_ID']
|
||||
track['mainArtist']['name'] = trackAPI['ART_NAME']
|
||||
if 'ART_PICTURE' in trackAPI:
|
||||
track['mainArtist']['pic'] = trackAPI['ART_PICTURE']
|
||||
|
||||
if 'PHYSICAL_RELEASE_DATE' in trackAPI:
|
||||
track['date'] = {
|
||||
'day': trackAPI["PHYSICAL_RELEASE_DATE"][8:10],
|
||||
'month': trackAPI["PHYSICAL_RELEASE_DATE"][5:7],
|
||||
'year': trackAPI["PHYSICAL_RELEASE_DATE"][0:4]
|
||||
}
|
||||
|
||||
track['album'] = {}
|
||||
track['album']['id'] = trackAPI['ALB_ID']
|
||||
track['album']['title'] = trackAPI['ALB_TITLE']
|
||||
if 'ALB_PICTURE' in trackAPI:
|
||||
track['album']['pic'] = trackAPI['ALB_PICTURE']
|
||||
|
||||
try:
|
||||
albumAPI = dz.get_album(track['album']['id'])
|
||||
track['album']['artist'] = {
|
||||
'id': albumAPI['artist']['id'],
|
||||
'name': albumAPI['artist']['name'],
|
||||
'pic': albumAPI['artist']['picture_small'][46:-24]
|
||||
}
|
||||
track['album']['trackTotal'] = albumAPI['nb_tracks']
|
||||
track['album']['recordType'] = albumAPI['record_type']
|
||||
track['album']['barcode'] = albumAPI['upc'] if 'upc' in albumAPI else None
|
||||
track['album']['label'] = albumAPI['label'] if 'label' in albumAPI else None
|
||||
if not 'pic' in track['album']:
|
||||
track['album']['pic'] = albumAPI['cover_small'][43:-24]
|
||||
if 'release_date' in albumAPI:
|
||||
track['date'] = {
|
||||
'day': albumAPI["release_date"][8:10],
|
||||
'month': albumAPI["release_date"][5:7],
|
||||
'year': albumAPI["release_date"][0:4]
|
||||
}
|
||||
track['album']['genre'] = []
|
||||
if 'genres' in albumAPI and 'data' in albumAPI['genres'] and len(albumAPI['genres']['data'])>0:
|
||||
for genre in albumAPI['genres']['data']:
|
||||
track['album']['genre'].append(genre['name'])
|
||||
except APIError:
|
||||
albumAPI = dz.get_album_gw(track['album']['id'])
|
||||
track['album']['artist'] = {
|
||||
'id': albumAPI['ART_ID'],
|
||||
'name': albumAPI['ART_NAME']
|
||||
}
|
||||
track['album']['trackTotal'] = albumAPI['NUMBER_TRACK']
|
||||
track['album']['discTotal'] = albumAPI['NUMBER_DISK']
|
||||
track['album']['recordType'] = trackAPI['TYPE']
|
||||
track['album']['barcode'] = None
|
||||
track['album']['label'] = albumAPI['LABEL_NAME'] if 'LABEL_NAME' in albumAPI else None
|
||||
if not 'pic' in track['album']:
|
||||
track['album']['pic'] = albumAPI['ALB_PICTURE']
|
||||
if 'PHYSICAL_RELEASE_DATE' in albumAPI:
|
||||
track['date'] = {
|
||||
'day': albumAPI["PHYSICAL_RELEASE_DATE"][8:10],
|
||||
'month': albumAPI["PHYSICAL_RELEASE_DATE"][5:7],
|
||||
'year': albumAPI["PHYSICAL_RELEASE_DATE"][0:4]
|
||||
}
|
||||
track['album']['genre'] = []
|
||||
|
||||
trackAPI2 = dz.get_track(track['id'])
|
||||
track['bpm'] = trackAPI2['bpm']
|
||||
if not 'replayGain' in track:
|
||||
track['replayGain'] = "{0:.2f} dB".format((float(trackAPI2['gain']) + 18.4) * -1)
|
||||
if not 'explicit' in track:
|
||||
track['explicit'] = trackAPI2['explicit_lyrics']
|
||||
track['artist'] = {}
|
||||
track['artists'] = []
|
||||
for artist in trackAPI2['contributors']:
|
||||
track['artists'].append(artist['name'])
|
||||
if not artist['role'] in track['artist']:
|
||||
track['artist'][artist['role']] = []
|
||||
track['artist'][artist['role']].append(artist['name'])
|
||||
|
||||
if not 'discTotal' in track['album']:
|
||||
albumAPI2 = dz.get_album_gw(track['album']['id'])
|
||||
track['album']['discTotal'] = albumAPI2['NUMBER_DISK']
|
||||
return track
|
||||
|
||||
def downloadTrack(id, bitrate):
|
||||
# Get the metadata
|
||||
track = getTrackData(id)
|
||||
|
||||
# Get the selected bitrate
|
||||
bitrateFound = False;
|
||||
if int(bitrate) == 9:
|
||||
track['selectedFormat'] = 9
|
||||
track['selectedFilesize'] = track['filesize']['flac']
|
||||
if track['filesize']['flac'] > 0:
|
||||
bitrateFound = True
|
||||
else:
|
||||
bitrateFound = False
|
||||
bitrate = 3
|
||||
if int(bitrate) == 3:
|
||||
track['selectedFormat'] = 3
|
||||
track['selectedFilesize'] = track['filesize']['mp3_320']
|
||||
if track['filesize']['mp3_320'] > 0:
|
||||
bitrateFound = True
|
||||
else:
|
||||
bitrateFound = False
|
||||
bitrate = 1
|
||||
if int(bitrate) == 1:
|
||||
track['selectedFormat'] = 3
|
||||
track['selectedFilesize'] = track['filesize']['mp3_320']
|
||||
if track['filesize']['mp3_320'] > 0:
|
||||
bitrateFound = True
|
||||
else:
|
||||
bitrateFound = False
|
||||
if not bitrateFound:
|
||||
track['selectedFormat'] = 8
|
||||
track['selectedFilesize'] = track['filesize']['default']
|
||||
track['album']['bitrate'] = track['selectedFormat']
|
||||
|
||||
# Create the filename
|
||||
filename = "{artist} - {title}".format(title=track['title'], artist=track['mainArtist']['name'])+extensions[track['selectedFormat']]
|
||||
print(filename)
|
||||
|
||||
track['downloadUrl'] = dz.get_track_stream_url(track['id'], track['MD5'], track['mediaVersion'], track['selectedFormat'])
|
||||
with open(filename, 'wb') as stream:
|
||||
dz.stream_track(track['id'], track['downloadUrl'], stream)
|
||||
if track['selectedFormat'] in [3,1,8]:
|
||||
tagID3(filename, track)
|
||||
elif track['selectedFormat'] == 9:
|
||||
tagFLAC(filename, track)
|
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env python3
|
||||
import wx
|
||||
from deemix.app.functions import downloadTrack, getIDFromLink, getTypeFromLink
|
||||
|
||||
class MainFrame(wx.Frame):
|
||||
def __init__(self):
|
||||
super().__init__(parent=None, title='deemix')
|
||||
panel = wx.Panel(self)
|
||||
main_sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
search_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
main_sizer.Add(search_sizer, 0, wx.EXPAND, 5)
|
||||
self.text_ctrl = wx.TextCtrl(panel)
|
||||
search_sizer.Add(self.text_ctrl, 1, wx.ALL, 5)
|
||||
my_btn = wx.Button(panel, label='Download')
|
||||
my_btn.Bind(wx.EVT_BUTTON, self.downloadTrack)
|
||||
search_sizer.Add(my_btn, 0, wx.ALL, 5)
|
||||
panel.SetSizer(main_sizer)
|
||||
self.Show()
|
||||
|
||||
def downloadTrack(self, event):
|
||||
value = self.text_ctrl.GetValue()
|
||||
if not value:
|
||||
print("You didn't enter anything!")
|
||||
return None
|
||||
type = getTypeFromLink(value)
|
||||
id = getIDFromLink(value,type)
|
||||
print(type, id)
|
||||
if type == "track":
|
||||
downloadTrack(id,9)
|
||||
self.text_ctrl.SetValue("")
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env python3
|
||||
#Empty File
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env python3
|
||||
#Empty File
|
|
@ -0,0 +1,82 @@
|
|||
#!/usr/bin/env python3
|
||||
from mutagen.id3 import ID3, ID3NoHeaderError
|
||||
from mutagen.id3 import TXXX, TIT2, TPE1, TALB, TPE2, TRCK, TPOS, TCON, TYER, TDAT, TLEN, TBPM, TPUB, TSRC, USLT, APIC, IPLS, TCOM, TCOP, TCMP
|
||||
from mutagen.flac import FLAC, Picture
|
||||
from urllib.request import urlopen
|
||||
|
||||
def tagID3(stream, track):
|
||||
try:
|
||||
tag = ID3(stream)
|
||||
except ID3NoHeaderError:
|
||||
tag = ID3()
|
||||
|
||||
tag.add(TIT2(text=track['title']))
|
||||
tag.add(TPE1(text=track['artists']))
|
||||
tag.add(TALB(text=track['album']['title']))
|
||||
tag.add(TPE2(text=track['album']['artist']['name']))
|
||||
tag.add(TRCK(text=str(track['trackNumber'])))
|
||||
tag.add(TPOS(text=str(track['discNumber'])))
|
||||
tag.add(TCON(text=track['album']['genre']))
|
||||
tag.add(TYER(text=str(track['date']['year'])))
|
||||
tag.add(TDAT(text=str(track['date']['month'])+str(track['date']['day'])))
|
||||
tag.add(TLEN(text=str(track['duration'])))
|
||||
tag.add(TBPM(text=str(track['bpm'])))
|
||||
tag.add(TPUB(text=track['album']['label']))
|
||||
tag.add(TSRC(text=track['ISRC']))
|
||||
tag.add(TXXX(desc="BARCODE", text=track['album']['barcode']))
|
||||
tag.add(TXXX(desc="ITUNESADVISORY", text="1" if track['explicit'] else "0"))
|
||||
tag.add(TXXX(desc="REPLAYGAIN_TRACK_GAIN", text=track['replayGain']))
|
||||
if 'unsync' in track['lyrics']:
|
||||
tag.add(USLT(text=track['lyrics']['unsync']))
|
||||
involvedPeople = []
|
||||
for role in track['contributors']:
|
||||
if role in ['author', 'engineer', 'mixer', 'producer', 'writer']:
|
||||
for person in track['contributors'][role]:
|
||||
involvedPeople.append([role,person])
|
||||
elif role == 'composer':
|
||||
tag.add(TCOM(text=track['contributors']['composer']))
|
||||
if len(involvedPeople) > 0:
|
||||
tag.add(IPLS(people=involvedPeople))
|
||||
tag.add(TCOP(text=track['copyright']))
|
||||
|
||||
tag.add(APIC(3, 'image/jpeg', 3, data=urlopen("http://e-cdn-images.deezer.com/images/cover/"+track["album"]['pic']+"/800x800.jpg").read()))
|
||||
|
||||
tag.save(stream, v1=2, v2_version=3, v23_sep=None)
|
||||
|
||||
def tagFLAC(stream, track):
|
||||
tag = FLAC(stream)
|
||||
|
||||
tag["TITLE"] = track['title']
|
||||
tag["ARTIST"] = track['artists']
|
||||
tag["ALBUM"] = track['album']['title']
|
||||
tag["ALBUMARTIST"] = track['album']['artist']['name']
|
||||
tag["TRACKNUMBER"] = str(track['trackNumber'])
|
||||
tag["TRACKTOTAL"] = str(track['album']['trackTotal'])
|
||||
tag["DISCNUMBER"] = str(track['discNumber'])
|
||||
tag["DISCTOTAL"] = str(track['album']['discTotal'])
|
||||
tag["GENRE"] = track['album']['genre']
|
||||
tag["YEAR"] = str(track['date']['year'])
|
||||
tag["DATE"] = "{}-{}-{}".format(str(track['date']['year']), str(track['date']['month']), str(track['date']['day']))
|
||||
tag["LENGTH"] = str(track['duration'])
|
||||
tag["BPM"] = str(track['bpm'])
|
||||
tag["PUBLISHER"] = track['album']['label']
|
||||
tag["ISRC"] = track['ISRC']
|
||||
tag["BARCODE"] = track['album']['barcode']
|
||||
tag["ITUNESADVISORY"] = "1" if track['explicit'] else "0"
|
||||
tag["REPLAYGAIN_TRACK_GAIN"] = track['replayGain']
|
||||
if 'unsync' in track['lyrics']:
|
||||
tag["LYRICS"] = track['lyrics']['unsync']
|
||||
for role in track['contributors']:
|
||||
if role in ['author', 'engineer', 'mixer', 'producer', 'writer', 'composer']:
|
||||
tag[role.upper()] = track['contributors'][role]
|
||||
elif role == 'musicpublisher':
|
||||
tag["ORGANIZATION"] = track['contributors']['musicpublisher']
|
||||
tag["COPYRIGHT"] = track['copyright']
|
||||
|
||||
image = Picture()
|
||||
image.type = 3
|
||||
image.mime = 'image/jpeg'
|
||||
image.data = urlopen("http://e-cdn-images.deezer.com/images/cover/"+track["album"]['pic']+"/800x800.jpg").read()
|
||||
tag.add_picture(image)
|
||||
|
||||
tag.save(deleteid3=True)
|
Loading…
Reference in New Issue