Prevents websites from automatically refreshing the page via meta tags or JavaScript
// ==UserScript==
// @name No Auto-Refresh
// @namespace Tm8gQXV0by1SZWZyZXNo
// @version 1.0
// @description Prevents websites from automatically refreshing the page via meta tags or JavaScript
// @author smed79
// @license GPLv3
// @icon https://i.servimg.com/u/f25/11/94/21/24/dhm10.png
// @match *://*/*
// @run-at document-start
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Helper: Check if a target URL points to the exact same page (ignoring #hash fragments)
const isSameUrl = (url) => {
try {
const targetUrl = new URL(url, window.location.href);
return targetUrl.href.split('#')[0] === window.location.href.split('#')[0];
} catch (e) {
return false;
}
};
// --- Block Meta Refresh ---
const removeMetaRefresh = () => {
document.querySelectorAll('meta[http-equiv="refresh" i]').forEach(meta => {
const content = meta.getAttribute('content');
if (content) {
// Extract URL if it's a redirect (e.g., "5; url=https://example.com")
const match = content.match(/url=([^;]+)/i);
if (match) {
const targetUrl = match[1].replace(/^['"]|['"]$/g, '').trim();
// Allow the meta tag if it's redirecting to a DIFFERENT page (e.g., post-login)
if (!isSameUrl(targetUrl)) return;
}
}
// If there's no URL (just a timer) or it points to the same page, remove it
meta.remove();
});
};
// --- Block JavaScript-based Refresh (Intercept Prototypes) ---
const blockJSRefresh = () => {
// Block location.reload() completely
Location.prototype.reload = function() {};
// Block location.replace() ONLY if replacing with the same URL
const originalReplace = Location.prototype.replace;
Location.prototype.replace = function(url) {
if (isSameUrl(url)) return;
return originalReplace.call(this, url);
};
// Block location.assign() ONLY if assigning the same URL
const originalAssign = Location.prototype.assign;
Location.prototype.assign = function(url) {
if (isSameUrl(url)) return;
return originalAssign.call(this, url);
};
// Intercept location.href = "..." assignments safely
try {
const hrefDescriptor = Object.getOwnPropertyDescriptor(Location.prototype, 'href');
if (hrefDescriptor) {
Object.defineProperty(Location.prototype, 'href', {
get: hrefDescriptor.get,
set: function(url) {
if (isSameUrl(url)) return;
hrefDescriptor.set.call(this, url);
}
});
}
} catch (e) {} // Fails safely if browser is excessively strict
};
// --- High-Performance Observer ---
// Instead of looping through all elements on every DOM change, we only check added nodes
const observer = new MutationObserver((mutations) => {
let shouldCheck = false;
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
// Only trigger querySelector if a meta tag or head element was added
if (node.nodeName === 'META' || node.nodeName === 'HEAD') {
shouldCheck = true;
break;
}
}
if (shouldCheck) break;
}
if (shouldCheck) removeMetaRefresh();
});
// Run immediately
blockJSRefresh();
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', removeMetaRefresh);
} else {
removeMetaRefresh();
}
// Keep observer active but strictly limited to the <head> to consume almost 0 CPU
if (document.documentElement) {
observer.observe(document.documentElement, { childList: true, subtree: true });
}
})();