diff --git a/src/backend/helpers/subs.ts b/src/backend/helpers/subs.ts index bd3d99f7..01bf4f7e 100644 --- a/src/backend/helpers/subs.ts +++ b/src/backend/helpers/subs.ts @@ -60,7 +60,6 @@ export async function downloadWebVTT(url: string): Promise { const cached = downloadCache.get(url); if (cached) return cached; - // Q: should this use proxiedFetch or sendExtensionRequest? const data = await fetch(url).then((v) => v.text()); return data; } diff --git a/src/components/player/display/base.ts b/src/components/player/display/base.ts index 4b3b8b9a..51e6d7bb 100644 --- a/src/components/player/display/base.ts +++ b/src/components/player/display/base.ts @@ -188,7 +188,6 @@ export function makeVideoElementDisplayInterface(): DisplayInterface { break; } } - console.log("Subtitle tracks loaded", hls?.subtitleTracks); }); } diff --git a/src/components/player/hooks/useCaptions.ts b/src/components/player/hooks/useCaptions.ts index 662108dd..e47ff788 100644 --- a/src/components/player/hooks/useCaptions.ts +++ b/src/components/player/hooks/useCaptions.ts @@ -3,9 +3,25 @@ import subsrt from "subsrt-ts"; import { ContentCaption } from "subsrt-ts/dist/types/handler"; import { downloadCaption, downloadWebVTT } from "@/backend/helpers/subs"; +import { Caption } from "@/stores/player/slices/source"; import { usePlayerStore } from "@/stores/player/store"; import { useSubtitleStore } from "@/stores/subtitles"; +import { parseVttSubtitles } from "../utils/captions"; + +const filterDuplicateCaptionCues = (cues: ContentCaption[]) => + cues.reduce((acc: ContentCaption[], cap: ContentCaption) => { + const lastCap = acc[acc.length - 1]; + const isSameAsLast = + lastCap?.start === cap.start && + lastCap?.end === cap.end && + lastCap?.content === cap.content; + if (lastCap === undefined || !isSameAsLast) { + acc.push(cap); + } + return acc; + }, []); + export function useCaptions() { const setLanguage = useSubtitleStore((s) => s.setLanguage); const enabled = useSubtitleStore((s) => s.enabled); @@ -33,16 +49,17 @@ export function useCaptions() { async (captionId: string) => { const caption = captions.find((v) => v.id === captionId); if (!caption) return; + + const captionToSet: Caption = { + id: caption.id, + language: caption.language, + url: caption.url, + srtData: "", + }; + if (!caption.hls) { const srtData = await downloadCaption(caption); - setCaption({ - id: caption.id, - language: caption.language, - srtData, - url: caption.url, - }); - resetSubtitleSpecificSettings(); - setLanguage(caption.language); + captionToSet.srtData = srtData; } else { // request a language change to hls, so it can load the subtitles await setSubtitlePreference?.(caption.language); @@ -60,42 +77,20 @@ export function useCaptions() { await Promise.all( fragments.map(async (frag) => { const vtt = await downloadWebVTT(frag.url); - const parsed = subsrt.parse(vtt); - return parsed.filter( - (c) => c.type === "caption", - ) as ContentCaption[]; + return parseVttSubtitles(vtt); }), ) ).flat(); - // for some reason, in some cases there will be captions - // with the same start/end times, the same text duplicated - const filtered = vttCaptions.reduce( - (acc: ContentCaption[], cap: ContentCaption) => { - const lastCap = acc[acc.length - 1]; - const isSameAsLast = - lastCap?.start === cap.start && - lastCap?.end === cap.end && - lastCap?.content === cap.content; - if (lastCap === undefined || !isSameAsLast) { - acc.push(cap); - } - return acc; - }, - [], - ); + const filtered = filterDuplicateCaptionCues(vttCaptions); const srtData = subsrt.build(filtered, { format: "srt" }); - - setCaption({ - id: caption.id, - language: caption.language, - srtData, - url: caption.url, - }); - resetSubtitleSpecificSettings(); - setLanguage(caption.language); + captionToSet.srtData = srtData; } + + setCaption(captionToSet); + resetSubtitleSpecificSettings(); + setLanguage(caption.language); }, [ setLanguage, diff --git a/src/components/player/utils/captions.ts b/src/components/player/utils/captions.ts index bc2079db..8f6a7d33 100644 --- a/src/components/player/utils/captions.ts +++ b/src/components/player/utils/captions.ts @@ -50,12 +50,16 @@ export function convertSubtitlesToSrt(text: string): string { return srt; } +export function parseVttSubtitles(vtt: string) { + return parse(vtt).filter((cue) => cue.type === "caption") as CaptionCueType[]; +} + export function parseSubtitles( text: string, _language?: string, ): CaptionCueType[] { const vtt = convertSubtitlesToVtt(text); - return parse(vtt).filter((cue) => cue.type === "caption") as CaptionCueType[]; + return parseVttSubtitles(vtt); } function stringToBase64(input: string): string {