version 4.3.68

This commit is contained in:
Lawrence Hook
2026-01-28 21:31:06 -05:00
parent 182f3cb3ee
commit f894715b62
10 changed files with 484 additions and 128 deletions
+7 -2
View File
@@ -3,7 +3,7 @@
"description": "Spend less time on YouTube. Customize YouTube's user interface to be less engaging.",
"homepage_url": "https://github.com/lawrencehook/remove-youtube-suggestions",
"manifest_version": 3,
"version": "4.3.67",
"version": "4.3.68",
"icons": {
"16": "/images/16.png",
@@ -22,6 +22,7 @@
"/shared/main.js",
"/shared/https.js",
"/shared/utils.js",
"/shared/banners.js",
"/content-script/main.js"
],
"css": ["/content-script/main.css"],
@@ -51,5 +52,9 @@
],
"host_permissions": [
"*://*.youtube.com/*"
]
],
"web_accessible_resources": [{
"resources": ["/images/rys.svg"],
"matches": ["*://*.youtube.com/*"]
}]
}
+220 -44
View File
@@ -191,61 +191,139 @@ html[global_enable="true"] ytd-rich-grid-row[empty="true"] #contents {
}
/* Reveal suggestions button */
.rys_reveal_button_container {
width: auto;
height: auto;
/* Reveal suggestions box */
.rys_reveal_box {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 10px;
padding: 14px 18px;
margin: auto;
margin-top: 15%;
background: var(--rys-primary);
border-radius: 12px;
font-size: 14px;
font-family: var(--rys-font);
z-index: 1000000;
position: relative;
width: fit-content;
box-shadow: 0 4px 16px var(--rys-shadow);
}
.rys_reveal_box * {
color: var(--rys-text);
}
.rys_reveal_header {
display: flex;
align-items: center;
justify-content: center;
justify-content: space-between;
width: 100%;
padding-bottom: 8px;
border-bottom: 1px solid var(--rys-separator);
}
.rys_reveal_button {
position: relative;
margin-top: 20%;
font-size: 20px;
padding: var(--yt-button-padding);
cursor: default;
z-index: 1000000;
color: var(--yt-spec-text-primary);
background-color: var(--yt-spec-base-background);
border: 3px solid var(--yt-spec-raised-background);
border-radius: var(--yt-button-border-radius);
.rys_reveal_branding {
display: flex;
align-items: center;
gap: 5px;
opacity: 0.8;
}
.rys_reveal_button:hover {
background-color: var(--yt-spec-raised-background);
}
#close_reveal_button {
position: absolute;
top: 0;
right: 3px;
.rys_reveal_logo {
width: 14px;
height: 14px;
}
.rys_reveal_brand {
font-weight: 600;
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.rys_reveal_actions {
display: flex;
align-items: center;
gap: 10px;
}
.rys_reveal_content {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
gap: 24px;
white-space: nowrap;
}
.rys_reveal_message {
font-weight: 500;
}
.rys_reveal_show {
background: var(--rys-text);
color: var(--rys-primary) !important;
padding: 6px 16px;
border-radius: 20px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
z-index: 1000001;
color: var(--yt-spec-text-primary);
font-size: 12px;
}
#close_reveal_button:hover {
text-decoration: none;
box-shadow: 0 2px 6px var(--rys-shadow);
}
html:not([global_enable="true"]) #rys_homepage_reveal_button,
html:not([add_reveal_button="true"]) #rys_homepage_reveal_button,
html:not([remove_homepage="true"]) #rys_homepage_reveal_button,
html:not([on_homepage="true"]) #rys_homepage_reveal_button,
.rys_reveal_show:hover {
background: #f5f5f5;
}
html:not([global_enable="true"]) #rys_sidebar_reveal_button,
html:not([add_reveal_button="true"]) #rys_sidebar_reveal_button,
html:not([remove_sidebar="true"]) #rys_sidebar_reveal_button,
html:not([on_video="true"]) #rys_sidebar_reveal_button,
.rys_reveal_dismiss {
cursor: pointer;
font-size: 11px;
white-space: nowrap;
opacity: 0.75;
text-decoration: none;
transition: opacity 0.15s ease;
}
html:not([global_enable="true"]) #rys_end_of_video_reveal_button,
html:not([add_reveal_button="true"]) #rys_end_of_video_reveal_button,
html:not([remove_end_of_video="true"]) #rys_end_of_video_reveal_button,
html:not([on_video="true"]) #rys_end_of_video_reveal_button,
#movie_player:not(.ended-mode) #rys_end_of_video_reveal_button,
.rys_reveal_dismiss:hover {
opacity: 1;
text-decoration: underline;
}
.rys_reveal_close {
background: none;
border: none;
font-size: 11px;
cursor: pointer;
padding: 0;
opacity: 0.6;
line-height: 1;
color: var(--rys-text);
transition: opacity 0.15s ease;
display: flex;
align-items: center;
}
.rys_reveal_close:hover {
opacity: 1;
}
html:not([global_enable="true"]) #rys_homepage_reveal_box,
html:not([add_reveal_homepage="true"]) #rys_homepage_reveal_box,
html:not([remove_homepage="true"]) #rys_homepage_reveal_box,
html:not([on_homepage="true"]) #rys_homepage_reveal_box,
html:not([global_enable="true"]) #rys_sidebar_reveal_box,
html:not([add_reveal_sidebar="true"]) #rys_sidebar_reveal_box,
html:not([remove_sidebar="true"]) #rys_sidebar_reveal_box,
html:not([on_video="true"]) #rys_sidebar_reveal_box,
html:not([global_enable="true"]) #rys_end_of_video_reveal_box,
html:not([add_reveal_end_of_video="true"]) #rys_end_of_video_reveal_box,
html:not([remove_end_of_video="true"]) #rys_end_of_video_reveal_box,
html:not([on_video="true"]) #rys_end_of_video_reveal_box,
#movie_player:not(.ended-mode) #rys_end_of_video_reveal_box,
html[foo="bar"] {
display: none;
@@ -399,4 +477,102 @@ html[global_enable="true"][foo=bar]
html[global_enable='true'][grayscale_mode='true'] ytd-app {
filter: grayscale(100%);
}
}
/* RYS UI Variables */
:root {
--rys-primary: #065fd4;
--rys-text: #fff;
--rys-separator: rgba(255, 255, 255, 0.15);
--rys-shadow: rgba(0, 0, 0, 0.15);
--rys-font: "Roboto", "Arial", sans-serif;
--rys-banner-height: 40px;
}
/* Announcement Banner on YouTube */
.rys_announcement_banner {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 16px;
background: var(--rys-primary);
font-size: 13px;
font-family: var(--rys-font);
z-index: 2350;
position: fixed;
top: 0;
left: 0;
right: 0;
}
/* Push down YouTube's fixed header and content when banner is visible */
html[rys-banner-visible="true"] #masthead-container,
html[rys-banner-visible="true"] ytd-masthead {
top: var(--rys-banner-height) !important;
}
html[rys-banner-visible="true"] ytd-app {
margin-top: var(--rys-banner-height);
}
html[rys-banner-visible="true"] tp-yt-app-drawer #contentContainer,
html[rys-banner-visible="true"] ytd-mini-guide-renderer {
margin-top: var(--rys-banner-height);
}
.rys_announcement_banner * {
color: var(--rys-text);
}
.rys_banner_logo {
width: 20px;
height: 20px;
}
.rys_banner_brand {
font-weight: 600;
margin-right: 8px;
padding-right: 12px;
border-right: 1px solid rgba(255, 255, 255, 0.4);
}
.rys_banner_message {
flex: 1;
}
.rys_banner_link {
text-decoration: underline;
opacity: 0.9;
cursor: pointer;
}
.rys_banner_link:hover {
opacity: 1;
}
.rys_banner_dismiss {
text-decoration: underline;
cursor: pointer;
opacity: 0.7;
font-size: 12px;
white-space: nowrap;
}
.rys_banner_dismiss:hover {
opacity: 1;
}
.rys_banner_close {
background: none;
border: none;
font-size: 18px;
cursor: pointer;
padding: 0 4px;
opacity: 0.7;
line-height: 1;
color: var(--rys-text);
}
.rys_banner_close:hover {
opacity: 1;
}
+80 -38
View File
@@ -19,6 +19,31 @@ const subsRegex = new RegExp(/\/feed\/subscriptions$/, 'i');
// Dynamic settings variables
const cache = {};
const closedRevealBoxes = new Set();
const rysLogoUrl = browser.runtime.getURL('images/rys.svg');
const REVEAL_BOX_CONFIGS = [
{
containerSelector: 'ytd-page-manager',
boxId: 'rys_homepage_reveal_box',
message: 'Homepage suggestions are hidden.',
showAction: () => HTML.setAttribute('remove_homepage', false),
revealSetting: 'add_reveal_homepage',
},
{
containerSelector: '#secondary-inner',
boxId: 'rys_sidebar_reveal_box',
message: 'Sidebar suggestions are hidden.',
showAction: () => HTML.setAttribute('remove_sidebar', false),
revealSetting: 'add_reveal_sidebar',
},
{
containerSelector: '#movie_player',
boxId: 'rys_end_of_video_reveal_box',
message: 'End-of-video suggestions are hidden.',
showAction: () => HTML.setAttribute('remove_end_of_video', false),
revealSetting: 'add_reveal_end_of_video',
},
];
let url = location.href;
let theaterClicked = false, hyper = false;
let onResultsPage = resultsPageRegex.test(url);
@@ -62,6 +87,11 @@ browser.storage.onChanged.addListener(logStorageChange);
browser.storage.local.get(settings => {
if (!settings) return;
const revealUpdates = migrateRevealSettings(settings);
if (Object.keys(revealUpdates).length) {
browser.storage.local.set(revealUpdates);
}
Object.entries({ ...DEFAULT_SETTINGS, ...settings}).forEach(([ id, value ]) => {
HTML.setAttribute(id, value);
cache[id] = value;
@@ -478,51 +508,47 @@ function runDynamicSettings() {
});
}
// Reveal suggestions button
const revealButtons = [
{
containerSelector: 'ytd-page-manager', buttonId: 'rys_homepage_reveal_button',
innerText: 'Show homepage suggestions',
clickListener: e => HTML.setAttribute('remove_homepage', false),
},
{
containerSelector: '#secondary-inner', buttonId: 'rys_sidebar_reveal_button',
innerText: 'Show sidebar suggestions',
clickListener: e => HTML.setAttribute('remove_sidebar', false),
},
{
containerSelector: '#movie_player', buttonId: 'rys_end_of_video_reveal_button',
innerText: 'Show end-of-video suggestions',
clickListener: e => HTML.setAttribute('remove_end_of_video', false),
},
];
revealButtons.forEach(obj => {
const { containerSelector, buttonId, innerText, clickListener } = obj;
// Reveal suggestions boxes
REVEAL_BOX_CONFIGS.forEach(({ containerSelector, boxId, message, showAction, revealSetting }) => {
const existingButton = qs(`#${buttonId}`);
if (existingButton) return;
if (closedRevealBoxes.has(boxId)) return;
if (qs(`#${boxId}`)) return;
const container = qs(containerSelector);
const buttonContainer = document.createElement('div');
buttonContainer.classList.add('rys_reveal_button_container');
if (!container) return;
const newButton = document.createElement('button');
newButton.setAttribute('id', buttonId);
newButton.classList.add('rys_reveal_button');
newButton.innerText = innerText;
newButton.addEventListener('click', clickListener);
const box = document.createElement('div');
box.id = boxId;
box.className = 'rys_reveal_box';
box.innerHTML = `
<div class="rys_reveal_header">
<div class="rys_reveal_branding">
<img src="${rysLogoUrl}" alt="RYS" class="rys_reveal_logo">
<span class="rys_reveal_brand">RYS</span>
</div>
<div class="rys_reveal_actions">
<a class="rys_reveal_dismiss">Don't show again</a>
<button class="rys_reveal_close" aria-label="Close">&times;</button>
</div>
</div>
<div class="rys_reveal_content">
<span class="rys_reveal_message">${message}</span>
<a class="rys_reveal_show">Reveal</a>
</div>
`;
const closeButton = document.createElement('div');
closeButton.setAttribute('id', 'close_reveal_button');
closeButton.innerHTML = "&#10006;";
closeButton.addEventListener('click', e => {
e.stopPropagation();
updateSetting('add_reveal_button', false);
box.querySelector('.rys_reveal_show')?.addEventListener('click', showAction);
box.querySelector('.rys_reveal_dismiss')?.addEventListener('click', () => {
if (revealSetting) {
updateSetting(revealSetting, false);
}
});
box.querySelector('.rys_reveal_close')?.addEventListener('click', () => {
closedRevealBoxes.add(boxId);
box.remove();
});
newButton.appendChild(closeButton);
buttonContainer.appendChild(newButton);
container?.appendChild(buttonContainer);
container.appendChild(box);
});
// Expand the "You" section in the left sidebar
@@ -557,6 +583,21 @@ function requestRunDynamicSettings() {
}
function injectAnnouncementBanners() {
if (!onHomepage) return;
if (!document.body) return;
const logoUrl = browser.runtime.getURL('images/rys.svg');
const banners = getActiveBanners('youtube_homepage');
banners.forEach(banner => {
initBanner(banner, logoUrl, () => ({
element: document.body,
insertMethod: 'prepend'
}));
});
}
function injectScripts() {
const on = cache['global_enable'] === true;
if (!on) return;
@@ -651,6 +692,7 @@ function handleNewPage() {
}
injectScripts();
injectAnnouncementBanners();
requestRunDynamicSettings();
}
+5 -1
View File
@@ -3,7 +3,7 @@
"description": "Spend less time on YouTube. Customize YouTube's user interface to be less engaging.",
"homepage_url": "https://github.com/lawrencehook/remove-youtube-suggestions",
"manifest_version": 2,
"version": "4.3.67",
"version": "4.3.68",
"icons": {
"16": "/images/16.png",
@@ -25,6 +25,7 @@
"/shared/main.js",
"/shared/https.js",
"/shared/utils.js",
"/shared/banners.js",
"/content-script/main.js"
],
"css": ["/content-script/main.css"],
@@ -52,5 +53,8 @@
"permissions": [
"storage",
"*://*.youtube.com/*"
],
"web_accessible_resources": [
"/images/rys.svg"
]
}
+3 -3
View File
@@ -300,7 +300,7 @@ html[foo=bar] {
gap: 15px;
}
#password_lock_container button {
color: black;
color: var(--body-color);
}
/* Password Modal */
@@ -318,7 +318,7 @@ html[foo=bar] {
}
#password_container_background button {
color: black;
color: var(--body-color);
}
#enable_password_container, #enable_password_container * {
@@ -382,7 +382,7 @@ html[foo=bar] {
}
#password-button button {
color: var(--body-background-color);
color: var(--body-color);
}
#disable_password_container a:first-child {
+22 -9
View File
@@ -101,7 +101,7 @@ input:focus {
}
/* Announcement Banner */
#announcement_banner {
.rys_announcement_banner {
display: flex;
align-items: center;
gap: 8px;
@@ -112,35 +112,48 @@ input:focus {
font-size: 13px;
}
#announcement_banner * {
.rys_announcement_banner * {
color: #fff;
}
#announcement_banner span {
.rys_banner_logo {
width: 20px;
height: 20px;
}
.rys_banner_brand {
font-weight: 600;
margin-right: 8px;
padding-right: 12px;
border-right: 1px solid rgba(255, 255, 255, 0.4);
}
.rys_banner_message {
flex: 1;
}
#announcement_banner a {
.rys_banner_link {
text-decoration: underline;
opacity: 0.9;
}
#announcement_banner a:hover {
.rys_banner_link:hover {
opacity: 1;
}
#dismiss_announcement {
.rys_banner_dismiss {
cursor: pointer;
opacity: 0.7;
font-size: 12px;
white-space: nowrap;
text-decoration: underline;
}
#dismiss_announcement:hover {
.rys_banner_dismiss:hover {
opacity: 1;
}
#close_announcement {
.rys_banner_close {
background: none;
border: none;
font-size: 18px;
@@ -150,6 +163,6 @@ input:focus {
line-height: 1;
}
#close_announcement:hover {
.rys_banner_close:hover {
opacity: 1;
}
+2 -6
View File
@@ -20,6 +20,7 @@
<script defer src="/shared/https.js"></script>
<script defer src="/shared/analytics.js"></script>
<script defer src="/shared/utils.js"></script>
<script defer src="/shared/banners.js"></script>
<script defer src="/options/reload.js"></script>
<script defer src="/options/main.js"></script>
<script defer src="/options/settings-menu.js"></script>
@@ -230,12 +231,7 @@
<button id='unlock-password-button'>Confirm</button>
</div>
<div id="announcement_banner" hidden>
<span>Premium features coming soon.</span>
<a href="https://lawrencehook.com/rys/premium" target="_blank">Learn more</a>
<a id="dismiss_announcement">Don't show again</a>
<button id="close_announcement" aria-label="Close">&times;</button>
</div>
<div id="banner_container"></div>
<div id="main_container">
+28 -19
View File
@@ -24,6 +24,11 @@ document.addEventListener("DOMContentLoaded", () => {
recordEvent('Page View: Options');
initAnnouncementBanner();
browser.storage.local.get(localSettings => {
const revealUpdates = migrateRevealSettings(localSettings);
if (Object.keys(revealUpdates).length) {
browser.storage.local.set(revealUpdates);
}
const settings = { ...DEFAULT_SETTINGS, ...localSettings };
const headerSettings = Object.entries(OTHER_SETTINGS).reduce((acc, [id, value]) => {
acc[id] = id in localSettings ? localSettings[id] : value;
@@ -155,6 +160,19 @@ function populateOptions(SECTIONS, headerSettings, SETTING_VALUES) {
const searchBar = document.getElementById('search_bar');
searchBar.addEventListener('input', onSearchInput);
const searchInput = searchBar.querySelector('input');
const focusSearchInput = () => {
if (!searchInput) return;
if (document.activeElement === searchInput) return;
searchInput.focus();
};
focusSearchInput();
setTimeout(focusSearchInput, 0);
setTimeout(focusSearchInput, 50);
window.addEventListener('focus', focusSearchInput);
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') focusSearchInput();
});
const turnBackOn = document.getElementById('turn_back_on');
turnBackOn.addEventListener('click', e => {
@@ -406,27 +424,18 @@ function timeLoop() {
}
// Announcement banner
const ANNOUNCEMENT_KEY = 'announcement_dismissed_premium_coming';
// Announcement banners
function initAnnouncementBanner() {
const banner = document.getElementById('announcement_banner');
const dismissBtn = document.getElementById('dismiss_announcement');
const closeBtn = document.getElementById('close_announcement');
if (!banner) return;
const container = document.getElementById('banner_container');
if (!container) return;
browser.storage.local.get(ANNOUNCEMENT_KEY, result => {
if (!result[ANNOUNCEMENT_KEY]) {
banner.removeAttribute('hidden');
}
});
const logoUrl = browser.runtime.getURL('images/rys.svg');
const banners = getActiveBanners('options');
dismissBtn?.addEventListener('click', () => {
banner.setAttribute('hidden', '');
browser.storage.local.set({ [ANNOUNCEMENT_KEY]: true });
});
closeBtn?.addEventListener('click', () => {
banner.setAttribute('hidden', '');
banners.forEach(banner => {
initBanner(banner, logoUrl, () => ({
element: container,
insertMethod: 'append'
}));
});
}
+77
View File
@@ -0,0 +1,77 @@
// Shared banner configuration and utilities
const BANNERS = [
{
id: 'premium_coming',
storageKey: 'announcement_dismissed_premium_coming',
message: 'Premium features coming soon.',
linkText: 'Learn more',
linkUrl: 'https://lawrencehook.com/rys/premium',
dismissText: "Don't show again",
showOn: ['options', 'youtube_homepage'],
},
];
function createBannerHTML(banner, logoUrl) {
const container = document.createElement('div');
container.id = `rys_banner_${banner.id}`;
container.className = 'rys_announcement_banner';
container.innerHTML = `
<img src="${logoUrl}" alt="RYS" class="rys_banner_logo">
<span class="rys_banner_brand">RYS</span>
<span class="rys_banner_message">${banner.message}</span>
<a href="${banner.linkUrl}" target="_blank" class="rys_banner_link">${banner.linkText}</a>
<a class="rys_banner_dismiss">${banner.dismissText}</a>
<button class="rys_banner_close" aria-label="Close">&times;</button>
`;
return container;
}
function initBanner(banner, logoUrl, getContainer) {
const existingBanner = document.getElementById(`rys_banner_${banner.id}`);
if (existingBanner) return;
browser.storage.local.get(banner.storageKey, result => {
if (result[banner.storageKey]) return;
const container = getContainer();
if (!container) return;
const bannerEl = createBannerHTML(banner, logoUrl);
// Insert banner
if (container.insertMethod === 'prepend') {
container.element.insertBefore(bannerEl, container.element.firstChild);
} else {
container.element.appendChild(bannerEl);
}
// Mark that a banner is visible (for CSS adjustments)
document.documentElement.setAttribute('rys-banner-visible', 'true');
// Event listeners
const dismissBtn = bannerEl.querySelector('.rys_banner_dismiss');
const closeBtn = bannerEl.querySelector('.rys_banner_close');
const removeBanner = () => {
bannerEl.remove();
// Check if any banners still visible
if (!document.querySelector('.rys_announcement_banner')) {
document.documentElement.removeAttribute('rys-banner-visible');
}
};
dismissBtn?.addEventListener('click', () => {
removeBanner();
browser.storage.local.set({ [banner.storageKey]: true });
});
closeBtn?.addEventListener('click', () => {
removeBanner();
});
});
}
function getActiveBanners(location) {
return BANNERS.filter(b => b.showOn.includes(location));
}
+40 -6
View File
@@ -67,18 +67,17 @@ const SECTIONS = [
id: "remove_end_of_video",
defaultValue: true
},
{
name: "Add a button to reveal suggestions",
tags: "Homepage, Video Player",
id: "add_reveal_button",
defaultValue: true
},
]
},
{
name: "Homepage",
tags: "Homepage",
options: [
{
name: "Show reveal box for homepage suggestions",
id: "add_reveal_homepage",
defaultValue: true
},
{
name: "Hide the header",
id: "remove_header",
@@ -269,6 +268,11 @@ const SECTIONS = [
name: "Video Player - UI",
tags: "Video Player",
options: [
{
name: "Show reveal box for end-of-video suggestions",
id: "add_reveal_end_of_video",
defaultValue: true
},
{
name: "Hide info cards",
id: "remove_info_cards",
@@ -320,6 +324,11 @@ const SECTIONS = [
name: "Video Player - Sidebar",
tags: "Video Player",
options: [
{
name: "Show reveal box for sidebar suggestions",
id: "add_reveal_sidebar",
defaultValue: true
},
{
name: "Center contents - removes the sidebar",
id: "remove_entire_sidebar",
@@ -613,6 +622,26 @@ const DEFAULT_SETTINGS = SECTIONS.reduce((acc, fieldset) => {
return acc;
}, { ...OTHER_SETTINGS });
// Migrate legacy add_reveal_button to per-surface settings
function migrateRevealSettings(settings) {
if (!settings || !('add_reveal_button' in settings)) return {};
const val = settings.add_reveal_button;
const updates = {};
if (!('add_reveal_homepage' in settings)) {
settings.add_reveal_homepage = val;
updates.add_reveal_homepage = val;
}
if (!('add_reveal_sidebar' in settings)) {
settings.add_reveal_sidebar = val;
updates.add_reveal_sidebar = val;
}
if (!('add_reveal_end_of_video' in settings)) {
settings.add_reveal_end_of_video = val;
updates.add_reveal_end_of_video = val;
}
return updates;
}
// For import/export
const idToShortId = {
@@ -703,6 +732,11 @@ const idToShortId = {
"shrink_video_thumbnails": '84',
"password": '85',
"hashed_password": '86',
"add_reveal_homepage": '87',
"add_reveal_sidebar": '88',
"add_reveal_end_of_video": '89',
"add_reveal_button": '90', // deprecated; migrated to add_reveal_* settings
"remove_sidebar_infinite_scroll": '91',
};