From 5abcc969c00ecdf0dfeb3dbe842a9f26be529822 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Thu, 2 May 2024 15:59:03 +0400 Subject: [PATCH 01/33] refactor: reduce indentation on `setDefaultValues()` --- src/defaults.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/defaults.ts b/src/defaults.ts index bf8f77059..9b75d72dc 100644 --- a/src/defaults.ts +++ b/src/defaults.ts @@ -28,14 +28,13 @@ function setDefaultValues() { JSON.parse(storedValueString) : storedValueString; // Check if the parsed value is an object and has properties - if (typeof storedValue === "object" && storedValue !== null) { - // Deep merge missing keys with their default values - const updatedValue = deepMerge(defaultValue as Record, storedValue as Record); - // Set the updated value in localStorage - localStorage.setItem(option, JSON.stringify(updatedValue)); - // Set the updated value in chrome storage - void chrome.storage.local.set({ [option]: updatedValue }); - } + if (typeof storedValue !== "object" || storedValue === null) continue; + // Deep merge missing keys with their default values + const updatedValue = deepMerge(defaultValue as Record, storedValue as Record); + // Set the updated value in localStorage + localStorage.setItem(option, JSON.stringify(updatedValue)); + // Set the updated value in chrome storage + void chrome.storage.local.set({ [option]: updatedValue }); } catch (error) { // Handle errors during JSON parsing console.error(`Error parsing stored value for option ${option}:`, error); From 17133235f73e67ee67c0c6b5357636e9a721a72f Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Thu, 2 May 2024 16:00:38 +0400 Subject: [PATCH 02/33] refactor: optimize function --- src/features/automaticTheaterMode/index.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/features/automaticTheaterMode/index.ts b/src/features/automaticTheaterMode/index.ts index 7efe2bccd..ae4be32b7 100644 --- a/src/features/automaticTheaterMode/index.ts +++ b/src/features/automaticTheaterMode/index.ts @@ -3,25 +3,21 @@ import type { YouTubePlayerDiv } from "@/src/types"; import { isWatchPage, waitForSpecificMessage } from "@/src/utils/utilities"; export async function enableAutomaticTheaterMode() { + if (!isWatchPage()) return; // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_automatic_theater_mode } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); // If automatic theater mode isn't enabled return if (!enable_automatic_theater_mode) return; - if (!isWatchPage()) return; // Get the player element - const playerContainer = isWatchPage() ? document.querySelector("div#movie_player") : null; + const playerContainer = document.querySelector("div#movie_player"); // If player element is not available, return if (!playerContainer) return; const { width } = await playerContainer.getSize(); - const { - body: { clientWidth } - } = document; - const isTheaterMode = width === clientWidth; + const isTheaterMode = document.body.clientWidth === width; // Get the size button const sizeButton = document.querySelector("button.ytp-size-button"); // If the size button is not available return From f6d57ef92c789f401d443d04360ac27d7ef9d782 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Thu, 2 May 2024 16:02:20 +0400 Subject: [PATCH 03/33] refactor: qol improvements --- src/features/buttonPlacement/utils.ts | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/features/buttonPlacement/utils.ts b/src/features/buttonPlacement/utils.ts index c7d0ca720..545a2ca4c 100644 --- a/src/features/buttonPlacement/utils.ts +++ b/src/features/buttonPlacement/utils.ts @@ -30,8 +30,8 @@ export function makeFeatureButton, isToggle: boolean ) { - const featureName = findKeyByValue(buttonName as MultiButtonNames) ?? (buttonName as SingleButtonFeatureNames); if (placement === "feature_menu") throw new Error("Cannot make a feature button for the feature menu"); + const featureName = findKeyByValue(buttonName as MultiButtonNames) ?? (buttonName as SingleButtonFeatureNames); const buttonExists = document.querySelector(`button#${getFeatureButtonId(buttonName)}`) !== null; const button = createStyledElement({ classlist: ["ytp-button"], @@ -72,18 +72,12 @@ export function makeFeatureButton(`#${getFeatureButtonId(buttonName)}`); @@ -166,7 +158,7 @@ export function checkIfFeatureButtonExists(buttonName: AllButtonNames, placement } } } -export function getFeatureButtonId(buttonName: AllButtonNames) { +export function getFeatureButtonId(buttonName: ButtonName) { return `yte-feature-${buttonName}-button` as const; } export function getFeatureButton(buttonName: AllButtonNames) { From 1d1f65ac6cc041be84777e8fc794ef55b337c6d4 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Thu, 2 May 2024 17:25:53 +0400 Subject: [PATCH 04/33] refactor: custom css --- src/features/customCSS/index.ts | 18 ++++-------------- src/features/customCSS/utils.ts | 7 ++----- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/features/customCSS/index.ts b/src/features/customCSS/index.ts index c43f1eef5..a6261bc06 100644 --- a/src/features/customCSS/index.ts +++ b/src/features/customCSS/index.ts @@ -4,32 +4,22 @@ import { createCustomCSSElement, customCSSExists, updateCustomCSS } from "./util export const customCssID = "yte-custom-css"; export async function enableCustomCSS() { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { custom_css_code, enable_custom_css } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); // Check if custom CSS is enabled if (!enable_custom_css) return; - if (customCSSExists()) { - updateCustomCSS({ - custom_css_code - }); - return; - } + if (customCSSExists()) return updateCustomCSS({ custom_css_code }); // Create the custom CSS style element - const customCSSStyleElement = createCustomCSSElement({ - custom_css_code - }); + const customCSSStyleElement = createCustomCSSElement({ custom_css_code }); // Insert the custom CSS style element document.head.appendChild(customCSSStyleElement); } export function disableCustomCSS() { // Get the custom CSS style element const customCSSStyleElement = document.querySelector(`#${customCssID}`); - // Check if the custom CSS style element exists - if (!customCSSStyleElement) return; // Remove the custom CSS style element - customCSSStyleElement.remove(); + customCSSStyleElement?.remove(); } diff --git a/src/features/customCSS/utils.ts b/src/features/customCSS/utils.ts index a62bc45ed..ec2c6b087 100644 --- a/src/features/customCSS/utils.ts +++ b/src/features/customCSS/utils.ts @@ -5,9 +5,7 @@ import { customCssID } from "@/src/features/customCSS"; export function updateCustomCSS({ custom_css_code }: Pick) { // Get the custom CSS style element const customCSSStyleElement = document.querySelector(`#${customCssID}`); - // Check if the custom CSS style element exists - if (!customCSSStyleElement) return; - customCSSStyleElement.replaceWith(createCustomCSSElement({ custom_css_code })); + customCSSStyleElement?.replaceWith(createCustomCSSElement({ custom_css_code })); } export function createCustomCSSElement({ custom_css_code }: Pick) { // Create the custom CSS style element @@ -20,6 +18,5 @@ export function customCSSExists() { // Get the custom CSS style element const customCSSStyleElement = document.querySelector(`#${customCssID}`); // Check if the custom CSS style element exists - if (!customCSSStyleElement) return false; - return true; + return customCSSStyleElement !== null; } From 91e4e982b23cfb7746642b5dfefcd13099ba5a88 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 12:56:48 +0400 Subject: [PATCH 05/33] refactor: deep dark css --- src/features/deepDarkCSS/index.ts | 12 +++++------- src/features/deepDarkCSS/utils.ts | 7 ++----- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/features/deepDarkCSS/index.ts b/src/features/deepDarkCSS/index.ts index 118c53204..dba550eaf 100644 --- a/src/features/deepDarkCSS/index.ts +++ b/src/features/deepDarkCSS/index.ts @@ -5,17 +5,17 @@ import { createDeepDarkCSSElement, deepDarkCSSExists, getDeepDarkCustomThemeStyl export const deepDarkCssID = "yte-deep-dark-css"; export async function enableDeepDarkCSS() { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { deep_dark_custom_theme_colors, deep_dark_preset, enable_deep_dark_theme } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); // Check if deep dark theme is enabled if (!enable_deep_dark_theme) return; if (deepDarkCSSExists()) { - updateDeepDarkCSS(deep_dark_preset === "Custom" ? getDeepDarkCustomThemeStyle(deep_dark_custom_theme_colors) : deepDarkPresets[deep_dark_preset]); - return; + return updateDeepDarkCSS( + deep_dark_preset === "Custom" ? getDeepDarkCustomThemeStyle(deep_dark_custom_theme_colors) : deepDarkPresets[deep_dark_preset] + ); } // Create the deep dark theme style element const deepDarkThemeStyleElement = createDeepDarkCSSElement( @@ -28,8 +28,6 @@ export async function enableDeepDarkCSS() { export function disableDeepDarkCSS() { // Get the deep dark theme style element const deepDarkThemeStyleElement = document.querySelector(`#${deepDarkCssID}`); - // Check if the deep dark theme style element exists - if (!deepDarkThemeStyleElement) return; // Remove the deep dark theme style element - deepDarkThemeStyleElement.remove(); + deepDarkThemeStyleElement?.remove(); } diff --git a/src/features/deepDarkCSS/utils.ts b/src/features/deepDarkCSS/utils.ts index 75c9c32c2..da8bd4cd0 100644 --- a/src/features/deepDarkCSS/utils.ts +++ b/src/features/deepDarkCSS/utils.ts @@ -6,9 +6,7 @@ import { deepDarkCssID } from "@/src/features/deepDarkCSS"; export function updateDeepDarkCSS(css_code: string) { // Get the custom CSS style element const customCSSStyleElement = document.querySelector(`#${deepDarkCssID}`); - // Check if the custom CSS style element exists - if (!customCSSStyleElement) return; - customCSSStyleElement.replaceWith(createDeepDarkCSSElement(css_code)); + customCSSStyleElement?.replaceWith(createDeepDarkCSSElement(css_code)); } export function createDeepDarkCSSElement(css_code: string) { // Create the custom CSS style element @@ -21,8 +19,7 @@ export function deepDarkCSSExists() { // Get the custom CSS style element const customCSSStyleElement = document.querySelector(`#${deepDarkCssID}`); // Check if the custom CSS style element exists - if (!customCSSStyleElement) return false; - return true; + return customCSSStyleElement !== null; } export function getDeepDarkCustomThemeStyle({ From 109c28bcd1f942d5c3c7bba8535ab40f1b89e71f Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 12:57:20 +0400 Subject: [PATCH 06/33] refactor: feature menu --- src/features/featureMenu/index.ts | 37 ++++++++++++------------------- src/features/featureMenu/utils.ts | 22 ++++++------------ 2 files changed, 21 insertions(+), 38 deletions(-) diff --git a/src/features/featureMenu/index.ts b/src/features/featureMenu/index.ts index 13e4704cb..efc7fa5d5 100644 --- a/src/features/featureMenu/index.ts +++ b/src/features/featureMenu/index.ts @@ -93,13 +93,11 @@ export async function enableFeatureMenu() { } function adjustAdsContainerStyles(featureMenuOpen: boolean) { const adsContainer = document.querySelector("div.video-ads.ytp-ad-module"); - if (adsContainer) { - const adsSpan = adsContainer.querySelector("span.ytp-ad-preview-container"); - if (adsSpan) { - adsSpan.style.opacity = featureMenuOpen ? "0.4" : ""; - adsSpan.style.zIndex = featureMenuOpen ? "36" : ""; - } - } + if (!adsContainer) return; + const adsSpan = adsContainer.querySelector("span.ytp-ad-preview-container"); + if (!adsSpan) return; + adsSpan.style.opacity = featureMenuOpen ? "0.4" : ""; + adsSpan.style.zIndex = featureMenuOpen ? "36" : ""; } export function setupFeatureMenuEventListeners(featureMenuOpenType: FeatureMenuOpenType) { eventManager.removeEventListeners("featureMenu"); @@ -211,23 +209,16 @@ export function setupFeatureMenuEventListeners(featureMenuOpenType: FeatureMenuO } function handleMutation(mutations: MutationRecord[]) { mutations.forEach((mutation) => { - if (mutation.type === "childList") { - const addedNodes = Array.from(mutation.addedNodes); - const isAdsElementAdded = addedNodes.some( - (node) => (node as HTMLDivElement).classList?.contains("video-ads") && (node as HTMLDivElement).classList?.contains("ytp-ad-module") - ); - if (isAdsElementAdded) { - const featureMenu = document.querySelector("#yte-feature-menu"); - if (featureMenu) { - adjustAdsContainerStyles(featureMenu.style.display === "block"); - } - } - } + if (mutation.type !== "childList") return; + const addedNodes = Array.from(mutation.addedNodes); + const isAdsElementAdded = addedNodes.some( + (node) => (node as HTMLDivElement).classList?.contains("video-ads") && (node as HTMLDivElement).classList?.contains("ytp-ad-module") + ); + if (!isAdsElementAdded) return; + const featureMenu = document.querySelector("#yte-feature-menu"); + if (featureMenu) adjustAdsContainerStyles(featureMenu.style.display === "block"); }); } const observer = new MutationObserver(handleMutation); - observer.observe(playerContainer, { - childList: true, - subtree: true - }); + observer.observe(playerContainer, { childList: true, subtree: true }); } diff --git a/src/features/featureMenu/utils.ts b/src/features/featureMenu/utils.ts index 017e3151d..fa3829d5d 100644 --- a/src/features/featureMenu/utils.ts +++ b/src/features/featureMenu/utils.ts @@ -88,19 +88,15 @@ export async function addFeatureItemToMenu(buttonName: ButtonName) { + const featureMenuItemIconId = `yte-${buttonName}-icon` as const; + const featureMenuItemId = `yte-feature-${buttonName}-menuitem` as const; + const featureMenuItemLabelId = `yte-${buttonName}-label` as const; return { featureMenuItemIconId, featureMenuItemId, From 55cbe8073606f1d0c125dbd15aa25229efb5502d Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 12:58:04 +0400 Subject: [PATCH 07/33] refactor: hide x features --- src/features/hideLiveStreamChat/index.ts | 9 +++------ src/features/hideScrollBar/index.ts | 4 +--- src/features/hideScrollBar/utils.ts | 4 +--- src/features/hideShorts/index.ts | 9 +++------ src/features/hideShorts/utils.ts | 5 +---- 5 files changed, 9 insertions(+), 22 deletions(-) diff --git a/src/features/hideLiveStreamChat/index.ts b/src/features/hideLiveStreamChat/index.ts index dfada6eed..ec348b4dc 100644 --- a/src/features/hideLiveStreamChat/index.ts +++ b/src/features/hideLiveStreamChat/index.ts @@ -18,25 +18,22 @@ const liveStreamChatElementPairs: ElementClassPair[] = [ } ]; export async function enableHideLiveStreamChat() { - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_hide_live_stream_chat: enableHideLiveStreamChat } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); if (!enableHideLiveStreamChat) return; await waitForAllElements(["div#player", "div#player-wide-container", "div#video-container", "div#player-container"]); const player = document.querySelector("div#movie_player"); if (!player) return; - const playerData = await player.getVideoData(); - if (!playerData.isLive) return; + if (!(await player.getVideoData()).isLive) return; modifyElementsClassList("add", liveStreamChatElementPairs); } export async function disableHideLiveStreamChat() { const player = document.querySelector("div#movie_player"); if (!player) return; - const playerData = await player.getVideoData(); - if (!playerData.isLive) return; + if (!(await player.getVideoData()).isLive) return; modifyElementsClassList("remove", liveStreamChatElementPairs); } diff --git a/src/features/hideScrollBar/index.ts b/src/features/hideScrollBar/index.ts index eecb0aea4..0930f93fa 100644 --- a/src/features/hideScrollBar/index.ts +++ b/src/features/hideScrollBar/index.ts @@ -10,7 +10,5 @@ export async function enableHideScrollBar() { options: { enable_hide_scrollbar } } } = optionsData; - // If the hide scroll bar option is disabled, return - if (!enable_hide_scrollbar) return; - hideScrollBar(); + if (enable_hide_scrollbar) hideScrollBar(); } diff --git a/src/features/hideScrollBar/utils.ts b/src/features/hideScrollBar/utils.ts index fcc40d7f0..e810775f8 100644 --- a/src/features/hideScrollBar/utils.ts +++ b/src/features/hideScrollBar/utils.ts @@ -14,7 +14,5 @@ export function hideScrollBar() { } export function showScrollBar() { const style = document.getElementById("yte-hide-scroll-bar"); - if (style) { - style.remove(); - } + style?.remove(); } diff --git a/src/features/hideShorts/index.ts b/src/features/hideShorts/index.ts index 49d6f035a..2a060dee3 100644 --- a/src/features/hideShorts/index.ts +++ b/src/features/hideShorts/index.ts @@ -4,12 +4,11 @@ import { waitForSpecificMessage } from "@/src/utils/utilities"; let shortsObserver: Nullable = null; export async function enableHideShorts() { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_hide_shorts } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); // If the hide shorts option is disabled, return if (!enable_hide_shorts) return; hideShorts(); @@ -20,8 +19,6 @@ export async function enableHideShorts() { export function disableHideShorts() { showShorts(); // Disconnect the observer - if (shortsObserver) { - shortsObserver.disconnect(); - shortsObserver = null; - } + shortsObserver?.disconnect(); + shortsObserver = null; } diff --git a/src/features/hideShorts/utils.ts b/src/features/hideShorts/utils.ts index 576cf95d6..1f6e6d917 100644 --- a/src/features/hideShorts/utils.ts +++ b/src/features/hideShorts/utils.ts @@ -10,7 +10,6 @@ type ElementVisibilityAction = (element: HTMLElement) => void; function toggleElementVisibility(selector: string, action: ElementVisibilityAction) { const elements = document.querySelectorAll(selector); - if (elements.length === 0) return; elements.forEach((element) => action(element)); } @@ -117,9 +116,7 @@ export function observeShortsElements() { }); // Only call hideShorts if one of the mutations contains one of the selectors - if (containsShortsSelector) { - hideShorts(); - } + if (containsShortsSelector) hideShorts(); }); observer.observe(document.body, observerOptions); From f33ab7ceb42105f702ae5ffdfb4d880956eecc8a Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 12:58:26 +0400 Subject: [PATCH 08/33] refactor: loop button --- src/features/loopButton/index.ts | 76 ++++++++++++++++---------------- src/features/loopButton/utils.ts | 8 ++-- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/src/features/loopButton/index.ts b/src/features/loopButton/index.ts index 3ec163e6a..23b4182da 100644 --- a/src/features/loopButton/index.ts +++ b/src/features/loopButton/index.ts @@ -13,7 +13,6 @@ import { loopButtonClickListener } from "./utils"; export const addLoopButton: AddButtonFunction = async () => { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { @@ -21,7 +20,7 @@ export const addLoopButton: AddButtonFunction = async () => { enable_loop_button } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); // If the loop button option is disabled, return if (!enable_loop_button) return; // Get the volume control element @@ -34,52 +33,53 @@ export const addLoopButton: AddButtonFunction = async () => { await addFeatureButton( "loopButton", loopButtonPlacement, - loopButtonPlacement === "feature_menu" ? - window.i18nextInstance.t("pages.content.features.loopButton.button.label") - : window.i18nextInstance.t("pages.content.features.loopButton.button.toggle.off"), + window.i18nextInstance.t( + loopButtonPlacement === "feature_menu" ? + "pages.content.features.loopButton.button.label" + : "pages.content.features.loopButton.button.toggle.off" + ), getFeatureIcon("loopButton", loopButtonPlacement !== "feature_menu" ? "shared_icon_position" : "feature_menu"), loopButtonClickListener, true ); const loopChangedHandler = (mutationList: MutationRecord[]) => { const loopSVG = getFeatureIcon("loopButton", loopButtonPlacement !== "feature_menu" ? "shared_icon_position" : "feature_menu"); - for (const mutation of mutationList) { - if (mutation.type === "attributes") { - const { attributeName, target } = mutation; - if (attributeName === "loop") { - const { loop } = target as HTMLVideoElement; - const featureName: SingleButtonFeatureNames = "loopButton"; - // Get the feature menu - const featureMenu = document.querySelector("#yte-feature-menu"); - // Check if the feature item already exists in the menu - const featureExistsInMenu = - featureMenu && featureMenu.querySelector(`#${getFeatureIds(featureName).featureMenuItemId}`) !== null; - if (featureExistsInMenu) { - const menuItem = getFeatureButton(featureName); - if (!menuItem) return; - menuItem.ariaChecked = loop ? "true" : "false"; + mutationList.forEach((mutation) => { + if (mutation.type !== "attributes") return; + const { attributeName, target } = mutation; + if (attributeName !== "loop") return; + + const { loop } = target as HTMLVideoElement; + const featureName: SingleButtonFeatureNames = "loopButton"; + // Get the feature menu + const featureMenu = document.querySelector("#yte-feature-menu"); + const featureItem = featureMenu?.querySelector(`#${getFeatureIds(featureName).featureMenuItemId}`) || null; + // Check if the feature item already exists in the menu + const featureExistsInMenu = featureMenu !== null && featureItem !== null; + if (featureExistsInMenu) { + const menuItem = getFeatureButton(featureName); + if (!menuItem) return; + menuItem.ariaChecked = loop ? "true" : "false"; + } + const button = document.querySelector(`#${getFeatureButtonId(featureName)}`); + if (!button) return; + switch (loopButtonPlacement) { + case "feature_menu": { + if (loopSVG instanceof SVGSVGElement) { + button.firstChild?.replaceWith(loopSVG); } - const button = document.querySelector(`#${getFeatureButtonId(featureName)}`); - if (!button) return; - switch (loopButtonPlacement) { - case "feature_menu": { - if (loopSVG instanceof SVGSVGElement) { - button.firstChild?.replaceWith(loopSVG); - } - break; - } - case "below_player": - case "player_controls_left": - case "player_controls_right": { - if (typeof loopSVG === "object" && "off" in loopSVG && "on" in loopSVG) { - button.firstChild?.replaceWith(loop ? loopSVG.on : loopSVG.off); - } - break; - } + break; + } + case "below_player": + case "player_controls_left": + case "player_controls_right": { + if (typeof loopSVG === "object" && "off" in loopSVG && "on" in loopSVG) { + button.firstChild?.replaceWith(loop ? loopSVG.on : loopSVG.off); } + break; } } - } + }); }; const loopChangeMutationObserver = new MutationObserver(loopChangedHandler); loopChangeMutationObserver.observe(videoElement, { attributeFilter: ["loop"], attributes: true }); diff --git a/src/features/loopButton/utils.ts b/src/features/loopButton/utils.ts index 1173d1a96..e5ca4efba 100644 --- a/src/features/loopButton/utils.ts +++ b/src/features/loopButton/utils.ts @@ -6,10 +6,8 @@ export function loopButtonClickListener(checked?: boolean) { } const videoElement = document.querySelector("video.html5-main-video"); if (!videoElement) return; + const loop = videoElement.hasAttribute("loop"); - if (loop) { - videoElement.removeAttribute("loop"); - } else { - videoElement.setAttribute("loop", ""); - } + if (loop) videoElement.removeAttribute("loop"); + else videoElement.setAttribute("loop", ""); } From 3356e641e4fe4807744ef9b1d1f60ba8bb302019 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 12:58:45 +0400 Subject: [PATCH 09/33] refactor: maximize button --- src/features/maximizePlayerButton/index.ts | 89 +++++++++------------- src/features/maximizePlayerButton/utils.ts | 15 +--- 2 files changed, 42 insertions(+), 62 deletions(-) diff --git a/src/features/maximizePlayerButton/index.ts b/src/features/maximizePlayerButton/index.ts index 888ef762d..a32d5bceb 100644 --- a/src/features/maximizePlayerButton/index.ts +++ b/src/features/maximizePlayerButton/index.ts @@ -1,5 +1,5 @@ import type { AddButtonFunction, RemoveButtonFunction } from "@/src/features"; -import type { Nullable, YouTubePlayerDiv } from "@/src/types"; +import type { YouTubePlayerDiv } from "@/src/types"; import { addFeatureButton, removeFeatureButton } from "@/src/features/buttonPlacement"; import { getFeatureButton, updateFeatureButtonIcon, updateFeatureButtonTitle } from "@/src/features/buttonPlacement/utils"; @@ -11,7 +11,6 @@ import { maximizePlayer, setupVideoPlayerTimeUpdate, updateProgressBarPositions // TODO: fix the "default/theatre" view button and pip button not making the player minimize to the previous state. export const addMaximizePlayerButton: AddButtonFunction = async () => { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { @@ -19,19 +18,18 @@ export const addMaximizePlayerButton: AddButtonFunction = async () => { enable_maximize_player_button: enableMaximizePlayerButton } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); // If the maximize player button option is disabled, return if (!enableMaximizePlayerButton) return; // Add a click event listener to the maximize button function maximizePlayerButtonClickListener(checked?: boolean) { const button = getFeatureButton("maximizePlayerButton"); if (!button) return; - const featureName = "maximizePlayerButton"; const { remove } = createTooltip({ direction: maximizePlayerButtonPlacement === "below_player" ? "down" : "up", element: button, - featureName, - id: `yte-feature-${featureName}-tooltip` + featureName: "maximizePlayerButton", + id: "yte-feature-maximizePlayerButton-tooltip" }); if (checked !== undefined) { if (checked) remove(); @@ -45,9 +43,9 @@ export const addMaximizePlayerButton: AddButtonFunction = async () => { setupVideoPlayerTimeUpdate(); } - const pipElement: Nullable = document.querySelector("button.ytp-pip-button"); - const sizeElement: Nullable = document.querySelector("button.ytp-size-button"); - const miniPlayerElement: Nullable = document.querySelector("button.ytp-miniplayer-button"); + const pipElement = document.querySelector("button.ytp-pip-button"); + const sizeElement = document.querySelector("button.ytp-size-button"); + const miniPlayerElement = document.querySelector("button.ytp-miniplayer-button"); function otherElementClickListener() { // Get the video element const videoElement = document.querySelector("video.video-stream.html5-main-video"); @@ -55,25 +53,26 @@ export const addMaximizePlayerButton: AddButtonFunction = async () => { if (!videoElement) return; const videoContainer = document.querySelector("#movie_player"); if (!videoContainer) return; - if (videoContainer.classList.contains("maximized_video_container") && videoElement.classList.contains("maximized_video")) { - const maximizePlayerButton = getFeatureButton("maximizePlayerButton"); - if (!maximizePlayerButton) return; - maximizePlayer(); - maximizePlayerButton.ariaChecked = "false"; - const button = getFeatureButton("maximizePlayerButton"); + if (!videoContainer.classList.contains("maximized_video_container") || !videoElement.classList.contains("maximized_video")) return; + const maximizePlayerButton = getFeatureButton("maximizePlayerButton"); + if (!maximizePlayerButton) return; + maximizePlayer(); + maximizePlayerButton.ariaChecked = "false"; + const button = getFeatureButton("maximizePlayerButton"); + if (button && button instanceof HTMLButtonElement) { const icon = getFeatureIcon("maximizePlayerButton", "shared_icon_position"); - if (button && button instanceof HTMLButtonElement) { - if (typeof icon === "object" && "off" in icon && "on" in icon) updateFeatureButtonIcon(button, icon.off); - updateFeatureButtonTitle("maximizePlayerButton", window.i18nextInstance.t("pages.content.features.maximizePlayerButton.button.toggle.off")); - } + if (typeof icon === "object" && "off" in icon && "on" in icon) updateFeatureButtonIcon(button, icon.off); + updateFeatureButtonTitle("maximizePlayerButton", window.i18nextInstance.t("pages.content.features.maximizePlayerButton.button.toggle.off")); } } await addFeatureButton( "maximizePlayerButton", maximizePlayerButtonPlacement, - maximizePlayerButtonPlacement === "feature_menu" ? - window.i18nextInstance.t("pages.content.features.maximizePlayerButton.button.label") - : window.i18nextInstance.t("pages.content.features.maximizePlayerButton.button.toggle.off"), + window.i18nextInstance.t( + maximizePlayerButtonPlacement === "feature_menu" ? + "pages.content.features.maximizePlayerButton.button.label" + : "pages.content.features.maximizePlayerButton.button.toggle.off" + ), getFeatureIcon("maximizePlayerButton", maximizePlayerButtonPlacement !== "feature_menu" ? "shared_icon_position" : "feature_menu"), maximizePlayerButtonClickListener, true @@ -114,16 +113,17 @@ export const addMaximizePlayerButton: AddButtonFunction = async () => { if (!controlsElement) return; if ( - videoContainer.classList.contains("maximized_video_container") && - videoElement.classList.contains("maximized_video") && - controlsElement.classList.contains("maximized_controls") - ) { - const buttonRect = (event.target as HTMLButtonElement).getBoundingClientRect(); - const tooltipRect = ytTooltip.getBoundingClientRect(); - ytTooltip.style.left = `${buttonRect.left - 48}px`; - ytTooltip.style.top = `${buttonRect.top - tooltipRect.height - 14}px`; - ytTooltip.style.zIndex = "2021"; - } + !videoContainer.classList.contains("maximized_video_container") || + !videoElement.classList.contains("maximized_video") || + !controlsElement.classList.contains("maximized_controls") + ) + return; + + const buttonRect = (event.target as HTMLButtonElement).getBoundingClientRect(); + const tooltipRect = ytTooltip.getBoundingClientRect(); + ytTooltip.style.left = `${buttonRect.left - 48}px`; + ytTooltip.style.top = `${buttonRect.top - tooltipRect.height - 14}px`; + ytTooltip.style.zIndex = "2021"; } function seekBarMouseEnterListener(event: MouseEvent) { // TODO: get the seek preview to be in the correct place when the video is maximized from default view @@ -150,15 +150,10 @@ export const addMaximizePlayerButton: AddButtonFunction = async () => { } } - if (pipElement) { - eventManager.addEventListener(pipElement, "click", otherElementClickListener, "maximizePlayerButton"); - } - if (sizeElement) { - eventManager.addEventListener(sizeElement, "click", otherElementClickListener, "maximizePlayerButton"); - } - if (miniPlayerElement) { - eventManager.addEventListener(miniPlayerElement, "click", otherElementClickListener, "maximizePlayerButton"); - } + if (pipElement) eventManager.addEventListener(pipElement, "click", otherElementClickListener, "maximizePlayerButton"); + if (sizeElement) eventManager.addEventListener(sizeElement, "click", otherElementClickListener, "maximizePlayerButton"); + if (miniPlayerElement) eventManager.addEventListener(miniPlayerElement, "click", otherElementClickListener, "maximizePlayerButton"); + const typLeftButtons = [ ...document.querySelectorAll("div.ytp-chrome-controls > div.ytp-left-controls > :not(.yte-maximized-player-button)") ]; @@ -173,16 +168,8 @@ export const addMaximizePlayerButton: AddButtonFunction = async () => { const typRightButtons = document.querySelectorAll( "div.ytp-chrome-controls > div.ytp-right-controls > :not(.yte-maximized-player-button)" ); - typLeftButtons.forEach((button) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore TODO: figure out the proper type for this - eventManager.addEventListener(button, "mouseenter", ytpLeftButtonMouseEnterListener, "maximizePlayerButton"); - }); - typRightButtons.forEach((button) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore TODO: figure out the proper type for this - eventManager.addEventListener(button, "mouseenter", ytpRightButtonMouseEnterListener, "maximizePlayerButton"); - }); + typLeftButtons.forEach((button) => eventManager.addEventListener(button, "mouseenter", ytpLeftButtonMouseEnterListener, "maximizePlayerButton")); + typRightButtons.forEach((button) => eventManager.addEventListener(button, "mouseenter", ytpRightButtonMouseEnterListener, "maximizePlayerButton")); }; export const removeMaximizePlayerButton: RemoveButtonFunction = async (placement) => { await removeFeatureButton("maximizePlayerButton", placement); diff --git a/src/features/maximizePlayerButton/utils.ts b/src/features/maximizePlayerButton/utils.ts index a5d66b7df..504145f12 100644 --- a/src/features/maximizePlayerButton/utils.ts +++ b/src/features/maximizePlayerButton/utils.ts @@ -11,9 +11,7 @@ export function updateProgressBarPositions() { const seekBar = document.querySelector("div.ytp-progress-bar"); const scrubber = document.querySelector("div.ytp-scrubber-container"); const hoverProgress = document.querySelector("div.ytp-hover-progress"); - if (!seekBar) return; - if (!scrubber) return; - if (!hoverProgress) return; + if (!seekBar || !scrubber || !hoverProgress) return; const elapsedTime = parseInt(seekBar?.ariaValueNow ?? "0") ?? 0; const duration = parseInt(seekBar?.ariaValueMax ?? "0") ?? 0; const seekBarWidth = seekBar?.clientWidth ?? 0; @@ -27,10 +25,7 @@ export function updateProgressBarPositions() { export function setupVideoPlayerTimeUpdate() { const videoElement = document.querySelector("video.video-stream.html5-main-video"); if (!videoElement) return; - const videoPlayerTimeUpdateListener = () => { - updateProgressBarPositions(); - }; - eventManager.addEventListener(videoElement, "timeupdate", videoPlayerTimeUpdateListener, "maximizePlayerButton"); + eventManager.addEventListener(videoElement, "timeupdate", () => updateProgressBarPositions(), "maximizePlayerButton"); } export function maximizePlayer() { // Get the video element @@ -65,10 +60,8 @@ export function maximizePlayer() { childNodes: [, svgPath] } = svgElement; if (!svgPath || !(svgPath instanceof SVGPathElement)) return; - if (svgPath.getAttribute("d") === theaterModeVariables.pathD) wasInTheatreMode = true; - else wasInTheatreMode = false; - if (wasInTheatreMode) setToTheatreMode = false; - else setToTheatreMode = true; + wasInTheatreMode = svgPath.getAttribute("d") === theaterModeVariables.pathD; + setToTheatreMode = !wasInTheatreMode; // TODO: finish this code to make the maximize player button work properly. (implement ytp-scrubber-container adjustment) if all else fails revert to using the theatre mode button to get the tooltips in the correct place console.log(`setToTheatreMode && wasInTheatreMode: ${setToTheatreMode && wasInTheatreMode}`); console.log(`setToTheatreMode && !wasInTheatreMode: ${setToTheatreMode && !wasInTheatreMode}`); From a576f5cd70f831a8a343bd00b770130f070a0b36 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 12:59:04 +0400 Subject: [PATCH 10/33] refactor: transcript button --- src/features/openTranscriptButton/index.ts | 3 +-- src/features/openTranscriptButton/utils.ts | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/features/openTranscriptButton/index.ts b/src/features/openTranscriptButton/index.ts index 8b5b04607..b38aaeb2d 100644 --- a/src/features/openTranscriptButton/index.ts +++ b/src/features/openTranscriptButton/index.ts @@ -6,12 +6,11 @@ import { addOpenTranscriptButton } from "./utils"; export async function openTranscriptButton() { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_open_transcript_button: enableOpenTranscriptButton } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); // If the open transcript button option is disabled, return if (!enableOpenTranscriptButton) return; await waitForAllElements(["ytd-video-description-transcript-section-renderer button"]); diff --git a/src/features/openTranscriptButton/utils.ts b/src/features/openTranscriptButton/utils.ts index fe688bafa..8997e4d91 100644 --- a/src/features/openTranscriptButton/utils.ts +++ b/src/features/openTranscriptButton/utils.ts @@ -7,18 +7,16 @@ import { waitForSpecificMessage } from "@/src/utils/utilities"; export const addOpenTranscriptButton: AddButtonFunction = async () => { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { button_placements: { openTranscriptButton: openTranscriptButtonPlacement } } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); function transcriptButtonClickerListener() { const transcriptButton = document.querySelector("ytd-video-description-transcript-section-renderer button"); - if (!transcriptButton) return; - transcriptButton.click(); + transcriptButton?.click(); } await addFeatureButton( "openTranscriptButton", From 2b3b621290a88360d332331f33390c974e045c6c Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 12:59:22 +0400 Subject: [PATCH 11/33] refactor: open settings on hover feature --- src/features/openYouTubeSettingsOnHover/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/features/openYouTubeSettingsOnHover/index.ts b/src/features/openYouTubeSettingsOnHover/index.ts index 20a8b4512..ac5e0a2de 100644 --- a/src/features/openYouTubeSettingsOnHover/index.ts +++ b/src/features/openYouTubeSettingsOnHover/index.ts @@ -5,12 +5,11 @@ import { isWatchPage, waitForSpecificMessage } from "@/src/utils/utilities"; export async function enableOpenYouTubeSettingsOnHover() { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_open_youtube_settings_on_hover: enableOpenYouTubeSettingsOnHover } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); // If the open YouTube settings on hover option is disabled, return if (!enableOpenYouTubeSettingsOnHover) return; const settingsButton = document.querySelector(".ytp-button.ytp-settings-button"); From f45afef4b152d7e36be90a213e14818eaf57866e Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 13:01:23 +0400 Subject: [PATCH 12/33] fix: make types constrained and make more issues for the future --- src/utils/EventManager.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/utils/EventManager.ts b/src/utils/EventManager.ts index 84d22d324..f30bff066 100644 --- a/src/utils/EventManager.ts +++ b/src/utils/EventManager.ts @@ -36,7 +36,7 @@ export type EventManager = { addEventListener: ( target: HTMLElementTagNameMap[keyof HTMLElementTagNameMap], eventName: K, - callback: EventCallback, + callback: EventCallback, featureName: FeatureName, options?: AddEventListenerOptions | boolean ) => void; @@ -70,16 +70,24 @@ export const eventManager: EventManager = { const existingListener = existingListeners.find((listener) => listener.callback === callback); // If the listener hasn't been added, add it if (!existingListener) { - const listenerInfo: EventListenerInfo = { + const listenerInfo: EventListenerInfo = { callback, eventName, target }; + // @ts-expect-error see: https://github.com/microsoft/TypeScript/issues/27808 + // TODO: Add a better way to handle the subtype constraints existingListeners.push(listenerInfo); eventListeners.set(eventName, existingListeners); targetListeners.set(target, eventListeners); this.listeners.set(featureName, targetListeners); - target.addEventListener(eventName, callback, options); + target.addEventListener( + eventName, + // @ts-expect-error The types are fucked in this one + // TODO: Let the future deal with it + callback, + options + ); } }, From 3d7a1fa4d4fe592e860c5b4b0b2988b5955564bf Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 13:55:52 +0400 Subject: [PATCH 13/33] refactor: playback speed button --- src/features/playbackSpeedButtons/index.ts | 31 +++++++--------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/src/features/playbackSpeedButtons/index.ts b/src/features/playbackSpeedButtons/index.ts index 8bb48477b..19d7420e6 100644 --- a/src/features/playbackSpeedButtons/index.ts +++ b/src/features/playbackSpeedButtons/index.ts @@ -11,11 +11,8 @@ import { createTooltip, isShortsPage, isWatchPage, waitForSpecificMessage } from import type { AddButtonFunction, RemoveButtonFunction } from "../index"; let currentPlaybackSpeed = 1; -async function updateTooltip( - buttonName: ButtonName, - speed: number -) { - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); +type TooltipButtonName = "decreasePlaybackSpeedButton" | "increasePlaybackSpeedButton"; +async function updateTooltip(buttonName: ButtonName, speed: number) { const { data: { options: { @@ -26,22 +23,21 @@ async function updateTooltip void { : isShortsPage() ? document.querySelector("div#shorts-player") : null; if (!playerContainer) return; - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { osd_display_color, osd_display_hide_time, osd_display_opacity, osd_display_padding, osd_display_position } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); new OnScreenDisplayManager( { displayColor: osd_display_color, @@ -81,14 +76,10 @@ function playbackSpeedButtonClickListener(amount: number): () => void { displayPadding: osd_display_padding, displayPosition: osd_display_position, displayType: "text", // TODO: support for line/round? currently buggy - playerContainer: playerContainer + playerContainer }, "yte-osd", - { - max: 4, - type: "speed", - value: currentPlaybackSpeed + amount - } + { max: 4, type: "speed", value: currentPlaybackSpeed + amount } ); const speed = currentPlaybackSpeed + amount; await setPlayerSpeed(speed); @@ -102,7 +93,6 @@ function playbackSpeedButtonClickListener(amount: number): () => void { } export const addIncreasePlaybackSpeedButton: AddButtonFunction = async () => { - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { @@ -111,7 +101,7 @@ export const addIncreasePlaybackSpeedButton: AddButtonFunction = async () => { playback_buttons_speed: playbackSpeedPerClick } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); if (!enable_playback_speed_buttons) return; await addFeatureButton( "increasePlaybackSpeedButton", @@ -126,7 +116,6 @@ export const addIncreasePlaybackSpeedButton: AddButtonFunction = async () => { }; export const addDecreasePlaybackSpeedButton: AddButtonFunction = async () => { - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { @@ -135,7 +124,7 @@ export const addDecreasePlaybackSpeedButton: AddButtonFunction = async () => { playback_buttons_speed: playbackSpeedPerClick } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); if (!enable_playback_speed_buttons) return; await addFeatureButton( "decreasePlaybackSpeedButton", From f75ca53cb3a2a6cee0895dab7e0a3fa115b559c2 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 13:56:12 +0400 Subject: [PATCH 14/33] refactor: player speed --- src/features/playerSpeed/index.ts | 64 ++++++++++++++----------------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/src/features/playerSpeed/index.ts b/src/features/playerSpeed/index.ts index 0d684cfb8..1d033d7b8 100644 --- a/src/features/playerSpeed/index.ts +++ b/src/features/playerSpeed/index.ts @@ -24,15 +24,13 @@ export async function setPlayerSpeed(input?: number): Promise { // If the input is a number, set the player speed to the given number if (input === undefined) { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); ({ data: { options: { enable_forced_playback_speed: enablePlayerSpeed, player_speed: playerSpeed } } - } = optionsData); - } else if (typeof input === "number") { - playerSpeed = input; - } + } = await waitForSpecificMessage("options", "request_data", "content")); + } else playerSpeed = input; + // If the player speed is not specified, return if (!playerSpeed) return; // If forced playback speed option is disabled, return @@ -95,9 +93,7 @@ export function setupPlaybackSpeedChangeListener() { let playerSpeed: number = 1; if (speedValueRegex.test(speedValue)) { const speedValueMatch = speedValue.match(speedValueRegex); - if (speedValueMatch) { - playerSpeed = Number(speedValueMatch[1]); - } + if (speedValueMatch) playerSpeed = Number(speedValueMatch[1]); } window.localStorage.setItem("playerSpeed", String(playerSpeed)); }; @@ -130,31 +126,29 @@ export function setupPlaybackSpeedChangeListener() { }); const config: MutationObserverInit = { childList: true, subtree: true }; - if (settingsPanelMenu) { - playerSpeedMenuObserver.observe(settingsPanelMenu, config); - customSpeedSliderObserver.observe(settingsPanelMenu, { - attributeFilter: ["aria-valuenow"], - attributes: true, - childList: true, - subtree: true - }); - const menuItems = [ - ...document.querySelectorAll('div.ytp-settings-menu:not(#yte-feature-menu) > .ytp-panel > .ytp-panel-menu [role="menuitem"]') - ]; - const speedMenuItem = menuItems.find( - (el) => - el.children[0].innerHTML === - `` - ); - if (!speedMenuItem) return; - const { - children: [, , speedMenuItemContent] - } = speedMenuItem; - if (!speedMenuItemContent) return; - const { textContent: speedValue } = speedMenuItem; - // If the playback speed is not available, return - if (!speedValue) return; - const playerSpeed = isNaN(Number(speedValue)) ? 1 : Number(speedValue); - window.localStorage.setItem("playerSpeed", String(playerSpeed)); - } + if (!settingsPanelMenu) return; + playerSpeedMenuObserver.observe(settingsPanelMenu, config); + customSpeedSliderObserver.observe(settingsPanelMenu, { + attributeFilter: ["aria-valuenow"], + attributes: true, + childList: true, + subtree: true + }); + const menuItems = Array.from( + document.querySelectorAll('div.ytp-settings-menu:not(#yte-feature-menu) > .ytp-panel > .ytp-panel-menu [role="menuitem"]') + ); + const speedMenuItem = menuItems.find( + (el) => + el.children[0].innerHTML === + `` + ); + if (!speedMenuItem) return; + const { + children: [, , speedMenuItemContent], + textContent: speedValue + } = speedMenuItem; + // If the playback speed is not available, return + if (!speedMenuItemContent || !speedValue) return; + const playerSpeed = isNaN(Number(speedValue)) ? 1 : Number(speedValue); + window.localStorage.setItem("playerSpeed", String(playerSpeed)); } From 6cb943f6a1dea3700593cacfef1cf275ebfbdda7 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:07:46 +0400 Subject: [PATCH 15/33] refactor: remaining time --- src/features/remainingTime/index.ts | 7 ++----- src/features/remainingTime/utils.ts | 9 ++------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/features/remainingTime/index.ts b/src/features/remainingTime/index.ts index 1abdc1cc2..325bcd4a7 100644 --- a/src/features/remainingTime/index.ts +++ b/src/features/remainingTime/index.ts @@ -30,12 +30,11 @@ function playerTimeUpdateListener() { } export async function setupRemainingTime() { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_remaining_time } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); // If remaining time option is disabled, return if (!enable_remaining_time) return; const timeDisplay = document.querySelector(".ytp-time-display > span:nth-of-type(2)"); @@ -58,9 +57,7 @@ export async function setupRemainingTime() { const remainingTimeElement = document.querySelector("span#ytp-time-remaining") ?? document.createElement("span"); // If the video is live return - if (playerVideoData.isLive && remainingTimeElementExists) { - remainingTimeElement.remove(); - } + if (playerVideoData.isLive && remainingTimeElementExists) remainingTimeElement.remove(); if (!remainingTimeElementExists) { remainingTimeElement.id = "ytp-time-remaining"; remainingTimeElement.textContent = remainingTime; diff --git a/src/features/remainingTime/utils.ts b/src/features/remainingTime/utils.ts index b255782b4..7194c1b50 100644 --- a/src/features/remainingTime/utils.ts +++ b/src/features/remainingTime/utils.ts @@ -9,13 +9,8 @@ export function formatTime(timeInSeconds: number) { ]; const formattedUnits: string[] = units.reduce((acc: string[], unit) => { - if (acc.length > 0) { - acc.push(unit.toString().padStart(2, "0")); - } else { - if (unit > 0) { - acc.push(unit.toString()); - } - } + if (acc.length > 0) acc.push(unit.toString().padStart(2, "0")); + else if (unit > 0) acc.push(unit.toString()); return acc; }, []); From 11eed28430ad231e6ea4e90254fa95e843bdb433 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:08:11 +0400 Subject: [PATCH 16/33] refactor: remove redirect links --- src/features/removeRedirect/index.ts | 31 ++++++++++++---------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/features/removeRedirect/index.ts b/src/features/removeRedirect/index.ts index 0f17f6b22..6ffa7ccd8 100644 --- a/src/features/removeRedirect/index.ts +++ b/src/features/removeRedirect/index.ts @@ -2,12 +2,11 @@ import { type Nullable } from "@/src/types"; import { browserColorLog, waitForSpecificMessage } from "@/src/utils/utilities"; export default async function enableRemoveRedirect() { - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_redirect_remover: removeRedirectEnabled } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); if (!removeRedirectEnabled) return; browserColorLog(`Enabling removeRedirect`, "FgMagenta"); const regex = /https\:\/\/www\.youtube\.com\/redirect\?.+/gm; @@ -16,26 +15,22 @@ export default async function enableRemoveRedirect() { ".yt-core-attributed-string__link, .yt-simple-endpoint.style-scope.yt-formatted-string" ); links.forEach((link: HTMLElement) => { - const href: null | string = link.getAttribute("href"); - if (href && href.match(regex)) { - const urlParams: URLSearchParams = new URLSearchParams(href); - link.setAttribute("href", urlParams.get("q") || ""); - } + const href: Nullable = link.getAttribute("href"); + if (!href || !href.match(regex)) return; + const urlParams: URLSearchParams = new URLSearchParams(href); + link.setAttribute("href", urlParams.get("q") || ""); }); const callback: MutationCallback = (mutationsList: MutationRecord[]) => { for (const mutation of mutationsList) { - if (mutation.type === "childList") { - mutation.addedNodes.forEach((node: Nullable) => { - if (node instanceof Element && node.hasAttribute("href")) { - const href: null | string = node.getAttribute("href"); - if (href !== null && href.match(regex)) { - const urlParams: URLSearchParams = new URLSearchParams(href); - node.setAttribute("href", urlParams.get("q") || ""); - } - } - }); - } + if (mutation.type !== "childList") return; + mutation.addedNodes.forEach((node: Nullable) => { + if (node instanceof Element === false || !node.hasAttribute("href")) return; + const href: Nullable = node.getAttribute("href"); + if (!href || !href.match(regex)) return; + const urlParams = new URLSearchParams(href); + node.setAttribute("href", urlParams.get("q") || ""); + }); } }; From f5d0dccc0c5e1b8b387f2c6cbf86e297f9965824 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:08:34 +0400 Subject: [PATCH 17/33] refactor: screenshot button --- src/features/screenshotButton/index.ts | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/features/screenshotButton/index.ts b/src/features/screenshotButton/index.ts index c1b4321ef..f7dc27071 100644 --- a/src/features/screenshotButton/index.ts +++ b/src/features/screenshotButton/index.ts @@ -23,12 +23,11 @@ async function takeScreenshot(videoElement: HTMLVideoElement) { context.drawImage(videoElement, 0, 0, canvas.width, canvas.height); // Wait for the options message and get the format from it - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { screenshot_format, screenshot_save_as } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); const blob = await new Promise>((resolve) => canvas.toBlob(resolve, "image/png")); if (!blob) return; @@ -46,9 +45,7 @@ async function takeScreenshot(videoElement: HTMLVideoElement) { listener(); const clipboardImage = new ClipboardItem({ "image/png": blob }); void navigator.clipboard.write([clipboardImage]); - setTimeout(() => { - remove(); - }, 1200); + setTimeout(() => remove(), 1200); break; } case "file": { @@ -65,7 +62,6 @@ async function takeScreenshot(videoElement: HTMLVideoElement) { export const addScreenshotButton: AddButtonFunction = async () => { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { @@ -73,7 +69,7 @@ export const addScreenshotButton: AddButtonFunction = async () => { enable_screenshot_button: enableScreenshotButton } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); // If the screenshot button option is disabled, return if (!enableScreenshotButton) return; @@ -84,12 +80,8 @@ export const addScreenshotButton: AddButtonFunction = async () => { const videoElement = document.querySelector("video"); // If video element is not available, return if (!videoElement) return; - try { - // Take a screenshot - await takeScreenshot(videoElement); - } catch (error) { - console.error(error); - } + // Take a screenshot + await takeScreenshot(videoElement).catch(console.error); })(); } await addFeatureButton( From 82bc5bc88a2a87b087d7f9faa3adf59e8bcd8f42 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:08:55 +0400 Subject: [PATCH 18/33] refactor: scroll wheel speed control --- src/features/scrollWheelSpeedControl/index.ts | 14 +++----------- src/features/scrollWheelSpeedControl/utils.ts | 5 ++--- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/features/scrollWheelSpeedControl/index.ts b/src/features/scrollWheelSpeedControl/index.ts index 3070b5007..d0e98f152 100644 --- a/src/features/scrollWheelSpeedControl/index.ts +++ b/src/features/scrollWheelSpeedControl/index.ts @@ -30,14 +30,10 @@ export default async function adjustSpeedOnScrollWheel() { if (playerVideoData.isLive) return; // Define the event handler for the scroll wheel events const handleWheel = (event: Event) => { - const setOptionsData = async () => { - return (optionsData = await waitForSpecificMessage("options", "request_data", "content")); - }; + const setOptionsData = async () => (optionsData = await waitForSpecificMessage("options", "request_data", "content")); void (async () => { - if (!optionsData) { - return void (await setOptionsData()); - } + if (!optionsData) return void (await setOptionsData()); const { data: { options: { @@ -87,11 +83,7 @@ export default async function adjustSpeedOnScrollWheel() { playerContainer: playerContainer }, "yte-osd", - { - max: 4, - type: "speed", - value: newSpeed - } + { max: 4, type: "speed", value: newSpeed } ); })(); }; diff --git a/src/features/scrollWheelSpeedControl/utils.ts b/src/features/scrollWheelSpeedControl/utils.ts index eeea217cb..33e937e43 100644 --- a/src/features/scrollWheelSpeedControl/utils.ts +++ b/src/features/scrollWheelSpeedControl/utils.ts @@ -18,8 +18,7 @@ export function adjustSpeed( ): Promise<{ newSpeed: number; oldSpeed: number }> { return new Promise((resolve) => { void (async () => { - if (!playerContainer.getPlaybackRate) return; - if (!playerContainer.setPlaybackRate) return; + if (!playerContainer.getPlaybackRate || !playerContainer.setPlaybackRate) return; const video = playerContainer.querySelector("video"); if (!video) return; const { playbackRate: speed } = video; @@ -38,7 +37,7 @@ export function adjustSpeed( * @param listener - The event listener function. */ export function setupScrollListeners(selector: Selector, handleWheel: (event: Event) => void) { - const elements: NodeListOf = document.querySelectorAll(selector); + const elements = document.querySelectorAll(selector); if (!elements.length) return browserColorLog(`No elements found with selector ${selector}`, "FgRed"); for (const element of elements) { eventManager.addEventListener(element, "wheel", handleWheel, "scrollWheelSpeedControl", { passive: false }); From 279a22b80930396af1ee99da25ab3a0cc69a948e Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:09:08 +0400 Subject: [PATCH 19/33] refactor: scroll wheel volume control --- src/features/scrollWheelVolumeControl/index.ts | 15 +++------------ src/features/scrollWheelVolumeControl/utils.ts | 11 +++-------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/src/features/scrollWheelVolumeControl/index.ts b/src/features/scrollWheelVolumeControl/index.ts index d7087f028..da56476f1 100644 --- a/src/features/scrollWheelVolumeControl/index.ts +++ b/src/features/scrollWheelVolumeControl/index.ts @@ -31,14 +31,9 @@ export default async function adjustVolumeOnScrollWheel(): Promise { const settingsPanelMenu = document.querySelector("div.ytp-settings-menu:not(#yte-feature-menu)"); // If the settings panel menu is targeted return if (settingsPanelMenu && settingsPanelMenu.contains(event.target as Node)) return; - const setOptionsData = async () => { - return (optionsData = await waitForSpecificMessage("options", "request_data", "content")); - }; - + const setOptionsData = async () => (optionsData = await waitForSpecificMessage("options", "request_data", "content")); void (async () => { - if (!optionsData) { - return void (await setOptionsData()); - } + if (!optionsData) return void (await setOptionsData()); const { data: { options: { @@ -100,11 +95,7 @@ export default async function adjustVolumeOnScrollWheel(): Promise { playerContainer: playerContainer }, "yte-osd", - { - max: 100, - type: "volume", - value: newVolume - } + { max: 100, type: "volume", value: newVolume } ); })(); }; diff --git a/src/features/scrollWheelVolumeControl/utils.ts b/src/features/scrollWheelVolumeControl/utils.ts index 947f319e4..15cbeb5b8 100644 --- a/src/features/scrollWheelVolumeControl/utils.ts +++ b/src/features/scrollWheelVolumeControl/utils.ts @@ -18,17 +18,12 @@ export function adjustVolume( ): Promise<{ newVolume: number; oldVolume: number }> { return new Promise((resolve) => { void (async () => { - if (!playerContainer.getVolume) return; - if (!playerContainer.setVolume) return; - if (!playerContainer.isMuted) return; - if (!playerContainer.unMute) return; + if (!playerContainer.getVolume || !playerContainer.setVolume || !playerContainer.isMuted || !playerContainer.unMute) return; const [volume, isMuted] = await Promise.all([playerContainer.getVolume(), playerContainer.isMuted()]); const newVolume = clamp(toDivisible(volume + scrollDelta * volumeStep, volumeStep), 0, 100); browserColorLog(`Adjusting volume by ${volumeStep} to ${newVolume}. Old volume was ${volume}`, "FgMagenta"); await playerContainer.setVolume(newVolume); - if (isMuted) { - if (typeof playerContainer.unMute === "function") await playerContainer.unMute(); - } + if (isMuted && typeof playerContainer.unMute === "function") await playerContainer.unMute(); resolve({ newVolume, oldVolume: volume }); })(); }); @@ -40,7 +35,7 @@ export function adjustVolume( * @param listener - The event listener function. */ export function setupScrollListeners(selector: Selector, handleWheel: (event: Event) => void) { - const elements: NodeListOf = document.querySelectorAll(selector); + const elements = document.querySelectorAll(selector); if (!elements.length) return browserColorLog(`No elements found with selector ${selector}`, "FgRed"); for (const element of elements) { eventManager.addEventListener(element, "wheel", handleWheel, "scrollWheelVolumeControl", { passive: false }); From 86c2cee2842e6b3e15868df29405e976fb0ef755 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:09:23 +0400 Subject: [PATCH 20/33] refactor: share shortener --- src/features/shareShortener/index.ts | 36 ++++++++++------------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/src/features/shareShortener/index.ts b/src/features/shareShortener/index.ts index f5bb3ea07..384741a85 100644 --- a/src/features/shareShortener/index.ts +++ b/src/features/shareShortener/index.ts @@ -2,7 +2,7 @@ import { browserColorLog, waitForSpecificMessage } from "@/src/utils/utilities"; const regexp: RegExp = new RegExp("(\\?|&)(si|feature|pp)=[^&]*", "g"); let intervalId: NodeJS.Timeout | null = null; let input: HTMLInputElement | null; -function cleanUrl(url: string): string { +function cleanUrl(url: string) { return url.replace(regexp, ""); } @@ -13,14 +13,10 @@ function cleanAndUpdateUrl() { input = null; } intervalId = setInterval(() => { - if (!input) { - input = document.querySelector("#share-url"); - } - if (input) { - if (!input.value.match(regexp)) return; - console.log("cleanAndUpdateUrl"); - input.value = cleanUrl(input.value); - } + if (!input) return void (input = document.querySelector("#share-url")); + if (!input.value.match(regexp)) return; + console.log("cleanAndUpdateUrl"); + input.value = cleanUrl(input.value); }, 50); } @@ -28,28 +24,23 @@ function cleanSearchPage(url: string) { if (!url.match(/https?:\/\/(?:www\.)?youtube\.com\/results\?search\_query\=.+/gm)) return; const allElements = Array.from(document.querySelectorAll("*")); allElements.forEach((e) => { - const href: null | string = e.getAttribute("href"); - if (href && href.match(/^\/watch\?v\=.+$/gm)) { - e.setAttribute("href", href.replace(regexp, "")); - } + const href = e.getAttribute("href"); + if (!href || !href.match(/^\/watch\?v\=.+$/gm)) return; + e.setAttribute("href", href.replace(regexp, "")); }); } function handleInput(event: MouseEvent) { const element = event.target as Element; - if (!element.classList.contains("yt-spec-touch-feedback-shape__fill")) { - return; - } - cleanAndUpdateUrl(); + if (element.classList.contains("yt-spec-touch-feedback-shape__fill")) cleanAndUpdateUrl(); } export async function enableShareShortener() { - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_share_shortener } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); if (!enable_share_shortener) return; cleanSearchPage(window.location.href); document.addEventListener("click", handleInput); @@ -58,8 +49,7 @@ export async function enableShareShortener() { export function disableShareShortener() { browserColorLog(`Disabling share shortener`, "FgMagenta"); document.removeEventListener("click", handleInput); - if (intervalId) { - clearInterval(intervalId); - intervalId = null; - } + if (!intervalId) return; + clearInterval(intervalId); + intervalId = null; } From 29afd29eb4e7ce44c509957e72f863656c72ac4b Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:09:52 +0400 Subject: [PATCH 21/33] refactor: auto scroll shorts --- src/features/shortsAutoScroll/index.ts | 3 +-- src/features/shortsAutoScroll/utils.ts | 12 +++++------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/features/shortsAutoScroll/index.ts b/src/features/shortsAutoScroll/index.ts index 8b0a9f67c..155dc3332 100644 --- a/src/features/shortsAutoScroll/index.ts +++ b/src/features/shortsAutoScroll/index.ts @@ -7,12 +7,11 @@ import { isShortsPage, waitForAllElements, waitForSpecificMessage } from "@/src/ export async function enableShortsAutoScroll() { if (!isShortsPage()) return; // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_shorts_auto_scroll } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); // If the shorts auto scroll option is disabled, return if (!enable_shorts_auto_scroll) return; await waitForAllElements(["#shorts-player"]); diff --git a/src/features/shortsAutoScroll/utils.ts b/src/features/shortsAutoScroll/utils.ts index 68003a8cd..aeac310e5 100644 --- a/src/features/shortsAutoScroll/utils.ts +++ b/src/features/shortsAutoScroll/utils.ts @@ -10,13 +10,11 @@ export const setupAutoScroll = (playerContainer: YouTubePlayerDiv, video: HTMLVi const currentTime = Math.floor(progressState.current); const duration = Math.floor(progressState.duration); - if (currentTime === duration) { - eventManager.removeEventListener(video, "timeupdate", "shortsAutoScroll"); - const nextButton = document.querySelector("#navigation-button-down > ytd-button-renderer > yt-button-shape > button"); - if (!nextButton) return; - // Click the next button - nextButton.click(); - } + if (currentTime !== duration) return; + eventManager.removeEventListener(video, "timeupdate", "shortsAutoScroll"); + const nextButton = document.querySelector("#navigation-button-down > ytd-button-renderer > yt-button-shape > button"); + // Click the next button + nextButton?.click(); }; eventManager.addEventListener(video, "timeupdate", shortTimeUpdate, "shortsAutoScroll"); }; From dc4aca8421258afaf93331ea2bcff973a88dac21 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:10:01 +0400 Subject: [PATCH 22/33] refactor: video history --- src/features/videoHistory/index.ts | 49 ++++++++++-------------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/src/features/videoHistory/index.ts b/src/features/videoHistory/index.ts index fd06fd91b..2857fbe48 100644 --- a/src/features/videoHistory/index.ts +++ b/src/features/videoHistory/index.ts @@ -14,12 +14,11 @@ import { } from "@/utils/utilities"; export async function setupVideoHistory() { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_video_history: enableVideoHistory } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); if (!enableVideoHistory) return; // Get the player container element const playerContainer = @@ -53,12 +52,11 @@ export async function setupVideoHistory() { } export async function promptUserToResumeVideo(cb: () => void) { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_video_history: enableVideoHistory, video_history_resume_type } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); if (!enableVideoHistory) return; // Get the player container element @@ -74,22 +72,16 @@ export async function promptUserToResumeVideo(cb: () => void) { if (!videoId) return; const videoHistoryOneData = await waitForSpecificMessage("videoHistoryOne", "request_data", "content", { id: videoId }); - if (!videoHistoryOneData) { - cb(); - return; - } + if (!videoHistoryOneData) return cb(); + const { data: { video_history_entry } } = videoHistoryOneData; if (video_history_entry && video_history_entry.status === "watching" && video_history_entry.timestamp > 0) { - if (video_history_resume_type === "automatic") { - void playerContainer.seekTo(video_history_entry.timestamp, true); - return cb(); - } - createResumePrompt(video_history_entry, playerContainer, cb); - } else { - cb(); + if (video_history_resume_type !== "automatic") return createResumePrompt(video_history_entry, playerContainer, cb); + void playerContainer.seekTo(video_history_entry.timestamp, true); } + cb(); } // Utility function to check if an element exists const elementExists = (elementId: string) => !!document.getElementById(elementId); @@ -180,11 +172,8 @@ function createResumePrompt(videoHistoryEntry: VideoHistoryEntry, playerContaine const elapsed = round(timestamp - start); const progress = round(Math.min(elapsed / (progressBarDuration * 1000), 1), 2); progressBar.style.width = `${round((1 - progress) * 100, 2)}%`; - if (progress < 1) { - animationFrameId = requestAnimationFrame(updateResumeProgress); - } else { - hidePrompt(); - } + if (progress < 1) animationFrameId = requestAnimationFrame(updateResumeProgress); + else hidePrompt(); } animationFrameId = requestAnimationFrame(updateResumeProgress); } @@ -202,13 +191,10 @@ function createResumePrompt(videoHistoryEntry: VideoHistoryEntry, playerContaine cb(); } - if (!elementExists(progressBarId)) { - prompt.appendChild(progressBar); - } + if (!elementExists(progressBarId)) prompt.appendChild(progressBar); + + if (!elementExists(closeButtonId)) prompt.appendChild(closeButton); - if (!elementExists(closeButtonId)) { - prompt.appendChild(closeButton); - } const { listener: resumePromptCloseButtonMouseOverListener } = createTooltip({ element: closeButton, featureName: "videoHistory", @@ -220,17 +206,14 @@ function createResumePrompt(videoHistoryEntry: VideoHistoryEntry, playerContaine startCountdown(); - const closeListener = () => { - hidePrompt(); - }; + const closeListener = () => hidePrompt(); eventManager.removeEventListener(resumeButton, "click", "videoHistory"); eventManager.addEventListener(resumeButton, "click", resumeButtonClickListener, "videoHistory"); eventManager.removeEventListener(closeButton, "click", "videoHistory"); eventManager.addEventListener(closeButton, "click", closeListener, "videoHistory"); // Display the prompt - if (!elementExists(promptId)) { - prompt.appendChild(resumeButton); - playerContainer.appendChild(prompt); - } + if (elementExists(promptId)) return; + prompt.appendChild(resumeButton); + playerContainer.appendChild(prompt); } From 7865dfcdf6488229a988dc7217c26728785a7069 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:10:22 +0400 Subject: [PATCH 23/33] refactor: volume boost logic --- src/features/volumeBoost/index.ts | 70 +++++++++++++------------------ 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/src/features/volumeBoost/index.ts b/src/features/volumeBoost/index.ts index 8baeaf1c7..fada61ca9 100644 --- a/src/features/volumeBoost/index.ts +++ b/src/features/volumeBoost/index.ts @@ -7,56 +7,48 @@ import eventManager from "@/src/utils/EventManager"; import { browserColorLog, formatError, waitForSpecificMessage } from "@/src/utils/utilities"; export default async function volumeBoost() { - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); - const { data: { options: { enable_volume_boost, volume_boost_amount, volume_boost_mode } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); if (!enable_volume_boost) return; setupVolumeBoost(); - if (volume_boost_mode === "per_video") { - await addVolumeBoostButton(); - } else if (volume_boost_mode === "global") { - applyVolumeBoost(volume_boost_amount); - } + if (volume_boost_mode === "per_video") await addVolumeBoostButton(); + else if (volume_boost_mode === "global") applyVolumeBoost(volume_boost_amount); } export async function enableVolumeBoost() { setupVolumeBoost(); - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { volume_boost_amount } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); applyVolumeBoost(volume_boost_amount); } function setupVolumeBoost() { - if (!window.audioCtx || !window.gainNode) { - browserColorLog(`Enabling volume boost`, "FgMagenta"); - try { - const player = document.querySelector("video"); - if (!player) return; - window.audioCtx = new (window.AudioContext || window.webkitAudioContext)(); - const source = window.audioCtx.createMediaElementSource(player); - const gainNode = window.audioCtx.createGain(); - source.connect(gainNode); - gainNode.connect(window.audioCtx.destination); - window.gainNode = gainNode; - } catch (error) { - browserColorLog(`Failed to enable volume boost: ${formatError(error)}`, "FgRed"); - } + if (window.audioCtx && window.gainNode) return; + browserColorLog(`Enabling volume boost`, "FgMagenta"); + try { + const player = document.querySelector("video"); + if (!player) return; + window.audioCtx = new (window.AudioContext || window.webkitAudioContext)(); + const source = window.audioCtx.createMediaElementSource(player); + const gainNode = window.audioCtx.createGain(); + source.connect(gainNode); + gainNode.connect(window.audioCtx.destination); + window.gainNode = gainNode; + } catch (error) { + browserColorLog(`Failed to enable volume boost: ${formatError(error)}`, "FgRed"); } } export function disableVolumeBoost() { - if (window.gainNode) { - browserColorLog(`Disabling volume boost`, "FgMagenta"); - window.gainNode.gain.value = 1; // Set gain back to default - } + if (!window.gainNode) return; + browserColorLog(`Disabling volume boost`, "FgMagenta"); + window.gainNode.gain.value = 1; // Set gain back to default } export function applyVolumeBoost(volume_boost_amount: number) { browserColorLog(`Setting volume boost to ${Math.pow(10, volume_boost_amount / 20)}`, "FgMagenta"); @@ -64,15 +56,13 @@ export function applyVolumeBoost(volume_boost_amount: number) { window.gainNode.gain.value = Math.pow(10, volume_boost_amount / 20); } export const addVolumeBoostButton: AddButtonFunction = async () => { - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); - const { data: { options: { button_placements: { volumeBoostButton: volumeBoostButtonPlacement } } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); await addFeatureButton( "volumeBoostButton", volumeBoostButtonPlacement, @@ -82,17 +72,13 @@ export const addVolumeBoostButton: AddButtonFunction = async () => { getFeatureIcon("volumeBoostButton", volumeBoostButtonPlacement !== "feature_menu" ? "shared_icon_position" : "feature_menu"), (checked) => { void (async () => { - if (checked !== undefined) { - updateFeatureButtonTitle( - "volumeBoostButton", - window.i18nextInstance.t(`pages.content.features.volumeBoostButton.button.toggle.${checked ? "on" : "off"}`) - ); - if (checked) { - await enableVolumeBoost(); - } else { - disableVolumeBoost(); - } - } + if (checked === undefined) return; + updateFeatureButtonTitle( + "volumeBoostButton", + window.i18nextInstance.t(`pages.content.features.volumeBoostButton.button.toggle.${checked ? "on" : "off"}`) + ); + if (checked) await enableVolumeBoost(); + else disableVolumeBoost(); })(); }, true From 3151b940d0a2fd2bef800bdc8b9313ec22079cbb Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:11:30 +0400 Subject: [PATCH 24/33] refactor: pause background players untested --- src/features/pauseBackgroundPlayers/index.ts | 37 +++++++------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/src/features/pauseBackgroundPlayers/index.ts b/src/features/pauseBackgroundPlayers/index.ts index 874093b69..fefcc3477 100644 --- a/src/features/pauseBackgroundPlayers/index.ts +++ b/src/features/pauseBackgroundPlayers/index.ts @@ -1,3 +1,5 @@ +import type { Nullable } from "@/src/types"; + import { browserColorLog, sendContentToBackgroundMessage, waitForSpecificMessage } from "@/src/utils/utilities"; const PauseBackgroundPlayers = () => { @@ -7,53 +9,40 @@ const PauseBackgroundPlayers = () => { }; export async function enablePauseBackgroundPlayers() { - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_pausing_background_players: pauseBackgroundPlayersEnabled } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); if (!pauseBackgroundPlayersEnabled) return; // ignore home page and channel pages if (window.location.href.match(/^https?:\/\/(?:www\.)?youtube\.com(\/?|\/channel\/.+|\/\@.+)$/gm)) return; browserColorLog("Enabling pauseBackgroundPlayers", "FgMagenta"); - let videoPlayerContainer: HTMLVideoElement | null = null; - if (!videoPlayerContainer) { - videoPlayerContainer = document.querySelector(".html5-main-video"); - } + let videoPlayerContainer: Nullable = null; + if (!videoPlayerContainer) videoPlayerContainer = document.querySelector(".html5-main-video"); + function detectPlaying() { - if (videoPlayerContainer) { - videoPlayerContainer.addEventListener("playing", PauseBackgroundPlayers); - } + videoPlayerContainer?.addEventListener("playing", PauseBackgroundPlayers); } - let debounceTimeout: null | number = null; + let debounceTimeout: Nullable = null; const observer = new MutationObserver((mutationsList: MutationRecord[]) => { if (debounceTimeout) clearTimeout(debounceTimeout); - // @ts-expect-error - doesn't recognize browser environment properly - debounceTimeout = setTimeout(() => { + debounceTimeout = window.setTimeout(() => { for (const mutation of mutationsList) { - if (mutation.addedNodes.length) { - detectPlaying(); - } + if (mutation.addedNodes.length) detectPlaying(); } }, 100); }); - if (videoPlayerContainer) { - observer.observe(videoPlayerContainer, { childList: true, subtree: true }); - } - if (!videoPlayerContainer?.paused) { - PauseBackgroundPlayers(); - } + if (videoPlayerContainer) observer.observe(videoPlayerContainer, { childList: true, subtree: true }); + if (!videoPlayerContainer?.paused) PauseBackgroundPlayers(); detectPlaying(); } export function disablePauseBackgroundPlayers() { const videoPlayerContainer: HTMLElement | null = document.querySelector(".html5-main-video"); - if (videoPlayerContainer) { - videoPlayerContainer.removeEventListener("playing", PauseBackgroundPlayers); - } + if (videoPlayerContainer) videoPlayerContainer.removeEventListener("playing", PauseBackgroundPlayers); browserColorLog("Disabling pauseBackgroundPlayers", "FgMagenta"); } From 59c9d0ad4034af73ce1904276a85cd8f7dd0dee3 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:11:42 +0400 Subject: [PATCH 25/33] refactor: player quality untested --- src/features/playerQuality/index.ts | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/features/playerQuality/index.ts b/src/features/playerQuality/index.ts index 7cf8553d0..af28f24ad 100644 --- a/src/features/playerQuality/index.ts +++ b/src/features/playerQuality/index.ts @@ -10,12 +10,11 @@ import { browserColorLog, chooseClosestQuality, isShortsPage, isWatchPage, waitF */ export default async function setPlayerQuality(): Promise { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_automatically_set_quality, player_quality } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); // If automatically set quality option is disabled, return if (!enable_automatically_set_quality) return; @@ -39,14 +38,14 @@ export default async function setPlayerQuality(): Promise { const availableQualityLevels = (await playerContainer.getAvailableQualityLevels()) as YoutubePlayerQualityLevel[]; // Check if the specified player quality is available - if (player_quality && player_quality !== "auto") { - const closestQuality = chooseClosestQuality(player_quality, availableQualityLevels); - if (!closestQuality) return; - // Log the message indicating the player quality being set - browserColorLog(`Setting player quality to ${closestQuality}`, "FgMagenta"); - - // Set the playback quality and update the default quality in the dataset - void playerContainer.setPlaybackQualityRange(closestQuality); - playerContainer.dataset.defaultQuality = closestQuality; - } + if (!player_quality || player_quality === "auto") return; + + const closestQuality = chooseClosestQuality(player_quality, availableQualityLevels); + if (!closestQuality) return; + // Log the message indicating the player quality being set + browserColorLog(`Setting player quality to ${closestQuality}`, "FgMagenta"); + + // Set the playback quality and update the default quality in the dataset + void playerContainer.setPlaybackQualityRange(closestQuality); + playerContainer.dataset.defaultQuality = closestQuality; } From f6383ac3d1a2b02fc5215173023d02fea6c1111f Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:11:53 +0400 Subject: [PATCH 26/33] refactor: remember volume untested --- src/features/rememberVolume/index.ts | 3 +-- src/features/rememberVolume/utils.ts | 35 ++++++++++++---------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/features/rememberVolume/index.ts b/src/features/rememberVolume/index.ts index bb29bf401..234c01611 100644 --- a/src/features/rememberVolume/index.ts +++ b/src/features/rememberVolume/index.ts @@ -12,12 +12,11 @@ import { setRememberedVolume, setupVolumeChangeListener } from "./utils"; */ export default async function enableRememberVolume(): Promise { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_remember_last_volume: enableRememberVolume, remembered_volumes: rememberedVolumes } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); // If the volume is not being remembered, return if (!enableRememberVolume) return; const IsWatchPage = isWatchPage(); diff --git a/src/features/rememberVolume/utils.ts b/src/features/rememberVolume/utils.ts index e8a10040a..91534b15f 100644 --- a/src/features/rememberVolume/utils.ts +++ b/src/features/rememberVolume/utils.ts @@ -4,12 +4,11 @@ import eventManager from "@/src/utils/EventManager"; import { browserColorLog, isShortsPage, isWatchPage, sendContentOnlyMessage, waitForSpecificMessage } from "@/src/utils/utilities"; export async function setupVolumeChangeListener() { // Wait for the "options" message from the content script - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_remember_last_volume: enableRememberVolume } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); // If the volume is not being remembered, return if (!enableRememberVolume) return; const IsWatchPage = isWatchPage(); @@ -29,13 +28,10 @@ export async function setupVolumeChangeListener() { void (async () => { if (!currentTarget) return; const newVolume = await playerContainer.getVolume(); - if (IsWatchPage) { - // Send a "setVolume" message to the content script - sendContentOnlyMessage("setRememberedVolume", { watchPageVolume: newVolume }); - } else if (IsShortsPage) { - // Send a "setVolume" message to the content script - sendContentOnlyMessage("setRememberedVolume", { shortsPageVolume: newVolume }); - } + // Send a "setVolume" message to the content script + if (IsWatchPage) sendContentOnlyMessage("setRememberedVolume", { watchPageVolume: newVolume }); + // Send a "setVolume" message to the content script + else if (IsShortsPage) sendContentOnlyMessage("setRememberedVolume", { shortsPageVolume: newVolume }); })(); }, "rememberVolume" @@ -55,16 +51,15 @@ export async function setRememberedVolume({ rememberedVolumes: configuration["remembered_volumes"]; }) { // If the remembered volume option is enabled, set the volume and draw the volume display - if (rememberedVolumes && enableRememberVolume) { - const { shortsPageVolume, watchPageVolume } = rememberedVolumes ?? {}; - if (isWatchPage && watchPageVolume) { - // Log the message indicating whether the last volume is being restored or not - browserColorLog(`Restoring watch page volume to ${watchPageVolume}`, "FgMagenta"); - await playerContainer.setVolume(watchPageVolume); - } else if (isShortsPage && shortsPageVolume) { - // Log the message indicating whether the last volume is being restored or not - browserColorLog(`Restoring shorts page volume to ${shortsPageVolume}`, "FgMagenta"); - await playerContainer.setVolume(shortsPageVolume); - } + if (!rememberedVolumes || !enableRememberVolume) return; + const { shortsPageVolume, watchPageVolume } = rememberedVolumes ?? {}; + if (isWatchPage && watchPageVolume) { + // Log the message indicating whether the last volume is being restored or not + browserColorLog(`Restoring watch page volume to ${watchPageVolume}`, "FgMagenta"); + await playerContainer.setVolume(watchPageVolume); + } else if (isShortsPage && shortsPageVolume) { + // Log the message indicating whether the last volume is being restored or not + browserColorLog(`Restoring shorts page volume to ${shortsPageVolume}`, "FgMagenta"); + await playerContainer.setVolume(shortsPageVolume); } } From 2205a63d34abfc5da219354eb2097fcffa1e2b4a Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:12:10 +0400 Subject: [PATCH 27/33] refactor: skip continue watching untested --- src/features/skipContinueWatching/index.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/features/skipContinueWatching/index.ts b/src/features/skipContinueWatching/index.ts index 53c71f00c..ca81b8b12 100644 --- a/src/features/skipContinueWatching/index.ts +++ b/src/features/skipContinueWatching/index.ts @@ -5,16 +5,14 @@ interface YtdWatchFlexyElement extends Element { } export async function enableSkipContinueWatching() { - const optionsData = await waitForSpecificMessage("options", "request_data", "content"); const { data: { options: { enable_skip_continue_watching } } - } = optionsData; + } = await waitForSpecificMessage("options", "request_data", "content"); if (!enable_skip_continue_watching) return; browserColorLog("Enabling skipContinueWatching", "FgMagenta"); const ytdWatchFlexyElement = document.querySelector("ytd-watch-flexy"); - if (ytdWatchFlexyElement) { - (ytdWatchFlexyElement as YtdWatchFlexyElement).youthereDataChanged_ = function () {}; - } + if (!ytdWatchFlexyElement) return; + (ytdWatchFlexyElement as YtdWatchFlexyElement).youthereDataChanged_ = function () {}; } From 4ea23fb0840a9d142701b43a8c9a8f6e9e63d06b Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:17:31 +0400 Subject: [PATCH 28/33] refactor: useNotifications provider --- src/hooks/useNotifications/provider.tsx | 26 +++++++------------------ 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/hooks/useNotifications/provider.tsx b/src/hooks/useNotifications/provider.tsx index 8f4ecb2f3..95e0b13ec 100644 --- a/src/hooks/useNotifications/provider.tsx +++ b/src/hooks/useNotifications/provider.tsx @@ -19,17 +19,12 @@ export const NotificationsProvider = ({ children }: NotificationProviderProps) = }; const createNotification: CreateNotification = (type, message, action) => { const removeNotificationAfterMs = action && action === "reset_settings" ? 15_000 : 5_000; - const notification = { action, message, removeAfterMs: removeNotificationAfterMs, timestamp: +new Date(), type } satisfies Notification; - - return notification; + return { action, message, removeAfterMs: removeNotificationAfterMs, timestamp: +new Date(), type } satisfies Notification; }; const scheduleNotificationRemoval: ScheduleNotificationRemoval = (notification, removeAfterMs) => { - if (removeAfterMs) { - setTimeout(() => { - removeNotification(notification); - }, removeAfterMs); - } + if (!removeAfterMs) return; + setTimeout(() => removeNotification(notification), removeAfterMs); }; const addNotification: AddNotification = (type, message, action) => { const notification = createNotification(type, message, action); @@ -52,14 +47,9 @@ export const NotificationsProvider = ({ children }: NotificationProviderProps) = const timePassed = now - (notification.timestamp ?? now); const { removeAfterMs: progressBarDuration } = notification; const progress = Math.max(100 - (timePassed / (progressBarDuration ?? 3000)) * 100, 0); - if (progress <= 0) { - // Automatically hide the notification when progress reaches 0 - return null; - } - return { - ...notification, - progress - }; + // Automatically hide the notification when progress reaches 0 + if (progress <= 0) return null; + return { ...notification, progress }; }) .filter(Boolean); }); @@ -67,9 +57,7 @@ export const NotificationsProvider = ({ children }: NotificationProviderProps) = }; updateNotifications(); return () => { - if (animationFrameId !== null) { - cancelAnimationFrame(animationFrameId); - } + if (animationFrameId) cancelAnimationFrame(animationFrameId); }; }, []); const contextValue = { addNotification, notifications, removeNotification } satisfies NotificationsContextProps; From 04f9aad0b5e416aac9d6c0e345a8d92dcd4bcd0f Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:47:45 +0400 Subject: [PATCH 29/33] refactor: pages --- src/pages/background/index.ts | 49 +++---- src/pages/content/index.ts | 20 +-- src/pages/embedded/index.ts | 241 +++++++++++----------------------- 3 files changed, 103 insertions(+), 207 deletions(-) diff --git a/src/pages/background/index.ts b/src/pages/background/index.ts index 25d484f30..f452f9191 100644 --- a/src/pages/background/index.ts +++ b/src/pages/background/index.ts @@ -49,37 +49,26 @@ chrome.runtime.onMessage.addListener((message: ContentToBackgroundSendOnlyMessag chrome.tabs.query({ url: "https://www.youtube.com/*" }, (tabs) => { for (const tab of tabs) { // Skip the active tab - if (tab.id === activeTabId) continue; - if (tab.id !== undefined) { - chrome.scripting.executeScript( - { - func: () => { - const videos = document.querySelectorAll("video"); - videos.forEach((video) => { - if (!video.paused) { - video.pause(); - } - }); - const audios = document.querySelectorAll("audio"); - audios.forEach((audio) => { - if (!audio.paused) { - audio.pause(); - } - }); - }, - target: { tabId: tab.id } + if (!tab.id || tab.id === activeTabId) continue; + chrome.scripting.executeScript( + { + func: () => { + const videos = document.querySelectorAll("video"); + videos.forEach((video) => { + if (!video.paused) video.pause(); + }); + const audios = document.querySelectorAll("audio"); + audios.forEach((audio) => { + if (!audio.paused) audio.pause(); + }); }, - (results) => { - if (chrome.runtime.lastError) { - console.error(chrome.runtime.lastError.message); - } else { - if (results[0].result) { - console.log(results); - } - } - } - ); - } + target: { tabId: tab.id } + }, + (results) => { + if (chrome.runtime.lastError) console.error(chrome.runtime.lastError.message); + else if (results[0].result) console.log(results); + } + ); } }); }); diff --git a/src/pages/content/index.ts b/src/pages/content/index.ts index 91d7a9fa4..4514b3931 100644 --- a/src/pages/content/index.ts +++ b/src/pages/content/index.ts @@ -148,15 +148,13 @@ document.addEventListener("yte-message-from-youtube", () => { case "pageLoaded": { chrome.storage.onChanged.addListener(storageListeners); - window.onunload = () => { - chrome.storage.onChanged.removeListener(storageListeners); - }; + window.onunload = () => chrome.storage.onChanged.removeListener(storageListeners); break; } case "videoHistoryOne": { - const { data } = message; - if (!data) return; - const { video_history_entry } = data; + const { + data: { video_history_entry } + } = message; if (!video_history_entry) return; const { id, status, timestamp } = video_history_entry; setVideoHistory(id, timestamp, status); @@ -223,12 +221,7 @@ const storageChangeHandler = async (changes: StorageChanges, areaName: string) = (acc, feature) => { const { [feature]: oldPlacement } = oldValue; const { [feature]: newPlacement } = newValue; - return Object.assign(acc, { - [feature]: { - new: newPlacement, - old: oldPlacement - } - }); + return Object.assign(acc, { [feature]: { new: newPlacement, old: oldPlacement } }); }, {} as Record ) @@ -415,8 +408,7 @@ const storageChangeHandler = async (changes: StorageChanges, areaName: string) = }; Object.entries(castedChanges).forEach(([key, change]) => { if (isValidChange(change)) { - if (!change.newValue) return; - if (!change.oldValue) return; + if (!change.newValue || !change.oldValue) return; const oldValue = parseStoredValue(change.oldValue) as configuration[typeof key]; const newValue = parseStoredValue(change.newValue) as configuration[typeof key]; const { [key]: handler } = keyActions; diff --git a/src/pages/embedded/index.ts b/src/pages/embedded/index.ts index 2d280886b..d5afd9841 100644 --- a/src/pages/embedded/index.ts +++ b/src/pages/embedded/index.ts @@ -169,11 +169,10 @@ const enableFeatures = () => { window.addEventListener("DOMContentLoaded", function () { void (async () => { - const response = await waitForSpecificMessage("language", "request_data", "content"); - if (!response) return; const { data: { language } - } = response; + } = await waitForSpecificMessage("language", "request_data", "content"); + if (!language) return; const i18nextInstance = await i18nService(language); window.i18nextInstance = i18nextInstance; // Listen to YouTube's soft navigate event @@ -207,16 +206,14 @@ window.addEventListener("DOMContentLoaded", function () { if (volumeBoostMode === "global") { await removeVolumeBoostButton(); await enableVolumeBoost(); - } else { - disableVolumeBoost(); - await addVolumeBoostButton(); + break; } - } else { disableVolumeBoost(); - if (volumeBoostMode === "per_video") { - await removeVolumeBoostButton(); - } + await addVolumeBoostButton(); + break; } + disableVolumeBoost(); + if (volumeBoostMode === "per_video") await removeVolumeBoostButton(); break; } case "volumeBoostAmountChange": { @@ -226,8 +223,7 @@ window.addEventListener("DOMContentLoaded", function () { switch (volumeBoostMode) { case "global": { - if (!volumeBoostEnabled) return; - applyVolumeBoost(volumeBoostAmount); + if (volumeBoostEnabled) applyVolumeBoost(volumeBoostAmount); break; } case "per_video": { @@ -245,43 +241,35 @@ window.addEventListener("DOMContentLoaded", function () { const { data: { enableForcedPlaybackSpeed, playerSpeed } } = message; - if (enableForcedPlaybackSpeed && playerSpeed) { - await setPlayerSpeed(Number(playerSpeed)); - } else if (!enableForcedPlaybackSpeed) { - restorePlayerSpeed(); - } + if (enableForcedPlaybackSpeed && playerSpeed) await setPlayerSpeed(Number(playerSpeed)); + else if (!enableForcedPlaybackSpeed) restorePlayerSpeed(); break; } case "screenshotButtonChange": { const { data: { screenshotButtonEnabled } } = message; - if (screenshotButtonEnabled) { - await addScreenshotButton(); - } else { - await removeScreenshotButton(); - } + if (screenshotButtonEnabled) await addScreenshotButton(); + else await removeScreenshotButton(); break; } case "maximizeButtonChange": { const { data: { maximizePlayerButtonEnabled } } = message; - if (maximizePlayerButtonEnabled) { - await addMaximizePlayerButton(); - } else { - await removeMaximizePlayerButton(); - const maximizePlayerButton = document.querySelector("video.html5-main-video"); - if (!maximizePlayerButton) return; - // Get the video element - const videoElement = document.querySelector("video.html5-main-video"); - // If video element is not available, return - if (!videoElement) return; - const videoContainer = document.querySelector("video.html5-main-video"); - if (!videoContainer) return; - if (videoContainer.classList.contains("maximized_video_container") && videoElement.classList.contains("maximized_video")) { - maximizePlayer(); - } + if (maximizePlayerButtonEnabled) return await addMaximizePlayerButton(); + + await removeMaximizePlayerButton(); + const maximizePlayerButton = document.querySelector("video.html5-main-video"); + if (!maximizePlayerButton) return; + // Get the video element + const videoElement = document.querySelector("video.html5-main-video"); + // If video element is not available, return + if (!videoElement) return; + const videoContainer = document.querySelector("video.html5-main-video"); + if (!videoContainer) return; + if (videoContainer.classList.contains("maximized_video_container") && videoElement.classList.contains("maximized_video")) { + maximizePlayer(); } break; } @@ -289,33 +277,24 @@ window.addEventListener("DOMContentLoaded", function () { const { data: { videoHistoryEnabled } } = message; - if (videoHistoryEnabled) { - await setupVideoHistory(); - } else { - eventManager.removeEventListeners("videoHistory"); - } + if (videoHistoryEnabled) await setupVideoHistory(); + else eventManager.removeEventListeners("videoHistory"); break; } case "remainingTimeChange": { const { data: { remainingTimeEnabled } } = message; - if (remainingTimeEnabled) { - await enableRemainingTime(); - } else { - removeRemainingTimeDisplay(); - } + if (remainingTimeEnabled) await enableRemainingTime(); + else removeRemainingTimeDisplay(); break; } case "loopButtonChange": { const { data: { loopButtonEnabled } } = message; - if (loopButtonEnabled) { - await addLoopButton(); - } else { - await removeLoopButton(); - } + if (loopButtonEnabled) await addLoopButton(); + else await removeLoopButton(); break; } case "playbackSpeedButtonsChange": { @@ -335,33 +314,24 @@ window.addEventListener("DOMContentLoaded", function () { const { data: { scrollWheelVolumeControlEnabled } } = message; - if (scrollWheelVolumeControlEnabled) { - await adjustVolumeOnScrollWheel(); - } else { - eventManager.removeEventListeners("scrollWheelVolumeControl"); - } + if (scrollWheelVolumeControlEnabled) await adjustVolumeOnScrollWheel(); + else eventManager.removeEventListeners("scrollWheelVolumeControl"); break; } case "scrollWheelSpeedControlChange": { const { data: { scrollWheelSpeedControlEnabled } } = message; - if (scrollWheelSpeedControlEnabled) { - await adjustSpeedOnScrollWheel(); - } else { - eventManager.removeEventListeners("scrollWheelSpeedControl"); - } + if (scrollWheelSpeedControlEnabled) await adjustSpeedOnScrollWheel(); + else eventManager.removeEventListeners("scrollWheelSpeedControl"); break; } case "rememberVolumeChange": { const { data: { rememberVolumeEnabled } } = message; - if (rememberVolumeEnabled) { - await enableRememberVolume(); - } else { - eventManager.removeEventListeners("rememberVolume"); - } + if (rememberVolumeEnabled) await enableRememberVolume(); + else eventManager.removeEventListeners("rememberVolume"); break; } case "hideScrollBarChange": { @@ -369,37 +339,24 @@ window.addEventListener("DOMContentLoaded", function () { const { data: { hideScrollBarEnabled } } = message; - if (hideScrollBarEnabled) { - if (!scrollBarHidden) { - hideScrollBar(); - } - } else { - if (scrollBarHidden) { - showScrollBar(); - } - } + if (hideScrollBarEnabled && !scrollBarHidden) hideScrollBar(); + if (!hideScrollBarEnabled && scrollBarHidden) showScrollBar(); break; } case "hideShortsChange": { const { data: { hideShortsEnabled } } = message; - if (hideShortsEnabled) { - await enableHideShorts(); - } else { - disableHideShorts(); - } + if (hideShortsEnabled) await enableHideShorts(); + else disableHideShorts(); break; } case "hideLiveStreamChatChange": { const { data: { hideLiveStreamChatEnabled } } = message; - if (hideLiveStreamChatEnabled) { - await enableHideLiveStreamChat(); - } else { - await disableHideLiveStreamChat(); - } + if (hideLiveStreamChatEnabled) await enableHideLiveStreamChat(); + else await disableHideLiveStreamChat(); break; } case "languageChange": { @@ -411,19 +368,14 @@ window.addEventListener("DOMContentLoaded", function () { updateFeatureMenuTitle(window.i18nextInstance.t("pages.content.features.featureMenu.button.label")); for (const feature of featuresInMenu) { const featureName = findKeyByValue(feature as MultiButtonNames) ?? (feature as SingleButtonFeatureNames); - if (featureToMultiButtonsMap.has(featureName)) { - updateFeatureMenuItemLabel( - feature, - window.i18nextInstance.t( + updateFeatureMenuItemLabel( + feature, + window.i18nextInstance.t( + featureToMultiButtonsMap.has(featureName) ? `pages.content.features.${featureName as MultiButtonFeatureNames}.buttons.${feature as MultiButtonNames}.label` - ) - ); - } else { - updateFeatureMenuItemLabel( - feature, - window.i18nextInstance.t(`pages.content.features.${featureName as SingleButtonNames}.button.label`) - ); - } + : `pages.content.features.${featureName as SingleButtonNames}.button.label` + ) + ); } } if (featuresInControls.size > 0) { @@ -438,21 +390,17 @@ window.addEventListener("DOMContentLoaded", function () { toggleFeature, window.i18nextInstance.t(`pages.content.features.${toggleFeature}.button.toggle.${buttonChecked ? "on" : "off"}`) ); - } else { - if (featureToMultiButtonsMap.has(featureName)) { - updateFeatureMenuItemLabel( - feature, - window.i18nextInstance.t( - `pages.content.features.${featureName as MultiButtonFeatureNames}.buttons.${feature as MultiButtonNames}.label` - ) - ); - } else { - updateFeatureButtonTitle( - feature, - window.i18nextInstance.t(`pages.content.features.${featureName as SingleButtonNames}.button.label`) - ); - } + return; } + + updateFeatureMenuItemLabel( + feature, + window.i18nextInstance.t( + featureToMultiButtonsMap.has(featureName) ? + `pages.content.features.${featureName as MultiButtonFeatureNames}.buttons.${feature as MultiButtonNames}.label` + : `pages.content.features.${featureName as SingleButtonNames}.button.label` + ) + ); } } break; @@ -484,94 +432,64 @@ window.addEventListener("DOMContentLoaded", function () { const { data: { openTranscriptButtonEnabled } } = message; - if (openTranscriptButtonEnabled) { - await openTranscriptButton(); - } else { - await removeOpenTranscriptButton(); - } + if (openTranscriptButtonEnabled) await openTranscriptButton(); + else await removeOpenTranscriptButton(); break; } case "openYTSettingsOnHoverChange": { const { data: { openYouTubeSettingsOnHoverEnabled } } = message; - if (openYouTubeSettingsOnHoverEnabled) { - await enableOpenYouTubeSettingsOnHover(); - } else { - disableOpenYouTubeSettingsOnHover(); - } + if (openYouTubeSettingsOnHoverEnabled) await enableOpenYouTubeSettingsOnHover(); + else disableOpenYouTubeSettingsOnHover(); break; } case "removeRedirectChange": { const { data: { removeRedirectEnabled } } = message; - if (removeRedirectEnabled) { - await enableRemoveRedirect(); - } + if (removeRedirectEnabled) await enableRemoveRedirect(); break; } case "pauseBackgroundPlayersChange": { const { data: { pauseBackgroundPlayersEnabled } } = message; - if (pauseBackgroundPlayersEnabled) { - await enablePauseBackgroundPlayers(); - } else { - disablePauseBackgroundPlayers(); - } + if (pauseBackgroundPlayersEnabled) await enablePauseBackgroundPlayers(); + else disablePauseBackgroundPlayers(); break; } case "shareShortenerChange": { const { data: { shareShortenerEnabled } } = message; - if (shareShortenerEnabled) { - await enableShareShortener(); - } else { - disableShareShortener(); - } + if (shareShortenerEnabled) await enableShareShortener(); + else disableShareShortener(); break; } case "skipContinueWatchingChange": { const { data: { skipContinueWatchingEnabled } } = message; - if (skipContinueWatchingEnabled) { - await enableSkipContinueWatching(); - } + if (skipContinueWatchingEnabled) await enableSkipContinueWatching(); break; } case "deepDarkThemeChange": { const { data: { deepDarkCustomThemeColors, deepDarkPreset, deepDarkThemeEnabled } } = message; - if (deepDarkThemeEnabled) { - if (deepDarkCSSExists()) { - updateDeepDarkCSS( - deepDarkPreset === "Custom" ? getDeepDarkCustomThemeStyle(deepDarkCustomThemeColors) : deepDarkPresets[deepDarkPreset] - ); - } else { - await enableDeepDarkCSS(); - } - } else { - disableDeepDarkCSS(); - } + if (!deepDarkThemeEnabled) return disableDeepDarkCSS(); + if (!deepDarkCSSExists()) return await enableDeepDarkCSS(); + updateDeepDarkCSS(deepDarkPreset === "Custom" ? getDeepDarkCustomThemeStyle(deepDarkCustomThemeColors) : deepDarkPresets[deepDarkPreset]); break; } case "customCSSChange": { const { data: { customCSSCode, customCSSEnabled } } = message; - if (customCSSEnabled) { - if (customCSSExists()) { - updateCustomCSS({ custom_css_code: customCSSCode }); - } else { - await enableCustomCSS(); - } - } else { - disableCustomCSS(); - } + if (!customCSSEnabled) return disableCustomCSS(); + if (!customCSSExists()) return enableCustomCSS(); + updateCustomCSS({ custom_css_code: customCSSCode }); break; } case "buttonPlacementChange": { @@ -595,11 +513,8 @@ window.addEventListener("DOMContentLoaded", function () { const { data: { shortsAutoScrollEnabled } } = message; - if (shortsAutoScrollEnabled) { - await enableShortsAutoScroll(); - } else { - disableShortsAutoScroll(); - } + if (shortsAutoScrollEnabled) await enableShortsAutoScroll(); + else disableShortsAutoScroll(); break; } default: { From 79f2303664ce4885609ad1da1fa5bed5ce8f3ba6 Mon Sep 17 00:00:00 2001 From: mist8kengas Date: Fri, 10 May 2024 14:48:47 +0400 Subject: [PATCH 30/33] feat(docs): add contributing page --- CONTRIBUTING.md | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..07e521ede --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,83 @@ +# Contributing + +## Table of Contents + +- [Glossary](#📚-glossary) +- [Getting Started](#🎉-getting-started) +- [Commits, Issues, and Pull Requests](#✏-commits-issues-and-pull-requests) +- [Contributor Workflow](#🗃-contributor-workflow) +- [Internationalization](#🌐-internationalization-i18n) +- [Code Quality](#🔧-code-quality) + +## 📚 Glossary + +Here are some terms that we interchangeably refer to in this document: + +- **Pull Request** (PR): Pull requests let you tell others about changes you've pushed to a branch in the repository. Once a pull request is opened, you can discuss and review the potential changes with collaborators and add follow-up commits before your changes are merged into the base branch. +- **Continuous Integration** (CI): A development practice where developers frequently integrate their code changes into a shared repository. Each integration triggers automated tests to ensure that the new code doesn't break existing functionality. CI aims to detect and fix integration errors quickly, promoting collaboration and maintaining a consistent codebase. +- **Continuous Development** (CD): An extension of Continuous Integration (CI) that focuses on automating the deployment of code changes to the production environment. + +## 🎉 Getting Started + +- Because our release CI/CD workflow is automated, we rely on commit messages that follow a format convention for semantic versioning[^1]. + As such, we use the [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) spec in commit messages. + +## ✏ Commits, Issues, and Pull Requests + +There are a few guidelines that we follow in order to maintain the quality of the codebase: + +- Make sure that commit messages are meaningful, and describe the commit itself. +- When creating [Bug Report Issues](https://github.com/YouTube-Enhancer/extension/issues/new?assignees=&labels=&projects=&template=bug_report.md&title=), make sure to follow the template and explain the issue in a clear and straightforward manner. +- Although we do not strictly enforce the [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) spec in pull requests, it is preferred over other ways of creating PR titles. +- In the description of the pull request, briefly describe the goal of the PR and the changes it will bring to the codebase. + +## 🗃 Contributor Workflow + +We use the "contributor workflow" to manage the code. Everyone suggests changes by making pull requests. This helps people contribute, make tests easier, and get feedback from others. + +To contribute to the codebase, the workflow is as follows: + +1. Fork the repository +2. Commit changes to the fork (using the `dev` branch) +3. Create a pull request (on the `dev` branch) + +_It is ill-advised to create pull requests against the `main` branch as `dev` changes are merged to the main branch in batches by the core maintainers._ + +> Read more about forking and making pull requests [here](https://docs.github.com/get-started/exploring-projects-on-github/contributing-to-a-project). + +## 🌐 Internationalization (i18n) + +### Crowdin Translation Project + +Our YouTube Enhancer extension supports multiple languages to provide a more inclusive experience for users around the world. We use Crowdin for managing translations. + +### Contributing Translations + +We welcome contributions to improve translations and make the extension accessible to a wider audience. If you'd like to contribute translations or suggest improvements, follow these steps: + +1. Visit our [Crowdin project](https://crowdin.com/project/youtube-enhancer). +2. Select your language and start translating. +3. If your language is not listed, feel free to request its addition. + +## 🔧 Code Quality + +Before new code gets merged into the repository, we do automated lint tests to verify the format of the code. + +It is recommended to test your code before committing by running the following commands: + +1. Lint check: `npm run lint` +2. Fix lint errors: `npm run lint:fix` + +> You won't need to do this if you use a supported editor[^2], as the process is automated. + +While we don't yet have a strict guideline on what kind of code should be in the repository, here are a few principles we loosely follow to maintain the general consistency of the code: + +- [DRY principle](https://en.wikipedia.org/wiki/Don't_repeat_yourself) +- [Rule of three]() +- [Single source of truth](https://en.wikipedia.org/wiki/Single_source_of_truth) + +--- + +[^1]: [Why Use Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#why-use-conventional-commits) +[^2]: [ESLint: A List of Editor Integrations](https://eslint.org/docs/latest/use/integrations#editors) + From 20631b6305a404dd65726602192306215cb5aefd Mon Sep 17 00:00:00 2001 From: livingflore Date: Sun, 16 Jun 2024 14:26:41 +0500 Subject: [PATCH 31/33] fix: eslint/prettier --- .../Inputs/CSSEditor/ExpandButton/index.tsx | 2 +- src/components/Inputs/Select/Select.tsx | 15 ++-- src/components/Settings/Settings.tsx | 19 ++-- src/defaults.ts | 12 ++- src/features/featureMenu/utils.ts | 2 +- src/features/hideEndScreenCards/index.ts | 6 +- src/features/loopButton/index.ts | 6 +- src/features/maximizePlayerButton/index.ts | 6 +- src/features/playbackSpeedButtons/index.ts | 25 +++--- src/features/playerQuality/index.ts | 7 +- src/features/playerSpeed/index.ts | 14 +-- src/features/remainingTime/index.ts | 14 +-- src/features/rememberVolume/index.ts | 7 +- src/features/rememberVolume/utils.ts | 7 +- src/features/scrollWheelSpeedControl/index.ts | 14 +-- .../scrollWheelVolumeControl/index.ts | 7 +- src/features/videoHistory/index.ts | 10 +-- src/features/volumeBoost/index.ts | 6 +- src/pages/embedded/index.ts | 57 ++++++------ src/types/index.ts | 86 ++++++++++--------- src/utils/OnScreenDisplayManager.ts | 11 ++- 21 files changed, 175 insertions(+), 158 deletions(-) diff --git a/src/components/Inputs/CSSEditor/ExpandButton/index.tsx b/src/components/Inputs/CSSEditor/ExpandButton/index.tsx index 529b2b1d7..52972304f 100644 --- a/src/components/Inputs/CSSEditor/ExpandButton/index.tsx +++ b/src/components/Inputs/CSSEditor/ExpandButton/index.tsx @@ -13,7 +13,7 @@ const ExpandButton = forwardRef(({ isExpand return ( ({ onClick={toggleSelect} type="button" > - {loading ? + {loading ? ( - : selectedOption ? - options.find((option) => option.value === selectedOption)?.element ? + ) : selectedOption ? ( + options.find((option) => option.value === selectedOption)?.element ? (
{options.find((option) => option.value === selectedOption)?.label} {options.find((option) => option.value === selectedOption)?.element}
- :
+ ) : ( +
{options.find((option) => option.value === selectedOption)?.label}
- - : Select an option} + ) + ) : ( + Select an option + )} {isSelectVisible && ( diff --git a/src/components/Settings/Settings.tsx b/src/components/Settings/Settings.tsx index 949d9252c..48f3815c7 100644 --- a/src/components/Settings/Settings.tsx +++ b/src/components/Settings/Settings.tsx @@ -1141,7 +1141,7 @@ export default function Settings() {
{isPopup && ( )} - {notifications.filter((n) => n.action === "reset_settings").length > 0 ? + {notifications.filter((n) => n.action === "reset_settings").length > 0 ? ( { const notificationToRemove = notifications.find((n) => n.action === "reset_settings"); @@ -1199,15 +1199,16 @@ export default function Settings() { type="button" value={t("settings.sections.bottomButtons.confirm.value")} /> - : - } + )}
diff --git a/src/defaults.ts b/src/defaults.ts index 9b75d72dc..bc282c514 100644 --- a/src/defaults.ts +++ b/src/defaults.ts @@ -20,13 +20,11 @@ function setDefaultValues() { try { // Parse the stored value to check its type const storedValue = - ( - typeof defaultConfiguration[option] === "object" || - typeof defaultConfiguration[option] === "boolean" || - typeof defaultConfiguration[option] === "number" - ) ? - JSON.parse(storedValueString) - : storedValueString; + typeof defaultConfiguration[option] === "object" || + typeof defaultConfiguration[option] === "boolean" || + typeof defaultConfiguration[option] === "number" + ? JSON.parse(storedValueString) + : storedValueString; // Check if the parsed value is an object and has properties if (typeof storedValue !== "object" || storedValue === null) continue; // Deep merge missing keys with their default values diff --git a/src/features/featureMenu/utils.ts b/src/features/featureMenu/utils.ts index 677f815de..c96fc30ad 100644 --- a/src/features/featureMenu/utils.ts +++ b/src/features/featureMenu/utils.ts @@ -96,7 +96,7 @@ export async function addFeatureItemToMenu { "hideEndScreenCardsButton", hideEndScreenCardsButtonPlacement, window.i18nextInstance.t( - hideEndScreenCardsButtonPlacement === "feature_menu" ? - "pages.content.features.hideEndScreenCardsButton.button.label" - : `pages.content.features.hideEndScreenCardsButton.button.toggle.${!endScreenCardsAreHidden ? "on" : "off"}` + hideEndScreenCardsButtonPlacement === "feature_menu" + ? "pages.content.features.hideEndScreenCardsButton.button.label" + : `pages.content.features.hideEndScreenCardsButton.button.toggle.${!endScreenCardsAreHidden ? "on" : "off"}` ), getFeatureIcon("hideEndScreenCardsButton", hideEndScreenCardsButtonPlacement), (checked) => handleButtonClick(hideEndScreenCardsButtonPlacement, checked), diff --git a/src/features/loopButton/index.ts b/src/features/loopButton/index.ts index d73192580..c8e38f805 100644 --- a/src/features/loopButton/index.ts +++ b/src/features/loopButton/index.ts @@ -34,9 +34,9 @@ export const addLoopButton: AddButtonFunction = async () => { "loopButton", loopButtonPlacement, window.i18nextInstance.t( - loopButtonPlacement === "feature_menu" ? - "pages.content.features.loopButton.button.label" - : "pages.content.features.loopButton.button.toggle.off" + loopButtonPlacement === "feature_menu" + ? "pages.content.features.loopButton.button.label" + : "pages.content.features.loopButton.button.toggle.off" ), getFeatureIcon("loopButton", loopButtonPlacement), loopButtonClickListener, diff --git a/src/features/maximizePlayerButton/index.ts b/src/features/maximizePlayerButton/index.ts index f5f1da173..8c9424d46 100644 --- a/src/features/maximizePlayerButton/index.ts +++ b/src/features/maximizePlayerButton/index.ts @@ -69,9 +69,9 @@ export const addMaximizePlayerButton: AddButtonFunction = async () => { "maximizePlayerButton", maximizePlayerButtonPlacement, window.i18nextInstance.t( - maximizePlayerButtonPlacement === "feature_menu" ? - "pages.content.features.maximizePlayerButton.button.label" - : "pages.content.features.maximizePlayerButton.button.toggle.off" + maximizePlayerButtonPlacement === "feature_menu" + ? "pages.content.features.maximizePlayerButton.button.label" + : "pages.content.features.maximizePlayerButton.button.toggle.off" ), getFeatureIcon("maximizePlayerButton", maximizePlayerButtonPlacement), maximizePlayerButtonClickListener, diff --git a/src/features/playbackSpeedButtons/index.ts b/src/features/playbackSpeedButtons/index.ts index 23ade9468..22345a5da 100644 --- a/src/features/playbackSpeedButtons/index.ts +++ b/src/features/playbackSpeedButtons/index.ts @@ -34,15 +34,19 @@ async function updateTooltip(buttonName: B id: `yte-feature-${buttonName}-tooltip` }); button.dataset.title = window.i18nextInstance.t( - speed == 4 && buttonName == "increasePlaybackSpeedButton" ? `pages.content.features.playbackSpeedButtons.increaseLimit` - : speed == 0.25 && buttonName == "decreasePlaybackSpeedButton" ? `pages.content.features.playbackSpeedButtons.decreaseLimit` - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - : `pages.content.features.playbackSpeedButtons.buttons.${buttonName as TooltipButtonName}.label`, + speed == 4 && buttonName == "increasePlaybackSpeedButton" + ? `pages.content.features.playbackSpeedButtons.increaseLimit` + : speed == 0.25 && buttonName == "decreasePlaybackSpeedButton" + ? `pages.content.features.playbackSpeedButtons.decreaseLimit` + : // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + `pages.content.features.playbackSpeedButtons.buttons.${buttonName as TooltipButtonName}.label`, { SPEED: - speed == 4 || speed == 0.25 ? String(speed) - : buttonName == "decreasePlaybackSpeedButton" ? String(speed - playbackSpeedPerClick) - : String(speed + playbackSpeedPerClick) + speed == 4 || speed == 0.25 + ? String(speed) + : buttonName == "decreasePlaybackSpeedButton" + ? String(speed - playbackSpeedPerClick) + : String(speed + playbackSpeedPerClick) } ); update(); @@ -58,9 +62,10 @@ function playbackSpeedButtonClickListener(amount: number): () => void { currentPlaybackSpeed = playbackRate; if (currentPlaybackSpeed + amount <= 0) return; if (currentPlaybackSpeed + amount > 4) return; - const playerContainer = - isWatchPage() ? document.querySelector("div#movie_player") - : isShortsPage() ? document.querySelector("div#shorts-player") + const playerContainer = isWatchPage() + ? document.querySelector("div#movie_player") + : isShortsPage() + ? document.querySelector("div#shorts-player") : null; if (!playerContainer) return; const { diff --git a/src/features/playerQuality/index.ts b/src/features/playerQuality/index.ts index 9459e4057..91dcf3c45 100644 --- a/src/features/playerQuality/index.ts +++ b/src/features/playerQuality/index.ts @@ -23,9 +23,10 @@ export default async function setPlayerQuality(): Promise { if (!player_quality) return; // Get the player element - const playerContainer = - isWatchPage() ? document.querySelector("div#movie_player") - : isShortsPage() ? document.querySelector("div#shorts-player") + const playerContainer = isWatchPage() + ? document.querySelector("div#movie_player") + : isShortsPage() + ? document.querySelector("div#shorts-player") : null; // If player element is not available, return diff --git a/src/features/playerSpeed/index.ts b/src/features/playerSpeed/index.ts index 1d033d7b8..3c063b782 100644 --- a/src/features/playerSpeed/index.ts +++ b/src/features/playerSpeed/index.ts @@ -36,9 +36,10 @@ export async function setPlayerSpeed(input?: number): Promise { // If forced playback speed option is disabled, return if (!enablePlayerSpeed) return; // Get the player element - const playerContainer = - isWatchPage() ? document.querySelector("div#movie_player") - : isShortsPage() ? document.querySelector("div#shorts-player") + const playerContainer = isWatchPage() + ? document.querySelector("div#movie_player") + : isShortsPage() + ? document.querySelector("div#shorts-player") : null; // If player element is not available, return if (!playerContainer) return; @@ -64,9 +65,10 @@ export function restorePlayerSpeed() { // If the player speed is not available, return if (!playerSpeed) return; // Get the player element - const playerContainer = - isWatchPage() ? document.querySelector("div#movie_player") - : isShortsPage() ? document.querySelector("div#shorts-player") + const playerContainer = isWatchPage() + ? document.querySelector("div#movie_player") + : isShortsPage() + ? document.querySelector("div#shorts-player") : null; const video = document.querySelector("video.html5-main-video"); // If player element is not available, return diff --git a/src/features/remainingTime/index.ts b/src/features/remainingTime/index.ts index 325bcd4a7..da8165f3d 100644 --- a/src/features/remainingTime/index.ts +++ b/src/features/remainingTime/index.ts @@ -8,9 +8,10 @@ import { calculateRemainingTime } from "./utils"; function playerTimeUpdateListener() { void (async () => { // Get the player element - const playerContainer = - isWatchPage() ? document.querySelector("div#movie_player") - : isShortsPage() ? document.querySelector("div#shorts-player") + const playerContainer = isWatchPage() + ? document.querySelector("div#movie_player") + : isShortsPage() + ? document.querySelector("div#shorts-player") : null; // If player element is not available, return @@ -40,9 +41,10 @@ export async function setupRemainingTime() { const timeDisplay = document.querySelector(".ytp-time-display > span:nth-of-type(2)"); if (!timeDisplay) return; // Get the player element - const playerContainer = - isWatchPage() ? document.querySelector("div#movie_player") - : isShortsPage() ? document.querySelector("div#shorts-player") + const playerContainer = isWatchPage() + ? document.querySelector("div#movie_player") + : isShortsPage() + ? document.querySelector("div#shorts-player") : null; // If player element is not available, return if (!playerContainer) return; diff --git a/src/features/rememberVolume/index.ts b/src/features/rememberVolume/index.ts index 234c01611..6bb1c7ccf 100644 --- a/src/features/rememberVolume/index.ts +++ b/src/features/rememberVolume/index.ts @@ -22,9 +22,10 @@ export default async function enableRememberVolume(): Promise { const IsWatchPage = isWatchPage(); const IsShortsPage = isShortsPage(); // Get the player container element - const playerContainer = - IsWatchPage ? document.querySelector("div#movie_player") - : IsShortsPage ? document.querySelector("div#shorts-player") + const playerContainer = IsWatchPage + ? document.querySelector("div#movie_player") + : IsShortsPage + ? document.querySelector("div#shorts-player") : null; // If player container is not available, return diff --git a/src/features/rememberVolume/utils.ts b/src/features/rememberVolume/utils.ts index 91534b15f..0e96ceee1 100644 --- a/src/features/rememberVolume/utils.ts +++ b/src/features/rememberVolume/utils.ts @@ -14,9 +14,10 @@ export async function setupVolumeChangeListener() { const IsWatchPage = isWatchPage(); const IsShortsPage = isShortsPage(); // Get the player container element - const playerContainer = - IsWatchPage ? document.querySelector("div#movie_player") - : IsShortsPage ? document.querySelector("div#shorts-player") + const playerContainer = IsWatchPage + ? document.querySelector("div#movie_player") + : IsShortsPage + ? document.querySelector("div#shorts-player") : null; if (!playerContainer) return; const videoElement = playerContainer.querySelector("div > video"); diff --git a/src/features/scrollWheelSpeedControl/index.ts b/src/features/scrollWheelSpeedControl/index.ts index d0e98f152..6bb01c350 100644 --- a/src/features/scrollWheelSpeedControl/index.ts +++ b/src/features/scrollWheelSpeedControl/index.ts @@ -19,9 +19,10 @@ export default async function adjustSpeedOnScrollWheel() { // Wait for the specified container selectors to be available on the page const containerSelectors = await waitForAllElements(["div#player", "div#player-wide-container", "div#video-container", "div#player-container"]); // Get the player element - const playerContainer = - isWatchPage() ? document.querySelector("div#movie_player") - : isShortsPage() ? document.querySelector("div#shorts-player") + const playerContainer = isWatchPage() + ? document.querySelector("div#movie_player") + : isShortsPage() + ? document.querySelector("div#shorts-player") : null; // If player element is not available, return if (!playerContainer) return; @@ -61,9 +62,10 @@ export default async function adjustSpeedOnScrollWheel() { await setOptionsData(); // Get the player element - const playerContainer = - isWatchPage() ? document.querySelector("div#movie_player") - : isShortsPage() ? document.querySelector("div#shorts-player") + const playerContainer = isWatchPage() + ? document.querySelector("div#movie_player") + : isShortsPage() + ? document.querySelector("div#shorts-player") : null; // If player element is not available, return if (!playerContainer) return; diff --git a/src/features/scrollWheelVolumeControl/index.ts b/src/features/scrollWheelVolumeControl/index.ts index da56476f1..8db541e84 100644 --- a/src/features/scrollWheelVolumeControl/index.ts +++ b/src/features/scrollWheelVolumeControl/index.ts @@ -73,9 +73,10 @@ export default async function adjustVolumeOnScrollWheel(): Promise { await setOptionsData(); // Get the player element - const playerContainer = - isWatchPage() ? document.querySelector("div#movie_player") - : isShortsPage() ? document.querySelector("div#shorts-player") + const playerContainer = isWatchPage() + ? document.querySelector("div#movie_player") + : isShortsPage() + ? document.querySelector("div#shorts-player") : null; // If player element is not available, return if (!playerContainer) return; diff --git a/src/features/videoHistory/index.ts b/src/features/videoHistory/index.ts index 2857fbe48..b7d21a003 100644 --- a/src/features/videoHistory/index.ts +++ b/src/features/videoHistory/index.ts @@ -21,10 +21,7 @@ export async function setupVideoHistory() { } = await waitForSpecificMessage("options", "request_data", "content"); if (!enableVideoHistory) return; // Get the player container element - const playerContainer = - isWatchPage() ? document.querySelector("div#movie_player") - : isShortsPage() ? null - : null; + const playerContainer = isWatchPage() ? document.querySelector("div#movie_player") : isShortsPage() ? null : null; // If player container is not available, return if (!playerContainer) return; const playerVideoData = await playerContainer.getVideoData(); @@ -60,10 +57,7 @@ export async function promptUserToResumeVideo(cb: () => void) { if (!enableVideoHistory) return; // Get the player container element - const playerContainer = - isWatchPage() ? document.querySelector("div#movie_player") - : isShortsPage() ? null - : null; + const playerContainer = isWatchPage() ? document.querySelector("div#movie_player") : isShortsPage() ? null : null; // If player container is not available, return if (!playerContainer) return; diff --git a/src/features/volumeBoost/index.ts b/src/features/volumeBoost/index.ts index b381bfe99..e94127230 100644 --- a/src/features/volumeBoost/index.ts +++ b/src/features/volumeBoost/index.ts @@ -66,9 +66,9 @@ export const addVolumeBoostButton: AddButtonFunction = async () => { await addFeatureButton( "volumeBoostButton", volumeBoostButtonPlacement, - volumeBoostButtonPlacement === "feature_menu" ? - window.i18nextInstance.t("pages.content.features.volumeBoostButton.button.label") - : window.i18nextInstance.t(`pages.content.features.volumeBoostButton.button.toggle.off`), + volumeBoostButtonPlacement === "feature_menu" + ? window.i18nextInstance.t("pages.content.features.volumeBoostButton.button.label") + : window.i18nextInstance.t(`pages.content.features.volumeBoostButton.button.toggle.off`), getFeatureIcon("volumeBoostButton", volumeBoostButtonPlacement), (checked) => { void (async () => { diff --git a/src/pages/embedded/index.ts b/src/pages/embedded/index.ts index efd055226..3b615a5b4 100644 --- a/src/pages/embedded/index.ts +++ b/src/pages/embedded/index.ts @@ -455,7 +455,9 @@ window.addEventListener("DOMContentLoaded", function () { updateFeatureMenuItemLabel( feature, window.i18nextInstance.t( - `pages.content.features.${multiFeatureName}.buttons.${multiButtonName}.label` as `pages.content.features.${typeof multiFeatureName}.buttons.${KeysOfUnion}.label`, + `pages.content.features.${multiFeatureName}.buttons.${multiButtonName}.label` as `pages.content.features.${typeof multiFeatureName}.buttons.${KeysOfUnion< + FeatureToMultiButtonMap[typeof multiFeatureName] + >}.label`, { SPEED: options.playback_buttons_speed } @@ -487,31 +489,33 @@ window.addEventListener("DOMContentLoaded", function () { return; } - if (featureToMultiButtonsMap.has(featureName)) { - const multiFeatureName = featureName as MultiButtonFeatureNames; - const multiButtonName = feature as MultiButtonNames; - switch (multiFeatureName) { - case "playbackSpeedButtons": { - updateFeatureMenuItemLabel( - feature, - window.i18nextInstance.t( - `pages.content.features.${multiFeatureName}.buttons.${multiButtonName}.label` as `pages.content.features.${typeof multiFeatureName}.buttons.${KeysOfUnion}.label`, - { - SPEED: options.playback_buttons_speed - } - ) - ); - break; - } - } - return - } + if (featureToMultiButtonsMap.has(featureName)) { + const multiFeatureName = featureName as MultiButtonFeatureNames; + const multiButtonName = feature as MultiButtonNames; + switch (multiFeatureName) { + case "playbackSpeedButtons": { + updateFeatureMenuItemLabel( + feature, + window.i18nextInstance.t( + `pages.content.features.${multiFeatureName}.buttons.${multiButtonName}.label` as `pages.content.features.${typeof multiFeatureName}.buttons.${KeysOfUnion< + FeatureToMultiButtonMap[typeof multiFeatureName] + >}.label`, + { + SPEED: options.playback_buttons_speed + } + ) + ); + break; + } + } + return; + } updateFeatureMenuItemLabel( feature, window.i18nextInstance.t( - featureToMultiButtonsMap.has(featureName) ? - `pages.content.features.${featureName as MultiButtonFeatureNames}.buttons.${feature as MultiButtonNames}.label` - : `pages.content.features.${featureName as SingleButtonNames}.button.label` + featureToMultiButtonsMap.has(featureName) + ? `pages.content.features.${featureName as MultiButtonFeatureNames}.buttons.${feature as MultiButtonNames}.label` + : `pages.content.features.${featureName as SingleButtonNames}.button.label` ) ); } @@ -520,9 +524,10 @@ window.addEventListener("DOMContentLoaded", function () { } case "automaticTheaterModeChange": { // Get the player element - const playerContainer = - isWatchPage() ? document.querySelector("div#player-container.ytd-watch-flexy") - : isShortsPage() ? document.querySelector("div#shorts-player") + const playerContainer = isWatchPage() + ? document.querySelector("div#player-container.ytd-watch-flexy") + : isShortsPage() + ? document.querySelector("div#shorts-player") : null; // If player element is not available, return if (!playerContainer) return; diff --git a/src/types/index.ts b/src/types/index.ts index cf358d7f1..5c4aa73e6 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -17,26 +17,26 @@ export type WithId = `#${S}`; export type Prettify = { [K in keyof T]: T[K]; }; -export type ExtractButtonFeatureNames = - T extends `pages.content.features.${infer FeatureName}.button.label` ? FeatureName - : T extends `pages.content.features.${infer FeatureName}.buttons.${string}.label` ? FeatureName +export type ExtractButtonFeatureNames = T extends `pages.content.features.${infer FeatureName}.button.label` + ? FeatureName + : T extends `pages.content.features.${infer FeatureName}.buttons.${string}.label` + ? FeatureName : never; -export type ExtractButtonNames = - T extends `pages.content.features.${infer ButtonName}.button.label` ? ButtonName - : T extends `pages.content.features.${string}.buttons.${infer ButtonName}.label` ? ButtonName +export type ExtractButtonNames = T extends `pages.content.features.${infer ButtonName}.button.label` + ? ButtonName + : T extends `pages.content.features.${string}.buttons.${infer ButtonName}.label` + ? ButtonName : never; // Taken from https://github.com/colinhacks/zod/issues/53#issuecomment-1681090113 type TypeToZod = { - [K in keyof T]: T[K] extends boolean | null | number | string | undefined ? - undefined extends T[K] ? - z.ZodOptional>> - : z.ZodType - : z.ZodObject>; + [K in keyof T]: T[K] extends boolean | null | number | string | undefined + ? undefined extends T[K] + ? z.ZodOptional>> + : z.ZodType + : z.ZodObject>; }; export type TypeToZodSchema = z.ZodObject<{ - [K in keyof T]: T[K] extends any[] ? z.ZodArray> - : T[K] extends object ? z.ZodObject> - : z.ZodType; + [K in keyof T]: T[K] extends any[] ? z.ZodArray> : T[K] extends object ? z.ZodObject> : z.ZodType; }>; export type TypeToPartialZodSchema< Input, @@ -44,40 +44,42 @@ export type TypeToPartialZodSchema< Override extends { [Key in Omitted]: ZodType } = never, Omit = false > = z.ZodObject< - Omit extends true ? OmitAndOverride - : { - [K in keyof Input]: Input[K] extends any[] ? z.ZodOptionalType> - : Input[K] extends object ? z.ZodOptionalType>> - : z.ZodOptionalType>; - } + Omit extends true + ? OmitAndOverride + : { + [K in keyof Input]: Input[K] extends any[] + ? z.ZodOptionalType> + : Input[K] extends object + ? z.ZodOptionalType>> + : z.ZodOptionalType>; + } >; -type PathImpl = - Key extends string ? - T[Key] extends Record ? - T[Key] extends ArrayLike ? - `${Key}.${PathImpl>}` | Key - : `${Key}.${PathImpl}` | Key - : Key - : never; +type PathImpl = Key extends string + ? T[Key] extends Record + ? T[Key] extends ArrayLike + ? `${Key}.${PathImpl>}` | Key + : `${Key}.${PathImpl}` | Key + : Key + : never; export type Path = PathImpl | keyof T; -export type PathValue> = - P extends `${infer Key}.${infer Rest}` ? - Key extends keyof T ? - Rest extends Path ? - PathValue - : never - : never - : P extends keyof T ? T[P] +export type PathValue> = P extends `${infer Key}.${infer Rest}` + ? Key extends keyof T + ? Rest extends Path + ? PathValue + : never + : never + : P extends keyof T + ? T[P] : never; export type OmitAndOverride = { - [K in keyof Omit]: Omit[K] extends any[] ? z.ZodOptionalType[K]>> - : Omit[K] extends object ? z.ZodOptionalType[K]>>> - : z.ZodOptionalType[K]>>; + [K in keyof Omit]: Omit[K] extends any[] + ? z.ZodOptionalType[K]>> + : Omit[K] extends object + ? z.ZodOptionalType[K]>>> + : z.ZodOptionalType[K]>>; } & Override; export type FilterKeysByValueType = { - [K in keyof O]: O[K] extends ValueType ? K - : O[K] extends Record ? K - : never; + [K in keyof O]: O[K] extends ValueType ? K : O[K] extends Record ? K : never; }[keyof O]; // #endregion Utility types // #region Constants diff --git a/src/utils/OnScreenDisplayManager.ts b/src/utils/OnScreenDisplayManager.ts index 0a691d0f5..3e97fe695 100644 --- a/src/utils/OnScreenDisplayManager.ts +++ b/src/utils/OnScreenDisplayManager.ts @@ -249,15 +249,14 @@ export default class OnScreenDisplayManager { const { top: topRectTop = 0 } = document.querySelector(".player-controls > ytd-shorts-player-controls")?.getBoundingClientRect() || {}; const { bottom: bottomRectBottom = 0, top: bottomRectTop = 0 } = bottomElement?.getBoundingClientRect() || {}; - const heightExcludingMarginPadding = - bottomElement ? - bottomElement.offsetHeight - - (parseInt(getComputedStyle(bottomElement).marginTop, 10) + + const heightExcludingMarginPadding = bottomElement + ? bottomElement.offsetHeight - + (parseInt(getComputedStyle(bottomElement).marginTop, 10) + parseInt(getComputedStyle(bottomElement).marginBottom, 10) + parseInt(getComputedStyle(bottomElement).paddingTop, 10) + parseInt(getComputedStyle(bottomElement).paddingBottom, 10)) + - 10 - : 0; + 10 + : 0; const paddingTop = isShortsPage() ? topRectTop / 2 : 0; const paddingBottom = isShortsPage() ? heightExcludingMarginPadding : Math.round(bottomRectBottom - bottomRectTop); From 95ac395461ff78536ea8aaaec03c6e8f7ac72a46 Mon Sep 17 00:00:00 2001 From: livingflore Date: Sun, 16 Jun 2024 18:40:22 +0500 Subject: [PATCH 32/33] fix: assert node type --- src/features/removeRedirect/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/removeRedirect/index.ts b/src/features/removeRedirect/index.ts index 6ffa7ccd8..3d6f7033b 100644 --- a/src/features/removeRedirect/index.ts +++ b/src/features/removeRedirect/index.ts @@ -25,7 +25,7 @@ export default async function enableRemoveRedirect() { for (const mutation of mutationsList) { if (mutation.type !== "childList") return; mutation.addedNodes.forEach((node: Nullable) => { - if (node instanceof Element === false || !node.hasAttribute("href")) return; + if (!(node instanceof Element) || !("href" in node)) return; const href: Nullable = node.getAttribute("href"); if (!href || !href.match(regex)) return; const urlParams = new URLSearchParams(href); From 9f0e468cf5023803aeaccc5c1a531d02149f815e Mon Sep 17 00:00:00 2001 From: VampireChicken12 Date: Sun, 23 Jun 2024 12:30:08 -0400 Subject: [PATCH 33/33] chore: format --- CONTRIBUTING.md | 2 +- .../Inputs/CSSEditor/ExpandButton/index.tsx | 2 +- src/components/Inputs/Select/Select.tsx | 15 ++-- src/components/Settings/Settings.css | 10 +-- src/components/Settings/Settings.tsx | 19 ++-- src/defaults.ts | 12 +-- src/features/hideEndScreenCards/index.ts | 6 +- .../hidePaidPromotionBanner/index.css | 2 +- src/features/loopButton/index.ts | 6 +- src/features/maximizePlayerButton/index.ts | 6 +- src/features/playbackSpeedButtons/index.ts | 25 +++--- src/features/playerQuality/index.ts | 7 +- src/features/playerSpeed/index.ts | 14 ++- src/features/remainingTime/index.ts | 14 ++- src/features/rememberVolume/index.ts | 7 +- src/features/rememberVolume/utils.ts | 7 +- src/features/scrollWheelSpeedControl/index.ts | 14 ++- .../scrollWheelVolumeControl/index.ts | 7 +- src/features/videoHistory/index.ts | 10 ++- src/features/volumeBoost/index.ts | 6 +- src/pages/embedded/index.ts | 13 ++- src/types/index.ts | 86 +++++++++---------- src/utils/OnScreenDisplayManager.ts | 11 +-- 23 files changed, 144 insertions(+), 157 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 07e521ede..67fa845b3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -79,5 +79,5 @@ While we don't yet have a strict guideline on what kind of code should be in the --- [^1]: [Why Use Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#why-use-conventional-commits) -[^2]: [ESLint: A List of Editor Integrations](https://eslint.org/docs/latest/use/integrations#editors) +[^2]: [ESLint: A List of Editor Integrations](https://eslint.org/docs/latest/use/integrations#editors) diff --git a/src/components/Inputs/CSSEditor/ExpandButton/index.tsx b/src/components/Inputs/CSSEditor/ExpandButton/index.tsx index 52972304f..529b2b1d7 100644 --- a/src/components/Inputs/CSSEditor/ExpandButton/index.tsx +++ b/src/components/Inputs/CSSEditor/ExpandButton/index.tsx @@ -13,7 +13,7 @@ const ExpandButton = forwardRef(({ isExpand return ( ({ onClick={toggleSelect} type="button" > - {loading ? ( + {loading ? - ) : selectedOption ? ( - options.find((option) => option.value === selectedOption)?.element ? ( + : selectedOption ? + options.find((option) => option.value === selectedOption)?.element ?
{options.find((option) => option.value === selectedOption)?.label} {options.find((option) => option.value === selectedOption)?.element}
- ) : ( -
+ :
{options.find((option) => option.value === selectedOption)?.label}
- ) - ) : ( - Select an option - )} + + : Select an option} {isSelectVisible && ( diff --git a/src/components/Settings/Settings.css b/src/components/Settings/Settings.css index a23089f35..a0aecded1 100644 --- a/src/components/Settings/Settings.css +++ b/src/components/Settings/Settings.css @@ -74,7 +74,7 @@ html { } /* https://stackoverflow.com/questions/11243337/a-taller-than-its-img-child */ -a>img { +a > img { display: block; } @@ -94,11 +94,11 @@ fieldset { padding-left: 0 !important; } -fieldset>p:first-of-type { +fieldset > p:first-of-type { margin-top: 0 !important; } -fieldset>p:last-of-type { +fieldset > p:last-of-type { margin-bottom: 0 !important; } @@ -359,7 +359,7 @@ button[id="openinnewtab_button"] { z-index: 100; } -#notifications>.notification { +#notifications > .notification { border-radius: var(--border-radius-md); padding: 10px 14px; -} \ No newline at end of file +} diff --git a/src/components/Settings/Settings.tsx b/src/components/Settings/Settings.tsx index 957a64f5d..e780dfae2 100644 --- a/src/components/Settings/Settings.tsx +++ b/src/components/Settings/Settings.tsx @@ -1193,7 +1193,7 @@ export default function Settings() {
{isPopup && ( )} - {notifications.filter((n) => n.action === "reset_settings").length > 0 ? ( + {notifications.filter((n) => n.action === "reset_settings").length > 0 ? { const notificationToRemove = notifications.find((n) => n.action === "reset_settings"); @@ -1251,16 +1251,15 @@ export default function Settings() { type="button" value={t("settings.sections.bottomButtons.confirm.value")} /> - ) : ( - - )} + }
diff --git a/src/defaults.ts b/src/defaults.ts index bc282c514..9b75d72dc 100644 --- a/src/defaults.ts +++ b/src/defaults.ts @@ -20,11 +20,13 @@ function setDefaultValues() { try { // Parse the stored value to check its type const storedValue = - typeof defaultConfiguration[option] === "object" || - typeof defaultConfiguration[option] === "boolean" || - typeof defaultConfiguration[option] === "number" - ? JSON.parse(storedValueString) - : storedValueString; + ( + typeof defaultConfiguration[option] === "object" || + typeof defaultConfiguration[option] === "boolean" || + typeof defaultConfiguration[option] === "number" + ) ? + JSON.parse(storedValueString) + : storedValueString; // Check if the parsed value is an object and has properties if (typeof storedValue !== "object" || storedValue === null) continue; // Deep merge missing keys with their default values diff --git a/src/features/hideEndScreenCards/index.ts b/src/features/hideEndScreenCards/index.ts index 94f423b4b..5cc9964fc 100644 --- a/src/features/hideEndScreenCards/index.ts +++ b/src/features/hideEndScreenCards/index.ts @@ -52,9 +52,9 @@ export const addHideEndScreenCardsButton: AddButtonFunction = async () => { "hideEndScreenCardsButton", hideEndScreenCardsButtonPlacement, window.i18nextInstance.t( - hideEndScreenCardsButtonPlacement === "feature_menu" - ? "pages.content.features.hideEndScreenCardsButton.button.label" - : `pages.content.features.hideEndScreenCardsButton.button.toggle.${!endScreenCardsAreHidden ? "on" : "off"}` + hideEndScreenCardsButtonPlacement === "feature_menu" ? + "pages.content.features.hideEndScreenCardsButton.button.label" + : `pages.content.features.hideEndScreenCardsButton.button.toggle.${!endScreenCardsAreHidden ? "on" : "off"}` ), getFeatureIcon("hideEndScreenCardsButton", hideEndScreenCardsButtonPlacement), (checked) => handleButtonClick(hideEndScreenCardsButtonPlacement, checked), diff --git a/src/features/hidePaidPromotionBanner/index.css b/src/features/hidePaidPromotionBanner/index.css index 4d2753feb..568811699 100644 --- a/src/features/hidePaidPromotionBanner/index.css +++ b/src/features/hidePaidPromotionBanner/index.css @@ -1,3 +1,3 @@ .yte-hide-paid-promotion-banner { display: none !important; -} \ No newline at end of file +} diff --git a/src/features/loopButton/index.ts b/src/features/loopButton/index.ts index c8e38f805..d73192580 100644 --- a/src/features/loopButton/index.ts +++ b/src/features/loopButton/index.ts @@ -34,9 +34,9 @@ export const addLoopButton: AddButtonFunction = async () => { "loopButton", loopButtonPlacement, window.i18nextInstance.t( - loopButtonPlacement === "feature_menu" - ? "pages.content.features.loopButton.button.label" - : "pages.content.features.loopButton.button.toggle.off" + loopButtonPlacement === "feature_menu" ? + "pages.content.features.loopButton.button.label" + : "pages.content.features.loopButton.button.toggle.off" ), getFeatureIcon("loopButton", loopButtonPlacement), loopButtonClickListener, diff --git a/src/features/maximizePlayerButton/index.ts b/src/features/maximizePlayerButton/index.ts index 8c9424d46..f5f1da173 100644 --- a/src/features/maximizePlayerButton/index.ts +++ b/src/features/maximizePlayerButton/index.ts @@ -69,9 +69,9 @@ export const addMaximizePlayerButton: AddButtonFunction = async () => { "maximizePlayerButton", maximizePlayerButtonPlacement, window.i18nextInstance.t( - maximizePlayerButtonPlacement === "feature_menu" - ? "pages.content.features.maximizePlayerButton.button.label" - : "pages.content.features.maximizePlayerButton.button.toggle.off" + maximizePlayerButtonPlacement === "feature_menu" ? + "pages.content.features.maximizePlayerButton.button.label" + : "pages.content.features.maximizePlayerButton.button.toggle.off" ), getFeatureIcon("maximizePlayerButton", maximizePlayerButtonPlacement), maximizePlayerButtonClickListener, diff --git a/src/features/playbackSpeedButtons/index.ts b/src/features/playbackSpeedButtons/index.ts index 22345a5da..23ade9468 100644 --- a/src/features/playbackSpeedButtons/index.ts +++ b/src/features/playbackSpeedButtons/index.ts @@ -34,19 +34,15 @@ async function updateTooltip(buttonName: B id: `yte-feature-${buttonName}-tooltip` }); button.dataset.title = window.i18nextInstance.t( - speed == 4 && buttonName == "increasePlaybackSpeedButton" - ? `pages.content.features.playbackSpeedButtons.increaseLimit` - : speed == 0.25 && buttonName == "decreasePlaybackSpeedButton" - ? `pages.content.features.playbackSpeedButtons.decreaseLimit` - : // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion - `pages.content.features.playbackSpeedButtons.buttons.${buttonName as TooltipButtonName}.label`, + speed == 4 && buttonName == "increasePlaybackSpeedButton" ? `pages.content.features.playbackSpeedButtons.increaseLimit` + : speed == 0.25 && buttonName == "decreasePlaybackSpeedButton" ? `pages.content.features.playbackSpeedButtons.decreaseLimit` + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + : `pages.content.features.playbackSpeedButtons.buttons.${buttonName as TooltipButtonName}.label`, { SPEED: - speed == 4 || speed == 0.25 - ? String(speed) - : buttonName == "decreasePlaybackSpeedButton" - ? String(speed - playbackSpeedPerClick) - : String(speed + playbackSpeedPerClick) + speed == 4 || speed == 0.25 ? String(speed) + : buttonName == "decreasePlaybackSpeedButton" ? String(speed - playbackSpeedPerClick) + : String(speed + playbackSpeedPerClick) } ); update(); @@ -62,10 +58,9 @@ function playbackSpeedButtonClickListener(amount: number): () => void { currentPlaybackSpeed = playbackRate; if (currentPlaybackSpeed + amount <= 0) return; if (currentPlaybackSpeed + amount > 4) return; - const playerContainer = isWatchPage() - ? document.querySelector("div#movie_player") - : isShortsPage() - ? document.querySelector("div#shorts-player") + const playerContainer = + isWatchPage() ? document.querySelector("div#movie_player") + : isShortsPage() ? document.querySelector("div#shorts-player") : null; if (!playerContainer) return; const { diff --git a/src/features/playerQuality/index.ts b/src/features/playerQuality/index.ts index 91dcf3c45..9459e4057 100644 --- a/src/features/playerQuality/index.ts +++ b/src/features/playerQuality/index.ts @@ -23,10 +23,9 @@ export default async function setPlayerQuality(): Promise { if (!player_quality) return; // Get the player element - const playerContainer = isWatchPage() - ? document.querySelector("div#movie_player") - : isShortsPage() - ? document.querySelector("div#shorts-player") + const playerContainer = + isWatchPage() ? document.querySelector("div#movie_player") + : isShortsPage() ? document.querySelector("div#shorts-player") : null; // If player element is not available, return diff --git a/src/features/playerSpeed/index.ts b/src/features/playerSpeed/index.ts index 3c063b782..1d033d7b8 100644 --- a/src/features/playerSpeed/index.ts +++ b/src/features/playerSpeed/index.ts @@ -36,10 +36,9 @@ export async function setPlayerSpeed(input?: number): Promise { // If forced playback speed option is disabled, return if (!enablePlayerSpeed) return; // Get the player element - const playerContainer = isWatchPage() - ? document.querySelector("div#movie_player") - : isShortsPage() - ? document.querySelector("div#shorts-player") + const playerContainer = + isWatchPage() ? document.querySelector("div#movie_player") + : isShortsPage() ? document.querySelector("div#shorts-player") : null; // If player element is not available, return if (!playerContainer) return; @@ -65,10 +64,9 @@ export function restorePlayerSpeed() { // If the player speed is not available, return if (!playerSpeed) return; // Get the player element - const playerContainer = isWatchPage() - ? document.querySelector("div#movie_player") - : isShortsPage() - ? document.querySelector("div#shorts-player") + const playerContainer = + isWatchPage() ? document.querySelector("div#movie_player") + : isShortsPage() ? document.querySelector("div#shorts-player") : null; const video = document.querySelector("video.html5-main-video"); // If player element is not available, return diff --git a/src/features/remainingTime/index.ts b/src/features/remainingTime/index.ts index da8165f3d..325bcd4a7 100644 --- a/src/features/remainingTime/index.ts +++ b/src/features/remainingTime/index.ts @@ -8,10 +8,9 @@ import { calculateRemainingTime } from "./utils"; function playerTimeUpdateListener() { void (async () => { // Get the player element - const playerContainer = isWatchPage() - ? document.querySelector("div#movie_player") - : isShortsPage() - ? document.querySelector("div#shorts-player") + const playerContainer = + isWatchPage() ? document.querySelector("div#movie_player") + : isShortsPage() ? document.querySelector("div#shorts-player") : null; // If player element is not available, return @@ -41,10 +40,9 @@ export async function setupRemainingTime() { const timeDisplay = document.querySelector(".ytp-time-display > span:nth-of-type(2)"); if (!timeDisplay) return; // Get the player element - const playerContainer = isWatchPage() - ? document.querySelector("div#movie_player") - : isShortsPage() - ? document.querySelector("div#shorts-player") + const playerContainer = + isWatchPage() ? document.querySelector("div#movie_player") + : isShortsPage() ? document.querySelector("div#shorts-player") : null; // If player element is not available, return if (!playerContainer) return; diff --git a/src/features/rememberVolume/index.ts b/src/features/rememberVolume/index.ts index 6bb1c7ccf..234c01611 100644 --- a/src/features/rememberVolume/index.ts +++ b/src/features/rememberVolume/index.ts @@ -22,10 +22,9 @@ export default async function enableRememberVolume(): Promise { const IsWatchPage = isWatchPage(); const IsShortsPage = isShortsPage(); // Get the player container element - const playerContainer = IsWatchPage - ? document.querySelector("div#movie_player") - : IsShortsPage - ? document.querySelector("div#shorts-player") + const playerContainer = + IsWatchPage ? document.querySelector("div#movie_player") + : IsShortsPage ? document.querySelector("div#shorts-player") : null; // If player container is not available, return diff --git a/src/features/rememberVolume/utils.ts b/src/features/rememberVolume/utils.ts index 0e96ceee1..91534b15f 100644 --- a/src/features/rememberVolume/utils.ts +++ b/src/features/rememberVolume/utils.ts @@ -14,10 +14,9 @@ export async function setupVolumeChangeListener() { const IsWatchPage = isWatchPage(); const IsShortsPage = isShortsPage(); // Get the player container element - const playerContainer = IsWatchPage - ? document.querySelector("div#movie_player") - : IsShortsPage - ? document.querySelector("div#shorts-player") + const playerContainer = + IsWatchPage ? document.querySelector("div#movie_player") + : IsShortsPage ? document.querySelector("div#shorts-player") : null; if (!playerContainer) return; const videoElement = playerContainer.querySelector("div > video"); diff --git a/src/features/scrollWheelSpeedControl/index.ts b/src/features/scrollWheelSpeedControl/index.ts index 6bb01c350..d0e98f152 100644 --- a/src/features/scrollWheelSpeedControl/index.ts +++ b/src/features/scrollWheelSpeedControl/index.ts @@ -19,10 +19,9 @@ export default async function adjustSpeedOnScrollWheel() { // Wait for the specified container selectors to be available on the page const containerSelectors = await waitForAllElements(["div#player", "div#player-wide-container", "div#video-container", "div#player-container"]); // Get the player element - const playerContainer = isWatchPage() - ? document.querySelector("div#movie_player") - : isShortsPage() - ? document.querySelector("div#shorts-player") + const playerContainer = + isWatchPage() ? document.querySelector("div#movie_player") + : isShortsPage() ? document.querySelector("div#shorts-player") : null; // If player element is not available, return if (!playerContainer) return; @@ -62,10 +61,9 @@ export default async function adjustSpeedOnScrollWheel() { await setOptionsData(); // Get the player element - const playerContainer = isWatchPage() - ? document.querySelector("div#movie_player") - : isShortsPage() - ? document.querySelector("div#shorts-player") + const playerContainer = + isWatchPage() ? document.querySelector("div#movie_player") + : isShortsPage() ? document.querySelector("div#shorts-player") : null; // If player element is not available, return if (!playerContainer) return; diff --git a/src/features/scrollWheelVolumeControl/index.ts b/src/features/scrollWheelVolumeControl/index.ts index 8db541e84..da56476f1 100644 --- a/src/features/scrollWheelVolumeControl/index.ts +++ b/src/features/scrollWheelVolumeControl/index.ts @@ -73,10 +73,9 @@ export default async function adjustVolumeOnScrollWheel(): Promise { await setOptionsData(); // Get the player element - const playerContainer = isWatchPage() - ? document.querySelector("div#movie_player") - : isShortsPage() - ? document.querySelector("div#shorts-player") + const playerContainer = + isWatchPage() ? document.querySelector("div#movie_player") + : isShortsPage() ? document.querySelector("div#shorts-player") : null; // If player element is not available, return if (!playerContainer) return; diff --git a/src/features/videoHistory/index.ts b/src/features/videoHistory/index.ts index b7d21a003..2857fbe48 100644 --- a/src/features/videoHistory/index.ts +++ b/src/features/videoHistory/index.ts @@ -21,7 +21,10 @@ export async function setupVideoHistory() { } = await waitForSpecificMessage("options", "request_data", "content"); if (!enableVideoHistory) return; // Get the player container element - const playerContainer = isWatchPage() ? document.querySelector("div#movie_player") : isShortsPage() ? null : null; + const playerContainer = + isWatchPage() ? document.querySelector("div#movie_player") + : isShortsPage() ? null + : null; // If player container is not available, return if (!playerContainer) return; const playerVideoData = await playerContainer.getVideoData(); @@ -57,7 +60,10 @@ export async function promptUserToResumeVideo(cb: () => void) { if (!enableVideoHistory) return; // Get the player container element - const playerContainer = isWatchPage() ? document.querySelector("div#movie_player") : isShortsPage() ? null : null; + const playerContainer = + isWatchPage() ? document.querySelector("div#movie_player") + : isShortsPage() ? null + : null; // If player container is not available, return if (!playerContainer) return; diff --git a/src/features/volumeBoost/index.ts b/src/features/volumeBoost/index.ts index e94127230..b381bfe99 100644 --- a/src/features/volumeBoost/index.ts +++ b/src/features/volumeBoost/index.ts @@ -66,9 +66,9 @@ export const addVolumeBoostButton: AddButtonFunction = async () => { await addFeatureButton( "volumeBoostButton", volumeBoostButtonPlacement, - volumeBoostButtonPlacement === "feature_menu" - ? window.i18nextInstance.t("pages.content.features.volumeBoostButton.button.label") - : window.i18nextInstance.t(`pages.content.features.volumeBoostButton.button.toggle.off`), + volumeBoostButtonPlacement === "feature_menu" ? + window.i18nextInstance.t("pages.content.features.volumeBoostButton.button.label") + : window.i18nextInstance.t(`pages.content.features.volumeBoostButton.button.toggle.off`), getFeatureIcon("volumeBoostButton", volumeBoostButtonPlacement), (checked) => { void (async () => { diff --git a/src/pages/embedded/index.ts b/src/pages/embedded/index.ts index 39a84851e..f8491da3c 100644 --- a/src/pages/embedded/index.ts +++ b/src/pages/embedded/index.ts @@ -609,9 +609,9 @@ window.addEventListener("DOMContentLoaded", function () { updateFeatureMenuItemLabel( feature, window.i18nextInstance.t( - featureToMultiButtonsMap.has(featureName) - ? `pages.content.features.${featureName as MultiButtonFeatureNames}.buttons.${feature as MultiButtonNames}.label` - : `pages.content.features.${featureName as SingleButtonNames}.button.label` + featureToMultiButtonsMap.has(featureName) ? + `pages.content.features.${featureName as MultiButtonFeatureNames}.buttons.${feature as MultiButtonNames}.label` + : `pages.content.features.${featureName as SingleButtonNames}.button.label` ) ); } @@ -620,10 +620,9 @@ window.addEventListener("DOMContentLoaded", function () { } case "automaticTheaterModeChange": { // Get the player element - const playerContainer = isWatchPage() - ? document.querySelector("div#player-container.ytd-watch-flexy") - : isShortsPage() - ? document.querySelector("div#shorts-player") + const playerContainer = + isWatchPage() ? document.querySelector("div#player-container.ytd-watch-flexy") + : isShortsPage() ? document.querySelector("div#shorts-player") : null; // If player element is not available, return if (!playerContainer) return; diff --git a/src/types/index.ts b/src/types/index.ts index 6a6f822dd..2f6e42fae 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -17,26 +17,26 @@ export type WithId = `#${S}`; export type Prettify = { [K in keyof T]: T[K]; }; -export type ExtractButtonFeatureNames = T extends `pages.content.features.${infer FeatureName}.button.label` - ? FeatureName - : T extends `pages.content.features.${infer FeatureName}.buttons.${string}.label` - ? FeatureName +export type ExtractButtonFeatureNames = + T extends `pages.content.features.${infer FeatureName}.button.label` ? FeatureName + : T extends `pages.content.features.${infer FeatureName}.buttons.${string}.label` ? FeatureName : never; -export type ExtractButtonNames = T extends `pages.content.features.${infer ButtonName}.button.label` - ? ButtonName - : T extends `pages.content.features.${string}.buttons.${infer ButtonName}.label` - ? ButtonName +export type ExtractButtonNames = + T extends `pages.content.features.${infer ButtonName}.button.label` ? ButtonName + : T extends `pages.content.features.${string}.buttons.${infer ButtonName}.label` ? ButtonName : never; // Taken from https://github.com/colinhacks/zod/issues/53#issuecomment-1681090113 type TypeToZod = { - [K in keyof T]: T[K] extends boolean | null | number | string | undefined - ? undefined extends T[K] - ? z.ZodOptional>> - : z.ZodType - : z.ZodObject>; + [K in keyof T]: T[K] extends boolean | null | number | string | undefined ? + undefined extends T[K] ? + z.ZodOptional>> + : z.ZodType + : z.ZodObject>; }; export type TypeToZodSchema = z.ZodObject<{ - [K in keyof T]: T[K] extends any[] ? z.ZodArray> : T[K] extends object ? z.ZodObject> : z.ZodType; + [K in keyof T]: T[K] extends any[] ? z.ZodArray> + : T[K] extends object ? z.ZodObject> + : z.ZodType; }>; export type TypeToPartialZodSchema< Input, @@ -44,42 +44,40 @@ export type TypeToPartialZodSchema< Override extends { [Key in Omitted]: ZodType } = never, Omit = false > = z.ZodObject< - Omit extends true - ? OmitAndOverride - : { - [K in keyof Input]: Input[K] extends any[] - ? z.ZodOptionalType> - : Input[K] extends object - ? z.ZodOptionalType>> - : z.ZodOptionalType>; - } + Omit extends true ? OmitAndOverride + : { + [K in keyof Input]: Input[K] extends any[] ? z.ZodOptionalType> + : Input[K] extends object ? z.ZodOptionalType>> + : z.ZodOptionalType>; + } >; -type PathImpl = Key extends string - ? T[Key] extends Record - ? T[Key] extends ArrayLike - ? `${Key}.${PathImpl>}` | Key - : `${Key}.${PathImpl}` | Key - : Key - : never; +type PathImpl = + Key extends string ? + T[Key] extends Record ? + T[Key] extends ArrayLike ? + `${Key}.${PathImpl>}` | Key + : `${Key}.${PathImpl}` | Key + : Key + : never; export type Path = PathImpl | keyof T; -export type PathValue> = P extends `${infer Key}.${infer Rest}` - ? Key extends keyof T - ? Rest extends Path - ? PathValue - : never - : never - : P extends keyof T - ? T[P] +export type PathValue> = + P extends `${infer Key}.${infer Rest}` ? + Key extends keyof T ? + Rest extends Path ? + PathValue + : never + : never + : P extends keyof T ? T[P] : never; export type OmitAndOverride = { - [K in keyof Omit]: Omit[K] extends any[] - ? z.ZodOptionalType[K]>> - : Omit[K] extends object - ? z.ZodOptionalType[K]>>> - : z.ZodOptionalType[K]>>; + [K in keyof Omit]: Omit[K] extends any[] ? z.ZodOptionalType[K]>> + : Omit[K] extends object ? z.ZodOptionalType[K]>>> + : z.ZodOptionalType[K]>>; } & Override; export type FilterKeysByValueType = { - [K in keyof O]: O[K] extends ValueType ? K : O[K] extends Record ? K : never; + [K in keyof O]: O[K] extends ValueType ? K + : O[K] extends Record ? K + : never; }[keyof O]; // #endregion Utility types // #region Constants diff --git a/src/utils/OnScreenDisplayManager.ts b/src/utils/OnScreenDisplayManager.ts index 3e97fe695..0a691d0f5 100644 --- a/src/utils/OnScreenDisplayManager.ts +++ b/src/utils/OnScreenDisplayManager.ts @@ -249,14 +249,15 @@ export default class OnScreenDisplayManager { const { top: topRectTop = 0 } = document.querySelector(".player-controls > ytd-shorts-player-controls")?.getBoundingClientRect() || {}; const { bottom: bottomRectBottom = 0, top: bottomRectTop = 0 } = bottomElement?.getBoundingClientRect() || {}; - const heightExcludingMarginPadding = bottomElement - ? bottomElement.offsetHeight - - (parseInt(getComputedStyle(bottomElement).marginTop, 10) + + const heightExcludingMarginPadding = + bottomElement ? + bottomElement.offsetHeight - + (parseInt(getComputedStyle(bottomElement).marginTop, 10) + parseInt(getComputedStyle(bottomElement).marginBottom, 10) + parseInt(getComputedStyle(bottomElement).paddingTop, 10) + parseInt(getComputedStyle(bottomElement).paddingBottom, 10)) + - 10 - : 0; + 10 + : 0; const paddingTop = isShortsPage() ? topRectTop / 2 : 0; const paddingBottom = isShortsPage() ? heightExcludingMarginPadding : Math.round(bottomRectBottom - bottomRectTop);