Skip to content

release: v0.20.0 - #92

Merged
renezander030 merged 11 commits into
masterfrom
release/0.20.0
Aug 21, 2026
Merged

release: v0.20.0#92
renezander030 merged 11 commits into
masterfrom
release/0.20.0

Conversation

@renezander030

Copy link
Copy Markdown
Owner

Two threads run through this release. Subtitle styling now crosses the draft boundary in both directions — export-ass writes it out, import-ass stops throwing it away. And the raw-recording pipeline closes inside the CLI: find the speech, voice the script, cut the dead air. Underneath, the ffmpeg fail-fast work from 0.19.0 is finished on the audio chain, and diagnose now produces the evidence the two open store-layout questions are waiting on. No command was removed and no existing flag changed meaning.

Fixed

Added

  • export-ass — styled ASS export: [V4+ Styles] derived from the draft's text styling, per-range override tags with explicit resets (&HAABBGGRR colour order tested both directions), --karaoke word timing from the same timestamps the WebVTT karaoke writer uses.
  • detect-silence — the audio twin of detect-scenes: silence spans plus the complementary keep segments, consumable by cut/compile; --pad keeps a margin around speech so no word clips mid-syllable.
  • tts — voiceover through any local TTS command template (piper, say, espeak-ng); no shell in the path, text via argv token or stdin, landing as a real audio segment through the existing add-audio path; doctor reports the configuration.
  • render --encoder — hardware/alternate video encoders, validated lazily against ffmpeg -encoders; without the flag the invocation is byte-identical to 0.19.1.
  • harvest-enums --sync / --add — whole-library catalogue sweep (skip-and-report on broken drafts, idempotent) and manual entries with full validation, both on the existing plan/--apply convention and atomic writer.
  • diagnose evidence capture — for nested-Timelines/ drafts, the report and sanitized bundles now carry the pointer file, the draft-file tree, the version/OS markers, and a root-vs-nested divergence comparison (hashes and counts, never raw text) — the before/after needed to settle CapCut 7.x edits are discarded when the active draft lives under Timelines/ #50 (refs CapCut 7.x edits are discarded when the active draft lives under Timelines/ #50, not closed). Separately, a read-only note fires when draft_meta_info.json registers no timeline media — the reported relink condition on newer CapCut builds — asking for a fixture bundle so the write side can be built from evidence instead of guesswork.

Release chores

Version bump (lockfile touched on exactly the two version strings), changelog, README release notes rotated in both languages, command reference regenerated and the Chinese translation synced.

Verification

807 tests, up from 703 on master — every new surface has its own test file (export/import-ass round-trip, silence-span math on captured ffmpeg stderr, fake-TTS e2e, catalogue sweep fixtures, diagnose redaction/byte-stability). biome check --error-on-warnings clean; the pre-commit hook re-ran the full suite on every commit on this branch.

…rrides and --karaoke word timing

Subtitles could leave a draft only as bare SRT/WebVTT; every colour, weight
and multi-range highlight stayed behind. export-ass emits the full look:
[Script Info] takes PlayRes from the draft canvas, one [V4+ Styles] line per
distinct text styling (font size/colour/alpha, bold/italic/underline,
alignment, border/shadow/background where they map onto BorderStyle/Outline/
Shadow/BackColour), and one Dialogue per text segment. A material's
styles[].range blocks (UTF-16 code units) that differ from the base style
become inline override tags with an explicit reset after the span. --karaoke
collapses word-timed caption segments the way export-srt --granularity word
does and writes {\k} centisecond timing on absolute rounded onsets, with the
highlight colour as PrimaryColour over the base SecondaryColour. Output goes
to stdout, or to --out with a JSON summary. Colour helpers encode/decode the
&HAABBGGRR / &HBBGGRR& blue-green-red forms and are tested in both
directions; the writer is pure and unit-tested without a draft on disk.
… per-range styles instead of dropping them

parseAss flattened every Dialogue with a single regex: each {...} override
block was deleted wholesale, \N/\n became newlines, \h a space, and the
result was trimmed — so a file's inline styling never reached the draft, and
the [V4+ Styles] section was never read at all. Now the Dialogue text is
walked with a running tag state: \b (0/1 and 400/700 weights), \i, \u,
\c/\1c (&HBBGGRR&, blue-green-red) and \fs map onto spans in UTF-16 code
units of the final stored text, \r resets to the Style line, and any other
tag ({\an8}, \pos, \k, ...) is stripped exactly as before. Spans that
merely restate the referenced Style's defaults (the \b0 half of a bold
range) produce no range. import-ass writes the spans through the same
per-range machinery text-ranges uses, and the Dialogue's [V4+ Styles] line
seeds font size, primary colour and alignment where no flag overrides them.
The round-trip test re-imports export-ass's styled output and asserts the
reproduced styles[] arrays and timings are identical.
…nd bundles (#50)

Issue #50 (CapCut 7.x reported to keep the live document at
Timelines/<id>/draft_info.json) is stalled on four evidence items the
reporter was asked for: Timelines/project.json, the file tree of the
draft/template/project files, the exact app version + OS marker, and a
root-vs-nested before/after showing whether a successful root write
leaves the nested document stale.

diagnose (and diagnose --bundle, plus the fixture bundle's
diagnose.json) now attaches a nested_evidence section carrying all four
whenever the timelines-nested layout or any nested Timelines/ document
exists: the pointer file redacted through the standard bundle redactors
(#59), the file tree with sizes and mtimes, the version marker via
detectVersion, and a per-nested-document comparison - content hashes,
which side is mtime-newer, and per-track segment/text counts plus a
text hash, never raw text, so the report stays privacy-safe by
construction.

Read-only: no write-path change - whether the nested pointer is
authoritative is a separate decision gated on this evidence arriving
(refs #50). Non-nested drafts produce byte-identical diagnose output
(regression-tested).
…o newer-build relink reports come with evidence

Newer CapCut builds (reported on CapCut International 9.1.0, macOS) are
reported to show timeline media as "file inaccessible" and to prompt
per-clip relinking when draft_meta_info.json's draft_materials does not
register the media, even with valid paths in the timeline file. This
CLI never writes draft_materials and no real entry shape has been
captured, so the registration write stays deliberately out of scope.

diagnose gains a read-only media_registration note, attached only when
the timeline references local media and draft_materials provably
registers nothing: sidecar missing entirely (CLI-born drafts), the key
absent, or present with every group empty. The note states what was
observed, the reported symptom, and the one-command ask - capcut
fixture on an app-authored draft from such a build produces the
sanitized bundle (it includes draft_meta_info.json) the write can be
built from. Any shape not provably empty suppresses the note; no
exit-code change, and the all-clear next_action survives.
@renezander030
renezander030 merged commit 7d9ce47 into master Aug 21, 2026
8 checks passed
@renezander030
renezander030 deleted the release/0.20.0 branch August 21, 2026 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

render: audio-chain filters are never probed (same failure class as #89); add a chain/probe guard test

1 participant