subtitle

package
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 22, 2026 License: GPL-3.0 Imports: 9 Imported by: 0

Documentation

Overview

Package subtitle parses SRT/VTT subtitle text and re-renders it to canonical SRT, per PLAN.md's "Upload safety" section. Ported from ../stash-subs/stash_subs/subtitles.py's parse()/render_srt()/render_vtt(): parsing anchors on the timestamp line and ignores cue numbers, headers and NOTE blocks, so anything unparsed is discarded — that discarding IS the sanitization. Re-rendering rather than storing raw uploaded bytes is what moansubs actually persists in subtitle_tracks.body.

Index

Constants

View Source
const (
	MaxBytes = 2 * 1024 * 1024 // 2 MiB
	MaxCues  = 10000
)

Caps from PLAN.md "Upload safety": "cap file size and cue count; reject anything absurd." Attacker-controlled upload input gets a hard ceiling before any parsing work happens.

Variables

This section is empty.

Functions

func BaseLang

func BaseLang(tag string) (string, error)

BaseLang normalizes tag (full BCP-47, e.g. "pt-BR") to its bare ISO 639 subtag (e.g. "pt") — the same reduction plugin/sidecar.go's ResolveCaptionLang applies before writing a caption filename, exposed here so the server's GET /api/v1/subtitles/{id}?format=srt path shares the one implementation instead of duplicating the language.Parse/Base dance. Delegates to CanonicalLang for the Parse/Base/confidence work.

func CanonicalLang

func CanonicalLang(tag string) (canonical, base string, err error)

CanonicalLang validates tag and returns its canonical BCP-47 form (e.g. "en_US" -> "en-US", "EN" -> "en") alongside its bare ISO 639 base subtag (e.g. "pt-BR" -> "pt"). Both the canonical form and the base are derived from the same language.Parse call so they can never disagree on what tag they describe.

Base() confidence must be language.High or better (Exact). "und" parses cleanly but Base() only guesses "en" at Low confidence — nobody uploaded English, the tag just carries no language at all — and a private-use tag like "x-klingon" parses with Base() at No confidence. Accepting either would silently misfile the track: this is stored verbatim as the track's language and compared for identical-track dedup (ingest, subtitles.go) and by /browse?lang=, so a guessed-at base isn't good enough. Errors naming the tag rather than guessing.

func RenderSRT

func RenderSRT(cues []Cue) string

RenderSRT re-renders cues to canonical SRT: sequential numbering, "HH:MM:SS,mmm --> HH:MM:SS,mmm", blank-line separated. This is what gets stored in subtitle_tracks.body (PLAN.md "Data model").

func RenderVTT

func RenderVTT(cues []Cue, note string) string

RenderVTT re-renders cues to WebVTT, optionally with a NOTE block carrying note verbatim (e.g. provenance JSON — see internal/provenance). Needed for later NOTE-block provenance passthrough on download (PLAN.md "AI-generated disclosure"); SRT remains the canonical stored form.

Types

type Cue

type Cue struct {
	Start time.Duration
	End   time.Duration
	Text  string
}

Cue is one subtitle cue: a start/end timestamp pair and its (sanitized) text, which may hold multiple newline-separated dialogue lines.

func Parse

func Parse(data []byte) ([]Cue, error)

Parse extracts cues from SRT or WebVTT input, sanitizing as it goes. Anchored on the timestamp line exactly like subtitles.py:parse(), so cue numbers, the WEBVTT header, cue identifiers and NOTE blocks are all ignored without needing to know which format this is — everything that isn't a recognized timestamp line plus following text is simply dropped.

Rejects: input over MaxBytes, invalid UTF-8, more than MaxCues cues, or input with no parsable cues at all.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL