Skip to content

About

Windows desktop tool for lossless audio remuxing, metadata tagging and format normalization with FFmpeg.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

音频规范化 + 元数据写入工具(Audio Normalizer)

Windows 桌面工具:对下载器保存的“文件名无意义、容器/编码不规范”的音频文件,用 FFmpeg/FFprobe 检测真实格式 → 优先无损重封装(stream copy)→ 写入音乐元数据 → 复验,产出结构规范、播放器兼容性好、可直接上传网易云音乐云盘的文件。

核心原则(按优先级):

  1. 绝不破坏原始音频(原文件只读,输出到 原目录/output/);
  2. 尽可能保持原始音质(默认 -c:a copy 无损重封装,绝不静默重新编码);
  3. 只认 FFprobe 检测出的真实编码/容器,不信任文件扩展名;
  4. 输出结构规范的 MP3 / M4A / Opus / OGG / FLAC / WAV;
  5. 正确写入标题、歌手、专辑等元数据(MP3 用 ID3v2.3);
  6. 处理后用 FFprobe 复验,验证失败则任务失败并保留一切原文件。

一、目录结构

audio-normalizer/
├── app/
│   ├── main.py                 # 程序入口(FFmpeg 检测 + 启动 GUI)
│   ├── core/                   # 核心逻辑(与 GUI 完全解耦)
│   │   ├── ffmpeg.py           #   FFmpeg/FFprobe 定位 + 参数数组执行封装
│   │   ├── probe.py            #   FFprobe JSON 解析 → AudioInfo
│   │   ├── plan.py             #   策略引擎:编码×容器映射表、扩展名不一致检测
│   │   ├── metadata.py         #   8 字段元数据模型 → FFmpeg 参数
│   │   └── processor.py        #   检测→计划→执行→降级→复验 编排
│   ├── ui/
│   │   └── main_window.py      # PySide6 主窗口(表格/表单/线程/确认桥)
│   └── utils/
│       ├── filename.py         # 命名模板 + Windows 非法字符过滤
│       └── logger.py           # logs/ 按日日志 + 结构化任务记录
├── scripts/
│   ├── make_test_samples.py    # 生成典型格式测试样例
│   └── smoke_test.py           # 核心逻辑回归冒烟测试
├── tests/samples/              # 测试样例(脚本生成)
├── requirements.txt
└── README.md

核心处理逻辑(app/core/)不依赖任何 GUI,以后做命令行或 Web UI 可复用。


二、环境搭建(conda)

:: 1. 创建环境(Python 3.12,PySide6 要求 ≥3.9)
conda create -n audio-normalizer python=3.12 -y

:: 2. 激活并安装依赖
conda activate audio-normalizer
pip install -r requirements.txt

若你的 conda 镜像源(如清华 pkgs/free)已失效报 404,可加 --override-channels -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/ 临时绕过,不影响全局配置。


三、FFmpeg 安装 / 放置

程序启动时按以下顺序查找 ffmpeg / ffprobe(缺一不可):

  1. 环境变量 AUDIO_NORMALIZER_FFMPEG_DIR 指定的目录;
  2. 程序目录(源码运行 = 项目根目录;打包后 = exe 所在目录);
  3. 系统 PATH。

方式 A(推荐,winget):

winget install Gyan.FFmpeg

装完重新打开终端即可(ffmpeg -version 验证)。

方式 B(绿色版):

  1. 从 https://www.gyan.dev/ffmpeg/builds/ 下载 ffmpeg-release-essentials.zip;
  2. 解压后把 bin\ffmpeg.exe 和 bin\ffprobe.exe 两个文件放到程序目录(项目根目录,或打包后的 exe 同目录)。

找不到时程序会弹中文提示,不会崩溃。


四、运行

conda activate audio-normalizer
cd path\to\audio-normalizer
python -m app.main

(若 conda run -n audio-normalizer python -m app.main 在你的 conda 版本上偶发插件报错,请改用 conda activate。)

使用流程:

  1. 点「选择文件」或「选择文件夹」(文件夹会递归收集音频,自动跳过 output/ 目录);
  2. 列表自动逐项检测:真实格式、时长、处理策略;扩展名与真实格式不一致的会标 ⚠(如文件名 .mp3、实际 AAC);「信息」列显示该文件的标题/歌手;
  3. 双击某行查看「处理前预览」:容器、编码、采样率、声道、码率、时长、推荐处理方式、是否重编码;
  4. 单击某行,右侧表单载入该文件的音乐信息(自动预填原文件已有的标签,可修改),编辑实时保存到该文件;信息均可留空;
  5. 想批量填写时:编辑好一组信息后点「应用到所有文件」(各文件仍可单独再改);多选时为只读,避免误操作;
  6. 底部选择输出目录(留空 = 每个原文件目录下的 output/)和文件名模板({title} - {artist} / {artist} - {title} / {track} - {title});属性全空时输出文件名使用原文件名;
  7. 点「开始处理」:逐文件按各自的属性 检测 → 无损重封装+写标签(一次 FFmpeg 调用)→ FFprobe 复验 → 完成;单个文件失败不影响其他文件。

不会静默重编码: 只有以下情况会重编码,且每次都先弹窗确认(明确提示“有损转换”):

  • 无损重封装失败时(询问是否降级重编码);
  • 勾选「强制转换为 MP3」时;
  • 遇到未知编码(如 WAVPACK/APE),需选择目标格式(MP3/M4A/OGG/WAV/FLAC)。

五、格式识别策略

真实编码(FFprobe) 目标容器 处理
MP3 .mp3 无损重封装,ID3v2.3 标签
AAC / ALAC .m4a 无损重封装(ADTS AAC 或 .mp3 伪装的 AAC 也会正确转成 M4A)
Opus .opus 无损重封装
Vorbis .ogg 无损重封装
FLAC .flac 无损重封装
PCM (WAV) .wav 无损重封装
其他(未知) 用户选择 确认后重编码

命名模板自动过滤 Windows 非法字符 \ / : * ? " < > |;同名输出自动追加 (1)、 (2)…,绝不覆盖任何已有文件。


六、典型输入格式测试方法

:: 1. 生成 6 种典型样例(含“文件名 .mp3、实为 ADTS AAC”的下载器典型情况)
conda activate audio-normalizer
python scripts/make_test_samples.py

:: 2. 核心逻辑回归测试(识别/重封装/标签/复验/降级/跳过,全自动断言)
python scripts/smoke_test.py

:: 3. GUI 冒烟测试(无窗口模式构建界面、添加文件、检测更新、预览)
python scripts/gui_smoke_test.py

生成的样例(tests/samples/):

文件 扩展名 真实格式 预期处理
standard_mp3.mp3 .mp3 MP3 无损重封装为标准 MP3
fake_aac.mp3 .mp3 ADTS AAC ⚠ 不一致 → 无损封装为 M4A
sample.m4a .m4a AAC/M4A 无损重封装
sample.opus .opus Opus/OGG 无损重封装
sample.flac .flac FLAC 无损重封装
sample.wav .wav PCM WAV 无损重封装

手动验证输出文件(示例):

ffprobe -v quiet -print_format json -show_format -show_streams "tests\samples\output\测试歌曲 - 测试歌手.m4a"
:: 检查 format.duration > 0、streams[0].codec_name == "aac"、format.tags.title 等

七、打包成 exe(PyInstaller)

conda activate audio-normalizer
pip install pyinstaller

:: 项目根目录下执行
pyinstaller --noconfirm --onefile --windowed --name AudioNormalizer ^
  --paths app ^
  --collect-all PySide6 ^
  app/main.py
  • 产物:dist\AudioNormalizer.exe(单文件,双击运行,无控制台黑窗);
  • 把 ffmpeg.exe、ffprobe.exe 放到 exe 同目录(程序自动优先从 exe 目录查找);
  • 日志在 exe 同目录的 logs/ 下;
  • 首次启动 PyInstaller 打包较慢属正常;若杀毒软件误报,加白名单即可。

八、已知限制与说明

  • 封面图会被丢弃:处理命令 -map 0:a:0 只保留音频流(保证与网易云云盘上传兼容性优先);封面保留可作为后续增强。
  • 每个文件独立的元数据:单击行编辑该文件信息,编辑实时保存;「应用到所有文件」可批量填充;检测时会自动预填原文件已有的标签(手动编辑过的行不会被覆盖)。
  • WAV 容器没有“专辑艺术家”字段(RIFF INFO 限制),该字段在 WAV 输出中不写入也不校验。
  • 原始文件在成功处理前不会被删除或覆盖;验证失败时保留原文件与半成品输出(文件名已保证不冲突),并在日志中记录失败原因。
  • 日志:logs/audio_normalizer_YYYY-MM-DD.log(控制台同步输出),每个文件记录 原文件/原始扩展名/真实容器/真实编码/输出格式/是否重编码/FFmpeg 命令/结果/失败原因/输出路径。

About

Windows desktop tool for lossless audio remuxing, metadata tagging and format normalization with FFmpeg.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages