VideoEdit

Active

Local web app that turns a CapCut cooking-video export into bilingual captions and dialogue transcripts, either as SRTs or written straight back into the CapCut draft.

Started
July 11, 2026
Phases
9 of 9 done

Highlights

  • CapCut, reverse-engineeredWrites styled bilingual caption tracks straight into CapCut's undocumented draft format.
  • In real useCaptions my wife's TikTok and Instagram cooking videos, in whatever language pair each needs.
  • 3 Whisper passes + GeminiCode-switched dialogue transcripts merged from en/fr/ja passes and aligned to word timings.
  • Peak-safe loudnessBalances voiceover volume by measured LUFS, flagging clips a flat gain can't fix.

Overview

A local web app for subtitling my wife’s TikTok/Instagram cooking videos. She edits in CapCut desktop and exports an mp4. This tool splits that export into scenes, groups them into logical sections, proposes short recipe-step captions with Gemini, transcribes the tasting/dialogue moments, and hands the result back either as SRT files to import into CapCut, or written directly into the linked CapCut draft so the styling and positioning she’s already dialed in for the primary/secondary caption tracks carry over automatically.

Most of the actual engineering weight sits in capcut_captions.py and its neighbors. CapCut’s draft format is undocumented, versioned across app releases, and cached in memory while the app is open. Getting captions and audio levels written into it correctly took real reverse-engineering against a live install, not just following a spec.

Problem

  • Consistent bilingual captions, without redoing styling by hand every video. She needs a short, imperative recipe-step caption style, plus a verbatim-and-translated dialogue track for tasting moments, in whatever language pair a given video needs. Doing that by hand per video is repetitive and easy to make inconsistent.
  • CapCut’s draft format has no public spec. Writing captions and audio gain directly into a draft_info.json means reverse-engineering undocumented, versioned, partially-duplicated state (see CapCut direct-write) against a real install, not implementing a documented API.
  • Voiceover volume varies clip to clip. Fixing that by ear inside CapCut is repetitive and easy to get subtly wrong. A single loud transient in an otherwise-quiet clip can make a naive fix clip audio that should have stayed clean (see Balance Audio Levels).

None of these is exotic alone, but together they’re why this is a real tool rather than a five-minute Whisper script: a genuinely useful output needs consistent styling and positioning that survives all the way into the editor she actually works in, not just a technically-correct SRT file.

Phases

Nine phases so far, from the first working pipeline slice to a read-only check that catches a CapCut draft edited by hand out from under the app:

Tech stack

What each piece of the stack is actually doing, and where to look for more:

Languages

  • Python

    Backend language for the pipeline and AI calls.

  • TypeScript

    Typed frontend, sharing shapes with the backend models.

Frameworks

  • FastAPI

    Serves the local API the React frontend talks to.

  • React

    Powers the local web UI, built with Vite.

AI/ML

  • faster-whisper

    Per-language transcription passes feeding the Gemini merge.

  • Gemini

    Generates captions, merges transcripts, and translates.

Libraries

  • PySceneDetect

    Splits the raw export into scenes via content detection.

Tooling

  • ffmpeg

    Extracts audio clips and measures/renders LUFS loudness.

Approach

Every CapCut-facing feature (direct-write, audio levels, position calibration, configuration check) was built and verified against a real CapCut install rather than against assumptions about the format, since none of it is documented. That discipline caught concrete, otherwise- invisible failures: captions that looked written but never rendered (the untouched nested Timelines copy), orphaned duplicate tracks from a desynced remembered-ids state file, a spike-flattened clip that a flat gain formula would have silently left inconsistent with its neighbors, and a caption edited by hand in CapCut that kept its old track’s styling, which the configuration check exists specifically to catch. The same build-against-real-usage discipline caught a quietly-accumulating duplicate-history bug in the caption history system, only visible once looked for directly in a real project’s saved data.

Future improvements

Straight from the project’s own deferred-to-v2 list:

  • CapCut draft JSON as input, not just output. Parsing draft_content.json directly for an exact cut list with no scenedetect errors, complementing the direct-write already shipped on the output side.
  • A caption style picker per video (clean / quantities / playful), instead of one style per profile.
  • Per-section regenerate with a corrective note, instead of regenerating a whole video’s captions at once.
  • Multi-account support with authentication. Today’s profiles are unauthenticated presets within one local install, not logged-in identities. Deliberately out of scope while this stays a two-person tool.