Greasy Fork is available in English.

Content Filter

Hide not interested content

Nainstalovat skript?
Skript doporučený autorem

Mohlo by se vám také líbit Novel Sites Enhance.

Nainstalovat skript
  1. // ==UserScript==
  2. // @name Content Filter
  3. // @name:ja コンテンツフィルター
  4. // @namespace https://greatest.deepsurf.us/en/users/1264733
  5. // @version 2024-07-16
  6. // @description Hide not interested content
  7. // @description:ja 興味のない内容を隠す
  8. // @author LE37
  9. // @license MIT
  10. // @include /^https:\/\/www\.alphapolis\.co\.jp\/(author|novel)\//
  11. // @include /^https:\/\/www\.bing\.com\/search/
  12. // @include /^https:\/\/www\.google\.com\/search/
  13. // @include /^https:\/\/greasyfork\.org\/[A-z-]+\/(discuss|scripts)/
  14. // @include /^https:\/\/(www\.|)ign\.com\//
  15. // @include /^https:\/\/kakuyomu\.jp\/(genr|pick|rank|rece|sear|user|works\/)/
  16. // @include /^https:\/\/forum\.palemoon\.org\/view(forum|topic)/
  17. // @include /^https:\/\/(mypage|ncode)\.syosetu\.com\/[A-z0-9]+\/?$/
  18. // @include /^https:\/\/yomou\.syosetu\.com\/(rank\/|search)/
  19. // @include /^https:\/\/novelcom\.syosetu\.com\/impression\//
  20. // @include /^https:\/\/syosetu\.org\/\?mode=r(ank|evi)/
  21. // @include /^https:\/\/syosetu\.org\/(novel|user)\/[0-9]+\//
  22. // @include /^https:\/\/forum\.vivaldi\.net\//
  23. // @include /^https:\/\/social\.vivaldi\.net\//
  24. // @include /^https:\/\/(www\.|)yandex\.com\/search/
  25. // @exclude https://www.alphapolis.co.jp/novel/ranking/annual
  26. // @exclude https://yomou.syosetu.com/rank/top/
  27. // @grant GM_setValue
  28. // @grant GM_getValue
  29. // @grant GM_deleteValue
  30. // @grant GM_listValues
  31. // @grant GM_registerMenuCommand
  32. // ==/UserScript==
  33.  
  34. (()=>{
  35. 'use strict';
  36. // GM Key
  37. let gMk;
  38. // Script firetime
  39. let cFt = 0;
  40. // MutationObserver targetNode, IntersectionObserver target
  41. let eOn, eIo;
  42. // Author/Novel page
  43. let cAp = false;
  44. // Shadowroot content
  45. let cSr = false;
  46. // Shadowhost, Shadowroot
  47. let eSh , eSr;
  48. // Target nodelist, UserLink, UserID, Tag, Alter
  49. let eNo, eUl, sId, sTg, eAt;
  50.  
  51. // Select mode
  52. let cSv = false;
  53. // Show blocklists
  54. let cSb = false;
  55. // Current list
  56. let tlo;
  57. // Mobile
  58. const rMb = navigator.userAgent.includes("Mobile");
  59. // Delay
  60. const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
  61. // Current url
  62. const uRi = location.href;
  63. switch (true) {
  64. // Alphapolis
  65. case /^https:\/\/www\.alphapolis\.co\.jp\/.*\/comment/.test(uRi):
  66. gMk = "APS";
  67. eNo = "div.comment";
  68. eUl = "span.name>a";
  69. sId = /detail\/(\d+)$/;
  70. break;
  71. case /^https:\/\/www\.alphapolis\.co\.jp\/novel\/(index|ranki)/.test(uRi):
  72. gMk = "APS";
  73. eNo = "div.section";
  74. eUl = "div.author>a";
  75. sId = /detail\/(\d+)$/;
  76. sTg = "li.tag a";
  77. break;
  78. case /^https:\/\/www\.alphapolis\.co\.jp\/(author|novel\/[0-9]+\/[0-9]+$)/.test(uRi):
  79. gMk = "APS";
  80. cAp = true;
  81. eUl = uRi.includes("author") ? "div.name>h1" : "div.author a";
  82. sId = /detail\/(\d+)$/;
  83. break;
  84. // BingSearch
  85. case /^https:\/\/www\.bing\.com\/search\?/.test(uRi):
  86. gMk = "BNG";
  87. eNo = "li.b_algo";
  88. eUl = null;
  89. eAt = "cite";
  90. sId = /((?<=https?:\/\/)[^\/]+)/;
  91. break;
  92. // GoogleSearch
  93. case /^https:\/\/www\.google\.com\/search\?/.test(uRi):
  94. gMk = "GGS";
  95. eNo = "div#rso>div";
  96. eUl = "a[jsname]";
  97. sId = /((?<=https?:\/\/)[^\/]+)/;
  98. break;
  99. // Greasyfork
  100. case /^https:\/\/greasyfork\.org\/[A-z-]+\/script/.test(uRi):
  101. gMk = "GFK";
  102. eNo = "li[data-script-id]";
  103. eUl = null;
  104. sId = /(.*)/;
  105. sTg = "dd.script-list-author a";
  106. eAt = "a.script-link";
  107. break;
  108. case /^https:\/\/greasyfork\.org\/[A-z-]+\/discus/.test(uRi):
  109. gMk = "GFK";
  110. eNo = "div.discussion-list-container";
  111. eUl = null;
  112. sId = /(.*)/;
  113. sTg = "a.user-link";
  114. eAt = "a.script-link";
  115. break;
  116. // Hameln
  117. case /^https:\/\/syosetu\.org\/\?mode=rank/.test(uRi):
  118. gMk = "HML";
  119. eNo = rMb ? "div.search_box" : "div.section3";
  120. eUl = null;
  121. sId = /:(.*)/;
  122. sTg = rMb ? 'span[id^="tag_"]' : 'div.all_keyword:nth-child(9) a';
  123. eAt = rMb ? "p:nth-child(2)" : "div.blo_title_sak";
  124. break;
  125. case /^https:\/\/syosetu\.org\/\?mode=revi/.test(uRi):
  126. gMk = "HML";
  127. eNo = rMb ? "div.search_box" : "div.section3";
  128. eUl = null;
  129. sId = /([^\s]+)/;
  130. eAt = rMb ? "h4" : "h3";
  131. break;
  132. case /^https:\/\/syosetu\.org\/novel\/[0-9]+\/$/.test(uRi):
  133. gMk = "HML";
  134. cAp = true;
  135. eNo = rMb ? "div.search_box" : "div.section3";
  136. eUl = null;
  137. sId = /([^/]+)/;
  138. eAt = 'span[itemprop="author"]';
  139. break;
  140. case /^https:\/\/syosetu\.org\/user\/[0-9]+\/$/.test(uRi):
  141. gMk = "HML";
  142. cAp = true;
  143. eNo = rMb ? "div.search_box" : "div.section3";
  144. eUl = null;
  145. sId = /([^/]+)/;
  146. eAt = rMb ? 'h3>a' : 'h3';
  147. break;
  148. // IGN
  149. case /^https:\/\/(www\.|)ign\.com\//.test(uRi):
  150. gMk = "IGN";
  151. cFt = 2;
  152. eOn = "body";
  153. cSr = true;
  154. eNo = "li";
  155. eUl = null;
  156. sId = /(.*)/;
  157. eAt = 'span[data-spot-im-class="message-username"]';
  158. break;
  159. // Kakuyomu
  160. case /^https:\/\/kakuyomu\.jp\/(genr|picku|ranki|recent_w)/.test(uRi):
  161. gMk = "KYU";
  162. eNo = "div.widget-work";
  163. eUl = "a.widget-workCard-authorLabel";
  164. sId = /users\/(.*)$/;
  165. sTg = "a[itemprop='keywords']";
  166. break;
  167. case /^https:\/\/kakuyomu\.jp\/search/.test(uRi):
  168. gMk = "KYU";
  169. cFt = 1;
  170. eNo = rMb ? 'div[class*="Spacer_margin-ml-m__"]' : 'div[class*="NewBox_borderSize-bb"]';
  171. eUl = rMb ? 'span[class*="workLabelAuthor__"] a' : "div.partialGiftWidgetActivityName>a";
  172. sId = /users\/(.*)$/;
  173. sTg = 'a[href^="/tags/"]';
  174. break;
  175. case /^https:\/\/kakuyomu\.jp\/recent_r/.test(uRi):
  176. gMk = "KYU";
  177. cFt = 1;
  178. eNo = "div.recentReviews-item";
  179. eUl = "a.widget-workCard-authorLabel";
  180. sId = /users\/(.*)$/;
  181. sTg = 'a[href^="/tags/"]';
  182. break;
  183. case /^https:\/\/kakuyomu\.jp\/.*\/comme/.test(uRi):
  184. gMk = "KYU";
  185. cFt = 1;
  186. eNo = rMb ? 'div[class^="NewBox_box__"]>ul>li' : 'ul:nth-child(1) li';
  187. eUl = 'div.partialGiftWidgetActivityName>a';
  188. sId = /users\/(.*)$/;
  189. break;
  190. case /^https:\/\/kakuyomu\.jp\/.*\/episo/.test(uRi):
  191. gMk = "KYU";
  192. cFt = 2;
  193. eOn = "#episodeFooter-cheerComments-panel-mainContents";
  194. eNo = "ul.widget-cheerCommentList li";
  195. eUl = "h5.widget-cheerComment-author a";
  196. sId = /users\/(.*)$/;
  197. break;
  198. case /^https:\/\/kakuyomu\.jp\/(users\/|works\/[0-9]+$)/.test(uRi):
  199. gMk = "KYU";
  200. cFt = 1;
  201. cAp = true;
  202. eUl = uRi.includes("users") ? 'div[class^="HeaderText"]>a' : 'div.partialGiftWidgetActivityName>a';
  203. sId = /users\/(.*)$/;
  204. break;
  205. // Narou
  206. case /^https:\/\/novelcom\.syosetu\.com\/impre/.test(uRi):
  207. gMk = "NUC";
  208. eNo = rMb ? "div.impression" : "div.waku";
  209. eUl = "div.comment_authorbox>div>a";
  210. sId = /\/(\d+)/;
  211. eAt = "div.comment_authorbox>div";
  212. break;
  213. case /^https:\/\/(mypage|ncode)\.syosetu\.com\/[A-z0-9]+\/?$/.test(uRi):
  214. gMk = "NRK";
  215. cAp = true;
  216. eUl = uRi.includes("ncode") ? 'div.novel_writername>a' : 'div.p-userheader__username';
  217. sId = /\/(\d+)/;
  218. break;
  219. case /^https:\/\/yomou\.syosetu\.com\/rank\//.test(uRi):
  220. gMk = "NRK";
  221. eNo = "div.p-ranklist-item";
  222. eUl = "div.p-ranklist-item__author a";
  223. sId = /\/(\d+)/;
  224. sTg = "div.p-ranklist-item__keyword a";
  225. break;
  226. case /^https:\/\/yomou\.syosetu\.com\/search/.test(uRi):
  227. gMk = "NRK";
  228. eNo = rMb ? "div.smpnovel_list" : "div.searchkekka_box";
  229. eUl = rMb ? null : "a:nth-child(2)";
  230. sId = rMb ? /:(.*)/ : /\/(\d+)/;
  231. sTg = 'a[href*="?word"]';
  232. eAt = "p.author";
  233. break;
  234. // PalemoonForum
  235. case /^https:\/\/forum\.palemoon\.org\/viewtopic/.test(uRi):
  236. gMk = "PMF";
  237. eNo = "#page-body div.post";
  238. eUl = 'a[class^="username"]';
  239. sId = /u=(\d+)/;
  240. break;
  241. case /^https:\/\/forum\.palemoon\.org\/viewforum/.test(uRi):
  242. gMk = "PMF";
  243. eNo = "ul.topiclist>li";
  244. eUl = "div.topic-poster>a";
  245. sId = /u=(\d+)/;
  246. break;
  247. // VivaldiForm
  248. case /^https:\/\/forum\.vivaldi\.net\//.test(uRi):
  249. gMk = "VVF";
  250. cFt = 2;
  251. sId = /user\/(.*)/;
  252. break;
  253. // VivaldiSocial
  254. case /^https:\/\/social\.vivaldi\.net\//.test(uRi):
  255. gMk = "VVS";
  256. cFt = 2;
  257. eOn = "body";
  258. eIo = ".load-more";
  259. eNo = "div.item-list>article";
  260. eUl = null;
  261. sId = /(.*)/;
  262. eAt = "strong.display-name__html";
  263. break;
  264. // Yandex
  265. case /^https:\/\/(www\.|)yandex\.com\//.test(uRi):
  266. gMk = "YDX";
  267. eNo = rMb ? "div.serp-item" : "#search-result>li";
  268. eUl = rMb ? null : "div.Path>a.Link";
  269. sId = rMb ? /(.*)/ : /((?<=https?:\/\/)[^\/]+)/;
  270. eAt = "span.Path-Item>b";
  271. break;
  272. }
  273. //console.log( {gMk, cFt, eOn, eIo, cAp, cSr, eNo, eUl, sId, sTg, eAt} );
  274.  
  275. // GM Menu
  276. GM_registerMenuCommand("View", SVM);
  277. GM_registerMenuCommand("List", CBM);
  278. // Read List
  279. URD();
  280. function URD() {
  281. const trc = GM_getValue(gMk);
  282. tlo = trc ? trc : { BAL:[], BTL:[] };
  283. }
  284. // Save List
  285. function USV() {
  286. if (gMk && JSON.stringify(tlo) !== JSON.stringify(GM_getValue(gMk))) {
  287. GM_setValue(gMk, tlo);
  288. }
  289. }
  290.  
  291. // Script Fire Time
  292. switch (cFt) {
  293. case 1:
  294. // Delay
  295. sleep(1500).then(() => FMD());
  296. break;
  297. case 2:
  298. // MutationObserver
  299. MOC();
  300. break;
  301. case 3:
  302. // IntersectionObserver
  303. IOC();
  304. break;
  305. case 0:
  306. default:
  307. // Normal
  308. FMD();
  309. }
  310. // MutationObserver
  311. function MOC() {
  312. switch (gMk) {
  313. case "KYU": {
  314. // Comments in Episode
  315. // Button load comments
  316. const bLc = document.querySelector('#episodeFooter-action-cheerCommentsButton');
  317. bLc.addEventListener("click", (e) => {
  318. waitForElement(eNo, 2000).then(() => { FMD(); });
  319. });
  320. break;
  321. }
  322. case "IGN":
  323. case "VVF": {
  324. let pUi = "";
  325. const observer = new MutationObserver(mutations => {
  326. if (location.href !== pUi) {
  327. pUi = location.href;
  328. if (location.pathname.startsWith("/articles")) {
  329. sleep(1000).then(() => IGN());
  330. } else if (location.pathname.startsWith("/topic")) {
  331. eNo = "ul.posts>li";
  332. eUl = "small.d-flex a";
  333. FMD();
  334. } else if (location.pathname.startsWith("/category")) {
  335. eNo = "ul.topic-list li";
  336. eUl = "small.hidden-xs>a";
  337. FMD();
  338. }
  339. }
  340. });
  341. observer.observe(document, { childList: true, subtree: true });
  342. break;
  343. }
  344. default:
  345. waitForElement(eNo, 3000).then(() => {
  346. FMD();
  347. // Vivaldi Social
  348. if (gMk === "VVS") sleep(3000).then(() => IOC());
  349. });
  350. }
  351. }
  352. function IGN() {
  353. eSh = eSr = undefined;
  354. waitForElement(eNo, 5000).then(() => {
  355. FMD();
  356. if (eSr) {
  357. // Button load more messages
  358. const bLm = eSr.querySelector('.spcv_load-more-messages');
  359. if (bLm) {
  360. bLm.addEventListener("click", (e) => {
  361. sleep(2000).then(() => FMD());
  362. });
  363. }
  364. }
  365. }).catch((error) => {
  366. //console.log(error);
  367. FMD();
  368. });
  369. }
  370. // Wait for an element to be loaded
  371. function waitForElement(selector, timeout) {
  372. return new Promise((resolve, reject) => {
  373. var timer = false;
  374. // Spot im shadownode
  375. if (cSr) {
  376. if (eSr && eSr.querySelectorAll(selector).length) return resolve();
  377. } else {
  378. if (document.querySelectorAll(selector).length) return resolve();
  379. }
  380. const obs = new MutationObserver(mutations => {
  381. // Spot im shadownode
  382. if (cSr) {
  383. eSh = document.querySelector('div[data-spotim-module]').firstElementChild;
  384. if (eSh) {
  385. eSr = eSh.shadowRoot;
  386. if (eSr && eSr.querySelectorAll(selector).length) {
  387. obs.disconnect();
  388. if (timer !== false) clearTimeout(timer);
  389. return resolve();
  390. }
  391. }
  392. } else {
  393. if (document.querySelectorAll(selector).length) {
  394. obs.disconnect();
  395. if (timer !== false) clearTimeout(timer);
  396. return resolve();
  397. }
  398. }
  399. });
  400. // Spot im shadownode
  401. const obn = eSr ? eSr.querySelectorAll('.spcv_conversation')[0] : document.querySelector(eOn);
  402. obs.observe(obn, { childList: true, subtree: true });
  403. if (timeout) {
  404. timer = setTimeout(() => {
  405. obs.disconnect();
  406. reject();
  407. }, timeout);
  408. }
  409. });
  410. }
  411. // IntersectionObserver
  412. function IOC() {
  413. const ioc = new IntersectionObserver((entries) => {
  414. if (entries[0].intersectionRatio <= 0) return;
  415. ioc.disconnect();
  416. // Vivaldi Social
  417. if (gMk === "VVS") sleep(2000).then(() => MOC());
  418. });
  419. ioc.observe(document.querySelector(eIo));
  420. }
  421.  
  422. // Filtering mode
  423. function FMD() {
  424. if (cAp) {
  425. // Filtering single target
  426. FST();
  427. } else {
  428. // Filtering multiple targets
  429. FMT();
  430. }
  431. if (!document.getElementById("ccf_fcb")) {
  432. CFB();
  433. }
  434. }
  435. // Filtering single target
  436. function FST() {
  437. let rBk = false;
  438. const eLk = eUl ? document.querySelector(eUl) : document.querySelector(eAt);
  439. let uId;
  440. // Narou author page fix
  441. if (gMk === "NRK") {
  442. uId = eLk.href ? eLk.href.match(sId)[1] : uRi.match(sId)[1];
  443. } else {
  444. uId = eUl ? eLk.href.match(sId)[1] : eLk.textContent.match(sId)[1];
  445. }
  446. rBk = CHK(eLk, "a", tlo.BAL, uId);
  447. eLk.style.color = rBk ? "fuchsia" : "dodgerblue";
  448. }
  449. // Filtering multiple targets
  450. function FMT() {
  451. const no = eSr ? eSr.querySelectorAll(eNo) : document.querySelectorAll(eNo);
  452. for (let i = 0; i < no.length; i++) {
  453. let rBk = false;
  454. let uId;
  455. // Filtering content contain single id(link) or text
  456. let eLk = eUl ? no[i].querySelector(eUl) : no[i].querySelector(eAt);
  457. if ( eLk !== null
  458. || gMk === "NUC"
  459. || gMk === "VVS"
  460. || (gMk === "NRK" && rMb) ) {
  461. if (!eLk) {
  462. switch (gMk) {
  463. // Narou search mobile no author link
  464. case "NRK": {
  465. const tca = document.createElement("p");
  466. tca.classList.add("author");
  467. tca.style.color = "#fe7643";
  468. const head = no[i].querySelector("div.accordion_head");
  469. // AD
  470. if (!head) {
  471. //console.log("===A D===");
  472. //rBk = true;
  473. continue;
  474. }
  475. tca.textContent = head.textContent.split("\n")[3];
  476. no[i].querySelector("a.read_button").after(tca);
  477. eLk = tca;
  478. uId = eLk.textContent.match(sId)[1];
  479. break;
  480. }
  481. // Vivaldi Social element out of view fix
  482. case "VVS":
  483. eLk = no[i].querySelector("span");
  484. uId = eLk.textContent.match(sId)[1].replace(/\s/g,'');
  485. break;
  486. // Narou nologin user fix
  487. default:
  488. eLk = no[i].querySelector(eAt);
  489. uId = eLk.textContent.split("\n")[2];
  490. }
  491. } else {
  492. uId = eUl ? eLk.href.match(sId)[1] : eLk.textContent.match(sId)[1];
  493. switch (gMk) {
  494. case "BNG":
  495. case "GGS":
  496. case "YDX": {
  497. // Lewis Nakao
  498. // https://stackoverflow.com/a/53197812
  499. const splitArr = uId.split('.'), arrLen = splitArr.length;
  500. if (arrLen == 2) {
  501. uId = splitArr[0];
  502. } else if (arrLen > 2) {
  503. uId = splitArr[arrLen - 2];
  504. //check to see if it's using a Country Code Top Level Domain (ccTLD) (i.e. ".me.uk")
  505. if (splitArr[arrLen - 2].length == 2 && splitArr[arrLen - 1].length == 2) {
  506. uId = splitArr[arrLen - 3];
  507. }
  508. }
  509. break;
  510. }
  511. case "VVS": {
  512. // Vivaldi Social id fix for foreground & background
  513. let emj = "";
  514. const ino = no[i].querySelectorAll(eAt + " img");
  515. if (ino) {
  516. for (let k = 0; k < ino.length; k++) {
  517. emj += ino[k].alt;
  518. }
  519. }
  520. uId = eLk.textContent.match(sId)[1] + emj;
  521. uId = uId.replace(/\s/g,'');
  522. break;
  523. }
  524. }
  525. }
  526. //console.log(uId);
  527. // Vivaldi Social choose the unchanged class as target
  528. rBk = gMk === "VVS" ? CHK(no[i].querySelector("div.status__wrapper"), "a", tlo.BAL, uId) : CHK(eLk, "a", tlo.BAL, uId);
  529. }
  530. const eNes = no[i].nextElementSibling;
  531. if (sTg && !rBk) {
  532. // Filtering content contain multiple tags(text)
  533. // Tag node
  534. let tno;
  535. // Hameln mobile origin tag, custom tag
  536. let tot, tct;
  537. if (gMk === "HML" && rMb) {
  538. tot = no[i].querySelector(".trigger p:nth-child(4)");
  539. tct = no[i].querySelector(sTg);
  540. if (!tct) {
  541. tno = tot.textContent.slice(3).match(/[^\s]+/g);
  542. tot.innerHTML = "";
  543. } else {
  544. tno = no[i].querySelectorAll(sTg);
  545. }
  546. } else {
  547. tno = no[i].querySelectorAll(sTg);
  548. }
  549. for (let j = 0; j < tno.length; j++) {
  550. let tag;
  551. if (tot && !tct) {
  552. tag = tno[j];
  553. tot.innerHTML += '<span id="tag_' + j + '">' + tag + '</span>';
  554. } else {
  555. // Greasyfork fix
  556. tag = gMk === "GFK" ? tno[j].href.match(/s\/(\d+)/)[1] : tno[j].textContent;
  557. }
  558. //console.log(tag);
  559. rBk = tot && !tct ? CHK(no[i].querySelector("span#tag_"+j), "t", tlo.BTL, tag) : CHK(tno[j], "t", tlo.BTL, tag);
  560. if (rBk) break;
  561. }
  562. }
  563. // Blocked Show Type
  564. if (!cSv) {
  565. no[i].style.display = rBk ? "none" : "";
  566. no[i].style.opacity = "1";
  567. } else {
  568. no[i].style.display = "";
  569. no[i].style.opacity = rBk ? "0.5" : "1";
  570. }
  571. }
  572. }
  573. // CheckKeyword
  574. function CHK(ele, n, l, s) {
  575. const result = gMk === "GFK" && n === "a" ? l.some((v) => s.toLowerCase().includes(v.toLowerCase())) : l.some((v) => s.toLowerCase() === v.toLowerCase());
  576. if (!ele.getAttribute("data-lkw")) {
  577. ele.setAttribute("data-lkw", n + s);
  578. }
  579. if (cSv) {
  580. ele.style.border = result ? "thin solid fuchsia" : "thin solid dodgerblue";
  581. } else {
  582. ele.style.border = "none";
  583. }
  584. return result;
  585. }
  586.  
  587. // Select mode
  588. function SVM() {
  589. const cbtn = document.getElementById("ccf_fcb");
  590. if (!cSv) {
  591. cSv = true;
  592. cbtn.textContent = "📙";
  593. document.addEventListener("click", PAC);
  594. URD();
  595. } else {
  596. cSv = false;
  597. cbtn.textContent = "📘";
  598. document.removeEventListener("click", PAC);
  599. // Auto save list
  600. USV();
  601. }
  602. FMD();
  603. }
  604. // PreventAnchorChange
  605. function PAC(e) {
  606. e.preventDefault();
  607. let tele = cSr ? e.composedPath()[0] : e.target;
  608. // Vivaldi Forum & Social fix
  609. if (gMk === "VVF" || gMk === "VVS") {
  610. e.stopPropagation();
  611. // StopPropagation fix
  612. if (tele.closest("#ccf_fcb")) SVM();
  613. // Vivaldi Social: "div.status__wrapper" is too difficult to select on mobile
  614. if (gMk === "VVS" && tele.closest("div.status__info")) tele = tele.parentElement.parentElement;
  615. }
  616. const ctel = tele.getAttribute("data-lkw") ? tele
  617. : tele.parentElement.getAttribute("data-lkw") ? tele.parentElement
  618. : null;
  619. //console.log(ctel.getAttribute("data-lkw"));
  620. if (ctel) {
  621. const tda = ctel.getAttribute("data-lkw");
  622. const tlst = tda.slice(0, 1) === "a" ? tlo.BAL : tlo.BTL;
  623. let tid = tda.slice(1);
  624. if (gMk === "GFK" && tda.slice(0, 1) === "a") {
  625. const t = prompt("Enter or use the first 5 letters as keyword", tid);
  626. tid = t !== null ? t : tid.slice(0, 5);
  627. //console.log(tid);
  628. }
  629. const li = tlst.findIndex((v) => v.toLowerCase() === tid.toLowerCase());
  630. if (li !== -1) {
  631. tlst.splice(li,1);
  632. } else {
  633. tlst.push(tid);
  634. }
  635. FMD();
  636. } else {
  637. //console.log("#ccf_fcb or wrong target: " + ctel);
  638. }
  639. // IGN Popup temp fix
  640. if (gMk === "IGN") {
  641. sleep(500).then(() => {
  642. const bsh = document.body.lastChild.shadowRoot;
  643. if (bsh) {
  644. const bsr = bsh.querySelector('button[title="Close the modal"]');
  645. if (bsr) bsr.click();
  646. }
  647. });
  648. }
  649. return false;
  650. }
  651.  
  652. // Custom Blocklists Menu
  653. function CBM() {
  654. if (!document.getElementById("ccf_blm")) {
  655. const cbl = document.body.appendChild(document.createElement("div"));
  656. const pos = !rMb ? " width: 50%; left: 25%;" : " width: 98%; left: 1%;";
  657. cbl.id = "ccf_blm";
  658. cbl.style = "position: fixed;" + pos + " overflow-y: scroll; overflow-wrap: break-word; height: 52%; top:10%; z-index: 9999; background-color: #f1f3f5; display: none;";
  659. }
  660. const blm = document.getElementById("ccf_blm");
  661. if (!cSb) {
  662. cSb = true;
  663. UBM();
  664. blm.style.display = "";
  665. blm.addEventListener("click", DBL);
  666. } else {
  667. cSb = false;
  668. blm.style.display = "none";
  669. blm.removeEventListener("click", DBL);
  670. blm.innerHTML = "";
  671. }
  672. }
  673. // Delete Block List
  674. function DBL(e) {
  675. const eT = e.target;
  676. let key, clst;
  677. if (eT.className === "ccf_sav" || eT.className === "ccf_sor" || eT.className === "ccf_del") {
  678. key = eT.parentElement.textContent.slice(0, 3);
  679. // Patch for invalid save data
  680. if (key === "und") {
  681. key = "undefined";
  682. }
  683. clst = document.getElementById("blm_" + key).textContent;
  684. }
  685. if (eT.id === "ccf_iop") {
  686. let copt = document.getElementById("ccf_inp").innerText;
  687. if ( copt.startsWith("{") ) {
  688. copt = copt.slice(1, -1).split("\n");
  689. for (let i=1; i<copt.length-1; i++) {
  690. let ttt = i === (copt.length-2) ? copt[i] : copt[i].slice(0, -1);
  691. GM_setValue(ttt.slice(1, 4), JSON.parse(ttt.slice(7)));
  692. if (ttt.slice(1, 4) === gMk) {
  693. URD();
  694. FMD();
  695. }
  696. }
  697. UBM();
  698. document.getElementById("ccf_inp").innerText = "Import completed";
  699. } else {
  700. document.getElementById("ccf_inp").innerText = "Invalid input";
  701. }
  702. } else if (eT.id === "ccf_sop") {
  703. const ctim = new Date().toISOString().split('T')[0];
  704. let copt = "{\n";
  705. const keys = GM_listValues();
  706. keys.forEach(k => {
  707. copt += '"' + k + '": ' + JSON.stringify(GM_getValue(k)) + ',\n';
  708. });
  709. SAT("ccf_bak_" + ctim, copt.slice(0, -2) + "\n}");
  710. alert("File downloads completed");
  711. } else if (eT.className === "ccf_sav") {
  712. GM_setValue(key, JSON.parse(clst));
  713. UBM();
  714. if (key === gMk) {
  715. URD();
  716. FMD();
  717. }
  718. } else if (eT.className === "ccf_sor") {
  719. const cal = JSON.parse(clst).BAL.sort();
  720. const ctl = JSON.parse(clst).BTL.sort();
  721. const clo = { BAL:cal, BTL:ctl };
  722. GM_setValue(key, clo);
  723. UBM();
  724. if (key === gMk) {
  725. URD();
  726. }
  727. } else if (eT.className === "ccf_del") {
  728. GM_deleteValue(key);
  729. UBM();
  730. if (key === gMk) {
  731. URD();
  732. FMD();
  733. }
  734. }
  735. }
  736. // Update Blocklists Menu
  737. function UBM() {
  738. const blm = document.getElementById("ccf_blm");
  739. const ost = "margin-left: 1em; cursor: pointer;";
  740. blm.innerHTML = `<h2>Blocklists:</h2>
  741. <p id="ccf_inp" style="${ost} background-color: cyan;" contenteditable>Paste options here</p>
  742. <p id="ccf_iop" style="${ost}">📤 Import options from above</p>
  743. <p id="ccf_sop" style="${ost}">💾 Save options to local txt</p>`;
  744. const btt = ' type="button" style="margin-left: 1em; cursor: pointer; color: ';
  745. const keys = GM_listValues();
  746. keys.forEach(k => {
  747. const ltt = (k === gMk) ? '" style="margin-left: 1em; background-color: cyan;" contenteditable>' : '" style="margin-left: 1em;" contenteditable>';
  748. blm.innerHTML += '<p style="margin-left: 1em; color: fuchsia;">' + k + ': ' +
  749. '<span class="ccf_sav"' + btt + 'green;">♻ Save</span>' +
  750. '<span class="ccf_sor"' + btt + 'blue;">🔀 Sort</span>' +
  751. '<span class="ccf_del"' + btt + 'red;">📛 Delete</span>' +
  752. '</p>' +
  753. '<span id="blm_' + k + ltt + JSON.stringify(GM_getValue(k)) + '</span>';
  754. });
  755. }
  756.  
  757. // Create Float Button
  758. function CFB() {
  759. BCR("ccf_fcb", "📘", "right: 2em;", "bottom: 2em;", "#55acee");
  760. BCR("ccf_lst", "📚", "right: 4em;", "bottom: 2em;", "#eeac55");
  761. document.addEventListener("click",BLM);
  762. }
  763. function BLM(e){
  764. switch(e.target.id){
  765. case "ccf_fcb":
  766. SVM();
  767. break;
  768. case "ccf_lst":
  769. CBM();
  770. break;
  771. }
  772. }
  773. // Button creater
  774. function BCR(id, text, posx, posy, color) {
  775. const cbtn = document.body.appendChild(document.createElement("button"));
  776. cbtn.id = id;
  777. cbtn.textContent = text;
  778. 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;
  779. cbtn.type = "button";
  780. }
  781. // Save as txt
  782. function SAT(title, text) {
  783. //console.log(text);
  784. const link = document.createElement("a");
  785. link.href = "data:text/plain;charset=utf-8," + encodeURIComponent(text);
  786. link.download = title + ".txt";
  787. link.style.display = "none";
  788. document.body.appendChild(link);
  789. link.click();
  790. document.body.removeChild(link);
  791. }
  792. })();