ncm-163key-parser


Namencm-163key-parser JSON
Version 0.1.0 PyPI version JSON
download
home_page
Summary简单明了地解析和生成 163key 字符串
upload_time2023-06-29 08:35:34
maintainer
docs_urlNone
authornukemiko
requires_python>=3.9
licenseCopyright 2023 nukemiko Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords netease 163 163key cloudmusic ncm
VCS
bugtrack_url
requirements attrs pyaes
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 简介

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

# 使用须知

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

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

# 支持特性

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

# 安装

## 所需依赖

-   [`pyaes`](https://pypi.org/project/pyaes) - AES 加解密
-   [`attrs`](https://pypi.org/project/attrs) - 工厂化构建属性类,被本项目用来构建元数据容器

## 获取方式

### PyPI(推荐)

[查看 PyPI 页面](https://pypi.org/project/ncm-163key-parser/)

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

```sh-session
$ > python -m pip install ncm-163key-parser
```

### 从本仓库获取

[前往当前版本发布页](https://github.com/nukemiko/ncm-163key-parser/releases/latest),此处提供了 Wheel 包下载。

安装下载的 Wheel 包:

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

# 使用方法

## 命令行工具(待实现)

## Python 调用

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

-   导入模块

```pycon
>>> import ncm163key
>>>
```

### 解析标识符

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

    ```pycon
    >>> 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` 传递给函数:

    ```pycon
    >>> 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` 对象。

    ```pycon
    >>> metadata1.musicName
    'METHOD_HYMME_AMENOFLAME/.'
    >>> metadata1.musicId
    471403213
    >>>
    ```

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

    -   `album` - 专辑名称
    -   `albumId` - 专辑 ID
    -   `albumPic` - 专辑封面下载链接

    ```pycon
    >>> metadata1.album
    'Kaleido Sphere ~天淵の双つ星~'
    >>> metadata1.albumId
    35338410
    >>> metadata1.albumPic
    'http://p2.music.126.net/cPwdlJxGCtX0e2L3SMQksg==/18915998044327357.jpg'
    >>>
    ```

-   `flac` - 歌曲的音频格式
    ```pycon
    >>> metadata1.format
    'flac'
    >>>
    ```
-   歌曲时长
    -   `duration` - 歌曲时长,单位为毫秒
    -   `duration_seconds`(只读) - 歌曲时长,由 `duration` 除以 1000 得到,与 `duration` 同步变化,单位为秒
    ```pycon
    >>> metadata.duration  # 单位为毫秒
    294026
    >>> metadata.duration_seconds  # metadata.duration_seconds 除以 1000,单位为秒
    294.026
    >>>
    ```

### 修改元数据

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

-   `metadata.bitrate`:仅接受非负整数。

```pycon
>>> 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`。

```pycon
>>> 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')
>>>
```

### 将元数据还原为标识符

```pycon
>>> ncm163key.dumps(metadata)
"163 key(Don't modify):..."
>>>
```

-   如果要使用自定义的标识符加密密钥,通过参数 `alter_id_key` 传递给函数:

```pycon
>>> ncm163key.dumps(metadata, alter_id_key=b'...')
b"163 key(Don't modify):..."
>>>
```

# (可能的)常见问题

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

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

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

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

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "ncm-163key-parser",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": "",
    "keywords": "netease,163,163key,cloudmusic,ncm",
    "author": "nukemiko",
    "author_email": "",
    "download_url": "https://files.pythonhosted.org/packages/ed/7b/96ee0e3fdd1197a4a2d552afe4af6f74ca0bcac989da1e0cbeac931ab017/ncm-163key-parser-0.1.0.tar.gz",
    "platform": null,
    "description": "# \u7b80\u4ecb\n\n`ncm-163key-parser` \u9879\u76ee\u610f\u56fe\u4ee5\u7b80\u5355\u660e\u4e86\u7684\u65b9\u5f0f\u64cd\u7eb5\u7f51\u6613\u4e91\u97f3\u4e50\u6b4c\u66f2\u6807\u8bc6\u7b26\uff08\u5373\u201c163 key\u201d\uff09\u3002\n\n# \u4f7f\u7528\u987b\u77e5\n\n\u672c\u9879\u76ee\u662f\u4ee5\u5b66\u4e60\u548c\u6280\u672f\u7814\u7a76\u7684\u521d\u8877\u521b\u5efa\u7684\uff0c\u4fee\u6539\u3001\u518d\u5206\u53d1\u65f6\u8bf7\u9075\u5faa[\u8bb8\u53ef\u534f\u8bae](LICENSE)\u3002\n\n**\u672c\u9879\u76ee\u867d\u7136\u53ef\u4ee5\u8bfb\u53d6\u7f51\u6613\u4e91\u97f3\u4e50\u52a0\u5bc6\u6587\u4ef6\u683c\u5f0f `.ncm` \u4e2d\u7684\u6807\u8bc6\u7b26\uff0c\u4f46\u662f\u4e0d\u53ef\u4e5f\u65e0\u6cd5\u79fb\u9664\u4e2d\u97f3\u9891\u6570\u636e\u7684\u52a0\u5bc6\u4fdd\u62a4\uff01\u5982\u679c\u4f60\u662f\u4e3a\u6b64\u800c\u6765\uff0c\u8bf7\u81ea\u884c\u641c\u7d22\u5e76\u5c1d\u8bd5\u5176\u4ed6\u9879\u76ee\uff01**\n\n# \u652f\u6301\u7279\u6027\n\n-   [x] \u89e3\u6790\u6807\u8bc6\u7b26\u4e3a\u5143\u6570\u636e\u3002\n-   [x] \uff08\u4ec5\u9650 Python \u8c03\u7528\uff09\u7b80\u660e\u5730\u7f16\u8f91\u89e3\u6790\u7684\u5143\u6570\u636e\u3002\n-   [x] \uff08\u4ec5\u9650 Python \u8c03\u7528\uff09\u5c06\u5143\u6570\u636e\u8fd8\u539f\u4e3a\u6807\u8bc6\u7b26\u3002\n-   [x] \u652f\u6301 PC \u548c Android \u5e73\u53f0\u7684\u7f51\u6613\u4e91\u97f3\u4e50\u5ba2\u6237\u7aef\u4e0b\u8f7d\u7684\u6587\u4ef6\u5305\u542b\u7684\u6807\u8bc6\u7b26\u3002\n    -   \u662f\u7684\uff0c\u4e24\u4e2a\u5e73\u53f0\u3001\u4e0d\u540c\u7248\u672c\u7684\u5ba2\u6237\u7aef\u4e0b\u8f7d\u7684\u6587\u4ef6\uff0c\u5305\u542b\u7684\u5143\u6570\u636e\u4e0d\u4e00\u81f4\u3002\n-   [ ] \uff08\u7b49\u5f85\u5b9e\u73b0\uff09\u540c\u65f6\u4e5f\u662f\u547d\u4ee4\u884c\u5de5\u5177\uff0c\u53ef\u7528\u4e8e\u76f4\u63a5\u8bfb\u53d6\u548c\u89e3\u6790\u6587\u4ef6\u4e2d\u7684\u6807\u8bc6\u7b26\u3002\n    -   \u652f\u6301\u7684\u6587\u4ef6\u7c7b\u578b\u5305\u62ec\uff1a\n        -   \u666e\u901a\u97f3\u9891\u6587\u4ef6\uff08.flac\u3001.mp3\uff09\n        -   \u7f51\u6613\u4e91\u97f3\u4e50\u52a0\u5bc6\u6587\u4ef6\u683c\u5f0f `.ncm`\u3002**\uff08\u672c\u9879\u76ee\u4e0d\u652f\u6301\u79fb\u9664\u5176\u97f3\u9891\u7684\u52a0\u5bc6\u4fdd\u62a4\uff09**\n-   [x] \u7eaf Python \u5b9e\u73b0\uff0c\u5305\u62ec\u4f9d\u8d56\u5305\u5728\u5185\uff0c\u6ca1\u6709\u4efb\u4f55 C \u6269\u5c55\u6a21\u5757\uff0c\u6d01\u7656\u4eba\u58eb\u7684\u4e0d\u4e8c\u4e4b\u9009\u3002\n\n# \u5b89\u88c5\n\n## \u6240\u9700\u4f9d\u8d56\n\n-   [`pyaes`](https://pypi.org/project/pyaes) - AES \u52a0\u89e3\u5bc6\n-   [`attrs`](https://pypi.org/project/attrs) - \u5de5\u5382\u5316\u6784\u5efa\u5c5e\u6027\u7c7b\uff0c\u88ab\u672c\u9879\u76ee\u7528\u6765\u6784\u5efa\u5143\u6570\u636e\u5bb9\u5668\n\n## \u83b7\u53d6\u65b9\u5f0f\n\n### PyPI\uff08\u63a8\u8350\uff09\n\n[\u67e5\u770b PyPI \u9875\u9762](https://pypi.org/project/ncm-163key-parser/)\n\n\u6216\u8005\u5728\u547d\u4ee4\u884c\u4f7f\u7528 `pip` \u4e0b\u8f7d\u5b89\u88c5\uff1a\n\n```sh-session\n$ > python -m pip install ncm-163key-parser\n```\n\n### \u4ece\u672c\u4ed3\u5e93\u83b7\u53d6\n\n[\u524d\u5f80\u5f53\u524d\u7248\u672c\u53d1\u5e03\u9875](https://github.com/nukemiko/ncm-163key-parser/releases/latest)\uff0c\u6b64\u5904\u63d0\u4f9b\u4e86 Wheel \u5305\u4e0b\u8f7d\u3002\n\n\u5b89\u88c5\u4e0b\u8f7d\u7684 Wheel \u5305\uff1a\n\n```sh-session\npython -m pip install /path/to/ncm_163key_parser-[version]-py3-none-any.whl\n```\n\n# \u4f7f\u7528\u65b9\u6cd5\n\n## \u547d\u4ee4\u884c\u5de5\u5177\uff08\u5f85\u5b9e\u73b0\uff09\n\n## Python \u8c03\u7528\n\n\u4ee5\u4e0b\u662f\u793a\u4f8b\u7528\u6cd5\u3002\u5982\u679c\u60f3\u8981\u73a9\u51fa\u82b1\u6837\uff0c\u8bf7\u5728\u4f7f\u7528\u65f6\u5173\u6ce8\u4f60\u4f7f\u7528\u7684 IDE \u5bf9\u672c\u6a21\u5757\u51fd\u6570\u3001\u7c7b\u548c\u65b9\u6cd5\u7684\u63d0\u793a\u4fe1\u606f\uff0c\u8fd9\u6837\u6709\u52a9\u4e8e\u4f60\u4e86\u89e3 API\u3002\n\n-   \u5bfc\u5165\u6a21\u5757\n\n```pycon\n>>> import ncm163key\n>>>\n```\n\n### \u89e3\u6790\u6807\u8bc6\u7b26\n\n-   \u4f7f\u7528 `loads()` \u52a0\u8f7d\u4e00\u4e2a\u6807\u8bc6\u7b26\uff0c\u8be5\u51fd\u6570\u53ef\u63a5\u53d7 `str` \u6216\u5b57\u8282\u5bf9\u8c61\u5f62\u5f0f\u7684\u6807\u8bc6\u7b26\uff1a\n\n    ```pycon\n    >>> metadata1 = ncm163key.loads(\"163 key(Don't modify):...\")\n    >>> metadata1\n    NCMMusicMetadataForAndroid(musicName='METHOD_HYMME_AMENOFLAME/.', musicId=471403213, artist={'stellatram': 12023150}, album='Kaleido Sphere \uff5e\u5929\u6df5\u306e\u53cc\u3064\u661f\uff5e', albumId=35338410, albumPic='http://...', ...)\n    >>> metadata2 = ncm163key.loads(b\"163 key(Don't modify):...\")\n    >>> metadata2\n    NCMMusicMetadataForPCv1NCM(musicName='\u5fd8\u308c\u3058\u306e\u8a00\u306e\u8449 (feat. \u5b89\u6b21\u5dba\u5e0c\u548c\u5b50) [2022]', musicId=1972641406, artist={'\u672a\u6765\u53e4\u4ee3\u697d\u56e3': 12131344, '\u5b89\u6b21\u5dba\u5e0c\u548c\u5b50': 30104787}, album='\u5fd8\u308c\u3058\u306e\u8a00\u306e\u8449\uff0f\u30a8\u30c7\u30f3\u306e\u63fa\u308a\u7c43', albumId=149778835, albumPic='https://...', ...)\n    >>>\n    ```\n\n-   \u5982\u679c\u4f7f\u7528\u4e86\u81ea\u5b9a\u4e49\u7684\u6807\u8bc6\u7b26\u52a0\u5bc6\u5bc6\u94a5\uff0c\u901a\u8fc7\u53c2\u6570 `alter_id_key` \u4f20\u9012\u7ed9\u51fd\u6570\uff1a\n\n    ```pycon\n    >>> ncm163key.loads(\"163 key(Don't modify):...\", alter_id_key=b'...')\n    >>> ncm163key.loads(b\"163 key(Don't modify):...\", alter_id_key=b'...')\n    >>>\n    ```\n\n### \u67e5\u770b\u89e3\u6790\u51fa\u7684\u5143\u6570\u636e\n\n\u4ee5\u4e0b\u5217\u51fa\u4e86\u51e0\u79cd\u5e38\u7528\u4fe1\u606f\u7684\u83b7\u53d6\u65b9\u6cd5\u3002\u9664\u975e\u7279\u6b8a\u8bf4\u660e\uff0c\u6240\u6709\u4ee5\u201cId\u201d\u7ed3\u5c3e\u7684\u5c5e\u6027\u90fd\u662f `int` \u5bf9\u8c61\u3002\n\n-   \u6b4c\u66f2\u540d\u79f0\u548c ID\n\n    -   `musicName` - \u6b4c\u66f2\u540d\u79f0\uff08\u5373\u6807\u9898\uff09\n    -   `musicId` - \u6b4c\u66f2 ID\n        -   \u6ce8\u610f\uff1a\u5982\u679c\u4f60\u7684\u4e0b\u8f7d\u6587\u4ef6\u6765\u6e90\u662f\u7f51\u6613\u4e91\u97f3\u4e50 PC \u7aef 3.0.0 \u53ca\u4ee5\u4e0a\u7248\u672c\uff0c`musicId` \u5c06\u4f1a\u662f\u4e00\u4e2a `str` \u800c\u4e0d\u662f `int` \u5bf9\u8c61\u3002\n\n    ```pycon\n    >>> metadata1.musicName\n    'METHOD_HYMME_AMENOFLAME/.'\n    >>> metadata1.musicId\n    471403213\n    >>>\n    ```\n\n-   \u6b4c\u624b\u5217\u8868\u548c\u6b4c\u624b ID\uff1a\n    -   `artist` - \u662f\u4e00\u4e2a\u5b9a\u5236\u7684\u7c7b\u5b57\u5178\u5bf9\u8c61\uff0c\u952e\uff08str\uff09\u4e3a\u6b4c\u624b\u540d\u79f0\uff0c\u503c\uff08int\uff09\u4e3a\u6b4c\u624b ID\uff0c\u4f1a\u5c1d\u8bd5\u81ea\u52a8\u8f6c\u6362\u88ab\u8d4b\u4e88\u7684\u503c\n    -   `artist_prettify()` - \u6839\u636e `artist` \u751f\u6210\u7684\u7f8e\u5316\u540e\u7684\u6b4c\u624b\u5217\u8868\uff0c\u9ed8\u8ba4\u4f7f\u7528\u987f\u53f7\u201c\u3001\u201d\u5206\u5272\u6bcf\u4e2a\u6b4c\u624b\u540d\u79f0\n    ```pycon\n    >>> metadata1.artist\n    {'stellatram': 12023150}\n    >>> metadata1.artist_prettify()\n    'stellatram'\n    >>> metadata2.artist_prettify()\n    '\u672a\u6765\u53e4\u4ee3\u697d\u56e3\u3001\u5b89\u6b21\u5dba\u5e0c\u548c\u5b50'\n    >>> metadata2.artist_prettify(sep=' | ')\n    '\u672a\u6765\u53e4\u4ee3\u697d\u56e3 | \u5b89\u6b21\u5dba\u5e0c\u548c\u5b50'\n    >>>\n    ```\n-   \u4e13\u8f91\u540d\u79f0\u3001ID \u548c\u4e13\u8f91\u5c01\u9762\u94fe\u63a5\uff1a\n\n    -   `album` - \u4e13\u8f91\u540d\u79f0\n    -   `albumId` - \u4e13\u8f91 ID\n    -   `albumPic` - \u4e13\u8f91\u5c01\u9762\u4e0b\u8f7d\u94fe\u63a5\n\n    ```pycon\n    >>> metadata1.album\n    'Kaleido Sphere \uff5e\u5929\u6df5\u306e\u53cc\u3064\u661f\uff5e'\n    >>> metadata1.albumId\n    35338410\n    >>> metadata1.albumPic\n    'http://p2.music.126.net/cPwdlJxGCtX0e2L3SMQksg==/18915998044327357.jpg'\n    >>>\n    ```\n\n-   `flac` - \u6b4c\u66f2\u7684\u97f3\u9891\u683c\u5f0f\n    ```pycon\n    >>> metadata1.format\n    'flac'\n    >>>\n    ```\n-   \u6b4c\u66f2\u65f6\u957f\n    -   `duration` - \u6b4c\u66f2\u65f6\u957f\uff0c\u5355\u4f4d\u4e3a\u6beb\u79d2\n    -   `duration_seconds`\uff08\u53ea\u8bfb\uff09 - \u6b4c\u66f2\u65f6\u957f\uff0c\u7531 `duration` \u9664\u4ee5 1000 \u5f97\u5230\uff0c\u4e0e `duration` \u540c\u6b65\u53d8\u5316\uff0c\u5355\u4f4d\u4e3a\u79d2\n    ```pycon\n    >>> metadata.duration  # \u5355\u4f4d\u4e3a\u6beb\u79d2\n    294026\n    >>> metadata.duration_seconds  # metadata.duration_seconds \u9664\u4ee5 1000\uff0c\u5355\u4f4d\u4e3a\u79d2\n    294.026\n    >>>\n    ```\n\n### \u4fee\u6539\u5143\u6570\u636e\n\n\u6240\u6709\u5c5e\u6027\u90fd\u662f\u53ef\u4fee\u6539\u7684\uff0c\u4f46\u8bf7\u6ce8\u610f\uff0c\u5c5e\u6027\u5bf9\u7c7b\u578b\u751a\u81f3\u7ed3\u6784\u90fd\u6709\u4e25\u683c\u8981\u6c42\u3002\u4ee5 `bitrate` \u548c `metadata.artist` \u4e3a\u4f8b\uff1a\n\n-   `metadata.bitrate`\uff1a\u4ec5\u63a5\u53d7\u975e\u8d1f\u6574\u6570\u3002\n\n```pycon\n>>> metadata.bitrate\n984052\n>>> metadata.bitrate = 1000000  # OK\n>>> metadata.bitrate\n1000000\n>>> metadata.bitrate = '2000000'  # TypeError\nTraceback (most recent call last):\n...\nTypeError: 'bitrate' must be <class 'int'> (got '2000000' that is a <class 'str'>).\n>>> metadata.bitrate = -1000000  # ValueError\nTraceback (most recent call last):\n...\nValueError: 'bitrate' must be >= 0: -1000000\n>>>\n```\n\n-   `metadata.artist`\uff1a\u4ec5\u63a5\u53d7\u53ef\u4ee5\u8f6c\u6362\u4e3a\u5b57\u5178\u7684\u5bf9\u8c61\uff1b\u952e\u5fc5\u987b\u662f\u5b57\u7b26\u4e32\uff0c\u5bf9\u5e94\u7684\u503c\u5fc5\u987b\u662f\u6574\u6570\uff0c\u5426\u5219\u4f1a\u5f15\u53d1 `TypeError`\u3002\n\n```pycon\n>>> metadata1.artist\n{'stellatram': 12023150}\n>>> metadata1.artist['\u7fa4\u661f'] = 122455  # OK\n>>> metadata1.artist\n{'stellatram': 12023150, '\u7fa4\u661f': 122455}\n>>> metadata1.artist = {\n... 'stellatram': 12023150,\n... '\u672a\u6765\u53e4\u4ee3\u697d\u56e3': 12131344,\n... '\u5b89\u6b21\u5dba\u5e0c\u548c\u5b50': 30104787\n... }  # \u5c1d\u8bd5\u4f7f\u7528\u771f\u6b63\u7684\u5b57\u5178\u5bf9\u8c61\u4e3a artist \u5c5e\u6027\u8d4b\u503c\uff0cOK\n>>> metadata.artist\n{'stellatram': 12023150, '\u672a\u6765\u53e4\u4ee3\u697d\u56e3': 12131344, '\u5b89\u6b21\u5dba\u5e0c\u548c\u5b50': 30104787}\n>>> metadata.artist = 'stellatram'  # ValueError\nTraceback (most recent call last):\n...\nValueError: not enough values to unpack (expected 2, got 1)\n>>> metadata.artist = 12023150  # TypeError\nTraceback (most recent call last):\n...\nTypeError: 'artist' must be <class 'ncm163key._ArtistsMapping'> (got 12023150 that is a <class 'int'>).\n>>> metadata.artist[12023150] = 12023150  # TypeError\nTraceback (most recent call last):\n...\nTypeError: non-str object are not available for the mapping keys: 12023150 ('int')\n>>> metadata1.artist['stellatram'] = '12023150'  # TypeError\nTraceback (most recent call last):\n...\nTypeError: non-int object are not available for the mapping values: '12023150' ('str', key='stellatram')\n>>>\n```\n\n### \u5c06\u5143\u6570\u636e\u8fd8\u539f\u4e3a\u6807\u8bc6\u7b26\n\n```pycon\n>>> ncm163key.dumps(metadata)\n\"163 key(Don't modify):...\"\n>>>\n```\n\n-   \u5982\u679c\u8981\u4f7f\u7528\u81ea\u5b9a\u4e49\u7684\u6807\u8bc6\u7b26\u52a0\u5bc6\u5bc6\u94a5\uff0c\u901a\u8fc7\u53c2\u6570 `alter_id_key` \u4f20\u9012\u7ed9\u51fd\u6570\uff1a\n\n```pycon\n>>> ncm163key.dumps(metadata, alter_id_key=b'...')\nb\"163 key(Don't modify):...\"\n>>>\n```\n\n# \uff08\u53ef\u80fd\u7684\uff09\u5e38\u89c1\u95ee\u9898\n\n> \u8fd9\u4e2a\u9879\u76ee\u80fd\u8f93\u51fa NCM \u6587\u4ef6\u7684\u97f3\u9891\u5185\u5bb9\u5417\uff1f\n\n\u4e0d\u884c\uff0c\u4ee5\u540e\u4e5f\u4e0d\u53ef\u80fd\u3002\u4e0b\u4e00\u4e2a\u3002\n\n> \u6211\u6ca1\u542c\u8bf4\u8fc7 `pyaes` \u8fd9\u4e2a\u5305\uff0c\u4e3a\u4ec0\u4e48\u8981\u7528\u5b83\u505a AES \u52a0\u89e3\u5bc6\uff0c\u800c\u4e0d\u7528 `pycryptodome`\uff1f\n\n\u6807\u8bc6\u7b26\u7684\u52a0\u89e3\u5bc6\u4f7f\u7528\u4e86 AES\uff0c\u6ca1\u6709\u5176\u4ed6\u52a0\u5bc6\u65b9\u5f0f\uff0c\u56e0\u6b64\u4f7f\u7528 `pyaes` \u8fd9\u79cd\u7b80\u5355\u7684 AES \u7b97\u6cd5\u5b9e\u73b0\u5c31\u8db3\u591f\u4e86\uff0c`pycryptodome` \u8fd9\u79cd\u5927\u800c\u5168\u7684\u52a0\u5bc6\u7b97\u6cd5\u5e93\u663e\u5f97\u6709\u4e9b\u81c3\u80bf\u3002\n",
    "bugtrack_url": null,
    "license": "Copyright 2023 nukemiko  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \u201cSoftware\u201d), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \u201cAS IS\u201d, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "\u7b80\u5355\u660e\u4e86\u5730\u89e3\u6790\u548c\u751f\u6210 163key \u5b57\u7b26\u4e32",
    "version": "0.1.0",
    "project_urls": {
        "Bug Tracker": "https://github.com/nukemiko/ncm-163key-parser/issues",
        "Homepage": "https://github.com/nukemiko/ncm-163key-parser"
    },
    "split_keywords": [
        "netease",
        "163",
        "163key",
        "cloudmusic",
        "ncm"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "3f14b5ecf385534abd4b3007ef3602ca5f361f4829ede8f3750de32899dd6ebb",
                "md5": "d1f62a396b182e48ab9da388bf843f14",
                "sha256": "7e4f41d19568ce54fc01bfc310d1d5f927ecb5a4d0a5b5174d52ade6b5f6b822"
            },
            "downloads": -1,
            "filename": "ncm_163key_parser-0.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "d1f62a396b182e48ab9da388bf843f14",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 13881,
            "upload_time": "2023-06-29T08:35:32",
            "upload_time_iso_8601": "2023-06-29T08:35:32.138669Z",
            "url": "https://files.pythonhosted.org/packages/3f/14/b5ecf385534abd4b3007ef3602ca5f361f4829ede8f3750de32899dd6ebb/ncm_163key_parser-0.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ed7b96ee0e3fdd1197a4a2d552afe4af6f74ca0bcac989da1e0cbeac931ab017",
                "md5": "e56a500b3662be6e6cf00941b75a92dc",
                "sha256": "9d6528cb7b5b478adaf9aa5475acb881a2f283d5b65fafa65ddf98bcca615417"
            },
            "downloads": -1,
            "filename": "ncm-163key-parser-0.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "e56a500b3662be6e6cf00941b75a92dc",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 17302,
            "upload_time": "2023-06-29T08:35:34",
            "upload_time_iso_8601": "2023-06-29T08:35:34.083991Z",
            "url": "https://files.pythonhosted.org/packages/ed/7b/96ee0e3fdd1197a4a2d552afe4af6f74ca0bcac989da1e0cbeac931ab017/ncm-163key-parser-0.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-06-29 08:35:34",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "nukemiko",
    "github_project": "ncm-163key-parser",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "attrs",
            "specs": []
        },
        {
            "name": "pyaes",
            "specs": []
        }
    ],
    "lcname": "ncm-163key-parser"
}
        
Elapsed time: 0.08989s