Skip to content

Latest commit

 

History

History
238 lines (197 loc) · 13.5 KB

File metadata and controls

238 lines (197 loc) · 13.5 KB

B站 m4s 视频合并工具 — 最终设计文档

1. 项目概述

一款 Windows 桌面小工具,用 Python + PySide6 开发。
核心功能:自动识别通过 IDM 等工具下载的 B 站分离式 m4s 文件(纯视频+纯音频),提供自动与手动配对、批量命名、灵活的输出目录结构、统一合并为完整视频。


2. 功能需求描述(Functional Requirements)

2.1 源文件分析与扫描

  • 输入:用户通过按钮或拖拽添加文件夹(可多个)。
  • 递归扫描:遍历所有子文件夹,收集全部 .m4s 文件。
  • 流类型分析:使用 ffprobe 检测每个 m4s 文件的音视频轨道状态。
    • video_only:仅有视频流
    • audio_only:仅有音频流
    • muxed:同时含有视频和音频流 → 标记为“已完整”
  • 分析结果展示:所有文件在工具内按状态分类展示。

2.2 智能配对(双模式)

工具支持同时处理两种来源的文件:

模式 A — 子文件夹自动配对

  • 触发条件:某个最底层文件夹内,恰好存在 1 个 video_only + 1 个 audio_only,且无其他同类型文件。
  • 行为
    • 自动将这一对视为一个合并任务。
    • 任务名称默认取该文件夹的名称
    • 任务自动进入“配对队列”(待合并列表)。
  • 多对情形(极少数,如文件夹内有 2 个纯视频+2 个纯音频):
    • 同样自动配对,按文件名字典序第1视频配第1音频、第2配第2。
    • 配对后在列表中用黄色高亮标记“疑似多集,请确认名称”。
  • 数量不对等(如 2 视频+1 音频):不自动配对,相关文件仍散落在“待整理”列表,标记预警色,等待用户手动干预。

模式 B — 零散文件手动配对

  • 所有未被自动配对的单独 video_onlyaudio_only 文件,集中列入“待整理”标签页。
  • 手动配对操作
    • 在“待整理”列表中,用户可多选一个视频文件和一个音频文件(通过 Ctrl/Shift)。
    • 点击工具栏「配对」按钮,或右键选择“配对所选”。
    • 配对后立即弹出一个内联编辑框或小弹窗,要求用户输入输出文件名(不含扩展名)。
    • 确认后该配对任务移入“配对队列”,输出文件名即为用户填写的内容。
  • 批量命名加速
    • 在“配对队列”中,用户可多选多个任务 → 右键选择“批量命名”。
    • 弹出对话框,填写:前缀文字 + 起始序号 + 序号位数(默认2)
    • 系统自动按任务顺序依次重命名为:前缀_01前缀_02...
  • 命名修改:任何任务的“输出名”均可在表格中双击单元格直接修改,优先级最高。

2.3 已完整文件处理

  • muxed 文件默认不进入合并队列,仅在界面上列出(可隐藏),状态显示“已完整(跳过)”。
  • 提供右键菜单选项:「转封装为输出格式」,可不经配对直接封装成目标容器格式(同样使用 ffmpeg -c copy)。此时命名默认使用原文件名。

2.4 预览功能

  • 在任意文件列表(待整理、配对队列中的源文件)上,右键菜单选择「预览」。
  • 工具调用系统默认播放器打开该 m4s 文件(使用 os.startfile())。
  • 帮助用户辨别视频内容以便正确配对,尤其是文件名无意义时。

2.5 输出设置

提供集中的设置面板,包含:

  • 输出格式:下拉选择框,选项:mp4mkvmovflv。默认 mp4
  • 输出目录:文本框 + 「浏览」按钮,用户选择一个文件夹作为最终视频的统一输出根目录。
    若留空,则要求用户必须先选择。
  • 路径镜像与层级控制
    • 默认行为:保留从“源拖入根目录”到文件所在文件夹的完整相对路径。
      • 例:拖入根 D:\下载,文件在 D:\下载\番剧A\01\ → 输出到 <输出根>\番剧A\01\
    • 自定义层级(路径深度):在设置区提供一个数字输入框,默认值为 0(保留全部层级)。
      • 若设为 1:则去掉最下层文件夹(即文件直接父文件夹被忽略)。
        • 上例输出变为:<输出根>\番剧A\番剧A 01.mp4
      • 若设为 2:同时去掉最末两级文件夹,最终扁平输出到输出根。
    • 实时预览:输入深度后,下方显示一个示例路径字符串(如“当前设置结果示例:E:\已完成\番剧A\番剧A 01.mp4”),方便理解。
    • 零散文件处理:对于直接位于拖入根目录下(无子文件夹)的配对,无论深度设为多少,都直接输出到输出根目录,不产生额外文件夹。
  • 源文件处理选项
    • 复选框:合并完成后删除原始 m4s 文件默认不勾选
    • 该选项仅作为许可开关,实际删除前还需二次确认。

2.6 合并处理

  • 用户点击「开始合并」,工具按配对队列顺序依次处理。
  • 每个任务调用 ffmpeg 进行流复制合并,保留原始质量。
  • 进度显示
    • 顶部总进度条(按已完成任务数/总任务数推进)。
    • 底部状态文本显示“正在处理:xxx.mp4”。
  • 合并完成:弹出结果摘要(成功 X 个,失败 Y 个)。
  • 删除源文件二次确认
    • 仅当用户在设置中勾选了“合并后删除”选项并且至少有一个文件合并成功时,合并完成弹窗后立即再弹出一个确认对话框:“所有成功合并的源文件将被删除,确定吗?[是]/[否]”。
    • 用户确认后才执行删除(移至回收站,而非直接永久删除)。

2.7 其他辅助功能

  • 列表清空:可一键清除所有扫描结果,恢复初始状态。
  • 错误处理:单文件合并失败不会中断后续任务,日志记录详细错误信息(仅窗口底部简单显示,点击可查看完整日志)。
  • 输出文件重名处理:若输出目录已存在同名文件,弹出小对话框,提供:覆盖 / 自动重命名(添加后缀) / 跳过。用户可勾选“本次合并全部采用此选择”。

3. 用户界面设计(UI Layout)

窗口标题:B站m4s合并工具
尺寸:约 1100x700 像素,可自由缩放。

3.1 顶部工具栏

  • 按钮:📂 添加文件夹🧹 清空列表
  • 右侧文本:“就绪” / “正在处理...”

3.2 主区域(左侧,占 65% 宽度)

采用 QTabWidget 两个标签页:

标签1:「合并队列」

  • 显示所有已确认的合并任务(自动配对+手动配对)。
  • 表格列:
    • 状态图标(待合并✓ / 错误❌)
    • 输出文件名(可编辑)
    • 源视频文件(完整相对路径)
    • 源音频文件
    • 预计输出路径
  • 右键菜单:批量命名移除任务预览视频预览音频
  • 支持多选行(用于批量命名或移除)。

标签2:「待整理」

  • 专门显示零散未配对的纯视频和纯音频文件。
  • 表格列:类型图标(🎬 或 🔊)、文件名所在文件夹
  • 右键菜单:配对所选(需选中一视频一音频)、预览标记为“已完整”跳过
  • 支持多选(但配对按钮仅在恰好选中一个视频和一个音频时真正可用,否则灰显提示)。
  • 点击「配对」后,弹出小输入框让用户填写输出名。或者直接在表格中新增一行(在配对队列中出现)并立即进入编辑状态。

3.3 设置面板(右侧,占 35% 宽度)

采用分组框样式的垂直布局:

组1:输出格式

  • 标签:“输出格式”
  • 下拉框:mp4 (默认) / mkv / mov / flv

组2:输出目录

  • 标签:“统一输出到”
  • 行:文本框(显示路径)+ 浏览... 按钮
  • 下方灰字提示:“合并后的视频将全部放置于此目录下(保留相对路径镜像)”

组3:路径层级

  • 标签:“保留文件夹层级深度(0为完整保留)”
  • 数字输入框,默认 0,最小值 0
  • 示例预览标签:“输出示例:E:...\番剧A\01\番剧A 01.mp4”(根据实际拖入路径动态更新)

组4:源文件处理

  • 复选框:“合并成功后允许删除原始 m4s 文件”
  • 下方灰字:“仅当勾选且合并全部成功后,会再次询问确认”

组5:操作按钮

  • 大按钮:▶ 开始合并(未完成设置或列表为空时禁用)
  • 下方状态提示:“请先添加文件夹并完成配对”

3.4 底部状态栏

  • 左侧:总进度条(占满剩余宽度)
  • 右侧:当前任务文字(如“正在合并: 番剧A 01.mp4”)

4. 系统处理流程(算法描述)

  1. 添加文件夹
    • 用户选择/拖拽文件夹路径 → 存储为“根路径列表”。
  2. 扫描阶段
    • 递归遍历所有根路径下的子目录,收集 .m4s 文件。
    • 对每个文件调用 ffprobe,解析 JSON,确定 video_onlyaudio_onlymuxed
    • 构建内部数据结构列表。
  3. 自动配对阶段(针对每个最底层子文件夹):
    • 分组统计该文件夹下的视频/音频文件。
    • count(video_only)=1count(audio_only)=1 → 创建配对,任务名=文件夹名。
    • 若数量相等且 > 1 → 按文件名排序后顺序配对,标记“多集”。
    • 若不满足以上条件 → 文件留入“待整理”池。
    • 所有 muxed 文件单独列表。
  4. 界面填充
    • “合并队列”加载所有自动配对任务。
    • “待整理”加载剩余零散文件。
    • “已完整”文件暂存入内部列表,不显示在主要标签页(可后续通过菜单查看)。
  5. 手动整理交互
    • 用户在“待整理”中手动配对并命名 → 实时更新“合并队列”。
    • 用户可随时切换标签进行编辑、重命名、删除任务等。
  6. 开始合并
    • 检查输出目录非空,若无则提示。
    • 遍历合并队列每个任务:
      • 计算输出路径(依据输出根、相对路径、路径深度、输出名、格式)。
      • 创建目标文件夹(os.makedirs)。
      • 组装 ffmpeg 命令:ffmpeg -i video.m4s -i audio.m4s -c copy -map 0:v:0 -map 1:a:0 -y "输出路径"-y 需结合重名策略调整)。
      • 使用 subprocess.Popen 执行,不解析内部进度,仅等待结束。
      • 依据返回码判断成功/失败,更新状态和进度条。
    • 合并循环结束后:
      • 显示结果摘要。
      • 如果设置允许删除且至少有一个成功,弹出确认删除对话框。
      • 用户确认后,遍历成功任务的源文件,调用 send2trash 移入回收站(避免彻底删除)。
  7. 错误处理
    • ffmpeg 执行失败时,该行标记为红色错误状态,记录 stderr 信息到内存日志,继续下一个。
    • 重名策略:检测到输出文件已存在时弹出对话框(覆盖/重命名/跳过),可勾选应用到所有后续。

5. 技术实现细节

  • 语言/框架:Python 3.9+,PySide6。
  • ffmpeg 依赖:需要系统已安装 ffmpeg 并加入 PATH。工具启动时自动检测 ffmpeg -version,若不可用则弹出警告并禁用合并按钮。
  • ffprobe JSON 解析
    ffprobe -v quiet -print_format json -show_streams "文件路径"
    
    解析 streams 数组,查找 codec_typevideoaudio
  • 预览实现os.startfile(filepath)
  • 路径镜像计算
    • 用户在拖入时,记住每个添加的文件夹的绝对路径,作为 root_paths
    • 对于一个源文件所在的绝对目录 file_dir,找到它是哪个 root 的子路径,得到 relative = os.path.relpath(file_dir, root)
    • 输出结构基于 relative 和用户设置的深度进行裁剪(去掉最后 N 级子目录)。
  • 路径深度裁剪算法
    • relative 分割成各级目录列表,例如 ['番剧A', '01']
    • depth >= len(parts),则结果为输出根(扁平)。
    • 否则保留前 len(parts)-depth 部分。
  • 删除文件:使用 send2trash 第三方库,安全删除至回收站。若无此库则退化为永久删除(需警告)。
  • 打包:最终用 PyInstaller 生成单文件 exe,可包含 ffmpeg 依赖检测但不捆绑 ffmpeg。

6. 错误、边界与特殊情况

  • 无管理员权限:不影响程序功能,文件删除、写入正常用户目录即可。
  • 文件名含空格/特殊字符:ffmpeg 命令使用列表形式传递参数,避免 shell 注入。
  • 媒体流异常(如一个文件同时有多个视频轨):解析时优先取第一个视频流和第一个音频流,并在界面备注。
  • 超大文件夹:性能上采用逐文件分析,扫描时用多线程避免界面冻结,但初期可简单用单线程 + 进度提示。
  • 输出磁盘空间不足:合并失败会捕获异常并提示。

7. 开发与交付计划

  1. 环境搭建:创建虚拟环境,安装 PySide6、send2trash 等。
  2. 核心工具函数:ffprobe 解析、配对逻辑、路径计算。
  3. 界面骨架:主窗口、标签页、表格、设置面板。
  4. 交互功能:拖拽、列表刷新、右键菜单、命名编辑。
  5. 合并引擎:调用 ffmpeg、进度更新、错误处理、删除逻辑。
  6. 测试与优化:各种 IDM 下载场景测试。
  7. 打包:PyInstaller 生成 exe。

以上即为完全详尽的最终设计,涵盖了所有功能定义、界面细节和技术实施路径。如确认无误,我就开始进入编码阶段。