您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
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); })();