Focused YouTube

Remove ads, shorts, and algorithmic suggestions on YouTube (EN/NL/DE/FR)

目前為 2025-06-29 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Focused YouTube
// @version      2025-06-29.5
// @author       Richard B
// @namespace    https://www.365devnet.eu/focusedyoutube
// @description  Remove ads, shorts, and algorithmic suggestions on YouTube (EN/NL/DE/FR)
// @match        *://*.youtube.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @run-at       document-start
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

// Credits: 
// Originally based on Focused YouTube by Kervyn
// https://github.com/KervynH/Focused-YouTube
// 
// Additional credits: https://github.com/lawrencehook/remove-youtube-suggestions
//
// MIT License
// 
// Copyright (c) 2025 Richard B
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

'use strict';

// Config custom settings here - now with user preferences support
const DEFAULT_SETTINGS = {
  /// homepage redirect ///
  redirectHomepage: false, // Options: 'wl', 'subs', 'lib', false
  hideHomepageButton: false,

  /// homepage suggestions ///
  hideAllSuggestions: false,
  hideAllButOneRow: true,
  hideInfiniteScroll: false,

  /// video player ///
  skipAds: true,
  hideLiveChat: true,
  hideRelatedVideos: true,
  hideMiniPlayerButton: true,
  hidePlayNextButton: true,
  forceCinemaMode: true,

  /// shorts ///
  hideShorts: true,
  redirectShortsPlayer: true,

  /// misc ///
  hideSearchButton: false,
  cleanSearchResults: true,
  hideSponsoredContent: true,
};

// Load user settings with fallback to defaults
const SETTINGS = {};
Object.keys(DEFAULT_SETTINGS).forEach(key => {
  SETTINGS[key] = GM_getValue(key, DEFAULT_SETTINGS[key]);
});

// Performance optimizations
let styleElement = null;
let lastUrl = '';
let observer = null;
const processingQueue = new Set();

// Mark settings in HTML
const HTML = document.documentElement;
Object.keys(SETTINGS).forEach(key => {
  HTML.setAttribute(key, SETTINGS[key]);
});

// Improved CSS selectors with better specificity and modern features
const DESKTOP_BLOCK_LIST = [
  // Ads - More comprehensive coverage
  '#masthead-ad',
  'ytd-mealbar-promo-renderer',
  'ytd-carousel-ad-renderer',
  'ytd-display-ad-renderer',
  'ytd-ad-slot-renderer',
  'ytd-promoted-sparkles-text-search-renderer',
  'div.ytp-ad-overlay-image',
  '.iv-branding.annotation-type-custom.annotation',
  '[class*="ad-showing"]',
  '.ytp-ad-module',

  // Sponsored Content - Enhanced detection
  'html[hideSponsoredContent="true"] ytd-rich-item-renderer:has(ytd-ad-slot-renderer)',
  'html[hideSponsoredContent="true"] ytd-ad-slot-renderer',
  'html[hideSponsoredContent="true"] ytd-in-feed-ad-layout-renderer',
  'html[hideSponsoredContent="true"] ytd-video-display-full-buttoned-and-button-group-renderer',
  'html[hideSponsoredContent="true"] ytd-ad-inline-playback-meta-block',
  'html[hideSponsoredContent="true"] top-landscape-image-layout-view-model',
  'html[hideSponsoredContent="true"] feed-ad-metadata-view-model',
  'html[hideSponsoredContent="true"] ad-badge-view-model',
  'html[hideSponsoredContent="true"] [class*="ytwAdBadgeViewModelHost"]',
  'html[hideSponsoredContent="true"] [class*="ytwFeedAdMetadataViewModelHost"]',
  'html[hideSponsoredContent="true"] [class*="badge-style-type-ad"]',

  // Shorts - Enhanced selectors based on HTML structure
  'html[hideShorts="true"] ytd-rich-section-renderer:has(ytd-rich-shelf-renderer[is-shorts])',
  'html[hideShorts="true"] ytd-rich-shelf-renderer[is-shorts]',
  'html[hideShorts="true"] ytd-rich-shelf-renderer:has(#title:contains("Shorts"))',
  'html[hideShorts="true"] ytd-reel-shelf-renderer',
  'html[hideShorts="true"] ytd-shelf-renderer:has([href*="/shorts/"])',
  'html[hideShorts="true"] ytm-shorts-lockup-view-model-v2',
  'html[hideShorts="true"] ytm-shorts-lockup-view-model',
  'html[hideShorts="true"] [aria-label*="Shorts"]',
  'html[hideShorts="true"] [class*="shortsLockupViewModelHost"]',
  'html[hideShorts="true"] .reel-item-endpoint',

  // Left Bar Navigation - Enhanced Shorts menu removal
  'a[href="/feed/trending"]',
  'a[href="/feed/explore"]',
  'html[hideShorts="true"] ytd-guide-entry-renderer:has([title="Shorts"])',
  'html[hideShorts="true"] ytd-guide-entry-renderer:has(yt-formatted-string:contains("Shorts"))',
  'html[hideShorts="true"] ytd-guide-section-renderer a[title="Shorts"]',
  'html[hideShorts="true"] ytd-mini-guide-entry-renderer[aria-label="Shorts"]',
  'html[hideShorts="true"] ytd-guide-section-renderer a[href*="/shorts"]',
  'ytd-guide-section-renderer.ytd-guide-renderer.style-scope:nth-of-type(4)',
  'ytd-guide-section-renderer.ytd-guide-renderer.style-scope:nth-of-type(3)',

  // Homepage - Better targeting
  'html[hideHomepageButton="true"] a:not(#logo)[href="/"]',
  'html[hideAllSuggestions="true"] ytd-browse[page-subtype="home"] ytd-rich-grid-renderer',
  'html[hideAllButOneRow="true"] ytd-browse[page-subtype="home"] #header',
  'html[hideAllButOneRow="true"] ytd-browse[page-subtype="home"] ytd-rich-grid-renderer > #contents > ytd-rich-grid-row:nth-child(n+2)',
  'html[hideInfiniteScroll="true"] ytd-browse[page-subtype="home"] ytd-rich-grid-renderer > #contents > ytd-continuation-item-renderer',

  // Video Player - Enhanced
  'html[hideRelatedVideos="true"] #secondary',
  'html[hideRelatedVideos="true"] #related',
  'html[hideRelatedVideos="true"] .html5-endscreen',
  'html[hideRelatedVideos="true"] .ytp-endscreen-content',
  'html[hidePlayNextButton="true"] .ytp-next-button',
  'html[hidePlayNextButton="true"] .ytp-prev-button',
  'html[hideLiveChat="true"] #chat',
  'html[hideLiveChat="true"] ytd-live-chat-frame',
  'html[hideMiniPlayerButton="true"] .ytp-miniplayer-button',
  '.ytd-download-button-renderer',

  // Search - Improved
  'div.sbdd_a',
  '#container.ytd-search ytd-search-pyv-renderer',
  'html[hideSearchButton="true"] ytd-searchbox',
  'html[hideSearchButton="true"] #voice-search-button',
];

const MOBILE_BLOCK_LIST = [
  // Ads 
  'ytm-companion-ad-renderer',
  'ytm-promoted-sparkles-web-renderer',
  '[class*="ad-showing"]',

  // Sponsored Content (Mobile) - Enhanced
  'html[hideSponsoredContent="true"] ytm-rich-item-renderer:has([class*="ad"])',
  'html[hideSponsoredContent="true"] ytm-ad-slot-renderer',
  'html[hideSponsoredContent="true"] [class*="ytwAdBadgeViewModelHost"]',
  'html[hideSponsoredContent="true"] [class*="sponsored"]',
  'html[hideSponsoredContent="true"] [class*="badge-style-type-ad"]',

  // Shorts - Enhanced mobile targeting
  'html[hideShorts="true"] ytm-reel-shelf-renderer',
  'html[hideShorts="true"] ytm-shorts-lockup-view-model-v2',
  'html[hideShorts="true"] ytm-shorts-lockup-view-model',
  'html[hideShorts="true"] [aria-label*="Shorts"]',
  'html[hideShorts="true"] [class*="shortsLockupViewModelHost"]',
  'html[hideShorts="true"] .reel-item-endpoint',

  // Homepage 
  'html[hideHomepageButton="true"] div[tab-identifier="FEwhat_to_watch"]',
  'html[hideSearchButton="true"] #header-bar > header > div > button',
  'html[hideSearchButton="true"] #center.style-scope.ytd-masthead',

  // Video Player 
  'html[hideRelatedVideos="true"] ytm-item-section-renderer[section-identifier="related-items"]',
  'html[hidePlayNextButton="true"] .player-controls-middle-core-buttons > div:nth-child(1)',
  'html[hidePlayNextButton="true"] .player-controls-middle-core-buttons > div:nth-child(5)',
  'html[hideLiveChat="true"] ytm-live-chat-frame',

  // Navigation Bar - Enhanced Shorts menu removal
  'html[hideHomepageButton="true"] ytm-pivot-bar-item-renderer:nth-child(1)',
  'html[hideShorts="true"] ytm-pivot-bar-item-renderer:nth-child(2)',
  'html[hideShorts="true"] ytm-guide-entry-renderer:has([title="Shorts"])',
  'html[hideShorts="true"] ytm-guide-entry-renderer:has([aria-label*="Shorts"])',
  'ytm-chip-cloud-chip-renderer[chip-style="STYLE_EXPLORE_LAUNCHER_CHIP"]',
];

// Improved style injection with error handling
function addStyle(css) {
  try {
    if (!styleElement) {
      styleElement = document.createElement('style');
      styleElement.id = 'focused-youtube-styles';
      document.head.appendChild(styleElement);
    }
    styleElement.textContent = css;
  } catch (error) {
    console.warn('Focused YouTube: Failed to inject styles:', error);
  }
}

// Apply styles based on platform
function applyStyles() {
  const isDesktop = location.hostname.startsWith('www.');
  const isMobile = location.hostname.startsWith('m.');
  
  if (isDesktop) {
    const styles = DESKTOP_BLOCK_LIST.map(e => `${e} { display: none !important; }`).join('\n');
    addStyle(styles);
  } else if (isMobile) {
    const styles = MOBILE_BLOCK_LIST.map(e => `${e} { display: none !important; }`).join('\n');
    addStyle(styles);
  }
}

// Improved URL change detection
function detectUrlChange() {
  const currentUrl = location.href;
  if (currentUrl !== lastUrl) {
    lastUrl = currentUrl;
    handleUrlChange();
  }
}

function handleUrlChange() {
  // Re-apply settings when navigating
  setTimeout(() => {
    runDynamicSettings();
  }, 100);
}

// Enhanced MutationObserver for better performance
function setupObserver() {
  if (observer) observer.disconnect();
  
  observer = new MutationObserver((mutations) => {
    let shouldProcess = false;
    
    for (const mutation of mutations) {
      if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
        for (const node of mutation.addedNodes) {
          if (node.nodeType === Node.ELEMENT_NODE) {
            const tagName = node.tagName?.toLowerCase();
            if (tagName?.includes('ytd-') || tagName?.includes('ytm-')) {
              shouldProcess = true;
              break;
            }
          }
        }
      }
      if (shouldProcess) break;
    }
    
    if (shouldProcess) {
      // Debounce processing
      clearTimeout(window.focusedYTTimeout);
      window.focusedYTTimeout = setTimeout(runDynamicSettings, 100);
    }
  });
  
  observer.observe(document.body, {
    childList: true,
    subtree: true,
    attributes: false,
    characterData: false
  });
}

// Start initialization
function initialize() {
  applyStyles();
  setupObserver();
  
  // URL change detection
  setInterval(detectUrlChange, 250);
  
  // Initial run
  setTimeout(runDynamicSettings, 500);
}

// Wait for DOM to be ready
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', initialize);
} else {
  initialize();
}

/***** Core Functions *****/

function runDynamicSettings() {
  try {
    if (SETTINGS.redirectHomepage && SETTINGS.redirectHomepage !== 'false') redirectHomepage();
    if (SETTINGS.redirectShortsPlayer) redirectShortsPlayer();
    if (SETTINGS.hideShorts) hideShortsVideos();
    if (SETTINGS.cleanSearchResults) cleanSearchResults();
    if (SETTINGS.skipAds) skipVideoAds();
    if (SETTINGS.hideRelatedVideos) disableRelatedAutoPlay();
    if (SETTINGS.forceCinemaMode) enableCinemaMode();
    if (SETTINGS.hideSponsoredContent) hideSponsoredContent();
  } catch (error) {
    console.warn('Focused YouTube: Error in runDynamicSettings:', error);
  }
}

function redirectHomepage() {
  if (location.pathname === '/' && !location.search) {
    const redirectMap = {
      'wl': '/playlist?list=WL',
      'subs': '/feed/subscriptions',
      'lib': '/feed/library'
    };
    
    const redirect = redirectMap[SETTINGS.redirectHomepage];
    if (redirect) {
      location.replace(redirect);
    }
  }
}

function redirectShortsPlayer() {
  if (location.pathname.startsWith('/shorts/')) {
    const videoId = location.pathname.replace('/shorts/', '');
    const newUrl = `/watch?v=${videoId}${location.search ? '&' + location.search.slice(1) : ''}`;
    location.replace(newUrl);
  }
}

function disableRelatedAutoPlay() {
  // Desktop autoplay
  const autoplayButtons = document.querySelectorAll('.ytp-autonav-toggle-button[aria-checked="true"]');
  autoplayButtons.forEach(button => {
    if (button.offsetParent && !processingQueue.has(button)) {
      processingQueue.add(button);
      button.click();
      setTimeout(() => processingQueue.delete(button), 1000);
    }
  });
  
  // Mobile autoplay
  const mobileAutoplayButtons = document.querySelectorAll('.ytm-autonav-toggle-button-container[aria-pressed="true"]');
  mobileAutoplayButtons.forEach(button => {
    if (button.offsetParent && !processingQueue.has(button)) {
      processingQueue.add(button);
      button.click();
      setTimeout(() => processingQueue.delete(button), 1000);
    }
  });
}

function hideShortsVideos() {
  // Remove sidebar Shorts menu item first
  const shortsMenuItems = document.querySelectorAll(
    'ytd-guide-entry-renderer:has([title="Shorts"]), ' +
    'ytd-guide-entry-renderer:has(yt-formatted-string), ' +
    'ytm-guide-entry-renderer:has([title="Shorts"]), ' +
    'ytm-guide-entry-renderer:has([aria-label*="Shorts"])'
  );
  shortsMenuItems.forEach(item => {
    const titleElement = item.querySelector('yt-formatted-string, [title], [aria-label]');
    const text = titleElement?.innerText || titleElement?.textContent || 
                 titleElement?.getAttribute('title') || titleElement?.getAttribute('aria-label');
    
    if (text && text.toLowerCase().includes('shorts')) {
      if (!processingQueue.has(item)) {
        processingQueue.add(item);
        item.remove();
      }
    }
  });

  // Remove shorts containers - Enhanced detection
  const shortsContainers = document.querySelectorAll(
    'ytd-rich-section-renderer:has(ytd-rich-shelf-renderer[is-shorts]), ' +
    'ytd-rich-section-renderer:has([id="title"]:is([innerText*="Shorts"], [textContent*="Shorts"]))'
  );
  shortsContainers.forEach(container => {
    if (!processingQueue.has(container)) {
      processingQueue.add(container);
      container.remove();
    }
  });

  // Remove shorts shelf renderers
  const shortsShelves = document.querySelectorAll('ytd-rich-shelf-renderer[is-shorts]');
  shortsShelves.forEach(shelf => {
    if (!processingQueue.has(shelf)) {
      processingQueue.add(shelf);
      shelf.remove();
    }
  });

  // Remove by title detection
  const shortsHeaders = document.querySelectorAll('#title');
  shortsHeaders.forEach(title => {
    const text = title.innerText || title.textContent;
    if (text && text.toLowerCase().includes('shorts')) {
      const container = title.closest('ytd-rich-section-renderer, ytd-rich-shelf-renderer');
      if (container && !processingQueue.has(container)) {
        processingQueue.add(container);
        container.remove();
      }
    }
  });

  // Remove shorts lockup components
  const shortsLockups = document.querySelectorAll(
    'ytm-shorts-lockup-view-model-v2, ytm-shorts-lockup-view-model, ' +
    '[class*="shortsLockupViewModelHost"], .reel-item-endpoint'
  );
  shortsLockups.forEach(lockup => {
    const parent = lockup.closest('ytd-rich-item-renderer, ytd-rich-section-renderer');
    if (parent && !processingQueue.has(parent)) {
      processingQueue.add(parent);
      parent.remove();
    }
  });

  // Fallback: Remove by shorts links
  const shortsLinks = document.querySelectorAll('a[href*="/shorts/"]');
  shortsLinks.forEach(link => {
    const containers = [
      link.closest('ytd-rich-item-renderer'),
      link.closest('ytd-rich-section-renderer'),
      link.closest('ytm-item-section-renderer'),
      link.closest('ytd-video-renderer'),
      link.closest('ytm-video-with-context-renderer')
    ].filter(Boolean);
    
    containers.forEach(container => {
      if (!processingQueue.has(container)) {
        processingQueue.add(container);
        container.remove();
      }
    });
  });

  // Remove shorts tabs on channel pages
  if (location.pathname.startsWith('/@') || location.pathname.startsWith('/c/') || location.pathname.startsWith('/channel/')) {
    const shortsTabs = document.querySelectorAll('[role="tab"], div.tab-content');
    shortsTabs.forEach(tab => {
      const text = tab.innerText?.toUpperCase();
      const shortsTerms = ['SHORTS', 'COURTS', 'KURZ', 'KORT']; // EN, FR, DE, NL
      
      if (shortsTerms.some(term => text?.includes(term)) && !processingQueue.has(tab)) {
        processingQueue.add(tab);
        (tab.parentElement || tab).remove();
      }
    });
  }
}

function skipVideoAds() {
  if (!location.pathname.startsWith('/watch')) return;
  
  // Skip ad buttons
  const skipButtons = document.querySelectorAll('.ytp-ad-skip-button-slot button, .ytp-ad-overlay-close-button, .ytp-ad-skip-button');
  skipButtons.forEach(button => {
    if (button.offsetParent && !processingQueue.has(button)) {
      processingQueue.add(button);
      button.click();
      setTimeout(() => processingQueue.delete(button), 500);
    }
  });

  // Fast-forward through ads
  const adVideo = document.querySelector('.ad-showing');
  if (adVideo) {
    const video = document.querySelector('.html5-main-video');
    if (video && video.duration && !isNaN(video.duration) && video.duration > 0) {
      video.currentTime = video.duration - 0.1;
    }
  }
}

function cleanSearchResults() {
  if (!location.pathname.startsWith('/results')) return;
  
  const relatedTerms = [
    // English
    'Related', 'People also watched', 'For you', 'Recommended', 'You might also like',
    'Similar videos', 'More like this', 'Suggested', 'Because you watched',
    
    // Dutch
    'Gerelateerd', 'Anderen bekeken ook', 'Voor jou', 'Aanbevolen', 'Misschien vind je dit ook leuk',
    'Vergelijkbare video\'s', 'Meer zoals dit', 'Voorgesteld', 'Omdat je keek naar',
    
    // German  
    'Ähnlich', 'Andere sahen auch', 'Für dich', 'Empfohlen', 'Das könnte dir auch gefallen',
    'Ähnliche Videos', 'Mehr davon', 'Vorgeschlagen', 'Weil du dir angesehen hast',
    
    // French
    'Connexe', 'D\'autres ont aussi regardé', 'Pour vous', 'Recommandé', 'Vous aimerez peut-être aussi',
    'Vidéos similaires', 'Plus comme ça', 'Suggéré', 'Parce que vous avez regardé'
  ];
  
  const badges = document.querySelectorAll('ytm-badge, .badge-style-type-simple');
  
  badges.forEach(badge => {
    const text = badge.innerText || badge.textContent;
    if (relatedTerms.some(term => text?.includes(term))) {
      const container = badge.closest('ytm-video-with-context-renderer, ytd-video-renderer');
      if (container && !processingQueue.has(container)) {
        processingQueue.add(container);
        container.remove();
      }
    }
  });
}

function enableCinemaMode() {
  if (!location.pathname.startsWith('/watch')) return;
  
  // Check if we're in fullscreen mode
  const isFullscreen = document.fullscreenElement || 
                      document.webkitFullscreenElement || 
                      document.mozFullScreenElement || 
                      document.msFullscreenElement;
  
  if (isFullscreen) return; // Don't force cinema mode if already in fullscreen
  
  // Find the cinema mode button
  const cinemaButton = document.querySelector('.ytp-size-button');
  
  if (cinemaButton && !processingQueue.has(cinemaButton)) {
    // Check if cinema mode is already active by looking for the expanded state
    const player = document.querySelector('#movie_player');
    const isAlreadyCinema = player?.classList.contains('ytp-big-mode') || 
                           document.querySelector('ytd-watch-flexy[theater]');
    
    if (!isAlreadyCinema) {
      processingQueue.add(cinemaButton);
      cinemaButton.click();
      setTimeout(() => processingQueue.delete(cinemaButton), 1000);
    }
  }
}

function hideSponsoredContent() {
  // Remove sponsored/ad containers - Enhanced detection based on new HTML structure
  const sponsoredContainers = document.querySelectorAll(
    'ytd-rich-item-renderer:has(ytd-ad-slot-renderer), ' +
    'ytd-rich-item-renderer:has(ytd-in-feed-ad-layout-renderer), ' +
    'ytd-rich-item-renderer:has(ytd-video-display-full-buttoned-and-button-group-renderer)'
  );
  sponsoredContainers.forEach(container => {
    if (!processingQueue.has(container)) {
      processingQueue.add(container);
      container.remove();
    }
  });

  // Remove ad slot renderers directly
  const adSlots = document.querySelectorAll('ytd-ad-slot-renderer');
  adSlots.forEach(slot => {
    const container = slot.closest('ytd-rich-item-renderer');
    if (container && !processingQueue.has(container)) {
      processingQueue.add(container);
      container.remove();
    }
  });

  // Remove in-feed ad layout renderers
  const adLayouts = document.querySelectorAll(
    'ytd-in-feed-ad-layout-renderer, ' +
    'ytd-video-display-full-buttoned-and-button-group-renderer, ' +
    'ytd-ad-inline-playback-meta-block, ' +
    'top-landscape-image-layout-view-model'
  );
  adLayouts.forEach(layout => {
    const container = layout.closest('ytd-rich-item-renderer');
    if (container && !processingQueue.has(container)) {
      processingQueue.add(container);
      container.remove();
    }
  });

  // Remove elements with sponsored badges - Enhanced detection
  const sponsoredBadges = document.querySelectorAll(
    'ad-badge-view-model, ' +
    '[class*="ytwAdBadgeViewModelHost"], ' +
    '[class*="badge-style-type-ad"], ' +
    '.badge-style-type-ad'
  );
  sponsoredBadges.forEach(badge => {
    const container = badge.closest('ytd-rich-item-renderer, ytm-rich-item-renderer');
    if (container && !processingQueue.has(container)) {
      processingQueue.add(container);
      container.remove();
    }
  });

  // Remove by sponsored text content - Enhanced with more variations
  const sponsoredTerms = [
    // English
    'Sponsored', 'Ad', 'Promoted', 'Advertisement',
    
    // Dutch
    'Gesponsord', 'Advertentie', 'Gepromoot', 'Reclame',
    
    // German
    'Gesponsert', 'Anzeige', 'Werbung', 'Gesponsort',
    
    // French
    'Sponsorisé', 'Publicité', 'Annonce', 'Promo'
  ];

  // Check badge elements
  const badges = document.querySelectorAll(
    'badge-shape, .badge-shape-wiz, [class*="badge"], ' +
    'ytd-badge-supported-renderer, .badge-style-type-ad, ' +
    '[aria-label*="Sponsored"], [title*="Sponsored"]'
  );
  badges.forEach(badge => {
    const text = badge.innerText || badge.textContent || badge.getAttribute('aria-label') || badge.getAttribute('title');
    if (text && sponsoredTerms.some(term => text.toLowerCase().includes(term.toLowerCase()))) {
      const container = badge.closest('ytd-rich-item-renderer, ytm-rich-item-renderer');
      if (container && !processingQueue.has(container)) {
        processingQueue.add(container);
        container.remove();
      }
    }
  });

  // Check for googleadservices links (ad links)
  const adLinks = document.querySelectorAll('a[href*="googleadservices.com"]');
  adLinks.forEach(link => {
    const container = link.closest('ytd-rich-item-renderer, ytm-rich-item-renderer');
    if (container && !processingQueue.has(container)) {
      processingQueue.add(container);
      container.remove();
    }
  });
}

// Settings management (for future UI)
function updateSetting(key, value) {
  SETTINGS[key] = value;
  GM_setValue(key, value);
  HTML.setAttribute(key, value);
  applyStyles();
  runDynamicSettings();
}

// Export for potential external use
window.FocusedYouTube = {
  settings: SETTINGS,
  updateSetting,
  runDynamicSettings
};