mirror of
https://github.com/Ujwal223/FocusGram.git
synced 2026-05-27 17:32:23 +02:00
130 lines
4.0 KiB
JavaScript
130 lines
4.0 KiB
JavaScript
/**
|
|
* FocusGram Autoplay Blocker
|
|
* Injected at DOCUMENT_START — before Instagram's JS loads.
|
|
* Prevents video autoplay by:
|
|
* 1. Blocking play() calls on video elements
|
|
* 2. Disabling autoplay attribute
|
|
* 3. Removing preload attributes
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
|
|
// This script is only registered when the setting is enabled, so default ON.
|
|
window.__fgBlockAutoplay = typeof window.__fgBlockAutoplay === 'boolean'
|
|
? window.__fgBlockAutoplay : true;
|
|
const ALLOW_KEY = '__fgUserStartedPlayback';
|
|
let userGestureUntil = 0;
|
|
|
|
function isReelRoute() {
|
|
const path = window.location.pathname || '';
|
|
return path.indexOf('/reel/') >= 0 || path === '/reels' || path.indexOf('/reels/') >= 0;
|
|
}
|
|
|
|
function isUserGestureActive() {
|
|
return Date.now() < userGestureUntil;
|
|
}
|
|
|
|
function markUserGesture(target) {
|
|
userGestureUntil = Date.now() + 1200;
|
|
try {
|
|
let video = target && target.closest ? target.closest('video') : null;
|
|
if (!video && target && target.querySelector) video = target.querySelector('video');
|
|
if (video) video[ALLOW_KEY] = true;
|
|
} catch (_) {}
|
|
}
|
|
|
|
document.addEventListener('pointerdown', function (event) {
|
|
markUserGesture(event.target);
|
|
}, true);
|
|
document.addEventListener('touchstart', function (event) {
|
|
markUserGesture(event.target);
|
|
}, true);
|
|
document.addEventListener('click', function (event) {
|
|
markUserGesture(event.target);
|
|
}, true);
|
|
|
|
// Override HTMLMediaElement.play() to check our flag
|
|
const _play = HTMLMediaElement.prototype.play;
|
|
HTMLMediaElement.prototype.play = function () {
|
|
if (
|
|
window.__fgBlockAutoplay &&
|
|
!isReelRoute() &&
|
|
this[ALLOW_KEY] !== true &&
|
|
!isUserGestureActive()
|
|
) {
|
|
// Return a resolved promise to avoid breaking Instagram's code
|
|
try { this.pause(); } catch (_) {}
|
|
return Promise.resolve();
|
|
}
|
|
return _play.call(this);
|
|
};
|
|
|
|
// Override autoplay property setter
|
|
const _videoDescriptor = Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'autoplay') || {};
|
|
const _originalAutoplaySetter = _videoDescriptor.set;
|
|
|
|
Object.defineProperty(HTMLVideoElement.prototype, 'autoplay', {
|
|
set: function (value) {
|
|
if (window.__fgBlockAutoplay && value) {
|
|
// Silently ignore autoplay attempts when blocking is enabled
|
|
return;
|
|
}
|
|
if (_originalAutoplaySetter) {
|
|
_originalAutoplaySetter.call(this, value);
|
|
}
|
|
},
|
|
get: function () {
|
|
if (_videoDescriptor.get) {
|
|
return _videoDescriptor.get.call(this);
|
|
}
|
|
return this.getAttribute('autoplay') !== null;
|
|
},
|
|
enumerable: _videoDescriptor.enumerable,
|
|
configurable: true,
|
|
});
|
|
|
|
// On page load and SPA navigation, scan for video elements and remove autoplay
|
|
const removeAutoplayFromVideos = () => {
|
|
document.querySelectorAll('video, [role="video"]').forEach(el => {
|
|
if (window.__fgBlockAutoplay && !isReelRoute() && el[ALLOW_KEY] !== true) {
|
|
el.autoplay = false;
|
|
el.removeAttribute('autoplay');
|
|
el.removeAttribute('preload');
|
|
try { el.preload = 'none'; } catch (_) {}
|
|
if (el.paused === false) {
|
|
el.pause();
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
// Run on load and when document changes
|
|
removeAutoplayFromVideos();
|
|
|
|
if (!window.__fgAutoplayObserver) {
|
|
let _timer = null;
|
|
window.__fgAutoplayObserver = new MutationObserver(() => {
|
|
clearTimeout(_timer);
|
|
_timer = setTimeout(removeAutoplayFromVideos, 500);
|
|
});
|
|
window.__fgAutoplayObserver.observe(document.documentElement, {
|
|
childList: true,
|
|
subtree: true,
|
|
});
|
|
}
|
|
|
|
// Allow Flutter to toggle
|
|
window.__fgSetBlockAutoplay = function (enabled) {
|
|
window.__fgBlockAutoplay = !!enabled;
|
|
if (enabled) {
|
|
removeAutoplayFromVideos();
|
|
}
|
|
};
|
|
|
|
document.addEventListener('play', function (event) {
|
|
if (event.target && event.target.tagName === 'VIDEO' && isUserGestureActive()) {
|
|
event.target[ALLOW_KEY] = true;
|
|
}
|
|
}, true);
|
|
})();
|