Stick YouTube video progress bar to the player bottom
目前為
// ==UserScript==
// @name Stick YouTube Progress Bar
// @version 1.0.8
// @match https://www.youtube.com/**
// @author peng-devs
// @namespace https://greasyfork.org/users/57176
// @description Stick YouTube video progress bar to the player bottom
// @icon https://www.youtube.com/s/desktop/c1d331ff/img/favicon_48x48.png
// @grant none
// @allFrames true
// @license MIT
// ==/UserScript==
(function() {
'use strict';
const NAME = "Stick YouTube Progress Bar";
const UPDATE_INTERVAL = 500;
const SMOOTH_ANIMATION = false;
let INTERVAL;
function main() {
if (!location.pathname.startsWith('/watch') &&
!location.pathname.startsWith('/live'))
return
if (INTERVAL) {
INTERVAL = undefined;
}
const observer = new MutationObserver((_) => {
const progress = document.getElementById('stick_progress');
// 如果是直播的話就不用了
const live_badge = document.querySelector(".ytp-live-badge");
if (live_badge && getComputedStyle(live_badge).display !== 'none') {
// TODO: 或許不用砍掉,可以直接用 css 的方式把它藏起來就好了?
progress?.remove();
observer.disconnect();
console.log(`[${NAME}] cancaled in livestream`);
return;
}
// 已經建好的可以重複利用
if (progress) return
// 判斷 youtube player 初始化完了沒
const intitailized = document.querySelector("video.video-stream");
if (!intitailized) return;
console.log(`[${NAME}] initializing...`);
INTERVAL = stick_progress_bar();
observer.disconnect();
console.log(`[${NAME}] loaded`);
});
observer.observe(document.body, { childList: true, subtree: true });
}
function stick_progress_bar() {
inject_custom_style(`
#stick_progress {
display: none;
z-index: 32;
position: absolute;
bottom: 4px;
width: 97.5%;
height: 4px;
margin: 0 1.25%;
background-color: rgba(255, 255, 255, .2);
}
.stick_play_progress, .stick_load_progress {
position: absolute;
width: 100%;
height: 100%;
}
.stick_play_progress, .stick_load_progress {
transform-origin: left;
${SMOOTH_ANIMATION ? `transition: all ${UPDATE_INTERVAL - 50}ms linear;` : ''}
transform: scaleX(0);
}
.stick_load_progress {
z-index: 33;
background-color: rgba(255, 255, 255, .4);
}
.stick_play_progress {
z-index: 34;
background-color: #f00;
}
.ytp-autohide #stick_progress {
display: block;
}
`);
const progress = document.createElement("div");
progress.id = "stick_progress";
const play_progress = document.createElement("div");
play_progress.className = "stick_play_progress";
progress.append(play_progress);
const load_progress = document.createElement("div");
load_progress.className = "stick_load_progress";
progress.append(load_progress);
const player = document.querySelector("#movie_player");
player.append(progress);
const video = document.querySelector("video.video-stream");
const interval = setInterval(() => {
// 只有在自動隱藏的時候才去更新進度條,不想浪費資源
if (!player.classList.contains("ytp-autohide")) return;
const progress = video.currentTime / video.duration;
play_progress.style.transform = `scaleX(${progress})`;
const loaded_progress = video.buffered.end(0) / video.duration;
load_progress.style.transform = `scaleX(${loaded_progress})`;
}, UPDATE_INTERVAL);
return interval;
}
function inject_custom_style(css) {
const style = document.createElement("style");
document.head.append(style);
style.dataset.source = NAME;
style.innerHTML = css;
}
main();
document.addEventListener('yt-navigate-finish', main, true);
})();