nHentai SauceBot

Automatically converts every 5-6 digit number it finds into a link to nHentai

  1. // ==UserScript==
  2. // @name nHentai SauceBot
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2
  5. // @description Automatically converts every 5-6 digit number it finds into a link to nHentai
  6. // @author ProgrammingandPorn
  7. // @match *://*.reddit.com/*
  8. // @grant none
  9. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAABKpJREFUWIXFl09oVFcUxn/3vjfzZjqNE20Qg6YDSdFCmkhLdBVEgsZaQZFYXWgp1BYE20WzcFMXXWbRYhcN+UMWLbalNaVQYimEEl2UYiFIQyQYY2owOtXmzTROMpk/7717u5g4ScwYX2ywBx68e+ae833z3XMO7wrmzTTNqrKysvdDoVCzaZrVUsrnAcnamKuUmnNddzybzfbPzMy0u647CSAAwuHw6xUVFd9JKdetEeCKppR6YNv20Uwm0y9M06yqrKy89qzAF5GYjsfjdUY0Gv0oFAo1PUtwACFESGudM0OhUDOA1ho084cCQog1BdRaz78UMIQQhMPhvaZhGNVW3uMN+QKt4WqkgD/dNJedJJfdJONGHkzj6VBdjxovyG5zA7sDG6g2IygNn2bG+Vkl8QzjJRGLxRzABDAcj/bgNhqs9cUcjvLoyUzypXcPN+iPiJn3eNvYxLvhKgJyIeb3XJIP8jdQAeOhKo6IxWL6UdY/WHW8GIgsceeUx5GZq/xlrQxemYPvy17DkkvJTjhpjuSGH1VTLe9z0+D03Mgy9+dzt4gH1MroQDyg6MhMLPF5ShVyljjKkoMmHtQM51PF9aXsFN/IBEI+eS4JKTkvbC5lp4q+YXeGe0Fdcn/JjEIIurK3i+u23C1f4ItJtOVuFdfd2duP7arHZh3Vc8X3pPR8g5eKWZzLN4GMWDjvTcpcNYHFMRlRWv4VCazTCwXTE6mjLFcgJITg4MGD9Pb2Mjo6ytDQEB0dHTQ2NhaHzbqcoidSV4yP6se37/I2pDC1tuVN6o0y3gptYbMZxlOKTu5x+rcfqaioIJlMMjIygmVZ1NfXY1kWN2/e5Nu9x3kvsAVDSu64Gb7K3uEPb4axoFuqDlRJAkt2eB4fis0cD28h8dlptjbv4tSpU/T39xcTCiHo7Oxk3759/PpJFy/3/ML5uUnO6TjSWLF4S8yBR0waBud0nJ+yf7O1eRfAEvCHirW2tjI+Ps7d9RYDGdsPeIH8kxR4aJ7ncf36dSKRCC0tLQwODi4jAQU1lFJIf22rjPLy8o/97JRSkkqlaGpq4tixY+zfv598Po9t28zOziKEWHIkPk37VgBAKcXJkyc5e/YshrFQ2Y7jcOHCBbq7u5mYmFgNgScXYSkTQlBbW8vhw4dpaWmhvLy8+FtHRwdtbW1+STwdgcWmtSYajXLixAnOnDkDQENDA7Zt+yLge8AbhsGOHTvYuXPnEr8QglQqRXt7OwMDAwDU1NT4/gO+Z6xlWfT29pJOp6mtrS25JxgMApBIJHwT8K1AOp2mr6+PSCRCV1cXoVAIrXXxOXToEI2Njdy/f5+xsTHfBEQsFnMBX99aUkr6+vqKCqRSKdLpNBs3bsQwDGzbZs+ePUxPT/sC11rnRVVV1YPV3Am01mzfvp0DBw5QV1dHIBBgdHSUixcvcuXKFb9pgMLdQFRWVl4NBoOvripyjSyfzw/KbDbb/3+AAyy+mg1LKaPPEnz+avaKdF130rbto0opf5WzNuD/TE1Nvel53l0DwHXd8XQ6/bXWOielDAshngOkKMxT/V8frbWrtZ5xHOfa7OzsF4lE4h3HcYYA/gUeRwxt5UumGgAAAABJRU5ErkJggg==
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. const MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
  16.  
  17. // Create a new MutationObserver object that will call its function on DOM modifications
  18. var observer = new MutationObserver(function(mutations, observer) {
  19. findNodes();
  20. });
  21.  
  22. // Define what element should be observed by the observer
  23. // and what types of mutations trigger the callback
  24. observer.observe(document.body, {
  25. subtree: true,
  26. childList: true,
  27. attributes: true
  28. });
  29.  
  30. // Call the initial findNodes function
  31. findNodes();
  32.  
  33. // Parse each node individually, searching for either 5 or 6 consecutive digits.
  34. function handleNode(node) {
  35. let splits = node.textContent.split(/(\d{6}|\d{5})/g);
  36.  
  37. // If at least one match is found, create a span element to replace the text
  38. if (splits.length > 1) {
  39. let newSpan = document.createElement('span');
  40.  
  41. // Loop through all matches
  42. splits.forEach(function(el) {
  43. let match = el.match(/\d{6}|\d{5}/g);
  44.  
  45. // If it's a sauce, replace it with a link, otherwise, add the text as normal
  46. if (match && match.length == 1 && match[0] == el) {
  47. let link = document.createElement('a');
  48. link.textContent = el;
  49. link.setAttribute('href', `https://nhentai.net/g/${el}/`);
  50. link.setAttribute('target', '_blank');
  51. link.classList.add('sauced');
  52. link.style.color = "var(--newCommunityTheme-linkText)";
  53. link.style.textDecoration = "underline";
  54. newSpan.appendChild(link);
  55. } else {
  56. newSpan.appendChild(document.createTextNode(el));
  57. }
  58. });
  59.  
  60. // Finally replace the original child
  61. node.parentNode.replaceChild(newSpan, node);
  62. }
  63. }
  64.  
  65. // Walk the DOM of the <body> handling all non-empty text nodes
  66. function findNodes() {
  67. //Create the TreeWalker
  68. let treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, {
  69. acceptNode: function(node) {
  70. if (node.textContent.length === 0 ||
  71. node.nodeName !== '#text' ||
  72. node.parentNode.nodeName == 'SCRIPT' ||
  73. node.parentNode.nodeName == 'STYLE' ||
  74. node.parentNode.nodeName == 'NOSCRIPT' ||
  75. node.parentNode.className == 'sauced' ||
  76. node.parentNode.closest('a') != null ||
  77. node.parentNode.closest('[role="textbox"]') != null
  78. ) {
  79. return NodeFilter.FILTER_SKIP; //Skip empty text nodes
  80. } else {
  81. return NodeFilter.FILTER_ACCEPT;
  82. }
  83. }
  84. }, false);
  85.  
  86. let nodes = [];
  87.  
  88. // Push all nodes into a list as the DOMwalker becomes invalid after completion
  89. while (treeWalker.nextNode()) {
  90. nodes.push(treeWalker.currentNode);
  91. }
  92.  
  93. //Iterate over all text nodes, calling handleTextNode on each node in the list
  94. nodes.forEach(function(el) {
  95. handleNode(el);
  96. });
  97. }
  98. })();