aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/document.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/document.ts')
-rw-r--r--src/document.ts80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/document.ts b/src/document.ts
new file mode 100644
index 00000000..d537dd0e
--- /dev/null
+++ b/src/document.ts
@@ -0,0 +1,80 @@
+/*
+ Content script are run in an isolated DOM so it is not possible to access some key details that are sanitized when passed cross-dom
+ This script is used to get the details from the page and make them available for the content script by being injected directly into the page
+*/
+
+import { PageType } from "./types";
+
+interface StartMessage {
+ type: "navigation",
+ pageType: PageType
+ videoID: string | null,
+}
+
+interface FinishMessage extends StartMessage {
+ channelID: string,
+ channelTitle: string
+}
+
+interface AdMessage {
+ type: "ad",
+ playing: boolean
+}
+
+interface VideoData {
+ type: "data",
+ videoID: string,
+ isLive: boolean,
+ isPremiere: boolean
+}
+
+type WindowMessage = StartMessage | FinishMessage | AdMessage | VideoData;
+
+// global playerClient - too difficult to type
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+let playerClient: any;
+
+const sendMessage = (message: WindowMessage): void => {
+ window.postMessage({ source: "sponsorblock", ...message }, "/");
+}
+
+function setupPlayerClient(e: CustomEvent): void {
+ if (playerClient) return; // early exit if already defined
+
+ playerClient = e.detail;
+ sendVideoData(); // send playerData after setup
+
+ e.detail.addEventListener('onAdStart', () => sendMessage({ type: "ad", playing: true } as AdMessage));
+ e.detail.addEventListener('onAdFinish', () => sendMessage({ type: "ad", playing: false } as AdMessage));
+}
+
+document.addEventListener("yt-player-updated", setupPlayerClient);
+document.addEventListener("yt-navigate-start", navigationStartSend);
+document.addEventListener("yt-navigate-finish", navigateFinishSend);
+
+function navigationParser(event: CustomEvent): StartMessage {
+ const pageType: PageType = event.detail.pageType;
+ const result: StartMessage = { type: "navigation", pageType, videoID: null };
+ if (pageType === "shorts" || pageType === "watch") {
+ const endpoint = event.detail.endpoint
+ result.videoID = (pageType === "shorts" ? endpoint.reelWatchEndpoint : endpoint.watchEndpoint).videoId;
+ }
+
+ return result;
+}
+
+function navigationStartSend(event: CustomEvent): void {
+ sendMessage(navigationParser(event) as StartMessage);
+}
+
+function navigateFinishSend(event: CustomEvent): void {
+ sendVideoData(); // arrived at new video, send video data
+ const videoDetails = event.detail?.response?.playerResponse?.videoDetails;
+ sendMessage({ channelID: videoDetails.channelId, channelTitle: videoDetails.author, ...navigationParser(event) } as FinishMessage);
+}
+
+function sendVideoData(): void {
+ if (!playerClient) return;
+ const { video_id, isLive, isPremiere } = playerClient.getVideoData();
+ sendMessage({ type: "data", videoID: video_id, isLive, isPremiere } as VideoData);
+} \ No newline at end of file