您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Stick YouTube video progress bar to the player bottom
// ==UserScript== // @name Stick YouTube Progress Bar // @version 1.0.13 // @match https://www.youtube.com/** // @author peng-devs // @namespace https://gf.qytechs.cn/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 observer; let internal; function main() { if (observer || internal) { console.log(`[${NAME}] cleaning prev states`) observer?.disconnect(); clearInterval(internal); observer = undefined; internal = undefined; } if (!location.pathname.startsWith('/watch') && !location.pathname.startsWith('/live')) return; observer = observe(document.body, () => { if (!observer) return; // 判斷 youtube player 初始化完了沒 const intitailized = document.querySelector("video.video-stream"); if (!intitailized) return; // 如果是直播的話就跳過 const live_badge = document.querySelector(".ytp-live-badge"); if (live_badge && getComputedStyle(live_badge).display !== 'none') { // 直接砍掉,懶得再做一個 hide/show 判斷 document.getElementById('stick_progress')?.remove(); observer.disconnect(); console.log(`[${NAME}] cancaled in livestream`); return; } console.log(`[${NAME}] initializing...`); init_stick_progress_bar(); observer.disconnect(); console.log(`[${NAME}] loaded`); }); } function init_stick_progress_bar() { const { container, progress_bar, buffer_bar } = create_progress_bar(); const player = document.querySelector("#movie_player"); player.append(container); let video = document.querySelector("video.video-stream"); internal = setInterval(() => { if (!video.getAttribute('src')) { // youtube 有時候會抽風把頁面重新 re-render console.debug(`[${NAME}] detect page re-render, reset video`); video = document.querySelector("video.video-stream"); } const progress = video.currentTime / video.duration; progress_bar.style.transform = `scaleX(${progress})`; if (video.buffered.length > 0 && video.duration > 0) { const buffer_progress = video.buffered.end(0) / video.duration; buffer_bar.style.transform = `scaleX(${buffer_progress})`; } }, UPDATE_INTERVAL); } function create_progress_bar() { // 已經建好的可以重複利用 let container = document.getElementById('stick_progress'); if (container) { const progress_bar = container.querySelector('.stick_progress_bar'); const buffer_bar = container.querySelector('.stick_buffer_bar'); progress_bar.style.transform = `scaleX(0)`; buffer_bar.style.transform = `scaleX(0)`; return { container, progress_bar, buffer_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_progress_bar, .stick_buffer_bar { position: absolute; width: 100%; height: 100%; transform-origin: left; transform: scaleX(0); ${SMOOTH_ANIMATION ? `transition: all ${UPDATE_INTERVAL - 50}ms linear;` : ''} } .stick_buffer_bar { z-index: 33; background-color: rgba(255, 255, 255, .4); } .stick_progress_bar { z-index: 34; background-color: #f00; } .ytp-autohide #stick_progress { display: block; } `); container = document.createElement("div"); container.id = "stick_progress"; const progress_bar = document.createElement("div"); progress_bar.className = "stick_progress_bar"; container.append(progress_bar); const buffer_bar = document.createElement("div"); buffer_bar.className = "stick_buffer_bar"; container.append(buffer_bar); return { container, progress_bar, buffer_bar, }; } function inject_custom_style(css) { const style = document.createElement("style"); document.head.append(style); style.dataset.source = NAME; style.innerHTML = css; } function observe(dom, callback) { const observer = new MutationObserver(callback); observer.observe(document.body, { childList: true, subtree: true }); return observer; } document.addEventListener('yt-navigate-finish', main, true); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址