// ==UserScript== // @name Pixiv小说自定义屏蔽 // @namespace http://tampermonkey.net/ // @version 2025-11-23.1 // @description 屏蔽含有指定关键词、作者名、标签或字数范围外的 Pixiv 项目,支持设置面板、导入导出配置、控制台打印 // @author 111 // @match https://www.pixiv.net/tags* // @icon https://www.google.com/s2/favicons?sz=64&domain=pixiv.net // @grant GM_addStyle // @run-at document-start // 尽早运行,确保在任何 fetch 发生之前完成劫持 // @downloadURL https://raw.githubusercontent.com/echo152/pixiv-custom-filter/main/pixiv-custom-filter.user.js // @updateURL https://raw.githubusercontent.com/echo152/pixiv-custom-filter/main/pixiv-custom-filter.user.js // @license MIT // ==/UserScript== (function() { 'use strict'; const defaultConfig = { contentKeywords: ['无限制ai', 'ai风月'], authorKeywords: ['(', '('], tagKeywords: ['语c', '男同'], minTextLength: 0, maxTextLength: 10000, hideNoDescription: false }; function getConfig() { const saved = localStorage.getItem('pixivFilterConfig'); if (saved) { try { return { ...defaultConfig, ...JSON.parse(saved) }; } catch (e) { console.warn('配置解析失败,使用默认值'); } } return { ...defaultConfig }; } function saveConfig(config) { localStorage.setItem('pixivFilterConfig', JSON.stringify(config)); } let config = getConfig(); GM_addStyle(` #pixivFilterBtn, #pixivConfigBtn { position: fixed; left: 10px; z-index: 9999; padding: 8px 12px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; box-shadow: 0 2px 5px rgba(0,0,0,0.2); } #pixivFilterBtn { top: 50%; } #pixivConfigBtn { top: 60%; background: #2196F3; } .hidden-by-ai-toggle { display: none !important; } #pixivConfigPanel { position: fixed; top: 120px; left: 120px; width: 400px; background: #fff; color: #333; padding: 16px; border-radius: 10px; box-shadow: 0 0 15px rgba(0,0,0,0.3); z-index: 10000; display: none; font-size: 14px; } #pixivConfigPanel textarea { width: 100%; height: 60px; margin-bottom: 12px; } #pixivConfigPanel input[type=number] { width: 80px; margin-bottom: 12px; } #pixivConfigPanel button { margin-right: 8px; } `); const configPanel = document.createElement('div'); configPanel.id = 'pixivConfigPanel'; configPanel.innerHTML = `
内容关键词(标题+简介):
作者关键词:
标签关键词:
最小字数:
最大字数:

`; document.body.appendChild(configPanel); const toggleButton = document.createElement('button'); toggleButton.id = 'pixivFilterBtn'; toggleButton.textContent = 'Hide AI'; document.body.appendChild(toggleButton); const configButton = document.createElement('button'); configButton.id = 'pixivConfigBtn'; configButton.textContent = '关键词设置'; document.body.appendChild(configButton); let isHidden = false; let configPanelVisible = false; let observedElements = []; function containsKeyword(text, keywords) { const lower = text.toLowerCase(); const foundKeywords = []; keywords.forEach(k => { if (lower.includes(k.toLowerCase())) { foundKeywords.push(k); } }); return foundKeywords; } function getTagTexts(li) { const tags = []; const tagLinks = li.querySelectorAll('div > div:nth-child(2) > div > div:nth-child(3) ul a, ul span span'); tagLinks.forEach(tag => { const text = tag.textContent?.trim(); if (text) tags.push(text); }); return tags; } function findTargetElements() { return document.querySelectorAll('#__next ul li'); } function toggleElements() { observedElements.forEach(li => { const titleElem = li.querySelector('div > div:nth-child(2) > div > div:nth-child(1) > div > a'); const authorElem = li.querySelector('div > div:nth-child(2) > div > div:nth-child(2) > a'); const authorName = authorElem ? authorElem.textContent.trim() : ''; const contentElem = li.querySelector('div > div:nth-child(2) > div > div:nth-child(3) >div>div>div'); const contentText = contentElem ? contentElem.textContent.trim() : ''; const textLengthElem = li.querySelector('div > div:nth-child(2) > div > div:nth-child(3) > div > div > div > span'); const textLength = textLengthElem ? parseInt(textLengthElem.textContent.replace(/[^\d]/g, '')) : 0; const tags = getTagTexts(li); const titleText = titleElem ? titleElem.textContent.trim() : ''; const matchedTags = containsKeyword(tags.join(' '), config.tagKeywords); const matchedAuthor = containsKeyword(authorName, config.authorKeywords); const matchedContent = containsKeyword(contentText, config.contentKeywords); const matchedTitle = containsKeyword(titleText, config.contentKeywords); const lengthTooShort = textLength < config.minTextLength; const lengthTooLong = textLength > config.maxTextLength; const noDescription = config.hideNoDescription && (!contentElem || contentText.length === 0||contentElem.innerHTML.includes("sc-99dab233")); const shouldHide = isHidden && ( matchedAuthor.length > 0 || matchedContent.length > 0 || matchedTitle.length > 0 || matchedTags.length > 0 || lengthTooShort || lengthTooLong || noDescription ); li.classList.toggle('hidden-by-ai-toggle', shouldHide); if (shouldHide) { let logMessage = '隐藏作品:'; if (matchedContent.length > 0) logMessage += `[内容: ${matchedContent.join(', ')}] `; if (matchedTitle.length > 0) logMessage += `[标题: ${matchedTitle.join(', ')}] `; if (matchedAuthor.length > 0) logMessage += `[作者: ${matchedAuthor.join(', ')}] `; if (matchedTags.length > 0) logMessage += `[标签: ${matchedTags.join(', ')}] `; if (lengthTooShort) logMessage += `[字数过少: ${textLength}] `; if (lengthTooLong) logMessage += `[字数过多: ${textLength}] `; if (noDescription) logMessage += '[无简介] '; console.log(authorName + ' ' + logMessage); } }); } function init() { observedElements = Array.from(findTargetElements()); toggleElements(); } toggleButton.addEventListener('click', function () { isHidden = !isHidden; toggleButton.textContent = isHidden ? 'Show AI' : 'Hide AI'; toggleElements(); }); configButton.addEventListener('click', function () { configPanelVisible = !configPanelVisible; configPanel.style.display = configPanelVisible ? 'block' : 'none'; }); configPanel.querySelector('#saveBtn').addEventListener('click', () => { config.contentKeywords = configPanel.querySelector('#contentInput').value.split('\n').map(s => s.trim()).filter(Boolean); config.authorKeywords = configPanel.querySelector('#authorInput').value.split('\n').map(s => s.trim()).filter(Boolean); config.tagKeywords = configPanel.querySelector('#tagInput').value.split('\n').map(s => s.trim()).filter(Boolean); config.minTextLength = parseInt(configPanel.querySelector('#minTextLength').value) || 0; config.maxTextLength = parseInt(configPanel.querySelector('#maxTextLength').value) || 100000; config.hideNoDescription = configPanel.querySelector('#hideNoDescription').checked; saveConfig(config); init(); alert('已保存设置'); }); configPanel.querySelector('#exportBtn').addEventListener('click', () => { const exportData = JSON.stringify(config, null, 2); navigator.clipboard.writeText(exportData).then(() => alert('配置已复制到剪贴板')); }); configPanel.querySelector('#importBtn').addEventListener('click', () => { const input = prompt('请粘贴你导出的配置JSON:'); if (input) { try { const imported = JSON.parse(input); config = { ...defaultConfig, ...imported }; saveConfig(config); location.reload(); } catch (e) { alert('导入失败,JSON 格式有误。'); } } }); configPanel.querySelector('#closeBtn').addEventListener('click', () => { configPanel.style.display = 'none'; configPanelVisible = false; }); const observer = new MutationObserver(() => { init(); }); observer.observe(document.body, { childList: true, subtree: true }); init(); })();