Skip to main content

简单明了地解析和生成 163key 字符串

Project description

简介

ncm-163key-parser 项目意图以简单明了的方式操纵网易云音乐歌曲标识符(即“163 key”)。

使用须知

本项目是以学习和技术研究的初衷创建的,修改、再分发时请遵循许可协议

本项目虽然可以读取网易云音乐加密文件格式 .ncm 中的标识符,但是不可也无法移除中音频数据的加密保护!如果你是为此而来,请自行搜索并尝试其他项目!

支持特性

  • 解析标识符为元数据。
  • (仅限 Python 调用)简明地编辑解析的元数据。
  • (仅限 Python 调用)将元数据还原为标识符。
  • 支持 PC 和 Android 平台的网易云音乐客户端下载的文件包含的标识符。
    • 是的,两个平台、不同版本的客户端下载的文件,包含的元数据不一致。
  • (等待实现)同时也是命令行工具,可用于直接读取和解析文件中的标识符。
    • 支持的文件类型包括:
      • 普通音频文件(.flac、.mp3)
      • 网易云音乐加密文件格式 .ncm(本项目不支持移除其音频的加密保护)
  • 纯 Python 实现,包括依赖包在内,没有任何 C 扩展模块,洁癖人士的不二之选。

安装

所需依赖

  • pyaes - AES 加解密
  • attrs - 工厂化构建属性类,被本项目用来构建元数据容器

获取方式

PyPI(推荐)

查看 PyPI 页面

或者在命令行使用 pip 下载安装:

$ > python -m pip install ncm-163key-parser

从本仓库获取

前往当前版本发布页,此处提供了 Wheel 包下载。

安装下载的 Wheel 包:

python -m pip install /path/to/ncm_163key_parser-[version]-py3-none-any.whl

使用方法

命令行工具(待实现)

Python 调用

以下是示例用法。如果想要玩出花样,请在使用时关注你使用的 IDE 对本模块函数、类和方法的提示信息,这样有助于你了解 API。

  • 导入模块
>>> import ncm163key
>>>

解析标识符

  • 使用 loads() 加载一个标识符,该函数可接受 str 或字节对象形式的标识符:

    >>> metadata1 = ncm163key.loads("163 key(Don't modify):...")
    >>> metadata1
    NCMMusicMetadataForAndroid(musicName='METHOD_HYMME_AMENOFLAME/.', musicId=471403213, artist={'stellatram': 12023150}, album='Kaleido Sphere ~天淵の双つ星~', albumId=35338410, albumPic='http://...', ...)
    >>> metadata2 = ncm163key.loads(b"163 key(Don't modify):...")
    >>> metadata2
    NCMMusicMetadataForPCv1NCM(musicName='忘れじの言の葉 (feat. 安次嶺希和子) [2022]', musicId=1972641406, artist={'未来古代楽団': 12131344, '安次嶺希和子': 30104787}, album='忘れじの言の葉/エデンの揺り籃', albumId=149778835, albumPic='https://...', ...)
    >>>
    
  • 如果使用了自定义的标识符加密密钥,通过参数 alter_id_key 传递给函数:

    >>> ncm163key.loads("163 key(Don't modify):...", alter_id_key=b'...')
    >>> ncm163key.loads(b"163 key(Don't modify):...", alter_id_key=b'...')
    >>>
    

查看解析出的元数据

以下列出了几种常用信息的获取方法。除非特殊说明,所有以“Id”结尾的属性都是 int 对象。

  • 歌曲名称和 ID

    • musicName - 歌曲名称(即标题)
    • musicId - 歌曲 ID
      • 注意:如果你的下载文件来源是网易云音乐 PC 端 3.0.0 及以上版本,musicId 将会是一个 str 而不是 int 对象。
    >>> metadata1.musicName
    'METHOD_HYMME_AMENOFLAME/.'
    >>> metadata1.musicId
    471403213
    >>>
    
  • 歌手列表和歌手 ID:

    • artist - 是一个定制的类字典对象,键(str)为歌手名称,值(int)为歌手 ID,会尝试自动转换被赋予的值
    • artist_prettify() - 根据 artist 生成的美化后的歌手列表,默认使用顿号“、”分割每个歌手名称
    >>> metadata1.artist
    {'stellatram': 12023150}
    >>> metadata1.artist_prettify()
    'stellatram'
    >>> metadata2.artist_prettify()
    '未来古代楽団、安次嶺希和子'
    >>> metadata2.artist_prettify(sep=' | ')
    '未来古代楽団 | 安次嶺希和子'
    >>>
    
  • 专辑名称、ID 和专辑封面链接:

    • album - 专辑名称
    • albumId - 专辑 ID
    • albumPic - 专辑封面下载链接
    >>> metadata1.album
    'Kaleido Sphere ~天淵の双つ星~'
    >>> metadata1.albumId
    35338410
    >>> metadata1.albumPic
    'http://p2.music.126.net/cPwdlJxGCtX0e2L3SMQksg==/18915998044327357.jpg'
    >>>
    
  • flac - 歌曲的音频格式

    >>> metadata1.format
    'flac'
    >>>
    
  • 歌曲时长

    • duration - 歌曲时长,单位为毫秒
    • duration_seconds(只读) - 歌曲时长,由 duration 除以 1000 得到,与 duration 同步变化,单位为秒
    >>> metadata.duration  # 单位为毫秒
    294026
    >>> metadata.duration_seconds  # metadata.duration_seconds 除以 1000,单位为秒
    294.026
    >>>
    

修改元数据

所有属性都是可修改的,但请注意,属性对类型甚至结构都有严格要求。以 bitratemetadata.artist 为例:

  • metadata.bitrate:仅接受非负整数。
>>> metadata.bitrate
984052
>>> metadata.bitrate = 1000000  # OK
>>> metadata.bitrate
1000000
>>> metadata.bitrate = '2000000'  # TypeError
Traceback (most recent call last):
...
TypeError: 'bitrate' must be <class 'int'> (got '2000000' that is a <class 'str'>).
>>> metadata.bitrate = -1000000  # ValueError
Traceback (most recent call last):
...
ValueError: 'bitrate' must be >= 0: -1000000
>>>
  • metadata.artist:仅接受可以转换为字典的对象;键必须是字符串,对应的值必须是整数,否则会引发 TypeError
>>> metadata1.artist
{'stellatram': 12023150}
>>> metadata1.artist['群星'] = 122455  # OK
>>> metadata1.artist
{'stellatram': 12023150, '群星': 122455}
>>> metadata1.artist = {
... 'stellatram': 12023150,
... '未来古代楽団': 12131344,
... '安次嶺希和子': 30104787
... }  # 尝试使用真正的字典对象为 artist 属性赋值,OK
>>> metadata.artist
{'stellatram': 12023150, '未来古代楽団': 12131344, '安次嶺希和子': 30104787}
>>> metadata.artist = 'stellatram'  # ValueError
Traceback (most recent call last):
...
ValueError: not enough values to unpack (expected 2, got 1)
>>> metadata.artist = 12023150  # TypeError
Traceback (most recent call last):
...
TypeError: 'artist' must be <class 'ncm163key._ArtistsMapping'> (got 12023150 that is a <class 'int'>).
>>> metadata.artist[12023150] = 12023150  # TypeError
Traceback (most recent call last):
...
TypeError: non-str object are not available for the mapping keys: 12023150 ('int')
>>> metadata1.artist['stellatram'] = '12023150'  # TypeError
Traceback (most recent call last):
...
TypeError: non-int object are not available for the mapping values: '12023150' ('str', key='stellatram')
>>>

将元数据还原为标识符

>>> ncm163key.dumps(metadata)
"163 key(Don't modify):..."
>>>
  • 如果要使用自定义的标识符加密密钥,通过参数 alter_id_key 传递给函数:
>>> ncm163key.dumps(metadata, alter_id_key=b'...')
b"163 key(Don't modify):..."
>>>

(可能的)常见问题

这个项目能输出 NCM 文件的音频内容吗?

不行,以后也不可能。下一个。

我没听说过 pyaes 这个包,为什么要用它做 AES 加解密,而不用 pycryptodome

标识符的加解密使用了 AES,没有其他加密方式,因此使用 pyaes 这种简单的 AES 算法实现就足够了,pycryptodome 这种大而全的加密算法库显得有些臃肿。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ncm-163key-parser-0.1.0.tar.gz (17.3 kB view hashes)

Uploaded Source

Built Distribution

ncm_163key_parser-0.1.0-py3-none-any.whl (13.9 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page