YouTube Tweaker Pro (Full Suite)

Remove YouTube ads, UI clutter, autoplay, and more. Now with auto ad skip, mute, theme toggle, import/export, reset, and full CSP-safe tweaks. Built for Eliminater74 🛠️⚙️🎬

// ==UserScript==
// @name         YouTube Tweaker Pro (Full Suite)
// @namespace    https://gf.qytechs.cn/users/eliminater74
// @version      3.1
// @description  Remove YouTube ads, UI clutter, autoplay, and more. Now with auto ad skip, mute, theme toggle, import/export, reset, and full CSP-safe tweaks. Built for Eliminater74 🛠️⚙️🎬
// @author       Eliminater74
// @match        *://www.youtube.com/*
// @grant        GM_addStyle
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  const SETTINGS_KEY = 'ytTweakerSettingsV3';
  const defaultSettings = {
    hideRightSidebar: false,
    hideLeftNav: false,
    muteAutoplay: false,
    hideShorts: false,
    forceTheater: false,
    widenLayout: false,
    hideComments: false,
    expandDescription: false,
    hideEndscreen: false,
    autoHD: false,
    hideHomepageAds: false,
    hideTopBannerPromo: false,
    hideKeywordChips: false,
    autoSkipAds: true,
    muteDuringAds: true,
    darkMode: true
  };

  let settings = { ...defaultSettings, ...JSON.parse(localStorage.getItem(SETTINGS_KEY) || '{}') };
  const saveSettings = () => localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
  const q = s => document.querySelector(s);
  const qAll = s => document.querySelectorAll(s);

  function resetSettings() {
    settings = { ...defaultSettings };
    saveSettings();
    location.reload();
  }

  function applySettings() {
    if (q('#related')) q('#related').style.display = settings.hideRightSidebar ? 'none' : '';
    ['#guide', 'ytd-mini-guide-renderer', 'ytd-guide-section-renderer'].forEach(sel =>
      qAll(sel).forEach(e => (e.style.display = settings.hideLeftNav ? 'none' : ''))
    );
    ['ytd-rich-section-renderer', 'ytd-reel-shelf-renderer'].forEach(sel =>
      qAll(sel).forEach(e => (e.style.display = settings.hideShorts ? 'none' : ''))
    );
    qAll('ytd-comments').forEach(e => (e.style.display = settings.hideComments ? 'none' : ''));
    qAll('ytd-promoted-video-renderer, ytd-display-ad-renderer, ytd-rich-item-renderer[is-promoted], ytd-ad-slot-renderer')
      .forEach(e => (e.style.display = settings.hideHomepageAds ? 'none' : ''));
    qAll('ytd-banner-promo-renderer, ytd-rich-banner-renderer')
      .forEach(e => (e.style.display = settings.hideTopBannerPromo ? 'none' : ''));
    qAll('ytd-feed-filter-chip-bar-renderer, .chip-bar')
      .forEach(e => (e.style.display = settings.hideKeywordChips ? 'none' : ''));

    const vid = q('video');
    if (vid && settings.muteAutoplay) vid.muted = true;

    if (settings.forceTheater) {
      const flexy = q('ytd-watch-flexy');
      const btn = q('.ytp-size-button');
      if (btn && flexy && !flexy.hasAttribute('theater')) btn.click();
    }

    if (settings.widenLayout && location.pathname.startsWith('/watch')) {
      const player = document.getElementById('player-container');
      if (player) player.style.maxWidth = '100%';
    }

    if (settings.expandDescription && location.pathname.startsWith('/watch')) {
      const exp = q('#expand');
      if (exp && exp.getAttribute('aria-expanded') !== 'true') exp.click();
    }

    const styleId = 'yt-endscreen-style';
    let style = document.getElementById(styleId);
    if (settings.hideEndscreen && !style) {
      style = document.createElement('style');
      style.id = styleId;
      style.textContent = `.ytp-ce-element, .ytp-ce-video { display: none !important; }`;
      document.head.appendChild(style);
    } else if (!settings.hideEndscreen && style) {
      style.remove();
    }

    if (settings.autoHD) {
      setTimeout(() => {
        const btn = q('.ytp-settings-button');
        if (btn) btn.click();
      }, 3000);
    }
  }

  function autoAdWatcher() {
    setInterval(() => {
      const skip = q('.ytp-ad-skip-button');
      if (settings.autoSkipAds && skip) skip.click();

      const adShowing = document.querySelector('.ad-showing');
      const vid = q('video');

      if (settings.muteDuringAds && adShowing && vid) vid.muted = true;
      else if (vid && settings.muteAutoplay === false) vid.muted = false;

      const adIndicator = q('.ytp-ad-preview-container,.ytp-ad-player-overlay');
      if (settings.autoSkipAds && adIndicator && vid && vid.duration < 60) {
        try {
          vid.currentTime = vid.duration;
        } catch (e) {}
      }
    }, 500);
  }

  GM_addStyle(`
    #yt-tweaker-gear {
      position: fixed;
      bottom: 20px;
      right: 20px;
      background: #000;
      color: #0ff;
      font-size: 20px;
      padding: 8px 12px;
      border-radius: 8px;
      cursor: grab;
      z-index: 2147483647;
      box-shadow: 0 0 8px #0ff;
      user-select: none;
    }
    #yt-tweaker-panel {
      position: fixed;
      bottom: 60px;
      right: 20px;
      padding: 12px;
      border-radius: 10px;
      font-family: monospace;
      font-size: 13px;
      z-index: 2147483647;
      display: none;
      box-shadow: 0 0 12px rgba(0,0,0,0.5);
    }
    .yt-dark-theme {
      background: #111;
      color: #0f0;
    }
    .yt-light-theme {
      background: #eee;
      color: #111;
    }
    #yt-tweaker-panel label {
      display: block;
      margin: 5px 0;
    }
    #yt-tweaker-panel button {
      margin: 4px 2px;
      font-size: 12px;
    }
    #yt-tweaker-panel input[type="checkbox"] {
      margin-right: 5px;
    }
  `);

  function createCheckbox(labelText, key) {
    const label = document.createElement('label');
    const checkbox = document.createElement('input');
    checkbox.type = 'checkbox';
    checkbox.checked = settings[key];
    checkbox.addEventListener('change', () => {
      settings[key] = checkbox.checked;
      saveSettings();
      applySettings();
    });
    label.appendChild(checkbox);
    label.appendChild(document.createTextNode(labelText));
    return label;
  }

  function createUI() {
    if (document.getElementById('yt-tweaker-gear')) return;

    const gear = document.createElement('div');
    gear.id = 'yt-tweaker-gear';
    gear.textContent = '⚙️';
    document.body.appendChild(gear);

    const panel = document.createElement('div');
    panel.id = 'yt-tweaker-panel';
    panel.className = settings.darkMode ? 'yt-dark-theme' : 'yt-light-theme';

    const title = document.createElement('strong');
    title.textContent = 'YouTube Tweaker';
    panel.appendChild(title);
    panel.appendChild(document.createElement('br'));
    panel.appendChild(document.createElement('br'));

    const toggles = [
      ['Hide Right Sidebar (Suggestions)', 'hideRightSidebar'],
      ['Hide Left Nav Menu', 'hideLeftNav'],
      ['Mute Autoplay', 'muteAutoplay'],
      ['Hide Shorts', 'hideShorts'],
      ['Force Theater Mode', 'forceTheater'],
      ['Widen Layout', 'widenLayout'],
      ['Hide Comments', 'hideComments'],
      ['Expand Description', 'expandDescription'],
      ['Hide Endscreen', 'hideEndscreen'],
      ['Auto HD Quality', 'autoHD'],
      ['Hide Homepage Ads', 'hideHomepageAds'],
      ['Hide Top Banner Promo', 'hideTopBannerPromo'],
      ['Hide Keyword Chips', 'hideKeywordChips'],
      ['Auto-Skip Ads', 'autoSkipAds'],
      ['Mute During Ads', 'muteDuringAds']
    ];

    toggles.forEach(([label, key]) => {
      panel.appendChild(createCheckbox(label, key));
    });

    panel.appendChild(document.createElement('hr'));

    const themeToggle = createCheckbox('Dark Theme UI', 'darkMode');
    themeToggle.querySelector('input').addEventListener('change', () => {
      panel.className = settings.darkMode ? 'yt-dark-theme' : 'yt-light-theme';
    });
    panel.appendChild(themeToggle);

    const tools = document.createElement('div');
    const btnReset = document.createElement('button');
    btnReset.textContent = 'Reset Settings';
    btnReset.onclick = () => confirm('Reset all settings?') && resetSettings();

    const btnExport = document.createElement('button');
    btnExport.textContent = 'Export';
    btnExport.onclick = () => {
      navigator.clipboard.writeText(JSON.stringify(settings, null, 2));
      alert('Settings copied to clipboard.');
    };

    const btnImport = document.createElement('button');
    btnImport.textContent = 'Import';
    btnImport.onclick = () => {
      const input = prompt('Paste settings JSON:');
      try {
        const obj = JSON.parse(input);
        settings = { ...defaultSettings, ...obj };
        saveSettings();
        location.reload();
      } catch {
        alert('Invalid JSON.');
      }
    };

    tools.appendChild(btnReset);
    tools.appendChild(btnExport);
    tools.appendChild(btnImport);
    panel.appendChild(tools);

    document.body.appendChild(panel);

    gear.addEventListener('click', () => {
      panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
    });

    let dragging = false, offsetX = 0, offsetY = 0;
    gear.addEventListener('mousedown', (e) => {
      dragging = true;
      offsetX = e.clientX - gear.offsetLeft;
      offsetY = e.clientY - gear.offsetTop;
      gear.style.cursor = 'grabbing';
    });
    document.addEventListener('mousemove', (e) => {
      if (dragging) {
        gear.style.left = `${e.clientX - offsetX}px`;
        gear.style.top = `${e.clientY - offsetY}px`;
        gear.style.bottom = 'auto';
        gear.style.right = 'auto';
      }
    });
    document.addEventListener('mouseup', () => {
      dragging = false;
      gear.style.cursor = 'grab';
    });
  }

  function watchNavigation() {
    let lastUrl = location.href;
    new MutationObserver(() => {
      if (location.href !== lastUrl) {
        lastUrl = location.href;
        setTimeout(applySettings, 1000);
      }
    }).observe(document.body, { childList: true, subtree: true });
  }

  function init() {
    const wait = setInterval(() => {
      if (document.querySelector('ytd-app')) {
        clearInterval(wait);
        createUI();
        applySettings();
        autoAdWatcher();
        watchNavigation();
      }
    }, 300);
  }

  init();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址