// ==UserScript==
// @name Facebook Enhancer v3.30
// @namespace https://github.com/TamperMonkeyDevelopment/TamperMonkeyScripts
// @version 3.30
// @description Hide/soft-remove Reels, Stories, Suggestions, PYMK, right-rail ads; pause/mute videos; unwrap links on click; keyword+regex filters; sticky 'Most Recent'; draggable settings panel (position save) + import/export; blur/review/show-hidden modes; per-post "Hide posts like this" control; hotkeys; throttled observer; locale-aware 'Sponsored'.
// @author Eliminater74
// @match *://*.facebook.com/*
// @grant GM_addStyle
// @grant GM_registerMenuCommand
// @license MIT
// @run-at document-end
// ==/UserScript==
(function () {
'use strict';
// -----------------------
// Storage / Defaults
// -----------------------
const STORAGE_KEY = 'fb-enhancer-settings';
const POS_KEY = 'fb-enhancer-positions';
const defaultSettings = {
// General / Visual
debugMode: false,
softRemove: true, // display:none instead of remove()
blurHidden: false, // visually blur hidden instead of hide/remove
reviewMode: false, // outline hidden items for debugging
showHidden: false, // temporarily show items we hid (softRemove only)
forceDarkMode: false,
customCSS: '',
// Feed & Hiding
blockSponsored: true,
blockSuggested: true,
hideReels: true,
hideReelLinks: true, // remove any unit that links to /reel/ or /reels/
aggressiveReelsBlock: true, // broader heuristics (video-count etc.)
reelsHeadingPhrases: 'reels,reels and short videos,short videos',
hideStories: true,
hidePeopleYouMayKnow: true,
hideRightRailAds: true,
keywordFilter: 'kardashian,tiktok,reaction',
keywordRegex: '',
// Video
disableAutoplay: true,
muteVideos: true,
// Navigation / Sidebar
toggleMarketplace: false,
toggleEvents: false,
toggleShortcuts: false,
// Behavior
unwrapLinks: true, // rewrite tracking URLs on click
unwrapOnHover: false, // (safer off)
autoExpandComments: true,
forceMostRecentFeed: true,
mostRecentRetryMs: 4000,
// Hotkeys
gearHotkey: 'Alt+E',
forceMostRecentHotkey: 'Alt+R',
showHiddenHotkey: 'Alt+H'
};
let settings = loadSettings();
const positions = loadPositions();
function loadSettings() {
try {
const saved = JSON.parse(localStorage.getItem(STORAGE_KEY));
return Object.assign({}, defaultSettings, saved || {});
} catch {
return { ...defaultSettings };
}
}
function saveSettings() {
localStorage.setItem(STORAGE_KEY, JSON.stringify(settings));
applyVisualModes();
}
function loadPositions() {
try {
return JSON.parse(localStorage.getItem(POS_KEY)) || {};
} catch {
return {};
}
}
function savePositions() {
localStorage.setItem(POS_KEY, JSON.stringify(positions));
}
// -----------------------
// Utilities
// -----------------------
const log = (...args) => settings.debugMode && console.log('[FB Enhancer]', ...args);
const throttle = (fn, ms) => {
let last = 0, timer;
return (...args) => {
const now = Date.now();
if (now - last >= ms) {
last = now;
fn(...args);
} else {
clearTimeout(timer);
timer = setTimeout(() => {
last = Date.now();
fn(...args);
}, ms - (now - last));
}
};
};
// -----------------------
// CSS
// -----------------------
GM_addStyle(`
.fb-enhancer-btn { position:fixed; top:60px; right:10px; background:#4267B2; color:#fff; padding:6px 10px;
border-radius:6px; z-index:999999; cursor:pointer; font-weight:bold; user-select:none; }
.fb-enhancer-panel { position:fixed; top:110px; right:10px; z-index:999999; background:#fff; color:#111;
padding:10px; width:340px; max-height:70vh; overflow:auto; border:1px solid #ccc; border-radius:8px; font-size:14px; display:none; }
.fb-enhancer-panel h3 { margin: 0 0 8px; }
.fb-enhancer-group { margin:8px 0; padding:8px; border:1px dashed #ddd; border-radius:6px; }
.fb-enhancer-row { display:flex; align-items:center; gap:8px; margin:6px 0; }
.fb-enhancer-row label { flex: 1; }
.fb-enhancer-actions { margin-top:8px; display:flex; gap:8px; flex-wrap:wrap; }
html.fb-dark-mode { filter: invert(1) hue-rotate(180deg); } /* cheap global dark flip */
html.fb-dark-mode img, html.fb-dark-mode video { filter: invert(1) hue-rotate(180deg); }
.fe-blur { filter: blur(10px) opacity(.35); pointer-events:none; }
.fe-review { outline: 2px dashed #f36 !important; position: relative; }
.fe-review::after {
content: 'FB Enhancer: hidden';
position: absolute; top: -10px; left: -2px; font-size: 11px;
background: #f36; color: #fff; padding: 0 4px; border-radius: 3px;
}
body.fe-show-hidden [data-fbEnhanced="1"] { display: initial !important; visibility: visible !important; }
/* Per-post control */
.fe-hide-btn {
position:absolute; top:6px; right:6px; z-index:9999; font-size:12px;
background:rgba(66,103,178,.95); color:#fff; border:none; border-radius:4px; padding:3px 6px;
cursor:pointer; display:none;
}
[role="article"]:hover .fe-hide-btn { display:block; }
`);
// -----------------------
// Visual Modes / Custom CSS
// -----------------------
function applyCustomCSS() {
const id = 'fb-enhancer-custom-style';
document.getElementById(id)?.remove();
if (settings.customCSS) {
const style = document.createElement('style');
style.id = id;
style.textContent = settings.customCSS;
document.head.appendChild(style);
}
}
function applyVisualModes() {
// Dark
if (settings.forceDarkMode) document.documentElement.classList.add('fb-dark-mode');
else document.documentElement.classList.remove('fb-dark-mode');
// Show hidden
document.body.classList.toggle('fe-show-hidden', !!settings.showHidden);
}
// -----------------------
// UI: Gear + Panel
// -----------------------
const ui = { btn:null, panel:null, toggle(){ ui.panel.style.display = ui.panel.style.display === 'none' ? 'block' : 'none'; } };
function addRow(container, key, label, type = 'boolean', placeholder = '') {
const row = document.createElement('div');
row.className = 'fb-enhancer-row';
const id = `fe_${key}`;
if (type === 'boolean') {
row.innerHTML = `<label><input type="checkbox" id="${id}" ${settings[key] ? 'checked' : ''}/> ${label}</label>`;
} else {
row.innerHTML = `<label>${label}</label><input type="text" id="${id}" value="${settings[key] ?? ''}" placeholder="${placeholder}" style="flex:2;">`;
}
container.appendChild(row);
return id;
}
function createSettingsMenu() {
// Button
const button = document.createElement('div');
button.textContent = '⚙ Enhancer';
button.className = 'fb-enhancer-btn';
button.id = 'fb-enhancer-toggle';
// Panel
const panel = document.createElement('div');
panel.id = 'fb-enhancer-panel';
panel.className = 'fb-enhancer-panel';
const root = document.createElement('div');
root.innerHTML = `<h3>Facebook Enhancer</h3>`;
// Groups
const gGeneral = document.createElement('div'); gGeneral.className = 'fb-enhancer-group';
gGeneral.innerHTML = `<strong>General / Visual</strong>`;
addRow(gGeneral, 'debugMode', 'Enable debug logs');
addRow(gGeneral, 'softRemove', 'Soft remove (display:none) instead of remove()');
addRow(gGeneral, 'blurHidden', 'Blur hidden items (reviewable)');
addRow(gGeneral, 'reviewMode', 'Outline hidden items (debug)');
addRow(gGeneral, 'showHidden', 'Temporarily show hidden items');
addRow(gGeneral, 'forceDarkMode', 'Force Dark Mode (CSS invert)');
addRow(gGeneral, 'customCSS', 'Custom CSS', 'text', '/* your CSS here */');
const gFeed = document.createElement('div'); gFeed.className = 'fb-enhancer-group';
gFeed.innerHTML = `<strong>Feed & Hiding</strong>`;
addRow(gFeed, 'blockSponsored', 'Hide Sponsored posts');
addRow(gFeed, 'blockSuggested', 'Hide Suggested for you');
addRow(gFeed, 'hideReels', 'Hide Reels modules');
addRow(gFeed, 'hideReelLinks', 'Hide units that contain /reel/ links');
addRow(gFeed, 'aggressiveReelsBlock', 'Aggressive Reels heuristics');
addRow(gFeed, 'reelsHeadingPhrases', 'Reels heading phrases (comma)', 'text', 'reels,reels and short videos,short videos');
addRow(gFeed, 'hideStories', 'Hide Stories');
addRow(gFeed, 'hidePeopleYouMayKnow', 'Hide People You May Know');
addRow(gFeed, 'hideRightRailAds', 'Hide Right Rail Ads');
addRow(gFeed, 'keywordFilter', 'Keyword filter (comma-separated)', 'text', 'kardashian,tiktok,reaction');
addRow(gFeed, 'keywordRegex', 'Keyword Regex (optional)', 'text', '(giveaway|crypto)\\b');
const gVideo = document.createElement('div'); gVideo.className = 'fb-enhancer-group';
gVideo.innerHTML = `<strong>Video</strong>`;
addRow(gVideo, 'disableAutoplay', 'Disable autoplay');
addRow(gVideo, 'muteVideos', 'Mute videos');
const gNav = document.createElement('div'); gNav.className = 'fb-enhancer-group';
gNav.innerHTML = `<strong>Navigation / Sidebar</strong>`;
addRow(gNav, 'toggleMarketplace', 'Hide Marketplace');
addRow(gNav, 'toggleEvents', 'Hide Events');
addRow(gNav, 'toggleShortcuts', 'Hide Your Shortcuts');
const gBehavior = document.createElement('div'); gBehavior.className = 'fb-enhancer-group';
gBehavior.innerHTML = `<strong>Behavior</strong>`;
addRow(gBehavior, 'unwrapLinks', 'Unwrap tracking links on click');
addRow(gBehavior, 'unwrapOnHover', 'Unwrap on hover (riskier—leave off)');
addRow(gBehavior, 'autoExpandComments', 'Auto-expand comments');
addRow(gBehavior, 'forceMostRecentFeed', 'Force Most Recent feed');
addRow(gBehavior, 'mostRecentRetryMs', 'Most Recent retry (ms)', 'text', '4000');
const gHotkeys = document.createElement('div'); gHotkeys.className = 'fb-enhancer-group';
gHotkeys.innerHTML = `<strong>Hotkeys</strong>`;
addRow(gHotkeys, 'gearHotkey', 'Toggle panel hotkey', 'text', 'Alt+E');
addRow(gHotkeys, 'forceMostRecentHotkey', 'Force Most Recent hotkey', 'text', 'Alt+R');
addRow(gHotkeys, 'showHiddenHotkey', 'Toggle "Show Hidden" hotkey', 'text', 'Alt+H');
root.append(gGeneral, gFeed, gVideo, gNav, gBehavior, gHotkeys);
const actions = document.createElement('div');
actions.className = 'fb-enhancer-actions';
actions.innerHTML = `
<button id="fe-save">Save</button>
<button id="fe-reset">Reset</button>
<button id="fe-export">Export</button>
<button id="fe-import">Import</button>
`;
root.appendChild(actions);
panel.appendChild(root);
document.body.append(button, panel);
restorePosition(button, 'gear');
restorePosition(panel, 'panel');
button.onclick = () => ui.toggle();
makeDraggable(button, 'gear');
makeDraggable(panel, 'panel');
document.getElementById('fe-save').onclick = () => {
const collect = (key) => {
const el = document.getElementById(`fe_${key}`);
if (!el) return;
if (el.type === 'checkbox') settings[key] = el.checked;
else {
const val = el.value;
if (key === 'mostRecentRetryMs') settings[key] = Math.max(1000, parseInt(val || '4000', 10) || 4000);
else settings[key] = val;
}
};
Object.keys(defaultSettings).forEach(collect);
saveSettings();
applyCustomCSS();
alert('Settings saved. Reloading…');
location.reload();
};
document.getElementById('fe-reset').onclick = () => {
localStorage.removeItem(STORAGE_KEY);
localStorage.removeItem(POS_KEY);
alert('Settings reset. Reloading…');
location.reload();
};
document.getElementById('fe-export').onclick = () => {
const blob = new Blob([JSON.stringify(settings, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = Object.assign(document.createElement('a'), { href: url, download: 'fb-enhancer-settings.json' });
document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url);
};
document.getElementById('fe-import').onclick = () => {
const input = document.createElement('input');
input.type = 'file'; input.accept = 'application/json';
input.onchange = () => {
const file = input.files && input.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = () => {
try {
const obj = JSON.parse(reader.result);
localStorage.setItem(STORAGE_KEY, JSON.stringify(Object.assign({}, defaultSettings, obj)));
alert('Imported. Reloading…'); location.reload();
} catch { alert('Invalid JSON.'); }
};
reader.readAsText(file);
};
input.click();
};
ui.btn = button;
ui.panel = panel;
if (typeof GM_registerMenuCommand === 'function') {
GM_registerMenuCommand('Toggle Enhancer Panel', () => ui.toggle());
GM_registerMenuCommand('Export Settings', () => document.getElementById('fe-export').click());
GM_registerMenuCommand('Import Settings', () => document.getElementById('fe-import').click());
GM_registerMenuCommand('Toggle Show Hidden', () => {
settings.showHidden = !settings.showHidden; saveSettings();
});
}
}
function makeDraggable(el, key) {
let offsetX = 0, offsetY = 0, isDragging = false;
el.style.position = 'fixed';
el.addEventListener('mousedown', e => {
isDragging = true;
offsetX = e.clientX - el.getBoundingClientRect().left;
offsetY = e.clientY - el.getBoundingClientRect().top;
e.preventDefault();
});
document.addEventListener('mousemove', e => {
if (!isDragging) return;
el.style.left = `${e.clientX - offsetX}px`;
el.style.top = `${e.clientY - offsetY}px`;
el.style.right = 'auto';
el.style.bottom = 'auto';
});
document.addEventListener('mouseup', () => {
if (!isDragging) return;
isDragging = false;
const rect = el.getBoundingClientRect();
positions[key] = { left: rect.left, top: rect.top };
savePositions();
});
}
function restorePosition(el, key) {
const pos = positions[key];
if (pos) {
el.style.left = `${pos.left}px`;
el.style.top = `${pos.top}px`;
el.style.right = 'auto';
el.style.bottom = 'auto';
}
}
// -----------------------
// Link unwrapping
// -----------------------
function unwrapUrl(href) {
try {
const u = new URL(href, location.origin);
if ((u.hostname || '').includes('l.facebook.com') && u.pathname.startsWith('/l.php')) {
const real = u.searchParams.get('u');
if (real) return decodeURIComponent(real);
}
} catch {}
return href;
}
function installLinkHandlers() {
if (!settings.unwrapLinks) return;
document.addEventListener('click', e => {
const a = e.target.closest('a[href]');
if (!a) return;
const newHref = unwrapUrl(a.getAttribute('href') || '');
if (newHref && newHref !== a.href) {
a.setAttribute('href', newHref);
log('Unwrapped link on click:', newHref);
}
}, true);
if (settings.unwrapOnHover) {
document.addEventListener('mouseover', e => {
const a = e.target.closest('a[href]');
if (!a) return;
const newHref = unwrapUrl(a.getAttribute('href') || '');
if (newHref && newHref !== a.href) a.setAttribute('href', newHref);
}, true);
}
}
// -----------------------
// Video control
// -----------------------
function handleVideo(video) {
if (video.dataset.fbEnhanced === 'v') return;
if (settings.muteVideos) video.muted = true;
if (settings.disableAutoplay) {
video.removeAttribute('autoplay');
if (!video.paused) video.pause();
}
video.dataset.fbEnhanced = 'v';
}
function scanVideos(root = document) {
root.querySelectorAll('video:not([data-fb-enhanced="v"])').forEach(handleVideo);
}
function pauseVideosOffscreen() {
if (!settings.disableAutoplay) return;
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
window.requestAnimationFrame(() => {
document.querySelectorAll('video').forEach(video => {
const rect = video.getBoundingClientRect();
const inView = rect.top >= 0 && rect.bottom <= window.innerHeight;
if (!inView && !video.paused) {
video.pause();
log('Paused offscreen video');
}
});
ticking = false;
});
ticking = true;
}
}, { passive: true });
}
// -----------------------
// Post filtering
// -----------------------
const sponsoredWords = [
'sponsored','publicidad','gesponsert','sponsorisé','patrocinado',
'patrocinada','sponsorizzato','gesponsord'
];
function appearsSponsored(el) {
const text = (el.innerText || el.textContent || '').toLowerCase();
return sponsoredWords.some(w => text.includes(w));
}
function matchesKeyword(text) {
if (!text) return false;
const hay = text.toLowerCase();
const list = (settings.keywordFilter || '')
.split(',').map(s => s.trim()).filter(Boolean);
if (list.some(k => hay.includes(k.toLowerCase()))) return true;
if (settings.keywordRegex) {
try { return new RegExp(settings.keywordRegex, 'i').test(text); }
catch { /* invalid regex ignored */ }
}
return false;
}
function processArticle(article) {
if (article.dataset.fbEnhanced === 'a') return;
try {
const text = (article.innerText || '');
if (settings.blockSponsored && appearsSponsored(article)) { softOrHardRemove(article); return; }
if (settings.blockSuggested && /suggested for you/i.test(text)) { softOrHardRemove(article); return; }
if (matchesKeyword(text)) { softOrHardRemove(article); return; }
if (settings.autoExpandComments) {
article.querySelectorAll('div[role="button"]').forEach(btn => {
if (/view (more )?comments|replies/i.test(btn.textContent)) btn.click();
});
}
installPerPostHideControl(article);
} catch (err) { log('Article error:', err); }
article.dataset.fbEnhanced = 'a';
}
function installPerPostHideControl(article) {
if (article.querySelector('.fe-hide-btn')) return;
article.style.position = article.style.position || 'relative';
const btn = document.createElement('button');
btn.className = 'fe-hide-btn';
btn.textContent = 'Hide posts like this';
btn.addEventListener('click', (e) => {
e.stopPropagation();
const base = buildKeywordSuggestion((article.innerText || ''));
const user = prompt('Add keywords (comma-separated). These will be appended to your filter:', base);
if (!user) return;
const existing = new Set((settings.keywordFilter || '').split(',')
.map(s=>s.trim()).filter(Boolean).map(s=>s.toLowerCase()));
user.split(',').map(s=>s.trim()).filter(Boolean).forEach(k => existing.add(k.toLowerCase()));
settings.keywordFilter = Array.from(existing).join(',');
saveSettings();
sweepAll();
alert('Added. Filter updated.');
});
article.appendChild(btn);
}
function buildKeywordSuggestion(text) {
const stop = new Set(('the,a,an,and,or,for,with,from,that,this,those,these,of,to,at,by,on,in,is,are,was,were,be,been,am,as,it,if,not,no,yes,do,does,did,you,your,me,my,our,we,they,them,he,she,his,her,him,who,what,when,where,why,how,about,into,over,under,more,most,so,just,can,will,up,down,out,get,got,have,has,had'
+ ',http,https,www,com,net,org,facebook,reel,reels,video,watch,like,share,comment').split(','));
const words = (text.toLowerCase().match(/[a-z0-9]+/g) || [])
.filter(w => w.length >= 4 && !stop.has(w));
const freq = new Map();
for (const w of words) freq.set(w, (freq.get(w) || 0) + 1);
const picks = Array.from(freq.entries()).sort((a,b)=>b[1]-a[1]).slice(0,5).map(([w])=>w);
return picks.join(',');
}
// -----------------------
// Hide helpers / modes
// -----------------------
function softOrHardRemove(el) {
if (!el || el.dataset.fbEnhanced === '1') return;
if (settings.blurHidden) {
el.classList.add('fe-blur');
} else if (settings.softRemove) {
el.style.display = 'none';
} else {
el.remove();
}
if (settings.reviewMode) el.classList.add('fe-review');
el.dataset.fbEnhanced = '1';
}
// -----------------------
// Reels / Stories / PYMK / Nav
// -----------------------
function closestContentContainer(el) {
return el.closest('div[data-pagelet]') ||
el.closest('[role="article"]') ||
el.closest('section') ||
el.closest('div[role="complementary"]') ||
el;
}
function isReelsHeadingText(txt) {
if (!txt) return false;
const hay = String(txt).toLowerCase();
return (settings.reelsHeadingPhrases || '')
.split(',').map(s => s.trim()).filter(Boolean)
.some(needle => hay.includes(needle));
}
function isLikelyReelsUnit(node) {
try {
const text = (node.innerText || node.textContent || '').trim();
const vids = node.querySelectorAll('video').length;
if (isReelsHeadingText(text) && vids >= 2) return true;
const dp = node.getAttribute && (node.getAttribute('data-pagelet') || '');
if (/Reel|Reels|VideoHome|HomeUnit|video/i.test(dp)) return true;
if (settings.aggressiveReelsBlock && vids >= 3) return true;
return false;
} catch { return false; }
}
function hideReels() {
if (!settings.hideReels) return;
// Headings / modules
document.querySelectorAll('h2, h3, [role="heading"], [aria-label], div[data-pagelet]').forEach(el => {
const label = el.getAttribute?.('aria-label') || el.textContent || '';
if (!label) return;
if (isReelsHeadingText(label) || isLikelyReelsUnit(el)) {
const box = closestContentContainer(el);
if (box && box.dataset.fbEnhanced !== '1') {
softOrHardRemove(box);
log('Reels module removed');
}
}
});
// Horizontal scrollers in feed
document.querySelectorAll('[role="feed"] div').forEach(el => {
if (el.dataset.fbEnhanced === '1') return;
if (isLikelyReelsUnit(el)) softOrHardRemove(closestContentContainer(el));
});
// Right rail
document.querySelectorAll('div[data-pagelet*="RightRail"], [role="complementary"]').forEach(el => {
if (el.dataset.fbEnhanced === '1') return;
if (isLikelyReelsUnit(el)) softOrHardRemove(closestContentContainer(el));
});
}
function hideReelLinksSweep(root = document) {
if (!settings.hideReelLinks) return;
root.querySelectorAll('a[href*="/reel/"], a[href*="/reels/"]').forEach(a => {
const box = closestContentContainer(a);
if (box && box.dataset.fbEnhanced !== '1') {
softOrHardRemove(box);
log('Reel link unit removed');
}
});
}
function hideStories() {
if (!settings.hideStories) return;
document.querySelectorAll('div[aria-label="Stories"], div[data-pagelet*="Stories"]').forEach(softOrHardRemove);
}
function hidePeopleYouMayKnow() {
if (!settings.hidePeopleYouMayKnow) return;
document.querySelectorAll('[role="feed"] div').forEach(block => {
const text = (block.innerText || '').toLowerCase();
const hasButtons = [...block.querySelectorAll('button')].some(b => (b.innerText || '').toLowerCase().includes('add friend'));
if (text.includes('people you may know') && hasButtons) softOrHardRemove(block);
});
}
function hideRightRailAds() {
if (!settings.hideRightRailAds) return;
document.querySelectorAll('div[data-pagelet*="RightRail"]').forEach(node => {
if (appearsSponsored(node)) softOrHardRemove(node);
});
}
function collapseSidebarSections() {
const map = {
toggleMarketplace: 'marketplace',
toggleEvents: 'events',
toggleShortcuts: 'your shortcuts'
};
for (let key in map) {
if (!settings[key]) continue;
const matchText = map[key];
document.querySelectorAll('span, div').forEach(el => {
const txt = (el.textContent || '').toLowerCase();
if (!txt || !txt.includes(matchText)) return;
const container = el.closest('ul') || el.closest('li') || el.closest('div[role="navigation"]');
if (container) softOrHardRemove(container);
});
}
}
// -----------------------
// Force Most Recent (sticky)
// -----------------------
let mostRecentTimer = null;
function forceMostRecent() {
if (!settings.forceMostRecentFeed) return;
const link = document.querySelector('a[href*="sk=h_chr"]');
if (link) { link.click(); log('Forcing Most Recent…'); }
}
function patchHistoryEvents() {
try {
const push = history.pushState;
history.pushState = function() { const r = push.apply(this, arguments); window.dispatchEvent(new Event('pushstate')); return r; };
const rep = history.replaceState;
history.replaceState = function() { const r = rep.apply(this, arguments); window.dispatchEvent(new Event('replacestate')); return r; };
} catch {}
}
function startMostRecentSticky() {
if (!settings.forceMostRecentFeed) return;
clearInterval(mostRecentTimer);
mostRecentTimer = setInterval(forceMostRecent, Math.max(1000, settings.mostRecentRetryMs | 0 || 4000));
window.addEventListener('popstate', () => setTimeout(forceMostRecent, 350));
window.addEventListener('pushstate', () => setTimeout(forceMostRecent, 350));
window.addEventListener('replacestate', () => setTimeout(forceMostRecent, 350));
}
// -----------------------
// Observers (throttled)
// -----------------------
const processMutations = throttle((mutations) => {
for (const m of mutations) {
m.addedNodes.forEach(node => {
if (node.nodeType !== 1) return;
if (node.getAttribute?.('role') === 'article') processArticle(node);
node.querySelectorAll?.('[role="article"]').forEach(processArticle);
if (node.matches?.('video')) handleVideo(node);
node.querySelectorAll?.('video').forEach(handleVideo);
});
}
hideReels();
hideReelLinksSweep();
hideStories();
hidePeopleYouMayKnow();
hideRightRailAds();
collapseSidebarSections();
}, 500);
function observePage() {
const mo = new MutationObserver(processMutations);
mo.observe(document.body, { childList: true, subtree: true });
// initial pass
document.querySelectorAll('[role="article"]').forEach(processArticle);
scanVideos();
hideReels();
hideReelLinksSweep();
hideStories();
hidePeopleYouMayKnow();
hideRightRailAds();
collapseSidebarSections();
}
function sweepAll() {
document.querySelectorAll('[role="article"]').forEach(a => { a.dataset.fbEnhanced = ''; processArticle(a); });
hideReels(); hideReelLinksSweep(); hideStories(); hidePeopleYouMayKnow(); hideRightRailAds(); collapseSidebarSections();
}
// -----------------------
// Hotkeys
// -----------------------
function parseHotkey(s) {
const parts = (s || '').toLowerCase().split('+').map(p => p.trim()).filter(Boolean);
return {
alt: parts.includes('alt'),
ctrl: parts.includes('ctrl') || parts.includes('control'),
shift: parts.includes('shift'),
key: parts[parts.length - 1] || ''
};
}
const hkPanel = parseHotkey(settings.gearHotkey);
const hkMostRecent = parseHotkey(settings.forceMostRecentHotkey);
const hkShowHidden = parseHotkey(settings.showHiddenHotkey);
document.addEventListener('keydown', (e) => {
const k = e.key.toLowerCase();
const match = (hk) => (!!hk.alt === e.altKey) && (!!hk.ctrl === e.ctrlKey) && (!!hk.shift === e.shiftKey) && (hk.key === k);
if (match(hkPanel)) { e.preventDefault(); ui.toggle(); }
if (match(hkMostRecent)) { e.preventDefault(); forceMostRecent(); }
if (match(hkShowHidden)) { e.preventDefault(); settings.showHidden = !settings.showHidden; saveSettings(); }
});
// -----------------------
// Init
// -----------------------
function init() {
applyCustomCSS();
createSettingsMenu();
applyVisualModes();
installLinkHandlers();
observePage();
pauseVideosOffscreen();
patchHistoryEvents();
startMostRecentSticky();
setInterval(() => { hideReels(); hideReelLinksSweep(); }, 5000); // periodic safety sweep
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init, { once: true });
} else {
init();
}
})();