My friend and I spent the summer building a subtitle sync engine that outperforms alass and ffsubsync
Lapse repo : github.com/r-stisen/lapse (Note: there's also a Jellyfin plugin for it, github.com/r-stisen/lapse-jellyfin-plugin , more on that at the bottom) My friend and I spent the summer building Lapse, a tool that fixes out-of-sync subtitles automatically. Point it at a video and a subtitle file and it works out the offset, corrects drift from framerate mismatches, and can even split a file if it was cut differently than your subtitle expects. You can run it as a CLI binary for one file at a time, as a Docker image that watches your whole library and syncs new files as they show up, or through the Jellyfin plugin mentioned above. We used AI to help look things up, papers, library docs, that kind of thing. GitHub Copilot has added a few comments here and there and helped with formatting, splitting up some long lines so the code reads easier, but that's pretty much it. We're also working on improving the documentation itself a bit more going forward. Since it's a summer project and we wanted to know if it was actually any good, we spent a day benchmarking it against alass and ffsubsync on 39 feature films chosen specifically because they're hard to sync (long runtimes, quiet stretches, heavy score, different cuts). Lapse passed 36 of 39 in normal mode . Full methodology and the per-film results are in docs/benchmarks.md (github.com/r-stisen/lapse/blob/main/docs/benchmarks.md) if you're curious. Worth saying up front: one day of testing on 39 films is not some final word on which tool is best, it was mostly us wanting to see how our own project stacked up. Lapse has also had a couple of upgrades since that benchmark that should make it a bit stronger and more secure, but we haven't re-run the numbers yet. Right now we're working on wider subtitle format support. There's a branch for MicroDVD already, and PGS is in progress, though MicroDVD is giving us more trouble than expected. Hoping to have most formats supported before the semester starts back up in September. We're also planning to add a doc that walks through how the syncing actually works under the hood. Short version for now: Lapse uses voice activity detection to find where speech happens in the audio, then compares that against where the subtitle cues say speech should happen, and uses that to work out offset and drift. Also spending some time right now on an efficient SRT parser, mostly as a starting point for more of this later. Parsing subtitles for a 2 hour film currently takes about 0.3ms on average, and I'm hoping to get that down to somewhere around 20 to 100 microseconds. So if you start using Lapse and suddenly feel a 200 microsecond speed difference, or maybe even more, you know i've succeded. Really trying to optimize where it actually counts here, because god forbid someone has to wait a whole extra millisecond from me being sloppy about it. Last thing, about that Jellyfin plugin noted at the top. It's actually pretty capable if you want to check it out. From the plugin you can install Lapse itself, or alass or ffsubsync instead if you'd rather use one of those. You can sync a movie directly from the movie's page, or go to the dashboard and set up a scheduled sync or run a bulk sync across your whole library. There's also control over subtitle appearance, size, color, a background behind the text, and it can translate subtitles and let you decide how the output should look. On top of that there's an overview showing what's synced and what still isn't. There are more improvements coming for it too, but the engine is still where most of our focus is going. Also feedback or anything is really welcome so dont hesitate to reach out or make an issue on Github )) Edit: added the link to the plugin repo in case anyone's interested