Fix Instagram Videos

Adds controls, prevents auto-mute, disables looping, and stops pause on tab switch

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu budete musieť nainštalovať rozšírenie, ako je napríklad Tampermonkey alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         Fix Instagram Videos
// @namespace    andreiv
// @version      1.1
// @description  Adds controls, prevents auto-mute, disables looping, and stops pause on tab switch
// @match        https://www.instagram.com/
// @match        https://www.instagram.com/*
// @license      MIT
// ==/UserScript==
(function() {
    'use strict';
    // Override muted property globally
    const originalMuted = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'muted');
    Object.defineProperty(HTMLMediaElement.prototype, 'muted', {
        get: function() {
            return false;
        },
        set: function(value) {
            // Always force unmuted
            if (originalMuted && originalMuted.set) {
                originalMuted.set.call(this, false);
            }
        },
        configurable: true
    });
    // Process video elements
    function processVideo(video) {
        // Remove Instagram's overlay
        if (video.nextElementSibling) {
            video.nextElementSibling.remove();
        }
        // Add controls and unmute
        video.controls = true;
        video.muted = false;
        video.volume = 1;

        // Prevent pause on tab switch
        const originalPause = video.pause;
        video.pause = function() {
            if (document.hidden) return;
            return originalPause.call(this);
        };

        // Block autoplay on tab return
        let blockPlay = false;
        const originalPlay = video.play;
        video.play = function() {
            // Only block if blockPlay is true (for tab switching)
            if (blockPlay) return Promise.resolve();

            // CRITICAL FIX: Check if we're at the end and reset
            // Firefox doesn't auto-reset currentTime when playing from ended state
            if (this.currentTime >= this.duration - 0.1 || this.ended) {
                this.currentTime = 0;
            }

            return originalPlay.call(this);
        };

        // Also intercept the play event to double-check
        video.addEventListener('play', function(e) {
            // If we're playing but still at the end, force reset
            if (video.currentTime >= video.duration - 0.1) {
                video.currentTime = 0;
            }
        }, true);

        // When tab becomes visible, block play for 500ms
        document.addEventListener('visibilitychange', () => {
            if (!document.hidden) {
                blockPlay = true;
                setTimeout(() => {
                    blockPlay = false;
                }, 500);
            }
        });

        // Prevent looping by intercepting ended event
        video.addEventListener('ended', (e) => {
            e.stopImmediatePropagation();
            video.pause();
            // Don't manipulate currentTime here, let it stay at the end naturally
        }, true);
    }
    // Watch for new videos
    const observer = new MutationObserver((mutations) => {
        mutations.forEach(mutation => {
            mutation.addedNodes.forEach(node => {
                if (node.nodeName === 'VIDEO') {
                    processVideo(node);
                } else if (node.querySelectorAll) {
                    node.querySelectorAll('video').forEach(processVideo);
                }
            });
        });
    });
    // Start observing
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });
    // Initial run for existing videos
    document.querySelectorAll('video').forEach(processVideo);
})();