Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stage 1: Refactor codebase (re) (re) #689

Open
wants to merge 46 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
5abcc96
refactor: reduce indentation on `setDefaultValues()`
mist8kengas May 2, 2024
1713323
refactor: optimize function
mist8kengas May 2, 2024
f6d57ef
refactor: qol improvements
mist8kengas May 2, 2024
1d1f65a
refactor: custom css
mist8kengas May 2, 2024
9c88d92
Merge branch 'dev' of https://github.com/YouTube-Enhancer/extension i…
mist8kengas May 10, 2024
91e4e98
refactor: deep dark css
mist8kengas May 10, 2024
109c28b
refactor: feature menu
mist8kengas May 10, 2024
55cbe80
refactor: hide x features
mist8kengas May 10, 2024
f33ab7c
refactor: loop button
mist8kengas May 10, 2024
3356e64
refactor: maximize button
mist8kengas May 10, 2024
a576f5c
refactor: transcript button
mist8kengas May 10, 2024
2b3b621
refactor: open settings on hover feature
mist8kengas May 10, 2024
f45afef
fix: make types constrained
mist8kengas May 10, 2024
3d7a1fa
refactor: playback speed button
mist8kengas May 10, 2024
f75ca53
refactor: player speed
mist8kengas May 10, 2024
6cb943f
refactor: remaining time
mist8kengas May 10, 2024
11eed28
refactor: remove redirect links
mist8kengas May 10, 2024
f5d0dcc
refactor: screenshot button
mist8kengas May 10, 2024
82bc5bc
refactor: scroll wheel speed control
mist8kengas May 10, 2024
279a22b
refactor: scroll wheel volume control
mist8kengas May 10, 2024
86c2cee
refactor: share shortener
mist8kengas May 10, 2024
29afd29
refactor: auto scroll shorts
mist8kengas May 10, 2024
dc4aca8
refactor: video history
mist8kengas May 10, 2024
7865dfc
refactor: volume boost logic
mist8kengas May 10, 2024
3151b94
refactor: pause background players
mist8kengas May 10, 2024
59c9d0a
refactor: player quality
mist8kengas May 10, 2024
f6383ac
refactor: remember volume
mist8kengas May 10, 2024
2205a63
refactor: skip continue watching
mist8kengas May 10, 2024
4ea23fb
refactor: useNotifications provider
mist8kengas May 10, 2024
04f9aad
refactor: pages
mist8kengas May 10, 2024
79f2303
feat(docs): add contributing page
mist8kengas May 10, 2024
b750794
Merge branch 'dev' into dev
VampireChicken12 May 11, 2024
663c56b
Merge branch 'dev' into dev
VampireChicken12 May 19, 2024
aa51abd
Merge branch 'dev' into dev
VampireChicken12 May 19, 2024
b8b31fe
Merge branch 'dev' into dev
VampireChicken12 May 20, 2024
de260f3
Merge branch 'dev' into dev
VampireChicken12 Jun 13, 2024
c2ad23c
Merge branch 'dev' into dev
VampireChicken12 Jun 14, 2024
20631b6
fix: eslint/prettier
livingflore Jun 16, 2024
95ac395
fix: assert node type
livingflore Jun 16, 2024
1361f45
Merge branch 'dev' into dev
VampireChicken12 Jun 16, 2024
1a1298c
Merge branch 'dev' into dev
VampireChicken12 Jun 22, 2024
9f0e468
chore: format
VampireChicken12 Jun 23, 2024
cb94460
Merge branch 'dev' into dev
VampireChicken12 Jun 30, 2024
e4df9c7
Merge branch 'dev' into dev
VampireChicken12 Jul 1, 2024
5abc38b
Merge branch 'dev' into dev
VampireChicken12 Nov 22, 2024
83f80fd
Merge pull request #3 from YouTube-Enhancer/dev
mist8kengas Nov 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -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](<https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)>)
- [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)
15 changes: 7 additions & 8 deletions src/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, unknown>, storedValue as Record<string, unknown>);
// 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<string, unknown>, storedValue as Record<string, unknown>);
// 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);
Expand Down
6 changes: 2 additions & 4 deletions src/features/automaticTheaterMode/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { YouTubePlayerDiv } from "@/src/types";
import { isLivePage, isWatchPage, waitForSpecificMessage } from "@/src/utils/utilities";

export async function enableAutomaticTheaterMode() {
if (!isWatchPage()) return;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Remove redundant isWatchPage() check.

The code checks isWatchPage() twice - once at the start and again in the player container query. Since we have an early return, the second check is unnecessary.

- const playerContainer = isWatchPage() || isLivePage() ? document.querySelector<YouTubePlayerDiv>("div#movie_player") : null;
+ const playerContainer = isLivePage() ? document.querySelector<YouTubePlayerDiv>("div#movie_player") : document.querySelector<YouTubePlayerDiv>("div#movie_player");

Also applies to: 16-16

🧰 Tools
🪛 ESLint

[error] 6-6: Insert

(prettier/prettier)

// Wait for the "options" message from the content script
const {
data: {
Expand All @@ -16,10 +17,7 @@ export async function enableAutomaticTheaterMode() {
// 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<HTMLButtonElement>("button.ytp-size-button");
// If the size button is not available return
Expand Down
20 changes: 6 additions & 14 deletions src/features/buttonPlacement/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ export function makeFeatureButton<Name extends AllButtonNames, Placement extends
isToggle: boolean,
initialChecked: boolean = false
) {
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"],
Expand Down Expand Up @@ -72,18 +72,12 @@ export function makeFeatureButton<Name extends AllButtonNames, Placement extends
return button;
}

const isIconToggle = typeof icon === "object" && "off" in icon && "on" in icon;
if (isToggle) {
button.ariaChecked = initialChecked ? "true" : "false";
if (typeof icon === "object" && "off" in icon && "on" in icon) {
button.append(initialChecked ? icon.on : icon.off);
} else if (icon instanceof SVGSVGElement) {
button.append(icon);
}
} else {
if (icon instanceof SVGSVGElement) {
button.append(icon);
}
if (isIconToggle) button.append(icon.off);
}
if (!isIconToggle && icon instanceof SVGSVGElement) button.append(icon);

eventManager.addEventListener(button, "mouseover", tooltipListener, featureName);
eventManager.addEventListener(
Expand All @@ -98,9 +92,7 @@ export function makeFeatureButton<Name extends AllButtonNames, Placement extends
return button;
}
export function updateFeatureButtonIcon(button: HTMLButtonElement, icon: SVGElement) {
if (button.firstChild) {
button.firstChild.replaceWith(icon);
}
button.firstChild?.replaceWith(icon);
}
export function updateFeatureButtonTitle(buttonName: AllButtonNames, title: string) {
const button = document.querySelector<HTMLButtonElement>(`#${getFeatureButtonId(buttonName)}`);
Expand Down Expand Up @@ -166,7 +158,7 @@ export function checkIfFeatureButtonExists(buttonName: AllButtonNames, placement
}
}
}
export function getFeatureButtonId(buttonName: AllButtonNames) {
export function getFeatureButtonId<ButtonName extends AllButtonNames>(buttonName: ButtonName) {
return `yte-feature-${buttonName}-button` as const;
}
export function getFeatureButton(buttonName: AllButtonNames) {
Expand Down
15 changes: 3 additions & 12 deletions src/features/customCSS/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,15 @@ export async function enableCustomCSS() {
} = 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<HTMLStyleElement>(`#${customCssID}`);
// Check if the custom CSS style element exists
if (!customCSSStyleElement) return;
// Remove the custom CSS style element
customCSSStyleElement.remove();
customCSSStyleElement?.remove();
}
7 changes: 2 additions & 5 deletions src/features/customCSS/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import { customCssID } from "@/src/features/customCSS";
export function updateCustomCSS({ custom_css_code }: Pick<configuration, "custom_css_code">) {
// Get the custom CSS style element
const customCSSStyleElement = document.querySelector<HTMLStyleElement>(`#${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<configuration, "custom_css_code">) {
// Create the custom CSS style element
Expand All @@ -20,6 +18,5 @@ export function customCSSExists() {
// Get the custom CSS style element
const customCSSStyleElement = document.querySelector<HTMLStyleElement>(`#${customCssID}`);
// Check if the custom CSS style element exists
if (!customCSSStyleElement) return false;
return true;
return customCSSStyleElement !== null;
}
9 changes: 4 additions & 5 deletions src/features/deepDarkCSS/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ export async function enableDeepDarkCSS() {
// 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(
Expand All @@ -27,8 +28,6 @@ export async function enableDeepDarkCSS() {
export function disableDeepDarkCSS() {
// Get the deep dark theme style element
const deepDarkThemeStyleElement = document.querySelector<HTMLStyleElement>(`#${deepDarkCssID}`);
// Check if the deep dark theme style element exists
if (!deepDarkThemeStyleElement) return;
// Remove the deep dark theme style element
deepDarkThemeStyleElement.remove();
deepDarkThemeStyleElement?.remove();
}
7 changes: 2 additions & 5 deletions src/features/deepDarkCSS/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLStyleElement>(`#${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
Expand All @@ -21,8 +19,7 @@ export function deepDarkCSSExists() {
// Get the custom CSS style element
const customCSSStyleElement = document.querySelector<HTMLStyleElement>(`#${deepDarkCssID}`);
// Check if the custom CSS style element exists
if (!customCSSStyleElement) return false;
return true;
return customCSSStyleElement !== null;
}

export function getDeepDarkCustomThemeStyle({
Expand Down
5 changes: 1 addition & 4 deletions src/features/featureMenu/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,5 @@ export function setupFeatureMenuEventListeners(featureMenuOpenType: FeatureMenuO
});
}
const observer = new MutationObserver(handleMutation);
observer.observe(playerContainer, {
childList: true,
subtree: true
});
observer.observe(playerContainer, { childList: true, subtree: true });
}
22 changes: 7 additions & 15 deletions src/features/featureMenu/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,15 @@ export async function addFeatureItemToMenu<Name extends AllButtonNames, Toggle e
eventManager.addEventListener(menuItem, "click", () => featureMenuClickListener(menuItem, listener, isToggle), featureName);
menuItem.appendChild(menuItemLabel);
// If it's a toggle item, create the toggle elements
const menuItemContent = document.createElement("div");
menuItemContent.classList.add("ytp-menuitem-content");
if (isToggle) {
const menuItemContent = document.createElement("div");
menuItemContent.classList.add("ytp-menuitem-content");
const menuItemToggle = document.createElement("div");
menuItemToggle.classList.add("ytp-menuitem-toggle-checkbox");
menuItemContent.appendChild(menuItemToggle);
menuItem.appendChild(menuItemContent);
menuItem.ariaChecked = initialChecked ? "true" : "false";
} else {
const menuItemContent = document.createElement("div");
menuItemContent.classList.add("ytp-menuitem-content");
menuItem.appendChild(menuItemContent);
}
menuItem.appendChild(menuItemContent);
// Add the item to the feature menu panel
featureMenuPanel.appendChild(menuItem);
// Adjust the height and width of the feature menu
Expand Down Expand Up @@ -164,14 +160,10 @@ export function updateFeatureMenuTitle(title: string) {
* @param buttonName the name of the button
* @returns { featureMenuItemIconId, featureMenuItemId, featureMenuItemLabelId}
*/
export function getFeatureIds(buttonName: AllButtonNames): {
featureMenuItemIconId: FeatureMenuItemIconId;
featureMenuItemId: FeatureMenuItemId;
featureMenuItemLabelId: FeatureMenuItemLabelId;
} {
const featureMenuItemIconId: FeatureMenuItemIconId = `yte-${buttonName}-icon`;
const featureMenuItemId: FeatureMenuItemId = `yte-feature-${buttonName}-menuitem`;
const featureMenuItemLabelId: FeatureMenuItemLabelId = `yte-${buttonName}-label`;
export function getFeatureIds<ButtonName extends AllButtonNames>(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,
Expand Down
6 changes: 2 additions & 4 deletions src/features/hideLiveStreamChat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ export async function enableHideLiveStreamChat() {
await waitForAllElements(["div#player", "div#player-wide-container", "div#video-container", "div#player-container"]);
const player = document.querySelector<YouTubePlayerDiv>("div#movie_player");
if (!player) return;
const playerData = await player.getVideoData();
if (!playerData.isLive) return;
if (!(await player.getVideoData()).isLive) return;
modifyElementsClassList("add", [
{
className: "yte-hide-live-stream-chat",
Expand All @@ -35,8 +34,7 @@ export async function enableHideLiveStreamChat() {
export async function disableHideLiveStreamChat() {
const player = document.querySelector<YouTubePlayerDiv>("div#movie_player");
if (!player) return;
const playerData = await player.getVideoData();
if (!playerData.isLive) return;
if (!(await player.getVideoData()).isLive) return;
modifyElementsClassList("remove", [
{
className: "yte-hide-live-stream-chat",
Expand Down
6 changes: 2 additions & 4 deletions src/features/hideShorts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ export async function enableHideShorts() {
export function disableHideShorts() {
showShorts();
// Disconnect the observer
if (shortsObserver) {
shortsObserver.disconnect();
shortsObserver = null;
}
shortsObserver?.disconnect();
shortsObserver = null;
}
5 changes: 1 addition & 4 deletions src/features/hideShorts/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ type ElementVisibilityAction = (element: HTMLElement) => void;

function toggleElementVisibility(selector: string, action: ElementVisibilityAction) {
const elements = document.querySelectorAll<HTMLDivElement>(selector);
if (elements.length === 0) return;
elements.forEach((element) => action(element));
}

Expand Down Expand Up @@ -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);
Expand Down
Loading