Old Reddit: Pause Videos / YT Embeds When Scrolled Out Upwards

Pauses Reddit videos and YouTube embeds when they scroll out of view (upwards).

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Old Reddit: Pause Videos / YT Embeds When Scrolled Out Upwards
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Pauses Reddit videos and YouTube embeds when they scroll out of view (upwards).
// @author       Claude AI
// @match        https://www.reddit.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // --- Utility functions ---

    // Find all regular <video> tags on Reddit (not inside YT iframes)
    function getAllRedditVideos() {
        return Array.from(document.querySelectorAll('video'))
            .filter(v => !v.closest('iframe')); // Exclude videos inside iframes
    }

    // Find all YouTube embed iframes
    function getAllYouTubeIframes() {
        return Array.from(document.querySelectorAll('iframe')).filter(iframe => {
            const src = iframe.src || '';
            // Matches youtube.com/embed or redditmedia.com/mediaembed
            return (
                /youtube\.com\/embed/i.test(src) ||
                /youtu\.be\//i.test(src) ||
                /redditmedia\.com\/mediaembed\//i.test(src)
            );
        });
    }

    // Is the element out of the viewport above (both bounds <= 0)?
    function isScrolledOutTop(el) {
        const rect = el.getBoundingClientRect();
        return rect.bottom <= 0 && rect.top <= 0;
    }

    // Pause <video> tags
    function handleRedditVideos() {
        getAllRedditVideos().forEach(video => {
            if (!video.paused && isScrolledOutTop(video)) {
                video.pause();
                console.debug('[Reddit Video Pause Userscript] Paused Reddit <video>:', video);
            }
        });
    }

    // Pause YouTube embeds using postMessage API
    function handleYouTubeEmbeds() {
        getAllYouTubeIframes().forEach(iframe => {
            if (isScrolledOutTop(iframe)) {
                // Tell YT iframe to pause (uses YouTube Iframe API's message format)
                try {
                    iframe.contentWindow.postMessage(
                        JSON.stringify({ event: 'command', func: 'pauseVideo', args: [] }),
                        '*'
                    );
                    console.debug('[Reddit Video Pause Userscript] Pause sent to YouTube embed:', iframe);
                } catch (err) {
                    console.warn('[Reddit Video Pause Userscript] Could not postMessage to YouTube embed:', err);
                }
            }
        });
    }

    // --- Main handler ---

    function handleVideosOutOfView() {
        handleRedditVideos();
        handleYouTubeEmbeds();
    }

    // --- Event setup with throttling ---

    let scrollTimer = null;
    function throttledScrollHandler() {
        if (scrollTimer) return;
        scrollTimer = setTimeout(() => {
            handleVideosOutOfView();
            scrollTimer = null;
        }, 200); // 200ms
    }

    window.addEventListener('scroll', throttledScrollHandler);
    window.addEventListener('resize', throttledScrollHandler);

    // Watch for DOM updates for dynamically added videos/embeds
    const observer = new MutationObserver(mutations => {
        handleVideosOutOfView();
    });
    observer.observe(document.body, {childList: true, subtree: true});

    // Initial startup delay for the page to load
    setTimeout(handleVideosOutOfView, 1500);

    console.debug('[Reddit Video Pause Userscript] Loaded (video/YT support)!');

})();