YouTube 廣告跳過器

自動跳過 YouTube 上的廣告,提供進階選項、效能改進和最佳影片品質選擇。

目前為 2024-08-10 提交的版本,檢視 最新版本

// ==UserScript==
// @name              YouTube Ad Skipper
// @name:en           YouTube Ad Skipper
// @name:vi           YouTube Ad Skipper
// @name:zh-cn         YouTube 广告跳过器
// @name:zh-tw         YouTube 廣告跳過器
// @name:ja           YouTube 広告スキッパー
// @name:ko           YouTube 광고 건너뛰기
// @name:es           YouTube Ad Skipper
// @name:ru           Пропускатель рекламы YouTube
// @name:id           YouTube Ad Skipper
// @name:hi           YouTube विज्ञापन स्किपर
// @namespace        http://tampermonkey.net/
// @version          2.1.0
// @description         Automatically skip ads on YouTube with advanced options, performance improvements, and best video quality selection.
// @description:en      Automatically skip ads on YouTube with advanced options, performance improvements, and best video quality selection.
// @description:vi      Tự động bỏ qua quảng cáo trên YouTube với các tùy chọn nâng cao, cải thiện hiệu suất và lựa chọn chất lượng video tốt nhất.
// @description:zh-cn    自动跳过 YouTube 上的广告,提供高级选项、性能改进和最佳视频质量选择。
// @description:zh-tw    自動跳過 YouTube 上的廣告,提供進階選項、效能改進和最佳影片品質選擇。
// @description:ja      YouTube の広告を自動的にスキップし、高度なオプション、パフォーマンスの向上、最高のビデオ品質の選択を提供します。
// @description:ko      YouTube에서 광고를 자동으로 건너뛰고 고급 옵션, 성능 향상 및 최상의 비디오 품질 선택을 제공합니다。
// @description:es      Omite automáticamente los anuncios en YouTube con opciones avanzadas, mejoras de rendimiento y selección de la mejor calidad de video.
// @description:ru      Автоматически пропускает рекламу на YouTube с расширенными настройками, улучшением производительности и выбором наилучшего качества видео.
// @description:id      Lewati iklan secara otomatis di YouTube dengan opsi lanjutan, peningkatan kinerja, dan pemilihan kualitas video terbaik.
// @description:hi      YouTube पर विज्ञापनों को स्वचालित रूप से छोड़ें, उन्नत विकल्पों, प्रदर्शन में सुधार और सर्वोत्तम वीडियो गुणवत्ता चयन के साथ।
// @author           Jann
// @license          MIT
// @icon             https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @match            https://*.youtube.com/*
// @grant            GM_setValue
// @grant            GM_getValue
// @grant            GM_registerMenuCommand
// @grant            GM_addStyle
// ==/UserScript==

// This userscript automatically skips ads on YouTube, providing options for 
// performance enhancements and selecting the best video quality.

// Features:
// - Automatically skips ads by clicking the skip button or seeking to the end.
// - Mutes ads (optional).
// - Hides ad overlays (optional).
// - Removes ad slots from the page (optional).
// - Auto-hides annotations (optional).
// - Disables autoplay (optional).
// - Improves performance by hiding comments, sidebar, disabling animations,
//   lazy-loading images, and reducing script execution (optional).
// - Automatically selects the best video quality (optional).
// - Provides a configurable settings menu accessible through the Tampermonkey menu.

// Configuration:
// The script can be configured through a JSON object in the settings menu.
// The following options are available:

// - `skipInterval`: Interval (in milliseconds) to check for ads. (Default: 500)
// - `observerThrottle`: Throttle time (in milliseconds) for the mutation observer. (Default: 1000)
// - `muteAds`: Mute ads during playback. (Default: false)
// - `hideAdOverlays`: Hide ad overlays that appear on top of the video. (Default: true)
// - `removeAdSlots`: Remove ad slots from the page entirely. (Default: true)
// - `autoHideAnnotations`: Automatically hide annotations that appear on the video. (Default: true)
// - `disableAutoplay`: Disable the autoplay feature on YouTube. (Default: false)
// - `improvePerformance`: Enable performance improvements. (Default: true)
// - `autoSelectBestQuality`: Automatically select the best available video quality. (Default: true)
// - `performance`: Object containing performance-related settings:
//   - `hideComments`: Hide the comments section. (Default: true)
//   - `hideSidebar`: Hide the sidebar on the watch page. (Default: true)
//   - `disableAnimations`: Disable animations on the page. (Default: true)
//   - `lazyLoadImages`: Lazy-load images to improve initial page load time. (Default: true)
//   - `reduceScriptExecution`: Reduce the execution of unnecessary scripts. (Default: true)

// How to use:
// 1. Install a userscript manager like Tampermonkey or Greasemonkey.
// 2. Copy and paste this script into the userscript manager.
// 3. Visit YouTube and enjoy ad-free viewing.

// To configure the script:
// 1. Open the Tampermonkey/Greasemonkey menu.
// 2. Click on "YouTube Ad Skipper".
// 3. Click on "Configure Ad Skipper".
// 4. A prompt will appear with the current configuration in JSON format.
// 5. Modify the configuration as desired and click "OK".

// Note: This script is provided as-is and may not work with all versions of YouTube. 
// Use it at your own risk.

// --- Code starts below ---
(function () {
  'use strict';

  const DEFAULT_CONFIG = {
    skipInterval: 500,
    observerThrottle: 1000,
    muteAds: false,
    hideAdOverlays: true,
    removeAdSlots: true,
    autoHideAnnotations: true,
    disableAutoplay: false,
    improvePerformance: true,
    autoSelectBestQuality: true,
    performance: {
      hideComments: true,
      hideSidebar: true,
      disableAnimations: true,
      lazyLoadImages: true,
      reduceScriptExecution: true
    }
  };

  let config = { ...DEFAULT_CONFIG, ...GM_getValue('AdSkipperConfig', {}) };

  function saveConfig() {
    GM_setValue('AdSkipperConfig', config);
  }

  function createSettingsMenu() {
    GM_registerMenuCommand("Configure Ad Skipper", () => {
      const newConfig = prompt("Enter new configuration (JSON):", JSON.stringify(config, null, 2));
      if (newConfig) {
        try {
          config = { ...DEFAULT_CONFIG, ...JSON.parse(newConfig) };
          saveConfig();
          alert("Configuration updated successfully!");
          location.reload();
        } catch (e) {
          alert("Error: Invalid configuration format!");
        }
      }
    });
  }

  function skipAds() {
    const video = document.querySelector('video');

    // Skip ads using the skip button
    document.querySelectorAll('.ytp-ad-skip-button, .ytp-ad-skip-button-modern').forEach(button => button.click());

    // Skip ads by seeking to the end
    if (document.querySelector('.ad-showing') && video) {
      video.currentTime = video.duration;
      video.muted = config.muteAds;
    }

    // Hide ad overlays
    if (config.hideAdOverlays) {
      document.querySelectorAll('.ytp-ad-overlay-close-button').forEach(button => button.click());
      document.querySelectorAll('.ytp-ad-overlay-image').forEach(overlay => overlay.style.display = 'none'); // Hide image overlays
    }

    // Remove ad slots
    if (config.removeAdSlots) {
      document.querySelectorAll('ytd-ad-slot-renderer, ytm-promoted-video-renderer').forEach(slot => {
        slot.style.display = 'none';
      });
    }

    // Auto-hide annotations
    if (config.autoHideAnnotations) {
      document.querySelectorAll('.ytp-ce-covering-overlay').forEach(overlay => overlay.style.display = 'none');
    }

    // Disable autoplay
    if (config.disableAutoplay) {
      const autoplayToggle = document.querySelector('.ytp-autonav-toggle-button[aria-checked="true"]');
      if (autoplayToggle) autoplayToggle.click();
    }
  }

  function throttle(func, limit) {
    let lastFunc;
    let lastRan;
    return function() {
      const context = this;
      const args = arguments;
      if (!lastRan) {
        func.apply(context, args);
        lastRan = Date.now();
      } else {
        clearTimeout(lastFunc);
        lastFunc = setTimeout(function() {
          if ((Date.now() - lastRan) >= limit) {
            func.apply(context, args);
            lastRan = Date.now();
          }
        }, limit - (Date.now() - lastRan));
      }
    }
  }

  const throttledSkipAds = throttle(skipAds, config.observerThrottle);

  const observer = new MutationObserver(throttledSkipAds);

  observer.observe(document.body, {
    childList: true,
    subtree: true
  });

  function setMaxVideoQuality() {
    if (!config.autoSelectBestQuality) return;

    const qualityMenu = document.querySelector('.ytp-settings-button');
    if (qualityMenu) {
      qualityMenu.click();
      setTimeout(() => {
        const qualitySettings = document.querySelector('.ytp-panel-menu');
        if (qualitySettings) {
          const qualityOptions = qualitySettings.querySelectorAll('.ytp-menuitem');
          let highestQuality = qualityOptions[qualityOptions.length - 1]; // Select the last option, which is usually the highest

          // Iterate through options and select the one with the highest resolution
          qualityOptions.forEach(option => {
            const resolution = option.textContent.trim().match(/\d+p/);
            if (resolution) {
              const currentResolution = parseInt(resolution[0].slice(0, -1));
              const highestResolution = parseInt(highestQuality.textContent.trim().match(/\d+p/)[0].slice(0, -1));
              if (currentResolution > highestResolution) {
                highestQuality = option;
              }
            }
          });

          if (highestQuality) {
            highestQuality.click();
          }
        }
        qualityMenu.click(); // Close the menu
      }, 100);
    }
  }

  function applyPerformanceImprovements() {
    if (!config.improvePerformance) return;

    let styles = '';

    if (config.performance.hideSidebar) {
      styles += `
        .ytd-watch-flexy:not([theater]) #secondary.ytd-watch-flexy,
        ytd-watch-next-secondary-results-renderer {
          display: none !important;
        }
      `;
    }

    if (config.performance.hideComments) {
      styles += `
        #comments {
          display: none !important;
        }
      `;
    }

    if (config.performance.disableAnimations) {
      styles += `
        * {
          transition: none !important;
          animation: none !important;
        }
      `;
    }

    if (config.performance.lazyLoadImages) {
      document.addEventListener('DOMContentLoaded', () => {
        const images = document.querySelectorAll('img');
        images.forEach(img => {
          img.loading = 'lazy';
        });
      });
    }

    if (config.performance.reduceScriptExecution) {
      // Disable certain YouTube features that might be script-heavy
      styles += `
        .ytp-ce-element {
          display: none !important;
        }
      `;
    }

    GM_addStyle(styles);

    // Additional performance improvements
    if (config.performance.reduceScriptExecution) {
      // Throttle scroll events
      let ticking = false;
      window.addEventListener('scroll', function(e) {
        if (!ticking) {
          window.requestAnimationFrame(function() {
            // Handle scroll event here
            ticking = false;
          });
          ticking = true;
        }
      });

      // Debounce resize events
      let resizeTimer;
      window.addEventListener('resize', function(e) {
        clearTimeout(resizeTimer);
        resizeTimer = setTimeout(function() {
          // Handle resize event here
        }, 250);
      });
    }
  }

  function init() {
    setInterval(skipAds, config.skipInterval);
    setInterval(setMaxVideoQuality, 5000);
    applyPerformanceImprovements();
    createSettingsMenu();
  }

  init();
})();