您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Prevents videos from autoplaying on websites and adds a play button overlay
// ==UserScript== // @name Disable Video Autoplay // @namespace http://tampermonkey.net/ // @version 1.0 // @description Prevents videos from autoplaying on websites and adds a play button overlay // @author You // @match *://*/* // @grant none // @run-at document-start // ==/UserScript== (function() { 'use strict'; // User-configurable options const config = { // List of domains where autoplay blocking is disabled (e.g. 'youtube.com') allowlist: [], // List of domains where autoplay blocking is always enabled (leave empty to target all sites) denylist: [], // Show a play button overlay on videos showPlayButton: true, // Enable debug logging in the console debug: false }; // Decide if the current site should be processed based on allowlist/denylist function shouldProcessSite() { const currentDomain = window.location.hostname.replace('www.', ''); // Skip processing if the site is in the allowlist if (config.allowlist.some(site => currentDomain.includes(site))) { logDebug('Site in allowlist, skipping'); return false; } // Only process if denylist is empty or the site is in the denylist if (config.denylist.length > 0 && !config.denylist.some(site => currentDomain.includes(site))) { logDebug('Site not in denylist, skipping'); return false; } return true; } // Print debug messages if debug mode is enabled function logDebug(message) { if (config.debug) { console.log('[Disable Autoplay]', message); } } // Remove autoplay from <video> elements and prevent programmatic autoplay function processVideoElement(video) { if (video.hasAttribute('autoplay')) { video.removeAttribute('autoplay'); video.pause(); logDebug('Removed autoplay attribute from video element'); } // Unmute video (some sites use muted+autoplay to bypass restrictions) video.muted = false; // Prevent autoplay even if triggered by scripts video.addEventListener('play', function(e) { if (!video.hasAttribute('data-user-initiated')) { video.pause(); logDebug('Prevented automatic playback'); } }, true); // Add overlay if enabled and not already present if (config.showPlayButton && !video.hasAttribute('data-overlay-added')) { addPlayButtonOverlay(video); } } // Modify <iframe> embeds (e.g. YouTube, Vimeo) to disable autoplay function processIframeElement(iframe) { // Special handling for YouTube/Vimeo embeds if (iframe.src && iframe.src.match(/youtube|vimeo/i)) { const currentSrc = iframe.src; // If autoplay=1, set to 0 if (currentSrc.includes('autoplay=1')) { iframe.src = currentSrc.replace('autoplay=1', 'autoplay=0'); logDebug('Disabled autoplay for embedded video iframe'); } else if (!currentSrc.includes('autoplay=0')) { // If no autoplay param, add autoplay=0 iframe.src = currentSrc + (currentSrc.includes('?') ? '&' : '?') + 'autoplay=0'; logDebug('Added autoplay=0 parameter to iframe'); } } // For other iframes, try to replace autoplay=1 with autoplay=0 in the src else if (iframe.src && iframe.src.includes('autoplay')) { try { iframe.src = iframe.src.replace(/autoplay=1/g, 'autoplay=0'); logDebug('Modified autoplay parameter in iframe src'); } catch (e) { logDebug('Could not modify iframe src: ' + e.message); } } } // Add a play button overlay to the video element function addPlayButtonOverlay(video) { // Don't add overlay if already present if (video.hasAttribute('data-overlay-added')) { return; } // Mark as processed so overlay isn't added again video.setAttribute('data-overlay-added', 'true'); // Create overlay container const container = document.createElement('div'); container.style.cssText = ` position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background-color: rgba(0, 0, 0, 0.2); z-index: 10000; cursor: pointer; opacity: 0; transition: opacity 0.3s; `; container.classList.add('autoplay-disabled-overlay'); // Create the circular play button const playButton = document.createElement('div'); playButton.style.cssText = ` width: 60px; height: 60px; background-color: rgba(0, 0, 0, 0.6); border-radius: 50%; display: flex; align-items: center; justify-content: center; `; // Create the triangle play icon const playIcon = document.createElement('div'); playIcon.style.cssText = ` width: 0; height: 0; border-top: 15px solid transparent; border-bottom: 15px solid transparent; border-left: 25px solid white; margin-left: 5px; `; // Assemble overlay playButton.appendChild(playIcon); container.appendChild(playButton); // Make sure the parent is positioned for absolute overlay const videoParent = video.parentElement; videoParent.style.position = videoParent.style.position || 'relative'; videoParent.appendChild(container); // Show overlay on hover videoParent.addEventListener('mouseenter', () => { container.style.opacity = '1'; }); videoParent.addEventListener('mouseleave', () => { container.style.opacity = '0'; }); // Play video when overlay is clicked container.addEventListener('click', () => { video.setAttribute('data-user-initiated', 'true'); video.play() .then(() => { // Hide overlay when playback starts container.style.display = 'none'; logDebug('Video playback started by user'); }) .catch(err => { logDebug('Error starting video playback: ' + err.message); // Keep overlay visible if playback fails }); }); logDebug('Added play button overlay to video'); } // Scan and process all <video> and <iframe> elements currently in the DOM function processExistingMedia() { document.querySelectorAll('video').forEach(processVideoElement); document.querySelectorAll('iframe').forEach(processIframeElement); logDebug('Processed existing media elements'); } // Watch for new videos/iframes added dynamically and process them function setupMutationObserver() { const observer = new MutationObserver((mutations) => { let needsProcessing = false; // If any new nodes are added, flag for processing mutations.forEach((mutation) => { if (mutation.addedNodes.length) { needsProcessing = true; } }); // Batch process after a short delay if (needsProcessing) { setTimeout(() => { processExistingMedia(); }, 100); // Let DOM settle } }); // Observe the whole document for added nodes observer.observe(document.body, { childList: true, subtree: true }); logDebug('Mutation observer set up for dynamic content'); } // Main entry point: set up everything function initialize() { if (!shouldProcessSite()) { return; } logDebug('Initializing autoplay blocker'); // Add style for overlays const style = document.createElement('style'); style.textContent = ` video[data-overlay-added] { visibility: visible !important; opacity: 1 !important; } `; document.head.appendChild(style); // Process any existing media right away processExistingMedia(); // Watch for new media setupMutationObserver(); // Re-scan after short delays to catch late-loaded elements setTimeout(processExistingMedia, 1000); setTimeout(processExistingMedia, 3000); } // Run as soon as possible if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initialize); } else { initialize(); } })();