您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
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 } } })