您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Block autoplay before user interaction on most websites
当前为
// ==UserScript== // @name Disable autoplay // @namespace https://www.androidacy.com/ // @version 2.2.1 // @description Block autoplay before user interaction on most websites // @author Androidacy // @include * // @icon https://www.androidacy.com/wp-content/uploads/cropped-cropped-cropped-cropped-New-Project-32-69C2A87-1-192x192.jpg // @grant none // @run-at document-end // ==/UserScript== (() => { const allowedToPlay = new WeakSet() const mediaTags = ['video', 'audio'] const processedAttr = 'data-disable-autoplay-processed' const debugLog = (...args) => { console.debug('[DisableAutoplay]', ...args) } const warnLog = (...args) => { console.warn('[DisableAutoplay]', ...args) } const disableAutoplay = media => { if (media.hasAttribute(processedAttr)) { debugLog('Already processed media element:', media) return } media.setAttribute(processedAttr, 'true') debugLog('Processing media element:', media) if (media.hasAttribute('autoplay')) { media.removeAttribute('autoplay') debugLog('Removed autoplay attribute from media:', media) } if (!media.paused) { media.pause() debugLog('Paused media element:', media) } const originalPlay = media.play media.play = (...args) => { if (allowedToPlay.has(media)) { debugLog('Playing media element:', media) return originalPlay.apply(media, args) } else { warnLog('Autoplay blocked for media element:', media) return Promise.reject(new Error('Autoplay is disabled by a userscript.')) } } const enablePlayback = event => { if (!event.isTrusted) { warnLog('Ignored untrusted event:', event) return } debugLog('User interaction detected:', event.type, 'on', event.target) allowedToPlay.add(media) media.play().catch(err => warnLog('Error playing media after user interaction:', err, media)) media.removeEventListener('click', enablePlayback) media.removeEventListener('touchstart', enablePlayback) removeCoverListeners(media, enablePlayback) } media.addEventListener('click', enablePlayback, { once: true, passive: false }) media.addEventListener('touchstart', enablePlayback, { once: true, passive: false }) debugLog('Added click and touchstart event listeners to media element:', media) addCoverListeners(media, enablePlayback) } const addCoverListeners = (media, handler) => { const covers = findCoverElements(media) covers.forEach(cover => { cover.addEventListener('click', handler, { once: true, passive: false }) cover.addEventListener('touchstart', handler, { once: true, passive: false }) debugLog('Added event listeners to cover element:', cover) }) } const removeCoverListeners = (media, handler) => { const covers = findCoverElements(media) covers.forEach(cover => { cover.removeEventListener('click', handler) cover.removeEventListener('touchstart', handler) debugLog('Removed event listeners from cover element:', cover) }) } const findCoverElements = media => { const covers = [] const mediaRect = media.getBoundingClientRect() const parent = media.parentElement if (!parent) return covers Array.from(parent.children).forEach(sibling => { if (sibling === media) return const style = window.getComputedStyle(sibling) const position = style.position const display = style.display const visibility = style.visibility const pointerEvents = style.pointerEvents if (display === 'none' || visibility === 'hidden' || pointerEvents === 'none') return if (!['absolute', 'fixed', 'relative'].includes(position)) return const siblingRect = sibling.getBoundingClientRect() if (isOverlapping(mediaRect, siblingRect)) { covers.push(sibling) } }) return covers } const isOverlapping = (rect1, rect2) => { const threshold = 0.3 const intersection = { left: Math.max(rect1.left, rect2.left), right: Math.min(rect1.right, rect2.right), top: Math.max(rect1.top, rect2.top), bottom: Math.min(rect1.bottom, rect2.bottom) } const width = intersection.right - intersection.left const height = intersection.bottom - intersection.top if (width <= 0 || height <= 0) return false const areaIntersection = width * height const areaMedia = rect1.width * rect1.height return (areaIntersection / areaMedia) >= threshold } const processMediaElements = () => { mediaTags.forEach(tag => { document.querySelectorAll(tag).forEach(media => { disableAutoplay(media) }) }) } const observeMedia = () => { const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType !== Node.ELEMENT_NODE) return mediaTags.forEach(tag => { if (node.matches(tag)) { debugLog('New media element added:', node) disableAutoplay(node) } node.querySelectorAll(tag).forEach(media => { debugLog('New nested media element added:', media) disableAutoplay(media) }) }) }) }) }) observer.observe(document.body, { childList: true, subtree: true }) debugLog('Started observing DOM for new media elements') } const init = () => { debugLog('Initializing Disable autoplay userscript') processMediaElements() observeMedia() } init() })()