From 615b9bce7cb681ae7786f1e3a5a74c9031bd8e7d Mon Sep 17 00:00:00 2001 From: adsuth Date: Wed, 13 Mar 2024 20:35:14 +0000 Subject: [PATCH 1/4] Fixes injection issues with previous shorts --- src/lib/ActionElement.ts | 10 ++-- src/lib/Events.ts | 4 +- src/lib/Info.ts | 45 ++++++++------ src/lib/InjectionSuccess.ts | 115 +++++++++++++++++------------------- src/lib/ProgressBar.ts | 9 ++- src/lib/VolumeSlider.ts | 5 +- src/lib/declarations.ts | 2 + src/lib/getters.ts | 4 ++ src/main.ts | 19 +++--- 9 files changed, 114 insertions(+), 99 deletions(-) diff --git a/src/lib/ActionElement.ts b/src/lib/ActionElement.ts index 85bde7a..56ab985 100644 --- a/src/lib/ActionElement.ts +++ b/src/lib/ActionElement.ts @@ -1,7 +1,7 @@ import { createAutoplaySwitch } from "./Autoplay"; import { setPlaybackRate } from "./PlaybackRate"; -import { CYCLABLE_PLAYBACK_RATES } from "./declarations"; -import { StateObject, BooleanDictionary, PolyDictionary } from "./definitions"; +import { CYCLABLE_PLAYBACK_RATES, INJECTION_MARKER } from "./declarations"; +import { BooleanDictionary, PolyDictionary, StateObject } from "./definitions"; import { getActionElement, getCurrentId, getTitle, getVideo } from "./getters"; import { wheel } from "./utils"; @@ -15,8 +15,10 @@ export function populateActionElement( const actionElement = getActionElement(); const ytShorts = getVideo(); - if (!actionElement) throw new Error("Action element not found"); - if (!ytShorts) throw new Error("Video not found"); + if (!actionElement) return; // throw new Error("Action element not found"); + if (!ytShorts) return; // throw new Error("Video not found"); + + actionElement.setAttribute(INJECTION_MARKER, ""); // ? set marker for injection checks // adsu- idk how any of this works so im just going to leave it be const betterYTContainer = document.createElement("div"); diff --git a/src/lib/Events.ts b/src/lib/Events.ts index 0bd2b20..ab3aa0f 100644 --- a/src/lib/Events.ts +++ b/src/lib/Events.ts @@ -5,8 +5,10 @@ import { getVideo } from "./getters"; /** * Handle adding event listeners to existing elements. * For example, adds a double click event to the player to enter fullscreen mode + * + * Note that duplicate event listeners are ignored, so need need to check */ -export function injectEventsToExistingElements(options: PolyDictionary) { +export function injectEvents(options: PolyDictionary) { const player: HTMLElement | null = getVideo(); // double click the player to enter fullscreen mode diff --git a/src/lib/Info.ts b/src/lib/Info.ts index 604eb02..f73e02d 100644 --- a/src/lib/Info.ts +++ b/src/lib/Info.ts @@ -1,33 +1,40 @@ import { isVideoPlaying } from "./VideoState"; +import { INJECTION_MARKER } from "./declarations"; import { BooleanDictionary } from "./definitions"; import { getCurrentId, + getInfoElement, getOverlayElement, getUploadDate, getViews, } from "./getters"; export function setInfo(features: BooleanDictionary) { - if (!isVideoPlaying()) throw new Error("Video not playing"); + if (!isVideoPlaying()) return; // throw new Error("Video not playing"); - const addInfo = () => { - const info = []; - if (features["viewCounter"]) { - const views = getViews().replace(/(\r\n|\n|\r)/gm, ""); - if (views) info.push(views); - } - if (features["uploadDate"]) { - const uploadDate = getUploadDate().replace(/(\r\n|\n|\r)/gm, ""); - if (uploadDate) info.push(uploadDate); - } + const overlayElement = getOverlayElement(); + const h5 = document.createElement("h5"); + h5.id = `bys-ytViews${getCurrentId()}`; + h5.setAttribute(INJECTION_MARKER, ""); // ? for injection checks + overlayElement.querySelector("reel-player-header-renderer h2")?.prepend(h5); - const overlayElement = getOverlayElement(); - const h5 = document.createElement("h5"); - h5.id = `ytViews${getCurrentId()}`; - h5.innerText = info.join(" | "); - overlayElement.querySelector("reel-player-header-renderer h2")?.prepend(h5); - clearInterval(views_interval); - }; + updateInfo(features); +} + +export function updateInfo(features: BooleanDictionary) { + const element = getInfoElement(); + if (element === null) return; + + const info = []; + + if (features["viewCounter"]) { + const views = getViews().replace(/(\r\n|\n|\r)/gm, ""); + if (views) info.push(views); + } + if (features["uploadDate"]) { + const uploadDate = getUploadDate().replace(/(\r\n|\n|\r)/gm, ""); + if (uploadDate) info.push(uploadDate); + } - const views_interval = setInterval(addInfo, 100); + element.innerText = info.join(" | "); } diff --git a/src/lib/InjectionSuccess.ts b/src/lib/InjectionSuccess.ts index 121f5b8..5ddf533 100644 --- a/src/lib/InjectionSuccess.ts +++ b/src/lib/InjectionSuccess.ts @@ -1,16 +1,17 @@ import { populateActionElement } from "./ActionElement"; -import { modifyProgressBar } from "./ProgressBar"; import { setInfo } from "./Info"; +import { InjectionItemsEnum } from "./InjectionState"; +import { modifyProgressBar } from "./ProgressBar"; import { setVolumeSlider } from "./VolumeSlider"; +import { INJECTION_MARKER } from "./declarations"; import { BooleanDictionary, PolyDictionary, StateObject } from "./definitions"; -import { getCurrentId } from "./getters"; -import { injectEventsToExistingElements } from "./Events"; import { - InjectionItemsEnum, - InjectionState, - InjectionStateUnit, - findInjectionStateInSet, -} from "./InjectionState"; + getActionElement, + getCurrentId, + getInfoElement, + getProgressBarList, + getVolumeContainer, +} from "./getters"; export function injectItems( state: StateObject, @@ -22,70 +23,60 @@ export function injectItems( const id = getCurrentId(); if (id === null) return; - // eslint-disable-next-line prettier/prettier - let injectionState = findInjectionStateInSet(id, state.injectedItems as Set); - let isNewState = false; - if (injectionState === null) { - // eslint-disable-next-line prettier/prettier - injectionState = createNewInjectionState(id, state, settings, options, features); - isNewState = true; - } + const items = Object.values(InjectionItemsEnum); - injectionState.injectRemainingItems(); + items.map((item) => + injectIfNotPresent(item, state, settings, options, features), + ); +} - // eslint-disable-next-line prettier/prettier - if (isNewState) { - (state.injectedItems as Set)?.add(injectionState); - } +/** + * Returns true if the element has an injection marker (this should mean the item was injected) + * @param element The element that has the marker, generally on something with a getter function (like, say, getVideo()) + */ +export function checkForInjectionMarker(element: Element | HTMLElement | null) { + return element !== null && element.hasAttribute(INJECTION_MARKER); } -function createNewInjectionState( - id: number, +/** + * Switch case, checks if the given item was injected or not + * @param item + */ +function injectIfNotPresent( + item: string, state: StateObject, - settings: { [x: string]: string | number | boolean }, + settings: PolyDictionary, options: PolyDictionary, features: BooleanDictionary, ) { - // eslint-disable-next-line prettier/prettier - return new InjectionState( - id, - new InjectionStateUnit(InjectionItemsEnum.ACTION_ELEMENT, () => { - populateActionElement(state, settings, features); - }), - new InjectionStateUnit(InjectionItemsEnum.EXISTING_EVENTS, () => { - injectEventsToExistingElements(options); - }), - new InjectionStateUnit(InjectionItemsEnum.PROGRESS_BAR, () => { - modifyProgressBar(features["progressBar"]); - }), - new InjectionStateUnit(InjectionItemsEnum.VOLUME_SLIDER, () => { - setVolumeSlider( - state, - settings, - options["showVolumeHorizontally"] as boolean, - features["volumeSlider"], - ); - }), - ); -} + switch (item) { + case InjectionItemsEnum.EXISTING_EVENTS: + if (!checkForInjectionMarker(getActionElement())) + populateActionElement(state, settings, features); + break; -export function injectInfoElement( - state: StateObject, - features: BooleanDictionary, -) { - const id = getCurrentId(); - if (id === null) return; + case InjectionItemsEnum.ACTION_ELEMENT: + if (!checkForInjectionMarker(getActionElement())) + populateActionElement(state, settings, features); + break; - const injectionState = findInjectionStateInSet( - id, - state.injectedItems as Set, - ); + case InjectionItemsEnum.PROGRESS_BAR: + if (!checkForInjectionMarker(getProgressBarList())) + modifyProgressBar(features["progressBar"]); + break; - if (injectionState === null) return; + case InjectionItemsEnum.VOLUME_SLIDER: + if (!checkForInjectionMarker(getVolumeContainer())) + setVolumeSlider( + state, + settings, + features["showVolumeHorizontally"], + features["volumeSlider"], + ); + break; - injectionState.addUnit( - new InjectionStateUnit(InjectionItemsEnum.INFO, () => { - setInfo(features); - }), - ); + case InjectionItemsEnum.INFO: + if (!checkForInjectionMarker(getInfoElement())) setInfo(features); + break; + } } diff --git a/src/lib/ProgressBar.ts b/src/lib/ProgressBar.ts index f5894f9..86745fb 100644 --- a/src/lib/ProgressBar.ts +++ b/src/lib/ProgressBar.ts @@ -1,3 +1,4 @@ +import { INJECTION_MARKER } from "./declarations"; import { getOverlayElement, getProgressBarList, getVideo } from "./getters"; import { render } from "./utils"; @@ -7,14 +8,16 @@ export function modifyProgressBar(enabled: boolean) { const overlayElement = getOverlayElement(); const ytShorts = getVideo(); - if (!overlayElement) throw new Error("Overlay element not found"); - if (ytShorts === null) throw new Error("Video not found"); + if (!overlayElement) return; // throw new Error("Overlay element not found"); + if (ytShorts === null) return; // throw new Error("Video not found"); //[id="0"] > div.overlay.style-scope.ytd-reel-video-renderer > ytd-reel-player-overlay-renderer > #overlay const progressBar = getProgressBarList() as HTMLElement; // ? the progressbar itself const pbBackground = progressBar.children[0] as HTMLElement; // ? the grey background of the bar const pbForeground = progressBar.children[1] as HTMLElement; // ? The red part of the progress bar + progressBar.setAttribute(INJECTION_MARKER, ""); // ? for injection checks + const subBox = overlayElement.children[1] as HTMLElement; const tooltip = render( `
`, @@ -52,7 +55,7 @@ function addListeners({ tooltip, }: ListenerProps) { const ytShorts = getVideo(); - if (ytShorts === null) throw new Error(); + if (ytShorts === null) return; // throw new Error(); progressBar.addEventListener("mouseover", () => { pbBackground.classList.add("betterYT-progress-bar-hover"); diff --git a/src/lib/VolumeSlider.ts b/src/lib/VolumeSlider.ts index d5e8a8e..91656d8 100644 --- a/src/lib/VolumeSlider.ts +++ b/src/lib/VolumeSlider.ts @@ -1,5 +1,5 @@ import { saveSettingsToStorage } from "./SaveToStorage"; -import { VOLUME_INCREMENT_AMOUNT } from "./declarations"; +import { INJECTION_MARKER, VOLUME_INCREMENT_AMOUNT } from "./declarations"; import { PolyDictionary, StateObject } from "./definitions"; import { getCurrentId, @@ -62,9 +62,10 @@ export function setVolumeSlider( if (!enabled) return; const id = getCurrentId(); - if (id === null) throw new Error("ID not found"); + if (id === null) return; // throw new Error("ID not found"); const volumeContainer = getVolumeContainer(); + volumeContainer.setAttribute(INJECTION_MARKER, ""); // ? for injections // const slider = document.createElement("input") const slider = render(` Date: Wed, 13 Mar 2024 20:38:12 +0000 Subject: [PATCH 2/4] Renamed files and removed old injection handling --- ...jectionSuccess.ts => InjectionHandling.ts} | 2 +- src/lib/InjectionState.ts | 127 ------------------ src/lib/definitions.ts | 12 +- src/main.ts | 2 +- 4 files changed, 11 insertions(+), 132 deletions(-) rename src/lib/{InjectionSuccess.ts => InjectionHandling.ts} (97%) delete mode 100644 src/lib/InjectionState.ts diff --git a/src/lib/InjectionSuccess.ts b/src/lib/InjectionHandling.ts similarity index 97% rename from src/lib/InjectionSuccess.ts rename to src/lib/InjectionHandling.ts index 5ddf533..a38b1f6 100644 --- a/src/lib/InjectionSuccess.ts +++ b/src/lib/InjectionHandling.ts @@ -1,6 +1,6 @@ import { populateActionElement } from "./ActionElement"; import { setInfo } from "./Info"; -import { InjectionItemsEnum } from "./InjectionState"; +import { InjectionItemsEnum } from "./definitions"; import { modifyProgressBar } from "./ProgressBar"; import { setVolumeSlider } from "./VolumeSlider"; import { INJECTION_MARKER } from "./declarations"; diff --git a/src/lib/InjectionState.ts b/src/lib/InjectionState.ts deleted file mode 100644 index 55484d7..0000000 --- a/src/lib/InjectionState.ts +++ /dev/null @@ -1,127 +0,0 @@ -// todo: change values out for localised strings -export enum InjectionItemsEnum { - EXISTING_EVENTS = "Events", - ACTION_ELEMENT = "Action Elements", - PROGRESS_BAR = "Progress Bar", - VOLUME_SLIDER = "Volume Slider", - INFO = "Info", -} - -export enum InjectionStateEnum { - FAILED = 0, - NEW, - SUCCESS, -} - -const MAX_NUMBER_OF_ATTEMPTS = 3; - -export class InjectionStateUnit { - name: InjectionItemsEnum; - state: InjectionStateEnum; - callback: () => void; - attempts: number; - - constructor(name: InjectionItemsEnum, callback: () => void) { - this.name = name; - this.callback = callback; - this.state = InjectionStateEnum.NEW; - this.attempts = 0; - } - - logError(err: Error) { - console.group("%cBYS Injection Error", "color: #ff7161;"); - console.log( - `%cError while injecting "${this.name}"\n\nInjection was attempted ${this.attempts} times.\n\nMessage: "${err.message}"`, - "color: #ff7161;", - ); - console.groupEnd(); - } - - inject() { - if (this.attempts > MAX_NUMBER_OF_ATTEMPTS) return; - - let state = InjectionStateEnum.SUCCESS; - this.attempts++; - - //prettier-ignore - try { - this.callback(); - } - catch (err) { - if (this.attempts === MAX_NUMBER_OF_ATTEMPTS) - { - this.logError(err as Error); - } - - state = InjectionStateEnum.FAILED; - } - finally { - this.state = state; - // eslint-disable-next-line no-unsafe-finally - return this.state === InjectionStateEnum.SUCCESS; - } - } -} - -export class InjectionState { - units: InjectionStateUnit[]; - id: number; - injectionSucceeded: boolean; - - constructor(id: number, ...units: InjectionStateUnit[]) { - this.units = units; - this.id = id; - this.injectionSucceeded = false; - } - - injectRemainingItems() { - if (this.injectionSucceeded) return; - - this.injectionSucceeded = true; - - for (const unit of this.units) { - if (unit.state !== InjectionStateEnum.SUCCESS) { - // eslint-disable-next-line prettier/prettier - this.injectionSucceeded = ( unit.inject() && this.injectionSucceeded ) as boolean ; - } - } - } - - /** - * Adds {@link InjectionStateUnit} to the list of injection candidates. - * This is specifically for items we know will fail if injected before the video starts, - * as otherwise we could just pass them into the constructor. - * - * This method will handle duplicate checks too. - * - * @param _unit The injection unit. - */ - addUnit(_unit: InjectionStateUnit) { - if (this.hasUnit(_unit.name)) return; - this.units.push(_unit); - this.injectionSucceeded = false; - } - - hasUnit(unitName: InjectionItemsEnum) { - for (const unit of this.units) { - if (unit.name === unitName) { - return true; - } - } - - return false; - } -} - -/** - * Assumes set items are objects that have an `id` prop - * @returns {@link InjectionState}, or {null} if unfound - */ -export function findInjectionStateInSet(id: number, set: Set) { - //prettier-ignore - for ( const item of set ) - if ( item.id === id ) - return item; - - return null; -} diff --git a/src/lib/definitions.ts b/src/lib/definitions.ts index 1228917..b2e129e 100644 --- a/src/lib/definitions.ts +++ b/src/lib/definitions.ts @@ -1,5 +1,3 @@ -import { InjectionState } from "./InjectionState"; - export type NumberDictionary = { [key: string]: number; }; @@ -25,7 +23,7 @@ export type IconDictionary = { }; export interface StateObject { - [key: string]: string | boolean | number | Set | null; + [key: string]: string | boolean | number | null; } export interface OptionsDictionary { @@ -50,3 +48,11 @@ export enum ChangedObjectStateEnum { SETTINGS, FEATURES, } + +export enum InjectionItemsEnum { + EXISTING_EVENTS = "Events", + ACTION_ELEMENT = "Action Elements", + PROGRESS_BAR = "Progress Bar", + VOLUME_SLIDER = "Volume Slider", + INFO = "Info", +} diff --git a/src/main.ts b/src/main.ts index c76e4de..1afbf29 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,7 +4,7 @@ import { handleAutoplay, handleEnableAutoplay } from "./lib/Autoplay"; import { injectEvents } from "./lib/Events"; import { handleHideShortsOverlay } from "./lib/HideShortsOverlay"; import { updateInfo } from "./lib/Info"; -import { injectItems } from "./lib/InjectionSuccess"; +import { injectItems } from "./lib/InjectionHandling"; import { setTimer } from "./lib/PlaybackRate"; import { handleProgressBarNotAppearing } from "./lib/ProgressBar"; import { handleSkipShortsWithLowLikes } from "./lib/SkipShortsWithLowLikes"; From 70ade22556406a5444dde944bff419c4825c8d4a Mon Sep 17 00:00:00 2001 From: adsuth Date: Wed, 13 Mar 2024 20:47:41 +0000 Subject: [PATCH 3/4] Removed EXISTING_EVENTS case --- src/lib/InjectionHandling.ts | 5 ----- src/lib/definitions.ts | 1 - 2 files changed, 6 deletions(-) diff --git a/src/lib/InjectionHandling.ts b/src/lib/InjectionHandling.ts index a38b1f6..3d3e7a1 100644 --- a/src/lib/InjectionHandling.ts +++ b/src/lib/InjectionHandling.ts @@ -50,11 +50,6 @@ function injectIfNotPresent( features: BooleanDictionary, ) { switch (item) { - case InjectionItemsEnum.EXISTING_EVENTS: - if (!checkForInjectionMarker(getActionElement())) - populateActionElement(state, settings, features); - break; - case InjectionItemsEnum.ACTION_ELEMENT: if (!checkForInjectionMarker(getActionElement())) populateActionElement(state, settings, features); diff --git a/src/lib/definitions.ts b/src/lib/definitions.ts index b2e129e..0b80445 100644 --- a/src/lib/definitions.ts +++ b/src/lib/definitions.ts @@ -50,7 +50,6 @@ export enum ChangedObjectStateEnum { } export enum InjectionItemsEnum { - EXISTING_EVENTS = "Events", ACTION_ELEMENT = "Action Elements", PROGRESS_BAR = "Progress Bar", VOLUME_SLIDER = "Volume Slider", From 5912f77760c39fde9be27c6e566975b5372e0930 Mon Sep 17 00:00:00 2001 From: adsuth Date: Wed, 13 Mar 2024 20:49:10 +0000 Subject: [PATCH 4/4] removed injectedItems from state and extraneous import --- src/lib/declarations.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/lib/declarations.ts b/src/lib/declarations.ts index 8a5e5da..d6fb24a 100644 --- a/src/lib/declarations.ts +++ b/src/lib/declarations.ts @@ -1,6 +1,5 @@ import BROWSER from "../background/browser"; import local from "../background/i18n"; -import { InjectionState } from "./InjectionState"; import { BooleanDictionary, NumberDictionary, @@ -152,8 +151,6 @@ export const DEFAULT_STATE: StateObject = { lastTime: -1, // ? this is for checking if items were injected openedCommentsId: -1, - injectedItems: new Set(), - actualVolume: null, skippedId: null,