您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
过滤广告 on iyf.tv
// ==UserScript== // @name IYF Ad Filter // @namespace http://tampermonkey.net/ // @version 0.3.12 // @description Filter ads on iyf.tv // @description:zh-CN 过滤广告 on iyf.tv // @author Dylan Zhang // @include https://*.iyf.tv/* // @include https://*.yifan.tv/* // @include https://*.yfsp.tv/* // @include https://*.aiyifan.tv/* // @icon https://www.google.com/s2/favicons?sz=64&domain=iyf.tv // @license MIT // @grant GM_addStyle // ==/UserScript== (function() { 'use strict'; /* utilities */ const utils = { ensureCondition(condition, maxAttempts = 600 /* 10s */, failureMessage) { return new Promise((resolve, reject) => { let attempts = 0 const detect = () => { const result = condition() if (result) { resolve(result) } else if (attempts < maxAttempts) { attempts++ requestAnimationFrame(detect) } else { reject(new Error(failureMessage)) } } requestAnimationFrame(detect) }) }, ensureElement(selector, maxAttempts = 600) { return utils.ensureCondition( () => document.querySelector(selector), maxAttempts, `Could not detect ${selector} after ${maxAttempts} attempts` ) }, getDeps(el, prop) { for(const key in el) { if (key.startsWith('__ngContext__')) { const context = el[key] for (const item of context) { if (item && typeof item === 'object' && item[prop]) { return [item[prop], item] } } } } return [] }, delegateArray(arr) { const delegateProto = Object.create(Array.prototype) delegateProto.push = function(){ return 0 } Object.setPrototypeOf(arr, delegateProto) return arr } } /* router */ class Router { constructor() { this.routes = new Map() this.initialize() } initialize() { const originalPushState = history.pushState const originalReplaceState = history.replaceState const pushstateEvent = new Event('pushstate') const replacestateEvent = new Event('replacestate') // override pushState history.pushState = function() { const result = originalPushState.apply(this, arguments) window.dispatchEvent(pushstateEvent) return result }; // override replaceState history.replaceState = function() { const result = originalReplaceState.apply(this, arguments) window.dispatchEvent(replacestateEvent) return result } ;['pushstate', 'replaceState', 'popstate'].forEach(eventName => { window.addEventListener(eventName, () => this.handle()) }) } use(path, handler) { const handlers = this.routes.has(path) ? [...this.routes.get(path), handler] : [handler] this.routes.set(path, handlers) return this } once(path, handler) { let done = false function fn() { if (done) return done = true handler.apply(this, arguments) } this.use(path, fn) return this } handle(pathname) { if (!pathname) pathname = this.getPathname() for(const [path, handlers] of this.routes) { if ( typeof path === 'string' && path === pathname || path instanceof RegExp && path.test(pathname) ) { handlers.forEach(fn => fn()) return } } } getPathname() { const path = location.pathname.split('/')[1] return path ? `/${path}` : '/' } } /* shortcuts */ class VideoShortcuts { constructor(vgAPI) { this.vgAPI = vgAPI this.step = 5 this.bindEvents() } bindEvents() { window.addEventListener('keydown', this.handleKeyDown.bind(this)) } handleKeyDown(event) { if (this.isTyping()) return if (!this.vgAPI) return switch(event.key) { case '1': case '2': case '3': case '4': case '5': this.setPlaybackRate(parseInt(event.key)) break case 'a': // rewind this.seek(this.getCurrentTime() - this.step) break case 'd': // fast forward this.seek(this.getCurrentTime() + this.step) break case 'f': // fullscreen this.toggleFullscreen() break } } toggleFullscreen() { this.isFullscreen() ? this.exitFullscreen() : this.requestFullscreen() } isFullscreen() { return this.vgAPI.fsAPI.isFullscreen } requestFullscreen() { this.vgAPI.fsAPI.request() } exitFullscreen() { this.vgAPI.fsAPI.exit() } seek(time) { this.vgAPI.currentTime = time } getCurrentTime() { return this.vgAPI.currentTime } setPlaybackRate(rate) { this.vgAPI.playbackRate = rate } isTyping() { const activeElement = document.activeElement return activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement || activeElement.isContentEditable === true } } /* page */ const commonStyle = ` a:has(img[alt="广告"]), a[href="https://www.wyav.tv/"], i.vip-label { display: none!important; } .navbar .multi-top-buttons, .navbar app-dn-user-menu-item.top-item, .navbar .login-inner-box, .navbar .menu-item:has(a[href="https://www.wyav.tv/"]) { display: none!important; } .navbar .menu-pop.two-col { width: 160px!important; left: 0!important; } .navbar .my-card.none-user, .navbar .none-user-content { height: auto!important; } .login-frame-container .gg-dl { display: none!important; } .login-frame-container .login-frame-box.heighter, .login-frame-container .inner { width: auto!important; margin-left: 0px!important; } #sticky-block .inner { display: none!important; } ` const indexStyle = ` .sliders .sec4, .sliders .sec4 + .separater, app-index app-recommended-news:nth-of-type(2), app-index app-classified-top-videos:nth-of-type(1) > app-home-collection, app-index div:has(> app-discovery-in-home), app-index .new-list { display: none!important; } ` const playStyle = ` .video-player > div:last-child, .video-player .overlay-logo, .video-player vg-pause-f, .video-player .publicbox, .video-player .quanlity-items .use-coin-box { display: none!important; } .video-player .player-title { margin-left: 0!important; } .video-player + div.ps > div.bl { display: none!important; } .main div.playPageTop { min-height: 594px!important; } ` const listStyle = ` #filterDiv, .filters { width: 100%; } .filters + div.ss-ctn { display: none!important; } ` const router = new Router() router.once('/', () => { GM_addStyle(indexStyle) }) const playRE = /^\/(play|watch)/ let videoShortcuts = null router.once(playRE, () => { GM_addStyle(playStyle) // shortcuts videoShortcuts = new VideoShortcuts() }) .use(playRE, () => { const { ensureElement, getDeps, delegateArray } = utils Promise.all([ ensureElement('aa-videoplayer'), ensureElement('vg-player'), ensureElement('.action-pannel i') ]).then(([ aaVideoPlayerEl, vgPlayerEl, danmuEl ]) => { // close danmu if (danmuEl.classList.contains('icondanmukai')) { danmuEl.click() } // remove pause ads for 20s const [pgmp] = getDeps(aaVideoPlayerEl, 'pgmp') if (pgmp) { pgmp.dataList = delegateArray([]) } else { console.warn('pgmp not found') } // shortcuts const [vgAPI] = getDeps(vgPlayerEl, 'API') if (vgAPI) { videoShortcuts.vgAPI = vgAPI } else { console.warn('vgAPI not found') } }) }) router.once(/^\/(list|search)/, () => { GM_addStyle(listStyle) }) function init() { GM_addStyle(commonStyle) router.handle() } init() })();