您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在播放器控制栏中添加一个开启list逆序播放功能开关
// ==UserScript== // @name YouTube List 逆序播放 // @namespace https://example.com/yt-reverse-autoplay // @version 2.7 // @description 在播放器控制栏中添加一个开启list逆序播放功能开关 // @match https://www.youtube.com/* // @run-at document-idle // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; const sleep = (ms) => new Promise(r => setTimeout(r, ms)); const qs = (sel, root = document) => root.querySelector(sel); const qsa = (sel, root = document) => Array.from(root.querySelectorAll(sel)); const log = (...a) => console.log('[YT-Rev]', ...a); let enabled = false; let guardTimer = null; let stateListenerSet = false; const BTN_ID = 'yt-rev-autoplay-toggle-in-controls'; const CONTROLS_SEL = '#movie_player > div.ytp-chrome-bottom > div.ytp-chrome-controls'; const hasPlaylist = () => { try { const u = new URL(location.href); if (u.searchParams.get('list')) return true; } catch {} return !!document.querySelector('ytd-playlist-panel-renderer'); }; const player = () => document.getElementById('movie_player'); const goPrevPlay = () => { const p = player(); if (!p || typeof p.previousVideo !== 'function') return false; p.previousVideo(); setTimeout(() => p.playVideo && p.playVideo(), 50); return true; }; const ensureShuffleOff = () => { const shuffleBtn = document.querySelector( 'ytd-toggle-button-renderer[button-renderer] button[aria-pressed]' ); if (enabled && shuffleBtn && shuffleBtn.getAttribute('aria-pressed') === 'true') { shuffleBtn.click(); log('shuffle off'); } }; const patchNextButtons = () => { const p = player(); if (!p) return; const nextBtn = document.querySelector('.ytp-next-button'); if (nextBtn && !nextBtn.__revPatched) { nextBtn.__revPatched = true; nextBtn.addEventListener('click', (e) => { if (!enabled) return; e.stopImmediatePropagation(); e.preventDefault(); goPrevPlay(); }, true); log('patched main next'); } qsa('ytd-playlist-panel-renderer #next-button button').forEach(btn => { if (!btn.__revPatched) { btn.__revPatched = true; btn.addEventListener('click', (e) => { if (!enabled) return; e.stopImmediatePropagation(); e.preventDefault(); goPrevPlay(); }, true); log('patched panel next'); } }); }; const attachStateListener = () => { const p = player(); if (!p || stateListenerSet || typeof p.addEventListener !== 'function') return; const onState = (s) => { // 1 PLAYING, 2 PAUSED, 0 ENDED, 3 BUFFERING, 5 CUED if (!enabled) return; if (s === 0) { log('onStateChange -> ENDED, go previous'); goPrevPlay(); } else if (s === 1) { startNearEndGuard(); } }; try { p.addEventListener('onStateChange', onState); stateListenerSet = true; log('state listener attached'); } catch (e) { log('addEventListener failed', e); } }; const startNearEndGuard = () => { clearInterval(guardTimer); const p = player(); if (!p || typeof p.getDuration !== 'function' || typeof p.getCurrentTime !== 'function') return; guardTimer = setInterval(() => { if (!enabled) return clearInterval(guardTimer); const d = p.getDuration ? p.getDuration() : 0; const t = p.getCurrentTime ? p.getCurrentTime() : 0; if (d > 0 && d - t <= 0.7) { log('near end, preempt -> previous'); clearInterval(guardTimer); goPrevPlay(); } }, 150); }; const makeBtn = () => { const btn = document.createElement('button'); btn.id = BTN_ID; btn.className = 'ytp-button'; btn.title = '逆序播放'; btn.setAttribute('aria-label', '逆序播放'); btn.style.opacity = '0.6'; btn.style.display = 'inline-flex'; btn.style.alignItems = 'center'; btn.style.justifyContent = 'center'; const ref = document.querySelector('.ytp-subtitles-button.ytp-button') || document.querySelector('.ytp-button'); if (ref) { const cs = getComputedStyle(ref); btn.style.width = cs.width; btn.style.height = cs.height; btn.style.padding = cs.padding; } else { btn.style.width = '54px'; btn.style.height = '54px'; btn.style.padding = '0 2px'; } const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('viewBox', '0 0 36 36'); svg.setAttribute('width', '100%'); svg.setAttribute('height', '100%'); svg.setAttribute('focusable', 'false'); svg.setAttribute('aria-hidden', 'true'); svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('fill', 'currentColor'); path.setAttribute('stroke', 'currentColor'); path.setAttribute('stroke-width', '1.4'); path.setAttribute('d', 'M7 6h6a7 7 0 1 1-6.3 9.8l.9-.45A6 6 0 1 0 13 7H7.8l1.6 1.6-.7.7L5.7 6.3 8.7 3.3l.7.7L7 6z'); path.setAttribute('transform', 'translate(6,6) scale(0.90)'); path.setAttribute('stroke-linecap', 'round'); path.setAttribute('stroke-linejoin', 'round'); svg.appendChild(path); btn.appendChild(svg); const setOn = (on) => { enabled = on; btn.setAttribute('aria-pressed', on ? 'true' : 'false'); btn.style.opacity = on ? '1' : '0.6'; if (on) { ensureShuffleOff(); patchNextButtons(); attachStateListener(); startNearEndGuard(); } else { clearInterval(guardTimer); } }; btn.addEventListener('click', () => setOn(!enabled)); setOn(hasPlaylist()); return btn; }; const placeBtn = async () => { let host = null; for (let i = 0; i < 40; i++) { host = qs('.ytp-right-controls'); if (host) break; await sleep(150); } if (!host) return; if (!document.getElementById(BTN_ID)) { const btn = makeBtn(); host.insertBefore(btn, host.firstChild); } }; const keepAlive = () => { const mo = new MutationObserver(() => { if (!qs(`#${BTN_ID}`)) placeBtn(); if (enabled) { patchNextButtons(); attachStateListener(); } }); mo.observe(document.body, {subtree: true, childList: true}); let last = location.href; const urlMo = new MutationObserver(() => { const now = location.href; if (now !== last) { last = now; const old = qs(`#${BTN_ID}`); if (old && old.parentElement) old.parentElement.removeChild(old); placeBtn(); } }); urlMo.observe(document, {subtree: true, childList: true}); }; (async () => { await placeBtn(); keepAlive(); log('ready'); })(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址