gimmickCellar

GranularBlocker

May 24th, 2026 (edited)
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.67 KB | None | 0 0
  1. // ==UserScript==
  2. // @name OWoT GranularBlocker
  3. // @namespace gimmickCellar
  4. // @version 1.1
  5. // @description /block but cooler
  6. // @author gimmickCellar
  7. // @match *://*ourworldoftext.com/*
  8. // @match *://localhost/*
  9. // @match *://127.0.0.1/*
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. var blocks = {
  15. ids: [],
  16. usernames: {},
  17. nickedanon: false,
  18. nonickanon: false,
  19. nicknames: [],
  20. messagecontains: [],
  21. blockAll: false,
  22. noTell: false,
  23. noAnon: false,
  24. noReg: false
  25. };
  26.  
  27. var renderedChats = [];
  28.  
  29. function loadBlocks() {
  30. var stored = localStorage.getItem("gimmick_blocks");
  31. if (stored) {
  32. try {
  33. var parsed = JSON.parse(stored);
  34. if (parsed && typeof parsed === "object") {
  35. blocks = Object.assign(blocks, parsed);
  36. }
  37. } catch (e) {}
  38. }
  39. }
  40.  
  41. function saveBlocks() {
  42. try {
  43. localStorage.setItem("gimmick_blocks", JSON.stringify(blocks));
  44. applyRetroactiveDeletions();
  45. } catch (err) {
  46. console.error(err);
  47. }
  48. }
  49.  
  50. function printFeedback(msg) {
  51. if (typeof addChat === "function") {
  52. addChat(null, 0, "user", "[ Client ]", msg, "Client", false, false, false, null, Date.now());
  53. } else {
  54. console.log("[Client] " + msg);
  55. }
  56. }
  57.  
  58. function shouldHideChat(e) {
  59. try {
  60. if (!e) return false;
  61. if (blocks.blockAll) return true;
  62.  
  63. var isTell = e.privateMessage === "to_me" || (e.dataObj && e.dataObj.privateMessage === "to_me");
  64. if (isTell && blocks.noTell) return true;
  65.  
  66. if (!e.registered && blocks.noAnon) return true;
  67. if (e.registered && blocks.noReg) return true;
  68.  
  69. if (e.type === "anon_nick" && blocks.nickedanon) return true;
  70. if (e.type === "anon" && blocks.nonickanon) return true;
  71.  
  72. if (typeof e.id === "number" && blocks.ids.includes(e.id)) return true;
  73.  
  74. if (e.nickname) {
  75. var nickUpper = e.nickname.toUpperCase();
  76. for (var i = 0; i < blocks.nicknames.length; i++) {
  77. if (nickUpper.includes(blocks.nicknames[i].toUpperCase())) {
  78. return true;
  79. }
  80. }
  81. }
  82.  
  83. if (e.message) {
  84. var msgUpper = e.message.toUpperCase();
  85. for (var i = 0; i < blocks.messagecontains.length; i++) {
  86. if (msgUpper.includes(blocks.messagecontains[i].toUpperCase())) {
  87. return true;
  88. }
  89. }
  90. }
  91.  
  92. if (e.registered && e.realUsername) {
  93. var userKey = e.realUsername.toUpperCase();
  94. if (blocks.usernames.hasOwnProperty(userKey)) {
  95. var userRules = blocks.usernames[userKey];
  96. if (Array.isArray(userRules)) {
  97. for (var j = 0; j < userRules.length; j++) {
  98. var rule = userRules[j];
  99. if (!rule || !rule.hasOwnProperty("condition") || rule.condition === null || rule.condition === undefined) {
  100. return true;
  101. }
  102. var ruleLower = String(rule.condition).toLowerCase();
  103. if (ruleLower === "tell" && isTell) {
  104. return true;
  105. }
  106. if (ruleLower.startsWith("messagecontains:")) {
  107. var matchText = String(rule.condition).substring("messagecontains:".length).toUpperCase();
  108. if (e.message && e.message.toUpperCase().includes(matchText)) {
  109. return true;
  110. }
  111. }
  112. if (ruleLower.startsWith("nickname:")) {
  113. var matchNick = String(rule.condition).substring("nickname:".length).toUpperCase();
  114. if (e.nickname && e.nickname.toUpperCase().includes(matchNick)) {
  115. return true;
  116. }
  117. }
  118. }
  119. }
  120. }
  121. }
  122. } catch (err) {
  123. console.error(err);
  124. }
  125.  
  126. return false;
  127. }
  128.  
  129. function deleteChatRecord(id, date) {
  130. try {
  131. var records = [window.chatRecordsPage, window.chatRecordsGlobal];
  132. for (var r = 0; r < records.length; r++) {
  133. var recList = records[r];
  134. if (!recList) continue;
  135. for (var i = 0; i < recList.length; i++) {
  136. var currentRec = recList[i];
  137. if (currentRec && currentRec.id === id && currentRec.date === date) {
  138. if (currentRec.element) {
  139. currentRec.element.remove();
  140. }
  141. recList.splice(i, 1);
  142. i--;
  143. }
  144. }
  145. }
  146. } catch (err) {
  147. console.error(err);
  148. }
  149. }
  150.  
  151. function applyRetroactiveDeletions() {
  152. try {
  153. var toDelete = [];
  154. for (var i = 0; i < renderedChats.length; i++) {
  155. var chat = renderedChats[i];
  156. if (shouldHideChat(chat)) {
  157. toDelete.push(chat);
  158. }
  159. }
  160. for (var j = 0; j < toDelete.length; j++) {
  161. var target = toDelete[j];
  162. deleteChatRecord(target.id, target.date);
  163. var idx = renderedChats.indexOf(target);
  164. if (idx > -1) {
  165. renderedChats.splice(idx, 1);
  166. }
  167. }
  168. } catch (err) {
  169. console.error(err);
  170. }
  171. }
  172.  
  173. function blockCommand(args) {
  174. try {
  175. var arg = args.join(" ").trim();
  176. if (!arg) {
  177. printFeedback("Usage: /block <nickedanon|nonickanon|anon|reg|tell|*|nickname:<text>|messagecontains:<text>|ID>");
  178. return;
  179. }
  180.  
  181. if (arg === "nickedanon") {
  182. blocks.nickedanon = true;
  183. saveBlocks();
  184. printFeedback("Blocked nicked anonymous users.");
  185. } else if (arg === "nonickanon") {
  186. blocks.nonickanon = true;
  187. saveBlocks();
  188. printFeedback("Blocked no-nick anonymous users.");
  189. } else if (arg === "anon") {
  190. blocks.noAnon = true;
  191. saveBlocks();
  192. printFeedback("Blocked all anonymous users.");
  193. } else if (arg === "reg") {
  194. blocks.noReg = true;
  195. saveBlocks();
  196. printFeedback("Blocked all registered users.");
  197. } else if (arg === "tell") {
  198. blocks.noTell = true;
  199. saveBlocks();
  200. printFeedback("Blocked whispers/tells.");
  201. } else if (arg === "*") {
  202. blocks.blockAll = true;
  203. saveBlocks();
  204. printFeedback("Blocked all users.");
  205. } else if (arg.startsWith("nickname:")) {
  206. var nickText = arg.substring("nickname:".length).trim();
  207. if (nickText) {
  208. if (!blocks.nicknames.includes(nickText)) {
  209. blocks.nicknames.push(nickText);
  210. saveBlocks();
  211. }
  212. printFeedback("Blocked nickname containing: " + nickText);
  213. }
  214. } else if (arg.startsWith("messagecontains:")) {
  215. var msgText = arg.substring("messagecontains:".length).trim();
  216. if (msgText) {
  217. if (!blocks.messagecontains.includes(msgText)) {
  218. blocks.messagecontains.push(msgText);
  219. saveBlocks();
  220. }
  221. printFeedback("Blocked messages containing: " + msgText);
  222. }
  223. } else {
  224. var id = parseInt(arg, 10);
  225. if (!isNaN(id)) {
  226. if (!blocks.ids.includes(id)) {
  227. blocks.ids.push(id);
  228. saveBlocks();
  229. }
  230. printFeedback("Blocked ID: " + id);
  231. } else {
  232. printFeedback("Invalid block target. Use /block without arguments to see options.");
  233. }
  234. }
  235. } catch (err) {
  236. console.error(err);
  237. }
  238. }
  239.  
  240. function unblockCommand(args) {
  241. try {
  242. var arg = args.join(" ").trim();
  243. if (!arg) {
  244. printFeedback("Usage: /unblock <nickedanon|nonickanon|anon|reg|tell|*|nickname:<text>|messagecontains:<text>|ID>");
  245. return;
  246. }
  247.  
  248. if (arg === "nickedanon") {
  249. blocks.nickedanon = false;
  250. saveBlocks();
  251. printFeedback("Unblocked nicked anonymous users.");
  252. } else if (arg === "nonickanon") {
  253. blocks.nonickanon = false;
  254. saveBlocks();
  255. printFeedback("Unblocked no-nick anonymous users.");
  256. } else if (arg === "anon") {
  257. blocks.noAnon = false;
  258. saveBlocks();
  259. printFeedback("Unblocked all anonymous users.");
  260. } else if (arg === "reg") {
  261. blocks.noReg = false;
  262. saveBlocks();
  263. printFeedback("Unblocked all registered users.");
  264. } else if (arg === "tell") {
  265. blocks.noTell = false;
  266. saveBlocks();
  267. printFeedback("Unblocked whispers/tells.");
  268. } else if (arg === "*") {
  269. blocks.blockAll = false;
  270. saveBlocks();
  271. printFeedback("Unblocked all users.");
  272. } else if (arg.startsWith("nickname:")) {
  273. var nickText = arg.substring("nickname:".length).trim();
  274. var index = blocks.nicknames.indexOf(nickText);
  275. if (index > -1) {
  276. blocks.nicknames.splice(index, 1);
  277. saveBlocks();
  278. printFeedback("Unblocked nickname containing: " + nickText);
  279. } else {
  280. printFeedback("Nickname filter not found: " + nickText);
  281. }
  282. } else if (arg.startsWith("messagecontains:")) {
  283. var msgText = arg.substring("messagecontains:".length).trim();
  284. var index = blocks.messagecontains.indexOf(msgText);
  285. if (index > -1) {
  286. blocks.messagecontains.splice(index, 1);
  287. saveBlocks();
  288. printFeedback("Unblocked messages containing: " + msgText);
  289. } else {
  290. printFeedback("Message filter not found: " + msgText);
  291. }
  292. } else {
  293. var id = parseInt(arg, 10);
  294. if (!isNaN(id)) {
  295. var index = blocks.ids.indexOf(id);
  296. if (index > -1) {
  297. blocks.ids.splice(index, 1);
  298. saveBlocks();
  299. printFeedback("Unblocked ID: " + id);
  300. } else {
  301. printFeedback("ID block not found: " + id);
  302. }
  303. } else {
  304. printFeedback("Invalid unblock target.");
  305. }
  306. }
  307. } catch (err) {
  308. console.error(err);
  309. }
  310. }
  311.  
  312. function blockuserCommand(args) {
  313. try {
  314. var input = args.join(" ").trim();
  315. if (!input) {
  316. printFeedback("Usage: /blockuser <username> [messagecontains:<text>|nickname:<text>|tell]");
  317. return;
  318. }
  319. var match = input.match(/^(.+?)\s+(messagecontains:.+|nickname:.+|tell)$/i);
  320. var username, condition;
  321. if (match) {
  322. username = match[1].trim();
  323. condition = match[2].trim();
  324. } else {
  325. username = input;
  326. condition = null;
  327. }
  328. var userKey = username.toUpperCase();
  329. if (!blocks.usernames[userKey]) {
  330. blocks.usernames[userKey] = [];
  331. }
  332. var exists = false;
  333. for (var i = 0; i < blocks.usernames[userKey].length; i++) {
  334. if (blocks.usernames[userKey][i] && blocks.usernames[userKey][i].condition === condition) {
  335. exists = true;
  336. break;
  337. }
  338. }
  339. if (!exists) {
  340. blocks.usernames[userKey].push({ condition: condition });
  341. saveBlocks();
  342. }
  343. if (condition) {
  344. printFeedback("Blocked user " + username + " under condition: " + condition);
  345. } else {
  346. printFeedback("Blocked user " + username + " unconditionally.");
  347. }
  348. } catch (err) {
  349. console.error(err);
  350. }
  351. }
  352.  
  353. function unblockuserCommand(args) {
  354. try {
  355. var input = args.join(" ").trim();
  356. if (!input) {
  357. printFeedback("Usage: /unblockuser <username> [messagecontains:<text>|nickname:<text>|tell]");
  358. return;
  359. }
  360. var match = input.match(/^(.+?)\s+(messagecontains:.+|nickname:.+|tell)$/i);
  361. var username, condition;
  362. if (match) {
  363. username = match[1].trim();
  364. condition = match[2].trim();
  365. } else {
  366. username = input;
  367. condition = null;
  368. }
  369. var userKey = username.toUpperCase();
  370. if (blocks.usernames[userKey]) {
  371. if (condition === null) {
  372. delete blocks.usernames[userKey];
  373. saveBlocks();
  374. printFeedback("Unblocked user " + username + " completely.");
  375. } else {
  376. var index = -1;
  377. for (var i = 0; i < blocks.usernames[userKey].length; i++) {
  378. if (blocks.usernames[userKey][i] && blocks.usernames[userKey][i].condition === condition) {
  379. index = i;
  380. break;
  381. }
  382. }
  383. if (index > -1) {
  384. blocks.usernames[userKey].splice(index, 1);
  385. if (blocks.usernames[userKey].length === 0) {
  386. delete blocks.usernames[userKey];
  387. }
  388. saveBlocks();
  389. printFeedback("Removed rule '" + condition + "' for user " + username);
  390. } else {
  391. printFeedback("Rule '" + condition + "' not found for user " + username);
  392. }
  393. }
  394. } else {
  395. printFeedback("User block not found for " + username);
  396. }
  397. } catch (err) {
  398. console.error(err);
  399. }
  400. }
  401.  
  402. function unblockallCommand() {
  403. try {
  404. blocks = {
  405. ids: [],
  406. usernames: {},
  407. nickedanon: false,
  408. nonickanon: false,
  409. nicknames: [],
  410. messagecontains: [],
  411. blockAll: false,
  412. noTell: false,
  413. noAnon: false,
  414. noReg: false
  415. };
  416. saveBlocks();
  417. printFeedback("Cleared all custom blocks.");
  418. } catch (err) {
  419. console.error(err);
  420. }
  421. }
  422.  
  423. function blocklistCommand() {
  424. try {
  425. var lines = ["=== Custom Block List ==="];
  426. if (blocks.blockAll) lines.push("- Block All (*): Enabled");
  427. if (blocks.noTell) lines.push("- Block Tells (whispers): Enabled");
  428. if (blocks.noAnon) lines.push("- Block Anonymous: Enabled");
  429. if (blocks.noReg) lines.push("- Block Registered: Enabled");
  430. if (blocks.nickedanon) lines.push("- Block Nicked Anonymous: Enabled");
  431. if (blocks.nonickanon) lines.push("- Block No-Nick Anonymous: Enabled");
  432.  
  433. if (blocks.ids.length > 0) {
  434. lines.push("- Blocked IDs: " + blocks.ids.join(", "));
  435. }
  436. if (blocks.nicknames.length > 0) {
  437. lines.push("- Nickname Filters: " + blocks.nicknames.map(function(n) { return '"' + n + '"'; }).join(", "));
  438. }
  439. if (blocks.messagecontains.length > 0) {
  440. lines.push("- Message Filters: " + blocks.messagecontains.map(function(m) { return '"' + m + '"'; }).join(", "));
  441. }
  442. var userKeys = Object.keys(blocks.usernames);
  443. if (userKeys.length > 0) {
  444. lines.push("- Blocked Users:");
  445. for (var i = 0; i < userKeys.length; i++) {
  446. var userKey = userKeys[i];
  447. var rules = blocks.usernames[userKey];
  448. if (Array.isArray(rules)) {
  449. var formattedRules = rules.map(function(r) {
  450. return r && r.condition ? r.condition : "unconditional";
  451. });
  452. lines.push(" • " + userKey + " [" + formattedRules.join(", ") + "]");
  453. }
  454. }
  455. }
  456. if (lines.length === 1) {
  457. lines.push("(No active blocks)");
  458. }
  459. printFeedback(lines.join("\n"));
  460. } catch (err) {
  461. console.error(err);
  462. }
  463. }
  464.  
  465. function init() {
  466. try {
  467. loadBlocks();
  468. w.chat.registerCommand("block", blockCommand, ["target"], "Client-side block command", "messagecontains:spam");
  469. w.chat.registerCommand("unblock", unblockCommand, ["target"], "Client-side unblock command", "messagecontains:spam");
  470. w.chat.registerCommand("blockuser", blockuserCommand, ["username", "condition"], "Client-side block user command", "JohnDoe tell");
  471. w.chat.registerCommand("unblockuser", unblockuserCommand, ["username", "condition"], "Client-side unblock user command", "JohnDoe");
  472. w.chat.registerCommand("unblockall", unblockallCommand, [], "Client-side clear all blocks", "");
  473. w.chat.registerCommand("blocklist", blocklistCommand, [], "Client-side show all active blocks", "");
  474.  
  475. var originalAddChat = window.addChat;
  476. window.addChat = function(chatfield, id, type, nickname, message, realUsername, op, admin, staff, color, date, dataObj) {
  477. try {
  478. var chatDate = date || Date.now();
  479. var isRegistered = (type === "user" || type === "user_nick");
  480. var e = {
  481. id: id,
  482. date: chatDate,
  483. type: type,
  484. nickname: nickname,
  485. message: message,
  486. realUsername: realUsername,
  487. registered: isRegistered,
  488. privateMessage: dataObj ? dataObj.privateMessage : null,
  489. dataObj: dataObj
  490. };
  491.  
  492. if (shouldHideChat(e)) {
  493. return;
  494. }
  495.  
  496. renderedChats.push(e);
  497. if (renderedChats.length > 4000) {
  498. renderedChats.shift();
  499. }
  500.  
  501. originalAddChat(chatfield, id, type, nickname, message, realUsername, op, admin, staff, color, chatDate, dataObj);
  502. } catch (innerErr) {
  503. console.error(innerErr);
  504. }
  505. };
  506. } catch (err) {
  507. console.error(err);
  508. }
  509. }
  510.  
  511. var checker = setInterval(function() {
  512. if (typeof w !== "undefined" && typeof w.chat !== "undefined" && typeof w.chat.registerCommand !== "undefined" && typeof w.on !== "undefined" && typeof window.addChat === "function") {
  513. clearInterval(checker);
  514. init();
  515. }
  516. }, 100);
  517. })();
Advertisement
Add Comment
Please, Sign In to add comment