屏蔽 CSDN

屏蔽 CSDN 及其它垃圾信息

  1. // ==UserScript==
  2. // @name 屏蔽 CSDN
  3. // @version 1.1.3
  4. // @author aaron yan
  5. // @description 屏蔽 CSDN 及其它垃圾信息
  6. // @match https://www.baidu.com
  7. // @match https://www.baidu.com/s*
  8. // @match https://www.google.com
  9. // @match https://www.google.com/search*
  10. // @match https://www.google.com.hk/search*
  11. // @match https://www.google.com.tw/search*
  12. // @grant GM_xmlhttpRequest
  13.  
  14. // @license MIT
  15.  
  16. // @changelog v1.1.0 (2024-01-17)
  17. // 1. 优化代码结构和性能
  18. // 2. 改进屏蔽规则管理
  19. // 3. 去除延时响应
  20. // @namespace https://greasyfork.org/users/1249199
  21. // ==/UserScript==
  22.  
  23. (function () {
  24. // 配置对象
  25. const CONFIG = {
  26. // 搜索引擎配置
  27. engines: {
  28. baidu: {
  29. host: 'baidu.com',
  30. container: '#content_left',
  31. selectors: {
  32. title: ['h3.c-title', '.t', '.tts-title', '.c-gap-right '],
  33. url: '.c-showurl',
  34. result: '.result.c-container, .c-container.new-pmd',
  35. source: 'div[class*="source"]',
  36. searchButton: '#su, input[type="submit"]' // 百度搜索按钮
  37. }
  38. },
  39. google: {
  40. host: 'google.com',
  41. container: '#search',
  42. selectors: {
  43. title: ['.VuuXrf'],
  44. result: '.MjjYud',
  45. searchButton: 'input[name="btnK"], input[type="submit"]' // 谷歌搜索按钮
  46. }
  47. }
  48. },
  49.  
  50. // 屏蔽规则配置
  51. blockRules: {
  52. // 技术网站
  53. tech: [
  54. "CSDN博客", "CSDN技术社区", "csdn.net",
  55. "简书", "PHP中文网",
  56. "Worktile", "慕课网", "知了爱学", "51CTO", "腾讯云计算",
  57. "360Doc", "千锋教育", "筋斗云"
  58. ],
  59. // 下载站点
  60. download: [
  61. "软件园", "下载之家", "下载网",
  62. "华军软件园", "当下软件园", "东坡下载站",
  63. "系统之家", "/soft/"
  64. ],
  65. // 医疗健康
  66. health: [
  67. "百度健康", "快速问医生", "求医网",
  68. "求医问药", "家庭医生", "寻医",
  69. "健康", "健客网", "医生"
  70. ],
  71. // 其他
  72. others: [
  73. "亿速云", "动力节点在线", "IT 技术博客",
  74. "千锋教育", "虎课网", "黑马程序员", "抖音"
  75. ]
  76. },
  77.  
  78. // URL屏蔽规则
  79. blockUrls: [
  80. 'douyin.com'
  81. ]
  82. };
  83.  
  84. // 工具函数
  85. const utils = {
  86. // 防抖函数
  87. debounce(func, wait) {
  88. let timeout;
  89. return function executedFunction(...args) {
  90. const later = () => {
  91. clearTimeout(timeout);
  92. func(...args);
  93. };
  94. clearTimeout(timeout);
  95. timeout = setTimeout(later, wait);
  96. };
  97. },
  98.  
  99. // 日志函数
  100. log(type, message, data = {}) {
  101. const styles = {
  102. block: 'color: #ff6b6b; font-weight: bold',
  103. info: 'color: #4CAF50; font-weight: bold',
  104. error: 'color: #f44336; font-weight: bold'
  105. };
  106. console.log(`%c ${message}`, styles[type]);
  107. },
  108.  
  109. // 获取当前搜索引擎
  110. getCurrentEngine() {
  111. const host = window.location.hostname;
  112. return Object.entries(CONFIG.engines).find(([, config]) =>
  113. host.includes(config.host)
  114. )?.[0];
  115. },
  116.  
  117. // 获取所有屏蔽关键词
  118. getAllBlockedSites() {
  119. return Object.values(CONFIG.blockRules)
  120. .flat()
  121. .filter((value, index, self) => self.indexOf(value) === index);
  122. }
  123. };
  124.  
  125. // 搜索结果处理类
  126. class SearchResultHandler {
  127. constructor(engine) {
  128. this.engine = engine;
  129. this.config = CONFIG.engines[engine];
  130. this.blockedSites = utils.getAllBlockedSites();
  131. }
  132.  
  133. // 检查是否应该屏蔽
  134. shouldBlock(element) {
  135. // 检查标题
  136. const titleSelectors = this.config.selectors.title;
  137. for (const selector of titleSelectors) {
  138. const titleElement = element.querySelector(selector);
  139. if (titleElement && this.blockedSites.some(site =>
  140. titleElement.textContent.trim().includes(site))) {
  141. return true;
  142. }
  143. }
  144.  
  145. // 检查URL(如果有URL选择器)
  146. if (this.config.selectors.url) {
  147. const urlElement = element.querySelector(this.config.selectors.url);
  148. if (urlElement && CONFIG.blockUrls.some(url =>
  149. urlElement.textContent.trim().includes(url))) {
  150. return true;
  151. }
  152. }
  153.  
  154. // 检查来源(如果有source选择器)
  155. if (this.config.selectors.source) {
  156. const sourceElement = element.querySelector(this.config.selectors.source);
  157. if (sourceElement && this.blockedSites.some(site =>
  158. sourceElement.textContent.trim().includes(site))) {
  159. return true;
  160. }
  161. }
  162.  
  163. return false;
  164. }
  165.  
  166. // 移除搜索结果
  167. removeBlockedSites() {
  168. try {
  169. const results = document.querySelectorAll(this.config.selectors.result);
  170. results.forEach(result => {
  171. if (this.shouldBlock(result)) {
  172. const title = result.querySelector(this.config.selectors.title[0])?.textContent.trim();
  173. const source = result.querySelector(this.config.selectors.source)?.textContent.trim();
  174. utils.log('block', 'Blocked:', {
  175. title,
  176. source: source || 'N/A'
  177. });
  178. result.remove();
  179. }
  180. });
  181. } catch (error) {
  182. utils.log('error', `[${this.engine}] Error:`, error);
  183. }
  184. }
  185. }
  186.  
  187. // 观察器类
  188. class ResultObserver {
  189. constructor() {
  190. this.engine = utils.getCurrentEngine();
  191. if (!this.engine) return;
  192.  
  193. this.handler = new SearchResultHandler(this.engine);
  194. this.container = document.querySelector(CONFIG.engines[this.engine].container);
  195. this.observer = null;
  196. }
  197.  
  198. init() {
  199. if (!this.container) return;
  200.  
  201. this.observer = new MutationObserver(() => this.handler.removeBlockedSites());
  202. this.observer.observe(this.container, {
  203. childList: true,
  204. subtree: true
  205. });
  206.  
  207. window.addEventListener('scroll',
  208. () => this.handler.removeBlockedSites(),
  209. { passive: true }
  210. );
  211.  
  212. this.handler.removeBlockedSites();
  213. }
  214.  
  215. reset() {
  216. if (this.observer) {
  217. this.observer.disconnect();
  218. }
  219. this.init();
  220. }
  221. }
  222.  
  223. // 初始化
  224. function init() {
  225. utils.log('info', '⚡ Content Blocker Activated! ⚡');
  226. let observer = null;
  227. let lastUrl = location.href;
  228.  
  229. function tryInit() {
  230. observer = new ResultObserver();
  231. if (observer.container) {
  232. observer.init();
  233. } else {
  234. setTimeout(tryInit, 100);
  235. }
  236. }
  237.  
  238. tryInit();
  239.  
  240. // 监听 URL 变化
  241. setInterval(() => {
  242. if (lastUrl !== location.href) {
  243. lastUrl = location.href;
  244. if (observer) {
  245. observer.reset();
  246. } else {
  247. tryInit();
  248. }
  249. }
  250. }, 1000);
  251.  
  252. // 监听表单提交事件
  253. document.addEventListener('submit', (e) => {
  254. if (e.target.matches('form')) {
  255. setTimeout(() => {
  256. if (observer) {
  257. observer.reset();
  258. } else {
  259. tryInit();
  260. }
  261. }, 500);
  262. }
  263. });
  264.  
  265. // 监听回车键
  266. document.addEventListener('keypress', (e) => {
  267. if (e.key === 'Enter' && (e.target.matches('input[type="text"]') || e.target.matches('input[type="search"]'))) {
  268. setTimeout(() => {
  269. if (observer) {
  270. observer.reset();
  271. } else {
  272. tryInit();
  273. }
  274. }, 500);
  275. }
  276. });
  277. }
  278.  
  279. // 立即执行初始化
  280. init();
  281. })();