Files

284 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Anisong Organizer
一个简单易用的自动化整理程序:扫描音乐文件夹,自动识别每首歌的出处并分类整理——动漫歌按系列排列,非动漫歌按歌手地区与成立时间排列,歌词与封面同步归类;适配网易云 .ncm 加密格式,一键解密后进入同一整理流水线。
- ✅ 零配置:工具包文件夹复制到任意音乐文件夹即可运行
- ✅ 零依赖:纯 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`(推荐)**:自动打开浏览器进入网页整理界面——也可把控制台打印的 `http://127.0.0.1:端口/` 链接复制到任意浏览器打开。界面上填写**来源文件夹**路径 → 扫描 → 在预览列表拖拽调整分类与顺序 → 「应用全部移动」;关闭网页即自动退出。详见下文「Web 界面」。
3. **(可选)命令行整理**:双击 `命令行运行.bat`(或执行 `python app\anime_sorter.py`)。程序自动处理**上级文件夹**里的音乐,打印完整整理预览(旧名 → 分类 → 新位置)并生成 `导览.txt``分类\歌曲\编号_曲名 ← 原名` 的对照清单,可按它手工移回),确认后输入 `y` 执行。
4. **以后新增歌曲**:把新歌丢进音乐文件夹,再运行一次即可。新歌编号自动续接,识别结果缓存到 `识别缓存.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 → 36sMusicBrainz 失败计数与提示验证通过
- 兼容性:映射表/设置文件兼容带 BOM 的 UTF-8(Windows 记事本编辑不会导致崩溃)