// ==UserScript== // @name 火狐倍速音画同步修复 // @namespace http://tampermonkey.net/ // @version 1.0.0 // @description 彻底绕过扩展拦截,轮询检测倍速变化,回到1倍速时触发修复,加入冷却时间防止频繁跳动 // @author ShuiYun // @match *://*/* // @grant none // @run-at document-idle // ==/UserScript== (function () { 'use strict'; // ========== 配置区 ========== // 触发一次“退1进1”修复后,需要等待多久(毫秒)才允许再次触发 // 5000 = 5秒,可根据你的实际观感自由修改(比如改成 3000 或 10000) const COOLDOWN_MS = 10000; // ============================ const lastRateMap = new WeakMap(); // 记录上一次的倍速 const cooldownMap = new WeakMap(); // 记录每个 video 上次触发修复的时间戳 // 每 100ms 扫描一次页面上的视频元素 setInterval(() => { const videos = document.getElementsByTagName('video'); for (const video of videos) { const currentRate = video.playbackRate; const lastRate = lastRateMap.get(video); // 如果记录过旧速率,且当前速率不等于旧速率,说明倍速刚刚被改变 if (lastRate !== undefined && currentRate !== lastRate) { // 倍速变为 1 且正在播放时,准备触发修复 if (currentRate === 1 && !video.paused) { const now = Date.now(); // 获取该视频上一次触发修复的时间,如果没有则记为 0 const lastTriggerTime = cooldownMap.get(video) || 0; // 判断:当前时间 - 上次触发时间 >= 配置的冷却时间 if (now - lastTriggerTime >= COOLDOWN_MS) { // 更新该视频的冷却时间戳 cooldownMap.set(video, now); // 执行“退1进1”修复 video.currentTime = Math.max(0, video.currentTime - 1); setTimeout(() => { video.currentTime += 1; }, 50); } } } // 无论变没变,都把当前的速率存下来作为下次对比的基准 lastRateMap.set(video, currentRate); } }, 100); })();