netease-cloud-music-dl源码架构全解读:7个核心文件如何构建一个完整的命令行音乐下载器
【免费下载链接】netease-cloud-music-dlNetease cloud music song downloader, with full ID3 metadata, eg: front cover image, artist name, album name, song title and so on.项目地址: https://gitcode.com/gh_mirrors/ne/netease-cloud-music-dl
ncm(netease-cloud-music-dl)是一款基于 Python 的网易云音乐命令行下载器:输入歌曲 ID 或链接,它就能把 MP3 和专辑封面一起下载下来,并把歌手名、歌曲标题、专辑名等元数据写进 ID3 Tags。这篇文章带你逐文件解读这个命令行音乐下载器的源码架构,看看 7 个核心文件是如何协作,串起「参数解析 → 接口请求 → 加密传输 → 文件下载 → 元数据写入」这条完整链路的。🎵
想先跑起来再读源码的话,两步即可:
git clone https://gitcode.com/gh_mirrors/ne/netease-cloud-music-dl python3 setup.py install安装完成后,命令行里直接敲ncm -s 歌曲ID就能开始下载。
一、目录结构速览:7 个核心文件的分工
整个项目非常小巧,核心逻辑全部集中在 ncm/ 目录下的 7 个 Python 文件里,一眼就能看全:
| 核心文件 | 一句话职责 | 扮演的角色 |
|---|---|---|
| ncm/start.py | 解析命令行参数,分发下载任务 | 前台接待 |
| ncm/config.py | 生成并读取ncm.ini配置 | 后台账本 |
| ncm/api.py | 封装网易云各类数据接口 | 情报员 |
| ncm/constants.py | 集中管理接口地址、请求头、加密常量 | 通讯录 |
| ncm/encrypt.py | 实现 weapi 的 AES + RSA 加密 | 密电员 |
| ncm/downloader.py | 下载调度、命名分类、进度条 | 搬运工 |
| ncm/file_util.py | 封面压缩、ID3 元数据写入 | 图书管理员 |
外层还有 setup.py(打包安装并注册ncm命令)和 requirements.txt(声明 4 个第三方依赖)。这种「一个目录装下全部核心逻辑」的扁平结构,是新手学习命令行工具架构非常友好的范本。
二、start.py 源码解读:命令行参数解析与任务分发
一切从用户敲下ncm开始。ncm/start.py 是整个程序入口——setup.py 中的entry_points把ncm命令绑定到ncm.start:main,所以敲下ncm实际执行的就是 main() 函数。
它做了三件事:
- 加载配置:模块导入时就调用
config.load_config()并把CloudApi()实例化好,保证后续任何下载动作都能读到用户配置; - 解析参数:用标准库
argparse定义了-s(单曲)、-ss(多首)、-hot(歌手热门)、-a(专辑)、-p(歌单)、-radio(播客)等参数; - 分发任务:
main()底部一连串if/elif,把参数路由到对应的下载函数(download_hot_songs、download_album_songs、download_playlist_songs等)。
有个贴心设计值得注意:get_parse_id() 允许用户直接粘贴完整网页链接。它用urlparse从链接的查询串里抠出id,于是「复制歌曲页面地址 → 直接粘贴」就能下载,完全不用手动找 ID。
三、api.py + constants.py 源码解读:如何请求网易云接口
所有「问网易云要数据」的请求都收口在 ncm/api.py 的CloudApi类里,它的设计有三个亮点:
- 会话复用:构造时创建一个
requests.Session并预置请求头,多次请求共享连接,效率更高; - 忙碌自动重试:get_request() 发现接口返回
406(服务器忙)时会打印提示并等 20 秒重试,而不是直接失败; - 默认追求高品质:get_song_url() 请求下载链接时默认指定 320k 比特率,拿不到就自动降级到最高可用品质。
接口地址全部集中在 ncm/constants.py:get_song_url()、get_album_url()、get_playlist_url()等小函数按 ID 拼出完整 URL,get_radio_url() 还带limit/offset分页参数,配合 get_radio_programs() 的循环翻页,可以把播客电台的全部节目取干净。
另一个容易被忽略的细节是 headers 定义:其中Cookie里的_ntes_nuid和NMTID每次启动都会随机生成 32 位字符串,用来模拟一个「全新真实访客」,降低被风控的概率。
四、encrypt.py 源码解读:weapi 双重加密的简单原理 🔐
网易云的歌曲下载链接接口(weapi前缀)不允许明文传参,api.py里每个post_request()都会先经过 encrypted_request() 加密。用大白话讲,这个「双重加密」分三步:
- 临时钥匙:随机生成一个 16 字节的
sec_key(相当于一次性钥匙); - AES 双重加密:先用固定的
nonce把请求参数 AES-CBC 加密一次,再用这把临时钥匙再加密一次,得到params; - RSA 锁住钥匙:用网易云公开的公钥
pub_key和模数modulus(定义在 constants.py)对临时钥匙做 RSA 加密,得到encSecKey,随请求一起发出。
服务端用自己的私钥解出临时钥匙,再解开参数——整个过程只用纯 Python 的pow()模幂运算就实现了 RSA,没有一行复杂依赖,是很好的密码学入门样例。
五、downloader.py 源码解读:下载调度、进度条与智能分类 ⬇️
ncm/downloader.py 是真正干活的核心,核心函数 download_song_by_song() 编排了单首歌曲的完整下载流水线:
- 命名与分类:按
config配置,文件名支持「歌曲名」「歌手 - 歌曲名」「歌曲名 - 歌手」三种格式;文件夹支持「平铺 / 按歌手 / 按歌手+专辑」三级智能分类; - 跳过重复:download_file() 流式下载(1KB 一块),如果本地已有同名文件且体积不小于远端,直接判定「已下载过」跳过,重复执行命令不会浪费流量;
- 进度条:ProgressBar 类 每下载超过 10KB 刷新一次百分比和文件大小,是命令行工具提升体验的经典小技巧;
- 封面流水线:歌曲下完后接着下载专辑封面 → 调用
resize_img()压缩 → 交给file_util.add_metadata_to_song()嵌入 MP3 → 最后删掉临时封面文件,磁盘上不留垃圾。
下面的演示 GIF 就是ncm -p 歌单ID批量下载时的真实终端效果,能清楚看到逐首下载、封面落盘和进度刷新的过程:
六、file_util.py 源码解读:封面压缩与 ID3 元数据写入 🎨
这是整个项目的灵魂,也是作者当初「一怒之下重写」的出发点——很多下载器根本不写封面。ncm/file_util.py 只有两个函数:
- resize_img():用 Pillow 把封面等比缩到 640×640 以内。原图动辄好几 MB,不压缩会让每首 MP3 白白多出一大块;
- add_metadata_to_song():用
mutagen库向 MP3 写入完整 ID3 标签——APIC(专辑封面)、TPE1(歌手)、TIT2(标题)、TALB(专辑名)、TRCK(曲目序号/总曲目数)。代码里还处理了细节:先删除旧的APIC帧防止一张图出现两个封面、没有 ID3 头时先补建标签、播客节目用 DJ 昵称代替歌手名。
下载完成后把 MP3 丢进任何音乐播放器,封面、歌手、专辑信息一应俱全,强迫症非常友好。
七、config.py 源码解读:ncm.ini 配置文件自动生成 ⚙️
ncm/config.py 负责所有「用户可调项」,路径固定在用户主目录下的~/.ncm/ncm.ini:
- 首次运行自动生成:init_config_file() 会把一份带详细注释的默认配置写到磁盘,用户改任何行为都不用碰代码;
- 四个核心开关:热门歌最大下载数(默认 50)、下载目录、音乐命名格式(3 种)、文件智能分类(3 种),由 load_config() 读取后暴露为全局常量,供
downloader.py在命名和分类时读取。
这种「配置驱动行为」的设计让下载器对不同用户的音乐库管理习惯(按歌手整理 or 平铺存放)都能适配。
八、总结:从输入到 MP3,一条完整的调用链路 🧩
回顾整条链路,7 个文件各司其职、几乎没有越界调用:
你敲下 ncm -p 歌单ID │ ▼ start.py 解析参数、把 URL 转成 ID,分发任务 │ ├──▶ config.py 读取命名格式、分类方式等配置 ├──▶ api.py 请求歌单/歌曲数据(constants.py 提供地址与请求头) │ └──▶ encrypt.py POST 请求先做 weapi 双重加密 ▼ downloader.py 按配置命名/分类,流式下载 MP3 + 封面,进度条实时刷新 │ ▼ file_util.py 封面压缩到 640px,ID3 写入封面/歌手/标题/专辑 │ ▼ 本地得到带完整元数据和封面的 MP3 ✅对新手来说,这个命令行音乐下载器有三个值得直接抄走的设计:用argparse+ 路由函数做入口分发、用集中式 constants 文件管理所有外部地址、用配置文件驱动用户行为。代码量不到一千行,却完整覆盖了参数解析、网络请求、加密、流式下载、进度反馈、媒体处理六大知识点——这也是它作为入门项目最值得推荐的原因。
【免费下载链接】netease-cloud-music-dlNetease cloud music song downloader, with full ID3 metadata, eg: front cover image, artist name, album name, song title and so on.项目地址: https://gitcode.com/gh_mirrors/ne/netease-cloud-music-dl
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考