Stick YouTube Progress Bar

Stick YouTube video progress bar to the player bottom

As of 2023-05-15. See the latest version.

// ==UserScript==
// @name          Stick YouTube Progress Bar
// @version       1.0.1
// @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==

const NAME = 'Stick YouTube Progress Bar'

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

  const observer = new MutationObserver(_ => {
    const progress_bar = document.querySelector('.ytp-play-progress')
    const loaded_progress_bar = document.querySelector('.ytp-load-progress')
    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(progress_bar, loaded_progress_bar)

    observer.disconnect()

    console.log(`[${NAME}] loaded`)
  })
  observer.observe(document.body, { childList: true, subtree: true })

}

function stick_progress_bar(progress_bar, loaded_progress_bar) {
  // 透過 css 讓進度條常駐在影片底部不會被隱藏起來
  inject_custom_style(`
    .ytp-autohide .ytp-chrome-bottom {
      opacity: initial !important;
    }

    .ytp-autohide .ytp-chrome-controls {
      opacity: 0 !important;
    }

    .ytp-autohide .ytp-progress-bar-container {
      bottom: 0 !important;
    }
  `)

  // 當播放器被標註自動隱藏的時候 YouTube 會停止更新進度條
  // 所以我們需要自己做一個 event 去更新它
  const movie_player = document.querySelector('#movie_player')
  const video = document.querySelector('video')
  video.addEventListener('timeupdate', () => {
    // 只有在自動隱藏的時候才去更新進度條,不然怕會跟原本的 event 衝突到
    if (!movie_player.classList.contains('ytp-autohide')) return

    const progress = video.currentTime / video.duration
    progress_bar.style.transform = `scaleX(${progress})`

    // 載入進度條沒有就算了,播放進度條比較重要
    if (!loaded_progress_bar) return
    const loaded_progress = video.buffered.end(0) / video.duration
    loaded_progress_bar.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()