Releases: SonicSandbox/Tsubasa-sync
Release list
tsubasa v0.1.9
One new function: take a subtitle track out of a video, as a file.
Nothing about pairing or retiming changed.
extract_subtitle() — the subtitles inside an MKV, saved as a file
Many videos carry their subtitles inside the file. A player shows them; a tool that
reads only subtitle files cannot see them. hato
needed exactly that: when a video already has Japanese subtitles inside it, one of its
choices is to save them beside the video, as a file — for a tool that reads only files.
import tsubasa
subs = tsubasa.embedded_subs("Show - 01.mkv", lang="ja")
got = tsubasa.extract_subtitle("Show - 01.mkv", subs.tracks[0], write=True)
if not got.ok:
print("could not take it out:", got.reason)
elif got.write_failed:
print("taken out, but not written:", got.reason)
else:
print("saved as", got.output_path) # Show - 01.ja.ass- In its own format, never converted. An
.asstrack comes out as.ass, with its
header and styles; an.srttrack as.srt. Each line's text is exactly what the file
stores. - Written only when you ask (
write=True), under tsubasa's own name for it —
<video>.<language>.<ext>— beside the video or inout_dir, in one step, and never
over a file that is already there. Withoutwrite=True,got.dataholds the bytes. - MKV only, and no ffmpeg needed — tsubasa reads the container itself. An MP4's
subtitles have no file format of their own, so taking them out would mean converting
them: refused, with the reason. - Refused with a reason, never guessed: a WebVTT track, a picture-based track (PGS,
VobSub), a damaged or still-downloading file — could not take it out is never a
shorter subtitle. - Checked against ffmpeg: 649 real subtitle files (400
.ass, 249.srt) put into a
video and taken back out — every line identical to ffmpeg's own copy of the same track.
⚠ An ASS track's fonts are attachments of the video, not part of the track, so they do
not come along — the words and the styles do.
Getting it
The app, no Python needed: download tsubasa-windows-x64.zip below, unzip
it anywhere, double-click tsubasa-gui.exe. SHA256SUMS is the checksum.
⚠ Unsigned, so the first launch shows "Windows protected your PC" — click
More info, then Run anyway.
As a command or a library:
pip install --upgrade tsubasa-sync
tsubasa /path/to/your/folder
ffmpeg is not bundled. Matroska files with a subtitle track inside need
nothing; any other container needs ffmpeg and ffprobe on PATH, or the
folder holding them in TSUBASA_FFMPEG.
tsubasa v0.1.8
One small change: .jp now means Japanese.
Nothing about pairing or retiming changed.
Show - 01.jp.srt is a Japanese subtitle
jp is Japan's country code, not a language code (that is ja). But it is
common in subtitle names: 271 of 17,790 real subtitle names in the project's
filename sample are written ….jp.<ext>. tsubasa read them as unknown language.
That mattered to tools built on tsubasa. hato,
which fetches Japanese subtitles, asks tsubasa whether a video already has one. A
video sitting beside Show - 01.jp.srt was told no, so hato fetched a second
subtitle beside a Japanese one that was already there.
Now jp reads as ja, in any casing (.jp., .JP., .Jp.), in the same place
any other language tag is read. Asking for lang="jp" resolves to Japanese as well.
Measured before it landed: of those 17,790 names, exactly the 271 .jp. ones
change, every one from unknown to Japanese. Nothing else moves.
What that changes in a folder
tsubasa keeps one subtitle per video per language. So if a folder holds a
.jp. subtitle and another Japanese subtitle for the same episode, tsubasa
now keeps one and moves the other to the trash, where it can be restored. That is
the rule it has always applied to two Japanese subtitles.
Before this release, the .jp. file was written out with no language in its name
(Show - 01.ass), and other tools read that as no language.
Getting it
The app, no Python needed: download tsubasa-windows-x64.zip below, unzip
it anywhere, double-click tsubasa-gui.exe. SHA256SUMS is the checksum.
⚠ Unsigned, so the first launch shows "Windows protected your PC" — click
More info, then Run anyway.
As a command or a library:
pip install --upgrade tsubasa-sync
tsubasa /path/to/your/folder
ffmpeg is not bundled. Matroska files with a subtitle track inside need
nothing; any other container needs ffmpeg and ffprobe on PATH, or the
folder holding them in TSUBASA_FFMPEG.
tsubasa v0.1.7
A safety release. Both fixes are about the same thing: what this tool moves
to the trash, and whether it tells you first.
Nothing about pairing or retiming changed. The alignment results are identical,
verified against 29 pairs of measured ground truth.
Upgrade if you keep more than one subtitle per episode. If every episode in
your library has exactly one subtitle file, neither of these could ever have
affected you.
It no longer trashes a subtitle whose language it cannot read
tsubasa keeps one subtitle per video per language, and everything else for
that slot goes to the trash. When it cannot work out a file's language from its
name it records that as unknown — and it was treating "unknown" as though it
were the name of a language. Two files it could not read were therefore assumed
to be the same language, and one of them was thrown away for the other.
They are not the same language. They are two files it knows nothing about.
Now, when the language is unknown, tsubasa still picks one file to write —
it has to, because they all resolve to the same output name and the second write
would destroy the first — but it supersedes nothing, and it says so:
1 subtitle NOT trashed: no language could be read from its name, and an
unreadable tag is not evidence that two files are the same language. Only
one file can be written as Show - 01.srt, so the other is left exactly
where it is: Show - 01.ae.srt
This turned up in a real library. Measured on the project's own end-to-end
benchmark, one more real broadcast subtitle now survives a run that previously
consumed it.
If you use a tool that writes several subtitles per episode and tells them
apart with a suffix — SubPlz does this, labelling each algorithm with a
language code — this is the release you want. tsubasa still will not tidy
those folders up for you, but it will no longer remove anything from them.
--dry-run now tells you what it would throw away
--dry-run promises to print every intended action. It printed the writes and
said nothing about the trash, because the field it counted only ever holds files
that have actually moved — and on a dry run nothing moves. So the one action
you cannot undo was the only one missing from the preview.
It now names each file, in the future tense:
1 subtitle would be superseded → trash
Show - 01.ae.srt
A count would not have been enough. The whole reason to read a dry run is to
decide whether you agree with it.
--json carries this as would_supersede. The existing superseded field is
unchanged and still means paths that actually moved.
Also
If your antivirus removes the Windows download, it is a false positive — and
the file is not gone. Defender quarantines rather than deletes, and it is a
few clicks from coming back.
docs/WINDOWS-STARTUP.md
now explains what gets flagged — PyInstaller's launcher, which every app
packaged that way carries — and gives you both ways to restore it.
⭐ If you already have Python,
pip install tsubasa-syncis the better
route. Same application, starts in about a second instead of a few, and
antivirus never touches it. The zip exists for people who do not have Python.
Getting it
The app, no Python needed: download tsubasa-windows-x64.zip below, unzip
it anywhere, double-click tsubasa-gui.exe. SHA256SUMS is the checksum.
⚠ Unsigned, so the first launch shows "Windows protected your PC" — click
More info, then Run anyway.
As a command or a library:
pip install --upgrade tsubasa-sync
tsubasa /path/to/your/folder
ffmpeg is not bundled. Matroska files with a subtitle track inside need
nothing; any other container needs ffmpeg and ffprobe on PATH, or the
folder holding them in TSUBASA_FFMPEG.
tsubasa v0.1.6
A fix release. The app feels the way it should now, it starts faster, and it
tells you when something is wrong with your install instead of waiting until you
try to sync something.
Nothing about pairing or retiming changed. If 0.1.5 works for you, this is a
free upgrade — the alignment results are identical, verified against 29 pairs of
measured ground truth and every one of 12,894 retimed subtitle timestamps.
The window responds properly
Four things were wrong with the buttons, and all four are the kind you feel
rather than read about:
- Pressing Sync or Stop did nothing visible. The pressed colour was being
computed the same way as the hover colour, so on the coloured buttons — the
ones you actually click — there was no feedback at all. - The red Stop button flashed blue when pressed during a run.
- Hovering over a button twice could leave it stuck lit, and it got brighter
each time. - Starting a run and moving the mouse away turned Stop back into a blue
Sync, while the run was still going. This was the common path — you click
Sync with the pointer on the button.
It starts faster
The app was importing its whole numeric stack just to draw a window, which it
never uses — it runs the command-line tool for every job. That is gone.
| Time to open the window | 462 ms → 251 ms |
| Memory the window holds | 29.5 MB → 19.0 MB |
⏱ If the first launch after a reboot still takes a few seconds, that is
Windows Defender, not tsubasa: the app is unsigned, so all 1,274 of its
files get scanned on every cold start. Nothing in the app can change that.
docs/WINDOWS-STARTUP.md
explains it and gives you a one-folder exclusion if you want the seconds back.
It notices a broken install
tsubasa --version now actually tries to load numpy rather than just checking
whether it is present. The common Windows failure — numpy installed, findable,
and failing to load with DLL load failed — used to report ok and then
fall over on your first sync. Now it says so, and tells you how to fix it:
PROBLEM: numpy is installed but will not load (ImportError: DLL load
failed while importing _multiarray_umath), and it is the one dependency
tsubasa cannot work without: every alignment raises. Reinstalling it
usually fixes this: `pip install --force-reinstall numpy`.
Getting it
The app, no Python needed: download tsubasa-windows-x64.zip below, unzip
it anywhere, double-click tsubasa-gui.exe. SHA256SUMS is the checksum.
⚠ Unsigned, so the first launch shows "Windows protected your PC" — click
More info, then Run anyway.
As a command or a library:
pip install --upgrade tsubasa-sync
tsubasa /path/to/your/folder
ffmpeg is not bundled. Matroska files with a subtitle track inside need
nothing; any other container needs ffmpeg and ffprobe on PATH, or the
folder holding them in TSUBASA_FFMPEG.
tsubasa v0.1.5
The first packaged release. tsubasa has been on PyPI for a few versions, but
this is the first one you can download and double-click — no Python, no pip, no
terminal.
What it does
You have videos. You have subtitles. They are named nothing like each other and
the timing is off. Point tsubasa at the folder.
- Pairs subtitles to videos by cue timing, not by text — so it works in any
language, and on files named nothing alike.黄泉のツガイ.S01E18.WEBRip.ABEMA.ja[cc].srt
finds[SubsPlease] Yomi no Tsugai - 18 (1080p) [DD1CA4BC].mkv. - Retimes the subtitle to match, and tells you the offset it applied.
- Refuses rather than guessing. A confidently wrong subtitle is worse than
no subtitle, so every pair it cannot measure is declined with the reason.
A different episode of the same show gets left alone. - Repairs broadcast cuts — a TV edit with an ad break removed is two
segments, and it solves both. - Never deletes anything. Superseded files go to the trash, never away.
- Remembers what it already did, so a settled folder re-runs in a fraction
of a second instead of doing the work again.
Two ways to use it
1. The app — Windows, nothing to install
Download tsubasa-windows-x64.zip below, unzip it anywhere, and
double-click tsubasa-gui.exe. Drag a folder onto the window.
⚠ It is not code-signed, so the first launch shows "Windows protected your
PC" — click More info, then Run anyway.SHA256SUMSbelow is the
checksum if you want to verify the download.
2. The command line and the library — anywhere Python runs
pip install tsubasa-synctsubasa ~/Anime # subtitles sitting with the videos
tsubasa ~/Anime --subs ~/Downloads/subs # or somewhere else entirely
tsubasa ~/Anime --dry-run # show me first, write nothingimport tsubasa # the distribution is tsubasa-sync
# ⚠ a real path — the shell expands `~` for the command line, Python does not
for result in tsubasa.sync(tsubasa.scan(r"D:\Anime")):
print(result.outcome, result.offset, result.reason)It is dry by default: sync(..., write=True) is what moves bytes.
tsubasa --version reports the build, whether its data tables are intact, and
whether it found ffmpeg — it is the one thing worth pasting into a bug report.
New in this release
- The Windows standalone, and a logo everywhere it belongs.
tsubasa --version, which reports whether the build is whole and not
merely present.- A modern folder picker, hover states throughout, and column headings that
no longer flash white on a dark theme. - The GUI no longer wedges if it cannot start its own command line, and it no
longer fails to open when drag-and-drop support is missing. - ⭐ Jellyfin and Emby libraries pair properly.
Show - 01.Japanese.srt
used to read as no language, so it was a different file from
Show - 01.ja.srt— neither replaced the other and both were kept. English
display names now resolve to their codes, and
Show - 01.Japanese.forced.srtkeeps its forced flag, which it also used to
lose. (Reported by the hato project.)
Good to know
- ffmpeg is not bundled. Matroska files with a subtitle track inside need
nothing; any other container needsffmpegandffprobeonPATH, or the
folder holding them inTSUBASA_FFMPEG. - A video with no subtitle track inside it cannot be synced yet — it is
refused with a reason rather than guessed at. Audio analysis is specified and
not yet wired. - Everything it writes outside your media lives in
%LOCALAPPDATA%\tsubasa.
GPL-3.0-or-later. Built by SonicSandbox.
