1.Ubuntu版的网易云音乐已经懒得加密了吗…名字里甚至都已经带了md5码的加密方法…
╰─$ ls ~/.cache/netease-cloud-music/CachedSongs
567602-128-55881971d77b3ec1a5a134e2670a72e7.mp3
2.如果是windows或Android,需要借助Python脚本解密加密了的缓存文件
解密用Python脚本来源:https://github.com/mbinary/netease-cached-music
使用方法:
将缓存文件放到脚本文件所在目录下,在python3中运行该脚本。解密结果会输出到”cached_网易云音乐“目录下。
以下为解密用脚本:(注:因为Python2.7对UTF8编码的支持问题,需要Python3或以上版本)
#coding : utf-8
import os
import sys
import glob
import requests
DESDIR = './cached_网易云音乐'
LRCDIR = os.path.join(DESDIR, 'lyric')
MSCDIR = os.path.join(DESDIR, 'music')
API = 'https://api.imjad.cn/cloudmusic/?'
# two args: id type
# type=song, lyric, comments, detail, artist, album, search
# eg API = 'https://api.imjad.cn/cloudmusic/?type=song&id=1234132' download music
hasModu = False
try:
from mutagen.easyid3 import EasyID3
from mutagen.mp3 import MP3
hasModu = True
except:
pass
def safeprint(s):
'''deal with invalid encoded filename'''
try:
print(s)
except:
print(repr(s)[1:-1])
class netease_music:
def __init__(self, path=''):
'''path is the direcoty that contains Music files(cached)'''
if path == '':
path = input('input the path of cached netease_music')
self.path = path
safeprint('[+] Current Path: ' + path)
os.chdir(path)
self.files = glob.glob('*.uc') + glob.glob('*.uc!')
self.id_mp = {}
for i in self.files:
self.id_mp[self.getId(i)] = i
if not os.path.exists(DESDIR):
os.mkdir(DESDIR)
if not os.path.exists(LRCDIR):
os.mkdir(LRCDIR)
if not os.path.exists(MSCDIR):
os.mkdir(MSCDIR)
# import re
# self.nameXpath ='//div[@class="tit"]/em[@class="f-ff2"]/text()'
# self.lrcSentencePt=re.compile(r'\[\d+:\d+\.\d+\](.*?)\\n') # wrong (r'\[\d+,\d+\](\(\d+,\d+\)(\w))+\n')
def getId(self, name):
return name[:name.find('-')]
def getInfoFromWeb(self, musicId):
dic = {}
url = API+'type=detail&id=' + musicId
info = requests.get(url).json()['songs'][0]
dic['artist'] = [info['ar'][0]['name']]
dic['title'] = [info['name']]
dic['cover'] = [info['al']['picUrl']]
return dic
def getInfoFromFile(self, path):
if not os.path.exists(path):
safeprint('Can not find file ' + path)
return {}
elif hasModu:
return dict(MP3(path, ID3=EasyID3))
else:
print('[Error] You can use pip3 to install mutagen or connet to the Internet')
raise Exception('Failed to get info of ' + path)
def getPath(self, dic,musicId):
title = dic['title'][0]
artist = dic['artist'][0]
if artist in title:
title = title.replace(artist, '').strip()
name = (title + '--' + artist)
for i in '>?*/\:"|<':
name = name.replace(i,'-') # form valid file name
self.id_mp[musicId] = name
#print('''{{title: "{title}",artist: "{artist}",mp3: "http://ounix1xcw.bkt.clouddn.com/{name}.mp3",cover: "{cover}",}},'''\
#.format(title = title,name = name,artist=artist,cover=dic['cover'][0]))
return os.path.join(MSCDIR, name + '.mp3')
def decrypt(self, cachePath):
musicId = self.getId(cachePath)
idpath = os.path.join(MSCDIR, musicId + '.mp3')
try: # from web
dic = self.getInfoFromWeb(musicId)
path = self.getPath(dic,musicId)
if os.path.exists(path): return
with open(path,'wb') as f:
f.write(bytes(self._decrypt(cachePath)))
except Exception as e: # from file
print(e)
if not os.path.exists(idpath):
with open(idpath,'wb') as f:
f.write(bytes(self._decrypt(cachePath)))
dic = self.getInfoFromFile(idpath)
path = getPath(dic,musicId)
if os.path.exists(path):
os.remove(idpath)
return
os.rename(idpath, path)
def _decrypt(self,cachePath):
with open(cachePath, 'rb') as f:
btay = bytearray(f.read())
for i, j in enumerate(btay):
btay[i] = j ^ 0xa3
return btay
def getLyric(self, musicId):
name = self.id_mp[musicId]
url = API + 'type=lyric&id=' + musicId
url2 = 'https://music.163.com/api/song/lyric?id='+ musicId +'&lv=1&kv=1&tv=-1'
try:
lrc = requests.get(url).json()['lrc']['lyric']
if lrc=='':
lrc = requests.get(url2).json()['lrc']['lyric']
if lrc=='':
raise Exception('')
file = os.path.join(LRCDIR, name + '.lrc')
if not os.path.exists(file):
with open(file, 'w', encoding='utf8') as f:
f.write(str(lrc))
except Exception as e:
print(e,end='')
safeprint(': Failed to get lyric of music '+name)
def getMusic(self):
for ct, cachePath in enumerate(self.files):
self.decrypt(cachePath)
musicId = self.getId(cachePath)
print('[{}]'.format(ct+1).ljust(5)+self.id_mp[musicId])
self.getLyric(musicId)
if __name__ == '__main__':
if len(sys.argv) > 1:
path = sys.argv[1].strip()
else:
path = os.path.join(os.getcwd(), '.')
handler = netease_music(path)
handler.getMusic()