屏蔽p站不感興趣的標籤和廣告教程

屏蔽p站不感興趣的標籤和廣告教程

作者:天溟啟

先使用pixiv官方的正文篩選第一遍結果,

會出現很多雷區標籤的作品

使用油猴腳本的程序的二次篩選功能,進行雷區標籤和標題的屏蔽

屏蔽後效果

腳本源碼,蒐集端via瀏覽器可使用

// ==UserScript==

// @name Pixiv 小說二次篩選器 v2

// @namespace

// @version 2.0.0

// @description 對 Pixiv 官方小說搜索結果按標題和完整可見標籤進行包含、排除篩選。

// @author ChatGPT

// @license MIT

// @match

// @run-at document-end

// @grant none

// ==/UserScript==

(function () {

'use strict';

const STORAGE_KEY = 'pixivNovelFilterV2.rules';

const HOST_ID = 'pixiv-novel-filter-v2-host';

const STYLE_ID = 'pixiv-novel-filter-v2-page-style';

const HIDDEN_CLASS = 'pixiv-novel-filter-v2-hidden';

const DASHES = '-‐‑‒–—―−﹘﹣-';

const norm = (value) => String(value ?? '').normalize('NFKC').trim().toLocaleLowerCase();

function parseRules(raw) {

const positive = [];

const negative = [];

const splitPrefix = new RegExp(`\\s+(?=[${DASHES}!!])`, 'u');

const negativePrefix = new RegExp(`^[${DASHES}!!]+`, 'u');

const entries = String(raw ?? '')

.split(/[\n,,;;]+/)

.flatMap((line) => line.trim().split(splitPrefix));

for (let entry of entries) {

entry = entry.trim();

if (!entry) continue;

const match = entry.match(negativePrefix);

const target = match ? negative : positive;

if (match) entry = entry.slic

e(match[0].length).trim();

entry = entry.replace(/^#/, '').trim();

const value = norm(entry);

if (value && !target.includes(value)) target.push(value);

}

return { positive, negative };

}

function matchesWork(work, titleRules, tagRules) {

const title = norm(work.title);

const tags = (work.tags || []).map(norm);

const hasTag = (rule) => tags.some((tag) => tag.includes(rule));

if (!titleRules.positive.every((rule) => title.includes(rule))) return false;

if (titleRules.negative.some((rule) => title.includes(rule))) return false;

if (!tagRules.positive.every(hasTag)) return false;

if (tagRules.negative.some(hasTag)) return false;

return true;

}

if (typeof document === 'undefined') {

globalThis.__PIXIV_FILTER_V2_TEST__ = { norm, parseRules, matchesWork };

return;

}

// 徹底移除 v1.x 的界面和隱藏樣式。即使舊腳本仍在運行,也無法覆蓋 v2 的篩選結果。

document.querySelectorAll('#pixiv-novel-second-filter-host').forEach((node) => node.remove());

document.getElementById('pixiv-novel-second-filter-page-style')?.remove();

document.querySelectorAll('.pxsf-hidden-by-second-filter, .pxsf-v13-hidden-by-second-filter')

.forEach((node) => node.classList.remove('pxsf-hidden-by-second-filter', 'pxsf-v13-hidden-by-second-filter'));

documen

t.getElementById(HOST_ID)?.remove();

document.getElementById(STYLE_ID)?.remove();

const pageStyle = document.createElement('style');

pageStyle.id = STYLE_ID;

pageStyle.textContent = `.${HIDDEN_CLASS} { display: none !important; }`;

document.head.appendChild(pageStyle);

const host = document.createElement('div');

host.id = HOST_ID;

const root = host.attachShadow({ mode: 'open' });

root.innerHTML = `

<style>

:host { all: initial; }

*, *::before, *::after { box-sizing: border-box; }

button, textarea { font: inherit; }

#open {

position: fixed; right: 16px; bottom: 145px; z-index: 2147483646;

border: 0; border-radius: 999px; padding: 11px 17px; cursor: pointer;

background: #f97316; color: white; font: 700 14px/1.2 system-ui, sans-serif;

box-shadow: 0 6px 20px rgb(0 0 0 / 28%);

}

#overlay {

display: none; position: fixed; inset: 0; z-index: 2147483647;

padding: 5vh 16px; background: rgb(0 0 0 / 54%);

font: 14px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif;

}

#overlay.show { display: flex; justify-content: center; align-items: flex-start; }

#panel {

width: min(760px, 100%); max-height: 90vh; overflow: auto; padding: 18px;

border-radius: 14px; background: #fff; color: #1f2937;

box-

shadow: 0 20px 60px rgb(0 0 0 / 38%);

}

header { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }

h2 { flex: 1; margin: 0; font-size: 19px; }

#close { border: 0; background: transparent; font-size: 25px; cursor: pointer; color: #64748b; }

.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }

label { font-weight: 700; }

textarea {

display: block; width: 100%; min-height: 120px; margin-top: 6px; padding: 10px;

resize: vertical; border: 1px solid #cbd5e1; border-radius: 8px; color: inherit; background: #fff;

}

.hint { margin-top: 5px; color: #64748b; font-size: 12px; font-weight: 400; }

.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 9px; margin-top: 16px; }

.primary, .secondary { border-radius: 8px; padding: 9px 14px; cursor: pointer; font-weight: 700; }

.primary { border: 1px solid #f97316; background: #f97316; color: white; }

.secondary { border: 1px solid #cbd5e1; background: #fff; color: #334155; }

#st