Store video.currentTime locally
当前为
// ==UserScript==
// @name Youtube - Resumer
// @namespace http://tampermonkey.net/
// @version 0.6
// @description Store video.currentTime locally
// @author You
// @match https://www.youtube.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @grant GM.setValue
// @grant GM.getValue
// @grant GM_addStyle
// @license MIT
// ==/UserScript==
function l(...args){
console.log('[Resumer]', ...args)
}
function videoId(url=document.URL){
return new URL(url).searchParams.get('v')
}
function save(video, id){
let completion = video.currentTime / video.duration
GM.setValue(id, video.currentTime)
GM.setValue(id + '-completion', completion)
}
function listen(){
let video = document.querySelector('video')
video.addEventListener('timeupdate', () => {
//Video source is '' and duration is NaN when going back to the home page
//When loading a new video, the event is fired with currentTime 0 and duration NaN
if(video.src && !isNaN(video.duration)){
let id = videoId() //if you use the miniplayer the url no longer includes the video id
if(id){
save(video, id)
}
}
})
}
async function resume(){
let video = document.querySelector('video')
let lastTime = await GM.getValue(videoId())
if(lastTime){
l('resuming', video.currentTime, lastTime)
video.currentTime = lastTime
}
}
function cleanUrl(){
//Remove t paramater when opening a video that had a progress bar
let url = new URL(document.URL)
url.searchParams.delete('t')
window.history.replaceState(null, null, url)
}
function addProgressBar(overlays, width){
let parent = document.createElement('div')
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>'
overlays.appendChild(parent.firstChild)
let progress = overlays.querySelector('#progress')
styleProgressBar(progress, width)
}
function styleProgressBar(progress, width){
progress.style.width = `${width}%`
progress.style.backgroundColor = 'blue'
}
function progressBars(){
let related = document.querySelector('#related')
//Add progress bars in the related section
const observer = new MutationObserver(async (mutationsList, observer) => {
for(let mutation of mutationsList){
if(mutation.target.id === 'overlays'){
let href = mutation.target.parentElement.parentElement.parentElement.parentElement.querySelector('a').href
let id = videoId(href)
let completion = await GM.getValue(id + '-completion')
if(completion){
let width = parseInt(completion * 100)
let progress = mutation.target.querySelector('#progress')
if(progress){
styleProgressBar(progress, width)
}else{
addProgressBar(mutation.target, width)
}
}
}
}
})
observer.observe(related, {childList:true, subtree:true})
}
let listening = false //the video element exists even if you go back to the home page, so no need to readd event listeners
let lastId //don't resume if going back to same page from miniplayer
//Event for each page change
document.addEventListener("yt-navigate-finish", async () => {
l('navigate-finish', lastId, videoId())
//video page
if(videoId() && lastId !== videoId()) {
lastId = videoId()
cleanUrl()
resume()
//Add listeners once
if(!listening){
l('listening')
listen()
progressBars()
listening = true
}
}
})
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址