Unlimited MAL Ignore list

Ignore an unlimited amount of users. Comes with custom settings: delete the entire post, replace the content of the message with a custom message, replace or delete the avatar, and keep or delete the signature.

目前为 2024-05-27 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Unlimited MAL Ignore list
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.84
  5. // @description Ignore an unlimited amount of users. Comes with custom settings: delete the entire post, replace the content of the message with a custom message, replace or delete the avatar, and keep or delete the signature.
  6. // @author Only_Brad
  7. // @author ShaggyZE
  8. // @match https://myanimelist.net/*
  9. // @run-at document-end
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. const FORUM_OPTIONS = "editprofile.php?go=forumoptions";
  14. const POSTS_URL = "forum/?topicid";
  15. const LAST_POST_URL = "forum";
  16. const TOPICS_URL = "forum/?board";
  17. const TOPICS_SEARCH_URL = "forum/search?";
  18. const CLUB_TOPICS_URL_1 = "clubs.php";
  19. const CLUB_TOPICS_URL_2 = "forum/?clubid";
  20. const PROFILE_URL = "profile";
  21. const COMTOCOM_URL = "comtocom.php";
  22. const COMMENTS_URL = "comments.php";
  23. const BLACKLIST_URL = "https://myanimelist.net/blacklist";
  24.  
  25. const BLACKLIST_KEY = "ignore-list";
  26. const SETTINGS_KEY = "ignore-list-settings";
  27.  
  28. const YOU_SELECTOR = ".header-profile-link";
  29. const POST_USERS_SELECTOR = ".profile";
  30. const TOPIC_USERS_SELECTOR = ".forum_postusername a";
  31. const MESSAGE_SELECTOR = ".content [id^=message]";
  32. const QUOTE_SELECTOR = ".quotetext";
  33. const AVATAR_SELECTOR = ".forum-icon";
  34. const USER_PROFILE_SELECTOR = "[href^='/profile']";
  35. const USER_INFO_SELECTOR = "[id^=messageuser]";
  36. const USERINFO_SELECTOR = ".custom-forum-title";
  37. const USERINFO_SELECTOR1 = ".userstatus";
  38. const USERINFO_SELECTOR2 = ".userinfo.joined";
  39. const USERINFO_SELECTOR3 = ".userinfo.posts";
  40. const USERINFO_SELECTOR4 = ".modified";
  41. const SIGNATURE_SELECTOR = ".sig";
  42. const FORUM_MESSAGE_SELECTOR = "[id^=msg]";
  43. const FORUM_MSG_NAME_SELECTOR = ".username a";
  44. const FORUM_QUOTE_NAME_SELECTOR = ".quotetext > strong > a";
  45. const FORUM_ACTION_BAR_SELECTOR = "[id^=postEditButtons]";
  46. const PROFILE_MSG_SELECTOR = "[id^=comBox]";
  47. const PROFILE_MSG_NAME_SELECTOR = ".text a.fw-b";
  48. const PROFILE_MSG_AVATAR_SELECTOR = ".image";
  49. const PROFILE_MSG_TEXT_SELECTOR = ".text .comment-text";
  50. const PROFILE_MSG_ACTION_BAR_SELECTOR = ".text > div.pb8 > a";
  51. const COMTOCOM_SELECTOR = "[id^=comBox]";
  52. const COMTOCOM_NAME_SELECTOR = ".dark_text a";
  53. const COMTOCOM_AVATAR_SELECTOR = ".picSurround a";
  54. const COMTOCOM_TEXT_SELECTOR = "[id^=comtext]";
  55. const COMTOCOM_ACTION_BAR_SELECTOR = ".dark_text a";
  56.  
  57. const IGNORE = 0;
  58. const REPLACE = 1;
  59. const DO_NOTHING = 2;
  60.  
  61. let blacklist;
  62. let settings;
  63.  
  64. //routing
  65. if (window.location.href.includes(FORUM_OPTIONS)) {
  66. AddBlacklistLink();
  67. } else if (window.location.href.includes(POSTS_URL)) {
  68. handlePosts();
  69. handleQuotes();
  70. } else if (
  71. window.location.href.includes(TOPICS_URL) ||
  72. window.location.href.includes(TOPICS_SEARCH_URL) ||
  73. window.location.href.includes(CLUB_TOPICS_URL_1) ||
  74. window.location.href.includes(CLUB_TOPICS_URL_2)
  75. ) {
  76. handleTopics();
  77. } else if (window.location.href.includes(PROFILE_URL)) {
  78. handleProfileMsgs();
  79. } else if (window.location.href.includes(COMTOCOM_URL)) {
  80. handleComToCom();
  81. } else if (window.location.href.includes(COMMENTS_URL)) {
  82. handleComToCom();
  83. } else if (window.location.href === BLACKLIST_URL) {
  84. handleBlacklist();
  85. } else if (window.location.href.includes(LAST_POST_URL)) {
  86. handleLastPost();
  87. }
  88.  
  89. //GM_addStyle equivalent that works on firefox
  90. function addStyle(css) {
  91. const style = document.getElementById("addStyleBy8626") || (function() {
  92. const style = document.createElement('style');
  93. style.type = 'text/css';
  94. style.id = "addStyleBy8626";
  95. document.head.appendChild(style);
  96. return style;
  97. })();
  98. style.innerHTML += css;
  99. }
  100.  
  101. //helper functions to load from localStorage
  102. function loadBlackList() {
  103. blacklist = JSON.parse(localStorage.getItem(BLACKLIST_KEY)) || [];
  104. }
  105.  
  106. function saveBlackList() {
  107. localStorage.setItem(BLACKLIST_KEY, JSON.stringify(blacklist));
  108. }
  109.  
  110. function loadSettings() {
  111. settings = JSON.parse(localStorage.getItem(SETTINGS_KEY)) || {
  112. replaceUsername: false,
  113. replaceAvatar: false,
  114. replaceProfileAvatar: false,
  115. removeSignatures: true,
  116. removeUserinfo: true,
  117. quoteMode: IGNORE,
  118. postMode: REPLACE,
  119. profileMsgMode: IGNORE,
  120. removeTopics: true,
  121. UnBlacklistUsername: false,
  122. removeUnBlacklist: false,
  123. customLastPost: "",
  124. customQuote: "",
  125. customPost: "",
  126. customAvatar: "",
  127. customProfileMsg: "",
  128. customProfileAvatar: "",
  129. specificCustomLastPost: {},
  130. specificCustomQuote: {},
  131. specificCustomPost: {},
  132. specificCustomProfileMsg: {}
  133. };
  134. if (!settings.specificCustomLastPost) settings.specificCustomLastPost = {};
  135. if (!settings.specificCustomQuote) settings.specificCustomQuote = {};
  136. if (!settings.specificCustomPost) settings.specificCustomPost = {};
  137. if (!settings.specificCustomProfileMsg) settings.specificCustomProfileMsg = {};
  138. }
  139.  
  140. function saveSetting(key, value) {
  141. if (typeof key === "object") {
  142. settings[key.key][key.subkey] = value;
  143. } else {
  144. settings[key] = value;
  145. }
  146. localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
  147. }
  148. function AddBlacklistLink() {
  149. //wip
  150. }
  151.  
  152. //functions called by the routers
  153. function handlePosts() {
  154. loadBlackList();
  155. loadSettings();
  156. addPostsBlackListButtons();
  157.  
  158. switch (settings.postMode) {
  159. case IGNORE:
  160. ignorePosts();
  161. return;
  162. case REPLACE:
  163. replacePosts();
  164. break;
  165. case DO_NOTHING:
  166. break;
  167. default:
  168. saveSetting("postMode", REPLACE);
  169. replacePosts();
  170. break;
  171. }
  172.  
  173.  
  174. if (settings.replaceAvatar) replaceAvatar();
  175. if (settings.removeSignatures) removeSignatures();
  176. if (settings.removeUserinfo) removeUserinfo();
  177. if (settings.replaceUsername) replaceUsername();
  178. }
  179.  
  180. function handleLastPost() {
  181. loadBlackList();
  182. loadSettings();
  183.  
  184. switch (settings.lastpostMode) {
  185. case IGNORE:
  186. ignoreLastPost();
  187. return;
  188. case REPLACE:
  189. replaceLastPost();
  190. break;
  191. case DO_NOTHING:
  192. break;
  193. default:
  194. saveSetting("lastpostMode", IGNORE);
  195. ignoreLastPost();
  196. break;
  197. }
  198. }
  199.  
  200. function handleQuotes() {
  201. loadBlackList();
  202. loadSettings();
  203.  
  204. switch (settings.quoteMode) {
  205. case IGNORE:
  206. ignoreQuotes();
  207. return;
  208. case REPLACE:
  209. replaceQuotes();
  210. break;
  211. case DO_NOTHING:
  212. break;
  213. default:
  214. saveSetting("quoteMode", IGNORE);
  215. ignoreQuotes();
  216. break;
  217. }
  218. }
  219.  
  220. function handleTopics() {
  221. loadBlackList();
  222. loadSettings();
  223. if (settings.removeTopics) {
  224. ignoreTopics();
  225. }
  226. }
  227.  
  228. function handleProfileMsgs() {
  229. loadBlackList();
  230. loadSettings();
  231. addProfileMsgBlackListButtons();
  232.  
  233. switch (settings.profileMsgMode) {
  234. case IGNORE:
  235. ignoreProfileMsgs();
  236. return;
  237. case REPLACE:
  238. replaceProfileMsg();
  239. break;
  240. case DO_NOTHING:
  241. break;
  242. default:
  243. saveSetting("profileMsgMode", IGNORE);
  244. ignoreProfileMsgs();
  245. break;
  246. }
  247.  
  248. if (settings.replaceProfileAvatar) replaceProfileAvatar();
  249. }
  250.  
  251. function handleComToCom() {
  252. loadBlackList();
  253. loadSettings();
  254. addComToComBlackListButtons();
  255.  
  256. switch (settings.profileMsgMode) {
  257. case IGNORE:
  258. ignoreComToCom();
  259. return;
  260. case REPLACE:
  261. replaceComToCom();
  262. break;
  263. case DO_NOTHING:
  264. break;
  265. default:
  266. saveSetting("profileMsgMode", IGNORE);
  267. ignoreComToCom();
  268. break;
  269. }
  270.  
  271. if (settings.replaceProfileAvatar) replaceComToComAvatar();
  272. }
  273.  
  274. function handleBlacklist() {
  275. loadBlackList();
  276. loadSettings();
  277.  
  278. document.title = "Blacklist - MyAnimeList.net";
  279.  
  280. //remove the 404 stuff
  281. document.querySelector("h1").textContent = "Ignore List";
  282. document.querySelector(".error404").remove();
  283.  
  284. //CSS
  285. addStyle(".flex{display:flex;gap:20px;margin-top:10px;}.user{display:flex;margin:10px}.name{margin-right:20px}.name{border-bottom:solid #000 1px}.name[contenteditable]{min-width:100px;border-bottom:solid #000 1px}.name[contenteditable]:focus{border:none;outline:solid red 5px}.page-common #content{display:flex;justify-content:center;}.settings{display:flex;gap:25px;}.settings>*{padding: 25px;}.customPost{width:100% !important;}.select-users{font-size:1rem;padding:10px;font-weight:bold;}");
  286.  
  287. //HTML for the blacklist
  288. document.getElementById("content").innerHTML =
  289. `<div data-blacklist class="black-list"></div>
  290. <div data-add-user class="add-user">
  291. <div data-user class="user">
  292. <div data-name class="name" contenteditable="true" onclick="this.focus()"></div>
  293. <button data-add class="add">Add</div>
  294. </div>
  295. </div>`
  296.  
  297. //HTML for the settings
  298. const settings = document.createElement("div");
  299. settings.innerHTML = `
  300. <h2>Settings</h2>
  301. <form>
  302. <div class="settings">
  303. <div class="posts">
  304. <h3>Posts</h3>
  305. <div class="form-check">
  306. <input class="form-check-input" type="radio" name="posts" id="doNothingPosts" data-clickable-setting="doNothingPosts">
  307. <label class="form-check-label" for="doNothingPosts">
  308. Do nothing
  309. </label>
  310. </div>
  311. <div class="form-check">
  312. <input class="form-check-input" type="radio" name="posts" id="hidePosts" data-clickable-setting="hidePosts">
  313. <label class="form-check-label" for="hidePosts">
  314. Hide posts
  315. </label>
  316. </div>
  317. <div class="form-check">
  318. <input class="form-check-input" type="radio" name="posts" id="replacePosts" data-clickable-setting="replacePosts">
  319. <label class="form-check-label" for="replacePosts">
  320. Replace posts with a custom message
  321. </label>
  322. </div>
  323. <textarea class="form-control customPost" name="customPost" id="customPost" data-text-setting="customPost"></textarea>
  324. </div>
  325. <div class="posts-extra">
  326. <h3>Posts extra options</h3>
  327. <div class="form-check">
  328. <input class="form-check-input" type="checkbox" name="replaceUsername" id="replaceUsername" data-clickable-setting="replaceUsername">
  329. <label class="form-check-label" for="replaceUsername">
  330. Replace user name with a custom name
  331. </label>
  332. <input class="form-control" type="text" name="customUsername" id="customUsername" data-text-setting="customUsername" placeholder="removed-user">
  333. <br>
  334. <small>Leave it empty to remove the username</small>
  335. </div>
  336. <div class="form-check">
  337. <input class="form-check-input" type="checkbox" name="replaceAvatar" id="replaceAvatar" data-clickable-setting="replaceAvatar">
  338. <label class="form-check-label" for="replaceAvatar">
  339. Replace avatars with a custom avatar
  340. </label>
  341. <input class="form-control" type="text" name="customAvatar" id="customAvatar" data-text-setting="customAvatar">
  342. <br>
  343. <small>Leave it empty to remove the avatar</small>
  344. </div>
  345. <div class="form-check" style="margin-top: 10px;">
  346. <input class="form-check-input" type="checkbox" name="removeSignatures" id="removeSignatures" data-clickable-setting="removeSignatures">
  347. <label class="form-check-label" for="removeSignatures">
  348. Hide the signature
  349. </label>
  350. </div>
  351. <div class="form-check" style="margin-top: 10px;">
  352. <input class="form-check-input" type="checkbox" name="removeUserinfo" id="removeUserinfo" data-clickable-setting="removeUserinfo">
  353. <label class="form-check-label" for="removeUserinfo">
  354. Hide user info
  355. </label>
  356. </div>
  357. <small style="margin-top: 20px; display: block;"><strong>These settings have no effect if the Posts setting is set to "Hide Posts"</strong></small>
  358. </div>
  359. <div class="quotes">
  360. <h3>Quotes</h3>
  361. <div class="form-check">
  362. <input class="form-check-input" type="radio" name="quotes" id="doNothingQuotes" data-clickable-setting="doNothingQuotes">
  363. <label class="form-check-label" for="doNothingQuotes">
  364. Do nothing
  365. </label>
  366. </div>
  367. <div class="form-check">
  368. <input class="form-check-input" type="radio" name="quotes" id="hideQuotes" data-clickable-setting="hideQuotes">
  369. <label class="form-check-label" for="hideQuotes">
  370. Hide quotes
  371. </label>
  372. </div>
  373. <div class="form-check">
  374. <input class="form-check-input" type="radio" name="quotes" id="replaceQuotes" data-clickable-setting="replaceQuotes">
  375. <label class="form-check-label" for="replaceQuotes">
  376. Replace quotes with a custom message
  377. </label>
  378. </div>
  379. <textarea class="form-control customPost" name="customQuote" id="customQuote" data-text-setting="customQuote"></textarea>
  380. </div>
  381. <div class="topics">
  382. <h3>Topics</h3>
  383. <div class="form-check">
  384. <input class="form-check-input" type="checkbox" name="removeTopics" id="removeTopics" data-clickable-setting="removeTopics">
  385. <label class="form-check-label" for="removeTopics">
  386. Hide topics
  387. </label>
  388. </div>
  389. </div>
  390. <div class="unblacklist">
  391. <h3>UnBlacklist</h3>
  392. <div class="form-check">
  393. <input class="form-check-input" type="checkbox" name="UnBlacklistUsername" id="UnBlacklistUsername" data-clickable-setting="UnBlacklistUsername">
  394. <label class="form-check-label" for="UnBlacklistUsername">
  395. Show user name when hovering<br>on UnBlacklist buttons/links
  396. </label>
  397. </div>
  398. <div class="form-check">
  399. <input class="form-check-input" type="checkbox" name="removeUnBlacklist" id="removeUnBlacklist" data-clickable-setting="removeUnBlacklist">
  400. <label class="form-check-label" for="removeUnBlacklist">
  401. Hide UnBlacklist buttons/links
  402. </label>
  403. </div>
  404. <small style="margin-top: 20px; display: block;"><strong>These settings have no effect if the Posts setting<br>is set to "Hide Posts" or Profile Messages setting<br>is set to "Hide profile messages"</strong></small>
  405. </div>
  406. </div>
  407. <div class="settings">
  408. <div class="profile-messages">
  409. <h3>Profile messages</h3>
  410. <div class="form-check">
  411. <input class="form-check-input" type="radio" name="profileMsgs" id="doNothingProfileMsgs" data-clickable-setting="doNothingProfileMsgs">
  412. <label class="form-check-label" for="doNothingProfileMsgs">
  413. Do nothing
  414. </label>
  415. </div>
  416. <div class="form-check">
  417. <input class="form-check-input" type="radio" name="profileMsgs" id="hideProfileMsgs" data-clickable-setting="hideProfileMsgs">
  418. <label class="form-check-label" for="hideProfileMsgs">
  419. Hide profile messages
  420. </label>
  421. </div>
  422. <div class="form-check">
  423. <input class="form-check-input" type="radio" name="profileMsgs" id="replaceProfileMsgs" data-clickable-setting="replaceProfileMsgs">
  424. <label class="form-check-label" for="replaceProfileMsgs">
  425. Replace profile messages with a custom message
  426. </label>
  427. </div>
  428. <textarea class="form-control customPost" name="customProfileMsg" id="customProfileMsg" data-text-setting="customProfileMsg"></textarea>
  429. </div>
  430. <div class="profile-messages-extra">
  431. <h3>Profile messages extra options</h3>
  432. <div class="form-check">
  433. <input class="form-check-input" type="checkbox" name="replaceProfileUsername" id="replaceProfileUsername" data-clickable-setting="replaceProfileUsername">
  434. <label class="form-check-label" for="replaceProfileUsername">
  435. Replace profile user with a custom name
  436. </label>
  437. <input class="form-control" type="text" name="customProfileUsername" id="customProfileUsername" data-text-setting="customProfileUsername" placeholder="removed-user">
  438. <br>
  439. <small>Leave it empty to remove the avatar</small>
  440. </div>
  441. <div class="form-check">
  442. <input class="form-check-input" type="checkbox" name="replaceProfileAvatar" id="replaceProfileAvatar" data-clickable-setting="replaceProfileAvatar">
  443. <label class="form-check-label" for="replaceProfileAvatar">
  444. Replace profile message avatar with a custom avatar
  445. </label>
  446. <input class="form-control" type="text" name="customProfileAvatar" id="customProfileAvatar" data-text-setting="customProfileAvatar">
  447. <br>
  448. <small>Leave it empty to remove the avatar</small>
  449. </div>
  450. <small style="margin-top: 20px; display: block;"><strong>These settings have no effect if the Profile Messages setting is set to "Hide profile messages"</strong></small>
  451. </div>
  452. <div class="lastpost">
  453. <h3>Last Post</h3>
  454. <div class="form-check">
  455. <input class="form-check-input" type="radio" name="lastpost" id="doNothingLastPost" data-clickable-setting="doNothingLastPost">
  456. <label class="form-check-label" for="doNothingLastPost">
  457. Do nothing
  458. </label>
  459. </div>
  460. <div class="form-check">
  461. <input class="form-check-input" type="radio" name="lastpost" id="hideLastPost" data-clickable-setting="hideLastPost">
  462. <label class="form-check-label" for="hideLastPost">
  463. Hide last posts
  464. </label>
  465. </div>
  466. <div class="form-check">
  467. <input class="form-check-input" type="radio" name="lastpost" id="replaceLastPost" data-clickable-setting="replaceLastPost">
  468. <label class="form-check-label" for="replaceLastPost">
  469. Replace user of last posts with a custom message
  470. </label>
  471. </div>
  472. <textarea class="form-control customPost" name="customLastPost" id="customLastPost" data-text-setting="customLastPost" placeholder="type a user name like removed-user"></textarea>
  473. </div>
  474. </div>
  475. <select name="users" class="select-users" data-select-users></select>
  476. <div class="flex">
  477. <div class="form-check">
  478. <label class="form-check-label" for="specificCustomPost">
  479. Replace this user's posts with a specific custom message
  480. </label>
  481. <textarea class="form-control customPost" name="specificCustomPost" id="specificCustomPost" data-text-setting="specificCustomPost"></textarea>
  482. </div>
  483. <div class="form-check">
  484. <label class="form-check-label" for="specificCustomLastPost">
  485. Replace the last posts username with a specific custom message
  486. </label>
  487. <textarea class="form-control customPost" name="specificCustomLastPost" id="specificCustomLastPost" data-text-setting="specificCustomLastPost" placeholder="type a user name like removed-user"></textarea>
  488. </div>
  489. <div class="form-check">
  490. <label class="form-check-label" for="specificCustomProfileMsg">
  491. Replace this user's profile messages with a custom message
  492. </label>
  493. <textarea class="form-control customPost" name="specificCustomProfileMsg" id="specificCustomProfileMsg" data-text-setting="specificCustomProfileMsg"></textarea>
  494. </div>
  495. <div class="form-check">
  496. <label class="form-check-label" for="specificCustomQuote">
  497. Replace this user's quotes with a specific custom message
  498. </label>
  499. <textarea class="form-control customPost" name="specificCustomQuote" id="specificCustomQuote" data-text-setting="specificCustomQuote"></textarea>
  500. </div>
  501. </div>
  502. </form>`;
  503.  
  504. document.getElementById("content").insertAdjacentElement("afterend", settings);
  505.  
  506. startEventListeners();
  507. loadSettingsIntoInputs();
  508. }
  509.  
  510. function clickedSetting(e) {
  511. const input = e.target;
  512. switch (input.dataset.clickableSetting) {
  513. case "doNothingLastPost":
  514. saveSetting("lastpostMode", DO_NOTHING);
  515. break;
  516. case "hideLastPost":
  517. saveSetting("lastpostMode", IGNORE);
  518. break;
  519. case "replaceLastPost":
  520. saveSetting("lastpostMode", REPLACE);
  521. break;
  522. case "doNothingQuotes":
  523. saveSetting("quoteMode", DO_NOTHING);
  524. break;
  525. case "hideQuotes":
  526. saveSetting("quoteMode", IGNORE);
  527. break;
  528. case "replaceQuotes":
  529. saveSetting("quoteMode", REPLACE);
  530. break;
  531. case "doNothingPosts":
  532. saveSetting("postMode", DO_NOTHING);
  533. break;
  534. case "hidePosts":
  535. saveSetting("postMode", IGNORE);
  536. break;
  537. case "replacePosts":
  538. saveSetting("postMode", REPLACE);
  539. break;
  540. case "replaceUsername":
  541. saveSetting("replaceUsername", input.checked);
  542. break;
  543. case "replaceAvatar":
  544. saveSetting("replaceAvatar", input.checked);
  545. break;
  546. case "removeTopics":
  547. saveSetting("removeTopics", input.checked);
  548. break;
  549. case "UnBlacklistUsername":
  550. saveSetting("UnBlacklistUsername", input.checked);
  551. break;
  552. case "removeUnBlacklist":
  553. saveSetting("removeUnBlacklist", input.checked);
  554. break;
  555. case "removeSignatures":
  556. saveSetting("removeSignatures", input.checked);
  557. break;
  558. case "removeUserinfo":
  559. saveSetting("removeUserinfo", input.checked);
  560. break;
  561. case "doNothingProfileMsgs":
  562. saveSetting("profileMsgMode", DO_NOTHING);
  563. break;
  564. case "hideProfileMsgs":
  565. saveSetting("profileMsgMode", IGNORE);
  566. break;
  567. case "replaceProfileMsgs":
  568. saveSetting("profileMsgMode", REPLACE);
  569. break;
  570. case "replaceProfileAvatar":
  571. saveSetting("replaceProfileAvatar", input.checked);
  572. break;
  573. default:
  574. return;
  575. }
  576. }
  577.  
  578. function textSetting(e) {
  579. const input = e.target;
  580. switch (input.dataset.textSetting) {
  581. case "customLastPost":
  582. saveSetting("customLastPost", input.value);
  583. break;
  584. case "customQuote":
  585. saveSetting("customQuote", input.value);
  586. break;
  587. case "customPost":
  588. saveSetting("customPost", input.value);
  589. break;
  590. case "customUsername":
  591. saveSetting("customUsername", input.value);
  592. break;
  593. case "customAvatar":
  594. saveSetting("customAvatar", input.value);
  595. break;
  596. case "customProfileMsg":
  597. saveSetting("customProfileMsg", input.value);
  598. break;
  599. case "customProfileAvatar":
  600. saveSetting("customProfileAvatar", input.value);
  601. break;
  602. case "specificCustomProfileMsg":
  603. {
  604. const selectedUser = document.querySelector("[data-select-users]").value;
  605. saveSetting({ key: "specificCustomProfileMsg", subkey: selectedUser }, input.value);
  606. break;
  607. }
  608. case "specificCustomPost":
  609. {
  610. const selectedUser = document.querySelector("[data-select-users]").value;
  611. saveSetting({ key: "specificCustomPost", subkey: selectedUser }, input.value);
  612. break;
  613. }
  614. case "specificCustomQuote":
  615. {
  616. const selectedUser = document.querySelector("[data-select-users]").value;
  617. saveSetting({ key: "specificCustomQuote", subkey: selectedUser }, input.value);
  618. break;
  619. }
  620. case "specificCustomLastPost":
  621. {
  622. const selectedUser = document.querySelector("[data-select-users]").value;
  623. saveSetting({ key: "specificCustomLastPost", subkey: selectedUser }, input.value);
  624. break;
  625. }
  626. default:
  627. return;
  628. }
  629. }
  630.  
  631. function startEventListeners() {
  632. document.querySelector("[data-add]").addEventListener("click", addNode);
  633. document.querySelectorAll("[data-clickable-setting]").forEach(clickable => {
  634. clickable.addEventListener("click", clickedSetting);
  635. });
  636. document.querySelectorAll("[data-text-setting]").forEach(text => {
  637. text.addEventListener("input", textSetting);
  638. });
  639. document.querySelector("[data-select-users]").addEventListener("change", loadSpecificMessages)
  640. blacklist.forEach(createNode);
  641. blacklist.forEach(addUserToSelect);
  642. }
  643.  
  644. function loadSettingsIntoInputs() {
  645. switch (settings.lastpostMode) {
  646. case DO_NOTHING:
  647. document.getElementById("doNothingLastPost").checked = true;
  648. break;
  649. case IGNORE:
  650. document.getElementById("hideLastPost").checked = true;
  651. break;
  652. case REPLACE:
  653. document.getElementById("replaceLastPost").checked = true;
  654. break;
  655. default:
  656. document.getElementById("hidePosts").checked = true;
  657. saveSetting("lastpostMode", IGNORE);
  658. break;
  659. }
  660.  
  661. switch (settings.quoteMode) {
  662. case DO_NOTHING:
  663. document.getElementById("doNothingQuotes").checked = true;
  664. break;
  665. case IGNORE:
  666. document.getElementById("hideQuotes").checked = true;
  667. break;
  668. case REPLACE:
  669. document.getElementById("replaceQuotes").checked = true;
  670. break;
  671. default:
  672. document.getElementById("hideQuotes").checked = true;
  673. saveSetting("quoteMode", IGNORE);
  674. break;
  675. }
  676.  
  677. switch (settings.postMode) {
  678. case DO_NOTHING:
  679. document.getElementById("doNothingPosts").checked = true;
  680. break;
  681. case IGNORE:
  682. document.getElementById("hidePosts").checked = true;
  683. break;
  684. case REPLACE:
  685. document.getElementById("replacePosts").checked = true;
  686. break;
  687. default:
  688. document.getElementById("hidePosts").checked = true;
  689. saveSetting("postMode", IGNORE);
  690. break;
  691. }
  692.  
  693. switch (settings.profileMsgMode) {
  694. case DO_NOTHING:
  695. document.getElementById("doNothingProfileMsgs").checked = true;
  696. break;
  697. case IGNORE:
  698. document.getElementById("hideProfileMsgs").checked = true;
  699. break;
  700. case REPLACE:
  701. document.getElementById("replaceProfileMsgs").checked = true;
  702. break;
  703. default:
  704. document.getElementById("hideProfileMsgs").checked = true;
  705. saveSetting("profileMsgMode", IGNORE);
  706. break;
  707. }
  708.  
  709. if (settings.removeTopics) {
  710. document.getElementById("removeTopics").checked = true;
  711. }
  712. if (settings.UnBlacklistUsername) {
  713. document.getElementById("UnBlacklistUsername").checked = true;
  714. }
  715. if (settings.removeUnBlacklist) {
  716. document.getElementById("removeUnBlacklist").checked = true;
  717. }
  718. if (settings.removeSignatures) {
  719. document.getElementById("removeSignatures").checked = true;
  720. }
  721. if (settings.removeUserinfo) {
  722. document.getElementById("removeUserinfo").checked = true;
  723. }
  724. if (settings.replaceUsername) {
  725. document.getElementById("replaceUsername").checked = true;
  726. }
  727. if (settings.replaceAvatar) {
  728. document.getElementById("replaceAvatar").checked = true;
  729. }
  730. if (settings.replaceProfileAvatar) {
  731. document.getElementById("replaceProfileAvatar").checked = true;
  732. }
  733.  
  734. document.getElementById("customLastPost").value = settings.customLastPost || "";
  735. document.getElementById("customQuote").value = settings.customQuote || "";
  736. document.getElementById("customPost").value = settings.customPost || "";
  737. document.getElementById("customUsername").value = settings.customUsername || "";
  738. document.getElementById("customAvatar").value = settings.customAvatar || "";
  739. document.getElementById("customProfileMsg").value = settings.customProfileMsg || "";
  740. document.getElementById("customProfileAvatar").value = settings.customProfileAvatar || "";
  741.  
  742. document.querySelector("[data-select-users]").dispatchEvent(new Event("change"));
  743. }
  744.  
  745. function alterLastPost(action) {
  746. document.querySelectorAll(QUOTE_SELECTOR).forEach(quotes => {
  747. if (quotes.querySelector(FORUM_QUOTE_NAME_SELECTOR) == null) return;
  748. const quoteuser = quotes.querySelector(FORUM_QUOTE_NAME_SELECTOR).textContent;
  749. let user = quoteuser.replace(' said:','');
  750. if (!blacklist.includes(user)) return;
  751. let quote = quotes;
  752. action(quote, user);
  753. });
  754. }
  755.  
  756. function alterQuotes(action) {
  757. document.querySelectorAll(QUOTE_SELECTOR).forEach(quotes => {
  758. if (quotes.querySelector(FORUM_QUOTE_NAME_SELECTOR) == null) return;
  759. const quoteuser = quotes.querySelector(FORUM_QUOTE_NAME_SELECTOR).textContent;
  760. let user = quoteuser.replace(' said:','');
  761. if (!blacklist.includes(user)) return;
  762. let quote = quotes;
  763. action(quote, user);
  764. });
  765. }
  766.  
  767. function alterPosts(action) {
  768. document.querySelectorAll(POST_USERS_SELECTOR).forEach(user => {
  769. if (!blacklist.includes(user.querySelector(FORUM_MSG_NAME_SELECTOR).textContent)) return;
  770. let post = user.parentNode;
  771. //for (let i = 0; i < 4; i++) {
  772. //post = post.parentNode;
  773. //}
  774. action(post, user);
  775. });
  776. }
  777.  
  778. function alterProfileMessages(action) {
  779. document.querySelectorAll(PROFILE_MSG_SELECTOR).forEach(profileMessage => {
  780. const username = profileMessage.querySelector(PROFILE_MSG_NAME_SELECTOR).textContent;
  781. if (!blacklist.includes(username)) return;
  782. action(profileMessage, username);
  783. });
  784. }
  785.  
  786. function alterComToCom(action) {
  787. document.querySelectorAll(COMTOCOM_SELECTOR).forEach(comMessage => {
  788. const username = comMessage.querySelector(COMTOCOM_NAME_SELECTOR).textContent;
  789. if (!blacklist.includes(username)) return;
  790. action(comMessage, username);
  791. });
  792. }
  793.  
  794. function ignoreLastPost() {
  795. alterQuotes(quote => {
  796. quote.style.display = "none";
  797. //post.previousElementSibling.style.display = "none";
  798. });
  799. }
  800.  
  801. function replaceLastPost() {
  802. alterQuotes((quote, user) => {
  803. const specificCustomLastPost = settings.specificCustomLastPost[user];
  804. quote.innerHTML = specificCustomLastPost ? specificCustomLastPost : settings.customQuote;
  805. });
  806. }
  807.  
  808. function ignoreQuotes() {
  809. alterQuotes(quote => {
  810. quote.style.display = "none";
  811. //post.previousElementSibling.style.display = "none";
  812. });
  813. }
  814.  
  815. function replaceQuotes() {
  816. alterQuotes((quote, user) => {
  817. const specificCustomQuote = settings.specificCustomQuote[user];
  818. quote.innerHTML = specificCustomQuote ? specificCustomQuote : settings.customQuote;
  819. });
  820. }
  821.  
  822. function ignorePosts() {
  823. alterPosts(post => {
  824. post.style.display = "none";
  825. post.previousElementSibling.style.display = "none";
  826. });
  827. }
  828.  
  829. function replacePosts() {
  830. alterPosts((post, user) => {
  831. const username = user.querySelector(FORUM_MSG_NAME_SELECTOR).textContent;
  832. const specificCustomPost = settings.specificCustomPost[username];
  833. post.querySelector(MESSAGE_SELECTOR).innerHTML = specificCustomPost ? specificCustomPost : settings.customPost;
  834. });
  835. }
  836.  
  837. function replaceProfileMsg() {
  838. alterProfileMessages((profileMessage, username) => {
  839. const specificCustomProfileMsg = settings.specificCustomProfileMsg[username];
  840. profileMessage.querySelector(PROFILE_MSG_TEXT_SELECTOR).innerHTML = specificCustomProfileMsg ? specificCustomProfileMsg : settings.customProfileMsg;
  841. });
  842. }
  843.  
  844. function replaceComToCom() {
  845. alterComToCom((comMessage, username) => {
  846. const specificCustomProfileMsg = settings.specificCustomProfileMsg[username];
  847. comMessage.querySelector(COMTOCOM_TEXT_SELECTOR).innerHTML = specificCustomProfileMsg ? specificCustomProfileMsg : settings.customProfileMsg;
  848. });
  849. }
  850.  
  851. function ignoreTopics() {
  852. document.querySelectorAll(TOPIC_USERS_SELECTOR).forEach(user => {
  853. if (!blacklist.includes(user.textContent)) return;
  854. user.closest("tr").style.display = "none";
  855. });
  856. }
  857.  
  858. function ignoreProfileMsgs() {
  859. alterProfileMessages(profileMessage => {
  860. profileMessage.style.display = "none";
  861. });
  862. }
  863.  
  864. function ignoreComToCom() {
  865. alterComToCom(comMessage => {
  866. comMessage.style.display = "none";
  867. });
  868. }
  869.  
  870. function replaceUsername() {
  871. alterPosts((post, user) => {
  872. user.querySelector(FORUM_MSG_NAME_SELECTOR).innerHTML = `<a href="${user.querySelector(USER_PROFILE_SELECTOR).href}">${settings.customUsername}</a>`;
  873. });
  874. }
  875.  
  876. function replaceAvatar() {
  877. alterPosts((post, user) => {
  878. const avatar = user.querySelector(AVATAR_SELECTOR);
  879.  
  880. if (!avatar) {
  881. if (settings.customAvatar === "") return;
  882.  
  883. const avatar = document.createElement("a");
  884. avatar.href = user.querySelector(USER_PROFILE_SELECTOR).href;
  885. avatar.className = "forum-icon";
  886. avatar.innerHTML = `
  887. <img class=" lazyloaded" data-src="${settings.customAvatar}" vspace="2" border="0" src="${settings.customAvatar}" width="100" height="125">`;
  888. user.querySelector(USER_INFO_SELECTOR).insertAdjacentElement('afterend', avatar);
  889. } else {
  890. if (settings.customAvatar === "") {
  891. avatar.style.display = "none";
  892. return;
  893. }
  894.  
  895. const img = avatar.querySelector("img");
  896. img.src = settings.customAvatar;
  897. img.setAttribute("data-src", settings.customAvatar);
  898. img.setAttribute("width", 100);
  899. img.setAttribute("height", 125);
  900. }
  901. });
  902. }
  903.  
  904. function replaceProfileAvatar() {
  905. alterProfileMessages(profileMessage => {
  906. const avatar = profileMessage.querySelector(PROFILE_MSG_AVATAR_SELECTOR);
  907.  
  908. if (settings.customProfileAvatar === "") {
  909. avatar.style.display = "none";
  910. return;
  911. }
  912.  
  913. const img = avatar.querySelector("img");
  914. img.src = settings.customProfileAvatar;
  915. img.setAttribute("data-src", settings.customProfileAvatar);
  916. });
  917. }
  918.  
  919. function replaceComToComAvatar() {
  920. alterComToCom(comMessage => {
  921. const avatar = comMessage.querySelector(COMTOCOM_AVATAR_SELECTOR);
  922.  
  923. if (settings.customProfileAvatar === "") {
  924. avatar.style.display = "none";
  925. return;
  926. }
  927.  
  928. const img = avatar.querySelector("img");
  929. img.src = settings.customProfileAvatar;
  930. img.setAttribute("data-src", settings.customProfileAvatar);
  931. });
  932. }
  933.  
  934. function removeSignatures() {
  935. alterPosts(post => {
  936. const signature = post.querySelector(SIGNATURE_SELECTOR);
  937. if (!signature) return;
  938. signature.style.display = "none";
  939. });
  940. }
  941.  
  942. function removeUserinfo() {
  943. alterPosts(post => {
  944. const userinfo = post.querySelector(USERINFO_SELECTOR);
  945. if (!userinfo) return;
  946. userinfo.style.display = "none";
  947. const userinfo1 = post.querySelector(USERINFO_SELECTOR1);
  948. if (!userinfo1) return;
  949. userinfo1.style.display = "none";
  950. const userinfo2 = post.querySelector(USERINFO_SELECTOR2);
  951. if (!userinfo2) return;
  952. userinfo2.style.display = "none";
  953. const userinfo3 = post.querySelector(USERINFO_SELECTOR3);
  954. if (!userinfo3) return;
  955. userinfo3.style.display = "none";
  956. const userinfo4 = post.querySelector(USERINFO_SELECTOR4);
  957. if (!userinfo4) return;
  958. userinfo4.style.display = "none";
  959. });
  960. }
  961. function addPostsBlackListButtons() {
  962. document.querySelectorAll(FORUM_MESSAGE_SELECTOR).forEach(forumMessage => {
  963. const actionBar = forumMessage.querySelector(FORUM_ACTION_BAR_SELECTOR);
  964. const username = forumMessage.querySelector(FORUM_MSG_NAME_SELECTOR).textContent;
  965. if (!blacklist.includes(username)) {
  966. addBlackListButton(actionBar, username);
  967. } else {
  968. addUnBlackListButton(actionBar, username);
  969. }
  970. });
  971. }
  972.  
  973. function addProfileMsgBlackListButtons() {
  974. document.querySelectorAll(PROFILE_MSG_SELECTOR).forEach(profileMessage => {
  975. let actionBar = profileMessage.querySelector(PROFILE_MSG_ACTION_BAR_SELECTOR);
  976. const username = profileMessage.querySelector(PROFILE_MSG_NAME_SELECTOR).textContent;
  977.  
  978. //this happens when you are looking at someone elses profile, create the actionBar.
  979. if (!actionBar) {
  980. actionBar = document.createElement("div");
  981. actionBar.className = "postActions ar mt4";
  982. profileMessage.querySelector(PROFILE_MSG_TEXT_SELECTOR).insertAdjacentElement("afterend", actionBar);
  983. }
  984.  
  985. if (!blacklist.includes(username)) {
  986. addBlackListLink(actionBar, username, " | ");
  987. } else {
  988. addUnBlackListLink(actionBar, username, " | ");
  989. }
  990. });
  991. }
  992.  
  993. function addComToComBlackListButtons() {
  994. document.querySelectorAll(COMTOCOM_SELECTOR).forEach(comMessage => {
  995. let actionBar = comMessage.querySelector(COMTOCOM_ACTION_BAR_SELECTOR);
  996. const username = comMessage.querySelector(COMTOCOM_NAME_SELECTOR).textContent;
  997.  
  998. //this happens when you manually enter the url of com-to-com between 2 users other than you.
  999. if (!actionBar) {
  1000. const actionBarContainer = document.createElement("div");
  1001. actionBarContainer.style.marginTop = "10px";
  1002. actionBar = document.createElement("small");
  1003. actionBarContainer.appendChild(actionBar);
  1004. comMessage.querySelector(COMTOCOM_TEXT_SELECTOR).insertAdjacentElement("afterend", actionBarContainer);
  1005. }
  1006.  
  1007. if (!blacklist.includes(username)) {
  1008. addBlackListLink(actionBar, username, " | ");
  1009. } else {
  1010. addUnBlackListLink(actionBar, username, " | ");
  1011. }
  1012. });
  1013. }
  1014.  
  1015. function addBlackListLink(actionBar, username, separator) {
  1016. const you = document.querySelector(YOU_SELECTOR).textContent;
  1017. if (username == you) return
  1018. const a = document.createElement("a");
  1019. a.href = "javascript:void(0)";
  1020. a.textContent = "Blacklist User";
  1021. a.dataset.username = username;
  1022. a.onclick = blacklistUser;
  1023.  
  1024. actionBar.after(a);
  1025.  
  1026. if (separator) {
  1027. actionBar.after(document.createTextNode(separator));
  1028. }
  1029. }
  1030.  
  1031. function addUnBlackListLink(actionBar, username, separator) {
  1032. if (settings.removeUnBlacklist) return;
  1033. const a = document.createElement("a");
  1034. a.href = "javascript:void(0)";
  1035. a.textContent = "UnBlacklist User";
  1036. if (settings.UnBlacklistUsername) a.title = username;
  1037. a.dataset.username = username;
  1038. a.onclick = blacklistUser;
  1039.  
  1040. actionBar.after(a);
  1041.  
  1042. if (separator) {
  1043. actionBar.after(document.createTextNode(separator));
  1044. }
  1045. }
  1046.  
  1047. function addBlackListButton(actionBar, username, separator) {
  1048. const you = document.querySelector(YOU_SELECTOR).textContent;
  1049. if (username == you) return
  1050. const a = document.createElement("button");
  1051. a.href = "javascript:void(0)";
  1052. a.textContent = "Blacklist User";
  1053. a.classList.add("mal-btn");
  1054. a.dataset.username = username;
  1055. a.onclick = blacklistUser;
  1056.  
  1057. if (actionBar.childElementCount > 0 && separator) {
  1058. actionBar.prepend(document.createTextNode(separator));
  1059. }
  1060. actionBar.prepend(a);
  1061. }
  1062.  
  1063. function addUnBlackListButton(actionBar, username, separator) {
  1064. if (settings.removeUnBlacklist) return;
  1065. const a = document.createElement("button");
  1066. a.href = "javascript:void(0)";
  1067. a.textContent = "UnBlacklist User";
  1068. a.classList.add("mal-btn");
  1069. if (settings.UnBlacklistUsername) a.title = username;
  1070. a.dataset.username = username;
  1071. a.onclick = blacklistUser;
  1072.  
  1073. if (actionBar.childElementCount > 0 && separator) {
  1074. actionBar.prepend(document.createTextNode(separator));
  1075. }
  1076. actionBar.prepend(a);
  1077. }
  1078.  
  1079. function blacklistUser(e) {
  1080. const username = e.target.dataset.username;
  1081.  
  1082. if (blacklist.includes(username)) {
  1083. removeUser(username);
  1084. window.location.reload();
  1085. } else {
  1086. addUser(username);
  1087. window.location.reload();
  1088. }
  1089. }
  1090.  
  1091. //Add a user to the blacklist
  1092. function addUser(username) {
  1093. blacklist.push(username);
  1094. saveBlackList();
  1095. }
  1096.  
  1097. //Remove a user from the blacklist if it's there
  1098. function removeUser(userName) {
  1099. blacklist = blacklist.filter(name => userName !== name);
  1100. saveBlackList();
  1101. }
  1102.  
  1103. //remove the user node from the html code and then update the localStorage
  1104. function removeNode(e) {
  1105. const row = e.target.parentNode;
  1106. const name = row.querySelector("[data-name]").textContent;
  1107. row.remove();
  1108. removeUser(name);
  1109. removeUserFromSelect(name);
  1110. }
  1111.  
  1112. //modify the user node from the html code and then update the localStorage
  1113. function saveNode(e) {
  1114. const newName = e.target.textContent;
  1115. const previousName = e.target.dataset.previousName;
  1116.  
  1117. previousName && removeUser(previousName);
  1118.  
  1119. if (newName !== "") {
  1120. addUser(newName);
  1121. e.target.dataset.previousName = newName;
  1122. } else {
  1123. e.target.parentNode.remove();
  1124. }
  1125. }
  1126.  
  1127. //add a new user node to the html code and then update the localStorage
  1128. function addNode(e) {
  1129. const node = e.target.parentNode;
  1130. const usernameNode = node.querySelector("[data-name]");
  1131. const username = usernameNode.textContent;
  1132. usernameNode.textContent = "";
  1133.  
  1134. if (!blacklist.includes(username)) {
  1135. createNode(username);
  1136. addUser(username);
  1137. addUserToSelect(username);
  1138. }
  1139. }
  1140.  
  1141. //create the user node then add it to the html code
  1142. function createNode(username) {
  1143. const newUser = document.createElement("div");
  1144. newUser.setAttribute("data-user", "");
  1145. newUser.className = "user";
  1146. newUser.innerHTML = `<div data-name class="name" contenteditable="true" onclick="this.focus()" data-previous-name="${username}">${username}</div>
  1147. <button data-remove class="remove">Remove</button>`;
  1148. newUser.querySelector("[data-name]").addEventListener("focusout", saveNode);
  1149. newUser.querySelector("[data-remove]").addEventListener("click", removeNode);
  1150. document.querySelector("[data-blacklist]").append(newUser);
  1151. }
  1152.  
  1153. //add the users inside the user select element
  1154. function addUserToSelect(username) {
  1155. const selectUser = document.querySelector("[data-select-users]");
  1156. const option = document.createElement("option");
  1157. option.value = option.textContent = username;
  1158. selectUser.appendChild(option);
  1159. }
  1160.  
  1161. //remove the user from the select list
  1162. function removeUserFromSelect(username) {
  1163. const userOption = document.querySelector(`[data-select-users] [value="${username}"]`);
  1164. if (userOption) userOption.remove();
  1165. }
  1166.  
  1167. //load a custom post and custom profile message of a specific blacklisted user into the 2 text areas designated for these inputs
  1168. function loadSpecificMessages(e) {
  1169. const userCustomLastPost = settings.specificCustomLastPost[e.target.value];
  1170. const userCustomQuote = settings.specificCustomQuote[e.target.value];
  1171. const userCustomPost = settings.specificCustomPost[e.target.value];
  1172. const userCustomProfileMsg = settings.specificCustomProfileMsg[e.target.value];
  1173. const customLastPost = document.getElementById("specificCustomLastPost");
  1174. const customQuote = document.getElementById("specificCustomQuote");
  1175. const customPost = document.getElementById("specificCustomPost");
  1176. const customProfileMsg = document.getElementById("specificCustomProfileMsg");
  1177. customLastPost.value = userCustomLastPost ? userCustomLastPost : "";
  1178. customQuote.value = userCustomQuote ? userCustomQuote : "";
  1179. customPost.value = userCustomPost ? userCustomPost : "";
  1180. customProfileMsg.value = userCustomProfileMsg ? userCustomProfileMsg : "";
  1181. }
  1182. })();