Content Filter

Hide not interested content

目前為 2024-04-23 提交的版本,檢視 最新版本

// ==UserScript==
// @name           Content Filter
// @name:ja        コンテンツフィルター
// @namespace      https://gf.qytechs.cn/en/users/1264733
// @version        2024-04-23
// @description    Hide not interested content
// @description:ja 興味のない内容を隠す
// @author         LE37
// @license        MIT
// @include        https://forum.palemoon.org/viewforum*
// @include        https://forum.palemoon.org/viewtopic*
// @include        https://forum.vivaldi.net/category/*
// @include        https://forum.vivaldi.net/topic/*
// @include        https://kakuyomu.jp/pickup_works*
// @include        https://kakuyomu.jp/rankings/*
// @include        https://kakuyomu.jp/recent_works*
// @include        https://kakuyomu.jp/users/*
// @include        https://kakuyomu.jp/works/*
// @include        https://mypage.syosetu.com/*/
// @include        https://ncode.syosetu.com/*/
// @include        https://novelcom.syosetu.com/impression/*
// @include        https://yomou.syosetu.com/rank/*
// @include        https://social.vivaldi.net/
// @include        https://social.vivaldi.net/explore*
// @include        https://social.vivaldi.net/public*
// @include        https://syosetu.org/novel/*/
// @include        https://syosetu.org/user/*/
// @include        https://syosetu.org/?mode=rank*
// @include        https://syosetu.org/?mode=review*
// @include        https://www.alphapolis.co.jp/author/*
// @include        https://www.alphapolis.co.jp/novel/*
// @include        https://www.ign.com/articles/*
// @include        https://www.yandex.com/search/*
// @include        https://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;
	// Needed if remove include and exclude in future
	switch (location.host) {
		case "www.alphapolis.co.jp":
			gMk = "APS";
			break;
		case "syosetu.org":
			gMk = "HML";
			break;
		case "www.ign.com":
			gMk = "IGN";
			break;
		case "kakuyomu.jp":
			gMk = "KYU";
			break;
		case "novelcom.syosetu.com":
			gMk = "NUC";
			break;
		case "mypage.syosetu.com":
		case "ncode.syosetu.com":
		case "yomou.syosetu.com":
			gMk = "NRK";
			break;
		case "forum.palemoon.org":
			gMk = "PMF";
			break;
		case "forum.vivaldi.net":
			gMk = "VVF";
			break;
		case "social.vivaldi.net":
			gMk = "VVS";
			break;
		case "yandex.com":
		case "www.yandex.com":
			gMk = "YDX";
			break;
		default:
			//console.log("DoNothing");
	}

	if (gMk) {
		RUN();
	}

	function RUN() {
		// cSr: Filting shadowroot content, only used when target within shadowroot
		// 0:off[default] 1:on
		let cSr = 0;
		// Shadowhost, Shadowroot, used when cSr = 1
		let eSh , eSr;

		// cAp: Filtering author/novel page
		// 0:off[default] 1:on
		let cAp = 0;

		// Select mode, 0:off[default] 1:on
		let cSv = 0;

		// cFt: Script firetime, prevent script fires too early
		// 0:Normal[default] 1:ReadyState Complete 2:MutationObserver 3:IntersectionObserver
		let cFt = 0;
		// eOn: MutationObserver targetNode, used when cFt = 2
		let eOn;
		// eIo: IntersectionObserver target, used when cFt = 3
		let eIo;

		// eNo: target nodelist, eUl: userLink, sId: userID, sTg: tag
		let eNo, eUl, sId, sTg;
		// eAt: Alternate text(target's textContent), used when predefine eUl(userlink) doen't contain valid href
		let eAt;

		// rMb: Client type
		// true:Mobile false:Desktop
		const rMb = navigator.userAgent.includes("Mobile");

		const uRi = location.href;
		switch (gMk) {
			case "APS":
				// Alphapolis
				if (uRi.includes("comment")) {
					// Comments
					eNo = "div.comment";
					eUl = "span.name>a";
				} else if (uRi.includes("index") || uRi.includes("ranking")) {
					// Ranking
					eNo = "div.section";
					eUl = "div.author>a";
					sTg = "li.tag a";
				} else if (uRi.includes("author") || (/novel[0-9\/]+$/).test(uRi)) {
					// Author Page
					cAp = 1;
					eUl = uRi.includes("author") ? "div.name>h1" : "div.author a";
				}
				sId = /detail\/(\d+)$/;
				break;
			case "HML":
				// Hameln
				eNo = rMb ? "div.search_box" : "div.section3";
				if (uRi.includes("rank")) {
					// Ranking
					eUl = null;
					eAt = rMb ? "p:nth-child(2)" : "div.blo_title_sak";
					sId = /:(.*)/;
					sTg = rMb ? 'span[id^="tag_"]' : 'div.all_keyword:nth-child(9) a';
				} else if (uRi.includes("review")) {
					// Comments
					eUl = null;
					eAt = rMb ? "h4" : "h3";
					sId = /([^\s]+)/;
				} else if ((/novel|user\/\d+\/$/).test(uRi)) {
					// Author Page
					cAp = 1;
					eUl = null;
					if (/novel\/\d+\/$/.test(uRi)) {
						eAt = 'span[itemprop="author"]'
					} else {
						eAt = rMb ? 'h3>a' : 'h3';
					}
					sId = /([^/]+)/;
				}
				break;

			case "IGN":
				// IGN
				cSr = 1;
				cFt = 2;
				eIo = '#comments-section';
				eOn = '#__next';
				eNo = "li";
				eUl = null;
				eAt = 'span[data-spot-im-class="message-username"]';
				sId = /(.*)/;
				break;
			case "KYU":
				// Kakuyomu
				if (uRi.includes("/pickup") || uRi.includes("/rank") || uRi.includes("/recent")) {
					// Ranking
					eNo = "div.widget-work";
					eUl = "a.widget-workCard-authorLabel";
					sId = /users\/(.*)$/;
					sTg = "a[itemprop='keywords']";
				} else if (uRi.includes("comments")) {
					// Comments
					cFt = 2;
					eOn = '#__next';
					eNo = rMb ? 'div[class^="NewBox_box__"]>ul>li' : 'ul:nth-child(1) li';
					eUl = 'div.partialGiftWidgetActivityName>a';
				} else if (uRi.includes("episodes")) {
					// Comments in Episode
					cFt = 2;
					eOn = "#episodeFooter-cheerComments-panel-mainContents";
					eNo = "ul.widget-cheerCommentList li";
					eUl = "h5.widget-cheerComment-author a";
				} else if (uRi.includes("users") || (/works\/\d+$/).test(uRi)) {
					// Author Page
					cFt = 2;
					eOn = '#__next';
					cAp = 1;
					eUl = uRi.includes("users") ? 'div[class^="HeaderText"]>a' : 'div.partialGiftWidgetActivityName>a';
				}
				sId = /users\/(.*)$/;
				break;
			case "NUC":
				// Narou Comments
				eNo = rMb ? "div.impression" : "div.waku";
				eUl = "div.comment_authorbox>div>a";
				eAt = "div.comment_authorbox>div";
				sId = /\/(\d+)/;
				break;
			case "NRK":
				// Narou Ranking
				if (uRi.includes("mypage") || uRi.includes("ncode")) {
					// Author Page
					cAp = 1;
					eUl = uRi.includes("ncode") ? 'div.novel_writername>a' : 'div.p-userheader__username';
				} else {
					// Ranking
					eNo = "div.p-ranklist-item";
					eUl = "div.p-ranklist-item__author a";
					sTg = "div.p-ranklist-item__keyword a";
				}
				sId = /\/(\d+)/;
				break;
			case "PMF":
				// Palemoon Forum
				if (uRi.includes("viewtopic")) {
					// Topic
					eNo = "#page-body div.post";
					eUl = 'a[class^="username"]';
					sId = /u=(\d+)/;
				} else {
					// Index
					eNo = "ul.topiclist>li";
					eUl = "div.topic-poster>a";
					sId = /u=(\d+)/;
				}
				break;
			case "VVF":
				// Vivaldi Forum
				if (uRi.includes("topic")) {
					// Topic
					eNo = "ul.posts>li";
					eUl = "small.d-flex a";
					sId = /user\/(.*)/;
				} else {
					// Index
					eNo = "ul.topic-list li";
					eUl = "small.hidden-xs>a";
					sId = /user\/(.*)/;
				}
				break;
			case "VVS":
				// Vivaldi Social
				cFt = 2;
				eOn = "div.app-holder";
				eNo = "div.item-list>article";
				eUl = null;
				eAt = "span.display-name__account";
				sId = /@(.*)$/;
				break;
			case "YDX":
				// Yandex Search
				eNo = rMb ? "div.serp-item" : "#search-result>li";
				eUl = rMb ? null : "div.Path>a.Link";
				eAt = "span.Path-Item>b";
				sId = rMb ? /(.*)/ : /\/([^\/]+)/;
				break;
		}

		// 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
		// mapsort???
		function UST() {
			tal.sort();
			ttl.sort();
			USV();
		}

		// Script Fire Time
		switch (cFt) {
			case 1:
				// ReadyState complete
				RSC();
				break;
			case 2:
				// MutationObserver
				MOC();
				break;
			case 3:
				// IntersectionObserver
				IOC();
				break;
			case 0:
			default:
				// Normal
				FMD();
		}

		// ReadyState complete
		function RSC() {
			document.addEventListener("readystatechange", (e) => {
				if (e.target.readyState === "complete") {
					FMD();
				}
			});
		}

		// MutationObserver
		function MOC() {
			const obs = new MutationObserver(() => {
				// Spotim fix
				if (cSr) {
					if (!eSr) {
						eSh = document.querySelector('div[data-spotim-module]').firstElementChild;
						if (eSh) {
							eSr = eSh.shadowRoot;
							IOC();
							obs.disconnect();
						}
					} else {
						eSr.querySelector('.spcv_load-more-messages').addEventListener("click", (e) => {
							setTimeout(() => {
								FTR();
							}, "1500");
						});
						obs.disconnect();
					}
				} else {
					//console.log("MOCXXX");
					setTimeout(() => {
						FMD();
					}, "1000");
					// Prevent infinite loop if add/remove element from observe targetnode
					if (document.getElementById("cFbtn")) {
						obs.disconnect();
					}
				}
			});
			// Spotim fix
			const obn = eSr ? eSr.querySelectorAll('.spcv_conversation')[0] : document.querySelector(eOn);
			obs.observe(obn, {
				childList: true,
				subtree: true
			});
		}

		// IntersectionObserver
		function IOC() {
			const ioc = new IntersectionObserver((entries) => {
				if (entries[0].intersectionRatio <= 0) return;
				//console.log("IOCXXX");
				// Spotim fix
				if (gMk === "IGN") {
					setTimeout(() => {
						FTR();
					}, "500");
					MOC();
				}
				ioc.disconnect();
			});
			ioc.observe(document.querySelector(eIo));
		}

		// Filtering mode
		function FMD() {
			if (cAp) {
				// Filtering author/novel page
				FAP();
			} else {
				// Filtering ranking/comments
				FTR();
			}
		}

		// Filtering author/novel page
		function FAP() {
				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, tal, uId);
				eLk.style.opacity = rBk ? "0.5" : "1";
				eLk.style.color = rBk ? "red" : "lime";
		}

		// Filtering ranking/comments
		function FTR() {
			const no = cSr ? 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") {
					// Narou nologin user fix
					if (!eLk) {
						eLk = no[i].querySelector(eAt);
						uId = eLk.textContent.split("\n")[2];
					} else {
						uId = eUl ? eLk.href.match(sId)[1] : eLk.textContent.match(sId)[1];
					}
					//console.log(uId);
					rBk = CHK(eLk, tal, uId);
				}

				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 {
							tag = tno[j].textContent;
						}
						//console.log(tag);
						rBk = tot && !tct ? CHK(no[i].querySelector("span#tag_"+j), ttl, tag) : CHK(tno[j], ttl, tag);
						if (rBk) {
							break;
						}
					}
				}

				// Blocked Show Type
				if (cSv === 0) {
					// Vivaldi Social flick fix
					if (gMk === "VVS") {
						no[i].style.visibility = rBk ? "hidden" : "visible";
					} else {
						no[i].style.display = rBk ? "none" : "";
					}
					no[i].style.opacity = "1";
				} else {
					if (gMk === "VVS") {
						no[i].style.visibility = "visible";
					} else {
						no[i].style.display = "";
					}
					no[i].style.opacity = rBk ? "0.5" : "1";
				}
			}
		}

		// CheckKeyword
		function CHK(ele, l, s) {
			const result = l.some((v) => s === v);
			if (cSv === 1) {
				ele.style.border = result ? "thin solid fuchsia" : "thin solid dodgerblue";
			} else {
				ele.style.border = "none";
			}
			return result;
		}

		// Select mode
		function SVM() {
			if (cSv === 0) {
				cSv = 1;
				// Disable default click
				document.addEventListener("click", PAC, true);
			} else {
				cSv = 0;
				// Disable default click
				document.removeEventListener("click", PAC, true);
				// Autosave list when turn off select mode
				USV();
			}
			FMD();
		}

		// PreventAnchorChange
		function PAC(e) {
			e.preventDefault();
			// Vivaldi Social fix
			if (gMk === "VVS") {
				e.stopPropagation();
			}
			const targetElement = cSr ? e.composedPath()[0] : e.target;
			//console.log(targetElement);
			let eLk;
			// Narou nologin user fix
			if (gMk === "NUC") {
				eLk = targetElement.href ? eUl : eAt;
			} else {
				eLk = eUl ? eUl : eAt;
			}
			// StopPropagation fix
			// StopPropagation will stop float button working,
			// So need binding #cFbtn to SVM temporary.
			if (targetElement.closest("#cFbtn")) {
				SVM;
			} else if (targetElement.closest(eLk)) {
				let ai;
				switch (gMk) {
					// Narou author page fix
					case "NRK":
						if (uRi.includes("mypage")) {
							// Author Page
							ai = uRi.match(sId)[1];
						} else {
							ai = eUl ? targetElement.href.match(sId)[1] : targetElement.textContent.match(sId)[1];
						}
						break;
					// Narou nologin user fix
					case "NUC":
						ai = targetElement.href ? targetElement.href.match(sId)[1] : targetElement.textContent.split("\n")[2];
						break;
					// Yandex fix
					case "YDX":
						ai = targetElement.href ? targetElement.href.match(sId)[1] : targetElement.parentElement.href.match(sId)[1];
						break;
					default:
						ai = eUl ? targetElement.href.match(sId)[1] : targetElement.textContent.match(sId)[1];
				}
				//console.log(ai);
				UTL(e, ai, tal);
				FMD();
			} else if (targetElement.closest(sTg)) {
				const kd = targetElement.textContent;
				UTL(e, kd, ttl);
				FMD();
			}
			// IGN Popup temp fix
			if (gMk === "IGN") {
				setTimeout(() => {
					const bsh = document.body.lastChild.shadowRoot;
					if (bsh) {
						const bsr = bsh.querySelector('button[title="Close the modal"]');
						if (bsr) {
							bsr.click();
						}
					}
				}, "500");
			}
			return false;
		}

		// UpdateTempList
		function UTL(e, s, l) {
			const li = l.findIndex((v) => v === s);
			if (li !== -1) {
				l.splice(li,1);
			} else {
				l.push(s);
			}
			//console.log(l);
			return l;
		}

		// Create Float Button
		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%;";
		cButton.type = "button";
		cButton.addEventListener("click", (e) => {
			SVM();
		});
		// Vivaldi Social CSP temp fix
		if (gMk === "VVS") {
			cButton.addEventListener("dblclick", (e) => {
				cSv = 1;
				SVM();
			});
		}
	}
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址