iteration1

This commit is contained in:
Javanaut
2026-04-13 13:16:33 +02:00
parent d9639561ce
commit c0b3977ea6
16 changed files with 1485 additions and 528 deletions

View File

@@ -0,0 +1,198 @@
# Metadata Editor
This file defines the requirements for a database-free interactive metadata
editor command derived from the current file-inspection UI.
Feasibility from the current codebase: yes, with a moderate refactor.
The strongest reusable pieces already exist:
- `ffprobe`-backed media probing through `FileProperties` and `MediaDescriptor`
- descriptor-level metadata and disposition mutation through `MediaDescriptor`
and `TrackDescriptor`
- diff and ffmpeg token generation through `MediaDescriptorChangeSet`
- stream-copy remux execution through `FfxController` with `VideoEncoder.COPY`
- reusable tag and track edit dialogs in the Textual UI
The main missing pieces are:
- a CLI bootstrap path that does not initialize SQLite
- a probe-only path that does not instantiate database-backed controllers
- a clean separation between original file state and editable draft state
- a safe temporary-output and replace workflow for writing changes back to the
same file path
## Scope
- One new command: `ffx edit <file>`
- One-file interactive editing through a Textual screen derived from
`MediaDetailsScreen`
- Editing container-level metadata and per-stream metadata already visible in
the application
- Editing stream dispositions that are represented as metadata-like output
state, especially `default` and `forced`
- Writing the result back to the original file path through a temporary output
file and replace step
## Out Of Scope
- SQLite reads, writes, migrations, or pattern matching
- TMDB lookups, show selection, pattern selection, or shifted-season logic
- Batch editing multiple files in one command invocation
- Video or audio transcoding
- Container changes, filename changes, or rename workflows
- Stream add, stream delete, stream reorder, or stream substitution from
external files in the first release
- Editing technical stream identity such as codec, stream type, source index,
or audio layout in the first release
- Chapter editing
## Terms
- `baseline descriptor`: immutable in-memory representation of the file as last
probed from disk
- `draft descriptor`: mutable in-memory representation of the desired output
state
- `edit mode`: the database-free TUI mode used by `ffx edit`
- `planned changes`: user-visible summary of the differences between baseline
and draft plus any configured cleanup actions
- `temporary output file`: the write target used before replacing the original
file path
## Rules
- `METADATA_EDITOR-0001`: The system shall provide a command `ffx edit <file>`
that requires exactly one existing media file path and opens an interactive
Textual editor for that file.
- `METADATA_EDITOR-0002`: `ffx edit` shall not initialize SQLite, shall not
open the configured database file, shall not prompt for database migration,
and shall not instantiate any controller that depends on `context['database']`.
- `METADATA_EDITOR-0003`: `ffx edit` may still read configuration and logging
settings from `~/.local/etc/ffx.json`, but any global database option shall
have no effect on this command's behavior.
- `METADATA_EDITOR-0004`: Edit mode shall be derived from the current
`MediaDetailsScreen` behavior and layout where practical, but all DB-only UI
elements and actions such as show selection, pattern input, and pattern CRUD
actions shall be hidden, disabled, or replaced.
- `METADATA_EDITOR-0005`: Edit mode shall keep the baseline descriptor and the
draft descriptor as separate objects. Editing actions shall mutate only the
draft descriptor until the operator explicitly applies changes.
- `METADATA_EDITOR-0006`: The application shall keep raw metadata values
separate from rendered labels. Rich or Textual markup may be used for
presentation, but it shall never be stored in descriptor state, reused as
source data, or written into the media file.
- `METADATA_EDITOR-0007`: The planned-changes view shall compare the baseline
descriptor with the draft descriptor using `MediaDescriptorChangeSet` or an
equivalent descriptor-diff mechanism. It shall no longer mean `file -> db`.
- `METADATA_EDITOR-0008`: The editor shall support container-tag add, edit, and
delete operations on the draft descriptor.
- `METADATA_EDITOR-0009`: The editor shall support per-stream metadata edit
operations on the draft descriptor, including at least language, title, and
arbitrary stream tag key-value pairs.
- `METADATA_EDITOR-0010`: The editor shall support setting and clearing
`default` and `forced` dispositions in the draft descriptor, while enforcing
that there is at most one `default` and at most one `forced` stream per track
type.
- `METADATA_EDITOR-0011`: The first released editor scope shall treat technical
stream structure as immutable. A user shall not be able to change stream
count, output order, codec, track type, audio layout, or source-index
mapping through `ffx edit`.
- `METADATA_EDITOR-0012`: The track-edit UI used in edit mode shall therefore
expose only metadata fields and supported disposition fields. Structural
fields that are editable in pattern-authoring workflows shall be read-only or
absent in edit mode.
- `METADATA_EDITOR-0013`: The command shall write changes through an ffmpeg
stream-copy remux workflow only. No transcoding shall be performed as part of
`ffx edit`.
- `METADATA_EDITOR-0014`: Because ffmpeg cannot rewrite the source file in
place, `ffx edit` shall write to a temporary output file on the same
filesystem as the source file and shall replace the original path only after
ffmpeg reports success.
- `METADATA_EDITOR-0015`: The temporary output path shall preserve the original
container type and file extension. The feature shall not silently change the
container or extension during a metadata-only edit.
- `METADATA_EDITOR-0016`: If the rewrite step fails, the original file shall
remain untouched. The system shall not leave the user with a partially
replaced source file.
- `METADATA_EDITOR-0017`: After a successful replace, the application shall
reprobe the rewritten file, refresh the baseline descriptor from disk, reset
the draft state to that fresh baseline, and clear the dirty state.
- `METADATA_EDITOR-0018`: Edit mode shall track whether unsaved draft changes
exist and shall require confirmation before dismissing the screen or quitting
the app when such changes would be lost.
- `METADATA_EDITOR-0019`: Edit mode shall not inject conversion-only encoding
metadata such as encoder quality or preset markers.
- `METADATA_EDITOR-0020`: Signature-tag behavior shall be explicit for
metadata-only editing. The default behavior shall not add a misleading
recoding-style signature to a file that was only remuxed for metadata
updates.
- `METADATA_EDITOR-0021`: Configured metadata-removal rules from the local
configuration shall be surfaced clearly in the UI and in the planned-changes
view. If those rules are applied during save, the operator shall be able to
tell that the file will be cleaned in addition to any manual edits.
- `METADATA_EDITOR-0022`: The command shall provide an invocation-level way to
disable config-driven cleanup when the operator wants a pure manual metadata
edit without automatic tag removal.
- `METADATA_EDITOR-0023`: The existing global `--dry-run` behavior shall apply
to `ffx edit`. In dry-run mode the command shall not replace the original
file and shall expose the planned write operation clearly enough for the user
to understand what would happen.
## Acceptance
- `ffx edit /path/to/file.mkv` opens successfully on a workstation where the
configured database is missing, empty, incompatible, or intentionally
inaccessible.
- Opening a file in edit mode does not trigger database bootstrap or migration
prompts.
- A user can change a container tag, save, and see the rewritten file at the
same path with the updated metadata.
- A user can change a stream title or language, save, and see the rewritten
file at the same path with the updated stream metadata.
- A user can change `default` or `forced` on a track, save, and see the
rewritten file at the same path with the updated dispositions.
- The planned-changes view reflects manual edits relative to the original file
and, when enabled, any configured cleanup removals.
- No rendered Rich or Textual color markup appears in the saved file metadata.
- If ffmpeg fails while saving, the original file remains present and readable
at the original path.
- In dry-run mode, the original file remains untouched.
## Current Code Fit
- Good fit:
- `FfxController.runJob(...)` already has a `VideoEncoder.COPY` path that
can remux streams and apply metadata and disposition tokens.
- `MediaDescriptorChangeSet` already computes container-tag, stream-tag, and
disposition differences and can generate ffmpeg metadata tokens.
- `TagDetailsScreen` and `TrackDetailsScreen` already provide reusable edit
dialogs for draft state.
- `PatternDetailsScreen` already demonstrates add, edit, and delete flows for
tags and tracks in a draft-first UI.
- Refactor required:
- `ffx` CLI initialization currently creates a database context for all
non-lightweight commands, so `edit` needs its own DB-free bootstrap path.
- `FileProperties` currently instantiates `PatternController` eagerly, so
probing must be split from pattern matching or made lazy.
- `MediaDetailsScreen` currently assumes `command == 'inspect'` and mixes
file state with database-backed target-pattern state.
- `MediaDetailsScreen` currently mutates the probed source descriptor
directly. Edit mode needs an immutable baseline descriptor and a separate
mutable draft descriptor.
- `TrackDetailsScreen` currently exposes structural fields that are valid for
pattern authoring but too dangerous for metadata-only file editing.
## Risks
- Container-level metadata support differs across formats, so some requested tag
changes may not round-trip identically through ffmpeg for every supported
container.
- The existing metadata-removal implementation is conversion-oriented and may
remove tags more aggressively than a user expects from a manual editor unless
cleanup policy is made explicit.
- The current codebase lacks a dedicated descriptor clone API, so draft-state
separation should be implemented deliberately instead of via accidental shared
references.
- Replacing a file path with a temporary output changes inode identity, so any
future requirement around preserving timestamps, hard links, or extended
attributes would need additional explicit handling.