Загрузка данных
// ==UserScript==
// @name Двач: Анти-Лахта Мод (Умная фильтрация)
// @namespace http://tampermonkey.net
// @version 2.5
// @description Скрывает бототреды только в общих лентах досок и никогда не трогает контент внутри самих тредов.
// @author You
// @match *://*.2ch.org/*
// @match *://*.2ch.hk/*
// @match *://*.m2ch.hk/*
// @match *://*.2ch.life/*
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// Функция проверки: находимся ли мы внутри треда?
function isInsideThread() {
const url = window.location.href;
// Если в URL есть "/res/" или имя файла заканчивается на ".html" (переход внутрь треда)
// то скрипт не должен работать
return url.includes('/res/') || url.includes('.html');
}
// Массив ключевых слов
const botShit = [
'webm', 'тяноч', 'отношен', 'секс', 'танцуль', 'Воскресной молитвы', 'субкота',
'фурр', 'почему так', 'девушк', 'лесополос', 'ZASMOBOS', 'Это гуар.',
'desktop', 'рабочий стол', 'фапочно', 'покажи', 'цуиь', 'аниме', 'mp4', 'banana', 'понитре',
'анимэ', 'дружботр', 'вацфу', 'вайф', 'тредю', 'зумер', 'тянка', 'тянко',
'тянок', 'септемба', 'котосуббота', '#пкм', 'пустите в', 'fap', 'РИСОВАЧ', 'НАУШН',
'рисовач тред', 'Храмом ГОЛОВЫ', 'храам голов', 'warcraft', 'war c', 'dekstop',
'Главный новостной', 'ШЛИК', 'fap', 'Оцени член', 'оцени', 'писяндрик'
];
// Функция обработки ОП-поста
function processPost(postElement) {
// ЕСЛИ МЫ ВНУТРИ ТРЕДА — КАТЕГОРИЧЕСКИ НИЧЕГО НЕ СКРЫВАЕМ
if (isInsideThread()) return;
// Защита от повторной обработки одного и того же элемента
if (postElement.dataset.checkedByLahta) return;
postElement.dataset.checkedByLahta = "true";
// Извлекаем текст
let threadText = postElement.textContent.replace('(OP)', '').toLowerCase();
threadText = threadText.replace(/\>+(\d+)>/g, '').replace(/\>+(\d+)/g, '');
threadText = threadText.replace(/\s+/g, ' ').trim();
// Ищем совпадение
const triggeredWord = botShit.find(word => {
const cleanWord = word.trim().toLowerCase();
return cleanWord !== '' && threadText.includes(cleanWord);
});
if (triggeredWord) {
// Находим контейнер всего треда на доске
const threadContainer = postElement.closest('.thread') || postElement.closest('[id^="thread-"]') || postElement.closest('.post-wrapper');
if (threadContainer) {
// Создаем плашку-заглушку
const placeholder = document.createElement('div');
placeholder.className = 'lahta-placeholder';
placeholder.style.border = '1px dashed #555555';
placeholder.style.padding = '10px 14px';
placeholder.style.margin = '12px 0';
placeholder.style.borderRadius = '4px';
placeholder.style.background = 'rgba(221, 161, 172, 0.05)';
placeholder.style.display = 'block';
placeholder.style.clear = 'both';
placeholder.innerHTML = `<span style="color: #dda1ac; font-weight: bold; text-decoration: none !important;">УДАЛЕНА БОТОХУЕТА [ ${triggeredWord.trim()} ]</span>`;
// Вставляем плашку перед скрываемым тредом
threadContainer.parentNode.insertBefore(placeholder, threadContainer);
// Скрываем оригинальный тред на главной странице доски
threadContainer.style.setProperty('display', 'none', 'important');
}
}
}
// Запуск сканирования
function scan() {
if (isInsideThread()) return;
const opPosts = document.querySelectorAll('.post_type_oppost, .oppost, .post.post_type_oppost');
opPosts.forEach(post => processPost(post));
}
// Первый запуск при инициализации страницы
scan();
// Наблюдатель за динамической подгрузкой новых постов/тредов
const observer = new MutationObserver((mutations) => {
// Если пользователь перешел внутрь треда (пусть даже по AJAX без перезагрузки), прекращаем обработку
if (isInsideThread()) return;
let shouldScan = false;
for (let mutation of mutations) {
if (mutation.addedNodes.length > 0) {
shouldScan = true;
break;
}
}
if (shouldScan) {
scan();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
})();
------------------------------------------------
// ==UserScript==
// @name Кнопка "скрыть тред"
// @namespace http://tampermonkey.net
// @version 2.5
// @description Увеличение с жирным черным крестом
// @match *://*.2ch.org/*
// @match *://*.2ch.hk/*
// @match *://*.m2ch.hk/*
// @match *://*.2ch.life/*
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// 1. Внедряем CSS-стили для кнопки
const style = document.createElement('style');
style.textContent = `
/* Настройка внешнего контейнера SVG кнопки */
svg.post__btn.post__btn_type_hide.icon.desktop.js-processed-btn {
display: inline-block !important;
width: 50px !important;
height: 50px !important;
box-sizing: border-box !important;
margin-left: 10px !important;
border-radius: 8px !important;
/* Базовое состояние: приглушенный сине-лиловый пиксельный стиль */
filter: invert(40%) sepia(20%) saturate(1200%) hue-rotate(220deg) !important;
image-rendering: pixelated !important;
image-rendering: crisp-edges !important;
/* Плавный переход для анимации при наведении (0.2 секунды) */
transition: filter 0.2s ease-in-out, transform 0.2s ease-in-out !important;
}
/* ЭФФЕКТ ПРИ НАВЕДЕНИИ (HOVER) */
/* Исходное состояние кнопки — добавляем быстрое время отклика */
svg.post__btn.post__btn_type_hide.icon.desktop.js-processed-btn {
transition: filter 0.15s ease-in-out, transform 0.15s ease-in-out !important;
}
/* Состояние при наведении */
svg.post__btn.post__btn_type_hide.icon.desktop.js-processed-btn:hover {
/* Смещаем спектр (hue-rotate) в сторону теплого пастельно-розового оттенка
и немного увеличиваем яркость (brightness) */
filter: invert(40%) sepia(20%) saturate(1500%) hue-rotate(310deg) brightness(1.1) !important;
/* Кнопка слегка и аккуратно увеличивается при наведении */
transform: scale(1.01) !important;
}
/* Настройки пикселизации для внутренних элементов */
svg.post__btn.post__btn_type_hide.icon.desktop.js-processed-btn * {
image-rendering: pixelated !important;
image-rendering: crisp-edges !important;
}
`;
document.head.appendChild(style);
// 2. Функция поиска и перемещения кнопок
function modifyButtons() {
// Ищем SVG-кнопки скрытия, которые мы еще не обрабатывали
let svgs = document.querySelectorAll('svg.post__btn.post__btn_type_hide.icon.desktop:not(.js-processed-btn)');
svgs.forEach((svg) => {
let parentDiv = svg.closest('.post__details');
if (parentDiv) {
// Помечаем SVG классом-маркером (CSS применится автоматически)
svg.classList.add('js-processed-btn');
// Переносим саму оригинальную SVG кнопку в самый конец родительского div
// Браузер автоматически заберет её со старого места и вставит в конец
parentDiv.appendChild(svg);
}
});
}
modifyButtons();
// 3. Отслеживание динамической подгрузки постов в треде
const observer = new MutationObserver(() => {
if (document.querySelector('svg.post__btn.post__btn_type_hide.icon.desktop:not(.js-processed-btn)')) {
modifyButtons();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
})();