您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Home opens the chronological Following feed. Reels shows as “Stories” (keeps the original Reels icon) and opens real Home (/) with posts hidden. Any /reels URL hard-redirects to Stories-only. Stories-only turns off away from "/".
// ==UserScript== // @name Instagram Chronological Feed + Stories // @namespace ig-home-following-reels-stories // @version 3.5 // @description Home opens the chronological Following feed. Reels shows as “Stories” (keeps the original Reels icon) and opens real Home (/) with posts hidden. Any /reels URL hard-redirects to Stories-only. Stories-only turns off away from "/". // @match https://www.instagram.com/* // @run-at document-start // @grant none // @license MIT // ==/UserScript== (() => { 'use strict'; /* ───────── Config & helpers ───────── */ const FOLLOWING_URL = 'https://www.instagram.com/?variant=following'; const STORY_FLAG_SS = 'tmStoriesOnly'; // sessionStorage flag const STORY_FLAG_LS = 'tmStoriesOnlyOnce'; // localStorage one-shot const STORY_HASH = '#tmso'; // URL hash marks stories-only const NAME_TAG = '[TM_SO]'; // window.name marker const isRoot = () => location.pathname === '/'; const onFollowing = () => location.search.startsWith('?variant=following'); const inStoriesOnly = () => sessionStorage.getItem(STORY_FLAG_SS) === '1'; const log = (...a) => console.info('[IG-TM]', ...a); /* ───────── EARLY: hard-redirect every /reels* path to Stories-only Home ───────── */ if (/^\/reels(\/|$)/.test(location.pathname)) { try { sessionStorage.setItem(STORY_FLAG_SS, '1'); localStorage.setItem(STORY_FLAG_LS, '1'); if (!String(window.name).includes(NAME_TAG)) window.name = NAME_TAG + window.name; } catch {} location.replace('/' + STORY_HASH); return; } /* ───────── CSS: hide posts in stories-only ───────── */ (function addStyles() { const style = document.createElement('style'); style.textContent = ` .tm-stories-only main article { display: none !important; } .tm-stories-only main { min-height: 0 !important; } `; document.documentElement.appendChild(style); })(); /* ───────── Hiding engine ───────── */ let mo = null; function hidePostsOnce() { if (!document.documentElement.classList.contains('tm-stories-only')) return; document.querySelectorAll('main article').forEach(el => { if (el.dataset.tmHidden) return; el.dataset.tmHidden = '1'; el.style.display = 'none'; el.setAttribute('aria-hidden', 'true'); }); } function startHiding() { hidePostsOnce(); if (mo) return; mo = new MutationObserver(() => { if (inStoriesOnly()) hidePostsOnce(); }); mo.observe(document.body, { childList: true, subtree: true }); } function stopHiding() { if (mo) { mo.disconnect(); mo = null; } document.querySelectorAll('main article[data-tm-hidden="1"]').forEach(el => { el.style.display = ''; el.removeAttribute('aria-hidden'); delete el.dataset.tmHidden; }); } function clearIntentSignals() { sessionStorage.removeItem(STORY_FLAG_SS); localStorage.removeItem(STORY_FLAG_LS); try { if (String(window.name).includes(NAME_TAG)) window.name = String(window.name).replace(NAME_TAG, ''); } catch {} } function setStoriesOnly(on) { if (on) { sessionStorage.setItem(STORY_FLAG_SS, '1'); document.documentElement.classList.add('tm-stories-only'); startHiding(); log('Stories-only ON'); } else { document.documentElement.classList.remove('tm-stories-only'); stopHiding(); clearIntentSignals(); log('Stories-only OFF'); } } /* ───────── Multi-signal intent for next “/” ───────── */ function setIntentForNextRoot() { sessionStorage.setItem(STORY_FLAG_SS, '1'); // in-tab localStorage.setItem(STORY_FLAG_LS, '1'); // one-shot try { if (!String(window.name).includes(NAME_TAG)) window.name = NAME_TAG + window.name; } catch {} } function hasAndConsumeIntentFromURL() { if (location.hash === STORY_HASH) { history.replaceState(history.state, '', location.pathname + location.search); return true; } return false; } function hasAndConsumeIntentFromName() { try { if (String(window.name).includes(NAME_TAG)) { window.name = String(window.name).replace(NAME_TAG, ''); return true; } } catch {} return false; } function hasAndConsumeIntentFromLS() { if (localStorage.getItem(STORY_FLAG_LS) === '1') { localStorage.removeItem(STORY_FLAG_LS); return true; } return false; } function consumeAnyIntent() { const signaled = inStoriesOnly() || hasAndConsumeIntentFromURL() || hasAndConsumeIntentFromName() || hasAndConsumeIntentFromLS(); if (signaled) sessionStorage.setItem(STORY_FLAG_SS, '1'); return signaled; } /* ───────── Apply policy for current URL ───────── */ function applyPolicyForLocation() { if (onFollowing()) { setStoriesOnly(false); return; } // never hide posts on Following if (isRoot()) { if (consumeAnyIntent()) setStoriesOnly(true); else location.replace(FOLLOWING_URL); return; } if (inStoriesOnly()) setStoriesOnly(false); } /* ───────── Relabel ONLY the primary sidebar Reels (with SVG) ───────── */ function relabelPrimaryReelsAnchor(a) { // Keep classes/href (preserves icon + styling). Only change visible label. // Find the first text node inside the anchor that equals "Reels". const textHolder = [...a.querySelectorAll('span, div')] .find(n => n.childElementCount === 0 && n.textContent.trim() === 'Reels'); if (textHolder) textHolder.textContent = 'Stories'; // Keep the SVG as-is so the icon remains the Reels glyph. // (Optionally adjust accessibility text—commented out to avoid A/B conflicts) // const svg = a.querySelector('svg[aria-label="Reels"]'); // if (svg) { // svg.setAttribute('aria-label', 'Stories'); // const title = svg.querySelector('title'); if (title) title.textContent = 'Stories'; // } a.dataset.tmLabeled = '1'; } /* ───────── Wire Home / Reels (icon item only) ───────── */ function wireNavOnce(root = document) { // HOME → Following root.querySelectorAll('a[href="/"]:not([data-tm-wired])').forEach(a => { a.dataset.tmWired = '1'; a.addEventListener('click', (ev) => { ev.preventDefault(); setStoriesOnly(false); location.assign(FOLLOWING_URL); }, { capture: true }); }); // PRIMARY REELS ITEM: must contain the Reels SVG → relabel to "Stories", keep icon root.querySelectorAll('a[href^="/reels"]:not([data-tm-wired])').forEach(a => { const hasIcon = !!a.querySelector('svg[aria-label="Reels"], svg title'); if (!hasIcon) return; // skip text-only Reels links a.dataset.tmWired = '1'; if (!a.dataset.tmLabeled) relabelPrimaryReelsAnchor(a); // Intercept clicks to go to stories-only Home a.addEventListener('click', (ev) => { ev.preventDefault(); setIntentForNextRoot(); location.assign('/' + STORY_HASH); }, { capture: true }); }); // TEXT-ONLY / OTHER Reels links (no SVG): intercept click but do not relabel root.querySelectorAll('a[href^="/reels"]:not([data-tm-wired-text])').forEach(a => { if (a.querySelector('svg[aria-label="Reels"], svg title')) return; // handled above a.dataset.tmWiredText = '1'; a.addEventListener('click', (ev) => { ev.preventDefault(); setIntentForNextRoot(); location.assign('/' + STORY_HASH); }, { capture: true }); }); } wireNavOnce(); new MutationObserver(m => { for (const rec of m) for (const n of rec.addedNodes || []) if (n.nodeType === 1) wireNavOnce(n); }).observe(document.documentElement, { childList: true, subtree: true }); /* ───────── Hook SPA navigation ───────── */ (function hookHistory() { const wrap = (fn) => function (...args) { const rv = fn.apply(this, args); queueMicrotask(applyPolicyForLocation); return rv; }; history.pushState = wrap(history.pushState.bind(history)); history.replaceState = wrap(history.replaceState.bind(history)); })(); window.addEventListener('popstate', applyPolicyForLocation); // Initial pass applyPolicyForLocation(); // Keep enforcing hiding if IG swaps content without URL change new MutationObserver(() => { if (isRoot() && inStoriesOnly()) startHiding(); }).observe(document.body, { childList: true, subtree: true }); })();