286 lines
18 KiB
Markdown
286 lines
18 KiB
Markdown
# Anisong Organizer
|
||
|
||
一个简单易用的自动化整理程序:扫描音乐文件夹,自动识别每首歌的出处并分类整理——动漫歌按系列排列,非动漫歌按歌手地区与成立时间排列,歌词与封面同步归类。
|
||
|
||
- ✅ 零配置:工具包文件夹复制到任意音乐文件夹即可运行
|
||
- ✅ 零依赖:纯 Python 标准库(联网识别日文曲名时推荐安装可选的 pykakasi;ncm 解密已装 numpy 时自动加速)
|
||
- ✅ 先预览后执行:默认只出预览,确认后才执行,绝不静默修改
|
||
- ✅ 幂等:重复运行不会重复处理,也不会破坏已整理好的结构
|
||
- ✅ 只动文件名:不修改音乐文件内容和内置标签
|
||
- ✅ 六分类输出:Anisong / 日韩 / 中国港澳台 / 中国大陆 / 欧美 / 其他(未被识别),没有内容的分类不创建文件夹
|
||
- ✅ 网易云 .ncm 一键解密:解密为 flac/mp3 后进入同一流水线,原 .ncm 保留到「加密原件」夹
|
||
- ✅ 歌词/封面同步:歌词与音乐同编号入「歌词」夹;封面按专辑名入「封面」夹
|
||
- ✅ 浏览器交互界面:`--web` 启动本地网页界面,可视化调整分类与顺序
|
||
|
||
---
|
||
|
||
## 快速上手
|
||
|
||
0. **(可选)便携版无需安装 Python**:工具包已内置官方 Python 嵌入式运行时(`python\` 目录,约 21MB)。双击 `启动网页版.bat` 直接打开浏览器整理界面;命令行用户双击 `命令行运行.bat`。本机已装 Python 时两套入口同样可用。
|
||
|
||
> 📦 **源码版注意**:从 git 仓库克隆的源码**不含**内置运行时(`python\` 目录)。需本机已装 Python 3.8+,或到 python.org 下载 [Windows embeddable package (64-bit)](https://www.python.org/downloads/windows/) 解压为 `python\` 目录,即可恢复免安装便携。
|
||
|
||
1. **放入工具包**:把本文件夹(`Anisong Organizer`)整个复制进你的音乐文件夹,例如:
|
||
|
||
```
|
||
D:\音乐\我的收藏\
|
||
├── Anisong Organizer\ ← 本工具包
|
||
├── 未闻花名 - 茅野爱衣.flac
|
||
├── Sexyback - Justin Timberlake,Timbaland.ncm
|
||
└── ...(你的音乐文件)
|
||
```
|
||
|
||
2. **双击运行**:双击 `命令行运行.bat`(或执行 `python app\anime_sorter.py`)。程序自动处理**上级文件夹**里的音乐。
|
||
|
||
3. **看导览**:程序打印完整的整理预览(旧名 → 分类 → 新位置),并生成 `导览.txt`(`分类\歌曲\编号_曲名 ← 原名` 的对照清单,可按它手工移回)。确认后输入 `y` 执行。
|
||
|
||
4. **想要图形界面**:执行 `python app\anime_sorter.py --web`,浏览器里拖拽调整分类、点击应用。
|
||
|
||
5. **以后新增歌曲**:把新歌丢进音乐文件夹,再运行一次即可。新歌编号自动续接,识别结果缓存到 `识别缓存.json` / `artist_map.json`,下次离线也能用。
|
||
|
||
## 整理结果示例
|
||
|
||
```
|
||
D:\音乐\我的收藏\
|
||
├── Anisong\ ← 识别到动漫的歌(按系列首播年份排序)
|
||
│ ├── 歌曲\01_疾風の如く.flac
|
||
│ ├── 加密原件\02_プランA.ncm
|
||
│ ├── 歌词\01_疾風の如く.lrc
|
||
│ └── 封面\プランA.jpg
|
||
├── 日韩\ ← 非动漫、歌手地区为日韩(按歌手成立年份排序)
|
||
│ ├── 歌曲\01_Power.flac
|
||
│ ├── 加密原件\01_Power.ncm
|
||
│ └── 歌词\01_Power.lrc
|
||
├── 中国港澳台\
|
||
│ └── 歌曲\01_海阔天空.mp3
|
||
├── 中国大陆\
|
||
│ └── 歌曲\01_平凡之路.mp3
|
||
├── 欧美\
|
||
│ └── 歌曲\01_Sexyback.flac
|
||
├── 其他(未被识别)\ ← 兜底:查不到出处的歌
|
||
│ └── 歌曲\01_未知之歌.mp3
|
||
└── Anisong Organizer\
|
||
```
|
||
|
||
(没有内容的分类不会创建文件夹。)
|
||
|
||
## 工作原理
|
||
|
||
```
|
||
音乐文件夹(.flac/.mp3/.ncm/.lrc…)
|
||
│
|
||
├─ ⓪ 解密与自愈 ─────── .ncm 解密为 flac/mp3(幂等);「加密原件」夹中
|
||
│ 缺失解密音频的 .ncm 自动恢复;封面提取待分类后入夹
|
||
│
|
||
├─ ① 提取曲名与歌手 ── FLAC 读内置标签(TITLE/ARTIST)
|
||
│ 其他格式或无标签时回退解析文件名「曲名 - 歌手」
|
||
│
|
||
├─ ② 曲名规范化 ─────── 简中混入修正(谜→謎 风→風)、全角空格、
|
||
│ 去注释尾巴(feat. XXX / Director's Edit. 等)
|
||
│
|
||
├─ ③ 分类判定 ──────── 1) 本地映射表 anime_map.json(含历史联网缓存)
|
||
│ 2) 四动漫源**并行**联网查询,按曲名语言调整优先级:
|
||
│ 假名→anison 优先 / 汉字→萌娘优先 / 英文→animethemes 优先
|
||
│ 命中 → Anisong;源连续失败 2 次自动熔断(本次运行停用)
|
||
│ 3) MusicBrainz 查歌手地区 → 日韩/中国港澳台/中国大陆/欧美
|
||
│ 4) 都查不到 → 其他(未被识别)
|
||
│
|
||
├─ ④ 排序 ──────────── Anisong: 系列按首播年份(老→新),系列内按 OP/ED 顺序
|
||
│ 日韩/港澳台/大陆/欧美: 按歌手分组(同歌手相邻),
|
||
│ 歌手按成立年份(未知置后),组内按曲名
|
||
│ 其他: 按 (歌手, 曲名)
|
||
│
|
||
├─ ⑤ 编号 ──────────── 每分类独立编号(01,02,03…),续接该分类现有最大号;
|
||
│ 歌词与加密原件与歌曲永远同号
|
||
│
|
||
├─ ⑥ 文件名清理 ────── Windows 禁用字符转全角、尾随点转全角、重名加 (2)
|
||
│
|
||
└─ ⑦ 预览确认后执行 ── 移动到分类文件夹(导览.txt 含完整绝对路径对照,可回退);
|
||
联网结果写入 识别缓存.json(每次联网运行重新生成) / artist_map.json 缓存
|
||
```
|
||
|
||
## 文件说明(分层结构)
|
||
|
||
```
|
||
Anisong Organizer\
|
||
├── 启动网页版.bat / 命令行运行.bat ← 入口层(双击即用)
|
||
├── app\ ← 程序层
|
||
├── data\ ← 数据层(用户维护/缓存/导览)
|
||
├── python\ ← 运行时层(内置 Python,免安装)
|
||
└── README.md
|
||
```
|
||
|
||
| 文件 | 作用 |
|
||
|---|---|
|
||
| `app\anime_sorter.py` | 主程序(命令行入口 + 全部流水线逻辑) |
|
||
| `app\ncm_decrypt.py` | 网易云 .ncm 解密模块(纯标准库,numpy 可选加速;可单独 `import` 使用) |
|
||
| `app\web_server.py` | `--web` 模式的本地服务(127.0.0.1 随机端口;关闭网页即自动退出) |
|
||
| `app\web_ui.html` | Web 界面页面(纯静态无 CDN,全离线可用) |
|
||
| `data\anime_map.json` | 本地曲目→动漫系列映射表(**用户维护**:种子数据 + ✎ 手动标注;不再自动追加联网结果) |
|
||
| `data\识别缓存.json` | 联网识别结果缓存(**每次联网运行自动重新生成**,不累积历史,可安全删除) |
|
||
| `data\artist_map.json` | MusicBrainz 歌手地区/成立时间缓存(自动生成,可手工编辑/预填,离线生效) |
|
||
| `data\设置.json` | 数据源开关 + 分类/输出/解密等全部选项 |
|
||
| `data\导览.txt` | 每次运行自动生成的整理导览(`编号_曲名 ← 原名` 对照,可据此手工撤销;Web 界面有「📖 导览」按钮直接查看) |
|
||
| `命令行运行.bat` | 双击运行入口(命令行界面;自动优先使用内置 `python\` 运行时) |
|
||
| `启动网页版.bat` | 双击启动浏览器整理界面(**关闭网页即自动退出进程**;仅出错时窗口停留) |
|
||
| `python\` | 内置的官方 Python 嵌入式运行时(便携版核心,免安装 Python) |
|
||
| `README.md` | 本说明文档 |
|
||
|
||
## 设置.json
|
||
|
||
```json
|
||
{
|
||
"sources": {
|
||
"animethemes": {"enabled": true},
|
||
"anison": {"enabled": true},
|
||
"wikipedia": {"enabled": true},
|
||
"moegirl": {"enabled": true}
|
||
},
|
||
"musicbrainz": {
|
||
"enabled": true,
|
||
"rate_limit": 1.05,
|
||
"user_agent": "AnisongOrganizer/1.0 ( contact )",
|
||
"max_failures": 3
|
||
},
|
||
"decrypt": {"enabled": true, "save_cover": true},
|
||
"output": "",
|
||
"categories": {
|
||
"anisong": "Anisong",
|
||
"jp_kr": "日韩",
|
||
"hk_mo_tw": "中国港澳台",
|
||
"cn_mainland": "中国大陆",
|
||
"western": "欧美",
|
||
"other": "其他(未被识别)"
|
||
},
|
||
"folders": {"songs": "歌曲", "originals": "加密原件", "lyrics": "歌词", "covers": "封面"}
|
||
}
|
||
```
|
||
|
||
- `sources`:各动漫识别源的启停(anison / wikipedia 需要加速器/代理)
|
||
- `musicbrainz`:歌手地区分类源(需要加速器/代理;`user_agent` 必填自定义格式,默认 UA 会被官方封 IP;连续失败 `max_failures` 次后本次运行自动禁用,剩余歌曲归「其他」)
|
||
- `decrypt`:ncm 解密与封面提取开关
|
||
- `output`:分类输出根目录,**空 = 被处理文件夹本身**;可填其他盘路径(自动跨盘移动)
|
||
- `categories` / `folders`:六分类与四子文件夹的名称,均可自定义
|
||
|
||
## 数据源(联网识别)
|
||
|
||
| 顺序 | 数据源 | 擅长 | 需要加速器/代理 |
|
||
|---|---|---|---|
|
||
| 1 | AnimeThemes.moe | 英文/罗马字曲名,自带年份与季度;日文曲名自动转罗马字后再查 | 否 |
|
||
| 2 | anison.info | 日文曲名,专门的动漫歌曲数据库(结果行直接含动漫名与 OP/ED 类型) | **是** |
|
||
| 3 | 日语维基百科 | 从歌曲条目的「テレビアニメ『X』のOP/ED」句式精确提取动漫 | **是** |
|
||
| 4 | 萌娘百科 | 中日文曲名,国内直连 | 否 |
|
||
| 5 | MusicBrainz | 歌手地区/成立年份(非动漫曲分类排序用),官方限速 1 次/秒,结果本地缓存 | **是** |
|
||
|
||
连不上的源不会卡死程序:运行结束统一汇总状态并提示(「✗ 数据源 anison 连接失败 2 次 —— 该源需要加速器/代理,请确认已开启后重试」)。MusicBrainz 查询失败时歌曲自动归入「其他(未被识别)」。Web 界面顶部有同样的数据源状态面板。
|
||
|
||
**动漫歌曲独特适配**(v4.1):
|
||
- **语言感知优先级**:假名标题(日文曲名)以日文曲库 anison 优先、纯汉字以中日文覆盖的萌娘百科优先、纯英文/罗马字以 AnimeThemes 优先——各取所长
|
||
- **并行查询**:启用源同时查询,按优先级取首个命中(耗时 = 最慢的源而非各源之和)
|
||
- **源熔断**:某源连续失败 2 次后本次运行自动停用,不再每首歌白等超时(无梯子实测 2 首歌 81.8s → 36s,歌越多收益越大)
|
||
|
||
## 命令行参数
|
||
|
||
```bash
|
||
python app\anime_sorter.py # 预览模式(默认),确认后执行
|
||
python app\anime_sorter.py --apply # 跳过确认直接执行
|
||
python app\anime_sorter.py --offline # 禁用联网,只查本地映射表/缓存
|
||
python app\anime_sorter.py --sources=animethemes,moegirl # 本次只用指定源
|
||
python app\anime_sorter.py D:\某文件夹 # 处理指定文件夹(缺省为工具包上级文件夹)
|
||
python app\anime_sorter.py D:\下载目录 --recursive # 递归整理子目录(网易云下载结构),执行后清理空目录
|
||
python app\anime_sorter.py --web # 启动浏览器交互界面
|
||
```
|
||
|
||
## Web 界面
|
||
|
||
`python app\anime_sorter.py --web` 启动本地服务并自动打开浏览器(仅监听 127.0.0.1,数据不出本机):
|
||
|
||
- 表单输入:**来源文件夹**(如网易云下载目录)+ **输出目录**(留空=来源文件夹)+ **递归整理子目录**(下载目录勾选,执行后自动清理源目录空壳);默认联网识别(**用户维护的 anime_map.json 始终第一优先**)
|
||
- 顶部实时显示**数据源状态**(正常/失败/熔断/需代理)
|
||
- 进度栏下方实时罗列**已识别的歌曲**(Anisong 标注所属动漫系列与首播年份,其他类标注乐队组建年份)
|
||
- 每首歌的**所属动漫系列以蓝色下拉框直接展示**(与分类下拉同款样式):正常显示当前匹配系列,展开后第一行是「+ 新建系列…」(**点击即出现输入框可直接打字**,选现存系列则立即生效并带出首播年份);标注**应用后自动写入 anime_map.json**。也可改分类(下拉)、调整顺序(↑↓)
|
||
- **勾选多行批量选择**后:可整体**拖拽**到其他分类或指定位置(也支持单选拖拽,拖动完成自动取消勾选);或通过批量工具栏一键移动
|
||
- 「应用全部移动」执行(执行前有确认弹窗);**应用后计划回到可编辑状态,可继续调整并再次应用**(反复整理直到满意)
|
||
- 工具栏的「**📖 导览**」按钮:弹窗直接展示整理导览(`编号_曲名 ← 原名` 对照),可复制或下载 `导览.txt`
|
||
- 可中途「停止」;执行结果统计展示
|
||
|
||
## 一键整理(网易云下载目录)
|
||
|
||
把网易云下载目录(`歌手\专辑\xxx.ncm` 嵌套结构)一键整理到指定路径:
|
||
|
||
```bash
|
||
python app\anime_sorter.py D:\网易云下载 --recursive --apply
|
||
# 输出目录: 设置.json 的 output(留空=下载目录本身);执行后自动清理空目录
|
||
```
|
||
|
||
或 Web 界面:来源填下载目录、输出填目标路径、勾选「递归整理子目录」→ 扫描 → 应用。
|
||
递归扫描自动跳过分类目录与工具包文件夹;子目录中的 .ncm 原位解密后统一移入输出目录分类。
|
||
|
||
**网易云下载设置全部适配**:
|
||
|
||
| 设置项 | 适配方式 |
|
||
|---|---|
|
||
| 命名「歌曲名」 | .ncm 用内嵌元数据补全歌手;普通文件无歌手信息时归「其他」,可 ✎ 手动标注 |
|
||
| 命名「歌手-歌曲名」 | 文件名双向解析,自动识别歌手在前还是曲名在前(优先取能命中映射表的方向) |
|
||
| 命名「歌曲名-歌手」 | 默认解析 ✓ |
|
||
| 保存「不分文件夹」 | 顶层扫描 ✓ |
|
||
| 保存「按歌手」/「按歌手\专辑」 | 递归模式自动包含 ✓ |
|
||
| VIP 曲目(VipSongsDownload 子文件夹) | 递归模式自动包含;非递归时检测到会提示勾选递归 |
|
||
|
||
## 常见问题与调试
|
||
|
||
### 歌曲被归入「其他(未被识别)」
|
||
|
||
可能原因:本地表没有且动漫源查不到、歌手不在 MusicBrainz 缓存、MusicBrainz 连不上(需加速器)、或文件名/标签里没有歌手信息。处理办法:
|
||
|
||
1. 在 Web 界面手动调整分类;
|
||
2. 或打开 `anime_map.json`(动漫歌)/ `artist_map.json`(非动漫歌)仿照已有条目手工添加;
|
||
3. 重新运行。
|
||
|
||
### 完全没网 / 联网超时
|
||
|
||
- 程序对每个接口都设了超时,网络不可用时自动跳过联网、只查本地表与缓存,不会卡死或崩溃。
|
||
- 想完全离线运行:加 `--offline`(本地映射与缓存仍生效)。
|
||
|
||
### 日文曲名识别率低
|
||
|
||
联网识别日文曲名依赖 `pykakasi` 做罗马字转写:`pip install pykakasi`。未安装时程序仍可运行,只是日文曲名的联网命中率会明显下降。
|
||
|
||
### 重复运行会怎样?
|
||
|
||
安全幂等。整理完成的文件都在分类文件夹里,顶层没有文件时运行直接显示「无需处理」;新增文件按分类现有最大号续接编号;「加密原件」夹中缺失解密音频的 .ncm 会自动重新解密恢复。
|
||
|
||
### 改错了想撤销?
|
||
|
||
`导览.txt` 里每首歌都是 `分类\歌曲\编号_曲名 ← 原名` 的对照,按它手工移回即可(Web 界面点「📖 导览」按钮直接查看/复制/下载)。
|
||
|
||
### 旧版本(v3.1)整理过的文件夹
|
||
|
||
自动迁移:顶层平铺编号的文件与旧「歌词」文件夹里的 .lrc 会重新归类进新结构(编号变为分类内编号,属预期);旧顶层「封面」文件夹无法可靠对应分类,保持原位并在运行时提示。
|
||
|
||
## 已知限制与设计取舍
|
||
|
||
- **联网源覆盖**:animethemes.moe 主要收录 OP/ED 主题曲;纯 OST/插入曲或冷门歌曲可能查不到 → 归「其他」,属预期兜底而非故障。
|
||
- **识别不是 100% 准确**:动漫识别采用「高置信才采用」策略;地区分类依赖 MusicBrainz 数据;预览确认与 Web 手动调整就是最后一道人工保险。
|
||
- **系列归属的合并粒度**:同世界观多季动画默认归为一个系列(如「とあるシリーズ」含魔禁+超炮)。想拆开就在 `anime_map.json` 里手动分成多个系列。
|
||
- **歌手名不写入文件名**:最终格式为 `编号_曲名`,歌手信息保留在文件内置标签中(本程序不修改标签)。
|
||
- **不写标签**:音乐文件本身只改名移动;如需写入 ALBUM=系列名 等标签,可在此基础上扩展。
|
||
- **只扫描文件夹第一层**:不递归处理子文件夹(分类文件夹内部不参与重复整理)。
|
||
- **.ncm 解密后原件保留**:解密是「另存新文件」而非替换,磁盘占用会翻倍;确认无误后可自行删除「加密原件」夹中的 .ncm。
|
||
|
||
## 依赖
|
||
|
||
- **无需安装任何环境**:工具包内置官方 Python 3.12 嵌入式运行时(`python\` 目录);本机已装 Python 3.8+ 时也可直接用(启动脚本自动优先内置运行时)。源码版不含该运行时,获取方式见「快速上手」第 0 步
|
||
- 零第三方强制依赖(纯标准库)
|
||
- 可选:pykakasi(提升日文曲名联网识别率)、numpy(ncm 解密加速,无则自动用纯 Python 路径)
|
||
|
||
## 测试情况
|
||
|
||
- **ncm 解密**:4 个真实网易云 .ncm 全部解密成功,输出与开源参考实现(ncmdump-py)**sha256 字节级一致**;numpy 与纯标准库两条路径均验证通过;AES 模块通过 NIST 标准测试向量
|
||
- **六分类(v4)**:本地映射/动漫源/MusicBrainz 缓存三类判定路径分别验证;日韩/港澳台/大陆/欧美/其他归属正确;地区分类按歌手成立年份排序正确
|
||
- **结构与幂等(v4)**:分类内编号独立、歌词/加密原件同号、空分类不创建文件夹、旧 v3.1 结构自动迁移、复跑「无需处理」且文件零改动(快照对比)
|
||
- **增量与自愈(v4)**:新增文件编号续接;删除解密产物后从「加密原件」自动恢复
|
||
- **Web 界面(v4)**:扫描/计划/改分类/调顺序/应用/停止/参数校验/源状态面板 20 项 API 测试全部通过(自动化)
|
||
- **源策略(v4.1)**:熔断机制(连续失败 2 次停用)、并行查询、语言感知优先级;无梯子计时实测 81.8s → 36s;MusicBrainz 失败计数与提示验证通过
|
||
- 兼容性:映射表/设置文件兼容带 BOM 的 UTF-8(Windows 记事本编辑不会导致崩溃)
|