Novel Ranking Filter [No GM_API Version]

Novel Ranking Filtering Bookmarklet for Mobile Browser

当前为 2024-06-19 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name           Novel Ranking Filter [No GM_API Version]
// @name:ja        小説ランキングフィルター [GM_APIなし]
// @namespace      https://greasyfork.org/en/users/1264733
// @version        2024-06-19
// @description    Novel Ranking Filtering Bookmarklet for Mobile Browser
// @description:ja モバイルブラウザ用小説ランキングフィルタリングブックマークレット
// @author         LE37
// @license        MIT
// @include        https://www.alphapolis.co.jp/novel/index*
// @include        https://www.alphapolis.co.jp/novel/ranking/*
// @include        https://kakuyomu.jp/genr*
// @include        https://kakuyomu.jp/pick*
// @include        https://kakuyomu.jp/rank*
// @include        https://kakuyomu.jp/sear*
// @include        https://kakuyomu.jp/rece*
// @include        https://syosetu.org/?mode=rank*
// @include        https://yomou.syosetu.com/rank/*
// @include        https://yomou.syosetu.com/search*
// @exclude        https://www.alphapolis.co.jp/novel/ranking/annual
// @exclude        https://yomou.syosetu.com/rank/top/
// @grant          none
// ==/UserScript==

(()=>{
	/*LS20240619*/
	'use strict';
	// GM key, Nodelist, userLink, userid, tag, alt;
	let gMk, eNo, eUl, sId, sTg, eAt;
	// View mode 
	let cSv = false;
	// Show/hide Blocklist
	let sFb = false;
	// Client type
	const rMb = navigator.userAgent.includes("Mobile");
	const path = location.pathname;
	switch (location.host) {
		case "www.alphapolis.co.jp":
			gMk = "A";
			eNo = "div.section";
			eUl = "div.author>a";
			sId = /detail\/(\d+)$/;
			sTg = "li.tag a";
			break;
		case "syosetu.org":
			gMk = "H";
			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";
			break;
		case "kakuyomu.jp":
			gMk = "K";
			sId = /users\/(.*)$/;
			if (path.startsWith("/search")) {
				eNo = rMb ? 'div[class*="Spacer_margin-ml-m__"]' : 'div[class*="NewBox_borderSize-bb"]';
				eUl = rMb ? 'span[class*="workLabelAuthor__"] a' : "div.partialGiftWidgetActivityName>a";
				sTg = 'a[href^="/tags/"]';
			} else if (path.startsWith("/recent_r")) {
				eNo = "div.recentReviews-item";
				eUl = "a.widget-workCard-authorLabel";
				sTg = 'a[href^="/tags/"]';
			} else {
				eNo = "div.widget-work";
				eUl = "a.widget-workCard-authorLabel";
				sTg = "a[itemprop='keywords']";
			}
			break;
		case "yomou.syosetu.com":
			gMk = "N";
			if (path.startsWith("/search")) {
				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";
			} else {
				eNo = "div.p-ranklist-item";
				eUl = "div.p-ranklist-item__author a";
				sId = /\/(\d+)/;
				sTg = "div.p-ranklist-item__keyword a";
			}
			break;
	}
	//console.log( {gMk, eNo, eUl, sId, sTg, eAt} );
	// Read list
	const G = JSON.parse(localStorage.getItem(gMk));
	let O = G ? G : { AL:[], TL:[] };
	let tal = O.AL;
	let ttl = O.TL;
	// Save list
	function USV() {
		O = { AL:tal, TL:ttl };
		localStorage.setItem(gMk, JSON.stringify(O));
	}
	// Sort list
	function UST() {
		tal.sort();
		ttl.sort();
		USV();
	}
	const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
	// Script fire time
	if (gMk === "K" && path.startsWith("/search")) {
		sleep(1500).then(() => FMD());
	} else {
		FMD();
	}
	CFB();
	// Filtering multiple targets
	function FMD() {
		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 === "N" && rMb) ) {
				if (!eLk) {
					// Narou search mobile no author link
					if (gMk === "N") {
						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];
					}
				} else {
					uId = eUl ? eLk.href.match(sId)[1] : eLk.textContent.match(sId)[1];
				}
				//console.log(uId);
				rBk = CHK(eLk, "a", 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 === "H" && 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", ttl, tag) : CHK(tno[j], "t", ttl, 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 r = 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 = r ? "thin solid fuchsia" : "thin solid dodgerblue";
		} else {
			ele.style.border = "none";
		}
		return r;
	}

	// Select mode
	function SVM() {
		const btn = document.getElementById("nrf_fcb");
		if (!cSv) {
			cSv = true;
			btn.textContent = "📙";
			document.addEventListener("click", ECH);
		} else {
			cSv = false;
			btn.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" ? tal : ttl;
			const tid = tda.slice(1);
			const li = tlst.findIndex((v) => v === tid);
			if (li !== -1) {
				tlst.splice(li,1);
			} else {
				tlst.push(tid);
			}
			FMD();
		}
	}

	// Create Blocklists Menu
	function CBM() {
		if (!document.getElementById("nrf_blm")) {
			const cbl = document.body.appendChild(document.createElement("div"));
			const pos = !rMb ? " width: 50%; left: 25%;" : " width: 98%; left: 1%;";
			cbl.id = "nrf_blm";
			cbl.style = "position: fixed;" + pos + " overflow-y: scroll; height: 52%; top:10%; z-index: 9999; background-color: #f1f3f5; display: none;";
		}
		const blm = document.getElementById("nrf_blm");
		if (!sFb) {
			sFb = true;
			UBM();
			blm.style.display = "";
			blm.addEventListener("click", DBL);
		} else {
			sFb = false;
			blm.style.display = "none";
			blm.removeEventListener("click", DBL);
			blm.innerHTML = "";
		}
	}
	// Delete Block List
	function DBL(e) {
		if (e.target.classList.contains("nrf_dbl")) {
			const key = e.target.textContent;
			localStorage.removeItem(key);
			UBM();
			// Delete current
			if (key === gMk) {
				// Delete cache
				tal = [];
				ttl = [];
				USV();
				FMD();
			}
		}
	}
	// Update Blocklists Menu
	function UBM() {
		const blm = document.getElementById("nrf_blm");
		blm.innerHTML = "";
		Object.keys(localStorage).forEach(k => {
			blm.innerHTML += '<p style="margin-left: 1em; font-size: 1em; line-height: 2em;">' +
								'<span class="nrf_dbl" type="button" style="color: red; cursor: pointer;">' + k + '</span>' + 
								'<span>: ' + localStorage.getItem(k) + '</span>' + 
							'</p>';
		});
	}

	// Create Float Button
	function CFB() {
		const btn = document.body.appendChild(document.createElement("button"));
		// Button Style
		btn.id = "nrf_fcb";
		btn.textContent = "📘";
		btn.style = "position: fixed; bottom: 2em; right: 2em; width: 44px; height: 44px; z-index: 9999; font-size: 200%; opacity: 50%; cursor:pointer; border: none; padding: unset;";
		btn.type = "button";
		btn.addEventListener("click", (e) => { SVM(); });
		btn.addEventListener("dblclick", (e) => { CBM(); });
	}
})();