Tab Media Focus (Smart Filter)

Pause media in other tabs when playing media in current tab (mobile-like behavior)

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Tab Media Focus (Smart Filter)
// @namespace    https://greasyfork.org/en/scripts/589569/
// @version      1.2
// @description  Pause media in other tabs when playing media in current tab (mobile-like behavior)
// @author       TechComet
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addValueChangeListener
// @run-at       document-idle
// @license      MIT
// ==/UserScript==

// Written using Qwen Ai from the first attempt

(function() {
    'use strict';

    // 1. Generate a unique ID for this tab
    const MY_TAB_ID = 'tab_' + Math.random().toString(36).substr(2, 9);
    const STORAGE_KEY = 'active_media_focus_id';

    // 2. Configuration for Smart Filtering
    const CONFIG = {
        ignoreMuted: true,             // Ignore muted videos (common in previews)
        ignoreShortDuration: true,     // Ignore very short videos (previews)
        minDurationSeconds: 5,         // Minimum duration to be considered "real" media
        previewKeywords: [             // Keywords in class names indicating previews
            'preview', 'thumbnail', 'mini', 'hover', 'feed', 'shorts',
            'ytd-thumbnail', 'video-preview', 'autoplay-preview'
        ]
    };

    console.log(`[MediaFocus] Initialized: ${MY_TAB_ID}`);

    // 3. Check if video is a preview/thumbnail based on multiple criteria
    function isPreviewVideo(media) {
        // A. Check Mute Status (Fastest & Most Reliable)
        if (CONFIG.ignoreMuted && (media.muted || media.volume === 0)) {
            return true;
        }

        // B. Check Class Names (Fast)
        if (media.classList) {
            for (let i = 0; i < media.classList.length; i++) {
                const cls = media.classList[i].toLowerCase();
                for (const keyword of CONFIG.previewKeywords) {
                    if (cls.includes(keyword)) {
                        return true;
                    }
                }
            }
        }

        // C. Check Duration (Reliable if metadata loaded)
        if (CONFIG.ignoreShortDuration && media.duration) {
            if (isFinite(media.duration) && media.duration < CONFIG.minDurationSeconds) {
                return true;
            }
        }

        return false;
    }

    // 4. Pause all media elements in this tab
    function pauseAllMedia() {
        const mediaElements = document.querySelectorAll('video, audio');
        let pausedCount = 0;
        mediaElements.forEach(media => {
            if (!media.paused) {
                media.pause();
                pausedCount++;
            }
        });
        if (pausedCount > 0) console.log(`[MediaFocus] Paused ${pausedCount} media element(s)`);
    }

    // 5. Claim focus when valid media starts playing
    function claimFocus() {
        GM_setValue(STORAGE_KEY, MY_TAB_ID);
    }

    // 6. Listen for 'play' events on the window (Capture Phase)
    // This avoids MutationObserver for better performance
    window.addEventListener('play', (event) => {
        const target = event.target;

        // Ensure it's a valid media element
        if (target instanceof HTMLMediaElement) {
            // Apply smart filters
            if (isPreviewVideo(target)) {
                return; // Ignore preview/thumbnail videos
            }

            // Valid media detected, claim focus
            console.log(`[MediaFocus] Valid media play detected`);
            claimFocus();
        }
    }, true); // 'true' enables capture phase

    // 7. Listen for changes from other tabs via shared storage
    GM_addValueChangeListener(STORAGE_KEY, function(key, oldVal, newVal, remote) {
        // If change came from a remote tab and it's not us, pause local media
        if (remote && newVal && newVal !== MY_TAB_ID) {
            console.log(`[MediaFocus] Tab ${newVal} is playing, pausing local media`);
            pauseAllMedia();
        }
    });

})();