避免页面崩溃的动态广告推文识别与隐藏逻辑(推荐标签识别)
// ==UserScript==
// @name Twitter/X 稳定屏蔽广告推文
// @namespace https://x.com
// @version 1.8
// @description 避免页面崩溃的动态广告推文识别与隐藏逻辑(推荐标签识别)
// @author _Sure.Lee
// @match https://twitter.com/*
// @match https://x.com/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
const OBSERVER_CONFIG = { childList: true, subtree: true };
function isPromoted(tweet) {
const labels = tweet.querySelectorAll('div[dir="ltr"]');
return Array.from(labels).some((el) =>
['推荐', 'Promoted', '推薦', '推广'].some(keyword => el.textContent.trim().includes(keyword))
);
}
function hideWithAnimation(tweet) {
if (tweet.dataset.__adHandled) return;
tweet.dataset.__adHandled = 'true';
tweet.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
tweet.style.opacity = '0';
tweet.style.transform = 'scale(0.95)';
setTimeout(() => {
try {
tweet.style.display = 'none'; // 更安全:不直接 remove
console.log('🧹 屏蔽广告推文成功');
} catch (e) {
console.warn('❗️ 删除广告推文失败:', e);
}
}, 600);
}
const visibilityObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const tweet = entry.target;
if (isPromoted(tweet)) {
console.log('👀 发现广告推文,准备屏蔽...');
requestIdleCallback(() => hideWithAnimation(tweet), { timeout: 1000 });
visibilityObserver.unobserve(tweet);
}
}
});
});
function scanTweets() {
const tweets = document.querySelectorAll('article[data-testid="tweet"]');
tweets.forEach((tweet) => {
if (!tweet.dataset.__observing) {
tweet.dataset.__observing = 'true';
visibilityObserver.observe(tweet);
}
});
}
// 启动 MutationObserver 监听动态加载
const mo = new MutationObserver(() => {
requestIdleCallback(scanTweets, { timeout: 500 });
});
mo.observe(document.body, OBSERVER_CONFIG);
// 首次执行
scanTweets();
})();