go-astisub: one Go library for rewriting subtitle files in six formats
Manipulate subtitles in GO (.srt, .ssa/.ass, .stl, .ttml, .vtt (webvtt), teletext, etc.)
At a glance
- What is it?
- go-astisub is a Go library and CLI for parsing, writing, syncing, fragmenting, merging and optimizing subtitle files across srt, ssa/ass, stl, ttml, webvtt and teletext. It fits pipeline work where subtitles must be re-timed or re-encoded programmatically, and its limits are visible in the roadmap and in what a conversion can carry across formats.
- Who is it for?
- Adopt go-astisub if subtitles are part of a Go pipeline and you need programmatic control over timing, fragmentation and format conversion rather than a one off edit. Do not adopt it if you need .smi support, which the roadmap still lists as unfinished, or if your workflow needs a released version to pin, since the repository has no GitHub releases and only a master branch.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 36 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One document model behind six subtitle formats
go-astisub is a Go library for manipulating subtitle files, and the useful part of its design is that the operations do not care which format you started with. The README lists srt, stl, ttml, ssa/ass, webvtt and teletext as supported, and the available operations are parsing, writing, applying linear correction, syncing, fragmenting, unfragmenting, merging and optimizing. The repository layout matches that claim: subtitles.go holds the shared core, and srt.go, ssa.go, stl.go, ttml.go, webvtt.go and teletext.go sit beside it as one file per format, with the CLI in cmd/ and format test data under testdata/. The user is a Go developer whose application or media pipeline has to re-time subtitles, split long cues, stitch several files together or convert between formats without shelling out to a separate binary. The same code path serves a live streaming pipeline and a batch transcode job, which is the reason to prefer a library over the CLI here.
Sync, fragment and unfragment are the operations pipelines actually need
The vocabulary is small and each verb has a distinct job. Syncing shifts every subtitle by a duration, which is what you want when a video's audio was trimmed. Fragmenting splits a long cue into shorter pieces of a given length, and unfragmenting does the reverse, joining adjacent cues that belong together. Merging combines two subtitle sets into one, which is how you would assemble a track from a part one file and a part two file. Optimizing is listed alongside them, and the example labels the call as optimizing subtitles, though the README does not spell out the rule it applies. Ordering is another item on the feature list. The key point is that these are timing operations on a parsed document, not text edits, so they compose: a track can be shifted, split, merged with another and then written out in a different format without a second parse of the raw text.
Linear correction takes four durations where a sync takes one
Syncing is the blunt instrument. It applies the same offset to everything, which breaks as soon as the source timing drifts rather than shifts. Linear correction is the finer one, and it takes four time values instead of one, as the library call shows: s1.ApplyLinearCorrection(1*time.Second, 2*time.Second, 5*time.Second, 7*time.Second). The CLI exposes the same four inputs as flags named a1, d1, a2 and d2, so the shape of the correction is defined by two pairs of values. The README does not explain how those pairs map to source and target timings, so you should read the source in the repository rather than guess at the semantics from the flag names. The practical takeaway is that a shift, a stretch or a drift correction are different problems, and only the shift has a single parameter.
Installing the library and the CLI, then converting a first file
The library is a standard Go module, added to a project with go get:
go get github.com/asticode/go-astisubThe command line tool lives under cmd/astisub in the same module and installs separately with go install github.com/asticode/go-astisub/cmd/astisub. Once installed, the shortest useful first step is a format conversion, where the input and output types can differ:
astisub convert -i example.srt -o example.ttmlThe same shape applies to the other verbs, with an input file, an output file and the operation specific flags:
astisub apply-linear-correction -i example.srt -a1 1s -d1 2s -a2 5s -d2 7s -o example.out.srt
astisub fragment -i example.srt -f 2s -o example.out.srt
astisub merge -i example.srt -i example.ttml -o example.out.srt
astisub sync -i example.srt -s "-2s" -o example.out.srtNote that merge accepts more than one -i flag, and that the sync offset is written as a negative duration, so the flag values are parsed as time values rather than as plain numbers.
The library in process and the CLI as a subprocess are two different integration shapes
The same operations exist in two forms, and choosing between them is an integration decision rather than a feature decision. The library parses into a document you hold in memory, so you can inspect it, decide what to do, and write it back out to a path or to a bytes.Buffer, which is what the example does with Write and WriteToTTML. Nothing touches the disk until you write, and the buffer form lets a subtitle track be produced inside a server response. The CLI runs the same logic as a separate process, which fits a shell pipeline and a media workflow where the subtitle file is one stage among several. The trade-off is error handling. The README explicitly warns that its library example skips error handling for readability and that you should not, which is a warning about the in process route: a file that fails to parse returns an error you are expected to check, and there is no partial progress to resume. The CLI moves that failure into an exit code.
The format list has a hole, and conversions are not documented as lossless
Two constraints deserve attention before you plan around this library. The first is the roadmap itself, which still lists.smi as an unchecked box while every other listed format is marked done, so a workflow that receives Sami subtitles has no path here. The second is what happens to styling when a file changes format. The library exposes a single shared document model with per format readers and writers, and the convert command accepts any input type with any output type, but the README does not say which fields survive the trip. An ssa/ass file carries named styles, and a plain srt file does not, so a conversion in that direction has to drop or flatten something, and the documentation does not say which behaviour you get. The same silence applies to the reverse direction, where a plain file that is written back out as ssa/ass will need a style the source never had. The same applies to teletext, which is a fixed character grid with a completely different timing and layout model from timed text.
MIT licensed, no tagged releases, and a module that still declares go 1.13
The licence is MIT, so embedding the library in a closed source Go application carries no obligation to publish your own code, and the licence file sits at the top of the repository. Versioning is where the friction is. The repository has no GitHub releases, and the README does not explain how versions are cut, so the install path documented above pulls the master branch and there is no release tag to pin in a go.mod requirement. The last push was on 2026-09-17, which means the dependency graph you resolve today is whatever master happened to contain. The module declaration is also conservative, listing go 1.13 as its language version, and it depends on go-astikit v0.20.0, go-astits v1.8.0, testify v1.4.0, golang.org/x/net and golang.org/x/text v0.3.2. The x/text and x/net pins are old, and the teletext support brings a charset mapping file with it, which is a reminder that this is a library with real parsing depth rather than a thin wrapper.
Editorial conclusion
Adopt go-astisub if subtitles are part of a Go pipeline and you need programmatic control over timing, fragmentation and format conversion rather than a one off edit. Do not adopt it if you need .smi support, which the roadmap still lists as unfinished, or if your workflow needs a released version to pin, since the repository has no GitHub releases and only a master branch. Before committing, convert one .ass file to .srt and check what survives, since the README does not document how styling carries between formats, and check that your input timings are anchored consistently, since the linear correction flags a1, d1, a2 and d2 are not explained. The last push was on 2026-09-17 and the module still declares go 1.13.
Frequently asked questions
What is go-astisub and what can it do?
go-astisub is a Go library, with an accompanying CLI, for manipulating subtitle files. It parses and writes srt, stl, ttml, ssa/ass, webvtt and teletext, and it can sync, fragment, unfragment, merge, optimize and apply linear correction to them.
How do I install go-astisub and its command line tool?
The library is installed as a Go module with go get github.com/asticode/go-astisub, and the CLI is installed separately from the same module with go install github.com/asticode/go-astisub/cmd/astisub.
Does go-astisub support .smi subtitles?
No. The roadmap in the README lists .smi as an unchecked item, while parsing, writing and the other operations are marked done for srt, ttml, vtt, stl, ssa/ass and teletext.
What is the difference between syncing and applying linear correction in go-astisub?
Syncing applies a single duration offset to every subtitle, for example s1.Add(-2*time.Second). Linear correction takes four duration values, as in ApplyLinearCorrection(1*time.Second, 2*time.Second, 5*time.Second, 7*time.Second), and the CLI exposes the same four inputs as the flags a1, d1, a2 and d2.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/asticode-go-astisub)Was this useful?