Skip to content

Commit

Permalink
Add thumbnail desaturation feature
Browse files Browse the repository at this point in the history
This update introduces a feature that allows users to adjust the desaturation level of video thumbnails, helping to mitigate issues with overly vibrant, clickbait thumbnails. The new setting is accessible via the options page and changes are implemented in the video player and thumbnail rendering functions. This user-configurable setting can range from 0 (vibrant) to 100 (black and white).
  • Loading branch information
jgoedde committed Apr 12, 2024
1 parent 7c3b92d commit 2b9aef6
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 5 deletions.
2 changes: 1 addition & 1 deletion maze-utils
2 changes: 1 addition & 1 deletion public/_locales
9 changes: 9 additions & 0 deletions public/options/options.html
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,15 @@
<div class="small-description">__MSG_titleMaxLinesDescription__</div>
</div>

<div data-type="number-change" data-sync="thumbnailDesaturationLevel">
<label class="number-container">
<span class="optionLabel">__MSG_thumbnailDesaturationLevel__</span>
<input type="number" step="25" min="0" max="100" style="width: 50px;">
</label>

<div class="small-description">__MSG_whatDesaturateThumbnails__</div>
</div>

<div data-type="toggle" data-sync="keepUnsubmitted">
<div class="sb-switch-container">
<label class="sb-switch">
Expand Down
9 changes: 8 additions & 1 deletion src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ interface SBConfig {
invidiousInstances: string[];
keepUnsubmitted: boolean;
keepUnsubmittedInPrivate: boolean;
/**
* The level of desaturation applied to thumbnails (0 - 100).
*
* @type {number}
*/
thumbnailDesaturationLevel: number;
titleFormatting: TitleFormatting;
shouldCleanEmojis: boolean;
onlyTitleCaseInEnglish: boolean;
Expand Down Expand Up @@ -161,6 +167,7 @@ const syncDefaults = {
invidiousInstances: [],
keepUnsubmitted: true,
keepUnsubmittedInPrivate: false,
thumbnailDesaturationLevel: 0,
titleFormatting: isEnglish ? TitleFormatting.TitleCase : TitleFormatting.Disable,
shouldCleanEmojis: true,
onlyTitleCaseInEnglish: false,
Expand Down Expand Up @@ -210,4 +217,4 @@ const localDefaults = {
};

const Config = new ConfigClass(syncDefaults, localDefaults, migrateOldSyncFormats, true);
export default Config;
export default Config;
24 changes: 23 additions & 1 deletion src/thumbnails/thumbnailRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,15 @@ function getThumbnailBox(image: HTMLElement, brandingLocation: BrandingLocation)
}
}

/**
* Applies desaturation effect to the supplied thumbnail.
*
* @param {HTMLImageElement | HTMLElement} thumbnail - The HTML image element or HTML element representing the thumbnail.
*/
function applyThumbnailDesaturation(thumbnail: HTMLImageElement | HTMLElement) {
thumbnail.style.filter = `grayscale(${(Config.config!.thumbnailDesaturationLevel / 100)})`;
}

export async function replaceThumbnail(element: HTMLElement, videoID: VideoID, brandingLocation: BrandingLocation,
showCustomBranding: ShowCustomBrandingInfo, timestamp?: number): Promise<boolean> {
const thumbnailSelector = getThumbnailSelector(brandingLocation);
Expand All @@ -540,6 +549,13 @@ export async function replaceThumbnail(element: HTMLElement, videoID: VideoID, b
: await waitFor(() => element.querySelector(thumbnailSelector) as HTMLImageElement);
const box = getThumbnailBox(image, brandingLocation);

if (Config.config!.extensionEnabled) {
applyThumbnailDesaturation(image)
} else {
// Reset back to normal
image.style.filter = `grayscale(0)`;
}

if (showCustomBranding.knownValue === false || !Config.config!.extensionEnabled
|| shouldReplaceThumbnailsFastCheck(videoID) === false) {
resetToShowOriginalThumbnail(image, brandingLocation);
Expand Down Expand Up @@ -588,6 +604,12 @@ export async function replaceThumbnail(element: HTMLElement, videoID: VideoID, b
}

thumbnail!.style.removeProperty("display");
if (Config.config!.extensionEnabled) {
applyThumbnailDesaturation(thumbnail);
} else {
// Reset back to normal
thumbnail.style.filter = "grayscale(0)";
}
if (!(thumbnail instanceof HTMLImageElement) || thumbnail.complete) {
if (removeWidth) thumbnail!.style.removeProperty("width");
removeBackgroundColor(image, brandingLocation);
Expand Down Expand Up @@ -956,4 +978,4 @@ async function getAutogeneratedThumbnailUrl(videoID: VideoID): Promise<string> {
}

return `https://i.ytimg.com/vi_webp/${videoID}/${thumbnailCode}.webp`;
}
}
3 changes: 2 additions & 1 deletion src/videoBranding/videoBranding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ export function setupOptionChangeListener(): void {
"useCrowdsourcedTitles",
"titleFormatting",
"shouldCleanEmojis",
"thumbnailDesaturationLevel",
"onlyTitleCaseInEnglish",
"thumbnailFallback",
"thumbnailFallbackAutogenerated",
Expand Down Expand Up @@ -479,4 +480,4 @@ export function getActualShowCustomBranding(showCustomBranding: ShowCustomBrandi
return showCustomBranding.knownValue === null
? showCustomBranding.actualValue
: Promise.resolve(showCustomBranding.knownValue);
}
}

0 comments on commit 2b9aef6

Please sign in to comment.