Content Filter

Hide not interested content

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

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name           Content Filter
// @name:ja        コンテンツフィルター
// @namespace      https://greasyfork.org/en/users/1264733
// @version        2024-04-27
// @description    Hide not interested content
// @description:ja 興味のない内容を隠す
// @author         LE37
// @license        MIT
// @include        https://*
// @grant          GM_getValue
// @grant          GM_setValue
// @grant          GM_registerMenuCommand
// ==/UserScript==

(()=>{
	'use strict';
	// GM Key
	let gMk;
	switch (location.host) {
		case "www.alphapolis.co.jp":
			gMk = "APS";
			break;
		case "greasyfork.org":
		//case "":
			gMk = "GFK";
			break;
		case "syosetu.org":
			gMk = "HML";
			break;
		/*case "":
			gMk = "HTM";
			break;*/
		case "www.ign.com":
			gMk = "IGN";
			break;
		case "kakuyomu.jp":
			gMk = "KYU";
			break;
		/*case "":
			gMk = "NNN";
			break;*/
		case "novelcom.syosetu.com":
			gMk = "NUC";
			break;
		case "mypage.syosetu.com":
		case "ncode.syosetu.com":
		case "yomou.syosetu.com":
			gMk = "NRK";
			break;
		/*case "":
		case "":
			gMk = "PHB";
			break;*/
		case "forum.palemoon.org":
			gMk = "PMF";
			break;
		/*case "":
			gMk = "SRB";
			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");

		// cAd: Additional Delay
		// 0:off[default] 1:on
		let cAd = 0;

		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 "GFK":
				// Greasyfork
				if (uRi.includes("/scripts")) {
					// Scripts
					eNo = "li[data-script-id]";
					// Script link
					eUl = "a.script-link";
					// Script authors
					sTg = "dd.script-list-author a";
				} else if (uRi.includes("/discussions")) {
					// Discussions
					eNo = "div.discussion-list-container";
					// Discussion link
					eUl = "a.script-link";
					// Discussion author
					sTg = "a.user-link";
				}
				sId = /s\/(\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 "HTM":
				//
				cFt = 2;
				eOn = "div.gallery-content";
				eNo = "div.gallery-content>div";
				eUl = "table.dj-desc tr:nth-child(3) td:nth-child(2) a";
				sId = /index-(\w+)\.html/;
				sTg = "td.relatedtags>ul>li";
				break;*/
			case "IGN":
				// IGN
				cSr = 1;
				cFt = 2;
				eOn = 'body';
				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
					cAd = 1;
					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
					cAd = 1;
					cAp = 1;
					eUl = uRi.includes("users") ? 'div[class^="HeaderText"]>a' : 'div.partialGiftWidgetActivityName>a';
				}
				sId = /users\/(.*)$/;
				break;
			/*case "NNN":
				//
				eNo = rMb ? "ul.ranking" : "div.rank_h";
				eUl = null;
				eAt = rMb ? "li:nth-child(2)" : "span.name";
				sId = /.{3}(.*)/;
				sTg = rMb ? "li.keyword a" : "td.s a";
				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 "PHB":
				//
				eNo = rMb ? "div.videoWrapper" : "div.wrap";
				eUl = rMb ? "a.uploaderLink" : "div.usernameWrap a";
				sId = /([^\/]+)$/;
				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 "SRB":
				//
				if (uRi.includes("thread")) {
					// Thread
					eNo = rMb ? 'div[id^="pid"]' : 'div[id^="post_"]:not([id^="post_rate"]):not([id^="post_new"])';
					eUl = rMb ? "ul.authi a" : "a.xw1";
					sId = rMb ? /uid=(\d+)/ : /uid-(\d+)/;
				} else {
					// Index
					eOn = "#threadlisttableid";
					eNo = rMb ? "div.threadlist>ul>li" : "table#threadlisttableid tbody";
					eUl = rMb ? null : "td:nth-child(3)>cite>a";
					eAt = "span.by";
					sId = rMb ? /(.*)/ : /uid-(\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();
		}

		const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

		// Script Fire Time
		switch (cFt) {
			case 1:
				// ReadyState complete
				RSC();
				break;
			case 2:
				// MutationObserver
				MOC();
				break;
			case 3:
				// IntersectionObserver
				IOC();
				break;
			case 0:
			default:
				if (cAd) {
					// Delay
					wait(1500).then(() => FMD());
				} else {
					// Normal
					FMD();
				}
				/*
				if (gMk === "SRB" && !rMb && !uRi.includes("thread")) {
					MOC();
				}*/
		}

		// ReadyState complete
		function RSC() {
			document.addEventListener("readystatechange", (e) => {
				if (e.target.readyState === "complete") {
					//console.log('RSC: Complete');
				}
			});
		}

		// MutationObserver
		function MOC() {
			if (gMk === "KYU") {
				// Comments in Episode
				// Button load comments
				const bLc = document.querySelector('#episodeFooter-action-cheerCommentsButton');
				bLc.addEventListener("click", (e) => {
					waitForElement(eNo, 2000).then(() => {
						//console.log('MOC: Ready');
						FTR();
					}).catch(() => {
						//console.log('MOC: Timeout');
					});
				});
			} else {
				waitForElement(eNo, 30000).then(() => {
					//console.log('MOC: Ready');
					FMD();
					// IGN news
					if (gMk === "IGN") {
						// Button load more messages
						const bLm = eSr.querySelector('.spcv_load-more-messages');
						bLm.addEventListener("click", (e) => {
							wait(2000).then(() => FTR());
						});
					}
				}).catch(() => {
					//console.log('MOC: Timeout');
				});
			}
		}

		// 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) {
						if (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) {
								if (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();
						}
					}
				});

				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;
				//console.log('IOC: Start');
				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);
				}

				//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 {
						// NNN desktop fix
						tno = no[i].querySelectorAll(sTg);//gMk === "NNN" && !rMb ? eNes.querySelectorAll(sTg) : 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(sId)[1] : tno[j].textContent;
						}
						//console.log(tag);
						/* HTM hidden tag fix
						if (gMk === "HTM" && tno[j].classList.length !== 0 || tag === "...") {
							break;
						}*/
						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 flicking when use display none
					if (gMk === "VVS") {
						no[i].style.visibility = rBk ? "hidden" : "visible";
					} else {
						no[i].style.display = rBk ? "none" : "";
					}
					no[i].style.opacity = "1";
					/* NNN desktop fix
					if (gMk === "NNN" && !rMb) {
						eNes.style.display = rBk ? "none" : "";
						eNes.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";
					/* NNN desktop fix
					if (gMk === "NNN" && !rMb) {
						eNes.style.display = "";
						eNes.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);
				// Auto save list
				USV();
			}
			FMD();
		}

		// PreventAnchorChange
		function PAC(e) {
			e.preventDefault();
			// Vivaldi Social fix
			if (gMk === "VVF" || 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
			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)) {
				// Greasyfork fix
				const kd = gMk === "GFK" ? targetElement.href.match(sId)[1] : targetElement.textContent;
				//console.log(kd);
				UTL(e, kd, ttl);
				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;
		}

		// 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 === "VVF" || gMk === "VVS") {
			cButton.addEventListener("dblclick", (e) => {
				cSv = 1;
				SVM();
			});
		}
	}
})();