// ==UserScript== // @name 8chan Catalog Filter // @version 1.2 // @description Filter catalog threads using regex patterns // @match *://8chan.moe/*/catalog.* // @grant none // @license MIT // @namespace https://greasyfork.org/users/1459581 // @downloadURL none // ==/UserScript== (function() { 'use strict'; // Initial configuration - can be modified by the user through the dashboard let config = { filters: [ { pattern: /Arknights|AKG/i, // Example regex pattern action: 'setTop' // 'setTop' or 'remove' } // More filters can be added by the user ] }; // Load saved configuration from localStorage if available function loadConfig() { const savedConfig = localStorage.getItem('8chanCatalogFilterConfig'); if (savedConfig) { try { const parsedConfig = JSON.parse(savedConfig); // Convert string patterns back to RegExp objects parsedConfig.filters = parsedConfig.filters.map(filter => ({ pattern: new RegExp(filter.patternText, filter.flags), patternText: filter.patternText, // Store the raw text pattern action: filter.action })); config = parsedConfig; } catch (e) { console.error('Failed to load saved filters:', e); } } } // Save configuration to localStorage function saveConfig() { // Convert RegExp objects to a serializable format const serializedConfig = { filters: config.filters.map(filter => ({ patternText: filter.patternText || filter.pattern.source, flags: filter.pattern.flags, action: filter.action })) }; localStorage.setItem('8chanCatalogFilterConfig', JSON.stringify(serializedConfig)); } // Create and inject the filter dashboard function createDashboard() { const toolsDiv = document.getElementById('divTools'); if (!toolsDiv) return; // Create container for the filter dashboard const dashboardContainer = document.createElement('div'); dashboardContainer.id = 'filterDashboard'; dashboardContainer.style.marginBottom = '10px'; // Create the dashboard controls const dashboardControls = document.createElement('div'); dashboardControls.className = 'catalogLabel'; dashboardControls.innerHTML = ` Filters: (${config.filters.length} active) `; // Create the filter manager panel (initially hidden) const filterManager = document.createElement('div'); filterManager.id = 'filterManagerPanel'; filterManager.style.display = 'none'; filterManager.style.border = '1px solid #ccc'; filterManager.style.padding = '10px'; filterManager.style.marginTop = '5px'; updateFilterManagerContent(filterManager); // Add everything to the dashboard container dashboardContainer.appendChild(dashboardControls); dashboardContainer.appendChild(filterManager); // Insert dashboard before the search box const searchDiv = toolsDiv.querySelector('div[style="float: right; margin-top: 6px;"]'); if (searchDiv) { toolsDiv.insertBefore(dashboardContainer, searchDiv); } else { toolsDiv.appendChild(dashboardContainer); } // Add event listeners document.getElementById('showFilterManager').addEventListener('click', function() { const panel = document.getElementById('filterManagerPanel'); panel.style.display = panel.style.display === 'none' ? 'block' : 'none'; }); document.getElementById('applyFilters').addEventListener('click', function() { processCatalog(); }); } function updateFilterManagerContent(filterManager) { let content = `
Pattern | Action | Remove |
---|---|---|
${filter.patternText || filter.pattern.source} | ${filter.action} |