前几天发现网易云音乐的ncm格式很坑爹,由于网易云的部分音乐采取了这种流媒体平台模式,这种格式的歌曲下载到设备本地以后只有在网易云音乐的app上面才能播放,而且还要在会员生效期间才能播

今天网易云弄出一个ncm,明天百度音乐来一个cnm,后天酷狗推出nmb,大后天qq音乐又来了个rnm。目前国内的音乐版权可谓是乱到了一个极端,阿叉想听一个歌手的歌还得在酷狗和网易云之间来回跑,最终用户就成了受害者

花钱买的歌我们理所当然有权利支配,而不是短期的租借,所以在这里提供一个在尽量不影响音质的情况下将ncm格式转换成flac格式的方法

↓↓↓↓↓↓↓↓↓

(链接挂了的话就尽情骚扰阿叉的微信吧)

使用方法就是把要转换的ncm音乐文件直接拖到 格式转换.exe上

然后flac格式的音乐文件就会自己变出来啦

↑↑↑↑↑↑↑↑↑

以这首Sailing为例,经过转换以后得到了flac文件:

把成品导入AU之后可以发现高频部分还是很完整的,完全符合无损音质的表现

和来自某狗的原版flac对比:

可以明显看出,转码后高频部分没有被切掉,比特率都是968kbps,音质几乎没有区别,所以我们可以完美地完成无损到无损的转换

附上源代码和注释:

import binascii

import struct

import base64

import json

import os

from Crypto.Cipher import AES

def dump(file_path):

core_key = binascii.a2b_hex("687A4852416D736F356B496E62617857")

meta_key = binascii.a2b_hex("2331346C6A6B5F215C5D2630553C2728")

#core_key和meta_key,把这个字符串按照十六进制反解析为二进制字节序列(bytes类型)

unpad = lambda s : s[0:-(s[-1] if type(s[-1]) == int else ord(s[-1]))]

f = open(file_path,'rb')

header = f.read(8)

assert binascii.b2a_hex(header) == b'4354454e4644414d'

#打开ncm文件并读取8个字节,确认这8个字节是否是字节序列b'4354454e4644414d',0x43=C,所以这些字节是'CTENFDAM',说明这些就是ncm独有的文件标记

f.seek(2, 1)

key_length = f.read(4)

key_length = struct.unpack('

key_data = f.read(key_length)

key_data_array = bytearray(key_data)

for i in range (0,len(key_data_array)): key_data_array[i] ^= 0x64

#获取4字节的key,并且按照小端(

key_data = bytes(key_data_array)

cryptor = AES.new(core_key, AES.MODE_ECB)

key_data = unpad(cryptor.decrypt(key_data))[17:]

#然后用之前的core_key创建了AES_ECB解密器,将整个明文分成若干段相同的小段,然后对每一小段进行加密,如果不足则会进行补足。

cryptor.decrypt(key_data)解析出来的是:

b'neteasecloudmusic10073261712832E7fT49x7dof9OKCgg9cdvhEuezy3iZCL1nFvBFd1T4uSktAJKmwZXsijPbijliionVUXXg9plTbXEclAE9Lb\r\r\r\r\r\r\r\r\r\r\r\r\r'

key_length = len(key_data)

key_data = bytearray(key_data)

key_box = bytearray(range(256))

c = 0

last_byte = 0

key_offset = 0

for i in range(256):

swap = key_box[i]

c = (swap + last_byte + key_data[key_offset]) & 0xff

key_offset += 1

if key_offset >= key_length: key_offset = 0

key_box[i] = key_box[c]

key_box[c] = swap

last_byte = c

#标准RC4-KSA算法去计算S-box

meta_length = f.read(4)

meta_length = struct.unpack('

meta_data = f.read(meta_length)

meta_data_array = bytearray(meta_data)

for i in range(0,len(meta_data_array)): meta_data_array[i] ^= 0x63

meta_data = bytes(meta_data_array)

meta_data = base64.b64decode(meta_data[22:])

cryptor = AES.new(meta_key, AES.MODE_ECB)

meta_data = unpad(cryptor.decrypt(meta_data)).decode('utf-8')[6:]

meta_data = json.loads(meta_data)

#meta_data的值是这样的:

b"163key(Don't modify):L64FU3W4YxX3ZFTmbZ+8/fOGFX4ZDFzRxiE6WTSCw8Wbw8yYSVQFmAmCHw9A96ZnO0UOuMsVWYFWvoqD0/YcH3r7VAGU8B3l+FBJm4JL6is23S2yXChnSbfLIksnEUcTC7JtrA1JAoR0GVnz+OT3hGTJRsjGIVQXg2yide/YKBACffE+oYBApqZ5Isq0n7h/MlBnjn6ihuSlIl5V2rXEjSISQr031eSBdEVJ/JcwttzLafIPBh2FQfaVd/U0inWY5jxCXZCw/jxcIdGmGH/0Oft3UlNPt2kDBrsivoVuD03tMWL6A5Flg/jCbofSOblHFC79oU3WF9doUjD24BXuu6K7wyoWkgyG7SJu8tk72hkGw3rLK1nbTHsSEIPjocC6Ba9mzF48SB087MFTSn+9PXPZIboMXFXGI3TpMj4rR6cD+6CEWS7EoZrUC1cipi/A0jT/rFtAirM4hmkbrvslJumMHDJz1q9o6t3XRWydyoIaC3ktXuesyV8sbuoQ+Y/EMWNZRN3KhGR/jnnQPBtseQ=="

前面有22位的“163 key(Don't modify):”,去掉之后用base64解码,并同样地通过AES_ECB和meta_key进行解密:

b'music:{"musicId":441491828,"musicName":"\xe6\xb0\xb4\xe6\x98\x9f\xe8\xae\xb0","artist":[["\xe9\x83\xad\xe9\xa1\xb6",2843]],"albumId":35005583,"album":"\xe9\xa3\x9e\xe8\xa1\x8c\xe5\x99\xa8\xe7\x9a\x84\xe6\x89\xa7\xe8\xa1\x8c\xe5\x91\xa8\xe6\x9c\x9f","albumPicDocId":2946691248081599,"albumPic":"https://p4.music.126.net/wSMfGvFzOAYRU_yVIfquAA==/2946691248081599.jpg","bitrate":320000,"mp3DocId":"668809cf9ba99c3b7cc51ae17a66027f","duration":325266,"mvId":5404031,"alias":[],"transNames":[],"format":"mp3"}\r\r\r\r\r\r\r\r\r\r\r\r\r'

去掉前面的 music: ,然后转为json字典,可以得到一些歌曲原本的信息,比如歌手,歌名之类的

crc32 = f.read(4)

crc32 = struct.unpack('

f.seek(5, 1)

image_size = f.read(4)

image_size = struct.unpack('

image_data = f.read(image_size)

file_name = meta_data['musicName'] + '.' + meta_data['format']

m = open(os.path.join(os.path.split(file_path)[0],file_name),'wb')

chunk = bytearray()

while True:

chunk = bytearray(f.read(0x8000))

chunk_length = len(chunk)

if not chunk:

break

for i in range(1,chunk_length+1):

j = i & 0xff;

chunk[i-1] ^= key_box[(key_box[j] + key_box[(key_box[j] + j) & 0xff]) & 0xff]

m.write(chunk)

m.close()

f.close()

#用修改后的RC4-PRGA算法进行还原并输出新的歌曲文件,得到flac的原本数据

if __name__ == '__main__':

import sys

if len(sys.argv) > 1:

for file_path in sys.argv[1:]:

try:

dump(file_path)

except:

pass

else:

print("Usage: python ncm_transformation.py \"File Name\"")

另:这个是git上一个大神弄的,看得懂的可以看一下,好像比这个要复杂点

https://github.com/nondanee/ncmdump

qq音乐专属格式转换_将网易云音乐专用的无损音乐格式转换成全平台通用的无损格式...相关推荐

  1. unreal无损音乐百度云_将网易云音乐专用的无损音乐格式转换成全平台通用的无损格式...

    前几天发现网易云音乐的ncm格式很坑爹,由于网易云的部分音乐采取了这种流媒体平台模式,这种格式的歌曲下载到设备本地以后只有在网易云音乐的app上面才能播放,而且还要在会员生效期间才能播 今天网易云弄出 ...

  2. 音乐APP攻防战:QQ、酷狗、酷我、网易云,谁会成为下一个虾米?

    作为最能进入人心的"声音",音乐早已成为人们生活中不可缺少的一部分. 随着互联网技术的发展与智能手机的普及,在线音乐成为数字经济的主要模式之一.据<2020中国音乐产业发展报 ...

  3. 音乐竞品分析:酷狗、QQ音乐、网易云、酷我、汽水音乐

    一.市场趋势         根据<2020年中国音乐产业发展研究报告--数字篇>可知, 随着我国国民经济的持续发展,居民可支配收入稳步上涨,文化娱乐消费在居民日常生活中的重要程度亦相应地 ...

  4. 音乐无界限,听见好时光—网易云音乐Linux版震撼来袭!

    为了带来更好的音乐体验,实现对音乐高品质的追求,经过网易云音乐与深度科技团队长达半年多的联合开发,大家期待已久的网易云音乐正式登陆 Linux 平台! 网易云音乐是一款专注于发现与分享的音乐产品,依托 ...

  5. 网易云音乐评论墙php源码,网易云音乐热评墙那些令人感慨的句子,哪一句打动了你?...

    越来越多的人开始使用网易云音乐来听歌了,套用某位网友的一句话就是:"我来网易云不是来听音乐的,我是来看评论的!网易云的评论区一直是情感泛滥的"重灾区",这里有大家口耳相传 ...

  6. 网易云音乐称酷狗抄袭计算机,网易云音乐称酷狗抄袭 双方有何恩怨?

    来源标题:网易云音乐谴责酷狗音乐"山寨"其推歌功能.页面设计等 2月2日,网易云音乐在官方微博发布致酷狗音乐的公告,声明酷狗音乐平台"山寨"网易云平台上&quo ...

  7. html网易云音乐图片轮播效果,看网易云音乐如何在界面设计中突出特色功能

    一般观念中一款产品的功能越具特色就会放在越突出的位置,但是如果一款产品层级较深,底层架构复杂导致若干功能优先级并列,那在UI设计中如何做到强化和弱化呢? 作为网易云音乐陈年老粉,不得不说这款产品做的真 ...

  8. Java 使用HttpURLConnection获取网易云(我喜欢的音乐)歌单内歌曲

    Java 使用HttpURLConnection获取网易云(我喜欢的音乐)歌单歌单内歌曲 1.HttpURLConnection简介 2.前期准备 2.1 目标url 2.2 歌曲ID获得 2.3 u ...

  9. 速领!抗疫大礼包(含QQ音乐、全民K歌、网易云音乐等等)

    腾讯系和网易系推出了抗疫礼包 都是免费领取,数量有限,大家抓紧哈! 腾讯系包括QQ音乐周卡.全民K歌周卡.腾讯视频周卡 网易系包括网易云音乐月卡.网易严选季卡.网易邮箱月卡.有道云笔记月卡 领取路径: ...

  10. 网易云api如何调用_分析网易云音乐API的经历

    在做qq机器人的时候想加入点歌功能,虽然自带一个点歌插件,但是只能分享QQ音乐,所以我想着自己写一个网易云音乐的. 首先打开网易云音乐的搜索界面,F12打开开发者工具并切换到Network. 随便搜索 ...

最新文章

  1. 四十六、文件系统的层次结构
  2. HTML5新增的一些特性
  3. 总结获取原生JS(javascript)的父节点、子节点、兄弟节点
  4. UML分析AsyncDisplayKit框架-ASMuplexImageNode异步下载时序图。
  5. python:对list去重
  6. 让数据中台飞起来—— Quick BI性能优化解决方案及实践
  7. Image Cup,我和几位师兄一起奋战!
  8. 根据id获取多维数组路径_clickhouse数据模型之用户路径分析
  9. Spring框架零基础学习(一):IOC|DI、AOP
  10. 数据可视化—第七次人口普查数据分析(基于d3.js)
  11. 2016,云计算行业走向何方?
  12. 《云计算技术与应用基础》课程标准
  13. Mangos地区代码
  14. java 提交mac地址栏_Mac系统快捷键大全 - 米扑博客
  15. untiy实现文本滚动
  16. 移动硬盘新加卷变为本地磁盘且不能打开磁盘查看文件
  17. char(10)和nchar(10)的区别
  18. ResNet 阅读学习和实现
  19. PyTorch 入门实战(五)——2013kaggle比赛 猫狗大战的实现
  20. python处理音频的软件_『开发技巧』Python音频操作工具PyAudio上手教程

热门文章

  1. C语言例题——简易秒表
  2. php字符串去重和去空,php去空格
  3. 加工机械双探头高频读写器CK-FR102AN用户开发手册
  4. 2017美赛A题论文阅读笔记
  5. C/C++经典项目开发:教你破解Windows系统密码,手把手教你做解密项目
  6. BP神经网络及其app设计
  7. 智慧体育训练考核系统软件-智能体能综合测评系统
  8. (重读)JavaScript高级程序设计第四版
  9. Android实现保存图片和视频到系统相册
  10. 机器人词库 python字典_('python,2017-robot-编程字典',)