您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Left-aligned progress indicators with fixed thumbnail height
当前为
// ==UserScript== // @name YouTube Universal Progress Tracker // @namespace http://tampermonkey.net/ // @version 3.2 // @description Left-aligned progress indicators with fixed thumbnail height // @author ikigaiDH // @match https://www.youtube.com/* // @grant none // @license GPL-3.0-only // ==/UserScript== (function() { 'use strict'; const STORAGE_KEY = 'yt_watch_history'; let watchHistory = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}'); // Universal video ID extractor const getVideoId = (element) => { try { const link = element.closest('a') || element.querySelector('a'); if (!link) return null; const url = new URL(link.href); return url.searchParams.get('v') || url.pathname.split('/watch/')[1]?.split('?')[0] || url.pathname.split('/')[2]; } catch { return null; } }; // Progress indicator creation const createIndicator = () => { const indicator = document.createElement('div'); Object.assign(indicator.style, { position: 'absolute', bottom: '4px', left: '4px', backgroundColor: '#cc0000', color: 'white', padding: '2px 6px', borderRadius: '2px', fontSize: '12px', fontWeight: 'bold', zIndex: '1000', fontFamily: 'Roboto, Arial, sans-serif', textTransform: 'uppercase' }); indicator.className = 'yt-progress-indicator'; return indicator; }; // Main update function const updateAllThumbnails = () => { // First, clean up any existing indicators to prevent duplicates document.querySelectorAll('.yt-progress-indicator').forEach(ind => ind.remove()); // Process all thumbnails document.querySelectorAll('ytd-thumbnail').forEach(thumbnail => { // Skip thumbnails that don't have proper structure if (!thumbnail.querySelector('#thumbnail')) return; const videoId = getVideoId(thumbnail); if (!videoId) return; const percentage = watchHistory[videoId] || 0; if (percentage > 0) { // Create new indicator const indicator = createIndicator(); indicator.textContent = percentage >= 100 ? '>100%' : `${Math.round(percentage)}%`; // Find the correct container for the indicator const overlays = thumbnail.querySelector('#overlays'); if (overlays) { overlays.appendChild(indicator); } else { const img = thumbnail.querySelector('#img'); if (img) { if (!img.style.position) { img.style.position = 'relative'; } img.appendChild(indicator); } } } }); }; // Video tracking with debouncing let currentVideoId = null; const trackVideo = () => { const video = document.querySelector('video'); if (!video) return; const newVideoId = new URLSearchParams(window.location.search).get('v'); if (newVideoId === currentVideoId) return; currentVideoId = newVideoId; const saveProgress = () => { if (video.duration > 0) { const percentage = (video.currentTime / video.duration) * 100; if (percentage > (watchHistory[currentVideoId] || 0)) { watchHistory[currentVideoId] = percentage; localStorage.setItem(STORAGE_KEY, JSON.stringify(watchHistory)); updateAllThumbnails(); } } }; video.addEventListener('timeupdate', saveProgress); }; // Enhanced observation with debouncing let updateTimeout = null; const observer = new MutationObserver(() => { if (updateTimeout) { clearTimeout(updateTimeout); } updateTimeout = setTimeout(() => { updateAllThumbnails(); trackVideo(); }, 100); }); // Initialization window.addEventListener('load', () => { observer.observe(document.body, { childList: true, subtree: true, attributes: false }); updateAllThumbnails(); trackVideo(); }); // Handle YouTube navigation document.addEventListener('yt-navigate-finish', updateAllThumbnails); document.addEventListener('yt-page-data-updated', updateAllThumbnails); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址