您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Fixes youtube video repeating when watching in playlist + refreshing page if video stopped downloading
当前为
- // ==UserScript==
- // @name Loop Fix
- // @description Fixes youtube video repeating when watching in playlist + refreshing page if video stopped downloading
- // @version 0.1.13
- // @author 0vC4
- // @namespace https://greasyfork.org/users/670183
- // @match *://*.youtube.com/*
- // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
- // @run-at document-start
- // @license MIT
- // @grant none
- // ==/UserScript==
- // refresh if no reply during these actions
- const maxLoadingTime = 500;
- const maxSeekingTime = 1500;
- (() => {
- function blockEvents(condition, ...events) {
- events = events.flat();
- const tag = window.EventTarget.prototype;
- tag._add = tag.addEventListener;
- tag.addEventListener = function (name, callback, options) {
- if (!events.includes(name)) return tag._add.call(this, name, callback, options);
- function cb(e) {
- if (!condition.call(this)) return;
- callback.call(this, e);
- };
- tag._add.call(this, name, cb, options);
- };
- }
- blockEvents(function() {
- return !this.loop; // have loop = block events
- }, 'pause', 'timeupdate', 'waiting');
- })();
- const log = window.console.log;
- window.loopState = localStorage.getItem('loopState') ?? false;
- function clicking(e) {
- window.loopState = JSON.parse(this.ariaChecked);
- };
- let created = false;
- let refreshing = false;
- let loaded = false;
- let oldVid = null;
- let seeking = false;
- let seekingId = 0;
- const maxSeekingDebounce = 500;
- const policy = window.trustedTypes && window.trustedTypes.createPolicy ? window.trustedTypes.createPolicy('timeout', {createScriptURL: str => str}) : {createScriptURL: str => str};
- const timeout = delay => URL.createObjectURL(new Blob([`setTimeout(() => postMessage(0), ${delay});`]));
- const refreshOnLoad = policy.createScriptURL(timeout(maxLoadingTime));
- const seekingDebounce = policy.createScriptURL(timeout(maxSeekingDebounce));
- if (document.readyState === "complete") {
- window.setInterval(()=>{
- const vid = window.document.querySelector('video.html5-main-video');
- if (vid) {
- // to prevent false detecting when changing video
- if (vid != oldVid) {
- loaded = false;
- oldVid = vid;
- }
- if (!created) {
- created = true;
- localStorage.removeItem('loopState');
- vid.addEventListener('seeking', () => {
- clearTimeout(seekingId);
- seeking = true;
- console.log('seeking true!');
- seekingId = setTimeout(() => {
- seeking = false;
- }, maxSeekingTime);
- });
- // refresh if no data for half sec
- const callback = () => {
- if (!loaded && vid.readyState === window.HTMLMediaElement.HAVE_NOTHING) {
- localStorage.setItem('loopState', window.loopState);
- window.location.href = window.location.href;
- }
- };
- new Worker(refreshOnLoad).onmessage = callback;
- }
- // apply loopState after .src or page refresh
- if (vid.loop != window.loopState) vid.loop = window.loopState;
- // to prevent early page refresh
- if (vid.readyState === window.HTMLMediaElement.HAVE_CURRENT_DATA || vid.readyState === window.HTMLMediaElement.HAVE_ENOUGH_DATA) loaded = true;
- const noData = vid.readyState === window.HTMLMediaElement.HAVE_CURRENT_DATA || vid.readyState === window.HTMLMediaElement.HAVE_METADATA;
- if (loaded && !refreshing && noData && !seeking && !vid.paused && +vid.currentTime.toFixed(0) >= +vid.buffered.end(0).toFixed(0) - 2) {
- refreshing = true;
- const callback = () => {
- if (seeking) {
- refreshing = false;
- return;
- }
- localStorage.setItem('loopState', window.loopState);
- window.location.href = window.location.href.split('?')[0] + '?t=' + (+vid.currentTime.toFixed(0) + 1) + '&' + window.location.href.split('?')[1];
- };
- new Worker(seekingDebounce).onmessage = callback;
- }
- }
- // attach loop click detector
- const repeat = window.document.querySelectorAll('.ytp-menuitem[tabindex="-1"]')[0];
- if (repeat && repeat.onclick != clicking) {
- repeat.onclick = clicking
- }
- });
- }