Overlay of buttons to skip back and forward through videos, and control playback speed.
当前为
// ==UserScript==
// @name Video Playback Controller
// @namespace http://tampermonkey.net/
// @version 2025-09-16
// @description Overlay of buttons to skip back and forward through videos, and control playback speed.
// @author You
// @match *://*/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=google.com
// @grant GM_addStyle
// @run-at document-idle
// ==/UserScript==
(function() {
'use strict';
GM_addStyle(`
.allExtensionDiv {
position: absolute !important;
top: 5px !important;
left: 0% !important;
display: flex !important;
flex-direction: column !important;
gap: 8px !important;
z-index: 9999 !important;
width: 35px !important;
}
.optionDiv {
top: 10% !important;
left: 0% !important;
gap: 8px !important;
z-index: 9999 !important;
}
.buttonDiv {
top: 10% !important;
left: 0% !important;
display: flex !important;
flex-direction: column !important;
gap: 8px !important;
z-index: 99999 !important;
}
.allExtensionDiv button {
pointer-events: auto !important;
padding: 5px !important;
width: 27px !important;
font-size: 12px !important;
border: none !important;
border-radius: 4px !important;
background: grey !important;
color: rgb(255, 255, 255) !important;
cursor: pointer !important;
opacity: 0.5 !important;
}
`)
let allExtensionDiv;
let optionDiv;
let buttonDiv;
function waitForVideo() {
return new Promise(resolve => {
const interval = setInterval(() => {
const video = document.querySelector("video");
if (video) {
clearInterval(interval);
resolve(video);
}
}, 100);
});
}
(async function() {
'use strict';
const video = await waitForVideo();
if (!video) return;
console.log("Stable video element:", video);
// your existing code here, using `video`
// create divs
if (allExtensionDiv) return; // don’t duplicate
allExtensionDiv = document.createElement("div")
allExtensionDiv.className = "allExtensionDiv"
// allExtensionDiv.style.display = allExtensionDiv.style.display === "none !important;" ? "flex !important;" : "none !important;";
// allExtensionDiv.style.display = allExtensionDiv.style.display === allExtensionDiv.style.setProperty('display', isHidden) ? ""
optionDiv = document.createElement("div");
optionDiv.className = "optionDiv";
buttonDiv = document.createElement("div");
buttonDiv.className = "buttonDiv";
// console.log(1.1, video);
// create all buttons
// option button
const optionsBtn = document.createElement("button");
optionsBtn.innerText = "⚙";
optionsBtn.onclick = (e) => {
let isHidden = (buttonDiv.style.display === 'none');
buttonDiv.style.setProperty("display", isHidden ? "flex" : "none", "important")
//buttonDiv.style.display === "flex !important;" ?
// (buttonDiv.style.display = "none !important;") :
// (buttonDiv.style.display = "flex !important;");
e.stopPropagation(); // Prevent triggering parent click events
e.preventDefault();
};
// skip back buttons
const smallSkipBackBtn = document.createElement("button");
smallSkipBackBtn.innerText = "-5";
smallSkipBackBtn.onclick = (e) => {
video.currentTime -= 5;
e.stopPropagation(); // Prevent triggering parent click events
e.preventDefault();
};
const bigSkipBackBtn = document.createElement("button");
bigSkipBackBtn.innerText = "-30";
bigSkipBackBtn.onclick = (e) => {
video.currentTime -= 30;
e.stopPropagation(); // Prevent triggering parent click events
e.preventDefault();
};
// console.log(1.2, video)
// skip forward buttons
const smallSkipForwardBtn = document.createElement("button");
smallSkipForwardBtn.innerText = "+5";
smallSkipForwardBtn.onclick = (e) => {
video.currentTime += 5;
e.stopPropagation(); // Prevent triggering parent click events
e.preventDefault();
};
const bigSkipForwardBtn = document.createElement("button");
bigSkipForwardBtn.innerText = "+30";
bigSkipForwardBtn.onclick = (e) => {
video.currentTime += 30;
e.stopPropagation(); // Prevent triggering parent click events
e.preventDefault();
};
// speed multiplier buttons
const smallSpeedMultBtn = document.createElement("button");
smallSpeedMultBtn.innerText = "x2";
smallSpeedMultBtn.onclick = (e) => {
e.stopPropagation(); // Prevent triggering parent click events
e.preventDefault();
};
smallSpeedMultBtn.addEventListener("mousedown", (e) => {
video.playbackRate = 2;
e.stopPropagation(); // Prevent triggering parent click events
e.preventDefault();
});
smallSpeedMultBtn.addEventListener("mouseup", (e) => {
video.playbackRate = 1;
e.stopPropagation(); // Prevent triggering parent click events
e.preventDefault();
});
// console.log(1.3, video)
const bigSpeedMultBtn = document.createElement("button");
bigSpeedMultBtn.innerText = "x3";
bigSpeedMultBtn.onclick = (e) => {
e.stopPropagation(); // Prevent triggering parent click events
e.preventDefault();
};
bigSpeedMultBtn.addEventListener("mousedown", (e) => {
video.playbackRate = 3;
e.stopPropagation(); // Prevent triggering parent click events
e.preventDefault();
});
bigSpeedMultBtn.addEventListener("mouseup", (e) => {
video.playbackRate = 1;
e.stopPropagation(); // Prevent triggering parent click events
e.preventDefault();
});
// handle double clicks
const allDivs = document.querySelectorAll("div");
allDivs.forEach(div => {
div.addEventListener('dblclick', (e) => {
console.log('Div was double-clicked!');
e.stopPropagation(); // Prevent triggering parent click events
e.preventDefault();
});
})
// console.log(1.4, video)
// setup inside of divs
optionDiv.appendChild(optionsBtn);
buttonDiv.appendChild(smallSkipBackBtn);
buttonDiv.appendChild(bigSkipBackBtn);
buttonDiv.appendChild(smallSkipForwardBtn);
buttonDiv.appendChild(bigSkipForwardBtn);
buttonDiv.appendChild(smallSpeedMultBtn);
buttonDiv.appendChild(bigSpeedMultBtn);
allExtensionDiv.appendChild(optionDiv);
allExtensionDiv.appendChild(buttonDiv);
console.log(2, video)
// Position buttonDiv over video
video.parentElement.style.position = "relative";
video.parentElement.appendChild(allExtensionDiv);
// Start hidden
allExtensionDiv.style.display = "none";
})();
})();