diff --git a/app/features/vods/vods-utils.test.ts b/app/features/vods/vods-utils.test.ts index 331f47e0a..9444e9612 100644 --- a/app/features/vods/vods-utils.test.ts +++ b/app/features/vods/vods-utils.test.ts @@ -33,6 +33,30 @@ describe("extractYoutubeIdFromVideoUrl", () => { expect(result).toBe("dQw4w9WgXcQ"); }); + it("should strip share tracking params from a shortened YouTube URL", () => { + const url = "https://youtu.be/fuj_pSAbU-A?si=mAzDxgrIJWLO1ykq"; + const result = extractYoutubeIdFromVideoUrl(url); + expect(result).toBe("fuj_pSAbU-A"); + }); + + it("should strip extra query params from a standard YouTube URL", () => { + const url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=120"; + const result = extractYoutubeIdFromVideoUrl(url); + expect(result).toBe("dQw4w9WgXcQ"); + }); + + it("should strip query params from a YouTube live URL", () => { + const url = "https://www.youtube.com/live/dQw4w9WgXcQ?feature=shared"; + const result = extractYoutubeIdFromVideoUrl(url); + expect(result).toBe("dQw4w9WgXcQ"); + }); + + it("should strip url fragments", () => { + const url = "https://youtu.be/dQw4w9WgXcQ#t=1m"; + const result = extractYoutubeIdFromVideoUrl(url); + expect(result).toBe("dQw4w9WgXcQ"); + }); + it("should return null for an invalid YouTube URL", () => { const url = "https://www.example.com/watch?v=dQw4w9WgXcQ"; const result = extractYoutubeIdFromVideoUrl(url); diff --git a/app/features/vods/vods-utils.ts b/app/features/vods/vods-utils.ts index 89d703cff..ef4c92130 100644 --- a/app/features/vods/vods-utils.ts +++ b/app/features/vods/vods-utils.ts @@ -52,7 +52,7 @@ export function canEditVideo({ export function extractYoutubeIdFromVideoUrl(url: string): string | null { const match = url.match( - /^(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/(?:watch\?v=|live\/)|youtu\.be\/)([^&/?]+)/, + /^(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/(?:watch\?v=|live\/)|youtu\.be\/)([^&/?#]+)/, ); return match ? match[1] : null; } diff --git a/db-test.sqlite3 b/db-test.sqlite3 index ce12bdc14..4573e552c 100644 Binary files a/db-test.sqlite3 and b/db-test.sqlite3 differ diff --git a/e2e/seeds/db-seed-AB_RR.sqlite3 b/e2e/seeds/db-seed-AB_RR.sqlite3 index c03b456be..6bd543bd4 100644 Binary files a/e2e/seeds/db-seed-AB_RR.sqlite3 and b/e2e/seeds/db-seed-AB_RR.sqlite3 differ diff --git a/e2e/seeds/db-seed-DEFAULT.sqlite3 b/e2e/seeds/db-seed-DEFAULT.sqlite3 index e47ae2a97..55e16f05e 100644 Binary files a/e2e/seeds/db-seed-DEFAULT.sqlite3 and b/e2e/seeds/db-seed-DEFAULT.sqlite3 differ diff --git a/e2e/seeds/db-seed-FINALIZED_BRACKET.sqlite3 b/e2e/seeds/db-seed-FINALIZED_BRACKET.sqlite3 index 8f2c1bf53..814dad20e 100644 Binary files a/e2e/seeds/db-seed-FINALIZED_BRACKET.sqlite3 and b/e2e/seeds/db-seed-FINALIZED_BRACKET.sqlite3 differ diff --git a/e2e/seeds/db-seed-IN_SQ_MATCH.sqlite3 b/e2e/seeds/db-seed-IN_SQ_MATCH.sqlite3 index f4bb46184..a66d65483 100644 Binary files a/e2e/seeds/db-seed-IN_SQ_MATCH.sqlite3 and b/e2e/seeds/db-seed-IN_SQ_MATCH.sqlite3 differ diff --git a/e2e/seeds/db-seed-NO_SCRIMS.sqlite3 b/e2e/seeds/db-seed-NO_SCRIMS.sqlite3 index 6fc36a79a..ef7163f9c 100644 Binary files a/e2e/seeds/db-seed-NO_SCRIMS.sqlite3 and b/e2e/seeds/db-seed-NO_SCRIMS.sqlite3 differ diff --git a/e2e/seeds/db-seed-NO_SQ_GROUPS.sqlite3 b/e2e/seeds/db-seed-NO_SQ_GROUPS.sqlite3 index 693119837..9e5464916 100644 Binary files a/e2e/seeds/db-seed-NO_SQ_GROUPS.sqlite3 and b/e2e/seeds/db-seed-NO_SQ_GROUPS.sqlite3 differ diff --git a/e2e/seeds/db-seed-NO_TOURNAMENT_TEAMS.sqlite3 b/e2e/seeds/db-seed-NO_TOURNAMENT_TEAMS.sqlite3 index 22f3bea22..4ec3dcf64 100644 Binary files a/e2e/seeds/db-seed-NO_TOURNAMENT_TEAMS.sqlite3 and b/e2e/seeds/db-seed-NO_TOURNAMENT_TEAMS.sqlite3 differ diff --git a/e2e/seeds/db-seed-NZAP_IN_TEAM.sqlite3 b/e2e/seeds/db-seed-NZAP_IN_TEAM.sqlite3 index a0d3cc1cc..83dac6759 100644 Binary files a/e2e/seeds/db-seed-NZAP_IN_TEAM.sqlite3 and b/e2e/seeds/db-seed-NZAP_IN_TEAM.sqlite3 differ diff --git a/e2e/seeds/db-seed-REG_OPEN.sqlite3 b/e2e/seeds/db-seed-REG_OPEN.sqlite3 index 865d10cd3..e970b22b2 100644 Binary files a/e2e/seeds/db-seed-REG_OPEN.sqlite3 and b/e2e/seeds/db-seed-REG_OPEN.sqlite3 differ diff --git a/e2e/seeds/db-seed-SMALL_SOS.sqlite3 b/e2e/seeds/db-seed-SMALL_SOS.sqlite3 index 581636555..9329d8bc5 100644 Binary files a/e2e/seeds/db-seed-SMALL_SOS.sqlite3 and b/e2e/seeds/db-seed-SMALL_SOS.sqlite3 differ diff --git a/e2e/seeds/db-seed-TEAM_MAP_PREFS.sqlite3 b/e2e/seeds/db-seed-TEAM_MAP_PREFS.sqlite3 index 00470291f..2fe1806c2 100644 Binary files a/e2e/seeds/db-seed-TEAM_MAP_PREFS.sqlite3 and b/e2e/seeds/db-seed-TEAM_MAP_PREFS.sqlite3 differ diff --git a/migrations/160-strip-youtube-id-url-params.js b/migrations/160-strip-youtube-id-url-params.js new file mode 100644 index 000000000..c8169b5d3 --- /dev/null +++ b/migrations/160-strip-youtube-id-url-params.js @@ -0,0 +1,13 @@ +export function up(db) { + db.transaction(() => { + for (const delimiter of ["?", "&", "#"]) { + db.prepare( + /* sql */ ` + update "UnvalidatedVideo" + set "youtubeId" = substr("youtubeId", 1, instr("youtubeId", ?) - 1) + where instr("youtubeId", ?) > 0 + `, + ).run(delimiter, delimiter); + } + })(); +}