Youtube - Resumer

Store video.currentTime locally

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

  1. // ==UserScript==
  2. // @name Youtube - Resumer
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.1
  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 listen(){
  25. let video = document.querySelector('video')
  26.  
  27. video.addEventListener('timeupdate', () => {
  28. //Video source is '' and duration is NaN when going back to the home page
  29. //When loading a new video, the event is fired with currentTime 0 and duration NaN
  30. if(video.src && !isNaN(video.duration)){
  31. //save
  32. let completion = video.currentTime / video.duration
  33. l(video.currentTime, completion * video.duration, video.duration, currentVideoId)
  34. GM.setValue(currentVideoId, video.currentTime)
  35. GM.setValue(currentVideoId + '-completion', completion)
  36. }
  37. })
  38. }
  39.  
  40. async function resume(){
  41. let video = document.querySelector('video')
  42. let lastTime = await GM.getValue(currentVideoId)
  43. if(lastTime){
  44. l('resuming', video.currentTime, lastTime)
  45. video.currentTime = lastTime
  46. }
  47. }
  48.  
  49. function cleanUrl(){
  50. //Remove t paramater when opening a video that had a progress bar
  51. let url = new URL(document.URL)
  52. url.searchParams.delete('t')
  53. window.history.replaceState(null, null, url)
  54. }
  55.  
  56. function addProgressBar(overlays, width){
  57. let parent = document.createElement('div')
  58. 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>'
  59. overlays.appendChild(parent.firstChild)
  60. let progress = overlays.querySelector('#progress')
  61. styleProgressBar(progress, width)
  62. }
  63.  
  64. function styleProgressBar(progress, width){
  65. progress.style.width = `{width}%`
  66. progress.style.backgroundColor = 'blue'
  67. }
  68.  
  69. function progressBars(){
  70. let related = document.querySelector('#related')
  71. //Add progress bars in the related section
  72. const observer = new MutationObserver(async (mutationsList, observer) => {
  73. for(let mutation of mutationsList){
  74. if(mutation.target.id === 'overlays'){
  75. let href = mutation.target.parentElement.parentElement.parentElement.parentElement.querySelector('a').href
  76. let id = videoId(href)
  77. let completion = await GM.getValue(id + '-completion')
  78. let width = parseInt(completion)*100
  79. if(completion){
  80. let progress = mutation.target.querySelector('#progress')
  81. if(progress){
  82. styleProgressBar(progress, width)
  83. }else{
  84. addProgressBar(mutation.target, width)
  85. }
  86. }
  87. }
  88. }
  89. })
  90. observer.observe(related, {childList:true, subtree:true})
  91. }
  92.  
  93. let listening = false //the video element exists even if you go back to the home page, so no need to readd event listeners
  94. let currentVideoId //store video id in case you use the miniplayer and the url no longer includes the video id
  95.  
  96. //Event for each page change
  97. document.addEventListener("yt-navigate-finish", async () => {
  98. l('navigate-finish')
  99. //video page
  100. let id = videoId()
  101. if(id) {
  102. l('video', id)
  103. cleanUrl()
  104. currentVideoId = id
  105. resume()
  106. //Add listeners once
  107. if(!listening){
  108. l('listening')
  109. listen()
  110. progressBars()
  111. listening = true
  112. }
  113. }
  114. })