rebase document script out of videoInfo #1312

This commit is contained in:
Michael C
2022-07-29 01:34:53 -04:00
committed by Ajay
parent f66a4d25bf
commit c479a601cd
5 changed files with 139 additions and 10 deletions

View File

@@ -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",

View File

@@ -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
View 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)
}

View File

@@ -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

View File

@@ -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: {