mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-08 20:47:11 +03:00
rebase document script out of videoInfo #1312
This commit is contained in:
@@ -69,7 +69,8 @@
|
|||||||
"icons/PlayerInfoIconSponsorBlocker.svg",
|
"icons/PlayerInfoIconSponsorBlocker.svg",
|
||||||
"icons/PlayerDeleteIconSponsorBlocker.svg",
|
"icons/PlayerDeleteIconSponsorBlocker.svg",
|
||||||
"popup.html",
|
"popup.html",
|
||||||
"content.css"
|
"content.css",
|
||||||
|
"js/document.js"
|
||||||
],
|
],
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"storage",
|
"storage",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
ToggleSkippable,
|
ToggleSkippable,
|
||||||
VideoID,
|
VideoID,
|
||||||
VideoInfo,
|
VideoInfo,
|
||||||
|
PageType
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import Utils from "./utils";
|
import Utils from "./utils";
|
||||||
import PreviewBar, { PreviewBarSegment } from "./js-components/previewBar";
|
import PreviewBar, { PreviewBarSegment } from "./js-components/previewBar";
|
||||||
@@ -55,6 +56,10 @@ let activeSkipKeybindElement: ToggleSkippable = null;
|
|||||||
|
|
||||||
// JSON video info
|
// JSON video info
|
||||||
let videoInfo: VideoInfo = null;
|
let videoInfo: VideoInfo = null;
|
||||||
|
// Page Type - browse/watch etc...
|
||||||
|
let pageType: PageType;
|
||||||
|
// if video is live or premiere
|
||||||
|
let isLivePremiere: boolean
|
||||||
// The channel this video is about
|
// The channel this video is about
|
||||||
let channelIDInfo: ChannelIDInfo;
|
let channelIDInfo: ChannelIDInfo;
|
||||||
// Locked Categories in this tab, like: ["sponsor","intro","outro"]
|
// Locked Categories in this tab, like: ["sponsor","intro","outro"]
|
||||||
@@ -90,7 +95,7 @@ let onInvidious: boolean;
|
|||||||
let onMobileYouTube: boolean;
|
let onMobileYouTube: boolean;
|
||||||
|
|
||||||
//the video id of the last preview bar update
|
//the video id of the last preview bar update
|
||||||
let lastPreviewBarUpdate;
|
let lastPreviewBarUpdate: VideoID;
|
||||||
|
|
||||||
// Is the video currently being switched
|
// Is the video currently being switched
|
||||||
let switchingVideos = null;
|
let switchingVideos = null;
|
||||||
@@ -334,6 +339,7 @@ function resetValues() {
|
|||||||
sponsorSkipped = [];
|
sponsorSkipped = [];
|
||||||
|
|
||||||
videoInfo = null;
|
videoInfo = null;
|
||||||
|
pageType = null;
|
||||||
channelWhitelisted = false;
|
channelWhitelisted = false;
|
||||||
channelIDInfo = {
|
channelIDInfo = {
|
||||||
status: ChannelIDStatus.Fetching,
|
status: ChannelIDStatus.Fetching,
|
||||||
@@ -1157,6 +1163,8 @@ function startSkipScheduleCheckingForStartSponsors() {
|
|||||||
|
|
||||||
function getYouTubeVideoID(document: Document, url?: string): string | boolean {
|
function getYouTubeVideoID(document: Document, url?: string): string | boolean {
|
||||||
url ||= document.URL;
|
url ||= document.URL;
|
||||||
|
// pageType shortcut
|
||||||
|
if (pageType === PageType.Channel) return getYouTubeVideoIDFromDocument()
|
||||||
// clips should never skip, going from clip to full video has no indications.
|
// clips should never skip, going from clip to full video has no indications.
|
||||||
if (url.includes("youtube.com/clip/")) return false;
|
if (url.includes("youtube.com/clip/")) return false;
|
||||||
// skip to document and don't hide if on /embed/
|
// skip to document and don't hide if on /embed/
|
||||||
@@ -1164,17 +1172,19 @@ function getYouTubeVideoID(document: Document, url?: string): string | boolean {
|
|||||||
// skip to URL if matches youtube watch or invidious or matches youtube pattern
|
// skip to URL if matches youtube watch or invidious or matches youtube pattern
|
||||||
if ((!url.includes("youtube.com")) || url.includes("/watch") || url.includes("/shorts/") || url.includes("playlist")) return getYouTubeVideoIDFromURL(url);
|
if ((!url.includes("youtube.com")) || url.includes("/watch") || url.includes("/shorts/") || url.includes("playlist")) return getYouTubeVideoIDFromURL(url);
|
||||||
// skip to document if matches pattern
|
// skip to document if matches pattern
|
||||||
if (url.includes("/channel/") || url.includes("/user/") || url.includes("/c/")) return getYouTubeVideoIDFromDocument();
|
if (url.includes("/channel/") || url.includes("/user/") || url.includes("/c/")) return getYouTubeVideoIDFromDocument(true, PageType.Channel);
|
||||||
// not sure, try URL then document
|
// not sure, try URL then document
|
||||||
return getYouTubeVideoIDFromURL(url) || getYouTubeVideoIDFromDocument(false);
|
return getYouTubeVideoIDFromURL(url) || getYouTubeVideoIDFromDocument(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getYouTubeVideoIDFromDocument(hideIcon = true): string | boolean {
|
function getYouTubeVideoIDFromDocument(hideIcon = true, pageHint = PageType.Watch): string | boolean {
|
||||||
// get ID from document (channel trailer / embedded playlist)
|
// get ID from document (channel trailer / embedded playlist)
|
||||||
const element = video?.parentElement?.parentElement?.querySelector("a.ytp-title-link[data-sessionlink='feature=player-title']");
|
const element = video?.parentElement?.parentElement?.querySelector("a.ytp-title-link[data-sessionlink='feature=player-title']");
|
||||||
const videoURL = element?.getAttribute("href");
|
const videoURL = element?.getAttribute("href");
|
||||||
if (videoURL) {
|
if (videoURL) {
|
||||||
onInvidious = hideIcon;
|
onInvidious = hideIcon;
|
||||||
|
// if href found, hint was correct
|
||||||
|
pageType = pageHint;
|
||||||
return getYouTubeVideoIDFromURL(videoURL);
|
return getYouTubeVideoIDFromURL(videoURL);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@@ -1731,7 +1741,7 @@ function updateEditButtonsOnPlayer(): void {
|
|||||||
// Don't try to update the buttons if we aren't on a YouTube video page
|
// Don't try to update the buttons if we aren't on a YouTube video page
|
||||||
if (!sponsorVideoID || onMobileYouTube) return;
|
if (!sponsorVideoID || onMobileYouTube) return;
|
||||||
|
|
||||||
const buttonsEnabled = !Config.config.hideVideoPlayerControls && !onInvidious;
|
const buttonsEnabled = !(Config.config.hideVideoPlayerControls || onInvidious);
|
||||||
|
|
||||||
let creatingSegment = false;
|
let creatingSegment = false;
|
||||||
let submitButtonVisible = false;
|
let submitButtonVisible = false;
|
||||||
@@ -2069,7 +2079,7 @@ function submitSponsorTimes() {
|
|||||||
//called after all the checks have been made that it's okay to do so
|
//called after all the checks have been made that it's okay to do so
|
||||||
async function sendSubmitMessage() {
|
async function sendSubmitMessage() {
|
||||||
// Block if submitting on a running livestream or premiere
|
// Block if submitting on a running livestream or premiere
|
||||||
if (isVisible(document.querySelector(".ytp-live-badge"))) {
|
if (isLivePremiere || isVisible(document.querySelector(".ytp-live-badge"))) {
|
||||||
alert(chrome.i18n.getMessage("liveOrPremiere"));
|
alert(chrome.i18n.getMessage("liveOrPremiere"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2182,6 +2192,33 @@ function getSegmentsMessage(sponsorTimes: SponsorTime[]): string {
|
|||||||
return sponsorTimesMessage;
|
return sponsorTimesMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function windowListenerHandler(event: MessageEvent): void {
|
||||||
|
const data = event.data;
|
||||||
|
const dataType = data.type
|
||||||
|
if (data.source !== "sponsorblock") return;
|
||||||
|
if (dataType === "navigation") {
|
||||||
|
sponsorVideoID = data.videoID;
|
||||||
|
pageType = data.pageType
|
||||||
|
/* for use with category-specific
|
||||||
|
channelIDInfo = {
|
||||||
|
id: data.channelID,
|
||||||
|
name: data.channelTitle,
|
||||||
|
status: 1
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
} else if (dataType === "ad") {
|
||||||
|
// update isAdPlaying
|
||||||
|
if(isAdPlaying != data.playing) {
|
||||||
|
isAdPlaying = data.playing
|
||||||
|
updatePreviewBar();
|
||||||
|
updateVisibilityOfPlayerControlsButton();
|
||||||
|
}
|
||||||
|
} else if (dataType === "data") {
|
||||||
|
sponsorVideoID = data.videoID;
|
||||||
|
isLivePremiere = data.isLive || data.isPremiere
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateActiveSegment(currentTime: number): void {
|
function updateActiveSegment(currentTime: number): void {
|
||||||
previewBar?.updateChapterText(sponsorTimes, sponsorTimesSubmitting, currentTime);
|
previewBar?.updateChapterText(sponsorTimes, sponsorTimesSubmitting, currentTime);
|
||||||
chrome.runtime.sendMessage({
|
chrome.runtime.sendMessage({
|
||||||
@@ -2226,8 +2263,13 @@ function addPageListeners(): void {
|
|||||||
refreshVideoAttachments();
|
refreshVideoAttachments();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// inject into document
|
||||||
|
const docScript = document.createElement("script");
|
||||||
|
docScript.src = chrome.runtime.getURL("js/document.js");
|
||||||
|
(document.head || document.documentElement).appendChild(docScript);
|
||||||
|
document.addEventListener("yt-navigate-start", resetValues);
|
||||||
document.addEventListener("yt-navigate-finish", refreshListners);
|
document.addEventListener("yt-navigate-finish", refreshListners);
|
||||||
|
window.addEventListener("message", windowListenerHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
function addHotkeyListener(): void {
|
function addHotkeyListener(): void {
|
||||||
|
|||||||
77
src/document.ts
Normal file
77
src/document.ts
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
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)
|
||||||
|
}
|
||||||
@@ -239,6 +239,14 @@ export type Keybind = {
|
|||||||
shift?: boolean
|
shift?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum PageType {
|
||||||
|
Shorts = "shorts",
|
||||||
|
Watch = "watch",
|
||||||
|
Search = "search",
|
||||||
|
Browse = "browse",
|
||||||
|
Channel = "channel"
|
||||||
|
}
|
||||||
|
|
||||||
export interface ButtonListener {
|
export interface ButtonListener {
|
||||||
name: string,
|
name: string,
|
||||||
listener: (e?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void
|
listener: (e?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ module.exports = env => ({
|
|||||||
options: path.join(__dirname, srcDir + 'options.ts'),
|
options: path.join(__dirname, srcDir + 'options.ts'),
|
||||||
help: path.join(__dirname, srcDir + 'help.ts'),
|
help: path.join(__dirname, srcDir + 'help.ts'),
|
||||||
permissions: path.join(__dirname, srcDir + 'permissions.ts'),
|
permissions: path.join(__dirname, srcDir + 'permissions.ts'),
|
||||||
|
document: path.join(__dirname, srcDir + 'document.ts'),
|
||||||
upsell: path.join(__dirname, srcDir + 'upsell.ts')
|
upsell: path.join(__dirname, srcDir + 'upsell.ts')
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
|
|||||||
Reference in New Issue
Block a user