Content Filter

Hide not interested content

当前为 2024-04-29 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name           Content Filter
// @name:ja        コンテンツフィルター
// @namespace      https://greasyfork.org/en/users/1264733
// @version        2024-04-29
// @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 = "body";
				eIo = ".load-more";
				eNo = "div.item-list>article";
				eUl = null;
				eAt = "strong.display-name__html";
				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());
						});
					}
					// Vivaldi Social
					if (gMk === "VVS") {
						wait(1500).then(() => IOC());
					}
				}).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();
						}
					}
				});
				// 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
				FAP();
			} else {
				// Filtering multiple targets
				FTR();
			}
		}

		// Filtering single target
		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 multiple targets
		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" || 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 use static no[i] instead of dynamic eLk
					rBk = gMk === "VVS" ? CHK(no[i], tal, uId) : 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) {
					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 {
					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 Forum & 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;
					// Vivaldi Social different id fix
					case "VVS":
							let emoji = "";
							const ino = targetElement.parentElement.querySelectorAll(eAt + " img");
							if (ino) {
								for (let k = 0; k < ino.length; k++) {
									emoji += ino[k].alt;
								}
							}
							ai = targetElement.textContent.match(sId)[1] + emoji;
							ai = ai.replace(/\s/g,'');
						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();
			});
		}
	}
})();