diff --git a/src/components/player/display/base.ts b/src/components/player/display/base.ts index ad333358..7a9ce041 100644 --- a/src/components/player/display/base.ts +++ b/src/components/player/display/base.ts @@ -12,6 +12,7 @@ import { SourceQuality, getPreferredQuality, } from "@/stores/player/utils/qualities"; +import { processCdnLink } from "@/utils/cdn"; import { canChangeVolume, canFullscreen, @@ -101,7 +102,7 @@ export function makeVideoElementDisplayInterface(): DisplayInterface { function setupSource(vid: HTMLVideoElement, src: LoadableSource) { if (src.type === "hls") { if (canPlayHlsNatively(vid)) { - vid.src = src.url; + vid.src = processCdnLink(src.url); vid.currentTime = startAt; return; } @@ -151,12 +152,12 @@ export function makeVideoElementDisplayInterface(): DisplayInterface { } hls.attachMedia(vid); - hls.loadSource(src.url); + hls.loadSource(processCdnLink(src.url)); vid.currentTime = startAt; return; } - vid.src = src.url; + vid.src = processCdnLink(src.url); vid.currentTime = startAt; } diff --git a/src/components/player/display/chromecast.ts b/src/components/player/display/chromecast.ts index ecf59a3d..dbaab0df 100644 --- a/src/components/player/display/chromecast.ts +++ b/src/components/player/display/chromecast.ts @@ -8,6 +8,7 @@ import { DisplayMeta, } from "@/components/player/display/displayInterface"; import { LoadableSource } from "@/stores/player/utils/qualities"; +import { processCdnLink } from "@/utils/cdn"; import { canChangeVolume, canFullscreen, @@ -112,7 +113,7 @@ export function makeChromecastDisplayInterface( metaData.title = meta.title; const mediaInfo = new chrome.cast.media.MediaInfo("video", type); - (mediaInfo as any).contentUrl = source.url; + (mediaInfo as any).contentUrl = processCdnLink(source.url); mediaInfo.streamType = chrome.cast.media.StreamType.BUFFERED; mediaInfo.metadata = metaData; mediaInfo.customData = { diff --git a/src/components/player/internals/ThumbnailScraper.tsx b/src/components/player/internals/ThumbnailScraper.tsx index f238aca8..b0fc8474 100644 --- a/src/components/player/internals/ThumbnailScraper.tsx +++ b/src/components/player/internals/ThumbnailScraper.tsx @@ -5,6 +5,7 @@ import { playerStatus } from "@/stores/player/slices/source"; import { ThumbnailImage } from "@/stores/player/slices/thumbnails"; import { usePlayerStore } from "@/stores/player/store"; import { LoadableSource, selectQuality } from "@/stores/player/utils/qualities"; +import { processCdnLink } from "@/utils/cdn"; import { isSafari } from "@/utils/detectFeatures"; function makeQueue(layers: number): number[] { @@ -46,11 +47,11 @@ class ThumnbnailWorker { const canvas = document.createElement("canvas"); this.hls = new Hls(); if (source.type === "mp4") { - el.src = source.url; + el.src = processCdnLink(source.url); el.crossOrigin = "anonymous"; } else if (source.type === "hls") { this.hls.attachMedia(el); - this.hls.loadSource(source.url); + this.hls.loadSource(processCdnLink(source.url)); } else throw new Error("Invalid loadable source type"); this.videoEl = el; this.canvasEl = canvas; diff --git a/src/setup/config.ts b/src/setup/config.ts index 2f16714b..2e1634a4 100644 --- a/src/setup/config.ts +++ b/src/setup/config.ts @@ -18,6 +18,7 @@ interface Config { BACKEND_URL: string; DISALLOWED_IDS: string; TURNSTILE_KEY: string; + CDN_REPLACEMENTS: string; } export interface RuntimeConfig { @@ -32,6 +33,7 @@ export interface RuntimeConfig { BACKEND_URL: string; DISALLOWED_IDS: string[]; TURNSTILE_KEY: string | null; + CDN_REPLACEMENTS: Array; } const env: Record = { @@ -46,6 +48,7 @@ const env: Record = { BACKEND_URL: import.meta.env.VITE_BACKEND_URL, DISALLOWED_IDS: import.meta.env.VITE_DISALLOWED_IDS, TURNSTILE_KEY: import.meta.env.VITE_TURNSTILE_KEY, + CDN_REPLACEMENTS: import.meta.env.VITE_CDN_REPLACEMENTS, }; // loads from different locations, in order: environment (VITE_{KEY}), window (public/config.js) @@ -84,5 +87,14 @@ export function conf(): RuntimeConfig { .split(",") .map((v) => v.trim()) .filter((v) => v.length > 0), // Should be comma-seperated and contain the media type and ID, formatted like so: movie-753342,movie-753342,movie-753342 + CDN_REPLACEMENTS: getKey("CDN_REPLACEMENTS", "") + .split(",") + .map((v) => + v + .split(":") + .map((s) => s.trim()) + .filter((s) => s.length > 0), + ) + .filter((v) => v.length === 2), // The format is :,: }; } diff --git a/src/utils/cdn.ts b/src/utils/cdn.ts new file mode 100644 index 00000000..3a86336c --- /dev/null +++ b/src/utils/cdn.ts @@ -0,0 +1,16 @@ +import { conf } from "@/setup/config"; + +export function processCdnLink(url: string): string { + const parsedUrl = new URL(url); + const replacements = conf().CDN_REPLACEMENTS; + for (const [before, after] of replacements) { + if (parsedUrl.hostname.endsWith(before)) { + parsedUrl.hostname = after; + parsedUrl.port = ""; + parsedUrl.protocol = "https://"; + return parsedUrl.toString(); + } + } + + return url; +}