Skip to content

Commit 19240b0

Browse files
committed
docs: document font subsetting, config v3, dependency resolution, and GUI changes
Update README (EN/CN) and the architecture, roadmap, security, and troubleshooting docs to reflect font subsetting (referenced/subset modes), config schema v3 with ffmpeg/notifications sections, external dependency resolution, snapshot digest verification, and the new GUI controls.
1 parent 64930ca commit 19240b0

6 files changed

Lines changed: 69 additions & 18 deletions

File tree

README.CN.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
<p align="center">
2+
<picture>
3+
<source media="(prefers-color-scheme: dark)" srcset="./logo/svg/plexmuxy-lockup-dark.svg" />
4+
<source media="(prefers-color-scheme: light)" srcset="./logo/svg/plexmuxy-lockup-light.svg" />
5+
<img src="./logo/svg/plexmuxy-lockup-light.svg" width="640" alt="PlexMuxy" />
6+
</picture>
7+
</p>
8+
19
# Plex 视频批量封装工具(PlexMuxy)
210

311
PlexMuxy 用于将视频、外挂音频、ASS/SSA 字幕和字体安全地批量封装为 Matroska 文件。CLI 与桌面 GUI 共用同一套计划和执行服务。
@@ -53,7 +61,7 @@ plexmuxy mux D:\Media --cleanup delete --yes
5361
plexmuxy diagnostics --output diagnostics.zip
5462
```
5563

56-
可用覆盖参数包括 `--output-dir``--output-suffix``--name-strategy``--name-template``--extra-dir``--overwrite``--cleanup`
64+
可用覆盖参数包括 `--output-dir``--output-suffix``--name-strategy``--name-template``--extra-dir``--font-mode``--overwrite``--cleanup`。例如 `--font-mode subset` 会为本次计划启用字体子集化
5765

5866
## 配置与兼容性
5967

@@ -63,6 +71,10 @@ plexmuxy diagnostics --output diagnostics.zip
6371

6472
默认匹配策略保守:`movie_fallback=false`、最低置信度 0.7、歧义项跳过。并发配置为 `max_parallel_mux_jobs`,范围 1–4,默认 1;旧 `thread_count` 仅用于迁移。
6573

74+
桌面端的“环境配置”是独立于任务工作流的持久化页面。它优先显示环境变量与 `PATH` 的自动探测结果;自动探测失败时,可通过系统文件选择器指定 `mkvmerge``ffmpeg``unrar`。Windows 构建在创建原生窗口前启用 Per-Monitor V2 DPI 感知,因此文件选择器和 WebView 在高分辨率、多显示器环境中使用系统缩放。
75+
76+
Windows 可在该页面启用任务结束通知。当前实现使用 Windows Shell 的原生通知区域后端,覆盖任务完成、失败和取消;通知不可用不会影响封装结果。需要应用激活、操作按钮和通知中心身份的 Windows App SDK 通知属于后续安装器/应用身份工作。
77+
6678
## 文件匹配
6779

6880
优先级为:完全同名(1.0)→ 标准化标题(0.85)→ 标准化集数身份(0.70)→ 可选的单视频电影回退。支持 `[1]``[100]``S01E01``S01EP01``E01``EP01``.01.``SP01``Special``OVA`
@@ -71,11 +83,13 @@ plexmuxy diagnostics --output diagnostics.zip
7183

7284
## 字体、压缩包和源轨道
7385

74-
`font.mode=all` 默认附加全部字体;`referenced` 会读取 ASS/SSA 样式字体与 `\fn` 覆盖标签;找不到字体时按 `missing_font_action` 处理。`subset` 当前安全回退为“引用到的完整字体”,不会生成已知缺字的子集。
86+
`font.mode=all` 默认附加全部字体;`referenced` 使用 ASS/SSA 结构解析与字体内部名称选择完整字体;`subset` 会真正生成只含所需字符的字体附件。子集模式按动态 `Format`、Style 和 override 状态解析 `\fn``\r``\b``\i``\p``\t(...)`,枚举 TTF/OTF/TTC/OTC 的全部 face,并按内部 family、weight、italic 和 cmap 做确定性匹配。临时字幕只把已验证 family 改为 `PMX_<hash>` alias,源字幕和源字体不会被修改。
87+
88+
所有视频的子集字体和临时字幕必须先在执行专用工作区完成并重新验证,之后才会启动任何 `mkvmerge` 进程。同一执行中的相同子集会复用缓存;工作区在成功、失败或取消后统一删除。FontTools 无法安全处理某个已匹配 family 时,默认只为该 family 附加完整原字体并保留原字体名;字体缺失、匹配歧义、缺字、无法安全解析的 ASS 或无法区分的无 BOM GB18030/CP932 编码不会静默继续。可通过 `missing_font_action``subset_failure_action` 选择跳过视频、终止任务或允许的完整字体回退。
7589

7690
ZIP/7z 在写入前检查压缩包大小、文件数、展开总大小、单文件大小和目录深度,并阻止路径穿越;RAR 无法可靠预检时必须显式允许。同名同内容字体去重,同名不同内容字体自动改名并报告冲突。
7791

78-
计划阶段会读取源容器轨道并展示。0.2 的产品决策是默认保留全部源轨道;未知语言、无标题轨道不得自动删除
92+
输出验证会同时核对字体附件名称和 MIME type。计划阶段也会读取源容器轨道并展示;默认保留全部源轨道,未知语言和无标题轨道不得自动删除
7993

8094
## 开发与验证
8195

README.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
<p align="center">
2+
<picture>
3+
<source media="(prefers-color-scheme: dark)" srcset="./logo/svg/plexmuxy-lockup-dark.svg" />
4+
<source media="(prefers-color-scheme: light)" srcset="./logo/svg/plexmuxy-lockup-light.svg" />
5+
<img src="./logo/svg/plexmuxy-lockup-light.svg" width="640" alt="PlexMuxy" />
6+
</picture>
7+
</p>
8+
19
# PlexMuxy
210

311
PlexMuxy safely batches video, external audio, ASS/SSA subtitles, and font attachments into Matroska files for Plex. The CLI and desktop GUI use the same planning and execution service.
@@ -56,7 +64,7 @@ plexmuxy mux D:\Media --cleanup delete --yes
5664
plexmuxy diagnostics --output diagnostics.zip
5765
```
5866

59-
Useful job overrides include `--output-dir`, `--output-suffix`, `--name-strategy`, `--name-template`, `--extra-dir`, `--overwrite`, and `--cleanup`.
67+
Useful job overrides include `--output-dir`, `--output-suffix`, `--name-strategy`, `--name-template`, `--extra-dir`, `--font-mode`, `--overwrite`, and `--cleanup`. For example, `--font-mode subset` enables font subsetting for that plan.
6068

6169
## Configuration
6270

@@ -89,6 +97,10 @@ Important defaults:
8997

9098
Parallel mux jobs are intentionally limited to 1–4 and default to 1. The old `thread_count` key is accepted only for migration. Archive limits apply before ZIP/7z extraction; uninspectable RAR archives require explicit permission.
9199

100+
The desktop “Environment configuration” view is persistent and separate from job options. It shows environment-variable and `PATH` discovery first, then offers a native file picker for `mkvmerge`, `ffmpeg`, or `unrar` when automatic discovery fails. Windows builds opt into Per-Monitor V2 awareness before creating native windows so the WebView and file dialogs follow system scaling on high-DPI and mixed-monitor setups.
101+
102+
Windows job notifications can be enabled on that page. The current native Windows Shell backend covers completed, failed, and cancelled jobs, and notification failures never change a mux result. Action buttons, application activation, and durable notification-center identity require a future installer/application-identity integration with the Windows App SDK.
103+
92104
## Matching
93105

94106
Each subtitle or external audio file is assigned once using this priority: exact stem (1.0), normalized title (0.85), normalized episode identity (0.70), and optional controlled single-video movie fallback. Episode parsing supports `[1]`, `[100]`, `S01E01`, `S01EP01`, `E01`, `EP01`, `.01.`, `SP01`, `Special`, and `OVA`.
@@ -97,7 +109,11 @@ Equal best candidates become `ambiguous_match` and are skipped. Low-confidence c
97109

98110
## Fonts and source tracks
99111

100-
`font.mode=all` preserves the compatibility-first behavior. `referenced` parses ASS/SSA style font names and `\fn` overrides, matches font metadata, and follows `missing_font_action`. `subset` currently falls back to referenced full fonts and reports that decision; it never emits a knowingly incomplete subset.
112+
`font.mode=all` preserves the compatibility-first behavior. `referenced` uses the structural ASS/SSA parser and internal font names to select complete fonts. `subset` performs real glyph subsetting: it follows dynamic `Format` fields plus Style and override state (`\fn`, `\r`, `\b`, `\i`, `\p`, and `\t(...)`), enumerates every TTF/OTF/TTC/OTC face, and deterministically matches internal family, weight, italic, and cmap metadata. Temporary subtitles rewrite only validated families to `PMX_<hash>` aliases; source subtitles and fonts are never modified.
113+
114+
Every plan in a batch is prepared and revalidated in an execution-scoped workspace before any `mkvmerge` process starts. Identical subset work is cached for that execution and the workspace is removed after success, failure, or cancellation. If FontTools cannot safely subset a matched family, the default policy attaches that family’s complete source faces without rewriting its name. Missing or ambiguous fonts, missing glyphs, structurally unsafe ASS, and ambiguous BOM-less GB18030/CP932 input are never silently treated as safe subsets. Configure `missing_font_action` and `subset_failure_action` for the permitted skip, fail-job, or full-font behavior.
115+
116+
Output verification checks the expected attachment file names and MIME types as well as track properties and counts.
101117

102118
Source container tracks are read with `mkvmerge -J` and shown in plans. The 0.2 product decision is to preserve all source tracks. Filter configuration is reserved for explicit future use; unknown languages and untitled tracks must remain included.
103119

docs/architecture.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,23 @@ CLI / GUI
55
66
Service (plan snapshot, progress, cancellation, bounded concurrency)
77
8-
Scanner → Matcher → Planner
9-
↓ ↓
10-
Archive/font safety Source-track inspection
8+
Scanner → Matcher → Planner → ASS analysis → Font face matching
9+
↓ ↓ ↓
10+
Archive/font safety Source-track inspection Immutable subset intent
11+
12+
Execution workspace → subset + alias rewrite + validation
1113
1214
Mux subprocess → Structural verifier → Batch cleanup
1315
```
1416

1517
The adapters validate user payloads and call `plexmuxy.service`; they do not implement mux policy. `scanner` classifies files without following symlinks or hidden paths by default. `matcher` globally assigns each candidate so a file cannot silently attach to two videos. `planner` creates deterministic outputs, tracks, attachment intent, and cleanup candidates.
1618

17-
`snapshot` records the normalized config plus size and nanosecond modification time for every existing input. Execution validates it and rechecks output appearance. Deserialization requires absolute paths and reconstructs typed models; output paths are recomputed from the saved configuration to reject edited plan paths.
19+
`snapshot` records the normalized config plus size and nanosecond modification time for every input. Schema 2 also records SHA-256 digests for subtitles, fonts, and font archives, together with deterministic subset intent; generated workspace paths are never serialized. Execution validates the snapshot and rechecks output appearance. Deserialization requires absolute paths and reconstructs typed models; output paths are recomputed from the saved configuration to reject edited plan paths.
1820

19-
`muxer` owns the `mkvmerge` subprocess so cancellation can terminate it. It never writes directly to the final pathname. `verify_mux_output` parses `mkvmerge -J`, distinguishes execution and verification error codes, and verifies expected structure. `cleanup` operates once, after all jobs settle, using dependency groups for shared files.
21+
Subset execution is deliberately two-phase. `ass_analysis`, `font_catalog`, and `font_matching` produce immutable intent during planning. After snapshot validation, `font_prepare` materializes archive members, subsets every selected face, validates cmap/name/style metadata, and rewrites temporary ASS/SSA files. Every plan must finish preparation before the bounded mux pool starts. `SubsetWorkspace` owns all generated files and removes them only after every mux worker exits.
2022

21-
The GUI `PlexMuxyApi` starts daemon-backed jobs and exposes `start_job`, `get_job_status`, `get_job_report`, and `cancel_job`. Progress events are plain core objects; the core package has no GUI dependency.
23+
`muxer` owns the `mkvmerge` subprocess so cancellation can terminate it. It never writes directly to the final pathname. Prepared runtime plans replace only subtitle and attachment inputs while results retain the original immutable plan. `verify_mux_output` parses `mkvmerge -J`, distinguishes execution and verification error codes, and verifies expected structure, attachment names, and MIME types. `cleanup` operates once, after all jobs settle, using dependency groups for shared files.
24+
25+
The GUI `PlexMuxyApi` starts daemon-backed jobs and exposes `start_job`, `get_job_status`, `get_job_report`, and `cancel_job`. Progress events include preparation, family, mux, verification, and cleanup phases; the core package has no GUI dependency. Persistent dependency paths and the Windows notification preference live in config version 3 and are not job overrides.
2226

2327
Source audio filtering is deliberately not enabled in 0.2. Plans expose source track metadata, but the preservation rule is the product default. Any future filter must be opt-in, list kept/excluded tracks with reasons, and retain unknown metadata by default.

docs/roadmap.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# Deferred follow-up work
22

3-
The 0.2 scope intentionally preserves source tracks and full/referenced fonts. Proposed follow-up issues:
3+
PlexMuxy now includes structural ASS/SSA analysis, real FontTools glyph subsetting, deterministic alias rewriting, TTC/OTC face handling, and execution-scoped cache/fallback. Remaining proposed follow-up issues:
44

5-
- ASS/SSA font alias analysis and richer missing-font reporting.
6-
- True glyph subsetting with fontTools, including CJK, shaping, OpenType features, TTC collections, and deterministic full-font fallback.
5+
- Optional HarfBuzz repacking and FFmpeg/libass golden-frame parity fixtures for more scripts and font formats.
6+
- Versioned persistent subset caching after FontTools/HarfBuzz compatibility keys are defined.
7+
- Windows App SDK notifications with installer-provided application identity, activation, and action buttons.
78
- Source audio preview and explicit commentary/language/title filters; unknown tracks must be kept.
89
- Multi-directory queue, persisted job history, and safe manual plan editing.
9-
- Internationalized CLI/GUI resources and optional update checks.
10+
- Internationalized CLI resources and optional update checks.
1011
- Optional Plex library scan integration isolated from the mux transaction.

docs/security.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ PlexMuxy treats source media as irreplaceable.
66
- Existing outputs require overwrite opt-in. Muxing still uses a unique temporary path, so a failed subprocess cannot corrupt the previous output.
77
- Delete cleanup and font-directory deletion require confirmation. Verification failure, cancellation, partial batch failure, and missing attachments suppress cleanup.
88
- `move` never overwrites an `Extra` file; it creates `name (1).ext`, `name (2).ext`, and so on.
9-
- Saved plans are untrusted input. Absolute paths, tracked file metadata, recomputed output paths, configuration hashes, attachment containment, and newly appeared outputs are checked before execution.
9+
- Saved plans are untrusted input. Absolute paths, tracked file metadata, recomputed output paths, configuration hashes, attachment containment, newly appeared outputs, and SHA-256 digests for subtitles/fonts/font archives are checked before execution.
1010
- ZIP/7z members are checked for path traversal and configurable size/count/depth limits before extraction. RAR is denied by default when metadata cannot be safely inspected.
11+
- Subset fonts and rewritten subtitles are created only under an execution-scoped system temporary directory, written through temporary names, reopened and validated, and removed after every mux worker exits. They are never added to user cleanup candidates.
12+
- Ambiguous font matches, missing glyphs, unsafe ASS/SSA structures, and ambiguous legacy encodings cannot silently enter the subset pipeline. Full-font fallback is limited to explicit policy branches.
1113
- Diagnostic archives contain no media and redact configured directories.
1214

1315
Treat any report of unintended overwrite, move, or deletion as release-blocking. Stop distribution, mark the release as affected, publish a warning, reproduce using copies, and ship a patch only after the data-safety regression suite passes.

docs/troubleshooting.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## `MKVMERGE_NOT_FOUND`
44

5-
Install MKVToolNix, add `mkvmerge` to `PATH`, or set the full executable/directory in `mkvmerge.path`. Run `plexmuxy diagnostics --output diagnostics.zip` to record the detected version.
5+
Install MKVToolNix, add `mkvmerge` to `PATH`, set the executable/directory in `mkvmerge.path`, or use GUI → Environment configuration → mkvmerge → Browse. An invalid explicit path is reported instead of silently falling back to a different binary. Run `plexmuxy diagnostics --output diagnostics.zip` to record the detected version.
66

77
## No plan was generated
88

@@ -28,6 +28,20 @@ Pass `--yes` only after reviewing the plan. The GUI presents a destructive-actio
2828

2929
Corrupt archives, resource-limit violations, path traversal, and uninspectable RAR files are reported. Extract RAR fonts manually into `Fonts`, or explicitly opt into uninspected extraction only for trusted archives.
3030

31+
## `font_subset_blocked` or `FONT_SUBSET_FAILED`
32+
33+
Planning blocks a video when a font is missing or ambiguous, a selected face lacks required characters, or the ASS/SSA structure cannot be analyzed and rewritten safely. BOM-less byte sequences that are both valid GB18030 and CP932 but decode differently are intentionally rejected. Use a correctly encoded/BOM-tagged subtitle, install the exact referenced font, or choose a documented `missing_font_action`; do not rename an unrelated font to bypass matching.
34+
35+
At execution time, `FONT_SUBSET_FAILED` means a previously matched source changed or a verified runtime subset/rewrite could not be produced. The default `subset_failure_action=fallback-full` applies only to a concrete matched family that cannot be subset safely. `skip-video` isolates the affected video and `fail-job` stops the batch before any mux process starts.
36+
37+
## A diagnostic path did not fit in the title bar
38+
39+
Transient results such as diagnostics export paths now appear in a wrapping toast with an “Open folder” action. The title bar is reserved for persistent state such as a missing required dependency and an active job.
40+
41+
## Windows notification is unavailable
42+
43+
Notifications require the Windows GUI build, its packaged ICO, and the pywebview Windows runtime. Use the test button on Environment configuration. The setting is disabled when capability detection fails; mux completion is unaffected. The current backend is a Windows Shell notification-area balloon, not an actionable Windows App SDK notification with application activation.
44+
3145
## GUI does not start
3246

33-
Install `plexmuxy[gui]`. On Windows, install the WebView2 Evergreen Runtime. The CLI remains usable without GUI packages.
47+
Install `plexmuxy[gui]`. On Windows, install the WebView2 Evergreen Runtime. The CLI remains usable without GUI packages. If file dialogs scale incorrectly, use the packaged GUI whose manifest requests Per-Monitor V2 awareness rather than launching an older wrapper executable.

0 commit comments

Comments
 (0)