Skip to content

Commit

Permalink
fix(content/index.tsx): Fix code running twice on page load
Browse files Browse the repository at this point in the history
  • Loading branch information
VampireChicken12 committed Aug 31, 2023
1 parent bd3a314 commit 3d9dc74
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 75 deletions.
2 changes: 1 addition & 1 deletion release.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ module.exports = {
[
"@semantic-release/exec",
{
verifyReleaseCmd: 'npm version ${nextRelease.version} -m "chore(release): ${nextRelease.version}";npm run build'
verifyReleaseCmd: "node -e \"const packageJson = require('./package.json');packageJson.version=${nextRelease.version}\";npm run build"
}
]
],
Expand Down
113 changes: 39 additions & 74 deletions src/pages/content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
// TODO: Add always show progressbar feature

// Centralized Event Manager
type FeatureName = "videoHistory" | "screenshotButton" | "maximizePlayerButton" | "scrollWheelVolumeControl";
type EventCallback<K extends keyof HTMLElementEventMap> = (event: HTMLElementEventMap[K]) => void;

interface EventListenerInfo<K extends keyof ElementEventMap> {
Expand All @@ -32,80 +31,60 @@ type EventManager = {
target: HTMLElementTagNameMap[keyof HTMLElementTagNameMap],
eventName: T,
callback: EventCallback<keyof HTMLElementEventMap>,
featureName: FeatureName
featureName: string
) => void;

removeEventListener: <T extends keyof HTMLElementEventMap>(
target: HTMLElementTagNameMap[keyof HTMLElementTagNameMap],
eventName: T,
featureName: FeatureName
featureName: string
) => void;

removeEventListeners: (featureName: FeatureName) => void;
removeEventListeners: (featureName: string) => void;

removeAllEventListeners: () => void;
};

const eventManager: EventManager = {
// Map of feature names to a map of targets to
// event listener info objects
listeners: new Map(),

// Adds an event listener for the given target, eventName, and featureName
addEventListener: function (target, eventName, callback, featureName) {
// Get the map of target listeners for the given featureName
const targetListeners = this.listeners.get(featureName) || new Map();
// Store the event listener info object in the map
targetListeners.set(target, { eventName, callback, target });
// Store the map of target listeners for the given featureName
targetListeners.set(target, { eventName, callback });
this.listeners.set(featureName, targetListeners);
// Add the event listener to the target
target.addEventListener(eventName, callback);
},

// Removes the event listener for the given target, eventName, and featureName
removeEventListener: function (target, eventName, featureName) {
// Get the map of target listeners for the given featureName
const targetListeners = this.listeners.get(featureName);
if (targetListeners) {
// Get the event listener info object for the given target
const listenerInfo = targetListeners.get(target);
if (listenerInfo) {
// Remove the event listener from the target
target.removeEventListener(eventName, listenerInfo.callback);
// Remove the event listener info object from the map
targetListeners.delete(target);
}
if (targetListeners.size === 0) {
// Remove the map of target listeners from the map
this.listeners.delete(featureName);
}
}
},

// Removes all event listeners for the given featureName
removeEventListeners: function (featureName) {
// Get the map of target listeners for the given featureName
const targetListeners = this.listeners.get(featureName);
if (targetListeners) {
// Remove all event listeners from their targets
targetListeners.forEach(({ target, eventName, callback }) => {
target.removeEventListener(eventName, callback);
});
// Remove the map of target listeners from the map
this.listeners.delete(featureName);
}
},

// Removes all event listeners
removeAllEventListeners: function () {
// Remove all event listeners from all targets
this.listeners.forEach((targetListeners) => {
targetListeners.forEach(({ target, eventName, callback }) => {
target.removeEventListener(eventName, callback);
});
});
// Remove all maps of target listeners from the map
this.listeners.clear();
}
};
Expand Down Expand Up @@ -272,14 +251,6 @@ async function promptUserToResumeVideo(timestamp: number) {
progressBar.style.borderBottomLeftRadius = "5px";
prompt.appendChild(progressBar);
}
const resumeButtonClickListener = () => {
// Hide the prompt and clear the countdown timer
clearInterval(countdownInterval);
prompt.style.display = "none";
browserColorLog(`Resuming video`, "FgGreen");
playerContainer.seekTo(timestamp, true);
};
const resumeButton = document.createElement("button") ?? document.getElementById("resume-prompt-button");
// Create the prompt element if it doesn't exist
if (!document.getElementById("resume-prompt")) {
prompt.id = "resume-prompt";
Expand All @@ -294,8 +265,11 @@ async function promptUserToResumeVideo(timestamp: number) {
prompt.style.boxShadow = "0px 0px 10px rgba(0, 0, 0, 0.2)";
prompt.style.zIndex = "25000";
document.body.appendChild(prompt);
resumeButton.id = "resume-prompt-button";

// Create a resume button
const resumeButton = document.createElement("button");
resumeButton.textContent = "Resume";

resumeButton.style.backgroundColor = "hsl(213, 80%, 50%)";
resumeButton.style.border = "transparent";
resumeButton.style.color = "white";
Expand All @@ -308,45 +282,45 @@ async function promptUserToResumeVideo(timestamp: number) {
resumeButton.style.textAlign = "center";
resumeButton.style.verticalAlign = "middle";
resumeButton.style.transition = "all 0.5s ease-in-out";
const resumeButtonClickListener = () => {
// Hide the prompt and clear the countdown timer
clearInterval(countdownInterval);
prompt.style.display = "none";
browserColorLog(`Resuming video`, "FgGreen");
playerContainer.seekTo(timestamp, true);
};
eventManager.addEventListener(resumeButton, "click", resumeButtonClickListener, "videoHistory");

prompt.appendChild(resumeButton);
}
if (document.getElementById("resume-prompt-button")) {
eventManager.removeEventListener(resumeButton, "click", "videoHistory");
}
eventManager.addEventListener(resumeButton, "click", resumeButtonClickListener, "videoHistory");

// Display the prompt
prompt.style.display = "block";
}

// #endregion Video History
// TODO: make sure listeners are cleaned up properly before re adding them
let wasInTheatreMode = false;
let setToTheatreMode = false;
// #region Main functions
async function takeScreenshot(videoElement: HTMLVideoElement) {
try {
// Create a canvas element and get its context
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");

// Set the dimensions of the canvas to the video's dimensions
const { videoWidth, videoHeight } = videoElement;
canvas.width = videoWidth;
canvas.height = videoHeight;

// Draw the video element onto the canvas
if (!context) return;

context.drawImage(videoElement, 0, 0, canvas.width, canvas.height);

// Wait for the options message and get the format from it
const { options } = await waitForSpecificMessage("options", { source: "content_script" });
if (!options) return;
const { screenshot_save_as, screenshot_format } = options;
const format = `image/${screenshot_format}`;

// Get the data URL of the canvas and create a blob from it
const dataUrl = canvas.toDataURL(format);

const blob = await new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, "image/png"));
if (!blob) return;

Expand Down Expand Up @@ -620,7 +594,7 @@ function maximizePlayer(maximizePlayerButton: HTMLButtonElement) {
maximizePlayerButton.appendChild(makeMinimizeSVG());
}
}
// TODO: get played progress bar to be accurate when maximized from default view

// TODO: Add event listener that updates scrubber position when maximize button is clicked
function updateProgressBarPositions() {
const seekBar = document.querySelector("div.ytp-progress-bar") as HTMLDivElement | null;
Expand Down Expand Up @@ -769,7 +743,7 @@ async function addMaximizePlayerButton(): Promise<void> {
}
}
function seekBarMouseEnterListener(event: MouseEvent) {
// TODO: get the seek preview to be in the correct place when the video is maximized from default view
// TODO: get the seek preview to be in the correct place when the video is maximized
const tooltip = document.querySelector("#movie_player > div.ytp-tooltip") as HTMLDivElement | null;
if (!tooltip) return;
// Get the video element
Expand Down Expand Up @@ -1101,30 +1075,16 @@ async function volumeBoost() {
browserColorLog(`Setting volume boost to ${Math.pow(10, volume_boost_amount / 20)}`, "FgMagenta");
window.gainNode.gain.value = Math.pow(10, volume_boost_amount / 20);
} else {
try {
window.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const source = window.audioCtx.createMediaElementSource(player as unknown as HTMLMediaElement);
const gainNode = window.audioCtx.createGain();
source.connect(gainNode);
gainNode.connect(window.audioCtx.destination);
window.gainNode = gainNode;
browserColorLog(`Setting volume boost to ${Math.pow(10, volume_boost_amount / 20)}`, "FgMagenta");
gainNode.gain.value = Math.pow(10, volume_boost_amount / 20);
} catch (error) {
browserColorLog(`Failed to set volume boost: ${formatError(error)}`, "FgRed");
}
window.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const source = window.audioCtx.createMediaElementSource(player as unknown as HTMLMediaElement);
const gainNode = window.audioCtx.createGain();
source.connect(gainNode);
gainNode.connect(window.audioCtx.destination);
window.gainNode = gainNode;
browserColorLog(`Setting volume boost to ${Math.pow(10, volume_boost_amount / 20)}`, "FgMagenta");
gainNode.gain.value = Math.pow(10, volume_boost_amount / 20);
}
}
function formatError(error: unknown) {
return error instanceof Error
? `\n${error.stack}\n\n${error.message}`
: error instanceof Object
? Object.hasOwnProperty.call(error, "toString") && typeof error.toString === "function"
? error.toString()
: "unknown error"
: "";
}

// #endregion Main functions
// #region Intercommunication functions
/**
Expand Down Expand Up @@ -1618,14 +1578,10 @@ function drawVolumeDisplay({
* @returns {string|null} The first section of the URL path, or null if not found.
*/
function extractFirstSectionFromYouTubeURL(url: string): string | null {
// Parse the URL into its components
const urlObj = new URL(url);
const { pathname: path } = urlObj;

// Split the path into an array of sections
const sections = path.split("/").filter((section) => section !== "");

// Return the first section, or null if not found
if (sections.length > 0) {
return sections[0];
}
Expand All @@ -1644,7 +1600,16 @@ function isShortsPage() {
// Error handling
window.addEventListener("error", (event) => {
event.preventDefault();
browserColorLog(formatError(event.error), "FgRed");
browserColorLog(
event.error instanceof Error
? event.error.message
: event.error instanceof Object
? Object.hasOwnProperty.call(event.error, "toString") && typeof event.error.toString === "function"
? event.error.toString()
: "unknown error"
: "",
"FgRed"
);
});
window.addEventListener("unhandledrejection", (event) => {
event.preventDefault();
Expand Down

0 comments on commit 3d9dc74

Please sign in to comment.