当访问小红书首页时自动移除个性化推送
// ==UserScript==
// @name Remove Xiaohongshu Recommended Feeds
// @name:zh-CN 移除小红书首页的个性化推送
// @description Automatically removes recommended content from Xiaohongshu homepage
// @description:zh-CN 当访问小红书首页时自动移除个性化推送
// @namespace https://github.com/
// @version 1.2.0.20250429
// @author Konano
// @homepageURL https://github.com/Konano/greasyfork-script
// @match https://www.xiaohongshu.com/*
// @icon https://www.xiaohongshu.com/favicon.ico
// @license MIT
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
// DOM MANIPULATION SECTION
// -----------------------
// Function to remove recommended feed elements
function removeRecommendedElements() {
// Track removed elements to avoid processing them multiple times
const elementsToRemove = [
{ selector: '#exploreFeeds', logMessage: 'Removed exploreFeeds element' },
{ selector: '#homefeed_recommend', logMessage: 'Removed homefeed_recommend element' },
{ selector: '[id^="homefeed."]', logMessage: 'Removed element with ID starting with "homefeed."', isQuerySelector: true }
];
elementsToRemove.forEach(item => {
const elements = item.isQuerySelector ?
document.querySelectorAll(item.selector) :
[document.querySelector(item.selector)].filter(Boolean);
elements.forEach(element => {
if (!element.dataset.removed) {
element.remove();
console.log(item.logMessage);
element.dataset.removed = 'true';
}
});
});
}
// Execute after page load
window.addEventListener('load', removeRecommendedElements);
// Monitor DOM changes to remove newly added elements
const domObserver = new MutationObserver(removeRecommendedElements);
domObserver.observe(document.documentElement, {
childList: true,
subtree: true
});
// INITIAL STATE MODIFICATION SECTION
// ---------------------------------
// Process inline script content to remove feed data
function processScriptContent(scriptElement) {
const content = scriptElement.textContent || '';
if (content.includes('window.__INITIAL_STATE__')) {
console.log('Found INITIAL_STATE script!');
// Remove feed data from the script content
scriptElement.textContent = scriptElement.textContent.replace(
/"feeds":\[\{.*?\}\],"currentChannel"/g,
'"feeds":[],"currentChannel"'
);
// Log the modified state if available
if (window.__INITIAL_STATE__) {
console.log('Modified INITIAL_STATE');
}
}
return scriptElement;
}
// Monitor for script elements being added to the page
const scriptObserver = new MutationObserver(mutations => {
for (const mutation of mutations) {
if (mutation.addedNodes && mutation.addedNodes.length) {
for (const node of mutation.addedNodes) {
if (node.nodeName === 'SCRIPT') {
processScriptContent(node);
} else if (node.querySelectorAll) {
const scripts = node.querySelectorAll('script');
scripts.forEach(script => processScriptContent(script));
// // Check if state is available and log feeds
// if (window.__INITIAL_STATE__?.feed) {
// console.log('Current feed state:', window.__INITIAL_STATE__.feed.feeds);
// }
}
}
}
}
});
scriptObserver.observe(document, {
childList: true,
subtree: true
});
// NETWORK REQUEST INTERCEPTION SECTION
// ----------------------------------
// Empty response for blocked requests
const emptyFeedResponse = '{"success":true,"data":{"items":[]}}';
// Block fetch requests to homefeed endpoint
const originalFetch = window.fetch;
window.fetch = function(input, init) {
if (typeof input === 'string' &&
input.endsWith('/homefeed') &&
init?.method?.toUpperCase() === 'POST') {
console.log('Blocked fetch request to ' + input);
return Promise.resolve(new Response(emptyFeedResponse, {
status: 200,
headers: {'Content-Type': 'application/json'}
}));
}
return originalFetch.apply(this, arguments);
};
// Block XMLHttpRequest to homefeed endpoint
const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url) {
const xhr = this;
if (typeof url === 'string' &&
url.endsWith('/homefeed') &&
method.toUpperCase() === 'POST') {
xhr._blockedHomefeed = true;
console.log('Blocked XMLHttpRequest to ' + url);
// Override send method for this specific XHR instance
xhr.send = function() {
setTimeout(function() {
// Set up fake successful response
Object.defineProperty(xhr, 'responseText', {
value: emptyFeedResponse,
writable: false
});
Object.defineProperty(xhr, 'status', {
value: 200,
writable: false
});
// Trigger appropriate callbacks
if (xhr.onreadystatechange) {
Object.defineProperty(xhr, 'readyState', { value: 4 });
xhr.onreadystatechange();
}
if (xhr.onload) xhr.onload();
// Dispatch events
xhr.dispatchEvent(new Event('load'));
xhr.dispatchEvent(new Event('loadend'));
}, 0);
};
}
return originalOpen.apply(this, arguments);
};
})();