Guest User

Claude Fable 5.1 & Нейроняша побеждает форсера в войне.

a guest
Sep 4th, 2026
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         2ch: hide posts containing "sosal"/"сосал"
  3. // @namespace    https://2ch.su/
  4. // @version      1.0
  5. // @description  Hides forum messages that contain the word "sosal" or "сосал" (case-insensitive)
  6. // @author       you
  7. // @match        https://2ch.su/*
  8. // @match        https://2ch.hk/*
  9. // @match        https://2ch.life/*
  10. // @match        https://2ch.pm/*
  11. // @run-at       document-end
  12. // @grant        none
  13. // ==/UserScript==
  14.  
  15. (function () {
  16.     'use strict';
  17.  
  18.     // ---------- settings ----------
  19.     // Substring match: also catches "СОСАЛ", "сосалом", "сосала", "sosal'".
  20.     // If you want only the exact whole word, use instead:
  21.     // const FILTER = /(^|[^a-zа-яё])(sosal|сосал)(?![a-zа-яё])/i;
  22.     const FILTER = /(sosal|сосал)/i;
  23.  
  24.     const HIDE_OP_POST = false;   // true = also hide the thread's opening post if it matches
  25.     const REMOVE_FROM_DOM = false; // false = display:none (safer for the site's own JS), true = remove element
  26.     // --------------------------------
  27.  
  28.     const PROCESSED = 'data-sosal-filter-checked';
  29.     let hiddenCount = 0;
  30.  
  31.     function checkPost(post) {
  32.         if (!post || post.hasAttribute(PROCESSED)) return;
  33.         post.setAttribute(PROCESSED, '1');
  34.  
  35.         if (!HIDE_OP_POST && post.classList.contains('post_type_oppost')) return;
  36.  
  37.         const article = post.querySelector('article.post__message');
  38.         if (!article) return;
  39.  
  40.         const text = article.textContent || '';
  41.         if (FILTER.test(text)) {
  42.             if (REMOVE_FROM_DOM) {
  43.                 post.remove();
  44.             } else {
  45.                 post.style.display = 'none';
  46.                 post.classList.add('sosal-filtered');
  47.             }
  48.             hiddenCount++;
  49.             console.log(`[sosal-filter] hidden post #${post.dataset.num} (total: ${hiddenCount})`);
  50.         }
  51.     }
  52.  
  53.     function scan(root) {
  54.         if (!root || root.nodeType !== Node.ELEMENT_NODE) return;
  55.         if (root.matches && root.matches('div.post')) checkPost(root);
  56.         root.querySelectorAll('div.post').forEach(checkPost);
  57.     }
  58.  
  59.     // 1) initial pass over already-rendered posts
  60.     scan(document.body);
  61.  
  62.     // 2) watch for posts added later (auto-refresh, "Обновить", hover previews)
  63.     const observer = new MutationObserver(mutations => {
  64.         for (const m of mutations) {
  65.             for (const node of m.addedNodes) {
  66.                 if (node.nodeType !== Node.ELEMENT_NODE) continue;
  67.                 if (node.matches('div.post')) {
  68.                     checkPost(node);
  69.                 } else if (node.querySelector && node.querySelector('div.post')) {
  70.                     scan(node);
  71.                 } else {
  72.                     // message body may be inserted/replaced separately
  73.                     const parentPost = node.closest && node.closest('div.post');
  74.                     if (parentPost) {
  75.                         parentPost.removeAttribute(PROCESSED);
  76.                         checkPost(parentPost);
  77.                     }
  78.                 }
  79.             }
  80.         }
  81.     });
  82.  
  83.     observer.observe(document.body, { childList: true, subtree: true });
  84. })();
Add Comment
Please, Sign In to add comment