Written by: Marlon Colca
Posted on 11 Sep 2025 - 23 days ago
nextjs typescript clones
Add support for .srt subtitles by converting them to WebVTT on the fly, so the native browser player can render captions without extra tooling.
.srt
subtitles by converting them to WebVTT on the fly, so the native browser player can render captions without extra tooling.src/lib/subtitles.ts
: helpers — isSrtUrl
, srtToVtt
, and processSubtitles
.src/hooks/useSubtitles.ts
: fetches .srt
, converts to VTT, and returns processed tracks.src/components/VideoPlayer.tsx
: uses useSubtitles()
and renders <track>
elements.// src/lib/subtitles.ts
export function srtToVtt(srt: string): string {
const text = srt.replace(/^\uFEFF/, "");
const blocks = text
.replace(/\r\n/g, "\n")
.replace(/\r/g, "\n")
.split(/\n\n+/);
const out: string[] = ["WEBVTT", ""];
for (const block of blocks) {
const lines = block.split("\n").filter((l) => l.trim() !== "");
if (!lines.length) continue;
let i = 0;
if (/^\d+$/.test(lines[0].trim())) i = 1; // optional index
if (!lines[i]) continue;
const time = lines[i]
.replace(/,/, ".")
.replace(/ --> .*?,/g, (m) => m.replace(",", "."));
const textLines = lines.slice(i + 1);
out.push(time, ...textLines, "");
}
return out.join("\n");
}
// src/hooks/useSubtitles.ts
export function useSubtitles(subtitles?: SubtitleTrack[]) {
const [processed, setProcessed] = useState<SubtitleTrack[] | undefined>();
useEffect(() => {
let cancelled = false;
let cleanup: (() => void) | undefined;
(async () => {
const { processed, revoke } = await processSubtitles(subtitles);
if (!cancelled) setProcessed(processed);
cleanup = revoke;
})();
return () => {
cancelled = true;
cleanup?.();
};
}, [subtitles]);
return processed ?? subtitles;
}
.vtt
during your build..srt
files need permissive CORS (Access-Control-Allow-Origin
). Local files under public/subs/
work out of the box..srt
files and they’ll “just work” without extra build steps.processSubtitles
creates Blob URLs for the converted VTT. The hook gives you a revoke
cleanup so those URLs are released when the component unmounts or tracks change./subs/TOS-en.srt
and enable the English track..srt
is fetched once, then the player uses an in‑memory Blob URL for the VTT.Persist and restore playback position, and reflect it in the catalog UI.
12 Sep 2025 - 22 days ago