Video Autoplay Blocker

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

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==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
    });

})();