Skip to content

Commit

Permalink
fix: Button placement change causing multi buttons to stop working.
Browse files Browse the repository at this point in the history
  • Loading branch information
VampireChicken12 committed May 23, 2024
1 parent 883fae2 commit caed598
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 35 deletions.
69 changes: 50 additions & 19 deletions src/pages/embedded/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@ import { deepDarkPresets } from "@/src/deepDarkPresets";
import { type FeatureFuncRecord, featureButtonFunctions } from "@/src/features";
import { enableAutomaticTheaterMode } from "@/src/features/automaticTheaterMode";
import { featuresInControls } from "@/src/features/buttonPlacement";
import {
checkIfFeatureButtonExists,
getFeatureButton,
updateFeatureButtonIcon,
updateFeatureButtonTitle
} from "@/src/features/buttonPlacement/utils";
import { getFeatureButton, updateFeatureButtonIcon, updateFeatureButtonTitle } from "@/src/features/buttonPlacement/utils";
import { disableCustomCSS, enableCustomCSS } from "@/src/features/customCSS";
import { customCSSExists, updateCustomCSS } from "@/src/features/customCSS/utils";
import { disableDeepDarkCSS, enableDeepDarkCSS } from "@/src/features/deepDarkCSS";
Expand Down Expand Up @@ -62,6 +57,8 @@ import volumeBoost, {
import { i18nService } from "@/src/i18n";
import { type ToggleFeatures, type ToggleIcon, getFeatureIcon, toggleFeatures } from "@/src/icons";
import {
type AllButtonNames,
type ButtonPlacement,
type ExtensionSendOnlyMessageMappings,
type Messages,
type MultiButtonFeatureNames,
Expand All @@ -76,6 +73,7 @@ import {
browserColorLog,
findKeyByValue,
formatError,
groupButtonChanges,
isShortsPage,
isWatchPage,
sendContentOnlyMessage,
Expand Down Expand Up @@ -182,7 +180,21 @@ const enableFeatures = () => {
await addLoopButton();
})();
};
const getFeatureFunctions = (featureName: AllButtonNames, oldPlacement: ButtonPlacement) => {
const { [featureName]: featureFunctions } = featureButtonFunctions;
// Ensure featureFunctions exist before proceeding
if (!featureFunctions) {
throw new Error(`Feature '${featureName}' not found in featureButtonFunctions`);
}

// Cast featureFunctions to FeatureFuncRecord
const castFeatureFunctions = featureFunctions as unknown as FeatureFuncRecord;

return {
add: () => castFeatureFunctions.add(),
remove: () => castFeatureFunctions.remove(oldPlacement)
};
};
window.addEventListener("DOMContentLoaded", function () {
void (async () => {
const response = await waitForSpecificMessage("language", "request_data", "content");
Expand Down Expand Up @@ -637,19 +649,38 @@ window.addEventListener("DOMContentLoaded", function () {
break;
}
case "buttonPlacementChange": {
const {
data: { buttonPlacement: buttonPlacements }
} = message;
for (const [featureName, { new: newPlacement, old: oldPlacement }] of Object.entries(buttonPlacements)) {
const buttonExists = checkIfFeatureButtonExists(featureName, newPlacement);
if (buttonExists) continue;
const { [featureName]: featureFunctions } = featureButtonFunctions;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const castFeatureFunctions = featureFunctions as unknown as FeatureFuncRecord;
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
await castFeatureFunctions.remove(oldPlacement);
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
await castFeatureFunctions.add();
const { data } = message;
const { multiButtonChanges, singleButtonChanges } = groupButtonChanges(data);
for (const [featureName, changes] of Object.entries(multiButtonChanges)) {
switch (featureName) {
case "playbackSpeedButtons": {
for (const [buttonName, { old: oldPlacement }] of Object.entries(changes)) {
const increasePlaybackSpeedButtonFuncs = getFeatureFunctions(
"increasePlaybackSpeedButton",
buttonName === "decreasePlaybackSpeedButton" ? multiButtonChanges[featureName]["increasePlaybackSpeedButton"].old : oldPlacement
);
const decreasePlaybackSpeedButtonFuncs = getFeatureFunctions(
"decreasePlaybackSpeedButton",
buttonName === "increasePlaybackSpeedButton" ? multiButtonChanges[featureName]["decreasePlaybackSpeedButton"].old : oldPlacement
);
switch (buttonName) {
case "increasePlaybackSpeedButton":
case "decreasePlaybackSpeedButton": {
await decreasePlaybackSpeedButtonFuncs.remove();
await increasePlaybackSpeedButtonFuncs.remove();
await decreasePlaybackSpeedButtonFuncs.add();
await increasePlaybackSpeedButtonFuncs.add();
}
}
}
break;
}
}
}
for (const [featureName, { old: oldPlacement }] of Object.entries(singleButtonChanges)) {
const featureFuncs = getFeatureFunctions(featureName, oldPlacement);
await featureFuncs.remove();
await featureFuncs.add();
}
break;
}
Expand Down
42 changes: 26 additions & 16 deletions src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ParseKeys, TOptions } from "i18next";
import type EnUS from "public/locales/en-US.json";
import type { YouTubePlayer } from "youtube-player/dist/types";

import z, { ZodType } from "zod";
Expand Down Expand Up @@ -118,6 +119,18 @@ export type VideoHistoryResumeType = (typeof videoHistoryResumeTypes)[number];
export const buttonPlacements = ["below_player", "feature_menu", "player_controls_left", "player_controls_right"] as const;
export type ButtonPlacement = (typeof buttonPlacements)[number];
export const featureMenuOpenTypes = ["click", "hover"] as const;
export type MultiButtonChange = {
[K in MultiButtonFeatureNames]: Record<FeatureToMultiButtonMap[K][number], { new: ButtonPlacement; old: ButtonPlacement }>;
};
export type SingleButtonChange = { [K in SingleButtonFeatureNames]: { new: ButtonPlacement; old: ButtonPlacement } };
export type ButtonPlacementChange = {
buttonPlacement: {
[Key in AllButtonNames]: {
new: ButtonPlacement;
old: ButtonPlacement;
};
};
};
export type FeatureMenuOpenType = (typeof featureMenuOpenTypes)[number];
export type DeepDarkCustomThemeColors = {
colorShadow: string;
Expand All @@ -131,12 +144,19 @@ export type DeepDarkCustomThemeColors = {
type TOptionsKeys = ParseKeys<"en-US", TOptions, undefined>;
export type AllButtonNames = Exclude<ExtractButtonNames<TOptionsKeys>, "featureMenu">;
export type SingleButtonNames = Exclude<AllButtonNames, MultiButtonNames>;
export type SingleButtonFeatureNames = Exclude<ExtractButtonFeatureNames<TOptionsKeys>, "featureMenu">;
export type SingleButtonFeatureNames = Exclude<
ExtractButtonFeatureNames<`pages.content.features.${string}.button.label` & TOptionsKeys>,
"featureMenu"
>;
export type MultiButtonNames = Exclude<AllButtonNames, SingleButtonFeatureNames>;
export type MultiButtonFeatureNames = Exclude<SingleButtonFeatureNames, AllButtonNames>;
export const featureToMultiButtonsMap: Map<MultiButtonFeatureNames, MultiButtonNames[]> = new Map([
["playbackSpeedButtons", ["increasePlaybackSpeedButton", "decreasePlaybackSpeedButton"]]
]);
export type MultiButtonFeatureNames = ExtractButtonFeatureNames<`pages.content.features.${string}.buttons.${string}.label` & TOptionsKeys>;
export type FeatureToMultiButtonMap = {
[K in MultiButtonFeatureNames]: (keyof EnUS["pages"]["content"]["features"][K]["buttons"])[];
};
const featureToMultiButtonMapEntries: FeatureToMultiButtonMap = {
playbackSpeedButtons: ["increasePlaybackSpeedButton" as const, "decreasePlaybackSpeedButton" as const]
};
export const featureToMultiButtonsMap = new Map(Object.entries(featureToMultiButtonMapEntries));
export type FeatureMenuItemIconId = `yte-${AllButtonNames}-icon`;
export type FeatureMenuItemId = `yte-feature-${AllButtonNames}-menuitem`;
export type FeatureMenuItemLabelId = `yte-${AllButtonNames}-label`;
Expand Down Expand Up @@ -259,17 +279,7 @@ export type ContentToBackgroundSendOnlyMessageMappings = {
};
export type ExtensionSendOnlyMessageMappings = {
automaticTheaterModeChange: DataResponseMessage<"automaticTheaterModeChange", { automaticTheaterModeEnabled: boolean }>;
buttonPlacementChange: DataResponseMessage<
"buttonPlacementChange",
{
buttonPlacement: {
[Key in AllButtonNames]: {
new: ButtonPlacement;
old: ButtonPlacement;
};
};
}
>;
buttonPlacementChange: DataResponseMessage<"buttonPlacementChange", ButtonPlacementChange>;
customCSSChange: DataResponseMessage<"customCSSChange", { customCSSCode: string; customCSSEnabled: boolean }>;
deepDarkThemeChange: DataResponseMessage<
"deepDarkThemeChange",
Expand Down
38 changes: 38 additions & 0 deletions src/utils/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@ import type {
ActionMessage,
AllButtonNames,
AnyFunction,
ButtonPlacement,
ButtonPlacementChange,
ContentSendOnlyMessageMappings,
ContentToBackgroundSendOnlyMessageMappings,
ExtensionSendOnlyMessageMappings,
FeatureToMultiButtonMap,
MessageMappings,
MessageSource,
Messages,
MultiButtonChange,
MultiButtonFeatureNames,
Nullable,
OnScreenDisplayPosition,
Path,
PathValue,
PlayerQualityFallbackStrategy,
Selector,
SendDataMessage,
SingleButtonChange,
SingleButtonFeatureNames,
SingleButtonNames,
YoutubePlayerQualityLevel
Expand Down Expand Up @@ -706,3 +712,35 @@ export function deepMerge(target: Record<string, unknown>, source: Record<string

return merged;
}

export function groupButtonChanges(changes: ButtonPlacementChange): {
multiButtonChanges: MultiButtonChange;
singleButtonChanges: SingleButtonChange;
} {
const multiButtonChanges: {
[K in MultiButtonFeatureNames]?: Partial<Record<FeatureToMultiButtonMap[K][number], { new: ButtonPlacement; old: ButtonPlacement }>>;
} = {};
const singleButtonChanges: { [K in SingleButtonFeatureNames]?: { new: ButtonPlacement; old: ButtonPlacement } } = {};

Object.keys(changes.buttonPlacement).forEach((button) => {
const buttonName = button;
const multiButtonFeatureNames = findKeyByValue(buttonName as Exclude<AllButtonNames, SingleButtonFeatureNames>);

if (multiButtonFeatureNames) {
const featureButtons = featureToMultiButtonsMap.get(multiButtonFeatureNames) || [];
if (featureButtons.includes(buttonName)) {
if (!multiButtonChanges[multiButtonFeatureNames]) {
multiButtonChanges[multiButtonFeatureNames] = {};
}
// eslint-disable-next-line prefer-destructuring
multiButtonChanges[multiButtonFeatureNames]![buttonName as FeatureToMultiButtonMap[typeof multiButtonFeatureNames][number]] =
changes.buttonPlacement[buttonName];
}
} else if (Object.keys(changes.buttonPlacement).includes(buttonName)) {
// eslint-disable-next-line prefer-destructuring
singleButtonChanges[buttonName as SingleButtonFeatureNames] = changes.buttonPlacement[buttonName];
}
});

return { multiButtonChanges: multiButtonChanges as MultiButtonChange, singleButtonChanges: singleButtonChanges as SingleButtonChange };
}

0 comments on commit caed598

Please sign in to comment.