Parsing SRT subtitles in the browser: the 30-line converter that makes every WebVTT player happy
Parsing SRT subtitles in the browser: the 30-line converter that makes every WebVTT player happy Disclosure: I'm building RKMovies — an ultra-lightweight 4K media player client (0.91 MB APK, hardware-accelerated decodi
Parsing SRT subtitles in the browser: the 30-line converter that makes every WebVTT player happy
Disclosure: I'm building RKMovies — an ultra-lightweight 4K media player client (0.91 MB APK, hardware-accelerated decoding, zero telemetry). Site: https://rkmovies.dpdns.org · Android APK: https://rkmovies.dpdns.org/apk · Windows app: https://rkmovies.dpdns.org/desktop
Every video player on Android that is worth using speaks WebVTT. Almost every subtitle file floating around the internet is SRT. They look identical at a glance, but the parsers do not forgive the differences.
The gap is small and annoying:
- SRT uses a comma in timestamps (
00:00:01,500), WebVTT demands a dot (00:00:01.500) - SRT cues start with an optional numeric index line, WebVTT does not have one
- SRT files often ship with a BOM and CRLF line endings
So instead of pulling in a subtitle library (remember: the whole APK is 0.91 MB, every dependency is a size audit), I wrote a tiny converter that runs in the browser when a local subtitle file is loaded:
async function fileToVtt(file) {
let t = await file.text();
t = t.replace(/\r/g, "").replace(/^/, "");
if (/^\s*WEBVTT/.test(t)) return t;
const out = [];
for (const b of t.split(/\n{2,}/)) {
const lines = b.split("\n").filter(l => l.trim() !== "");
if (/^\d+$/.test(lines[0]?.trim())) lines.shift();
const tl = lines.shift();
if (!tl || tl.indexOf("-->") < 0) continue;
out.push(tl.replace(/,/g, ".") + "\n" + lines.join("\n"));
}
return out.length ? "WEBVTT\n\n" + out.join("\n\n") + "\n" : "";
}
The whole thing is ~20 lines. It reuses the same cleanup pass we already run for inline captions (stripping tags like <i> and positioning junk), then hands the result to the player as a Blob URL. From the user's side: pick an .srt file, it just works.
Two edge cases that actually bit me in testing:
- Some SRT files use LF only, some CRLF, some have a BOM. Normalizing all three up front saves a "why are my subtitles empty" bug report.
- Multi-line cues must stay multi-line. If you flatten them, dialogue and sound effects merge into one unreadable line.
If you are shipping a small player and want subtitles without a dependency, this is the whole trick. WebVTT is forgiving once the commas become dots.
RKMovies runs this on Android (0.91 MB APK with hardware decoding and multi-audio support: https://rkmovies.dpdns.org/apk) and on Windows (https://rkmovies.dpdns.org/desktop). No account, no telemetry.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.