您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Displays the remaining duration of a YouTube video next to the video duration, taking into account the playback rate.
当前为
- // ==UserScript==
- // @name YouTube - Remaining time
- // @namespace https://gist.github.com/4lrick/cf14cf267684f06c1b7bc559ddf2b943
- // @version 1.1
- // @description Displays the remaining duration of a YouTube video next to the video duration, taking into account the playback rate.
- // @description:fr Affiche la durée restante d'une vidéo YouTube à côté de la durée de la vidéo, en tenant compte de la vitesse de lecture.
- // @description:es Muestra la duración restante de un video de YouTube junto a la duración del video, teniendo en cuenta la velocidad de reproducción.
- // @description:de Zeigt die verbleibende Dauer eines YouTube-Videos neben der Videodauer an und berücksichtigt dabei die Wiedergabegeschwindigkeit.
- // @description:it Mostra la durata rimanente di un video di YouTube accanto alla durata del video, tenendo conto della velocità di riproduzione.
- // @description:zh 在视频时长旁边显示YouTube视频的剩余时长,考虑播放速度。
- // @author 4lrick
- // @match https://www.youtube.com/*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
- // @grant none
- // @license GPL-3.0-only
- // ==/UserScript==
- (() => {
- 'use strict';
- let timeDisplay;
- let videoIsInit = false;
- let activeVideoElement = null;
- let activeVideoInterval = null;
- const checkAndMonitorVideoPage = () => {
- const newVideoPageActive = window.location.href.startsWith('https://www.youtube.com/watch');
- if (newVideoPageActive && !videoIsInit) {
- initializeTimeDisplay();
- videoIsInit = true;
- }
- };
- const initializeTimeDisplay = () => {
- timeDisplay = document.createElement('div');
- timeDisplay.style.display = 'inline-block';
- timeDisplay.style.marginLeft = '10px';
- timeDisplay.style.color = '#ddd';
- const timeDuration = document.querySelector('.ytp-time-duration');
- const timeContainer = document.querySelector('.ytp-time-display');
- const appContainer = document.querySelector('ytd-app');
- if (timeDuration && timeContainer) {
- timeContainer.appendChild(timeDisplay);
- }
- setupMutationObserver(appContainer);
- };
- const setupMutationObserver = (appContainer) => {
- const observer = new MutationObserver((mutationsList, observer) => {
- updateActiveVideo();
- });
- observer.observe(appContainer, { subtree: true, childList: true });
- };
- const updateActiveVideo = () => {
- const isMiniplayerActive = document.querySelector('ytd-app').hasAttribute('miniplayer-is-active');
- const videoElement = document.querySelector('video');
- if (!isMiniplayerActive && videoElement) {
- if (activeVideoInterval) {
- clearInterval(activeVideoInterval);
- }
- activeVideoElement = videoElement;
- updateVideoTime();
- activeVideoInterval = setInterval(updateVideoTime, 1000);
- } else {
- clearInterval(activeVideoInterval);
- activeVideoElement = null;
- timeDisplay.textContent = '';
- }
- };
- const updateVideoTime = () => {
- const { currentTime, duration, playbackRate } = activeVideoElement;
- const timeRemaining = (duration - currentTime) / playbackRate;
- const hoursRemaining = Math.floor(timeRemaining / 3600);
- const minutesRemaining = Math.floor((timeRemaining % 3600) / 60);
- const secondsRemaining = Math.floor(timeRemaining % 60);
- let formattedTimeRemaining = '';
- if (hoursRemaining > 0) {
- formattedTimeRemaining += hoursRemaining.toString() + ':';
- }
- formattedTimeRemaining += minutesRemaining.toString().padStart(2, '0') + ':' + secondsRemaining.toString().padStart(2, '0');
- timeDisplay.textContent = '(' + formattedTimeRemaining + ')';
- };
- const checkVideoPageActiveInterval = () => {
- checkAndMonitorVideoPage();
- window.requestAnimationFrame(checkVideoPageActiveInterval);
- };
- checkVideoPageActiveInterval();
- })();