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.
- rendervd-0.1.0/CHANGELOG.md +26 -0
- rendervd-0.1.0/LICENSE +21 -0
- rendervd-0.1.0/MANIFEST.in +16 -0
- rendervd-0.1.0/PKG-INFO +304 -0
- rendervd-0.1.0/README.md +270 -0
- rendervd-0.1.0/pyproject.toml +68 -0
- rendervd-0.1.0/rendervd/__init__.py +17 -0
- rendervd-0.1.0/rendervd/cli.py +1201 -0
- rendervd-0.1.0/rendervd/config.py +256 -0
- rendervd-0.1.0/rendervd/doctor.py +420 -0
- rendervd-0.1.0/rendervd/execution/__init__.py +1 -0
- rendervd-0.1.0/rendervd/execution/assets.py +20 -0
- rendervd-0.1.0/rendervd/execution/errors.py +13 -0
- rendervd-0.1.0/rendervd/execution/ingest.py +169 -0
- rendervd-0.1.0/rendervd/execution/pipeline.py +496 -0
- rendervd-0.1.0/rendervd/execution/probe.py +246 -0
- rendervd-0.1.0/rendervd/execution/replay.py +142 -0
- rendervd-0.1.0/rendervd/execution/reuse.py +79 -0
- rendervd-0.1.0/rendervd/execution/runner.py +85 -0
- rendervd-0.1.0/rendervd/execution/tracing.py +77 -0
- rendervd-0.1.0/rendervd/paths.py +90 -0
- rendervd-0.1.0/rendervd/planning/__init__.py +5 -0
- rendervd-0.1.0/rendervd/planning/audio.py +204 -0
- rendervd-0.1.0/rendervd/planning/command_graph.py +1233 -0
- rendervd-0.1.0/rendervd/planning/dvd_backup.py +117 -0
- rendervd-0.1.0/rendervd/planning/ingest.py +113 -0
- rendervd-0.1.0/rendervd/planning/lang.py +83 -0
- rendervd-0.1.0/rendervd/planning/makemkv_scan.py +165 -0
- rendervd-0.1.0/rendervd/planning/plan_builder.py +184 -0
- rendervd-0.1.0/rendervd/planning/probes.py +142 -0
- rendervd-0.1.0/rendervd/planning/titles.py +86 -0
- rendervd-0.1.0/rendervd/planning/video_analysis.py +590 -0
- rendervd-0.1.0/rendervd/subfix/__init__.py +5 -0
- rendervd-0.1.0/rendervd/subfix/options.py +68 -0
- rendervd-0.1.0/rendervd/subfix/planning.py +74 -0
- rendervd-0.1.0/rendervd/subfix/toolchain.py +37 -0
- rendervd-0.1.0/rendervd/subfix/vlc_clear.py +469 -0
- rendervd-0.1.0/rendervd/util.py +180 -0
- rendervd-0.1.0/rendervd.egg-info/PKG-INFO +304 -0
- rendervd-0.1.0/rendervd.egg-info/SOURCES.txt +43 -0
- rendervd-0.1.0/rendervd.egg-info/dependency_links.txt +1 -0
- rendervd-0.1.0/rendervd.egg-info/entry_points.txt +2 -0
- rendervd-0.1.0/rendervd.egg-info/requires.txt +8 -0
- rendervd-0.1.0/rendervd.egg-info/top_level.txt +1 -0
- 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
|
+
|
rendervd-0.1.0/PKG-INFO
ADDED
|
@@ -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.
|
rendervd-0.1.0/README.md
ADDED
|
@@ -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.
|