Keeps YouTube progress bar visible all the time.
当前为
// ==UserScript==
// @name YouTube Permanent ProgressBar
// @namespace http://tampermonkey.net/
// @version 0.3.4
// @description Keeps YouTube progress bar visible all the time.
// @author ChromiaCat
// @match *://www.youtube.com/*
// @license MIT
// ==/UserScript==
var style = document.createElement('style');
var to = { createHTML: s => s },
tp = window.trustedTypes?.createPolicy ? trustedTypes.createPolicy("", to) : to,
html = s => tp.createHTML(s);
style.type = 'text/css';
style.innerHTML = html('.ytp-autohide .ytp-chrome-bottom{opacity:1!important;display:block!important}.ytp-autohide .ytp-chrome-bottom .ytp-progress-bar-container{bottom:-1px!important}.ytp-autohide .ytp-chrome-bottom .ytp-chrome-controls{opacity:0!important}');
document.getElementsByTagName('head')[0].appendChild(style);
var permanentProgressBar = {
options: {
UPDATE_INTERVAL: 200, // Update interval in milliseconds.
PROGRESSBAR_OPACITY_WINDOW: 1, // Progress bar opacity in window mode.
PROGRESSBAR_OPACITY_FULLSCREEN: 0.5, // Progress bar opacity in fullscreen mode.
UPDATE_VIDEO_TIMER: true, // Update the video timer (current time display).
UPDATE_PROGRESSBAR: true, // Update the progress bar for played content.
UPDATE_BUFFERBAR: true, // Update the buffer bar for loaded content.
},
// Converts current video time to a pretty, human-readable format
prettifyVideoTime: function (video) {
let seconds = "" + Math.floor(video.currentTime % 60);
let minutes = "" + Math.floor((video.currentTime % 3600) / 60);
let hours = "" + Math.floor(video.currentTime / 3600);
if (video.currentTime / 60 > 60) {
return `${hours}:${minutes.padStart(2, '0')}:${seconds.padStart(2, '0')}`;
} else {
return `${minutes}:${seconds.padStart(2, '0')}`;
}
},
// Gets either the current time or the buffered end for the video
getDuration: function (video, type) {
if (type === "PROGRESSBAR") {
return video.currentTime; // Current time for the progress bar.
} else if (type === "BUFFERBAR") {
if (video.buffered.length > 0) {
// Find the buffered range relevant to the current time.
let bufferedEnd = 0;
for (let i = 0; i < video.buffered.length; i++) {
if (video.currentTime >= video.buffered.start(i) && video.currentTime <= video.buffered.end(i)) {
bufferedEnd = video.buffered.end(i);
break;
}
}
return bufferedEnd;
}
return 0; // No buffered data.
}
},
// works only on chapterless (old) videos
updateCurrentTimeField: function (player) {
const video = player.querySelector("video");
const currentTime = player.querySelector(".ytp-time-current");
if (!video || !currentTime) {
return;
}
currentTime.innerText = permanentProgressBar.prettifyVideoTime(video);
},
// Updates the progress bar (without chapters)
updateProgressBar: function (player) {
const video = player.querySelector("video");
const progressBar = player.querySelector(".ytp-play-progress");
const bufferBar = player.querySelector(".ytp-load-progress");
if (!video || !progressBar || !bufferBar) {
return;
}
// Set progress and buffer bars based on video playback and buffered time.
progressBar.style.transform = `scaleX(${video.currentTime / video.duration})`;
bufferBar.style.transform = `scaleX(${this.getDuration(video, "BUFFERBAR") / video.duration})`;
},
// Updates the progress and buffer bars for videos with chapters
updateProgressBarWithChapters: function (player, type) {
const video = player.querySelector("video");
if (video == null || isNaN(video.duration)) {
return;
}
// Get chapter progress bar elements
const progressBarWidthsCollection = player.getElementsByClassName("ytp-progress-bar-padding");
let progressBarChaptersCollection;
if (type === "PROGRESSBAR") {
progressBarChaptersCollection = player.getElementsByClassName("ytp-play-progress");
} else if (type === "BUFFERBAR") {
progressBarChaptersCollection = player.getElementsByClassName("ytp-load-progress");
}
// quit if elements do not exist
if (!progressBarWidthsCollection || !progressBarChaptersCollection) {
return;
}
// Compute the ratio of video duration to chapter progress bar width
let totalProgressBarWidth = 0;
for (let i = 0; i < progressBarWidthsCollection.length; i++) {
totalProgressBarWidth += progressBarWidthsCollection[i].offsetWidth;
}
const durationWidthRatio = video.duration / totalProgressBarWidth;
// loop inside chapters
let chaptersPixelWidthUntilCurrentChapter = 0;
for (let i = 0; i < progressBarWidthsCollection.length; i++) {
// Check if the buffered or played time exceeds the current chapter width
if (this.getDuration(video, type) > durationWidthRatio * (chaptersPixelWidthUntilCurrentChapter + progressBarWidthsCollection[i].offsetWidth)) {
progressBarChaptersCollection[i].style.transform = "scaleX(1)";
chaptersPixelWidthUntilCurrentChapter += progressBarWidthsCollection[i].offsetWidth; // increase the current chapters location by adding last watched chapter
// If not, it means that we are on this chapter.
// Find the appropriate size for the chapter and scale it
} else {
let currentTimeInChapter = this.getDuration(video, type) - (durationWidthRatio * chaptersPixelWidthUntilCurrentChapter); // current time
let currentChapterLength = durationWidthRatio * progressBarWidthsCollection[i].offsetWidth; // total chapter time
let currentChapterRatio = currentTimeInChapter / currentChapterLength;
progressBarChaptersCollection[i].style.transform = `scaleX(${currentChapterRatio})`;
break;
}
}
},
// Main update function called periodically
update: function () {
const player = document.querySelector(".html5-video-player"); // Get video element
if (player == null) {
return;
}
/* update css
if(document.fullscreenElement){
document.querySelector(".ytp-chrome-bottom").style.opacity = permanentProgressBar.options.PROGRESSBAR_OPACITY_FULLSCREEN;
}
else{
document.querySelector(".ytp-chrome-bottom").style.opacity = permanentProgressBar.options.PROGRESSBAR_OPACITY_WINDOW;
}
*/
if (this.options.UPDATE_VIDEO_TIMER) {
this.updateCurrentTimeField(player);
}
if (this.options.UPDATE_PROGRESSBAR) {
this.updateProgressBarWithChapters(player, "PROGRESSBAR");
}
if (this.options.UPDATE_BUFFERBAR) {
this.updateProgressBarWithChapters(player, "BUFFERBAR");
}
},
// Starts the periodic update process
start: function () {
setInterval(this.update.bind(this), this.options.UPDATE_INTERVAL);
}
};
permanentProgressBar.start();