Watch One Pace with official Japanese subtitles, perfectly timed to the fan recut.
One Pace ships English subs only. Official Japanese subtitles exist (Netflix rips on
Jimaku / kitsunekko) โ but they're timed to the original episodes,
not the recut. This tool listens to the One Pace episode's own audio, finds where every
official line is actually spoken, and writes a .ja.ass that players auto-load.
The official text is never altered: speech recognition is only used as a timing key,
so ASR mistakes can't reach your screen.
โโ you โโโโโโโโโโโโโโ โโ pipeline (opace_asr_bridge.py) โโโโโโโโโโโโโโโ
โ video.mkv โ โโโบ โ transcribe (cached) โ match official lines โ โ
โ official .vtt(s) โ โ write video.ja.ass + .debug.tsv + .review.jsonโ
โโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโ review.json (raw track)
โผ
โโ reviewer/index.html โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ drop video + review.json โ watch, flag fixes (previews live): โ
โ remove ยท missing ยท retime ยท trim ยท wrong ยท edit ยท section ยท noteโ
โ Export โ video.review-notes.json (drop in the episode folder)โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ re-run the pipeline with --redo
โโ pipeline โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ BAKES your notes into video.ja.ass (no re-transcription) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ watch the finished video.ja.ass in mpv / VLC
- Generate โ
python opace_asr_bridge.py "<episode>"โโฆja.ass(what you watch) +โฆdebug.tsv(trace) +โฆreview.json(the reviewer's input). - Review โ open
reviewer/index.html, drop the video +review.json, watch, and flag fixes. Each previews live. Export the notes into the folder. - Bake โ re-run with
--redo; your notes are applied into the.ja.ass. - Repeat 2โ3 until happy. The only things that aren't a one-button bake are a
missing source file (a
*** DIALOGUE, UNMATCHED ***gap โ add the right.vttand re-run) andsection/noteobservations (human judgement).
excludes.txt / pins.txt (below) still work โ they're the hand-edited shortcut
when you don't want to open the player. The reviewer covers everything they do and
more, so they're optional now, not the main path.
These names/extensions are reserved โ the tool recognizes them by pattern:
| Name / pattern | Role | Written by |
|---|---|---|
*.mkv *.mp4 *.m4v *.avi *.webm |
input โ the One Pace video (exactly one per folder) | you |
*.vtt *.srt *.ass (but not *.ja.ass) |
input โ official JA sub(s); one per source episode, used in filename order | you |
excludes.txt |
override โ lines to delete, one exact text per line | you |
pins.txt |
override โ lines to force-place: text, or MM:SS text for an exact time |
you |
*.review-notes.json |
override โ fixes exported from the reviewer | the reviewer |
<video>.ja.ass |
output โ the timed subtitle you watch (mpv/VLC auto-load) | pipeline |
<video>.ja.ass.debug.tsv |
output โ per-line placement trace | pipeline |
<video>.ja.ass.review.json |
output โ raw track the reviewer loads | pipeline |
work/asr_*.json, work/*.wav |
cache, regenerable (gitignored) | pipeline |
Two things worth being precise about:
- Inputs and overrides are read every time an episode is processed โ there's
no separate "override mode." The matcher always reads the video + subs; the
emit step always applies
excludes.txt/pins.txt/*.review-notes.jsonif present. You add an override, then reprocess. --redoonly decides whether an already-finished episode runs at all. An episode that already has a<video>.ja.assis skipped by default (so re-runninginputs/doesn't redo everything);--redoforces it to reprocess โ which is exactly when your newly-added overrides get baked in. (--forceis a kept alias.)
Requirements: Python 3.10+, ffmpeg on PATH (macOS: brew install ffmpeg), and
ideally an NVIDIA GPU (CPU works, ~10ร slower).
The Python dependencies live in requirements.txt. Create an isolated virtual
environment for the project and install them into it:
python -m venv .venv # create the .venv/ folder (once)
source .venv/bin/activate # enter it โ prompt shows (.venv)
pip install -r requirements.txt # install the deps into itAfter that, just activate the venv whenever you work on the project; if the
script errors with ModuleNotFoundError, you forgot to activate it:
source .venv/bin/activate # before each session
deactivate # when you're doneThe .venv/ folder is machine-specific and git-ignored โ never commit it; rebuild
it with the three commands above. GPU users also want the CUDA libs (commented at
the bottom of requirements.txt); on Apple Silicon / CPU they're unnecessary.
Put each episode in its own folder: one video + its official Japanese sub(s).
An episode cut from several source episodes gets several sub files โ they're used
in filename order, which matches playback order for normal naming (S01E02 before S01E19).
Folders can nest however you like โ anything containing exactly one video plus sub file(s) is an episode; everything else is just organization:
inputs/
โโโ rd03/
โ โโโ [One Pace][3-5] Romance Dawn 03 [1080p].mkv
โ โโโ ใฏใณใใผใน.S01E02.WEBRip.Netflix.ja[cc].vtt โ multi-source episode:
โ โโโ ใฏใณใใผใน.S01E19.WEBRip.Netflix.ja[cc].vtt โ one sub per source ep
โโโ rd04/
โ โโโ ...
โโโ orange town/
โโโ 1/
โ โโโ [One Pace][8-11] Orange Town 01 [1080p].mkv
โ โโโ ใฏใณใใผใน.S01E04.WEBRip.Netflix.ja[cc].vtt
โ โโโ ใฏใณใใผใน.S01E05.WEBRip.Netflix.ja[cc].vtt
โ โโโ ใฏใณใใผใน.S01E06.WEBRip.Netflix.ja[cc].vtt
โโโ 2/
โโโ 3/
Then:
python opace_asr_bridge.py inputs/ # everything, recursively
python opace_asr_bridge.py "inputs/orange town" # one arc
python opace_asr_bridge.py inputs/rd03/ # one episodeFirst run downloads the Whisper model (~3 GB). Each episode takes ~3โ5 minutes on a
mid-range GPU (transcription is cached โ re-runs take seconds). The result lands next
to the video as <video>.ja.ass; mpv/VLC load it automatically. Episodes that already
have a .ja.ass are skipped โ --redo redoes them.
--delete-video removes each video (plus its cached audio) after successful
processing to reclaim disk space. Mind that the subs are only useful with the
video โ use this for arcs you've already watched, or when the videos are copies of
a library kept elsewhere. Re-processing with different subs stays possible either
way (the transcript is cached separately and is all the matcher needs).
Each episode prints a report; the arc run ends with a summary. The important part is the gap list โ stretches with no subtitles, classified by what the audio contains:
gaps > 20s:
01:26.75 -> 02:52.61 (quiet: song/transition, OK) โ opening theme, fine
17:46.25 -> 18:16.41 *** DIALOGUE, UNMATCHED -- missing a sub source? ***
ASR heard: ใใใฎใใใชใฉใใ ใใ
ใใ... โ read this sample!
A dialogue gap means people are talking but no official line matched โ almost always
a missing or wrong subtitle file. One Pace episodes often pull content from source
episodes the episode title doesn't mention, and streaming-service episode boundaries
don't always match the TV episodes. The printed sample tells you (or a search engine)
which episode the missing scene is from: add that sub file to the folder and re-run
with --redo.
reviewer/index.html is a single-file web app (no build, no server โ just open it)
for reviewing an episode and capturing what's wrong as a structured list. Drop in
the video and its โฆโ.ja.ass.review.json sidecar (written next to every output);
it renders the track, surfaces unplaced official lines that fall in the gap you're
watching ("is this spoken here?"), and lets you flag remove / missing / retime /
wrong / trim / edit / note per line โ each previewed live on the track. Export the notes,
drop the โฆโ.review-notes.json back in the episode folder, and re-run with
--redo: the tool bakes the edits into the .ja.ass (no re-transcription).
Notes that need judgement (a missing source file, a structural fix) are decided
from the list. See reviewer/README.md.
The โฆโ.ja.ass.review.json sidecar is committed to git, so you can review on a
different machine than you processed on. If it's ever missing (older episode, lost
file), regenerate it from the existing .ja.ass without re-transcribing:
python opace_asr_bridge.py "inputs/.../episode folder" --rebuild-reviewThis reconstructs the sidecar offline; the only thing lost is the per-line
confidence hint (method/parts), which is nice-to-have for reviewing, not
required. A full --redo pass restores those.
<video>.ja.ass.debug.tsvlists every official line with its placement method and time โcover= heard in the audio,rescue/part= fuzzy-matched,interp/interp1= inferred from context (no acoustic evidence; the lines to be most skeptical of).- A line that genuinely shouldn't exist (One Pace cut it, but context made it look
present): put its exact text in
<episode folder>/excludes.txt, one line per entry, and re-run with--redo. - The opposite โ a line you can hear but ASR couldn't (heavy music): put its exact
text in
<episode folder>/pins.txt; it gets placed by official-sub spacing from the nearest matched line. Your ears outrank every automated gate. Prefix the line with the timestamp you heard it at โ11:39 ๆง๏ผโ to place it exactly there instead (better near One Pace's reorders/cuts, where spacing-inference drifts). --separatere-transcribes from a dialogue-isolated track (BS-RoFormer; needspip install "audio-separator[gpu]"andpython3-dev). Slower, and not better across the board โ use it as a second opinion on stubborn episodes.
- The video must have Japanese audio. Multi-audio releases are handled (the
jpn-tagged track is selected automatically), but an English-dub-only file produces garbage โ the telltale is a tiny "lines placed" count. - Pure screams/grunts (
ใใใใผใฃ,ใใฃโฆ) are only subtitled when actually heard โ a wrong grunt is worse than a missing one. - Opening/ending songs are intentionally unsubtitled (lyrics aren't in the dialogue subs).
Whisper transcribes the episode with word-level timestamps. Both the transcript and the official lines are converted to hiragana readings (MeCab), so kanji/kana spelling differences don't matter. The two character streams are aligned; every official line whose characters are found gets stamped with the time those characters were spoken. Unmatched lines are recovered by windowed fuzzy search, proportional interpolation, and anchor extrapolation โ each gated by structural checks (scene continuity, gap ratios, neighbor-spacing predictions) so that no line is placed without either acoustic evidence or strong structural proof. Design rationale and war stories: DEVLOG.md.