Add CLAUDE.md and harden .gitignore
Document the fork's architecture and dev/verify workflow for future work (no test framework; verify via pure-logic functions and generated command_var). Extend .gitignore to exclude .claude/ local config (machine-specific paths + personal permission allowlists), common secret file patterns, and editor/OS junk, while keeping the shipped base_*.mpg package data tracked. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
480ec59ba4
commit
5fe1013be8
2 changed files with 97 additions and 0 deletions
29
.gitignore
vendored
29
.gitignore
vendored
|
|
@ -1,7 +1,36 @@
|
|||
# Python build/cache artifacts
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
build/
|
||||
dist/
|
||||
*.egg-info/
|
||||
|
||||
# Compiled translations (generated from po/ at build time)
|
||||
src/devedeng/data/locale/
|
||||
|
||||
# Claude Code local config / session state (machine-specific, may include
|
||||
# local paths and personal permission allowlists; not for sharing)
|
||||
.claude/
|
||||
CLAUDE.local.md
|
||||
|
||||
# Local environment / secrets (defense-in-depth; nothing here today)
|
||||
.env
|
||||
.env.*
|
||||
*.pem
|
||||
*.key
|
||||
*.p12
|
||||
id_rsa*
|
||||
credentials*
|
||||
*.secret
|
||||
|
||||
# Editor / OS junk
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*~
|
||||
.DS_Store
|
||||
|
||||
# Runtime/output artifacts this project can produce
|
||||
*.iso
|
||||
*.mpg.progress
|
||||
|
|
|
|||
68
CLAUDE.md
Normal file
68
CLAUDE.md
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## What this is
|
||||
|
||||
This is a **fork** of DeVeDe-NG (a GTK3 video-DVD authoring app) that adds, on top of upstream: embedded-subtitle **hardsubbing** (burn-in), selectable DVD **encode profiles**, and **auto-splitting** of over-long projects across multiple ISOs. See `FORK_NOTES.md` for the feature-level description of the fork's additions; this file covers how to work in the code.
|
||||
|
||||
## Running and installing
|
||||
|
||||
Run straight from the source tree without installing (best for iterating):
|
||||
|
||||
```bash
|
||||
PYTHONPATH=src python3 -c "import devedeng.devedeng as d; d.py()"
|
||||
```
|
||||
|
||||
`d.py()` calls `Gtk.main()` and blocks. When driving it from a tool/agent, launch detached so an editor/terminal crash can't wedge it:
|
||||
|
||||
```bash
|
||||
nohup env PYTHONPATH=src python3 -c "import devedeng.devedeng as d; d.py()" >/tmp/devede_run.log 2>&1 & disown
|
||||
```
|
||||
|
||||
Install (system): `sudo python3 -m pip install .` (add `--break-system-packages` if pip refuses). Entry point is `devede_ng` → `devedeng/devedeng.py:py()`.
|
||||
|
||||
Runtime external tools (must be on PATH): `ffmpeg`/`ffprobe` (or `avconv`/`avprobe`), `dvdauthor`, `mkisofs`/`genisoimage`, `spumux`, and optionally a player (vlc/mpv/mplayer) and burner (brasero/k3b/xfburn). The full dependency list lives in `stdeb.cfg` / `stpacman.cfg`.
|
||||
|
||||
## Testing
|
||||
|
||||
There is **no test framework or test suite.** Verify changes two ways:
|
||||
|
||||
1. **Pure logic** (no GTK/display) — e.g. the split planner. Import and exercise directly:
|
||||
```bash
|
||||
cd src && python3 -c "from devedeng.project import plan_disc_split; ..."
|
||||
```
|
||||
`plan_disc_split`, `_movie_chapter_seconds`, and `_nearest_chapter_before` in `project.py` are deliberately module-level pure functions so they can be unit-tested without instantiating GTK.
|
||||
|
||||
2. **Generated ffmpeg commands** — build a converter and inspect `command_var` without running anything. The config singleton works headless:
|
||||
```python
|
||||
cfg = devedeng.configuration_data.configuration.get_config(); cfg.disc_type = "dvd"
|
||||
conv = devedeng.ffmpeg.ffmpeg(); conv.convert_file(mock_file_movie, "/tmp/out.mpg", 0)
|
||||
print(conv.command_var) # the exact ffmpeg argv
|
||||
```
|
||||
`convert_file` takes the `file_movie` object as `file_project` and reads `hardsub_index`/`hardsub_kind`, the encode profile from config, etc. For a full integration check, run a real short encode through the executor's GLib loop and watch a fake progress bar (GTK is installed but there is no Xvfb here, so the *windowed* UI can only be verified by actually launching the app on a display).
|
||||
|
||||
`contrib/dvd-safe-converter.sh` is the known-good baseline the **Compatibility** profile is modelled on — use it as a regression reference for the no-subtitle DVD encode (mpeg2video / 720x480 / 29.97 / AC3 192k / 48k).
|
||||
|
||||
## Architecture
|
||||
|
||||
### Pluggable backend layer (`converter.py`)
|
||||
Every external program is wrapped in a small class (`ffmpeg.py`, `avconv.py`, `ffprobe.py`, `avprobe.py`, `mkisofs.py`, `dvdauthor_converter.py`, players, burners). Each declares capability flags (`supports_convert`, `supports_analize`, `supports_menu`, `supports_mkiso`, `supports_burn`) and a `check_is_installed()` staticmethod. `converter` is a singleton (`converter.get_converter()`) that probes which tools are installed and exposes the chosen analyzer/converter/menuer/mkiso/burner. **Implication:** there are two parallel implementations of most things — `ffmpeg`/`ffprobe` (default) and `avconv`/`avprobe` (legacy libav). A change to the encode path or analyzer usually needs mirroring across both backends.
|
||||
|
||||
### Process execution & progress (`executor.py`)
|
||||
All external commands run through `executor` (subclassed by every backend). A command is built into `self.command_var` (an argv list), launched via `launch_process`, and its stdout/stderr are read **asynchronously** through `GLib.IOChannel` watches that call `process_stdout`/`process_stderr` — this keeps the GTK main loop alive during long encodes. `executor.run()` and `wait_end()` call optional `start_progress_polling()`/`stop_progress_polling()` hooks (ffmpeg uses them). **Critical constraint:** ffmpeg progress is written to a `-progress` *file* and polled on a timer, deliberately **not** a pipe — a pipe deadlocks the encoder if the GUI ever stops draining it.
|
||||
|
||||
### Job orchestration (`runner.py` + executor dependency graph)
|
||||
A `runner` shows the progress window with one bar per core (`config.multicore`, default cores−1) and runs queued processes in parallel. Processes express ordering via `add_dependency()` / `add_child_process()`; the runner launches a process only when its dependencies have finished, freeing the bar for the next. A typical DVD job: N parallel `convert_file` encodes → `dvdauthor` (depends on all encodes) → `mkisofs` (depends on dvdauthor).
|
||||
|
||||
### Project model & UI binding (`interface_manager.py`, `project.py`, `file_movie.py`)
|
||||
`interface_manager` auto-binds named GLADE widgets to Python attributes via `add_toggle`/`add_text`/`add_group`/etc., and serializes only those registered fields (`serialize`/`unserialize`). `devede_project` (`project.py`) is the main window and owns the file list, disc settings, and the create-disc flow. `file_movie` is one movie/title. **Gotcha:** attributes that are *not* registered with the `add_*` helpers (e.g. `hardsub_index`, `hardsub_kind`) are not serialized automatically — they are persisted explicitly in `file_movie.store_element`/`restore_element`, and skipped in group ("multiproperties") mode. Some newer UI (the hardsub picker, the encode-profile selector) is built **in Python at runtime** and packed into existing containers rather than added to the `.ui` files.
|
||||
|
||||
### Bitrate / size model (the math that ties profiles + splitting together)
|
||||
`file_movie.set_final_rates()` maps the encode profile to `video_rate_final` / `audio_rate_final` (Compatibility = 4500k/192k, High = audio 448k + disc-fit video, Custom = user). `get_estimated_size()` / `get_kbytes_per_second()` derive size from those rates. `project.get_dvd_size()` returns per-disc capacity (already with a ~10% margin). The pure `plan_disc_split()` uses these to distribute whole titles across discs and time-split a single over-long movie at the chapter boundary nearest each disc's capacity; `dvdauthor_converter.create_dvd_project` takes a parallel `segment_lengths` list so a split segment's chapter markers stay inside the segment. NTSC DVD audio is AC3 for all profiles in this fork (upstream used MP2 for NTSC).
|
||||
|
||||
## Conventions worth matching
|
||||
- ffmpeg/avconv commands are assembled by appending to `command_var`; keep additions in that style and mirror across both backends where the feature applies to both.
|
||||
- MPEG-2/yuv420p needs **even** width/height — round pad/crop targets and use positive crop offsets (see the pad/crop block in `ffmpeg.py`).
|
||||
- All user-visible strings go through `_()` (gettext); `.ui` labels use `translatable="yes"`. Translations live in `po/`.
|
||||
- The build writes compiled locale `.mo` files into `src/devedeng/data/locale/` (gitignored).
|
||||
Loading…
Add table
Add a link
Reference in a new issue