Youtube - Resumer

Store video.currentTime locally

目前为 2022-11-27 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Youtube - Resumer
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.5
  5. // @description Store video.currentTime locally
  6. // @author You
  7. // @match https://www.youtube.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
  9. // @grant GM.setValue
  10. // @grant GM.getValue
  11. // @grant GM_addStyle
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15.  
  16. function l(...args){
  17. console.log('[Resumer]', ...args)
  18. }
  19.  
  20. function videoId(url=document.URL){
  21. return new URL(url).searchParams.get('v')
  22. }
  23.  
  24. function save(video, id){
  25. let completion = video.currentTime / video.duration
  26. GM.setValue(id, video.currentTime)
  27. GM.setValue(id + '-completion', completion)
  28. }
  29.  
  30. function listen(){
  31. let video = document.querySelector('video')
  32.  
  33. video.addEventListener('timeupdate', () => {
  34. //Video source is '' and duration is NaN when going back to the home page
  35. //When loading a new video, the event is fired with currentTime 0 and duration NaN
  36. if(video.src && !isNaN(video.duration)){
  37. let id = videoId() //if you use the miniplayer the url no longer includes the video id
  38. if(id){
  39. save(video, id)
  40. }
  41. }
  42. })
  43. }
  44.  
  45. async function resume(){
  46. let video = document.querySelector('video')
  47. let lastTime = await GM.getValue(videoId())
  48. if(lastTime){
  49. l('resuming', video.currentTime, lastTime)
  50. video.currentTime = lastTime
  51. }
  52. }
  53.  
  54. function cleanUrl(){
  55. //Remove t paramater when opening a video that had a progress bar
  56. let url = new URL(document.URL)
  57. url.searchParams.delete('t')
  58. window.history.replaceState(null, null, url)
  59. }
  60.  
  61. function addProgressBar(overlays, width){
  62. let parent = document.createElement('div')
  63. parent.innerHTML = '<ytd-thumbnail-overlay-resume-playback-renderer class="style-scope ytd-thumbnail"><!--css-build:shady--><div id="progress" class="style-scope ytd-thumbnail-overlay-resume-playback-renderer"></div></ytd-thumbnail-overlay-resume-playback-renderer>'
  64. overlays.appendChild(parent.firstChild)
  65. let progress = overlays.querySelector('#progress')
  66. styleProgressBar(progress, width)
  67. }
  68.  
  69. function styleProgressBar(progress, width){
  70. progress.style.width = `${width}%`
  71. progress.style.backgroundColor = 'blue'
  72. }
  73.  
  74. function progressBars(){
  75. let related = document.querySelector('#related')
  76. //Add progress bars in the related section
  77. const observer = new MutationObserver(async (mutationsList, observer) => {
  78. for(let mutation of mutationsList){
  79. if(mutation.target.id === 'overlays'){
  80. let href = mutation.target.parentElement.parentElement.parentElement.parentElement.querySelector('a').href
  81. let id = videoId(href)
  82. let completion = await GM.getValue(id + '-completion')
  83. if(completion){
  84. let width = parseInt(completion * 100)
  85. let progress = mutation.target.querySelector('#progress')
  86. if(progress){
  87. styleProgressBar(progress, width)
  88. }else{
  89. addProgressBar(mutation.target, width)
  90. }
  91. }
  92. }
  93. }
  94. })
  95. observer.observe(related, {childList:true, subtree:true})
  96. }
  97.  
  98. let listening = false //the video element exists even if you go back to the home page, so no need to readd event listeners
  99. let lastId //don't resume if going back to same page from miniplayer
  100.  
  101. //Event for each page change
  102. document.addEventListener("yt-navigate-finish", async () => {
  103. l('navigate-finish', videoId())
  104. //video page
  105. if(lastId !== videoId()) {
  106. lastId = videoId()
  107. cleanUrl()
  108. resume()
  109. //Add listeners once
  110. if(!listening){
  111. l('listening')
  112. listen()
  113. progressBars()
  114. listening = true
  115. }
  116. }
  117. })