Greasy Fork

来自缓存

Content Filter

Hide not interested content

目前为 2024-05-24 提交的版本。查看 最新版本

// ==UserScript==
// @name           Content Filter
// @name:ja        コンテンツフィルター
// @namespace      https://greasyfork.org/en/users/1264733
// @version        2024-05-24
// @description    Hide not interested content
// @description:ja 興味のない内容を隠す
// @author         LE37
// @license        MIT
// @include        /^https:\/\/www\.alphapolis\.co\.jp\/(author|novel)\//
// @include        /^https:\/\/greasyfork\.org\/[A-z-]+\/(discuss|scripts)/
// @include        /^https:\/\/(www\.|)ign\.com\//
// @include        /^https:\/\/kakuyomu\.jp\/(genr|pick|rank|rece|user|works\/)/
// @include        /^https:\/\/forum\.palemoon\.org\/view(forum|topic)/
// @include        /^https:\/\/(mypage|ncode)\.syosetu\.com\/[A-z0-9]+\//
// @include        /^https:\/\/yomou\.syosetu\.com\/rank\//
// @include        /^https:\/\/novelcom\.syosetu\.com\/impression\//
// @include        /^https:\/\/syosetu\.org\/\?mode=r(ank|evi)/
// @include        /^https:\/\/syosetu\.org\/(novel|user)\/[0-9]+\//
// @include        /^https:\/\/forum\.vivaldi\.net\//
// @include        /^https:\/\/social\.vivaldi\.net\//
// @include        /^https:\/\/(www\.|)yandex\.com\/search\//
// @exclude        https://www.alphapolis.co.jp/novel/ranking/annual
// @exclude        https://yomou.syosetu.com/rank/top/
// @grant          GM_getValue
// @grant          GM_setValue
// @grant          GM_registerMenuCommand
// ==/UserScript==

(()=>{
	'use strict';
	// GM Key
	let gMk;
	// Script firetime
	let cFt = 0;
	// MutationObserver targetNode, IntersectionObserver target
	let eOn, eIo;
	// Author/Novel page
	let cAp = false;
	// Shadowroot content
	let cSr = false;
	// Shadowhost, Shadowroot
	let eSh , eSr;
	// Target nodelist, UserLink, UserID, Tag, Alter
	let eNo, eUl, sId, sTg, eAt;

	// Select mode
	let cSv = false;
	// Mobile
	const rMb = navigator.userAgent.includes("Mobile");
	// Current url
	const uRi = location.href;
	switch (true) {
		// Alphapolis
		case /^https:\/\/www\.alphapolis\.co\.jp\/.*\/comment/.test(uRi):
			gMk = "APS";
			eNo = "div.comment";
			eUl = "span.name>a";
			sId = /detail\/(\d+)$/;
			break;
		case /^https:\/\/www\.alphapolis\.co\.jp\/novel\/(index|ranki)/.test(uRi):
			gMk = "APS";
			eNo = "div.section";
			eUl = "div.author>a";
			sId = /detail\/(\d+)$/;
			sTg = "li.tag a";
			break;
		case /^https:\/\/www\.alphapolis\.co\.jp\/(author|novel\/[0-9]+\/[0-9]+$)/.test(uRi):
			gMk = "APS";
			cAp = true;
			eUl = uRi.includes("author") ? "div.name>h1" : "div.author a";
			sId = /detail\/(\d+)$/;
			break;
		// Greasyfork
		case /^https:\/\/greasyfork\.org\/[A-z-]+\/script/.test(uRi):
			gMk = "GFK";
			eNo = "li[data-script-id]";
			eUl = null;
			sId = /(.*)/;
			sTg = "dd.script-list-author a";
			eAt = "a.script-link";
			break;
		case /^https:\/\/greasyfork\.org\/[A-z-]+\/discus/.test(uRi):
			gMk = "GFK";
			eNo = "div.discussion-list-container";
			eUl = null;
			sId = /(.*)/;
			sTg = "a.user-link";
			eAt = "a.script-link";
			break;
		// Hameln
		case /^https:\/\/syosetu\.org\/\?mode=rank/.test(uRi):
			gMk = "HML";
			eNo = rMb ? "div.search_box" : "div.section3";
			eUl = null;
			sId = /:(.*)/;
			sTg = rMb ? 'span[id^="tag_"]' : 'div.all_keyword:nth-child(9) a';
			eAt = rMb ? "p:nth-child(2)" : "div.blo_title_sak";
			break;
		case /^https:\/\/syosetu\.org\/\?mode=revi/.test(uRi):
			gMk = "HML";
			eNo = rMb ? "div.search_box" : "div.section3";
			eUl = null;
			sId = /([^\s]+)/;
			eAt = rMb ? "h4" : "h3";
			break;
		case /^https:\/\/syosetu\.org\/novel\/[0-9]+\/$/.test(uRi):
			gMk = "HML";
			cAp = true;
			eNo = rMb ? "div.search_box" : "div.section3";
			eUl = null;
			sId = /([^/]+)/;
			eAt = 'span[itemprop="author"]';
			break;
		case /^https:\/\/syosetu\.org\/user\/[0-9]+\/$/.test(uRi):
			gMk = "HML";
			cAp = true;
			eNo = rMb ? "div.search_box" : "div.section3";
			eUl = null;
			sId = /([^/]+)/;
			eAt = rMb ? 'h3>a' : 'h3';
			break;
		// IGN
		case /^https:\/\/(www\.|)ign\.com\//.test(uRi):
			gMk = "IGN";
			cFt = 2;
			eOn = "body";
			cSr = true;
			eNo = "li";
			eUl = null;
			sId = /(.*)/;
			eAt = 'span[data-spot-im-class="message-username"]';
			break;
		// Kakuyomu
		case /^https:\/\/kakuyomu\.jp\/(genr|picku|ranki|recen)/.test(uRi):
			gMk = "KYU";
			eNo = "div.widget-work";
			eUl = "a.widget-workCard-authorLabel";
			sId = /users\/(.*)$/;
			sTg = "a[itemprop='keywords']";
			break;
		case /^https:\/\/kakuyomu\.jp\/.*\/comme/.test(uRi):
			gMk = "KYU";
			cFt = 1;
			eNo = rMb ? 'div[class^="NewBox_box__"]>ul>li' : 'ul:nth-child(1) li';
			eUl = 'div.partialGiftWidgetActivityName>a';
			sId = /users\/(.*)$/;
			break;
		case /^https:\/\/kakuyomu\.jp\/.*\/episo/.test(uRi):
			gMk = "KYU";
			cFt = 2;
			eOn = "#episodeFooter-cheerComments-panel-mainContents";
			eNo = "ul.widget-cheerCommentList li";
			eUl = "h5.widget-cheerComment-author a";
			sId = /users\/(.*)$/;
			break;
		case /^https:\/\/kakuyomu\.jp\/(users\/|works\/[0-9]+$)/.test(uRi):
			gMk = "KYU";
			cFt = 1;
			cAp = true;
			eUl = uRi.includes("users") ? 'div[class^="HeaderText"]>a' : 'div.partialGiftWidgetActivityName>a';
			sId = /users\/(.*)$/;
			break;
		// Narou
		case /^https:\/\/novelcom\.syosetu\.com\/impre/.test(uRi):
			gMk = "NUC";
			eNo = rMb ? "div.impression" : "div.waku";
			eUl = "div.comment_authorbox>div>a";
			sId = /\/(\d+)/;
			eAt = "div.comment_authorbox>div";
			break;
		case /^https:\/\/(mypage|ncode)\.syosetu\.com\/[A-z0-9]+\/$/.test(uRi):
			gMk = "NRK";
			cAp = true;
			eUl = uRi.includes("ncode") ? 'div.novel_writername>a' : 'div.p-userheader__username';
			sId = /\/(\d+)/;
			break;
		case /^https:\/\/yomou\.syosetu\.com\/rank\//.test(uRi):
			gMk = "NRK";
			eNo = "div.p-ranklist-item";
			eUl = "div.p-ranklist-item__author a";
			sId = /\/(\d+)/;
			sTg = "div.p-ranklist-item__keyword a";
			break;
		// PalemoonForum
		case /^https:\/\/forum\.palemoon\.org\/viewtopic/.test(uRi):
			gMk = "PMF";
			eNo = "#page-body div.post";
			eUl = 'a[class^="username"]';
			sId = /u=(\d+)/;
			break;
		case /^https:\/\/forum\.palemoon\.org\/viewforum/.test(uRi):
			gMk = "PMF";
			eNo = "ul.topiclist>li";
			eUl = "div.topic-poster>a";
			sId = /u=(\d+)/;
			break;
		// VivaldiForm
		case /^https:\/\/forum\.vivaldi\.net\//.test(uRi):
			gMk = "VVF";
			cFt = 2;
			sId = /user\/(.*)/;
			break;
		// VivaldiSocial
		case /^https:\/\/social\.vivaldi\.net\//.test(uRi):
			gMk = "VVS";
			cFt = 2;
			eOn = "body";
			eIo = ".load-more";
			eNo = "div.item-list>article";
			eUl = null;
			sId = /(.*)/;
			eAt = "strong.display-name__html";
			break;
		// Yandex
		case /^https:\/\/(www\.|)yandex\.com\//.test(uRi):
			gMk = "YDX";
			eNo = rMb ? "div.serp-item" : "#search-result>li";
			eUl = rMb ? null : "div.Path>a.Link";
			sId = rMb ? /(.*)/ : /\/([^\/]+)/;
			eAt = "span.Path-Item>b";
			break;
	}
	//console.log( {gMk, cFt, eOn, eIo, cAp, cSr, eNo, eUl, sId, sTg, eAt} );

	// GM Menu
	GM_registerMenuCommand("View", SVM);
	GM_registerMenuCommand("Sort", UST);
	// Read List
	const URD = GM_getValue(gMk);
	let tlo = URD ? URD : { BAL:[], BTL:[] };
	const tal = tlo.BAL;
	const ttl = tlo.BTL;
	// Save List
	function USV() {
		tlo = { BAL:tal, BTL:ttl };
		GM_setValue(gMk, tlo);
	}
	// Sort List
	function UST() {
		tal.sort();
		ttl.sort();
		USV();
	}

	const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
	// Script Fire Time
	switch (cFt) {
		case 1:
			// Delay
			wait(1500).then(() => FMD());
			break;
		case 2:
			// MutationObserver
			MOC();
			break;
		case 3:
			// IntersectionObserver
			IOC();
			break;
		case 0:
		default:
			// Normal
			FMD();
	}
	// MutationObserver
	function MOC() {
		switch (gMk) {
			case "KYU": {
				// Comments in Episode
				// Button load comments
				const bLc = document.querySelector('#episodeFooter-action-cheerCommentsButton');
				bLc.addEventListener("click", (e) => {
					waitForElement(eNo, 2000).then(() => { FMD(); });
				});
				break;
			}
			case "IGN":
			case "VVF": {
				let pUi = "";
				const observer = new MutationObserver(mutations => {
					if (location.href !== pUi) {
						pUi = location.href;
						if (location.pathname.startsWith("/articles")) {
							wait(1000).then(() => IGN());
						} else if (location.pathname.startsWith("/topic")) {
							eNo = "ul.posts>li";
							eUl = "small.d-flex a";
							FMD();
						} else if (location.pathname.startsWith("/category")) {
							eNo = "ul.topic-list li";
							eUl = "small.hidden-xs>a";
							FMD();
						}
					}
				});
				observer.observe(document, { childList: true, subtree: true });
				break;
			}
			default:
				waitForElement(eNo, 2000).then(() => {
					FMD();
					// Vivaldi Social
					if (gMk === "VVS") wait(1500).then(() => IOC());
				});
		}
	}
	function IGN() {
		eSh = eSr = undefined;
		waitForElement(eNo, 5000).then(() => {
			FMD();
			if (eSr) {
				// Button load more messages
				const bLm = eSr.querySelector('.spcv_load-more-messages');
				if (bLm) {
					bLm.addEventListener("click", (e) => {
						wait(2000).then(() => FMD());
					});
				}
			}
		}).catch((error) => {
			//console.log(error);
			FMD();
		});
	}
	// Wait for an element to be loaded
	function waitForElement(selector, timeout) {
		return new Promise((resolve, reject) => {
			var timer = false;
			// Spot im shadownode
			if (cSr) {
				if (eSr && eSr.querySelectorAll(selector).length) return resolve();
			} else {
				if (document.querySelectorAll(selector).length) return resolve();
			}
			const obs = new MutationObserver(mutations => {
				// Spot im shadownode
				if (cSr) {
					eSh = document.querySelector('div[data-spotim-module]').firstElementChild;
					if (eSh) {
						eSr = eSh.shadowRoot;
						if (eSr && eSr.querySelectorAll(selector).length) {
							obs.disconnect();
							if (timer !== false) clearTimeout(timer);
							return resolve();
						}
					}
				} else {
					if (document.querySelectorAll(selector).length) {
						obs.disconnect();
						if (timer !== false) clearTimeout(timer);
						return resolve();
					}
				}
			});
			// Spot im shadownode
			const obn = eSr ? eSr.querySelectorAll('.spcv_conversation')[0] : document.querySelector(eOn);
			obs.observe(obn, { childList: true, subtree: true });
			if (timeout) {
				timer = setTimeout(() => {
					obs.disconnect();
					reject();
				}, timeout);
			}
		});
	}
	// IntersectionObserver
	function IOC() {
		const ioc = new IntersectionObserver((entries) => {
			if (entries[0].intersectionRatio <= 0) return;
			ioc.disconnect();
			// Vivaldi Social
			if (gMk === "VVS") wait(1500).then(() => MOC());
		});
		ioc.observe(document.querySelector(eIo));
	}

	// Filtering mode
	function FMD() {
		if (cAp) {
			// Filtering single target
			FST();
		} else {
			// Filtering multiple targets
			FMT();
		}
		if (!document.getElementById("cFbtn")) {
			CFB();
		}
	}
	// Filtering single target
	function FST() {
		let rBk = false;
		const eLk = eUl ? document.querySelector(eUl) : document.querySelector(eAt);
		let uId;
		// Narou author page fix
		if (gMk === "NRK") {
			uId = eLk.href ? eLk.href.match(sId)[1] : uRi.match(sId)[1];
		} else {
			uId = eUl ? eLk.href.match(sId)[1] : eLk.textContent.match(sId)[1];
		}
		rBk = CHK(eLk, "a", tal, uId);
		eLk.style.color = rBk ? "fuchsia" : "dodgerblue";
	}
	// Filtering multiple targets
	function FMT() {
		const no = eSr ? eSr.querySelectorAll(eNo) : document.querySelectorAll(eNo);
		for (let i = 0; i < no.length; i++) {
			let rBk = false;
			let uId;
			// Filtering content contain single id(link) or text
			let eLk = eUl ? no[i].querySelector(eUl) : no[i].querySelector(eAt);
			if (eLk !== null || gMk === "NUC" || gMk === "VVS") {
				// Narou nologin user fix
				// Vivaldi Social element out of view fix
				if (!eLk) {
					eLk = gMk === "VVS" ? no[i].querySelector("span") : no[i].querySelector(eAt);
					uId = gMk === "VVS" ? eLk.textContent.match(sId)[1].replace(/\s/g,'') : eLk.textContent.split("\n")[2];
				} else {
					uId = eUl ? eLk.href.match(sId)[1] : eLk.textContent.match(sId)[1];
					// Vivaldi Social id fix for foreground & background
					if (gMk ==="VVS") {
						let emoji = "";
						const ino = no[i].querySelectorAll(eAt + " img");
						if (ino) {
							for (let k = 0; k < ino.length; k++) {
								emoji += ino[k].alt;
							}
						}
						uId = eLk.textContent.match(sId)[1] + emoji;
						uId = uId.replace(/\s/g,'');
					}
				}
				//console.log(uId);
				// Vivaldi Social choose the unchanged class as target
				rBk = gMk === "VVS" ? CHK(no[i].querySelector("div.status__wrapper"), "a", tal, uId) : CHK(eLk, "a", tal, uId);
			}
			const eNes = no[i].nextElementSibling;
			if (sTg && !rBk) {
				// Filtering content contain multiple tags(text)
				// Tag node
				let tno;
				// Hameln mobile origin tag, custom tag
				let tot, tct;
				if (gMk === "HML" && rMb) {
					tot = no[i].querySelector(".trigger p:nth-child(4)");
					tct = no[i].querySelector(sTg);
					if (!tct) {
						tno = tot.textContent.slice(3).match(/[^\s]+/g);
						tot.innerHTML = "";
					} else {
						tno = no[i].querySelectorAll(sTg);
					}
				} else {
					tno = no[i].querySelectorAll(sTg);
				}
				for (let j = 0; j < tno.length; j++) {
					let tag;
					if (tot && !tct) {
						tag = tno[j];
						tot.innerHTML += '<span id="tag_' + j + '">' + tag + '</span>';
					} else {
						// Greasyfork fix
						tag = gMk === "GFK" ? tno[j].href.match(/s\/(\d+)/)[1] : tno[j].textContent;
					}
					//console.log(tag);
					rBk = tot && !tct ? CHK(no[i].querySelector("span#tag_"+j), "t", ttl, tag) : CHK(tno[j], "t", ttl, tag);
					if (rBk) break;
				}
			}
			// Blocked Show Type
			if (!cSv) {
				no[i].style.display = rBk ? "none" : "";
				no[i].style.opacity = "1";
			} else {
				no[i].style.display = "";
				no[i].style.opacity = rBk ? "0.5" : "1";
			}
		}
	}
	// CheckKeyword
	function CHK(ele, n, l, s) {
		const result = gMk === "GFK" && n === "a" ? l.some((v) => (new RegExp(v, "i")).test(s)) : l.some((v) => s === v);
		if (!ele.getAttribute("data-lkw")) {
			ele.setAttribute("data-lkw", n + s);
		}
		if (cSv) {
			ele.style.border = result ? "thin solid fuchsia" : "thin solid dodgerblue";
		} else {
			ele.style.border = "none";
		}
		return result;
	}

	// Select mode
	function SVM() {
		const cButton = document.getElementById("cFbtn");
		if (!cSv) {
			cSv = true;
			cButton.textContent = "📙";
			document.addEventListener("click", PAC, true);
		} else {
			cSv = false;
			cButton.textContent = "📘";
			document.removeEventListener("click", PAC, true);
			// Auto save list
			USV();
		}
		FMD();
	}
	// PreventAnchorChange
	function PAC(e) {
		e.preventDefault();
		const targetElement = cSr ? e.composedPath()[0] : e.target;
		// Vivaldi Forum & Social fix
		if (gMk === "VVF" || gMk === "VVS") {
			e.stopPropagation();
			// StopPropagation fix
			if (targetElement.closest("#cFbtn")) SVM();
		}
		const tEle = targetElement.getAttribute("data-lkw") ? targetElement
					: targetElement.parentElement.getAttribute("data-lkw") ? targetElement.parentElement
					: null;
		//console.log( {tEle, tEle.getAttribute("data-lkw")} );
		if (tEle) {
			const tda = tEle.getAttribute("data-lkw");
			const tlst = tda.slice(0, 1) === "a" ? tal : ttl;
			let tid = tda.slice(1);
			if (gMk === "GFK" && tda.slice(0, 1) === "a") {
				const t = prompt("Enter or use the first 5 letters as keyword", tid);
				tid = t !== null ? t : tid.slice(0, 5);
				//console.log(tid);
			}
			const li = tlst.findIndex((v) => v === tid);
			if (li !== -1) {
				tlst.splice(li,1);
			} else {
				tlst.push(tid);
			}
			FMD();
		}
		// IGN Popup temp fix
		if (gMk === "IGN") {
			wait(500).then(() => {
				const bsh = document.body.lastChild.shadowRoot;
				if (bsh) {
					const bsr = bsh.querySelector('button[title="Close the modal"]');
					if (bsr) bsr.click();
				}
			});
		}
		return false;
	}

	// Create Float Button
	function CFB() {
		const cButton = document.body.appendChild(document.createElement("button"));
		// Button Style
		cButton.id = "cFbtn";
		cButton.textContent = "📘";
		cButton.style = "position: fixed; bottom: 20%; right: 10%; width: 44px; height: 44px; z-index: 9999; font-size: 200%; opacity: 50%; cursor:pointer; border: none; padding: unset;";
		cButton.type = "button";
		cButton.addEventListener("click", (e) => { SVM(); });
	}
})();