可以使用该脚本,使用快捷键调节
// ==UserScript== // @name 全网视频倍速调节快捷键 // @namespace https://www.bilibili.com // @version 2.0 // @description 可以使用该脚本,使用快捷键调节 // @author pick // @match */* // @icon https://www.google.com/s2/favicons?sz=64&domain=bilibili.com // @grant none // ==/UserScript== 'use strict'; let LOCALSTORAGE_PLAYBACK_RATE_KEY = "video_playbackRate"; let SHOW_DIV_ID = "pickBilibili"; let INNER_DIV_ID = "innerDiv"; let DEBUG = false; let DEBUG_PREFIX = "PICK-DEBUG"; let MAX_NO_FOUND_VIDEO_CONTINUOUS_TIMES = 30; let lastKeyPressTime = new Map(); let doubleClickInterval = 200; let DETAIL_KEY = 'a'; let RATE_ARRAYS = { 'z': [1, 1.5, 2], 'x': [1, 1.25, 1.5, 2, 3], 'c': [1, 2, 3], 'v': [1, 5, 10] } let HTML = `<div id="${SHOW_DIV_ID}" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: rgba(128, 128, 128, 0.5); padding: 20px; border-radius: 10px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.6); z-index: 10;display: none"> <div id="${INNER_DIV_ID}"></div> </div>` log("脚本开始运行"); if (window.top === window.self) { // 只在主文档中执行一次 document.addEventListener("keydown", videoKeydownEvent); proxy(); } else { document.addEventListener("keydown", videoKeydownEvent); proxy(); } function proxy() { let noFoundVideoContinuousTimes = 0; const intervalId = setInterval(() => { let number = setPlaybackRate(); if (number === 0) { noFoundVideoContinuousTimes += 1; // log("连续没发现视频次数:" + noFoundVideoContinuousTimes); } else { // log("连续没发现视频次数,归0"); noFoundVideoContinuousTimes = 0; } if (noFoundVideoContinuousTimes === MAX_NO_FOUND_VIDEO_CONTINUOUS_TIMES) { // log("连续没发现视频次数:" + noFoundVideoContinuousTimes + ",任务终止"); clearInterval(intervalId); } }, 1000); } /** * 将当前页面所有video标签的倍数设置为用户使用的倍速 * @returns {number} 当前页面视频数量 */ function setPlaybackRate() { let videoDivs = getVideoDivs(); let playbackRate = getLocalPlaybackRate(); for (let i = 0; i < videoDivs.length; i++) { videoDivs[i].playbackRate = playbackRate; //视频可以聚焦 // videoDivs[i].setAttribute('tabindex', '0'); if ((videoDivs[i].pickHaveAlreadShow == null || videoDivs[i].pickHaveAlreadShow !== videoDivs[i].src) && !videoDivs[i].paused) { showPlaybackRateNew({showText: getLocalPlaybackRate() + "倍速", dismissTime: 1000}); videoDivs[i].pickHaveAlreadShow = videoDivs[i].src; } } return videoDivs.length; } /** * 键盘事件调整倍速事件 * @param event 事件 */ function videoKeydownEvent(event) { log("功能键 ctrl", event.ctrlKey, "shiftKey", event.shiftKey, "altKey", event.altKey, "eventKey", event.key); if (event.altKey || event.shiftKey || event.ctrlKey || event.target.tagName === "INPUT" || event.target.tagName === 'TEXTAREA') { return; } if (getVideoDivs().length === 0) { return; } if (event.key === 's') { showPlaybackRateNew({showText: getLocalPlaybackRate() + "倍速", dismissTime: 500, key: event.key}); return; } else if (event.key === DETAIL_KEY) { showPlaybackRateNew({showText: getLocalPlaybackRate() + "倍速", dismissTime: 2000, key: event.key}); } if(RATE_ARRAYS[event.key] == null){ return; } if (doubleClick(event)) { log("doubleClick", event.type, event.key, event.target); event.stopPropagation(); setLocalPlaybackRate(getLastPlaybackRate(event.key)); setPlaybackRate(); showPlaybackRateNew({showText: getLocalPlaybackRate() + "倍速", dismissTime: 500}); } else { log(event.type, event.key, event.target); event.stopPropagation(); setLocalPlaybackRate(getNextPlaybackRate(event.key)); setPlaybackRate(); showPlaybackRateNew({showText: getLocalPlaybackRate() + "倍速", dismissTime: 500, key: event.key}); } } function doubleClick(event) { return false; let lastTime = lastKeyPressTime.get(event.key); if (lastTime === null) { lastTime = 0; } const currentTime = Date.now(); let doubleClick = false; if (currentTime - lastTime <= doubleClickInterval) { doubleClick = true; } else { doubleClick = false; } lastKeyPressTime.set(event.key, Date.now()); return doubleClick; } function getNextPlaybackRate(key) { let rateArray = RATE_ARRAYS[key]; let rate = getLocalPlaybackRate(); for (let i = 0; i < rateArray.length; i++) { if (rate < rateArray[i]) { return rateArray [i] } } return rateArray[0]; } function getLastPlaybackRate(key) { let rateArray = RATE_ARRAYS[key]; let rate = getLocalPlaybackRate(); for (let i = rateArray.length - 1; i >= 0; i--) { if (rate > rateArray[i]) { return rateArray [i] } } return rateArray[rateArray.length - 1]; } /** * * @returns {number} localStorage中存储的倍速 */ function getLocalPlaybackRate() { let item = localStorage.getItem(LOCALSTORAGE_PLAYBACK_RATE_KEY); let playbackRate; try { playbackRate = parseFloat(item); } catch (err) { playbackRate = 1; } return playbackRate; } /** * 向localStorage中存储倍速 * @param playbackRate 倍速 */ function setLocalPlaybackRate(playbackRate) { localStorage.setItem(LOCALSTORAGE_PLAYBACK_RATE_KEY, playbackRate); } function log(...args) { if (DEBUG) { console.log(DEBUG_PREFIX, ...args); } } /** * 获得该页面下video的div * @returns {any[]} */ function getVideoDivs() { let videos = document.querySelectorAll("video"); let r###lt = []; for (let i = 0; i < videos.length; i++) { let thisVideo = videos[i]; if (thisVideo.style.display == null || thisVideo.style.display === "") { r###lt.push(thisVideo); } } return r###lt; } function findVideo() { let videoDivs = getVideoDivs(); if (videoDivs.length === 0) { return { parent: null, video: document.body } } else { let targetVideo; for (let video of videoDivs) { if (video === document.activeElement) { targetVideo = video; break; } } if (location.hostname === "www.douyin.com") { targetVideo = videoDivs.length === 3 ? videoDivs[1] : videoDivs[0]; } else { targetVideo = videoDivs[0]; } return { parent: targetVideo.parentElement, video: targetVideo }; } } /** * * @returns {{showDiv: Element, textDiv: Element, video:Element, innerDiv:Element}} 调整倍速后,展示倍速,获得相关div */ function findSuitShowInfo() { let videoInfo = findVideo(); let parent = videoInfo.parent; let insertDiv = parent.querySelector("#" + SHOW_DIV_ID); if (insertDiv == null) { parent.insertAdjacentHTML("beforeend", HTML); } return { showDiv: parent.querySelector("#" + SHOW_DIV_ID), innerDiv: parent.querySelector("#" + INNER_DIV_ID), video: videoInfo.video } } /** * * @param configuration 配置信息,showText:展示内容,dismissTime消失时间 */ function showPlaybackRateNew(configuration) { let info = findSuitShowInfo(); if (info != null) { info.showDiv.style.display = 'block'; if (configuration.key === 's') { info.innerDiv.innerHTML = `<p style="font-size:30px;color:black;font-weight: bold;text-align: center">${configuration.showText}</p> <p style="font-size:30px;color:black;font-weight: bold;text-align: center">${getVideoCustomerInfo(info.video)}</p>`; } else if (configuration.key === DETAIL_KEY) { info.innerDiv.innerHTML = `<p style="font-size:30px;color:black;font-weight: bold;text-align: center">${configuration.showText}</p> <p style="font-size:30px;color:black;font-weight: bold;text-align: center">${getVideoCustomerInfo(info.video)}</p> <p style="font-size:30px;color:black;font-weight: bold;text-align: center">${speedPrint()}</p> <p style="font-size:30px;color:black;font-weight: bold;text-align: center">${DETAIL_KEY}:详细信息</p>`; } else { info.innerDiv.innerHTML = `<p style="font-size:30px;color:black;font-weight: bold;text-align: center">${configuration.showText}</p> <p style="font-size:30px;color:black;font-weight: bold;text-align: center">${getKeyArrayPrint(configuration)}</p>`; } SLEEP(configuration.dismissTime).then(function () { info.showDiv.style.display = 'none'; }); } else { log("无法展示倍速"); } } function getKeyArrayPrint(configuration) { if (RATE_ARRAYS[configuration.key] != null) { return RATE_ARRAYS[configuration.key].map(n => n === getLocalPlaybackRate() ? `<span style="color: red;">${n}</span>` : n).join(" "); } return ``; } function getVideoCustomerInfo(video) { return "分辨率:" + video.videoWidth + "x" + video.videoHeight; } function speedPrint() { let r###lt = []; for (let key in RATE_ARRAYS) { let concat; concat = key + "键:" + RATE_ARRAYS[key].map(n => n === getLocalPlaybackRate() ? `<span style="color: red;">${n}</span>` : n).join(" "); r###lt.push(concat); } return r###lt.join("<br>"); } let SLEEP = (time) => new Promise((resolve) => { if (time == null || time === 0) { resolve(); } else { setTimeout(resolve, time); } });