BDMV → Emby Builder 只读分析 Blu-ray BDMV,根据 MPLS 播放关系识别电影、剧集和附加内容,并生成适合 Emby 扫描的派生媒体目录。完整单 M2TS 可以直接复制或硬链接;确属同一逻辑视频的分段和裁切范围则无损重封装,不重新编码视频、音频或字幕。
本项目源于作者的个人使用需求。 开发目的是在保留原始 BDMV 的同时,更方便地生成符合 Emby 命名和目录习惯的媒体库。代码公开在 GitHub,主要用于留存项目,也希望能为有类似需求的用户提供参考或直接使用。项目将随作者自身需求不定期更新,目前没有固定的维护计划或功能路线图。
真实原盘的扫描、规划和构建目前只在 macOS 上验证过;代码和自动化测试包含 Linux、Windows 兼容处理,但尚未在这两个系统上完成真实 BDMV 与 libbluray 工作流验证。
本项目是非官方工具,与 Emby LLC 或 Blu-ray Disc Association 没有隶属、授权或背书关系。
- 递归发现单张或多张 BDMV,读取 META、MPLS、PlayItem、Entry Mark、连接条件、多角度、SubPath 和 SubPlayItem;
- 离线选择电影主标题、拆分剧集 episode,并收集同盘或纯特典盘中的附加内容;
- 支持一集一个 M2TS、一集跨多个 M2TS,以及有充分 playlist/章节证据时一个 M2TS 包含多集的结构;
- 排除重复 playlist、菜单循环和明显的交互导航结构;
- 支持直接复制、硬链接和无损重封装三种处理策略;
- 输出可审核的计划、dry-run、构建结果和状态文件;
- 写入前检查路径、文件身份、硬链接能力和剩余空间,写入后检查时长、轨道和时间线;
- 不访问在线元数据服务,不移动、重命名或修改源 BDMV。
程序不执行 BD-J 菜单,也不能稳定取得花絮的自然语言名称。无法充分证明的逻辑边界会保持整体或产生警告,不会使用作品名、盘号或固定 playlist ID 特判。
- Python 3.11 或更高版本;
- FFmpeg 和 FFprobe;
- 普通完整 playlist 需要多段或裁切重封装时,FFmpeg 必须支持 libbluray 的
blurayprotocol。
项目没有第三方 Python 运行时依赖。建议安装到项目内虚拟环境:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e .
bdmv-emby-builder --helpmacOS 可通过 Homebrew 安装带 libbluray 的构建:
brew install ffmpeg-full仅当当前 shell 没有找到 ffmpeg-full 时,才需要调整 PATH。也可以使用环境变量或 TOML 指定程序位置:
export BDMV_EMBY_FFMPEG="/path/to/ffmpeg"
export BDMV_EMBY_FFPROBE="/path/to/ffprobe"Linux 和 Windows 需要自行安装带 libbluray 的 FFmpeg 构建。无论使用哪个平台,都应先检查实际生效的程序:
bdmv-emby-builder doctor涉及普通 playlist 重封装时,检查结果中的 bluray_protocol 应为 true。
复制 config.example.toml 为本地任务文件,例如 task.toml:
[task]
source = "/absolute/path/to/BDMV_LIBRARY"
destination = "/absolute/path/to/EmbyLibrary"
[[disc]]
path = "Movie/MAIN_DISC"
disc_type = "movie"
processing = "copy_remux"
[[disc]]
path = "Movie/BONUS_DISC"
disc_type = "bonus"
title = "Movie Name"推荐执行顺序:
# 检查环境
bdmv-emby-builder doctor --config task.toml
# 生成计划,不写媒体
bdmv-emby-builder plan --config task.toml --out plan.json
# 解析最终 copy / hardlink / remux 动作,不写媒体
bdmv-emby-builder build plan.json --results dry-run-results.json
# 先构建一个任务并播放确认
bdmv-emby-builder build plan.json --execute \
--only JOB_ID --results one-job-results.json
# 执行完整计划
bdmv-emby-builder build plan.json --execute \
--results build-results.json
# 检查目标库状态
bdmv-emby-builder status "/absolute/path/to/EmbyLibrary"可选的 scan 命令用于导出更底层的只读结构:
bdmv-emby-builder scan "/absolute/path/to/BDMV_LIBRARY" --out scan.jsonplan.json 是程序生成的审核产物,不是人工配置文件。重新规划后应重新执行 dry-run,不要手工修改计划后继续构建。
每个 TOML 文件描述一次任务。[task] 保存本次输入和输出;每个 [[disc]] 保存一张盘需要人工指定的类别、作品归属和处理策略。
| 字段 | 必填 | 说明 |
|---|---|---|
source |
是 | 单张盘根目录或包含多张盘的根目录;其下应能发现 BDMV,不能直接指向 BDMV 本身 |
destination |
是 | Emby 派生媒体根目录,不能位于 source 内 |
建议使用绝对路径。命令行位置参数可以临时覆盖这两个字段。
| 字段 | 必填 | 说明 |
|---|---|---|
path |
多盘任务需要 | 相对于 task.source 的盘目录;单盘任务可以省略 |
disc_type |
是 | movie、series、bonus 或 ignore |
title |
否 | 覆盖作品目录名,或把主盘、特典盘和多版本归入同一作品 |
edition |
否 | 同作品、同分辨率存在多个剪辑时使用的版本标签 |
processing |
否 | copy_remux、hardlink_remux 或 hardlink_only |
hardlink_only_failure |
否 | block_disc 或 skip_job,仅影响 hardlink_only |
season |
否 | 仅限 series;覆盖季号,0 表示 Specials |
episode_start |
否 | 仅限 series;指定该盘第一集集号 |
disc_type 表示盘的主要用途,不限制盘内只能存在一种内容:
movie:选择一部电影主标题,其余有效内容进入 extras 候选;series:识别一个或多个 episode,其余有效内容进入 extras 候选;bonus:不选择正片,全部有效内容按 extras 规则筛选;ignore:忽略该盘。
配置不接受 playlist ID、单条花絮名称或单独的输出文件名。程序负责技术规划,用户负责确认作品归属、季号、多版本以及无法从 BDMV 判断的内容语义。
作品标题按以下优先级确定:
[[disc]].title;- 命令行
--title; - BDMV META 日文标题;
- META 英文或其他标题;
- 盘目录名。
季号按 [[disc]].season、命令行 --season、META/目录中的明确季标、默认第 1 季依次确定。默认季号会在计划中标记为低置信度;同一作品、季和 edition 的多张盘会连续编号,必要时可用 episode_start 修正起始集数。
所有设置均可省略。
| 字段 | 默认值 | 说明 |
|---|---|---|
extra_min_seconds |
60 |
附加内容候选最低时长 |
container |
"m2ts" |
输出容器,可选 m2ts 或 mkv |
extras_folder |
"extras" |
本次任务统一使用的 Emby 附加内容目录 |
remux_backend |
"auto" |
auto、bluray 或显式接受限制的 concat |
copy_boundary_tolerance_seconds |
0.1 |
判断 PlayItem 是否完整覆盖 M2TS 的边界误差 |
duration_tolerance_seconds |
2.0 |
成品相对 MPLS 逻辑时长的允许误差 |
minimum_free_space_bytes |
5368709120 |
目标卷固定最小剩余空间 |
free_space_margin_ratio |
0.05 |
目标文件系统容量预留比例 |
batch_space_check |
true |
执行前检查整批任务空间 |
hardlink_only_failure |
"block_disc" |
hardlink_only 失败时整盘阻塞或逐项跳过 |
ffmpeg |
"ffmpeg" |
FFmpeg 命令或路径 |
ffprobe |
"ffprobe" |
FFprobe 命令或路径 |
主标题优先采用本盘 FFmpeg/libbluray 的相关标题结果;不可用时才回退到本盘最长有效候选并产生警告。对于 BDMV META 标题具有连续编号的电影合集,程序会比较无歧义同行盘的本地选择;如果相同 playlist 编号在目标盘上也对应合理长候选但与本盘结果冲突,只记录审核提示,不自动覆盖本盘选择。编号连续、至少两张同行盘支持且覆盖全部同行盘 80% 以上时标为强提示;能形成唯一建议但不满足这些条件时标为弱提示。该提示本身不会增加构建阻塞,实际可执行性仍由所选处理模式、源文件完整性和安全校验决定。计划会按所选模式处理本盘主标题,并把符合附加内容筛选条件的其他有效长候选写入 extras/,供用户播放后在派生目录中更名或移动。
剧集拆分优先使用原盘明确关系,包括完整独立 PlayItem、连续覆盖主标题的独立单集 playlist,以及具有可靠 Entry Mark、连接条件和时长旁证的 PlayItem/章节分组。多角度、逻辑连续连接、重复 clip、无法证明安全的 SubPath 或边界证据不足时不会拆分。
程序会对满足严格条件的短时静音、静态系统卡进行复核。电影硬链接模式只有在计划和构建阶段都能重新证明时才允许排除;低置信度的短 extras 只增加人工复核提示,不会自动删除。该功能不使用 OCR。
完整识别约束见处理与重封装设计。
| 模式 | 完整单 M2TS | 分段或裁切内容 | 适合场景 |
|---|---|---|---|
copy_remux |
逐字节复制 | 无损重封装 | 默认;希望派生库与原盘文件身份独立 |
hardlink_remux |
同文件系统优先硬链接,失败时复制 | 无损重封装 | 希望减少一对一文件的额外空间占用 |
hardlink_only |
只允许硬链接 | 不处理 | 只接受零额外媒体数据的一对一映射 |
重封装使用 stream copy,主要消耗磁盘读写,CPU 占用通常远低于转码。
hardlink_only 默认在同盘任一已规划输出无法硬链接时阻塞整盘。设置 hardlink_only_failure = "skip_job" 后,只跳过无法硬链接的已规划输出,不会降级为复制或重封装。若主标题本身无法可靠识别,规划仍会直接失败。
硬链接成品与源 M2TS 共享文件内容。删除或重命名一侧目录项不会删除另一侧,但原地修改任一文件会同时影响两边;应把硬链接媒体视为只读。
电影和剧集使用 Emby 常见目录结构:
EmbyMovies/
└── Movie Name/
├── Movie Name - 1080p.m2ts
└── extras/
└── Bonus Disc - PL00004-P01 - 000042.m2ts
EmbyTV/
└── Series Name/
├── Season 01/
│ ├── Series Name - S01E01 - 1080p.m2ts
│ └── Series Name - S01E02 - 1080p.m2ts
└── extras/
分辨率标签来自选中正片的实际视频流。
程序默认把识别出的附加内容统一写入作品目录下的 extras/,文件名仅由盘标题、playlist/分段编号和时长组成。这个文件名用于稳定定位来源,不表示程序已经判断出内容类别。
BDMV 通常不能可靠说明一段内容是预告、访谈、OP/ED、广播内容还是幕后花絮。构建完成后,用户应逐项播放确认,并仅在 Emby 派生目录中自行更名或移动到合适的分类目录。
extras_folder 可以把整个任务的附加内容改为 Emby 支持的其他目录,例如 specials、shorts、scenes、featurettes、behind the scenes、deleted scenes、interviews 或 trailers,但不会逐条自动分类。需要参与剧集刮削和播放顺序的正式 Special 应人工放入 Season 00 或 Specials,并按 S00E01 等格式命名。具体规则以 Emby 电影命名和剧集命名文档为准。
执行前至少确认:
warnings、正片/episode/extras 数量和playlist_selection;main_selection_evidence中的本盘选择、合理长候选及跨盘提示;- 季号、集号、多版本归属和输出路径;
playlist_segment、源 M2TS、in/out 范围;- dry-run 中的最终
operation和预计空间; - 标记为
content_review的附加内容。
scan、plan 和未加 --execute 的 build 不写媒体。实际构建只在目标根中创建文件,默认不覆盖已有成品;使用 --overwrite 前应先确认目标。媒体先写入随机临时文件,校验通过后再原子替换。构建结果和目标目录中的 .bdmv-emby-state.json 会保留主标题选择证据;status 同时展示该证据,并检查缺失、内容变化及硬链接身份。
任务 TOML、scan、plan、results 和 state 通常包含绝对路径、目录名和媒体库清单,应视为本地隐私数据,不要未经检查上传。更完整的边界见隐私与安全。
原始 BDMV 是源归档,Emby 目录是派生数据。两者位于同一块硬盘时不构成备份;确认输出前不要删除原盘,正式备份应位于独立存储介质。
- 自动主标题选择、同盘多部长片、多剪辑版和复杂多角度内容仍需人工审核;
- 花絮自然语言名称和语义类别通常不能从 BDMV 稳定获得;
- M2TS 对章节及丰富轨道元数据的表达有限,章节主要保存在计划和状态中;
- 重新规划不会自动删除旧计划不再引用的派生文件;
- 真实原盘工作流目前只在 macOS 验证,Linux 和 Windows 用户应先用少量内容测试。
本项目采用 MIT License。