rendervd 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. rendervd-0.1.0/CHANGELOG.md +26 -0
  2. rendervd-0.1.0/LICENSE +21 -0
  3. rendervd-0.1.0/MANIFEST.in +16 -0
  4. rendervd-0.1.0/PKG-INFO +304 -0
  5. rendervd-0.1.0/README.md +270 -0
  6. rendervd-0.1.0/pyproject.toml +68 -0
  7. rendervd-0.1.0/rendervd/__init__.py +17 -0
  8. rendervd-0.1.0/rendervd/cli.py +1201 -0
  9. rendervd-0.1.0/rendervd/config.py +256 -0
  10. rendervd-0.1.0/rendervd/doctor.py +420 -0
  11. rendervd-0.1.0/rendervd/execution/__init__.py +1 -0
  12. rendervd-0.1.0/rendervd/execution/assets.py +20 -0
  13. rendervd-0.1.0/rendervd/execution/errors.py +13 -0
  14. rendervd-0.1.0/rendervd/execution/ingest.py +169 -0
  15. rendervd-0.1.0/rendervd/execution/pipeline.py +496 -0
  16. rendervd-0.1.0/rendervd/execution/probe.py +246 -0
  17. rendervd-0.1.0/rendervd/execution/replay.py +142 -0
  18. rendervd-0.1.0/rendervd/execution/reuse.py +79 -0
  19. rendervd-0.1.0/rendervd/execution/runner.py +85 -0
  20. rendervd-0.1.0/rendervd/execution/tracing.py +77 -0
  21. rendervd-0.1.0/rendervd/paths.py +90 -0
  22. rendervd-0.1.0/rendervd/planning/__init__.py +5 -0
  23. rendervd-0.1.0/rendervd/planning/audio.py +204 -0
  24. rendervd-0.1.0/rendervd/planning/command_graph.py +1233 -0
  25. rendervd-0.1.0/rendervd/planning/dvd_backup.py +117 -0
  26. rendervd-0.1.0/rendervd/planning/ingest.py +113 -0
  27. rendervd-0.1.0/rendervd/planning/lang.py +83 -0
  28. rendervd-0.1.0/rendervd/planning/makemkv_scan.py +165 -0
  29. rendervd-0.1.0/rendervd/planning/plan_builder.py +184 -0
  30. rendervd-0.1.0/rendervd/planning/probes.py +142 -0
  31. rendervd-0.1.0/rendervd/planning/titles.py +86 -0
  32. rendervd-0.1.0/rendervd/planning/video_analysis.py +590 -0
  33. rendervd-0.1.0/rendervd/subfix/__init__.py +5 -0
  34. rendervd-0.1.0/rendervd/subfix/options.py +68 -0
  35. rendervd-0.1.0/rendervd/subfix/planning.py +74 -0
  36. rendervd-0.1.0/rendervd/subfix/toolchain.py +37 -0
  37. rendervd-0.1.0/rendervd/subfix/vlc_clear.py +469 -0
  38. rendervd-0.1.0/rendervd/util.py +180 -0
  39. rendervd-0.1.0/rendervd.egg-info/PKG-INFO +304 -0
  40. rendervd-0.1.0/rendervd.egg-info/SOURCES.txt +43 -0
  41. rendervd-0.1.0/rendervd.egg-info/dependency_links.txt +1 -0
  42. rendervd-0.1.0/rendervd.egg-info/entry_points.txt +2 -0
  43. rendervd-0.1.0/rendervd.egg-info/requires.txt +8 -0
  44. rendervd-0.1.0/rendervd.egg-info/top_level.txt +1 -0
  45. rendervd-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ This project follows PEP 440 versions.
6
+
7
+ ## Unreleased
8
+
9
+ ## 0.1.0rc2 - 2026-02-13
10
+
11
+ - TestPyPI validation release.
12
+
13
+ - (placeholder)
14
+
15
+ ## 0.1.0rc1 - 2026-02-13
16
+
17
+ - TestPyPI validation release (Trusted Publishing/OIDC).
18
+
19
+ ## 0.1.0 - 2026-02-09
20
+
21
+ Initial public release.
22
+
23
+ - Core CLI: `plan`, `run`, `replay`.
24
+ - Diagnostics: `rendervd doctor` validates external tools and prints actionable output (JSON supported).
25
+ - Subtitles/Subfix: optional OCR/mux features are enabled automatically when supported tools are present; otherwise the pipeline stays deterministic and skips those phases.
26
+ - Packaging: PyPI-ready metadata, standard OSS repo files, and maintainer docs.
rendervd-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 rendervd contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,16 @@
1
+ include README.md LICENSE CHANGELOG.md pyproject.toml
2
+ recursive-include rendervd *.py
3
+
4
+ # Keep sdists clean: exclude maintainer-only material
5
+ prune docs
6
+ prune .github
7
+ prune tests
8
+ prune tools
9
+
10
+ global-exclude __pycache__
11
+ global-exclude *.py[cod]
12
+ global-exclude .pytest_cache
13
+ global-exclude *.trace.jsonl
14
+ global-exclude .DS_Store
15
+
16
+
@@ -0,0 +1,304 @@
1
+ Metadata-Version: 2.4
2
+ Name: rendervd
3
+ Version: 0.1.0
4
+ Summary: DVD/ISO → MP4 pipeline
5
+ Author: rendervd contributors
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/actx4gh/rendervd
8
+ Project-URL: Issues, https://github.com/actx4gh/rendervd/issues
9
+ Project-URL: Changelog, https://github.com/actx4gh/rendervd/blob/main/CHANGELOG.md
10
+ Project-URL: Documentation, https://github.com/actx4gh/rendervd/blob/main/README.md
11
+ Keywords: dvd,iso,ffmpeg,video,mp4,cli
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Multimedia :: Video
22
+ Classifier: Topic :: Utilities
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest; extra == "dev"
28
+ Requires-Dist: nox; extra == "dev"
29
+ Requires-Dist: ruff; extra == "dev"
30
+ Requires-Dist: mypy; extra == "dev"
31
+ Requires-Dist: build; extra == "dev"
32
+ Requires-Dist: twine; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ # rendervd
36
+
37
+ `rendervd` is a command-line tool that turns a DVD source (optical disc, ISO, or a DVD-Video backup directory) into an MP4.
38
+
39
+ This repository provides a **Python implementation** of `rendervd`, designed to be easy to install, test, and maintain.
40
+
41
+ `rendervd` orchestrates external tools (it does **not** reimplement codecs/demuxers):
42
+ - `ffmpeg` and `ffprobe` for ingest/probing/encoding
43
+ - `makemkvcon` (MakeMKV) for title scanning (auto-pick) and single-title ingest
44
+ - `dvdbackup` for mirroring optical discs to disk (optional, drive-only)
45
+ - `subocr` + `tesseract` and `mkvextract` (MKVToolNix) for OCR’ing bitmap DVD subtitles (optional; enabled by default when the toolchain is present)
46
+
47
+ ## What it does
48
+
49
+ - **One-shot mode:** `rendervd [options]` (plans + runs; produces the final MP4)
50
+ - **Two-phase mode:**
51
+ - `rendervd plan ...` (extracts + probes + analyzes, then emits a `plan.json`)
52
+ - `rendervd run plan.json` (executes the plan)
53
+ - **Replay:** `rendervd replay plan.json` replays the embedded external command graph best-effort
54
+ (requires the plan to be created with `--plan-include-commands`).
55
+
56
+ ## Requirements
57
+
58
+ - Python **3.10+**
59
+ - External tools available on `PATH`:
60
+ - **Required:** `ffmpeg`, `ffprobe`, `makemkvcon`
61
+ - **Optional (drive backup mode):** `dvdbackup` (used when `--dvd-src` is a block device like `/dev/sr0` and backup mode is `auto` or `--backup`)
62
+ - **Optional (Subfix / OCR toolchain):** `subocr`, `tesseract` (+ tessdata), and `mkvextract` (from MKVToolNix)
63
+
64
+ ### Doctor: validate your environment
65
+
66
+ Run:
67
+
68
+ ```sh
69
+ rendervd doctor
70
+ ```
71
+
72
+ This prints a categorized report of required/recommended/optional dependencies and key FFmpeg capabilities.
73
+
74
+ Exit codes:
75
+ - `0`: all required checks pass
76
+ - `1`: missing required tools or required FFmpeg capabilities
77
+ - `2`: required checks pass, but some recommended/optional components are missing
78
+
79
+ Machine-readable JSON:
80
+
81
+ ```sh
82
+ rendervd doctor --json
83
+ ```
84
+
85
+ ### FFmpeg build requirements
86
+
87
+ `rendervd` depends on FFmpeg features that are sometimes missing from minimal builds.
88
+
89
+ **Must-have**
90
+
91
+ - **H.264 encoder:** `libx264` (used for MP4 video encoding).
92
+ - Quick check:
93
+ ```sh
94
+ ffmpeg -hide_banner -encoders | grep -E '(^|\s)libx264(\s|$)'
95
+ ```
96
+ - If you build FFmpeg yourself, this typically means configuring with:
97
+ - `--enable-gpl --enable-libx264`
98
+
99
+ **Needed for multi-title stitch from DVD/ISO**
100
+
101
+ - **`dvdvideo` demuxer support** (used for the dvdvideo ingest path when stitching multiple titles).
102
+ - Quick check:
103
+ ```sh
104
+ ffmpeg -hide_banner -demuxers | grep -E '(^|\s)dvdvideo(\s|$)'
105
+ ```
106
+ - Builds without `dvdvideo` often lack the underlying DVD navigation/read libraries.
107
+ If building from source, ensure the FFmpeg build can find/enable common DVD libs such as
108
+ **libdvdnav** and **libdvdread**.
109
+
110
+ **Used for analysis (usually present in normal builds)**
111
+
112
+ - Filters: `idet` and `cropdetect`
113
+ - Quick check:
114
+ ```sh
115
+ ffmpeg -hide_banner -filters | grep -E '(^|\s)(idet|cropdetect)(\s|$)'
116
+ ```
117
+
118
+ Notes:
119
+ - Encrypted discs are frequently unreadable via plain FFmpeg. For those, install/use **MakeMKV** (`makemkvcon`).
120
+ - If your FFmpeg lacks any of the above, install a “full” distro/Homebrew build or rebuild FFmpeg with the relevant options.
121
+
122
+ Also:
123
+ - Accessing an optical drive like `/dev/sr0` often requires elevated permissions (e.g. running under `sudo` or adding your user to the appropriate group).
124
+ - Encrypted discs commonly require MakeMKV on the host system.
125
+
126
+ ## Install
127
+
128
+ ### Option A: pipx (recommended for an "installed CLI" workflow)
129
+
130
+ Once published to PyPI:
131
+
132
+ ```sh
133
+ pipx install rendervd
134
+
135
+ # confirm
136
+ rendervd --help
137
+ ```
138
+
139
+ ### Option B: venv + pip
140
+
141
+ ```sh
142
+ python -m venv .venv
143
+ . .venv/bin/activate
144
+ python -m pip install -U pip
145
+ python -m pip install rendervd
146
+
147
+ # confirm
148
+ rendervd --help
149
+ ```
150
+
151
+ ### Option C: from source (development)
152
+
153
+ ```sh
154
+ git clone <repository-url>
155
+ cd <repository-dir>
156
+ python -m pip install -U pip
157
+ python -m pip install -e .
158
+
159
+ # confirm
160
+ rendervd --help
161
+ ```
162
+
163
+ ## Quick start
164
+
165
+ ### 1) One-shot: auto-pick the main title and produce an MP4
166
+
167
+ ```sh
168
+ # optical drive
169
+ PYTHONUNBUFFERED=1 rendervd --dvd-src /dev/sr0 -o ./out
170
+
171
+ # ISO file
172
+ PYTHONUNBUFFERED=1 rendervd --dvd-src ./movie.iso -o ./out
173
+ ```
174
+ > Note: When `--dvd-src` is a block device (e.g. `/dev/sr0`), the default backup mode is **auto**: `rendervd` will mirror the disc to `<workdir>/dvd_backup` using `dvdbackup` and then ingest from the backup directory. Use `--no-backup` to read the drive directly, or `--backup --backup-dir <dir>` to force/control the backup location.
175
+
176
+ If `ffmpeg`/`ffprobe` are not on your `PATH`, pass `--ffmpeg /path/to/ffmpeg --ffprobe /path/to/ffprobe`.
177
+
178
+
179
+ ### 2) Multi-title stitch (e.g., episodic discs)
180
+
181
+ ```sh
182
+ PYTHONUNBUFFERED=1 rendervd --dvd-src /dev/sr0 -n 3 --min-duration 450 -o ./out
183
+ ```
184
+
185
+ ### 3) Plan first, then run
186
+
187
+ Planning performs extraction + probes + analysis **before** writing the plan:
188
+
189
+ ```sh
190
+ PYTHONUNBUFFERED=1 rendervd plan --dvd-src /dev/sr0 -o ./out -w ./work --plan-out ./plan.json
191
+ PYTHONUNBUFFERED=1 rendervd run ./plan.json
192
+ ```
193
+
194
+ ### 4) Replay (best-effort)
195
+
196
+ ```sh
197
+ PYTHONUNBUFFERED=1 rendervd plan --dvd-src ./movie.iso -o ./out --plan-include-commands --plan-out ./plan.json
198
+ PYTHONUNBUFFERED=1 rendervd replay ./plan.json
199
+ ```
200
+
201
+ ## Titles and selection
202
+
203
+ - `--titles "3,6,10"` selects specific DVD titles.
204
+ - Otherwise, `rendervd` scans titles and auto-picks:
205
+ - `--count N` (default `1`) picks up to N longest titles, with a “clearly longer main feature” heuristic.
206
+ - `--min-duration SEC` (default `600`) ignores shorter titles.
207
+
208
+ Run `rendervd --help` for the full option set.
209
+
210
+ ## Subtitles
211
+
212
+ `rendervd` preserves subtitle streams when present on the source titles.
213
+
214
+ ### Subfix (OCR bitmap DVD subtitles → mov_text)
215
+
216
+ Subfix is **auto-enabled by default** when the full toolchain is available:
217
+
218
+ - `subocr`
219
+ - `tesseract`
220
+ - `mkvextract`
221
+
222
+ If the toolchain is missing, Subfix is automatically disabled with a warning.
223
+ In that case, bitmap DVD subtitles (`dvd_subtitle`) are preserved by copying them into the output MP4 as-is (no OCR).
224
+
225
+ When a source contains **bitmap DVD subtitles** (`dvd_subtitle` / VobSub), rendervd will:
226
+ - extract the per-stream concatenated subtitle-only MKV: `workdir/concat/<basename>.sMM.mkv`
227
+ - extract `.idx/.sub` via `mkvextract` (track id 0)
228
+ - OCR via `subocr vobsub-ocr` to SRT
229
+ - apply the “VLC clear” fix (default: enabled; payload U+2060)
230
+ - mux the result into the final MP4 as **`mov_text`**
231
+
232
+ Disable Subfix (preserve bitmap behavior):
233
+
234
+ ```sh
235
+ rendervd --no-subfix ...
236
+ ```
237
+
238
+ Implementation details:
239
+ - **Multi-title stitch:** subtitle streams are extracted per segment/per stream, concatenated per stream, then muxed.
240
+ - **Single-title:** subtitle streams are carried through to final mux.
241
+
242
+ MP4 subtitle codec policy:
243
+ - **Bitmap DVD subs** (`dvd_subtitle` / `vobsub` / related):
244
+ - **Default:** OCR’d to text and muxed as `mov_text` (see Subfix above).
245
+ - If Subfix is disabled: **copied** (`-c:s copy`). Note: bitmap subs inside MP4 are not universally supported by every player.
246
+ - **Text subtitles** (`subrip`/SRT, `ass`, `ssa`, `webvtt`): encoded as **`mov_text`** for MP4 compatibility.
247
+
248
+ Verify subtitle presence in the final MP4:
249
+
250
+ ```sh
251
+ ffprobe -v error -select_streams s -show_entries stream=index,codec_name:stream_tags=language,title -of json ./out/<NAME>.mp4
252
+ ```
253
+
254
+ ## Output, workdir, reruns
255
+
256
+ - `--outdir DIR` controls where the final MP4 is written.
257
+ - `--out-basename NAME` controls the final MP4 base name (default: derived from disc title; `UPPERCASE_WITH_UNDERSCORES`).
258
+ - Output path is `OUTDIR/OUT_BASENAME.mp4`.
259
+ - `--basename NAME` controls the work prefix used for intermediates (default: derived from disc title when available).
260
+ - `--workdir DIR` controls where intermediates go.
261
+ - If omitted, a temporary workdir is created under the current directory and auto-removed unless `--keep` is used.
262
+ - Rerun behavior:
263
+ - `--overwrite` (default): overwrite expected outputs
264
+ - `--resume`: reuse existing intermediates/outputs when valid
265
+ - `--no-overwrite`: fail if expected outputs already exist
266
+
267
+ ## Tracing (NDJSON)
268
+
269
+ You can capture a newline-delimited JSON trace of external commands:
270
+
271
+ ```sh
272
+ TRACE_CMDS_ENABLED=1 TRACE_CMDS_FILE=./trace.ndjson TRACE_CMDS_APPEND=0 rendervd --dvd-src ./movie.iso -o ./out
273
+ ```
274
+
275
+ ## Docs
276
+
277
+ - `docs/plan.md` explains `plan.json` structure and replay semantics.
278
+ - `docs/plan.schema.json` is the machine-readable plan schema.
279
+
280
+ ## Development
281
+
282
+ ```sh
283
+ python -m venv .venv
284
+ source .venv/bin/activate
285
+ pip install -U pip
286
+ pip install -e ".[dev]"
287
+
288
+ pytest -q
289
+ ```
290
+
291
+ Optional:
292
+
293
+ ```sh
294
+ # integration (real tools); skipped by default
295
+ RENDERVD_INTEGRATION=1 pytest -q
296
+
297
+ # Subfix integration requires a fixture MKV containing at least one dvd_subtitle stream.
298
+ # Provide its path and enable integration:
299
+ RENDERVD_INTEGRATION=1 RENDERVD_SUBFIX_FIXTURE_MKV=/path/to/title_with_vobsub.mkv pytest -q
300
+ ```
301
+
302
+ ## Legal
303
+
304
+ Ensure you have the rights/authorization to copy and transcode any disc content you process.
@@ -0,0 +1,270 @@
1
+ # rendervd
2
+
3
+ `rendervd` is a command-line tool that turns a DVD source (optical disc, ISO, or a DVD-Video backup directory) into an MP4.
4
+
5
+ This repository provides a **Python implementation** of `rendervd`, designed to be easy to install, test, and maintain.
6
+
7
+ `rendervd` orchestrates external tools (it does **not** reimplement codecs/demuxers):
8
+ - `ffmpeg` and `ffprobe` for ingest/probing/encoding
9
+ - `makemkvcon` (MakeMKV) for title scanning (auto-pick) and single-title ingest
10
+ - `dvdbackup` for mirroring optical discs to disk (optional, drive-only)
11
+ - `subocr` + `tesseract` and `mkvextract` (MKVToolNix) for OCR’ing bitmap DVD subtitles (optional; enabled by default when the toolchain is present)
12
+
13
+ ## What it does
14
+
15
+ - **One-shot mode:** `rendervd [options]` (plans + runs; produces the final MP4)
16
+ - **Two-phase mode:**
17
+ - `rendervd plan ...` (extracts + probes + analyzes, then emits a `plan.json`)
18
+ - `rendervd run plan.json` (executes the plan)
19
+ - **Replay:** `rendervd replay plan.json` replays the embedded external command graph best-effort
20
+ (requires the plan to be created with `--plan-include-commands`).
21
+
22
+ ## Requirements
23
+
24
+ - Python **3.10+**
25
+ - External tools available on `PATH`:
26
+ - **Required:** `ffmpeg`, `ffprobe`, `makemkvcon`
27
+ - **Optional (drive backup mode):** `dvdbackup` (used when `--dvd-src` is a block device like `/dev/sr0` and backup mode is `auto` or `--backup`)
28
+ - **Optional (Subfix / OCR toolchain):** `subocr`, `tesseract` (+ tessdata), and `mkvextract` (from MKVToolNix)
29
+
30
+ ### Doctor: validate your environment
31
+
32
+ Run:
33
+
34
+ ```sh
35
+ rendervd doctor
36
+ ```
37
+
38
+ This prints a categorized report of required/recommended/optional dependencies and key FFmpeg capabilities.
39
+
40
+ Exit codes:
41
+ - `0`: all required checks pass
42
+ - `1`: missing required tools or required FFmpeg capabilities
43
+ - `2`: required checks pass, but some recommended/optional components are missing
44
+
45
+ Machine-readable JSON:
46
+
47
+ ```sh
48
+ rendervd doctor --json
49
+ ```
50
+
51
+ ### FFmpeg build requirements
52
+
53
+ `rendervd` depends on FFmpeg features that are sometimes missing from minimal builds.
54
+
55
+ **Must-have**
56
+
57
+ - **H.264 encoder:** `libx264` (used for MP4 video encoding).
58
+ - Quick check:
59
+ ```sh
60
+ ffmpeg -hide_banner -encoders | grep -E '(^|\s)libx264(\s|$)'
61
+ ```
62
+ - If you build FFmpeg yourself, this typically means configuring with:
63
+ - `--enable-gpl --enable-libx264`
64
+
65
+ **Needed for multi-title stitch from DVD/ISO**
66
+
67
+ - **`dvdvideo` demuxer support** (used for the dvdvideo ingest path when stitching multiple titles).
68
+ - Quick check:
69
+ ```sh
70
+ ffmpeg -hide_banner -demuxers | grep -E '(^|\s)dvdvideo(\s|$)'
71
+ ```
72
+ - Builds without `dvdvideo` often lack the underlying DVD navigation/read libraries.
73
+ If building from source, ensure the FFmpeg build can find/enable common DVD libs such as
74
+ **libdvdnav** and **libdvdread**.
75
+
76
+ **Used for analysis (usually present in normal builds)**
77
+
78
+ - Filters: `idet` and `cropdetect`
79
+ - Quick check:
80
+ ```sh
81
+ ffmpeg -hide_banner -filters | grep -E '(^|\s)(idet|cropdetect)(\s|$)'
82
+ ```
83
+
84
+ Notes:
85
+ - Encrypted discs are frequently unreadable via plain FFmpeg. For those, install/use **MakeMKV** (`makemkvcon`).
86
+ - If your FFmpeg lacks any of the above, install a “full” distro/Homebrew build or rebuild FFmpeg with the relevant options.
87
+
88
+ Also:
89
+ - Accessing an optical drive like `/dev/sr0` often requires elevated permissions (e.g. running under `sudo` or adding your user to the appropriate group).
90
+ - Encrypted discs commonly require MakeMKV on the host system.
91
+
92
+ ## Install
93
+
94
+ ### Option A: pipx (recommended for an "installed CLI" workflow)
95
+
96
+ Once published to PyPI:
97
+
98
+ ```sh
99
+ pipx install rendervd
100
+
101
+ # confirm
102
+ rendervd --help
103
+ ```
104
+
105
+ ### Option B: venv + pip
106
+
107
+ ```sh
108
+ python -m venv .venv
109
+ . .venv/bin/activate
110
+ python -m pip install -U pip
111
+ python -m pip install rendervd
112
+
113
+ # confirm
114
+ rendervd --help
115
+ ```
116
+
117
+ ### Option C: from source (development)
118
+
119
+ ```sh
120
+ git clone <repository-url>
121
+ cd <repository-dir>
122
+ python -m pip install -U pip
123
+ python -m pip install -e .
124
+
125
+ # confirm
126
+ rendervd --help
127
+ ```
128
+
129
+ ## Quick start
130
+
131
+ ### 1) One-shot: auto-pick the main title and produce an MP4
132
+
133
+ ```sh
134
+ # optical drive
135
+ PYTHONUNBUFFERED=1 rendervd --dvd-src /dev/sr0 -o ./out
136
+
137
+ # ISO file
138
+ PYTHONUNBUFFERED=1 rendervd --dvd-src ./movie.iso -o ./out
139
+ ```
140
+ > Note: When `--dvd-src` is a block device (e.g. `/dev/sr0`), the default backup mode is **auto**: `rendervd` will mirror the disc to `<workdir>/dvd_backup` using `dvdbackup` and then ingest from the backup directory. Use `--no-backup` to read the drive directly, or `--backup --backup-dir <dir>` to force/control the backup location.
141
+
142
+ If `ffmpeg`/`ffprobe` are not on your `PATH`, pass `--ffmpeg /path/to/ffmpeg --ffprobe /path/to/ffprobe`.
143
+
144
+
145
+ ### 2) Multi-title stitch (e.g., episodic discs)
146
+
147
+ ```sh
148
+ PYTHONUNBUFFERED=1 rendervd --dvd-src /dev/sr0 -n 3 --min-duration 450 -o ./out
149
+ ```
150
+
151
+ ### 3) Plan first, then run
152
+
153
+ Planning performs extraction + probes + analysis **before** writing the plan:
154
+
155
+ ```sh
156
+ PYTHONUNBUFFERED=1 rendervd plan --dvd-src /dev/sr0 -o ./out -w ./work --plan-out ./plan.json
157
+ PYTHONUNBUFFERED=1 rendervd run ./plan.json
158
+ ```
159
+
160
+ ### 4) Replay (best-effort)
161
+
162
+ ```sh
163
+ PYTHONUNBUFFERED=1 rendervd plan --dvd-src ./movie.iso -o ./out --plan-include-commands --plan-out ./plan.json
164
+ PYTHONUNBUFFERED=1 rendervd replay ./plan.json
165
+ ```
166
+
167
+ ## Titles and selection
168
+
169
+ - `--titles "3,6,10"` selects specific DVD titles.
170
+ - Otherwise, `rendervd` scans titles and auto-picks:
171
+ - `--count N` (default `1`) picks up to N longest titles, with a “clearly longer main feature” heuristic.
172
+ - `--min-duration SEC` (default `600`) ignores shorter titles.
173
+
174
+ Run `rendervd --help` for the full option set.
175
+
176
+ ## Subtitles
177
+
178
+ `rendervd` preserves subtitle streams when present on the source titles.
179
+
180
+ ### Subfix (OCR bitmap DVD subtitles → mov_text)
181
+
182
+ Subfix is **auto-enabled by default** when the full toolchain is available:
183
+
184
+ - `subocr`
185
+ - `tesseract`
186
+ - `mkvextract`
187
+
188
+ If the toolchain is missing, Subfix is automatically disabled with a warning.
189
+ In that case, bitmap DVD subtitles (`dvd_subtitle`) are preserved by copying them into the output MP4 as-is (no OCR).
190
+
191
+ When a source contains **bitmap DVD subtitles** (`dvd_subtitle` / VobSub), rendervd will:
192
+ - extract the per-stream concatenated subtitle-only MKV: `workdir/concat/<basename>.sMM.mkv`
193
+ - extract `.idx/.sub` via `mkvextract` (track id 0)
194
+ - OCR via `subocr vobsub-ocr` to SRT
195
+ - apply the “VLC clear” fix (default: enabled; payload U+2060)
196
+ - mux the result into the final MP4 as **`mov_text`**
197
+
198
+ Disable Subfix (preserve bitmap behavior):
199
+
200
+ ```sh
201
+ rendervd --no-subfix ...
202
+ ```
203
+
204
+ Implementation details:
205
+ - **Multi-title stitch:** subtitle streams are extracted per segment/per stream, concatenated per stream, then muxed.
206
+ - **Single-title:** subtitle streams are carried through to final mux.
207
+
208
+ MP4 subtitle codec policy:
209
+ - **Bitmap DVD subs** (`dvd_subtitle` / `vobsub` / related):
210
+ - **Default:** OCR’d to text and muxed as `mov_text` (see Subfix above).
211
+ - If Subfix is disabled: **copied** (`-c:s copy`). Note: bitmap subs inside MP4 are not universally supported by every player.
212
+ - **Text subtitles** (`subrip`/SRT, `ass`, `ssa`, `webvtt`): encoded as **`mov_text`** for MP4 compatibility.
213
+
214
+ Verify subtitle presence in the final MP4:
215
+
216
+ ```sh
217
+ ffprobe -v error -select_streams s -show_entries stream=index,codec_name:stream_tags=language,title -of json ./out/<NAME>.mp4
218
+ ```
219
+
220
+ ## Output, workdir, reruns
221
+
222
+ - `--outdir DIR` controls where the final MP4 is written.
223
+ - `--out-basename NAME` controls the final MP4 base name (default: derived from disc title; `UPPERCASE_WITH_UNDERSCORES`).
224
+ - Output path is `OUTDIR/OUT_BASENAME.mp4`.
225
+ - `--basename NAME` controls the work prefix used for intermediates (default: derived from disc title when available).
226
+ - `--workdir DIR` controls where intermediates go.
227
+ - If omitted, a temporary workdir is created under the current directory and auto-removed unless `--keep` is used.
228
+ - Rerun behavior:
229
+ - `--overwrite` (default): overwrite expected outputs
230
+ - `--resume`: reuse existing intermediates/outputs when valid
231
+ - `--no-overwrite`: fail if expected outputs already exist
232
+
233
+ ## Tracing (NDJSON)
234
+
235
+ You can capture a newline-delimited JSON trace of external commands:
236
+
237
+ ```sh
238
+ TRACE_CMDS_ENABLED=1 TRACE_CMDS_FILE=./trace.ndjson TRACE_CMDS_APPEND=0 rendervd --dvd-src ./movie.iso -o ./out
239
+ ```
240
+
241
+ ## Docs
242
+
243
+ - `docs/plan.md` explains `plan.json` structure and replay semantics.
244
+ - `docs/plan.schema.json` is the machine-readable plan schema.
245
+
246
+ ## Development
247
+
248
+ ```sh
249
+ python -m venv .venv
250
+ source .venv/bin/activate
251
+ pip install -U pip
252
+ pip install -e ".[dev]"
253
+
254
+ pytest -q
255
+ ```
256
+
257
+ Optional:
258
+
259
+ ```sh
260
+ # integration (real tools); skipped by default
261
+ RENDERVD_INTEGRATION=1 pytest -q
262
+
263
+ # Subfix integration requires a fixture MKV containing at least one dvd_subtitle stream.
264
+ # Provide its path and enable integration:
265
+ RENDERVD_INTEGRATION=1 RENDERVD_SUBFIX_FIXTURE_MKV=/path/to/title_with_vobsub.mkv pytest -q
266
+ ```
267
+
268
+ ## Legal
269
+
270
+ Ensure you have the rights/authorization to copy and transcode any disc content you process.