Skip to content

Instantly share code, notes, and snippets.

@soardex
Created July 3, 2015 08:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save soardex/84c67472dee43a65e344 to your computer and use it in GitHub Desktop.
Save soardex/84c67472dee43a65e344 to your computer and use it in GitHub Desktop.
NetEase music.163.com
## from https://gist.github.com/scturtle/5972996
import re
import os
import sys
import md5
import json
import random
import requests
ENCODE = 'gbk' if sys.platform.startswith('win') else 'utf8'
CMD = 'axel -a -n 4 -o "{name}.mp3" "{url}"'
SEARCH = 'http://music.163.com/api/search/get/web'
DETAIL = 'http://music.163.com/api/song/detail/?ids=[{}]'
LRC = 'http://music.163.com/api/song/media?id={}'
HEADERS = {'Referer': 'http://music.163.com'}
MP3 = 'http://m{}.music.126.net/{}/{}.mp3'
class Json:
def __repr__(self):
return json.dumps(self.json, indent=2)
def json2obj(json):
if isinstance(json, dict):
obj = Json()
setattr(obj, 'json', json)
for k, v in json.items():
k = k.replace(' ', '_')
setattr(obj, k, json2obj(v))
return obj
if isinstance(json, list):
return map(json2obj, json)
return json
def search(q, tp=1):
'''
>>> search('2375').result.songs[0].id
365613
'''
return json2obj(requests.post(SEARCH, headers=HEADERS,
data=dict(type=tp, s=q, offset=0,
limit=30, total='true')
).json())
def searchAlbum(q):
return search(q, tp=10)
def searchArtist(q):
return search(q, tp=100)
def detail(sids):
'''
>>> detail([365613]).songs[0].name
u'2375'
'''
return json2obj(requests.get(DETAIL.format(','.join(map(str, sids))),
headers=HEADERS).json())
def url_2_sids(url):
'''
>>> url_2_sids('http://music.163.com/#/album?id=36197')
['365612', '365613', '365614', '365615', '365617']
'''
_id = url.split('=')[1]
if 'song?id' in url:
return [_id]
else:
r = requests.get(url.replace('/#/', '/'), headers=HEADERS)
return re.findall(r'song\?id=(\d+)', r.content)
def encrypted_id(id):
''' from https://github.com/yanunon/NeteaseCloudMusic '''
byte1 = bytearray('3go8&$8*3*3h0k(2)2')
byte2 = bytearray(id)
byte1_len = len(byte1)
for i in xrange(len(byte2)):
byte2[i] = byte2[i] ^ byte1[i % byte1_len]
m = md5.new()
m.update(byte2)
result = m.digest().encode('base64')[:-1]
result = result.replace('/', '_')
result = result.replace('+', '-')
return result
def download(sids, withlrc=False):
'''
>>> dfsId = str(detail([365613]).songs[0].bMusic.dfsId)
>>> MP3.format(1, encrypted_id(dfsId), dfsId)
'http://m1.music.126.net/n5usuzBfOxdzcGGnF_2hnQ==/2781764418296774.mp3'
'''
json = detail(sids)
for i in json.songs:
name = ''
for c in i.name:
try:
name += c.encode(ENCODE)
except:
pass
#url = i.mp3Url
dfsId = str(i.bMusic.dfsId)
url = MP3.format(random.randrange(1, 3), encrypted_id(dfsId), dfsId)
cc = os.system(CMD.format(name=name, url=url))
assert not cc, 'Interrupted'
if withlrc:
lrc = requests.get(LRC.format(i.id), headers=HEADERS).json()
lrc = json2obj(lrc)
if hasattr(lrc, 'lyric'):
open(name + '.lrc', 'w').write(lrc.lyric.encode('utf-8'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment