Video Autoplay Blocker

Blocks all video autoplay and allowed playback only after user interaction.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

You will need to install an extension such as Tampermonkey to install this script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name         Video Autoplay Blocker
// @namespace    VmlkZW8gQXV0b3BsYXkgQmxvY2tlcg
// @version      1.0
// @description  Blocks all video autoplay and allowed playback only after user interaction.
// @author       smed79
// @license      GPLv3
// @icon         https://i25.servimg.com/u/f25/11/94/21/24/stop-v10.png
// @match        *://*/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function () {
    'use strict';

    // Flag to track user interaction
    let userInteracted = false;

    // Mark videos as user-initiated after interaction
    const markUserInitiated = () => {
        userInteracted = true;
        document.querySelectorAll('video').forEach(v => {
            v.dataset.userInitiated = 'true';
        });
    };

    // Listen for user interaction events
    ['click', 'keydown', 'touchstart'].forEach(evt =>
        window.addEventListener(evt, markUserInitiated, true)
    );

    // Override play() to block autoplay unless user-initiated
    const originalPlay = HTMLMediaElement.prototype.play;
    HTMLMediaElement.prototype.play = function () {
        if (this.tagName === 'VIDEO') {
            const isUserInitiated = userInteracted || this.dataset.userInitiated === 'true';
            if (isUserInitiated) {
                return originalPlay.apply(this, arguments);
            } else {
                console.warn('[Autoplay Blocked]: play() intercepted');
                const p = Promise.resolve();
                p.catch(() => {});
                return p;
            }
        }
        return originalPlay.apply(this, arguments);
    };

    // Check for nearby custom controls
    const hasCustomControlsNearby = (video) => {
        const container = video.closest('div, section, article, body');
        if (!container) return false;

        const keywords = ['play', 'pause', 'btn', 'control', 'icon', 'player'];
        const controlsLike = container.querySelectorAll('button, [role="button"], [class], [id]');

        for (let el of controlsLike) {
            const cls = (el.className || '') + ' ' + (el.id || '');
            const clsLower = cls.toLowerCase();
            if (keywords.some(k => clsLower.includes(k))) {
                return true;
            }
        }

        return false;
    };

    // Block autoplay and ensure controls
    const blockAutoplay = (video) => {
        video.autoplay = false;
        video.muted = false;
        video.removeAttribute('autoplay');
        video.removeAttribute('muted');
        video.preload = 'metadata';
        video.pause();

        const hasNativeControls = video.hasAttribute('controls');
        const hasCustomControls = hasCustomControlsNearby(video);

        if (!hasNativeControls && !hasCustomControls) {
            video.setAttribute('controls', 'true');
        }
    };

    // Process all videos on the page
    const processVideos = () => {
        document.querySelectorAll('video').forEach(blockAutoplay);
    };

    // Run on DOM ready and window load
    document.addEventListener('DOMContentLoaded', processVideos);
    window.addEventListener('load', processVideos);

    // Observe DOM for dynamically added videos
    const observer = new MutationObserver((mutations) => {
        mutations.forEach(m => {
            m.addedNodes.forEach(node => {
                if (node.tagName === 'VIDEO') {
                    blockAutoplay(node);
                } else if (node.querySelectorAll) {
                    node.querySelectorAll('video').forEach(blockAutoplay);
                }
            });
        });
    });

    observer.observe(document.documentElement || document.body, {
        childList: true,
        subtree: true
    });

})();