Novel Ranking Comments Filter

Hide not interested content on ranking/comments page

安装此脚本
作者推荐脚本

您可能也喜欢Novel Sites Enhance

安装此脚本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name           Novel Ranking Comments Filter
// @name:ja        小説ランキング・コメント・フィルター
// @namespace      https://greasyfork.org/en/users/1264733
// @version        2024-07-16
// @description    Hide not interested content on ranking/comments page
// @description:ja ランキング/コメントページで興味のないコンテンツを隠す
// @author         LE37
// @license        MIT
// @include        /^https:\/\/www\.alphapolis\.co\.jp\/(author|novel)\//
// @include        /^https:\/\/kakuyomu\.jp\/(genr|pick|rank|rece|sear|user|works\/)/
// @include        /^https:\/\/(mypage|ncode)\.syosetu\.com\/[A-z0-9]+\/?$/
// @include        /^https:\/\/yomou\.syosetu\.com\/(rank\/|search)/
// @include        /^https:\/\/novelcom\.syosetu\.com\/impression\//
// @include        /^https:\/\/syosetu\.org\/\?mode=r(ank|evi)/
// @include        /^https:\/\/syosetu\.org\/(novel|user)\/[0-9]+\//
// @exclude        https://www.alphapolis.co.jp/novel/ranking/annual
// @exclude        https://yomou.syosetu.com/rank/top/
// @grant          GM_setValue
// @grant          GM_getValue
// @grant          GM_deleteValue
// @grant          GM_listValues
// @grant          GM_registerMenuCommand
// ==/UserScript==

(()=>{
	'use strict';
	// GM key, Fire time, Observe node, Nodelist, userLink, userid, tag, alt;
	let gMk, cFt, eOn, eNo, eUl, sId, sTg, eAt;
	// Author page,
	let cAp = false;
	// Select mode
	let cSv = false;
	// Show blocklists
	let cSb = false;
	// Current list
	let tlo;
	// Mobile
	const rMb = navigator.userAgent.includes("Mobile");
	// Delay
	const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
	// Current url
	const uRi = location.href;
	// Site info
	const SITE_INFO = [
		// Alphapolis
		[/^https:\/\/www\.alphapolis\.co\.jp\/.*\/comment/, 'gMk = "APS"; eNo = "div.comment"; eUl = "span.name>a"; sId = /detail\\/(\\d+)$/;'],
		[/^https:\/\/www\.alphapolis\.co\.jp\/novel\/(index|ranki)/, 'gMk = "APS"; eNo = "div.section"; eUl = "div.author>a"; sId = /detail\\/(\\d+)$/; sTg = "li.tag a";'],
		[/^https:\/\/www\.alphapolis\.co\.jp\/(author|novel\/[0-9]+\/[0-9]+$)/, 'gMk = "APS"; cAp = true; eUl = uRi.includes("author") ? "div.name>h1" : "div.author a"; sId = /detail\\/(\\d+)$/;'],
		// Hameln
		[/^https:\/\/syosetu\.org\/\?mode=rank/, '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";'],
		[/^https:\/\/syosetu\.org\/\?mode=revi/, 'gMk = "HML"; eNo = rMb ? "div.search_box" : "div.section3"; eUl = null; sId = /([^\\s]+)/; eAt = rMb ? "h4" : "h3";'],
		[/^https:\/\/syosetu\.org\/novel\/[0-9]+\/$/, 'gMk = "HML"; cAp = 1; eNo = rMb ? "div.search_box" : "div.section3"; eUl = null; sId = /([^/]+)/; eAt = \'span[itemprop="author"]\';'],
		[/^https:\/\/syosetu\.org\/user\/[0-9]+\/$/, 'gMk = "HML"; cAp = 1; eNo = rMb ? "div.search_box" : "div.section3"; eUl = null; sId = /([^/]+)/; eAt = rMb ? \'h3>a\' : \'h3\';'],
		// kakuyomu
		[/^https:\/\/kakuyomu\.jp\/(picku|ranki|recent_w)/, 'gMk = "KYU"; eNo = "div.widget-work"; eUl = "a.widget-workCard-authorLabel"; sId = /users\\/(.*)$/; sTg = "a[itemprop=\'keywords\']";'],
		[/^https:\/\/kakuyomu\.jp\/search/, 'gMk = "KYU"; cFt = 1; eNo = rMb ? \'div[class*="Spacer_margin-ml-m__"]\' : \'div[class*="NewBox_borderSize-bb"]\'; eUl = rMb ? \'span[class*="workLabelAuthor__"] a\' : "div.partialGiftWidgetActivityName>a"; sId = /users\\/(.*)$/; sTg = "a[href^=\'/tags/\']";'],
		[/^https:\/\/kakuyomu\.jp\/recent_r/, 'gMk = "KYU"; cFt = 1; eNo = "div.recentReviews-item"; eUl = "a.widget-workCard-authorLabel"; sId = /users\\/(.*)$/; sTg = "a[href^=\'/tags/\']";'],
		[/^https:\/\/kakuyomu\.jp\/.*\/comme/, 'gMk = "KYU"; cFt = 1; eNo = rMb ? \'div[class^="NewBox_box__"]>ul>li\' : \'ul:nth-child(1) li\'; eUl = \'div.partialGiftWidgetActivityName>a\'; sId = /users\\/(.*)$/;'],
		[/^https:\/\/kakuyomu\.jp\/.*\/episo/, 'gMk = "KYU"; cFt = 2; eOn = "#episodeFooter-cheerComments-panel-mainContents"; eNo = "ul.widget-cheerCommentList li"; eUl = "h5.widget-cheerComment-author a"; sId = /users\\/(.*)$/;'],
		[/^https:\/\/kakuyomu\.jp\/(users\/|works\/[0-9]+$)/, 'gMk = "KYU"; cFt = 1; cAp = true; eUl = uRi.includes("users") ? \'div[class^="HeaderText"]>a\' : \'div.partialGiftWidgetActivityName>a\'; sId = /users\\/(.*)$/;'],
		// Narou
		[/^https:\/\/novelcom\.syosetu\.com\/impre/, 'gMk = "NUC"; eNo = rMb ? "div.impression" : "div.waku"; eUl = "div.comment_authorbox>div>a"; sId = /\\/(\\d+)/; eAt = "div.comment_authorbox>div";'],
		[/^https:\/\/(mypage|ncode)\.syosetu\.com\/[A-z0-9]+\/?$/, 'gMk = "NRK"; cAp = true; eUl = uRi.includes("ncode") ? \'div.novel_writername>a\' : \'div.p-userheader__username\'; sId = /\\/(\\d+)/;'],
		[/^https:\/\/yomou\.syosetu\.com\/rank\//, 'gMk = "NRK"; eNo = "div.p-ranklist-item"; eUl = "div.p-ranklist-item__author a"; sId = /\\/(\\d+)/; sTg = "div.p-ranklist-item__keyword a";'],
		[/^https:\/\/yomou\.syosetu\.com\/search/, 'gMk = "NRK"; eNo = rMb ? "div.smpnovel_list" : "div.searchkekka_box"; eUl = rMb ? null : "a:nth-child(2)"; sId = rMb ? /:(.*)/ : /\\/(\\d+)/; sTg = "a[href*=\'?word\']"; eAt = "p.author";'],
	];
	// Load site info
	function LSI() {
		for (let i = 0; i < SITE_INFO.length; i++) {
			if (SITE_INFO[i][0].test(uRi)) {
				eval(SITE_INFO[i][1]);
			}
		}
	}
	LSI();
	//console.log( {gMk, cFt, cAp, eOn, eNo, eUl, sId, sTg, eAt} );
	// GM menu
	GM_registerMenuCommand("View", SVM);
	GM_registerMenuCommand("List", CBM);
	// Read List
	URD();
	function URD() {
		const trc = GM_getValue(gMk);
		tlo = trc ? trc : { BAL:[], BTL:[] };
	}
	// Save List
	function USV() {
		if (gMk && JSON.stringify(tlo) !== JSON.stringify(GM_getValue(gMk))) {
			GM_setValue(gMk, tlo);
		}
	}

	// Script Fire Time
	switch (cFt) {
		case 1:
			// Delay
			sleep(1500).then(() => FMD());
			break;
		case 2:
			// Mutation observer
			MOC();
			break;
		default:
			// Normal
			FMD();
	}
	function MOC() {
		const obs = new MutationObserver(() => {
			obs.disconnect();
			FMD();
		});
		obs.observe(document.querySelector(eOn), { childList: true, subtree: true, });
	}

	// Filtering mode
	function FMD() {
		if (cAp) {
			// Filtering single target
			FST();
		} else {
			// Filtering multiple targets
			FMT();
		}
		if (!document.getElementById("nrcf_fcb")) {
			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", tlo.BAL, uId);
		eLk.style.color = rBk ? "fuchsia" : "dodgerblue";
	}
	// Filtering multiple targets
	function FMT() {
		const no = 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 === "NRK" && rMb) ) {
				if (!eLk) {
					switch (gMk) {
						// Narou search mobile no author link
						case "NRK": {
							const tca = document.createElement("p");
							tca.classList.add("author");
							tca.style.color = "#fe7643";
							const head = no[i].querySelector("div.accordion_head");
							// AD
							if (!head) {
								//console.log("===A D===");
								//rBk = true;
								continue;
							}
							tca.textContent = head.textContent.split("\n")[3];
							no[i].querySelector("a.read_button").after(tca);
							eLk = tca;
							uId = eLk.textContent.match(sId)[1];
							break;
						}
						// Narou nologin user fix
						default:
							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, "a", tlo.BAL, 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), "t", tlo.BTL, tag) : CHK(tno[j], "t", tlo.BTL, tag);
					if (rBk) break;
				}
			}
			// Blocked show type
			no[i].style.display = !cSv && rBk ? "none" : "";
			no[i].style.opacity = cSv && rBk ? "0.5" : "1";
		}
	}
	// Check keyword
	function CHK(ele, n, l, s) {
		const result = l.some((v) => s === v);
		if (!ele.classList.contains("c_h_k")) {
			ele.classList.add("c_h_k");
			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 cbtn = document.getElementById("nrcf_fcb");
		if (!cSv) {
			cSv = true;
			cbtn.textContent = "📙";
			document.addEventListener("click", ECH);
			URD();
		} else {
			cSv = false;
			cbtn.textContent = "📘";
			document.removeEventListener("click", ECH);
			// Auto save list
			USV();
		}
		FMD();
	}
	// Handler
	function ECH(e) {
		e.preventDefault();
		const tEle = e.target.classList.contains("c_h_k") ? e.target
					: e.target.parentElement.classList.contains("c_h_k") ? e.target.parentElement
					: null;
		//console.log(tEle);
		if (tEle) {
			const tda = tEle.getAttribute("data-lkw");
			const tlst = tda.slice(0, 1) === "a" ? tlo.BAL : tlo.BTL;
			const tid = tda.slice(1);
			const li = tlst.findIndex((v) => v === tid);
			if (li !== -1) {
				tlst.splice(li,1);
			} else {
				tlst.push(tid);
			}
			FMD();
		}
	}

	// Custom Blocklists Menu
	function CBM() {
		if (!document.getElementById("nrcf_blm")) {
			const cbl = document.body.appendChild(document.createElement("div"));
			const pos = !rMb ? " width: 50%; left: 25%;" : " width: 98%; left: 1%;";
			cbl.id = "nrcf_blm";
			cbl.style = "position: fixed;" + pos + " overflow-y: scroll; overflow-wrap: break-word; height: 52%; top:10%; z-index: 9999; background-color: #f1f3f5; display: none;";
		}
		const blm = document.getElementById("nrcf_blm");
		if (!cSb) {
			cSb = true;
			UBM();
			blm.style.display = "";
			blm.addEventListener("click", DBL);
		} else {
			cSb = false;
			blm.style.display = "none";
			blm.removeEventListener("click", DBL);
			blm.innerHTML = "";
		}
	}
	// Delete Block List
	function DBL(e) {
		const eT = e.target;
		let key, clst;
		if (eT.className === "nrcf_sav" || eT.className === "nrcf_sor" || eT.className === "nrcf_del") {
			key = eT.parentElement.textContent.slice(0, 3);
			// Patch for invalid save data
			if (key === "und") {
				key = "undefined";
			}
			clst = document.getElementById("blm_" + key).textContent;
		}
		if (eT.id === "nrcf_iop") {
			let copt = document.getElementById("nrcf_inp").innerText;
			if ( copt.startsWith("{") ) {
				copt = copt.slice(1, -1).split("\n");
				for (let i=1; i<copt.length-1; i++) {
					let ttt = i === (copt.length-2) ? copt[i] : copt[i].slice(0, -1);
					GM_setValue(ttt.slice(1, 4), JSON.parse(ttt.slice(7)));
					if (ttt.slice(1, 4) === gMk) {
						URD();
						FMD();
					}
				}
				UBM();
				document.getElementById("nrcf_inp").innerText = "Import completed";
			} else {
				document.getElementById("nrcf_inp").innerText = "Invalid input";
			}
		} else if (eT.id === "nrcf_sop") {
			const ctim = new Date().toISOString().split('T')[0];
			let copt = "{\n";
			const keys = GM_listValues();
			keys.forEach(k => {
				copt += '"' + k + '": ' + JSON.stringify(GM_getValue(k)) + ',\n';
			});
			SAT("nrcf_bak_" + ctim, copt.slice(0, -2) + "\n}");
			alert("File downloads completed");
		} else if (eT.className === "nrcf_sav") {
			GM_setValue(key, JSON.parse(clst));
			UBM();
			if (key === gMk) {
				URD();
				FMD();
			}
		} else if (eT.className === "nrcf_sav") {
			GM_setValue(key, JSON.parse(clst));
			UBM();
			if (key === gMk) {
				URD();
				FMD();
			}
		} else if (eT.className === "nrcf_sor") {
			const cal = JSON.parse(clst).BAL.sort();
			const ctl = JSON.parse(clst).BTL.sort();
			const clo = { BAL:cal, BTL:ctl };
			GM_setValue(key, clo);
			UBM();
			if (key === gMk) {
				URD();
			}
		} else if (eT.className === "nrcf_del") {
			GM_deleteValue(key);
			UBM();
			if (key === gMk) {
				URD();
				FMD();
			}
		}
	}
	// Update Blocklists Menu
	function UBM() {
		const blm = document.getElementById("nrcf_blm");
		const ost = "margin-left: 1em; cursor: pointer;";
		blm.innerHTML = `<h2>Blocklists:</h2>
			<p id="nrcf_inp" style="${ost} background-color: cyan;" contenteditable>Paste options here</p>
			<p id="nrcf_iop" style="${ost}">📤 Import options from above</p>
			<p id="nrcf_sop" style="${ost}">💾 Save options to local txt</p>`;
		const btt = ' type="button" style="margin-left: 1em; cursor: pointer; color: ';
		const keys = GM_listValues();
		keys.forEach(k => {
			blm.innerHTML += '<p style="margin-left: 1em; color: fuchsia;">' + k + ': ' + 
								'<span class="nrcf_sav"' + btt + 'green;">♻ Save</span>' + 
								'<span class="nrcf_sor"' + btt + 'blue;">🔀 Sort</span>' + 
								'<span class="nrcf_del"' + btt + 'red;">📛 Delete</span>' + 
							'</p>' + 
							'<span id="blm_' + k + '" style="margin-left: 1em;" contenteditable>' + JSON.stringify(GM_getValue(k)) + '</span>';
		});
	}

	// Create Float Button
	function CFB() {
		BCR("nrcf_fcb", "📘", "right: 2em;", "bottom: 2em;", "#55acee");
		BCR("nrcf_lst", "📚", "right: 4em;", "bottom: 2em;", "#eeac55");
		document.addEventListener("click",BLM);
	}
	function BLM(e){
		switch(e.target.id){
			case "nrcf_fcb":
				SVM();
				break;
			case "nrcf_lst":
				CBM();
				break;
		}
	}
	// Button creater
	function BCR(id, text, posx, posy, color) {
		const cbtn = document.body.appendChild(document.createElement("button"));
		cbtn.id = id;
		cbtn.textContent = text;
		cbtn.style = "position: fixed;width: 44px;height: 44px;z-index: 9999;font-size: 200%;opacity: 50%;cursor: pointer;border: none;padding: unset;color: " + color + ";" + posx + posy;
		cbtn.type = "button";
	}
	// Save as txt
	function SAT(title, text) {
		//console.log(text);
		const link = document.createElement("a");
		link.href = "data:text/plain;charset=utf-8," + encodeURIComponent(text);
		link.download = title + ".txt";
		link.style.display = "none";
		document.body.appendChild(link);
		link.click();
		document.body.removeChild(link);
	}
})();