Novel Ranking Comments Filter

Hide not interested content on ranking/comments page

安裝腳本?
作者推薦腳本

您可能也會喜歡 Novel Sites Enhance

安裝腳本
  1. // ==UserScript==
  2. // @name Novel Ranking Comments Filter
  3. // @name:ja 小説ランキング・コメント・フィルター
  4. // @namespace https://gf.qytechs.cn/en/users/1264733
  5. // @version 2024-07-16
  6. // @description Hide not interested content on ranking/comments page
  7. // @description:ja ランキング/コメントページで興味のないコンテンツを隠す
  8. // @author LE37
  9. // @license MIT
  10. // @include /^https:\/\/www\.alphapolis\.co\.jp\/(author|novel)\//
  11. // @include /^https:\/\/kakuyomu\.jp\/(genr|pick|rank|rece|sear|user|works\/)/
  12. // @include /^https:\/\/(mypage|ncode)\.syosetu\.com\/[A-z0-9]+\/?$/
  13. // @include /^https:\/\/yomou\.syosetu\.com\/(rank\/|search)/
  14. // @include /^https:\/\/novelcom\.syosetu\.com\/impression\//
  15. // @include /^https:\/\/syosetu\.org\/\?mode=r(ank|evi)/
  16. // @include /^https:\/\/syosetu\.org\/(novel|user)\/[0-9]+\//
  17. // @exclude https://www.alphapolis.co.jp/novel/ranking/annual
  18. // @exclude https://yomou.syosetu.com/rank/top/
  19. // @grant GM_setValue
  20. // @grant GM_getValue
  21. // @grant GM_deleteValue
  22. // @grant GM_listValues
  23. // @grant GM_registerMenuCommand
  24. // ==/UserScript==
  25.  
  26. (()=>{
  27. 'use strict';
  28. // GM key, Fire time, Observe node, Nodelist, userLink, userid, tag, alt;
  29. let gMk, cFt, eOn, eNo, eUl, sId, sTg, eAt;
  30. // Author page,
  31. let cAp = false;
  32. // Select mode
  33. let cSv = false;
  34. // Show blocklists
  35. let cSb = false;
  36. // Current list
  37. let tlo;
  38. // Mobile
  39. const rMb = navigator.userAgent.includes("Mobile");
  40. // Delay
  41. const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
  42. // Current url
  43. const uRi = location.href;
  44. // Site info
  45. const SITE_INFO = [
  46. // Alphapolis
  47. [/^https:\/\/www\.alphapolis\.co\.jp\/.*\/comment/, 'gMk = "APS"; eNo = "div.comment"; eUl = "span.name>a"; sId = /detail\\/(\\d+)$/;'],
  48. [/^https:\/\/www\.alphapolis\.co\.jp\/novel\/(index|ranki)/, 'gMk = "APS"; eNo = "div.section"; eUl = "div.author>a"; sId = /detail\\/(\\d+)$/; sTg = "li.tag a";'],
  49. [/^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+)$/;'],
  50. // Hameln
  51. [/^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";'],
  52. [/^https:\/\/syosetu\.org\/\?mode=revi/, 'gMk = "HML"; eNo = rMb ? "div.search_box" : "div.section3"; eUl = null; sId = /([^\\s]+)/; eAt = rMb ? "h4" : "h3";'],
  53. [/^https:\/\/syosetu\.org\/novel\/[0-9]+\/$/, 'gMk = "HML"; cAp = 1; eNo = rMb ? "div.search_box" : "div.section3"; eUl = null; sId = /([^/]+)/; eAt = \'span[itemprop="author"]\';'],
  54. [/^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\';'],
  55. // kakuyomu
  56. [/^https:\/\/kakuyomu\.jp\/(picku|ranki|recent_w)/, 'gMk = "KYU"; eNo = "div.widget-work"; eUl = "a.widget-workCard-authorLabel"; sId = /users\\/(.*)$/; sTg = "a[itemprop=\'keywords\']";'],
  57. [/^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/\']";'],
  58. [/^https:\/\/kakuyomu\.jp\/recent_r/, 'gMk = "KYU"; cFt = 1; eNo = "div.recentReviews-item"; eUl = "a.widget-workCard-authorLabel"; sId = /users\\/(.*)$/; sTg = "a[href^=\'/tags/\']";'],
  59. [/^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\\/(.*)$/;'],
  60. [/^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\\/(.*)$/;'],
  61. [/^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\\/(.*)$/;'],
  62. // Narou
  63. [/^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";'],
  64. [/^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+)/;'],
  65. [/^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";'],
  66. [/^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";'],
  67. ];
  68. // Load site info
  69. function LSI() {
  70. for (let i = 0; i < SITE_INFO.length; i++) {
  71. if (SITE_INFO[i][0].test(uRi)) {
  72. eval(SITE_INFO[i][1]);
  73. }
  74. }
  75. }
  76. LSI();
  77. //console.log( {gMk, cFt, cAp, eOn, eNo, eUl, sId, sTg, eAt} );
  78. // GM menu
  79. GM_registerMenuCommand("View", SVM);
  80. GM_registerMenuCommand("List", CBM);
  81. // Read List
  82. URD();
  83. function URD() {
  84. const trc = GM_getValue(gMk);
  85. tlo = trc ? trc : { BAL:[], BTL:[] };
  86. }
  87. // Save List
  88. function USV() {
  89. if (gMk && JSON.stringify(tlo) !== JSON.stringify(GM_getValue(gMk))) {
  90. GM_setValue(gMk, tlo);
  91. }
  92. }
  93.  
  94. // Script Fire Time
  95. switch (cFt) {
  96. case 1:
  97. // Delay
  98. sleep(1500).then(() => FMD());
  99. break;
  100. case 2:
  101. // Mutation observer
  102. MOC();
  103. break;
  104. default:
  105. // Normal
  106. FMD();
  107. }
  108. function MOC() {
  109. const obs = new MutationObserver(() => {
  110. obs.disconnect();
  111. FMD();
  112. });
  113. obs.observe(document.querySelector(eOn), { childList: true, subtree: true, });
  114. }
  115.  
  116. // Filtering mode
  117. function FMD() {
  118. if (cAp) {
  119. // Filtering single target
  120. FST();
  121. } else {
  122. // Filtering multiple targets
  123. FMT();
  124. }
  125. if (!document.getElementById("nrcf_fcb")) {
  126. CFB();
  127. }
  128. }
  129. // Filtering single target
  130. function FST() {
  131. let rBk = false;
  132. const eLk = eUl ? document.querySelector(eUl) : document.querySelector(eAt);
  133. let uId;
  134. // Narou author page fix
  135. if (gMk === "NRK") {
  136. uId = eLk.href ? eLk.href.match(sId)[1] : uRi.match(sId)[1];
  137. } else {
  138. uId = eUl ? eLk.href.match(sId)[1] : eLk.textContent.match(sId)[1];
  139. }
  140. rBk = CHK(eLk, "a", tlo.BAL, uId);
  141. eLk.style.color = rBk ? "fuchsia" : "dodgerblue";
  142. }
  143. // Filtering multiple targets
  144. function FMT() {
  145. const no = document.querySelectorAll(eNo);
  146. for (let i = 0; i < no.length; i++) {
  147. let rBk = false;
  148. let uId;
  149. // Filtering content contain single id(link) or text
  150. let eLk = eUl ? no[i].querySelector(eUl) : no[i].querySelector(eAt);
  151.  
  152. if ( eLk !== null
  153. || gMk === "NUC"
  154. || (gMk === "NRK" && rMb) ) {
  155. if (!eLk) {
  156. switch (gMk) {
  157. // Narou search mobile no author link
  158. case "NRK": {
  159. const tca = document.createElement("p");
  160. tca.classList.add("author");
  161. tca.style.color = "#fe7643";
  162. const head = no[i].querySelector("div.accordion_head");
  163. // AD
  164. if (!head) {
  165. //console.log("===A D===");
  166. //rBk = true;
  167. continue;
  168. }
  169. tca.textContent = head.textContent.split("\n")[3];
  170. no[i].querySelector("a.read_button").after(tca);
  171. eLk = tca;
  172. uId = eLk.textContent.match(sId)[1];
  173. break;
  174. }
  175. // Narou nologin user fix
  176. default:
  177. eLk = no[i].querySelector(eAt);
  178. uId = eLk.textContent.split("\n")[2];
  179. }
  180. } else {
  181. uId = eUl ? eLk.href.match(sId)[1] : eLk.textContent.match(sId)[1];
  182. }
  183. //console.log(uId);
  184. rBk = CHK(eLk, "a", tlo.BAL, uId);
  185. }
  186. if (sTg && !rBk) {
  187. // Filtering content contain multiple tags(text)
  188. // Tag node
  189. let tno;
  190. // Hameln mobile origin tag, custom tag
  191. let tot, tct;
  192. if (gMk === "HML" && rMb) {
  193. tot = no[i].querySelector(".trigger p:nth-child(4)");
  194. tct = no[i].querySelector(sTg);
  195. if (!tct) {
  196. tno = tot.textContent.slice(3).match(/[^\s]+/g);
  197. tot.innerHTML = "";
  198. } else {
  199. tno = no[i].querySelectorAll(sTg);
  200. }
  201. } else {
  202. tno = no[i].querySelectorAll(sTg);
  203. }
  204. for (let j = 0; j < tno.length; j++) {
  205. let tag;
  206. if (tot && !tct) {
  207. tag = tno[j];
  208. tot.innerHTML += '<span id="tag_' + j + '">' + tag + '</span>';
  209. } else {
  210. tag = tno[j].textContent;
  211. }
  212. //console.log(tag);
  213. rBk = tot && !tct ? CHK(no[i].querySelector("span#tag_"+j), "t", tlo.BTL, tag) : CHK(tno[j], "t", tlo.BTL, tag);
  214. if (rBk) break;
  215. }
  216. }
  217. // Blocked show type
  218. no[i].style.display = !cSv && rBk ? "none" : "";
  219. no[i].style.opacity = cSv && rBk ? "0.5" : "1";
  220. }
  221. }
  222. // Check keyword
  223. function CHK(ele, n, l, s) {
  224. const result = l.some((v) => s === v);
  225. if (!ele.classList.contains("c_h_k")) {
  226. ele.classList.add("c_h_k");
  227. ele.setAttribute("data-lkw", n + s);
  228. }
  229. if (cSv) {
  230. ele.style.border = result ? "thin solid fuchsia" : "thin solid dodgerblue";
  231. } else {
  232. ele.style.border = "none";
  233. }
  234. return result;
  235. }
  236.  
  237. // Select mode
  238. function SVM() {
  239. const cbtn = document.getElementById("nrcf_fcb");
  240. if (!cSv) {
  241. cSv = true;
  242. cbtn.textContent = "📙";
  243. document.addEventListener("click", ECH);
  244. URD();
  245. } else {
  246. cSv = false;
  247. cbtn.textContent = "📘";
  248. document.removeEventListener("click", ECH);
  249. // Auto save list
  250. USV();
  251. }
  252. FMD();
  253. }
  254. // Handler
  255. function ECH(e) {
  256. e.preventDefault();
  257. const tEle = e.target.classList.contains("c_h_k") ? e.target
  258. : e.target.parentElement.classList.contains("c_h_k") ? e.target.parentElement
  259. : null;
  260. //console.log(tEle);
  261. if (tEle) {
  262. const tda = tEle.getAttribute("data-lkw");
  263. const tlst = tda.slice(0, 1) === "a" ? tlo.BAL : tlo.BTL;
  264. const tid = tda.slice(1);
  265. const li = tlst.findIndex((v) => v === tid);
  266. if (li !== -1) {
  267. tlst.splice(li,1);
  268. } else {
  269. tlst.push(tid);
  270. }
  271. FMD();
  272. }
  273. }
  274.  
  275. // Custom Blocklists Menu
  276. function CBM() {
  277. if (!document.getElementById("nrcf_blm")) {
  278. const cbl = document.body.appendChild(document.createElement("div"));
  279. const pos = !rMb ? " width: 50%; left: 25%;" : " width: 98%; left: 1%;";
  280. cbl.id = "nrcf_blm";
  281. cbl.style = "position: fixed;" + pos + " overflow-y: scroll; overflow-wrap: break-word; height: 52%; top:10%; z-index: 9999; background-color: #f1f3f5; display: none;";
  282. }
  283. const blm = document.getElementById("nrcf_blm");
  284. if (!cSb) {
  285. cSb = true;
  286. UBM();
  287. blm.style.display = "";
  288. blm.addEventListener("click", DBL);
  289. } else {
  290. cSb = false;
  291. blm.style.display = "none";
  292. blm.removeEventListener("click", DBL);
  293. blm.innerHTML = "";
  294. }
  295. }
  296. // Delete Block List
  297. function DBL(e) {
  298. const eT = e.target;
  299. let key, clst;
  300. if (eT.className === "nrcf_sav" || eT.className === "nrcf_sor" || eT.className === "nrcf_del") {
  301. key = eT.parentElement.textContent.slice(0, 3);
  302. // Patch for invalid save data
  303. if (key === "und") {
  304. key = "undefined";
  305. }
  306. clst = document.getElementById("blm_" + key).textContent;
  307. }
  308. if (eT.id === "nrcf_iop") {
  309. let copt = document.getElementById("nrcf_inp").innerText;
  310. if ( copt.startsWith("{") ) {
  311. copt = copt.slice(1, -1).split("\n");
  312. for (let i=1; i<copt.length-1; i++) {
  313. let ttt = i === (copt.length-2) ? copt[i] : copt[i].slice(0, -1);
  314. GM_setValue(ttt.slice(1, 4), JSON.parse(ttt.slice(7)));
  315. if (ttt.slice(1, 4) === gMk) {
  316. URD();
  317. FMD();
  318. }
  319. }
  320. UBM();
  321. document.getElementById("nrcf_inp").innerText = "Import completed";
  322. } else {
  323. document.getElementById("nrcf_inp").innerText = "Invalid input";
  324. }
  325. } else if (eT.id === "nrcf_sop") {
  326. const ctim = new Date().toISOString().split('T')[0];
  327. let copt = "{\n";
  328. const keys = GM_listValues();
  329. keys.forEach(k => {
  330. copt += '"' + k + '": ' + JSON.stringify(GM_getValue(k)) + ',\n';
  331. });
  332. SAT("nrcf_bak_" + ctim, copt.slice(0, -2) + "\n}");
  333. alert("File downloads completed");
  334. } else if (eT.className === "nrcf_sav") {
  335. GM_setValue(key, JSON.parse(clst));
  336. UBM();
  337. if (key === gMk) {
  338. URD();
  339. FMD();
  340. }
  341. } else if (eT.className === "nrcf_sav") {
  342. GM_setValue(key, JSON.parse(clst));
  343. UBM();
  344. if (key === gMk) {
  345. URD();
  346. FMD();
  347. }
  348. } else if (eT.className === "nrcf_sor") {
  349. const cal = JSON.parse(clst).BAL.sort();
  350. const ctl = JSON.parse(clst).BTL.sort();
  351. const clo = { BAL:cal, BTL:ctl };
  352. GM_setValue(key, clo);
  353. UBM();
  354. if (key === gMk) {
  355. URD();
  356. }
  357. } else if (eT.className === "nrcf_del") {
  358. GM_deleteValue(key);
  359. UBM();
  360. if (key === gMk) {
  361. URD();
  362. FMD();
  363. }
  364. }
  365. }
  366. // Update Blocklists Menu
  367. function UBM() {
  368. const blm = document.getElementById("nrcf_blm");
  369. const ost = "margin-left: 1em; cursor: pointer;";
  370. blm.innerHTML = `<h2>Blocklists:</h2>
  371. <p id="nrcf_inp" style="${ost} background-color: cyan;" contenteditable>Paste options here</p>
  372. <p id="nrcf_iop" style="${ost}">📤 Import options from above</p>
  373. <p id="nrcf_sop" style="${ost}">💾 Save options to local txt</p>`;
  374. const btt = ' type="button" style="margin-left: 1em; cursor: pointer; color: ';
  375. const keys = GM_listValues();
  376. keys.forEach(k => {
  377. blm.innerHTML += '<p style="margin-left: 1em; color: fuchsia;">' + k + ': ' +
  378. '<span class="nrcf_sav"' + btt + 'green;">♻ Save</span>' +
  379. '<span class="nrcf_sor"' + btt + 'blue;">🔀 Sort</span>' +
  380. '<span class="nrcf_del"' + btt + 'red;">📛 Delete</span>' +
  381. '</p>' +
  382. '<span id="blm_' + k + '" style="margin-left: 1em;" contenteditable>' + JSON.stringify(GM_getValue(k)) + '</span>';
  383. });
  384. }
  385.  
  386. // Create Float Button
  387. function CFB() {
  388. BCR("nrcf_fcb", "📘", "right: 2em;", "bottom: 2em;", "#55acee");
  389. BCR("nrcf_lst", "📚", "right: 4em;", "bottom: 2em;", "#eeac55");
  390. document.addEventListener("click",BLM);
  391. }
  392. function BLM(e){
  393. switch(e.target.id){
  394. case "nrcf_fcb":
  395. SVM();
  396. break;
  397. case "nrcf_lst":
  398. CBM();
  399. break;
  400. }
  401. }
  402. // Button creater
  403. function BCR(id, text, posx, posy, color) {
  404. const cbtn = document.body.appendChild(document.createElement("button"));
  405. cbtn.id = id;
  406. cbtn.textContent = text;
  407. 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;
  408. cbtn.type = "button";
  409. }
  410. // Save as txt
  411. function SAT(title, text) {
  412. //console.log(text);
  413. const link = document.createElement("a");
  414. link.href = "data:text/plain;charset=utf-8," + encodeURIComponent(text);
  415. link.download = title + ".txt";
  416. link.style.display = "none";
  417. document.body.appendChild(link);
  418. link.click();
  419. document.body.removeChild(link);
  420. }
  421. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址