Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Instagram Video Controls (unmute, no autoplay, dynamic loading)
- // @namespace http://tampermonkey.net/
- // @version 2025-06-19
- // @description Add controls to Instagram videos, unmute by default, disable autoplay, handle dynamic content, and provide Tampermonkey menu options for controls, sound, and autoplay blocking.
- // @author You
- // @match https://www.instagram.com/*
- // @grant GM_registerMenuCommand
- // @grant GM_getValue
- // @grant GM_setValue
- // ==/UserScript==
- (function () {
- 'use strict';
- // Default settings
- const defaults = {
- showControls: true,
- unmute: true,
- blockAutoplay: true
- };
- // Load saved settings or use defaults
- const settings = {
- showControls: GM_getValue('showControls', defaults.showControls),
- unmute: GM_getValue('unmute', defaults.unmute),
- blockAutoplay: GM_getValue('blockAutoplay', defaults.blockAutoplay)
- };
- // Toggle a boolean setting via Tampermonkey menu
- const toggleSetting = (key, label) => {
- const newValue = !settings[key];
- settings[key] = newValue;
- GM_setValue(key, newValue);
- alert(`${label} set to ${newValue ? 'ON' : 'OFF'}. Refresh the page to apply changes.`);
- };
- // Register menu commands
- GM_registerMenuCommand(
- `[${settings.showControls ? '✓' : ' '}] Show controls`,
- () => toggleSetting('showControls', 'Show controls')
- );
- GM_registerMenuCommand(
- `[${settings.unmute ? '✓' : ' '}] Unmute videos`,
- () => toggleSetting('unmute', 'Unmute videos')
- );
- GM_registerMenuCommand(
- `[${settings.blockAutoplay ? '✓' : ' '}] Block autoplay`,
- () => toggleSetting('blockAutoplay', 'Block autoplay')
- );
- const processed = new WeakSet();
- /**
- * Enhance a single <video> element: add controls, unmute, disable autoplay attribute,
- * bring to front, and optionally override play() to block Instagram-triggered autoplay.
- * @param {HTMLVideoElement} video
- */
- const enhanceVideo = (video) => {
- if (processed.has(video)) return;
- // 1. Show native controls if enabled
- if (settings.showControls) {
- video.controls = true;
- }
- // 2. Unmute if enabled
- if (settings.unmute) {
- video.muted = false;
- video.volume = 1.0;
- video.removeAttribute('muted');
- // Ensure Instagram scripts don't re-mute
- video.addEventListener('loadedmetadata', () => { video.muted = false; });
- video.addEventListener('play', () => { video.muted = false; });
- video.addEventListener('volumechange', () => { if (video.muted) video.muted = false; });
- video.addEventListener('timeupdate', () => { if (video.muted) video.muted = false; });
- }
- // 3. Disable autoplay attribute/property
- if (video.hasAttribute('autoplay')) {
- video.removeAttribute('autoplay');
- }
- try {
- video.autoplay = false;
- } catch (e) {
- // ignore if not writable
- }
- // 4. Bring controls to front: adjust style
- Object.assign(video.style, {
- position: 'relative',
- zIndex: '1000'
- });
- // 5. Optionally override play() to block Instagram-triggered autoplay
- if (settings.blockAutoplay && !video.__playOverridden) {
- // Track user clicks on the video to allow manual play
- video.addEventListener('click', () => {
- video._lastUserClick = Date.now();
- });
- const originalPlay = video.play.bind(video);
- video.play = (...args) => {
- // If user clicked recently (within 500ms), allow play
- if (video._lastUserClick && (Date.now() - video._lastUserClick) < 500) {
- return originalPlay(...args);
- }
- // Otherwise block autoplay attempts
- console.log('Blocked autoplay for video:', video);
- // Return a resolved promise to satisfy callers expecting a Promise
- return Promise.resolve();
- };
- video.__playOverridden = true;
- }
- processed.add(video);
- };
- // Process all existing <video> elements on the page
- const enhanceAllExisting = () => {
- document.querySelectorAll('video').forEach(enhanceVideo);
- };
- // Observe DOM mutations to catch newly added videos
- const observeNewVideos = () => {
- const observer = new MutationObserver((mutations) => {
- for (const mut of mutations) {
- for (const node of mut.addedNodes) {
- if (!(node instanceof HTMLElement)) continue;
- if (node.tagName === 'VIDEO') {
- enhanceVideo(node);
- } else {
- const vids = node.querySelectorAll?.('video');
- if (vids?.length) {
- vids.forEach(enhanceVideo);
- }
- }
- }
- }
- });
- observer.observe(document.body, { childList: true, subtree: true });
- };
- // Periodically re-run enhancement (for SPA navigation cases)
- const periodicEnhance = () => {
- setInterval(enhanceAllExisting, 2000);
- };
- // Initial run
- enhanceAllExisting();
- observeNewVideos();
- periodicEnhance();
- // Fallback: re-enhance on clicks (in case React re-renders)
- document.addEventListener('click', enhanceAllExisting, true);
- })();
Add Comment
Please, Sign In to add comment