import { test } from "node:test"; import assert from "node:assert/strict"; import { momentUrl, viewerMomentUrl, platformMomentUrl, momentBaseUrl, viewerMomentBaseUrl, platformMomentBaseUrl, viewerPostUrl, } from "yt-dlp-transcript-common/lib/momentUrl"; // ─── Archilyzer viewer link (preferred) ─── test("viewer link: origin + slug + seconds → ?v=&t=", () => { const url = viewerMomentUrl( "https://rekietalyzer.pages.dev", "rekietalaw/0eYLR6CbR78", 754, ); assert.ok(url); const u = new URL(url!); assert.equal(u.origin, "https://rekietalyzer.pages.dev"); assert.equal(u.pathname, "/"); // The slug round-trips through URL decoding to exactly the modal's ?v= value. assert.equal(u.searchParams.get("v"), "rekietalaw/0eYLR6CbR78"); assert.equal(u.searchParams.get("t"), "754"); }); test("viewer link: an origin with its own path/query is normalized to /", () => { const url = viewerMomentUrl("https://site.example/search?q=x", "ch/vid", 10); const u = new URL(url!); assert.equal(u.pathname, "/"); assert.equal(u.searchParams.get("q"), null); assert.equal(u.searchParams.get("v"), "ch/vid"); }); test("viewer link: t is omitted at second 0", () => { const url = viewerMomentUrl("https://site.example", "ch/vid", 0); const u = new URL(url!); assert.equal(u.searchParams.get("t"), null); assert.equal(u.searchParams.get("v"), "ch/vid"); }); test("viewer link: null without an origin or a slug", () => { assert.equal(viewerMomentUrl(null, "ch/vid", 10), null); assert.equal(viewerMomentUrl("https://site.example", null, 10), null); }); // ─── Platform fallback ─── test("platform link: YouTube gets &t=s appended", () => { const url = platformMomentUrl( "https://www.youtube.com/watch?v=abc123", "youtube", 90, ); const u = new URL(url!); assert.equal(u.searchParams.get("v"), "abc123"); assert.equal(u.searchParams.get("t"), "90s"); }); test("platform link: platform is detected from the URL when not given", () => { const url = platformMomentUrl("https://www.youtube.com/watch?v=abc123", null, 5); assert.match(url!, /t=5s/); }); test("platform link: Odysee gets ?t= (raw seconds)", () => { const url = platformMomentUrl( "https://odysee.com/@chan/video", "odysee", 42, ); const u = new URL(url!); assert.equal(u.searchParams.get("t"), "42"); }); test("platform link: Twitch gets ?t=", () => { const url = platformMomentUrl( "https://www.twitch.tv/videos/12345", "twitch", 3661, ); const u = new URL(url!); assert.equal(u.searchParams.get("t"), "1h1m1s"); }); test("platform link: Rumble has no reliable start param → bare webpage url", () => { const url = platformMomentUrl("https://rumble.com/v123-title.html", "rumble", 60); assert.equal(url, "https://rumble.com/v123-title.html"); }); test("platform link: second 0 → bare webpage url; no webpage url → null", () => { assert.equal( platformMomentUrl("https://www.youtube.com/watch?v=abc", "youtube", 0), "https://www.youtube.com/watch?v=abc", ); assert.equal(platformMomentUrl(null, "youtube", 30), null); }); // ─── momentUrl: prefers the viewer link, falls back to the platform link ─── test("momentUrl: viewer link wins when an origin is present", () => { const url = momentUrl({ siteOrigin: "https://site.example", slug: "ch/vid", seconds: 12, webpageUrl: "https://www.youtube.com/watch?v=vid", platform: "youtube", }); const u = new URL(url!); assert.equal(u.origin, "https://site.example"); assert.equal(u.searchParams.get("v"), "ch/vid"); }); test("momentUrl: falls back to the platform link with no origin (local source)", () => { const url = momentUrl({ siteOrigin: null, slug: "ch/vid", seconds: 12, webpageUrl: "https://www.youtube.com/watch?v=vid", platform: "youtube", }); assert.match(url!, /youtube\.com/); assert.match(url!, /t=12s/); }); test("momentUrl: null when neither a viewer nor a platform link can be built", () => { const url = momentUrl({ siteOrigin: null, slug: "ch/vid", seconds: 12 }); assert.equal(url, null); }); // ─── Base (appendable) forms — the link_style:"base" building blocks ─── test("viewer base: ends in t= with the slug encoded; appending seconds parses", () => { const base = viewerMomentBaseUrl( "https://rekietalyzer.pages.dev", "rekietalaw/uamorPe6hSc", ); assert.ok(base); assert.ok(base!.endsWith("&t="), "the base ends in t= so seconds append cleanly"); assert.ok( base!.includes("v=rekietalaw%2FuamorPe6hSc"), "the slug's / is %2F-encoded by URLSearchParams", ); // Appending integer seconds yields exactly the viewer deep-link params. const u = new URL(base! + "754"); assert.equal(u.searchParams.get("v"), "rekietalaw/uamorPe6hSc"); assert.equal(u.searchParams.get("t"), "754"); }); test("viewer base: null without an origin/slug or with an unparseable origin", () => { assert.equal(viewerMomentBaseUrl(null, "ch/vid"), null); assert.equal(viewerMomentBaseUrl("https://site.example", null), null); assert.equal(viewerMomentBaseUrl("not a url", "ch/vid"), null); }); test("platform base: YouTube ends in t= (existing query → &t=, none → ?t=)", () => { const withQuery = platformMomentBaseUrl( "https://www.youtube.com/watch?v=abc123", "youtube", ); assert.ok(withQuery!.endsWith("&t=")); const noQuery = platformMomentBaseUrl("https://youtu.be/abc123", "youtube"); assert.ok(noQuery!.endsWith("?t=")); }); test("platform base: a pre-existing t param is stripped and re-appended LAST", () => { const base = platformMomentBaseUrl( "https://www.youtube.com/watch?t=99s&v=abc", "youtube", ); assert.ok(base!.endsWith("&t="), "t= is the last param"); assert.ok(!base!.includes("99s"), "the old seek value is gone"); const u = new URL(base! + "42"); assert.equal(u.searchParams.get("v"), "abc"); assert.equal(u.searchParams.get("t"), "42"); }); test("platform base: Odysee ends in t= (raw-seconds param)", () => { const base = platformMomentBaseUrl("https://odysee.com/@chan/video", "odysee"); assert.ok(base!.endsWith("?t=")); }); test("platform base: non-appendable cases → null (never an invalid seek)", () => { // Twitch's t takes an XhYmZs token — appending raw seconds would mis-seek. assert.equal( platformMomentBaseUrl("https://www.twitch.tv/videos/12345", "twitch"), null, ); // Rumble has no dependable start param at all. assert.equal( platformMomentBaseUrl("https://rumble.com/v123-title.html", "rumble"), null, ); assert.equal(platformMomentBaseUrl(null, "youtube"), null); assert.equal(platformMomentBaseUrl("not a url", "youtube"), null); }); test("momentBaseUrl: viewer base wins, platform fallback, else null", () => { const viewer = momentBaseUrl({ siteOrigin: "https://site.example", slug: "ch/vid", webpageUrl: "https://www.youtube.com/watch?v=vid", platform: "youtube", }); assert.ok(viewer!.startsWith("https://site.example/?v=")); assert.ok(viewer!.endsWith("&t=")); const platform = momentBaseUrl({ siteOrigin: null, slug: "ch/vid", webpageUrl: "https://www.youtube.com/watch?v=vid", platform: "youtube", }); assert.ok(platform!.startsWith("https://www.youtube.com/watch?v=vid")); assert.ok(platform!.endsWith("&t=")); assert.equal(momentBaseUrl({ siteOrigin: null, slug: "ch/vid" }), null); }); // ─── An archived post's page ─── test("viewerPostUrl: origin + post slug → ?v=%2F&vm=post", () => { assert.equal( viewerPostUrl("https://jasolyzer.pages.dev", "piratesoftware-bsky/3l6uxj6esfr2z"), "https://jasolyzer.pages.dev/?v=piratesoftware-bsky%2F3l6uxj6esfr2z&vm=post", ); // An origin with its own path is normalized to the viewer's root. assert.equal( viewerPostUrl("https://site.example/search?q=x", "ch-x/123"), "https://site.example/?v=ch-x%2F123&vm=post", ); }); test("viewerPostUrl: no origin, no slug, or a bad origin → null", () => { assert.equal(viewerPostUrl(null, "a/b"), null); assert.equal(viewerPostUrl("https://x.example", ""), null); assert.equal(viewerPostUrl("not a url", "a/b"), null); });