您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Movie But Ads is a collection of user scripts that enhance the viewing experience on Chinese movie websites. These scripts remove ads, improve functionality, and optimize the user interface for a smoother movie-watching experience.
// ==UserScript== // @name MovieButAds > Duboku // @namespace https://duboku.movie-but-ads.mutoo.im // @version 0.5.0 // @description Movie But Ads is a collection of user scripts that enhance the viewing experience on Chinese movie websites. These scripts remove ads, improve functionality, and optimize the user interface for a smoother movie-watching experience. // @author mutoo<[email protected]> // @license MIT // @icon https://www.google.com/s2/favicons?domain=www.duboku.tv // @match https://*.duboku.tv/* // @match https://*.duboku.fun/* // @run-at document-start // @grant none // ==/UserScript== (function(){'use strict';class Router { constructor() { this.routes = new Map(); } register(path, callback) { this.routes.set(path, callback); } handle(pathname = location.pathname) { for (const [path, callback] of this.routes) { if (typeof path === 'string' && pathname === path) { callback(); return; } if (path instanceof RegExp && path.test(pathname)) { callback(); return; } } console.warn(`No route found for ${pathname}`); } } const router = new Router();/** * ensure a condition is met * @param {() => boolean} condition * @param {number} maxAttempts * @param {string} failureMessage * @returns {Promise<boolean>} */ function ensureCondition(condition, maxAttempts = 600, failureMessage) { return new Promise((resolve, reject) => { let attempts = 0; function detect() { const result = condition(); if (result) { resolve(result); } else if (attempts < maxAttempts) { attempts++; requestAnimationFrame(detect); } else { reject(new Error(failureMessage)); } } requestAnimationFrame(detect); }); } /** * ensure a global object is present * @param {string} objectName * @param {number} maxAttempts * @returns {Promise<boolean>} */ function ensureGlobalObject(objectName, maxAttempts = 600) { return ensureCondition(() => window[objectName], maxAttempts, `Cannot detect ${objectName} after ${maxAttempts} attempts`); }class KeyboardShortcuts { constructor(videoController, options) { this.videoController = videoController; this.skip = 10; this.audioContext = null; this.delayNode = null; this.delayNodeConnected = false; this.keyUpDelegate = options?.onKeyUp ?? function () {}; this.bindEvents(); } bindEvents() { window.addEventListener('keyup', this.handleKeyUp.bind(this)); } initAudioContext() { if (!this.audioContext) { this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); this.delayNode = this.audioContext.createDelay(5); } } handleKeyUp(e) { if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) { return; } const { videoController: vc } = this; switch (e.key) { case '1': case '2': case '3': case '4': case '5': vc.setPlaybackRate(parseInt(e.key)); break; case '-': vc.decreasePlaybackRate(); break; case '=': vc.increasePlaybackRate(); break; case 'f': vc.toggleFullscreen(); break; case 'p': vc.togglePictureInPicture(); break; case ',': vc.seek(vc.getCurrentTime() - this.skip); break; case '.': vc.seek(vc.getCurrentTime() + this.skip); break; case '<': vc.seek(vc.getCurrentTime() - this.skip * 2); break; case '>': vc.seek(vc.getCurrentTime() + this.skip * 2); break; case 'c': this.connectAudio(); break; case '[': this.decreaseAudioDelay(); break; case ']': this.increaseAudioDelay(); break; default: this.keyUpDelegate(e); break; } } connectAudio() { const video = this.videoController.getVideo(); if (video && !this.delayNodeConnected) { this.initAudioContext(); const source = this.audioContext.createMediaElementSource(video); source.connect(this.delayNode).connect(this.audioContext.destination); this.delayNodeConnected = true; console.log('Audio connected'); } } decreaseAudioDelay() { if (this.delayNodeConnected) { this.delayNode.delayTime.value = Math.max(0, this.delayNode.delayTime.value - 0.1); console.log('DelayTime:', this.delayNode.delayTime.value); } } increaseAudioDelay() { if (this.delayNodeConnected) { this.delayNode.delayTime.value += 0.1; console.log('DelayTime:', this.delayNode.delayTime.value); } } }class VideoControllerInterface { /** get the video element */ getVideo() { throw new Error('Not implemented'); } /** set the playback rate */ setPlaybackRate(_rate) { throw new Error('Not implemented'); } /** get the playback rate */ getPlaybackRate() { throw new Error('Not implemented'); } /** decrease the playback rate */ decreasePlaybackRate() { const rate = this.getPlaybackRate(); this.setPlaybackRate(Math.max(0, rate - 0.25)); } /** increase the playback rate */ increasePlaybackRate() { const rate = this.getPlaybackRate(); this.setPlaybackRate(Math.min(rate + 0.25, 10)); } /** check if the video is fullscreen */ isFullscreen() { throw new Error('Not implemented'); } /** request fullscreen */ requestFullscreen() { throw new Error('Not implemented'); } /** exit fullscreen */ exitFullscreen() { throw new Error('Not implemented'); } /** toggle fullscreen */ toggleFullscreen() { if (this.isFullscreen()) { this.exitFullscreen(); } else { if (document.pictureInPictureElement) { document.exitPictureInPicture(); } this.requestFullscreen(); } } /** request picture in picture */ requestPictureInPicture() { throw new Error('Not implemented'); } /** toggle picture in picture */ togglePictureInPicture() { if (!('pictureInPictureEnabled' in document)) { console.warn('Picture-in-picture is not supported in this browser.'); return; } if (document.pictureInPictureElement) { document.exitPictureInPicture(); } else { if (this.isFullscreen()) { this.exitFullscreen(); } this.requestPictureInPicture(); } } /** seek to a specific time */ seek(_time) { throw new Error('Not implemented'); } /** get the current time */ getCurrentTime() { throw new Error('Not implemented'); } /** get the duration */ getDuration() { throw new Error('Not implemented'); } }class DubokuTvVideoController extends VideoControllerInterface { constructor(player) { super(); this.vjs = player; } getVideo() { return this.vjs.$('video'); } setPlaybackRate(rate) { this.vjs.playbackRate(rate); } getPlaybackRate() { return this.vjs.playbackRate(); } isFullscreen() { return this.vjs.isFullscreen(); } requestFullscreen() { this.vjs.requestFullscreen(); } exitFullscreen() { this.vjs.exitFullscreen(); } requestPictureInPicture() { this.getVideo().requestPictureInPicture(); } seek(time) { this.vjs.currentTime(Math.max(0, Math.min(time, this.getDuration()))); } getCurrentTime() { return this.vjs.currentTime(); } getDuration() { return this.vjs.duration(); } }router.register(/^\/static\/player\//, () => { ensureGlobalObject('player').then(player => { // autoplay player.autoplay(true); // steal focus for iframe window.focus(); // add the video controller and keyboard shortcuts const videoController = new DubokuTvVideoController(player); new KeyboardShortcuts(videoController, { onKeyUp: e => { if (e.key === ' ') { if (player.paused()) { player.play(); } else { player.pause(); } } } }); console.log('movie-but-ads', 'duboku.tv'); }); }); router.handle();})();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址