Frankenstein - Stitch the best video and audio from different MKV files into one perfectly synced copy.
You have two versions of the same film:
movie_hq.mkv— high-quality video (H.265 1080p) but only the original language audiomovie_lang.mkv— your preferred language dub, but low-quality video
Naively muxing them together leaves the audio out of sync: the two versions may differ due to gradual drift (e.g. 29.97 vs 30 fps sources) or discrete cuts (censored/missing scenes in one version).
frankensync detects and corrects both automatically, then produces a new MKV with the tracks you chose.
Install ffmpeg and mkvtoolnix:
# Debian / Ubuntu
sudo apt install ffmpeg mkvtoolnix
# macOS
brew install ffmpeg mkvtoolnixRequires Python >= 3.14 and uv >= 0.11.6:
uv tool install git+https://github.com/n-elia/frankenstein- Copy both MKV files into the same folder
- Open a terminal in that folder and run:
frankensync- Pick the video, audio, and subtitle tracks in the interactive TUI
- Done -- the merged file is written as
<name>_merged.mkvin the same folder
frankensync <file1.mkv> <file2.mkv> [--output PATH]| Argument | Description |
|---|---|
file1, file2 |
MKV files to merge (optional in directory mode) |
--output, -o |
Output path. Defaults to <stem>_merged.mkv. |
From a local checkout, prefix with uv run:
uv run frankensync movie_hq.mkv movie_lang.mkv -o movie_final.mkv
Step 1 — Select the video track
Step 2 — Select the audio track
Step 3 — Select the subtitle track (optional)
- Interactive TUI (Textual) to pick video, audio, and subtitle tracks across both source files
- Chroma cross-correlation (librosa + scipy) to compute the exact time mapping between the two audio versions
- No video re-encoding -- the video track is always stream-copied
- Lossless audio correction for pure drift (
mkvmerge --syncadjusts PTS timestamps only) - Re-encoding only when cuts require it -- uses the source codec where possible, falls back to AAC, and fills censored gaps with the reference audio
- Subtitle realignment -- SRT and ASS/SSA timestamps are remapped using the same warp map; bitmap formats (PGS/VOBSUB) get a constant offset
| Category | Supported formats | Notes |
|---|---|---|
| Container | MKV | Via mkvtoolnix for muxing/extraction and ffprobe for inspection |
| Video | All codecs supported by ffmpeg | Always stream-copied, never re-encoded |
| Audio | All codecs supported by ffmpeg | Lossless PTS correction via mkvmerge --sync; re-encoding only when cuts require it |
| Subtitles | SRT, ASS/SSA | Full warp-map remap via scipy interpolation |
| Subtitles (bitmap) | PGS, VOBSUB | Constant offset only |
