YouTube - Remaining time

在视频时长旁边显示YouTube视频的剩余时长,考虑播放速度。

当前为 2024-03-15 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name YouTube - Remaining time
  3. // @namespace https://gist.github.com/4lrick/cf14cf267684f06c1b7bc559ddf2b943
  4. // @version 1.5
  5. // @description Displays the remaining duration of a YouTube video next to the video duration, taking into account the playback rate.
  6. // @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.
  7. // @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.
  8. // @description:de Zeigt die verbleibende Dauer eines YouTube-Videos neben der Videodauer an und berücksichtigt dabei die Wiedergabegeschwindigkeit.
  9. // @description:it Mostra la durata rimanente di un video di YouTube accanto alla durata del video, tenendo conto della velocità di riproduzione.
  10. // @description:zh-CN 在视频时长旁边显示YouTube视频的剩余时长,考虑播放速度。
  11. // @author 4lrick
  12. // @match https://www.youtube.com/*
  13. // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
  14. // @grant none
  15. // @license GPL-3.0-only
  16. // ==/UserScript==
  17.  
  18. (function() {
  19. 'use strict';
  20. let init = false;
  21. let timeDisplay;
  22.  
  23. function displayRemainingTime() {
  24. const videoElement = document.querySelector('video');
  25.  
  26. if (videoElement) {
  27. const timeRemaining = (videoElement.duration - videoElement.currentTime) / videoElement.playbackRate;
  28. const hours = Math.floor(timeRemaining / 3600);
  29. const minutes = Math.floor((timeRemaining % 3600) / 60);
  30. const seconds = Math.floor(timeRemaining % 60);
  31. const isLive = document.querySelector('.ytp-live');
  32. const viewLiveCount = document.querySelector('span[dir="auto"].bold.style-scope.yt-formatted-string');
  33. const isEmbed = window.location.href;
  34.  
  35. if ((viewLiveCount !== null && viewLiveCount.textContent.trim() !== "watching now") || isEmbed.includes("youtube.com/embed") && !isLive) {
  36. timeDisplay.textContent = `(${hours > 0 ? `${hours}:` : ''}${minutes < 10 ? '0' : ''}${minutes}:${seconds < 10 ? '0' : ''}${seconds})`;
  37. } else {
  38. timeDisplay.textContent = null;
  39. }
  40. }
  41. }
  42.  
  43. function initDisplay() {
  44. timeDisplay = document.createElement('div');
  45. timeDisplay.style.display = 'inline-block';
  46. timeDisplay.style.marginLeft = '10px';
  47. timeDisplay.style.color = '#ddd';
  48.  
  49. const timeContainer = document.querySelector('.ytp-time-display');
  50.  
  51. if (timeContainer) {
  52. timeContainer.appendChild(timeDisplay);
  53. init = true;
  54. }
  55.  
  56. }
  57.  
  58. function checkVideoExists() {
  59. const videoElement = document.querySelector('video');
  60.  
  61. if (videoElement) {
  62. if (!init) {
  63. initDisplay();
  64. }
  65.  
  66. if (init) {
  67. videoElement.addEventListener('timeupdate', displayRemainingTime);
  68. }
  69. }
  70. }
  71.  
  72. const observer = new MutationObserver(checkVideoExists);
  73. const body = document.body;
  74. const config = { childList: true, subtree: true };
  75. observer.observe(body, config);
  76. })();