diff --git a/apps/web/package.json b/apps/web/package.json index 5eb48de..2567f7d 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,7 +1,7 @@ { "name": "@typetype/web", "private": true, - "version": "1.5.0", + "version": "1.5.1", "type": "module", "scripts": { "dev": "vite", diff --git a/apps/web/src/components/subtitle-track-utils.ts b/apps/web/src/components/subtitle-track-utils.ts index a62c0c2..b1875ec 100644 --- a/apps/web/src/components/subtitle-track-utils.ts +++ b/apps/web/src/components/subtitle-track-utils.ts @@ -46,7 +46,7 @@ export function buildSafeSubtitleTracks( let src = ""; try { - src = toSubtitleVttUrl(rawUrl, normalizeText(item.languageTag), item.isAutoGenerated); + src = toSubtitleVttUrl(rawUrl); } catch { continue; } diff --git a/apps/web/src/lib/proxy.ts b/apps/web/src/lib/proxy.ts index a86d620..62a481a 100644 --- a/apps/web/src/lib/proxy.ts +++ b/apps/web/src/lib/proxy.ts @@ -54,40 +54,12 @@ export function proxyImage(url: string): string { return proxyUrl(normalized); } -export function toSubtitleVttUrl( - url: string, - languageTag: string, - isAutoGenerated: boolean, -): string { +export function toSubtitleVttUrl(url: string): string { const parsed = new URL(url); const youtubeTimedText = (parsed.hostname === "youtube.com" || parsed.hostname.endsWith(".youtube.com")) && parsed.pathname === "/api/timedtext"; - if (youtubeTimedText) return youtubeSubtitleUrl(parsed, languageTag, isAutoGenerated); parsed.searchParams.set("fmt", "vtt"); + if (youtubeTimedText) return parsed.toString(); return proxyUrl(parsed.toString()); } - -function youtubeSubtitleUrl(timedText: URL, languageTag: string, isAutoGenerated: boolean): string { - const videoId = timedText.searchParams.get("v")?.trim() ?? ""; - const sourceLanguage = timedText.searchParams.get("lang")?.trim() ?? ""; - const translation = timedText.searchParams.get("tlang")?.trim() ?? ""; - const language = languageTag.trim() || translation || sourceLanguage; - if (!/^[A-Za-z0-9_-]{11}$/.test(videoId) || !language) { - throw new Error("Invalid YouTube subtitle track"); - } - const auto = - isAutoGenerated || - timedText.searchParams.get("kind") === "asr" || - timedText.searchParams.get("vssId")?.startsWith("a.") === true; - const params = new URLSearchParams({ - language, - variant: auto ? "auto" : "manual", - format: "vtt", - }); - if (sourceLanguage) params.set("sourceLanguage", sourceLanguage); - if (translation) params.set("translation", translation); - const name = timedText.searchParams.get("name")?.trim(); - if (name) params.set("name", name); - return `${absoluteBase()}/subtitles/youtube/${encodeURIComponent(videoId)}?${params}`; -} diff --git a/apps/web/tests/subtitle-track-utils.test.ts b/apps/web/tests/subtitle-track-utils.test.ts index 333faba..25a6012 100644 --- a/apps/web/tests/subtitle-track-utils.test.ts +++ b/apps/web/tests/subtitle-track-utils.test.ts @@ -22,14 +22,10 @@ test("uses caption variants instead of numeric duplicate language labels", () => ]); expect(tracks.map((track) => track.label)).toEqual(["English (CC1)", "English (DTVCC1)"]); - expect(tracks.every((track) => new URL(track.src).searchParams.get("format") === "vtt")).toBe( - true, - ); - expect(tracks.every((track) => new URL(track.src).hostname === "typetype.test")).toBe(true); - expect( - tracks.every((track) => new URL(track.src).pathname === "/api/subtitles/youtube/abcdefghijk"), - ).toBe(true); - expect(tracks.every((track) => !track.src.includes("secret"))).toBe(true); + expect(tracks.every((track) => new URL(track.src).searchParams.get("fmt") === "vtt")).toBe(true); + expect(tracks.every((track) => new URL(track.src).hostname === "www.youtube.com")).toBe(true); + expect(tracks.every((track) => new URL(track.src).pathname === "/api/timedtext")).toBe(true); + expect(tracks.every((track) => track.src.includes("sig=secret"))).toBe(true); }); test("preserves generated and translated YouTube subtitle selection", () => { @@ -44,10 +40,11 @@ test("preserves generated and translated YouTube subtitle selection", () => { ]); const src = new URL(track?.src ?? ""); - expect(src.searchParams.get("language")).toBe("fr"); - expect(src.searchParams.get("sourceLanguage")).toBe("en"); - expect(src.searchParams.get("translation")).toBe("fr"); - expect(src.searchParams.get("variant")).toBe("auto"); + expect(src.hostname).toBe("m.youtube.com"); + expect(src.searchParams.get("fmt")).toBe("vtt"); + expect(src.searchParams.get("lang")).toBe("en"); + expect(src.searchParams.get("kind")).toBe("asr"); + expect(src.searchParams.get("tlang")).toBe("fr"); }); test("keeps non YouTube subtitle tracks on the generic proxy", () => { diff --git a/package.json b/package.json index 55e98d2..7055b25 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@typetype/frontend", - "version": "1.5.0", + "version": "1.5.1", "devDependencies": { "@biomejs/biome": "^2.5.7", "knip": "^6.32.0",