Content Filter

Hide not interested content

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

  1. // ==UserScript==
  2. // @name Content Filter
  3. // @name:ja コンテンツフィルター
  4. // @namespace https://greasyfork.org/en/users/1264733
  5. // @version 2024-04-14
  6. // @description Hide not interested content
  7. // @description:ja 興味のない内容を隠す
  8. // @author LE37
  9. // @license MIT
  10. // @include https://forum.palemoon.org/viewforum*
  11. // @include https://forum.palemoon.org/viewtopic*
  12. // @include https://forum.vivaldi.net/category/*
  13. // @include https://forum.vivaldi.net/topic/*
  14. // @include https://kakuyomu.jp/pickup_works*
  15. // @include https://kakuyomu.jp/rankings/*
  16. // @include https://kakuyomu.jp/recent_works*
  17. // @include https://kakuyomu.jp/works/*/comments*
  18. // @include https://kakuyomu.jp/works/*/episodes/*
  19. // @include https://novelcom.syosetu.com/impression/*
  20. // @include https://yomou.syosetu.com/rank/*
  21. // @include https://syosetu.org/?mode=rank*
  22. // @include https://syosetu.org/?mode=review*
  23. // @include https://www.alphapolis.co.jp/novel/index*
  24. // @include https://www.alphapolis.co.jp/novel/ranking/*
  25. // @include https://www.alphapolis.co.jp/novel/*/comment*
  26. // @include https://www.ign.com/articles/*
  27. // @include https://www.yandex.com/search/*
  28. // @include https://yandex.com/search/*
  29. // @exclude https://www.alphapolis.co.jp/novel/ranking/annual
  30. // @exclude https://yomou.syosetu.com/rank/top/
  31. // @grant GM_registerMenuCommand
  32. // @grant GM_setValue
  33. // @grant GM_getValue
  34. // ==/UserScript==
  35.  
  36. (()=>{
  37. 'use strict';
  38. // GM Key
  39. let gMk;
  40. switch (location.host) {
  41. case "www.alphapolis.co.jp":
  42. gMk = "APS";
  43. break;
  44. case "syosetu.org":
  45. gMk = "HML";
  46. break;
  47. case "www.ign.com":
  48. gMk = "IGN";
  49. break;
  50. case "kakuyomu.jp":
  51. gMk = "KYU";
  52. break;
  53. case "novelcom.syosetu.com":
  54. gMk = "NUC";
  55. break;
  56. case "yomou.syosetu.com":
  57. gMk = "NRK";
  58. break;
  59. case "forum.palemoon.org":
  60. gMk = "PMF";
  61. break;
  62. case "forum.vivaldi.net":
  63. gMk = "VVF";
  64. break;
  65. case "yandex.com":
  66. case "www.yandex.com":
  67. gMk = "YDX";
  68. break;
  69. default:
  70. //console.log("DoNothing");
  71. }
  72. if (gMk) {
  73. RUN();
  74. }
  75. function RUN() {
  76. // GM Menu
  77. GM_registerMenuCommand("View", SVM);
  78. GM_registerMenuCommand("Save", USV);
  79. // cSr: ShadowsRoot, cFt: FireTime, eOn: MutationObserverNode, eIo: IntersectionObserverNode, eNo: Node, eUl: UserLink, sId: UserID, sTg: Tag, eAt: Alter;
  80. let cSr, cFt, eOn, eIo, eNo, eUl, sId, sTg, eAt;
  81. // Client Type
  82. const rMb = navigator.userAgent.includes("Mobile");
  83. const uRi = location.href;
  84. switch (gMk) {
  85. case "APS":
  86. // Alphapolis
  87. cFt = 0;
  88. if (uRi.includes("comment")) {
  89. // Comments
  90. eNo = "div.comment";
  91. eUl = "span.name>a";
  92. } else {
  93. // Ranking
  94. eNo = "div.section";
  95. eUl = "div.author>a";
  96. sTg = "li.tag a";
  97. }
  98. sId = /detail\/(\d+)$/;
  99. break;
  100. case "HML":
  101. // Hameln
  102. cFt = 0;
  103. eNo = rMb ? "div.search_box" : "div.section3";
  104. if (uRi.includes("rank")) {
  105. // Ranking
  106. eUl = "div.blo_title_sak a";
  107. sTg = "div.all_keyword:nth-child(9) a";
  108. } else {
  109. // Comments
  110. eUl = "h3>a:nth-child(1)";
  111. }
  112. sId = /((?<=uid=).*|(\d+)(?=\/))/;
  113. break;
  114. case "IGN":
  115. // IGN
  116. cSr = 1;
  117. cFt = 3;
  118. eIo = '#comments-section';
  119. eOn = '.spcv_conversation';
  120. eNo = "li";
  121. eUl = null;
  122. eAt = 'span[data-spot-im-class="message-username"]';
  123. sId = /(.*)/;
  124. break;
  125. case "KYU":
  126. // Kakuyomu
  127. if (uRi.includes("/pickup") || uRi.includes("/rank") || uRi.includes("/recent")) {
  128. // Ranking
  129. cFt = 0;
  130. eNo = "div.widget-work";
  131. eUl = "a.widget-workCard-authorLabel";
  132. sId = /users\/(.*)$/;
  133. sTg = "a[itemprop='keywords']";
  134. } else if (uRi.includes("comments")) {
  135. // Comments
  136. cFt = 2;
  137. eOn = '#__next';
  138. eNo = rMb ? 'div[class^="NewBox_box__"]>ul>li' : 'ul:nth-child(1) li';
  139. eUl = 'div.partialGiftWidgetActivityName>a';
  140. } else {
  141. // Comments in Episode
  142. cFt = 2;
  143. eOn = "#episodeFooter-cheerComments-panel-mainContents";
  144. eNo = "ul.widget-cheerCommentList li";
  145. eUl = "h5.widget-cheerComment-author a";
  146. }
  147. sId = /users\/(.*)$/;
  148. break;
  149. case "NUC":
  150. // Narou Comments
  151. cFt = 0;
  152. eNo = rMb ? "div.impression" : "div.waku";
  153. eUl = "div.comment_authorbox>div>a";
  154. eAt = "div.comment_authorbox>div";
  155. sId = /\/(\d+)/;
  156. break;
  157. case "NRK":
  158. // Narou Ranking
  159. cFt = 0;
  160. eNo = "div.p-ranklist-item";
  161. eUl = "div.p-ranklist-item__author a";
  162. sId = /\/(\d+)/;
  163. sTg = "div.p-ranklist-item__keyword a";
  164. break;
  165. case "PMF":
  166. // Palemoon Forum
  167. cFt = 0;
  168. if (uRi.includes("viewtopic")) {
  169. // Topic
  170. eNo = "#page-body div.post";
  171. eUl = 'a[class^="username"]';
  172. sId = /u=(\d+)/;
  173. } else {
  174. // Index
  175. eNo = "ul.topiclist>li";
  176. eUl = "div.topic-poster>a";
  177. sId = /u=(\d+)/;
  178. }
  179. break;
  180. case "VVF":
  181. // Vivaldi Forum
  182. cFt = 0;
  183. if (uRi.includes("topic")) {
  184. // Topic
  185. eNo = "ul.posts>li";
  186. eUl = "small.d-flex a";
  187. sId = /user\/(.*)/;
  188. } else {
  189. // Index
  190. eNo = "ul.topic-list li";
  191. eUl = "small.hidden-xs>a";
  192. sId = /user\/(.*)/;
  193. }
  194. break;
  195. case "YDX":
  196. // Yandex Search
  197. cFt = 0;
  198. eNo = rMb ? "div.serp-item" : "#search-result>li";
  199. eUl = rMb ? null : "div.Path>a.Link";
  200. eAt = "span.Path-Item>b";
  201. sId = rMb ? /(.*)/ : /\/([^\/]+)/;
  202. break;
  203. }
  204. // Read List
  205. const URD = GM_getValue(gMk);
  206. let tlo = URD ? URD : { BAL:[], BTL:[] };
  207. const tal = tlo.BAL;
  208. const ttl = tlo.BTL;
  209. // Save List
  210. function USV() {
  211. tlo = { BAL:tal, BTL:ttl };
  212. GM_setValue(gMk, tlo);
  213. }
  214. // Select View
  215. let cSv = 0;
  216. // Script Fire Time
  217. switch (cFt) {
  218. case 1:
  219. RSC();
  220. break;
  221. case 2:
  222. MOC();
  223. break;
  224. case 3:
  225. IOC();
  226. break;
  227. case 0:
  228. default:
  229. FTR();
  230. }
  231. // ReadyState
  232. function RSC() {
  233. document.addEventListener("readystatechange", (e) => {
  234. if (e.target.readyState === "complete") {
  235. FTR();
  236. }
  237. });
  238. }
  239. // MutationObserver
  240. function MOC() {
  241. const obs = new MutationObserver(() => {
  242. FTR();
  243. //obs.disconnect();
  244. });
  245. // Shadowroot spotim fix
  246. const obn = cSr ? document.querySelector('div[data-spotim-module]').firstElementChild.shadowRoot.querySelectorAll(eOn)[0] : document.querySelector(eOn);
  247. obs.observe(obn, {
  248. childList: true,
  249. subtree: true
  250. });
  251. }
  252. // IntersectionObserver
  253. function IOC() {
  254. const ioc = new IntersectionObserver((entries) => {
  255. if (entries[0].intersectionRatio <= 0) return;
  256. FTR();
  257. // IGN fix
  258. if (gMk === "IGN") {
  259. MOC();
  260. }
  261. ioc.disconnect();
  262. });
  263. ioc.observe(document.querySelector(eIo));
  264. }
  265. // Filtering
  266. function FTR() {
  267. // Shadowroot spotim fix
  268. // ShadowHost, ShadowRoot
  269. let eSh, eSr;
  270. if (cSr) {
  271. eSh = document.querySelector('div[data-spotim-module]').firstElementChild;
  272. if (eSh) {
  273. eSr = eSh.shadowRoot;
  274. }
  275. //console.log(eSr);
  276. }
  277. const no = cSr ? eSr.querySelectorAll(eNo) : document.querySelectorAll(eNo);
  278. for (let i = 0; i < no.length; i++) {
  279. let rBk = false;
  280. let uId;
  281. // Filtering content contain single id(link) or text
  282. let eLk = eUl ? no[i].querySelector(eUl) : no[i].querySelector(eAt);
  283. if (eLk !== null || gMk === "NUC") {
  284. // Narou nologin user fix
  285. if (!eLk) {
  286. eLk = no[i].querySelector(eAt);
  287. uId = no[i].querySelector(eAt).textContent.split("\n")[2];
  288. } else {
  289. uId = eUl ? eLk.href.match(sId)[1] : eLk.textContent.match(sId)[1];
  290. }
  291. //console.log(uId);
  292. rBk = CHK(eLk, tal, uId);
  293. }
  294. if (!rBk) {
  295. // Filtering content contain multiple tags(text)
  296. const tno = no[i].querySelectorAll(sTg);
  297. if (tno !== null) {
  298. for (let j = 0; j < tno.length; j++) {
  299. const tag = tno[j].textContent;
  300. //console.log(tag);
  301. rBk = CHK(tno[j], ttl, tag);
  302. if (rBk) {
  303. break;
  304. }
  305. }
  306. }
  307. }
  308. // Blocked Show Type
  309. if (cSv === 0) {
  310. no[i].style.visibility = rBk ? "hidden" : "visible";
  311. no[i].style.opacity = "1";
  312. } else {
  313. no[i].style.visibility = "visible";
  314. no[i].style.opacity = rBk ? "0.5" : "1";
  315. }
  316. }
  317. }
  318. // CheckKeyword
  319. function CHK(ele, l, s) {
  320. const result = l.some((v) => s === v);
  321. if (cSv === 1) {
  322. ele.style.border = result ? "thin solid lime" : "thin solid red";
  323. } else {
  324. ele.style.border = "none";
  325. }
  326. return result;
  327. }
  328. // SelectViewMode
  329. function SVM() {
  330. if (cSv === 0) {
  331. cSv = 1;
  332. // Disable default click
  333. document.addEventListener("click", PAC, true);
  334. } else {
  335. cSv = 0;
  336. // Disable default click
  337. document.removeEventListener("click", PAC, true);
  338. // AutoSave
  339. USV();
  340. }
  341. FTR();
  342. }
  343. // PreventAnchorChange
  344. function PAC(e) {
  345. e.preventDefault();
  346. e.stopPropagation();
  347. const targetElement = cSr ? e.composedPath()[0] : e.target;
  348. //console.log(targetElement);
  349. let eLk;
  350. // Narou nologin user fix
  351. if (gMk === "NUC") {
  352. eLk = targetElement.href ? eUl : eAt;
  353. } else {
  354. eLk = eUl ? eUl : eAt;
  355. }
  356. if (targetElement.closest(eLk)) {
  357. let ai;
  358. switch (gMk) {
  359. // Narou nologin user fix
  360. case "NUC":
  361. ai = targetElement.href ? targetElement.href.match(sId)[1] : targetElement.textContent.split("\n")[2];
  362. break;
  363. // Yandex fix
  364. case "YDX":
  365. ai = targetElement.href ? targetElement.href.match(sId)[1] : targetElement.parentElement.href.match(sId)[1];
  366. break;
  367. default:
  368. ai = eUl ? targetElement.href.match(sId)[1] : targetElement.textContent.match(sId)[1];
  369. }
  370. //console.log(ai);
  371. UTL(e, ai, tal);
  372. } else if (targetElement.closest(sTg)) {
  373. const kd = targetElement.textContent;
  374. UTL(e, kd, ttl);
  375. }
  376. FTR();
  377. return false;
  378. }
  379. // UpdateTempList
  380. function UTL(e, s, l) {
  381. const li = l.findIndex((v) => v === s);
  382. if (li !== -1) {
  383. l.splice(li,1);
  384. } else {
  385. l.push(s);
  386. }
  387. //console.log(l);
  388. return l;
  389. }
  390. }
  391. })();