YouTube Ad Skipper @ Gurveer

Instantly skips YouTube ads (skippable & non-skippable) and blocks ad elements. Features: customizable settings, statistics tracking, keyboard shortcuts. © 2025 Gurveer. All rights reserved.

Installera detta skript?
Upphovsmannens rekommenderade skript

Du kanske också gillar YouTube Music DJ Controller Pro Ultimate.

Installera detta skript

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         YouTube Ad Skipper @ Gurveer
// @namespace    https://github.com/gurr-i/browser-scripts
// @version      9.0.0
// @author       Gurveer (@Gurveer)
// @description  Instantly skips YouTube ads (skippable & non-skippable) and blocks ad elements. Features: customizable settings, statistics tracking, keyboard shortcuts. © 2025 Gurveer. All rights reserved.
// @license      All Rights Reserved
// @copyright    2025, Gurveer (@Gurveer)
// @icon         https://www.google.com/s2/favicons?domain=youtube.com
// @match        https://www.youtube.com/*
// @match        https://m.youtube.com/*
// @match        https://music.youtube.com/*
// @exclude      https://studio.youtube.com/*
// @grant        none
// @run-at       document-start
// @noframes
// ==/UserScript==


(function () {
  'use strict';
 
  /**
   * YouTube Ad Skipper
   * 
   * @author Gurveer (@Gurveer)
   * @version 1.0.0
   * @license All Rights Reserved
   * @copyright 2025 Gurveer. All rights reserved.
   * 
   * This script automatically skips YouTube ads and blocks ad elements.
   * Features:
   * - Instant ad skipping (skippable and non-skippable)
   * - Interface ad blocking
   * - Customizable settings
   * - Statistics tracking
   * - Keyboard shortcuts (Ctrl+Shift+A for settings, Ctrl+Shift+S for stats)
   */
  (function() {
    function loadSettings() {
      try {
        const saved = localStorage.getItem("ytAdSkipperSettings");
        return saved ? JSON.parse(saved) : {};
      } catch (e) {
        return {};
      }
    }
    let videoPlayer;
    let originalVolume = 1;
    let originalMuted = false;
    let adStats = {
      blocked: 0,
      skipped: 0,
      sessionStart: Date.now()
    };
    let lastAdSkipTime = 0;
    let adSkipCooldown = 2e3;
    const settings = {
      autoUnmute: true,
      speedUpAds: false,
      // Disabled by default for better compatibility
      showStats: true,
      showNotifications: true,
      debugMode: false,
      // Disabled in production
      ...loadSettings()
    };
    const adSelectors = [
      "#masthead-ad",
      "ytd-rich-item-renderer.style-scope.ytd-rich-grid-row #content:has(.ytd-display-ad-renderer)",
      ".video-ads.ytp-ad-module",
      "tp-yt-paper-dialog:has(yt-mealbar-promo-renderer)",
      'ytd-engagement-panel-section-list-renderer[target-id="engagement-panel-ads"]',
      "#related #player-ads",
      "#related ytd-ad-slot-renderer",
      "ytd-ad-slot-renderer",
      "ytd-in-feed-ad-layout-renderer",
      "yt-mealbar-promo-renderer",
      'ytd-popup-container:has(a[href="/premium"])',
      "ad-slot-renderer",
      "ytm-companion-ad-renderer",
      ".ytp-ad-overlay-container",
      ".ytp-ad-text-overlay"
    ];
    window.debugMode = settings.debugMode;
    function formatDate(date) {
      const year = date.getFullYear();
      const month = String(date.getMonth() + 1).padStart(2, "0");
      const day = String(date.getDate()).padStart(2, "0");
      const hours = String(date.getHours()).padStart(2, "0");
      const minutes = String(date.getMinutes()).padStart(2, "0");
      const seconds = String(date.getSeconds()).padStart(2, "0");
      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    }
    function debugLog(message) {
      if (!window.debugMode) return;
      console.log(`[Ad Skipper] ${formatDate(/* @__PURE__ */ new Date())} - ${message}`);
    }
    function saveSettings() {
      try {
        localStorage.setItem("ytAdSkipperSettings", JSON.stringify(settings));
      } catch (e) {
        debugLog("Failed to save settings: " + e.message);
      }
    }
    function showNotification(message, duration = 3e3) {
      if (!settings.showNotifications) return;
      if (!document.getElementById("michroma-font")) {
        const fontLink = document.createElement("link");
        fontLink.id = "michroma-font";
        fontLink.rel = "stylesheet";
        fontLink.href = "https://fonts.googleapis.com/css2?family=Michroma&display=swap";
        document.head.appendChild(fontLink);
      }
      const notification = document.createElement("div");
      notification.style.cssText = `
    position: fixed;
    top: 80px;
    right: 20px;
    background: rgba(0, 0, 0, 0.75);
    color: #fff;
    padding: 12px 20px;
    border-radius: 8px;
    font-family: 'Michroma', sans-serif;
    font-size: 13px;
    z-index: 999998;
    box-shadow: 0 4px 12px rgba(0,0,0,0.5);
    backdrop-filter: blur(10px);
    animation: slideIn 0.3s ease-out;
  `;
      notification.textContent = message;
      const style = document.createElement("style");
      style.textContent = `
    @keyframes slideIn {
      from { transform: translateX(400px); opacity: 0; }
      to { transform: translateX(0); opacity: 1; }
    }
  `;
      document.head.appendChild(style);
      document.body.appendChild(notification);
      setTimeout(() => {
        notification.style.animation = "slideIn 0.3s ease-out reverse";
        setTimeout(() => notification.remove(), 300);
      }, duration);
    }
    function saveVideoState() {
      if (videoPlayer && !videoPlayer.classList.contains("ad-showing")) {
        originalVolume = videoPlayer.volume;
        originalMuted = videoPlayer.muted;
        debugLog(`Saved video state: volume=${originalVolume}, muted=${originalMuted}`);
      }
    }
    function restoreVideoState() {
      if (videoPlayer && settings.autoUnmute) {
        videoPlayer.volume = originalVolume;
        videoPlayer.muted = originalMuted;
        debugLog("Restored video state");
      }
    }
    function updateStats() {
      if (!settings.showStats) return;
      if (!document.getElementById("michroma-font")) {
        const fontLink = document.createElement("link");
        fontLink.id = "michroma-font";
        fontLink.rel = "stylesheet";
        fontLink.href = "https://fonts.googleapis.com/css2?family=Michroma&display=swap";
        document.head.appendChild(fontLink);
      }
      let statsDiv = document.getElementById("yt-ad-skipper-stats");
      if (!statsDiv) {
        statsDiv = document.createElement("div");
        statsDiv.id = "yt-ad-skipper-stats";
        statsDiv.style.cssText = `
      position: fixed;
      bottom: 20px;
      right: 20px;
      background: rgba(0, 0, 0, 0.41);
      color: #fff;
      padding: 12px 18px;
      border-radius: 8px;
      font-family: 'Michroma', sans-serif;
      font-size: 11px;
      z-index: 999997;
      min-width: 160px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.39);
      backdrop-filter: blur(10px);
    `;
        document.body.appendChild(statsDiv);
      }
      const sessionTime = Math.floor((Date.now() - adStats.sessionStart) / 6e4);
      statsDiv.textContent = "";
      const title = document.createElement("div");
      title.style.cssText = "font-weight: bold; margin-bottom: 8px; font-size: 10px; letter-spacing: 0.5px;";
      title.textContent = "🛡️ Ad Skipper @Gurveer";
      const blocked = document.createElement("div");
      blocked.style.cssText = "margin: 4px 0; letter-spacing: 0.3px; font-size: 8px;";
      blocked.textContent = `Blocked: ${adStats.blocked}`;
      const skipped = document.createElement("div");
      skipped.style.cssText = "margin: 4px 0; letter-spacing: 0.3px; font-size: 8px;";
      skipped.textContent = `Skipped: ${adStats.skipped}`;
      const session = document.createElement("div");
      session.style.cssText = "margin: 4px 0; letter-spacing: 0.3px; font-size: 8px;";
      session.textContent = `Session: ${sessionTime}m`;
      statsDiv.appendChild(title);
      statsDiv.appendChild(blocked);
      statsDiv.appendChild(skipped);
      statsDiv.appendChild(session);
    }
    function setExecutionFlag(flagId) {
      const style = document.createElement("style");
      style.id = flagId;
      (document.head || document.body).appendChild(style);
    }
    function getExecutionFlag(flagId) {
      return document.getElementById(flagId);
    }
    function hasExecutionFlag(flagId) {
      if (getExecutionFlag(flagId)) {
        return true;
      }
      setExecutionFlag(flagId);
      return false;
    }
    function createAdBlockStyle(flagId) {
      if (hasExecutionFlag(flagId)) {
        debugLog("Ad-blocking style already applied");
        return;
      }
      const style = document.createElement("style");
      (document.head || document.body).appendChild(style);
      style.appendChild(document.createTextNode(generateAdBlockCss(adSelectors)));
      const blockedAds = document.querySelectorAll(adSelectors.join(","));
      adStats.blocked = blockedAds.length;
      updateStats();
      debugLog("Ad-blocking style applied successfully");
    }
    function generateAdBlockCss(selectors) {
      return selectors.map((selector) => `${selector}{display:none!important}`).join(" ");
    }
    function simulateTouch() {
      try {
        const touch = new Touch({
          identifier: Date.now(),
          target: this,
          clientX: 12,
          clientY: 34,
          radiusX: 56,
          radiusY: 78,
          rotationAngle: 0,
          force: 1
        });
        const touchStart = new TouchEvent("touchstart", {
          bubbles: true,
          cancelable: true,
          view: window,
          touches: [touch],
          targetTouches: [touch],
          changedTouches: [touch]
        });
        this.dispatchEvent(touchStart);
        const touchEnd = new TouchEvent("touchend", {
          bubbles: true,
          cancelable: true,
          view: window,
          touches: [],
          targetTouches: [],
          changedTouches: [touch]
        });
        this.dispatchEvent(touchEnd);
      } catch (e) {
        debugLog("Touch simulation failed: " + e.message);
      }
    }
    function fetchVideoElement() {
      videoPlayer = document.querySelector(".ad-showing video") || document.querySelector(".html5-main-video") || document.querySelector("video.video-stream") || document.querySelector("video");
      if (videoPlayer) {
        debugLog("Video element found: " + videoPlayer.className);
      } else {
        debugLog("No video element found");
      }
    }
    function resumePlayback() {
      if ((videoPlayer == null ? void 0 : videoPlayer.paused) && videoPlayer.currentTime < 1) {
        videoPlayer.play();
        debugLog("Resumed video playback");
      }
    }
    function clearOverlay() {
      const premiumPopups = [...document.querySelectorAll("ytd-popup-container")];
      const targetPopups = premiumPopups.filter((popup) => popup.querySelector('a[href="/premium"]'));
      if (targetPopups.length > 0) {
        targetPopups.forEach((popup) => popup.remove());
        debugLog("Removed ad blocker popup");
      }
      const backdrops = document.querySelectorAll("tp-yt-iron-overlay-backdrop");
      const targetBackdrop = Array.from(backdrops).find((backdrop) => backdrop.style.zIndex === "2201");
      if (targetBackdrop) {
        targetBackdrop.className = "";
        targetBackdrop.removeAttribute("opened");
        debugLog("Closed overlay backdrop");
      }
    }
    function bypassAd() {
      if (!videoPlayer) {
        debugLog("bypassAd: No video player");
        return;
      }
      const skipBtn = document.querySelector(".ytp-ad-skip-button") || document.querySelector(".ytp-skip-ad-button") || document.querySelector(".ytp-ad-skip-button-modern");
      const shortAd = document.querySelector(".video-ads.ytp-ad-module .ytp-ad-player-overlay") || document.querySelector(".ytp-ad-button-icon");
      const adShowing = videoPlayer.classList.contains("ad-showing");
      const adInterrupting = videoPlayer.classList.contains("ad-interrupting");
      const adPlaying = document.querySelector(".ad-showing");
      const isAdPlaying = skipBtn || shortAd || adShowing || adInterrupting || adPlaying;
      if (isAdPlaying) {
        const now = Date.now();
        if (now - lastAdSkipTime < adSkipCooldown) {
          return;
        }
        debugLog(`AD DETECTED! Skip: ${!!skipBtn}, Short: ${!!shortAd}, Showing: ${adShowing}, Interrupting: ${adInterrupting}, AdPlaying: ${!!adPlaying}`);
        if (!videoPlayer.dataset.adStateSaved) {
          saveVideoState();
          videoPlayer.dataset.adStateSaved = "true";
          debugLog("Saved video state");
        }
        if (!window.location.href.includes("https://m.youtube.com/")) {
          if (!videoPlayer.muted) {
            videoPlayer.muted = true;
            debugLog("Muted ad");
          }
        }
        if (settings.speedUpAds && videoPlayer.playbackRate < 16) {
          videoPlayer.playbackRate = 16;
          debugLog("Sped up ad to 16x");
        }
        if (skipBtn) {
          debugLog("Clicking skip button...");
          skipBtn.click();
          simulateTouch.call(skipBtn);
          adStats.skipped++;
          updateStats();
          showNotification("⚡ Ad skipped!", 2e3);
          debugLog("Clicked skip ad button");
          lastAdSkipTime = now;
          if (videoPlayer.duration && videoPlayer.duration > 0) {
            videoPlayer.currentTime = videoPlayer.duration - 0.1;
            debugLog("Force-ended skippable ad");
          }
        } else if (videoPlayer.duration && videoPlayer.duration > 0 && !isNaN(videoPlayer.duration)) {
          debugLog(`Forcing ad end: current=${videoPlayer.currentTime}, duration=${videoPlayer.duration}`);
          videoPlayer.currentTime = videoPlayer.duration - 0.1;
          adStats.skipped++;
          updateStats();
          showNotification("⚡ Ad skipped!", 2e3);
          debugLog("Force-ended non-skippable ad");
          lastAdSkipTime = now;
        }
      } else {
        if (videoPlayer.dataset.adStateSaved) {
          if (videoPlayer.playbackRate > 1) {
            videoPlayer.playbackRate = 1;
            debugLog("Restored playback rate");
          }
          restoreVideoState();
          delete videoPlayer.dataset.adStateSaved;
          debugLog("Restored video state - ad ended");
        }
      }
    }
    function checkAndSkipAds() {
      try {
        fetchVideoElement();
        clearOverlay();
        bypassAd();
        resumePlayback();
      } catch (error) {
        debugLog("Error in ad blocker: " + error.message);
      }
    }
    function blockPlayerAds(flagId) {
      if (hasExecutionFlag(flagId)) {
        debugLog("Player ad blocker already running");
        return;
      }
      const target = document.body;
      const config = { childList: true, subtree: true };
      const observer = new MutationObserver(checkAndSkipAds);
      observer.observe(target, config);
      debugLog("Player ad blocker started successfully");
      setInterval(checkAndSkipAds, 2e3);
    }
    function createSettingsPanel() {
      if (!document.getElementById("michroma-font")) {
        const fontLink = document.createElement("link");
        fontLink.id = "michroma-font";
        fontLink.rel = "stylesheet";
        fontLink.href = "https://fonts.googleapis.com/css2?family=Michroma&display=swap";
        document.head.appendChild(fontLink);
      }
      const backdrop = document.createElement("div");
      backdrop.id = "yt-ad-skipper-backdrop";
      backdrop.style.cssText = `
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.7);
    z-index: 999998;
    display: none;
    backdrop-filter: blur(5px);
  `;
      document.body.appendChild(backdrop);
      const panel = document.createElement("div");
      panel.id = "yt-ad-skipper-settings";
      panel.style.cssText = `
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: rgba(0, 0, 0, 0.75);
    color: #fff;
    padding: 24px;
    border-radius: 12px;
    font-family: 'Michroma', sans-serif;
    z-index: 999999;
    box-shadow: 0 8px 32px rgba(0,0,0,0.6);
    backdrop-filter: blur(10px);
    display: none;
    min-width: 320px;
    max-width: 420px;
  `;
      const title = document.createElement("h3");
      title.style.cssText = "margin: 0 0 20px 0; font-size: 16px; letter-spacing: 1px; text-align: center;";
      title.textContent = "⚙️ Ad Skipper Settings";
      panel.appendChild(title);
      const options = [
        { id: "autoUnmute", label: "Auto-unmute after ads", checked: settings.autoUnmute },
        { id: "speedUpAds", label: "Speed up ads (16x)", checked: settings.speedUpAds },
        { id: "showStats", label: "Show statistics", checked: settings.showStats },
        { id: "showNotifications", label: "Show notifications", checked: settings.showNotifications },
        { id: "debugMode", label: "Debug mode", checked: settings.debugMode }
      ];
      options.forEach((opt) => {
        const label = document.createElement("label");
        label.style.cssText = "display: block; margin: 12px 0; cursor: pointer; font-size: 11px; letter-spacing: 0.3px;";
        const checkbox = document.createElement("input");
        checkbox.type = "checkbox";
        checkbox.id = opt.id;
        checkbox.checked = opt.checked;
        checkbox.style.cssText = "margin-right: 8px; cursor: pointer;";
        label.appendChild(checkbox);
        label.appendChild(document.createTextNode(" " + opt.label));
        panel.appendChild(label);
      });
      const saveBtn = document.createElement("button");
      saveBtn.id = "saveSettings";
      saveBtn.textContent = "Save Settings";
      saveBtn.style.cssText = `
    margin-top: 20px;
    padding: 10px 18px;
    background: rgba(255, 0, 0, 0.8);
    color: #fff;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-family: 'Michroma', sans-serif;
    font-size: 11px;
    letter-spacing: 0.5px;
    width: 100%;
    transition: background 0.3s ease;
  `;
      saveBtn.onmouseover = () => saveBtn.style.background = "rgba(255, 0, 0, 1)";
      saveBtn.onmouseout = () => saveBtn.style.background = "rgba(255, 0, 0, 0.8)";
      panel.appendChild(saveBtn);
      const closeBtn = document.createElement("button");
      closeBtn.id = "closeSettings";
      closeBtn.textContent = "Close";
      closeBtn.style.cssText = `
    margin-top: 10px;
    padding: 10px 18px;
    background: rgba(96, 96, 96, 0.8);
    color: #fff;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-family: 'Michroma', sans-serif;
    font-size: 11px;
    letter-spacing: 0.5px;
    width: 100%;
    transition: background 0.3s ease;
  `;
      closeBtn.onmouseover = () => closeBtn.style.background = "rgba(96, 96, 96, 1)";
      closeBtn.onmouseout = () => closeBtn.style.background = "rgba(96, 96, 96, 0.8)";
      panel.appendChild(closeBtn);
      document.body.appendChild(panel);
      const closePanel = () => {
        panel.style.display = "none";
        backdrop.style.display = "none";
      };
      saveBtn.addEventListener("click", () => {
        settings.autoUnmute = document.getElementById("autoUnmute").checked;
        settings.speedUpAds = document.getElementById("speedUpAds").checked;
        settings.showStats = document.getElementById("showStats").checked;
        settings.showNotifications = document.getElementById("showNotifications").checked;
        settings.debugMode = document.getElementById("debugMode").checked;
        window.debugMode = settings.debugMode;
        saveSettings();
        showNotification("✅ Settings saved!");
        closePanel();
        if (!settings.showStats) {
          const statsDiv = document.getElementById("yt-ad-skipper-stats");
          if (statsDiv) statsDiv.remove();
        } else {
          updateStats();
        }
      });
      closeBtn.addEventListener("click", closePanel);
      backdrop.addEventListener("click", closePanel);
    }
    function addKeyboardShortcuts() {
      document.addEventListener("keydown", (e) => {
        if (e.ctrlKey && e.shiftKey && e.key === "A") {
          e.preventDefault();
          const panel = document.getElementById("yt-ad-skipper-settings");
          const backdrop = document.getElementById("yt-ad-skipper-backdrop");
          if (panel && backdrop) {
            const isVisible = panel.style.display !== "none";
            panel.style.display = isVisible ? "none" : "block";
            backdrop.style.display = isVisible ? "none" : "block";
          }
        }
        if (e.ctrlKey && e.shiftKey && e.key === "S") {
          e.preventDefault();
          settings.showStats = !settings.showStats;
          saveSettings();
          if (settings.showStats) {
            updateStats();
            showNotification("📊 Stats enabled");
          } else {
            const statsDiv = document.getElementById("yt-ad-skipper-stats");
            if (statsDiv) statsDiv.remove();
            showNotification("📊 Stats disabled");
          }
        }
      });
    }
    function initialize() {
      debugLog("========================================");
      debugLog("Initializing YouTube Ad Skipper v1.0.0");
      debugLog("Author: Gurveer (@Gurveer)");
      debugLog("========================================");
      createAdBlockStyle("adBlockStyle");
      blockPlayerAds("playerAdBlock");
      createSettingsPanel();
      addKeyboardShortcuts();
      updateStats();
      setTimeout(checkAndSkipAds, 1e3);
      setInterval(() => {
        if (settings.showStats) {
          const blockedAds = document.querySelectorAll(adSelectors.join(","));
          adStats.blocked = blockedAds.length;
          updateStats();
        }
      }, 5e3);
      debugLog("YouTube Ad Skipper initialized successfully");
      debugLog("Press Ctrl+Shift+A to open settings");
      showNotification("🛡️ Ad Skipper Active", 3e3);
    }
    if (document.readyState === "loading") {
      document.addEventListener("DOMContentLoaded", initialize);
      debugLog("YouTube ad skipper scheduled");
    } else {
      initialize();
    }
    function resumeAndClear() {
      const video = document.querySelector("video.html5-main-video");
      if (video == null ? void 0 : video.paused) {
        video.play();
        debugLog("Resumed paused video");
      }
    }
    function clearPopup(node) {
      var _a, _b;
      try {
        const popup = (_a = node.querySelector) == null ? void 0 : _a.call(node, ".ytd-popup-container .ytd-enforcement-message-view-model");
        if (popup && popup.parentNode) {
          popup.parentNode.remove();
          debugLog("Removed popup element");
          const backdrops = document.getElementsByTagName("tp-yt-iron-overlay-backdrop");
          for (let i = backdrops.length - 1; i >= 0; i--) {
            backdrops[i].remove();
          }
          resumeAndClear();
        }
        if (((_b = node.tagName) == null ? void 0 : _b.toLowerCase()) === "tp-yt-iron-overlay-backdrop") {
          node.remove();
          debugLog("Removed backdrop element");
          resumeAndClear();
        }
      } catch (error) {
        debugLog("Error clearing popup: " + error.message);
      }
    }
    const popupObserver = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === "childList") {
          Array.from(mutation.addedNodes).filter((node) => node.nodeType === 1).forEach((node) => clearPopup(node));
        }
      });
    });
    if (document.body) {
      popupObserver.observe(document.body, {
        childList: true,
        subtree: true
      });
    } else {
      document.addEventListener("DOMContentLoaded", () => {
        popupObserver.observe(document.body, {
          childList: true,
          subtree: true
        });
      });
    }
  })();
 
})();