Content Filter

Hide not interested content

As of 2024-04-17. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name           Content Filter
// @name:ja        コンテンツフィルター
// @namespace      https://greatest.deepsurf.us/en/users/1264733
// @version        2024-04-17
// @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://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_registerMenuCommand
// @grant          GM_setValue
// @grant          GM_getValue
// ==/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 "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 = "div.blo_title_sak a";
					eAt = "div.blo_title_sak";
					sTg = "div.all_keyword:nth-child(9) a";
				} else if (uRi.includes("review")) {
					// Comments
					eUl = "h3>a:nth-child(1)";
				} else if ((/novel|user\/\d+\/$/).test(uRi)) {
					// Author Page
					cAp = 1;
					eUl = /novel\/\d+\/$/.test(uRi) ? 'span[itemprop="author"]>a' : 'div.section3>h3';
					eAt = 'span[itemprop="author"]';
				}
				sId = /((?<=uid=).*|(\d+)(?=\/))/;
				break;
			case "IGN":
				// IGN
				cSr = 1;
				cFt = 3;
				eIo = '#comments-section';
				eOn = '.spcv_conversation';
				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
					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 "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;
		}

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

		// 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
				if (cAp) {
					// Filtering author/novel page
					FAP();
				} else {
					// Filtering ranking/comments
					FTR();
				}
		}

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

		// MutationObserver
		function MOC() {
			const obs = new MutationObserver(() => {
				FTR();
				//obs.disconnect();
			});
			// Shadowroot fix
			const obn = cSr ? eSr.querySelectorAll(eOn)[0] : document.querySelector(eOn);
			obs.observe(obn, {
				childList: true,
				subtree: true
			});
		}

		// IntersectionObserver
		function IOC() {
			// Shadowroot fix
			if (cSr) {
				eSh = document.querySelector('div[data-spotim-module]').firstElementChild;
				if (eSh) {
					eSr = eSh.shadowRoot;
				}
				//console.log(eSr);
			}
			const ioc = new IntersectionObserver((entries) => {
				if (entries[0].intersectionRatio <= 0) return;
				FTR();
				// IGN fix
				if (gMk === "IGN") {
					MOC();
				}
				ioc.disconnect();
			});
			ioc.observe(document.querySelector(eIo));
		}

		// Filtering author/novel page
		function FAP() {
				let rBk = false;
				let eLk = document.querySelector(eUl);
				let uId;
				// Hameln nologin author fix
				if (!eLk && gMk === "HML") {
					eLk = document.querySelector(eAt);
					uId = eLk.textContent;
				} else {
					// Hameln Narou author page fix
					uId = eLk.href ? eLk.href.match(sId)[1] : uRi.match(sId)[1];
				}
				rBk = CBN(eLk, tal, uId);
				eLk.style.opacity = rBk ? "0.5" : "1";
		}

		// 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 === "HML" || gMk === "NUC") {
					// Hameln Narou nologin user fix
					if (!eLk) {
						eLk = no[i].querySelector(eAt);
						uId = gMk === "HML" ? no[i].querySelector(eAt).textContent.slice(3, -1) : no[i].querySelector(eAt).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 (!rBk) {
					// Filtering content contain multiple tags(text)
					const tno = no[i].querySelectorAll(sTg);
					if (tno !== null) {
						for (let j = 0; j < tno.length; j++) {
							const tag = tno[j].textContent;
							//console.log(tag);
							rBk = CHK(tno[j], ttl, tag);
							if (rBk) {
								break;
							}
						}
					}
				}

				// Blocked Show Type
				if (cSv === 0) {
					//no[i].style.visibility = rBk ? "hidden" : "visible";
					no[i].style.display = rBk ? "none" : "";
					no[i].style.opacity = "1";
	
				} else {
					//no[i].style.visibility = "visible";
					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 lime" : "thin solid red";
			} 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();
			}
			FTR();
		}

		// PreventAnchorChange
		function PAC(e) {
			e.preventDefault();
			//e.stopPropagation();
			const targetElement = cSr ? e.composedPath()[0] : e.target;
			//console.log(targetElement);
			let eLk;
			// Hameln Narou nologin user fix
			if (gMk === "HML" || gMk === "NUC") {
				eLk = targetElement.href ? eUl : eAt;
			} else {
				eLk = eUl ? eUl : eAt;
			}
			if (targetElement.closest(eLk)) {
				let ai;
				switch (gMk) {
					// Hameln nologin author fix
					case "HML":
						ai = targetElement.href ? targetElement.href.match(sId)[1] : targetElement.textContent.slice(3, -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);
				FTR();
			} else if (targetElement.closest(sTg)) {
				const kd = targetElement.textContent;
				UTL(e, kd, ttl);
				FTR();
			}
			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 Buttons
		function CBN(ele, l, s) {
			const result = l.some((v) => s === v);
			const eNes = ele.nextElementSibling;
			let bBtn;
			if (eNes && eNes.classList.contains("bbtn")) {
				bBtn = eNes;
			} else {
				bBtn = document.createElement("span");
				bBtn.classList.add("bbtn");
				ele.after(bBtn);
				bBtn.addEventListener("click", ()=>{
					const li = l.findIndex((v) => v === s);
					if (li !== -1) {
						l.splice(li,1);
					} else {
						l.push(s);
					}
					//console.log(l);
					USV();
					FAP();
				}, true);
			}
			// Button Style
			bBtn.innerHTML = result ? '<button style="color:lime;background-color:black;" type="button">✔Unblock</button>' : '<button style="color:red;background-color:white;" type="button">❌Block</button>';
			return result;
		}

		// CustomMenu
		if (!cAp) {
			const cMenu = document.createElement("div");
			cMenu.innerHTML = '<nav class="cNav" style="position: fixed; top: 16%; left: 19%; width: 62%; height: 44px; z-index: 9999;">' +
									'<button id="cBtn" style="width: 44px; height: 44px; font-size: 200%; opacity: 50%;" type="button">📘</button>' + 
								'</nav>';
			document.body.appendChild(cMenu);
			document.getElementById("cBtn").addEventListener("click", SVM, true);
		}
	}
})();