Greasy Fork 还支持 简体中文。

Stick YouTube Progress Bar

Stick YouTube video progress bar to the player bottom

À partir de 2023-05-16. Voir la dernière version.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name          Stick YouTube Progress Bar
// @version       1.0.4
// @match         https://www.youtube.com/watch?v=**
// @match         https://www.youtube.com/live/**
// @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";

  function main() {
    console.log(`[${NAME}] initializing...`);

    const observer = new MutationObserver((_) => {
      // 沒什麼意義,只是拿來判斷 control bar 初始化完了沒
      const progress_bar = document.querySelector(".ytp-progress-list");
      if (!progress_bar) return;

      // 如果是直播的話就不用了
      const live_badge = document.querySelector(".ytp-live-badge");
      if (live_badge && !live_badge.getAttribute("disabled")) {
        observer.disconnect();
        console.log(`[${NAME}] cancaled in livestream`);
        return;
      }

      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;
        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.addEventListener("timeupdate", () => {
      // 只有在自動隱藏的時候才去更新進度條,不想浪費資源
      if (!movie_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})`;
    });
  }

  function inject_custom_style(css) {
    const style = document.createElement("style");
    document.head.append(style);
    style.dataset.source = NAME;
    style.innerHTML = css;
  }

  main();

})();