// ==UserScript== // @name Auto Skip YouTube Ads // @name:zh-CN 自动跳过 YouTube 广告 // @namespace https://github.com/oxol/userscripts // @version 1.0 // @description Automatically skip YouTube ads instantly. // @description:zh-CN 立即自动跳过 YouTube 广告。 // @author oxol // @match https://www.youtube.com/* // @match https://m.youtube.com/* // @match https://music.youtube.com/* // @exclude https://studio.youtube.com/* // @grant none // @license MIT // @compatible firefox // @compatible chrome // @compatible opera // @compatible safari // @compatible edge // @noframes // ==/UserScript== function skipAd() { if (checkIsYouTubeShorts()) return const adShowing = document.querySelector('.ad-showing') const pieCountdown = document.querySelector('.ytp-ad-timed-pie-countdown-container') const surveyQuestions = document.querySelector('.ytp-ad-survey-questions') if (adShowing === null && pieCountdown === null && surveyQuestions === null) return const moviePlayerEl = document.querySelector('#movie_player') let playerEl let player if (isYouTubeMobile || isYouTubeMusic) { playerEl = moviePlayerEl player = playerEl } else { playerEl = document.querySelector('#ytd-player') player = playerEl && playerEl.getPlayer() } if (playerEl === null || player === null) { console.log({ message: 'Player not found', timeStamp: getCurrentTimeString() }) return } let adVideo = null if (pieCountdown === null && surveyQuestions === null) { adVideo = document.querySelector( '#ytd-player video.html5-main-video, #song-video video.html5-main-video' ) console.table({ message: 'Ad video', video: adVideo !== null, src: adVideo?.src, paused: adVideo?.paused, currentTime: adVideo?.currentTime, duration: adVideo?.duration, timeStamp: getCurrentTimeString() }) if (adVideo !== null) { adVideo.muted = true } if (adVideo === null || !adVideo.src || adVideo.paused || isNaN(adVideo.duration)) { return } console.log({ message: 'Ad video has finished loading', timeStamp: getCurrentTimeString() }) } if (isYouTubeMusic && adVideo !== null) { adVideo.currentTime = adVideo.duration console.table({ message: 'Ad skipped', timeStamp: getCurrentTimeString(), adShowing: adShowing !== null, pieCountdown: pieCountdown !== null, surveyQuestions: surveyQuestions !== null }) } else { const videoData = player.getVideoData() const videoId = videoData.video_id const start = Math.floor(player.getCurrentTime()) if (moviePlayerEl !== null && moviePlayerEl.isSubtitlesOn()) { window.setTimeout(moviePlayerEl.toggleSubtitlesOn, 1000) } if ('loadVideoWithPlayerVars' in playerEl) { playerEl.loadVideoWithPlayerVars({ videoId, start }) } else { playerEl.loadVideoByPlayerVars({ videoId, start }) } console.table({ message: 'Ad skipped', videoId, start, title: videoData.title, timeStamp: getCurrentTimeString(), adShowing: adShowing !== null, pieCountdown: pieCountdown !== null, surveyQuestions: surveyQuestions !== null }) } } function checkIsYouTubeShorts() { return location.pathname.startsWith('/shorts/') } function getCurrentTimeString() { return new Date().toTimeString().split(' ', 1)[0] } function addCss() { const adsSelectors = [ '#player-ads', '#panels > ytd-engagement-panel-section-list-renderer[target-id="engagement-panel-ads"]', '#masthead-ad', '.yt-mealbar-promo-renderer', '.ytp-featured-product', 'ytd-merch-shelf-renderer', 'ytmusic-mealbar-promo-renderer', 'ytmusic-statement-banner-renderer' ] const adsSelector = adsSelectors.join(',') const css = `${adsSelector} { display: none !important; }` const style = document.createElement('style') style.textContent = css document.head.appendChild(style) } function removeAdElements() { const adSelectors = [ ['ytd-reel-video-renderer', '.ytd-ad-slot-renderer'] ] for (const adSelector of adSelectors) { const adEl = document.querySelector(adSelector[0]) if (adEl === null) continue const neededEl = adEl.querySelector(adSelector[1]) if (neededEl === null) continue adEl.remove() } } const isYouTubeMobile = location.hostname === 'm.youtube.com' const isYouTubeDesktop = !isYouTubeMobile const isYouTubeMusic = location.hostname === 'music.youtube.com' const isYouTubeVideo = !isYouTubeMusic addCss() if (isYouTubeVideo) { window.setInterval(removeAdElements, 1000) removeAdElements() } window.setInterval(skipAd, 500) skipAd()