lib:textjack

3/5/2025, 7:16:43 PM

当前为 2025-03-12 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name lib:textjack
  3. // @version 4
  4. // @match *://*/*
  5. // @run-at document-start
  6. // @author rssaromeo
  7. // @license GPLv3
  8. // @include *
  9. // @grant none
  10. // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAMAAABiM0N1AAAAAXNSR0IB2cksfwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAHJQTFRFAAAAEIijAo2yAI60BYyuF4WaFIifAY6zBI2wB4usGIaZEYigIoiZCIyrE4igG4iYD4mjEomhFoedCoqpDIqnDomlBYyvE4efEYmiDYqlA42xBoytD4mkCYqqGYSUFYidC4qoC4upAo6yCoupDYqmCYur4zowOQAAACZ0Uk5TAO////9vr////1+/D/+/L+/Pf/////+f3///////H4////////+5G91rAAACgUlEQVR4nM2Y22KjIBCGidg1264liZqDadK03X3/V2wNKHMC7MpF/xthHD5mgERAqZhWhfYqH6K+Qf2qNNf625hCoFj9/gblMUi5q5jLkXLCKudgyiRm0FMK82cWJp1fLbV5VmvJbCIc0GCYaFqqlDJgADdBjncqAXYobm1xh72aFMflbysteFfdy2Yi1XGOm5HGBzQ1dq7TzEoxjeNTjQZb7VA3e1c7+ImgasAgQ9+xusNVNZIo5xmOMgihIS2PbCQIiHEUdTvhxCcS/kPomfFI2zHy2PkWmA6aNatIJpKFJyekyy02xh5Y3DI9T4aOT6VhIUrsNTFp1pf79Z4SIIVDegl6IJO6cHiL/GimIZDhgTu/BlYWCQzHMl0zBWT/T3KAhtxOuUB9FtBrpsz0RV4xsjHmW+UCaffcSy/5viMGer0/6HdFNMZBq/vjJL38H9Dqx4Fuy0Em12DbZy+9pGtiDijbglwAehyj11n0tRD3WUBm+lwulE/8h4BuA+iWAQQnteg2Xm63WQLTpnMnpjdge0Mgu/GRPsV4xdjQ94Lfi624fabhDkfUqIKNrM64Q837v8yL0prasepCgrtvw1sJpoqanGEX7b5mQboNW8eawXaWXTMfMGxub472hzWzHSn6Sg2G9+6TAyRruE71s+zAzjWaknoyJCQzwxrghH2k5FDT4eqWunuNxyN9QCGcxVod5oADbYnIUkDTGZEf1xDJnSFteQ3KdsT8zYDMQXcHxsevcLH1TrsABzkNPyA/L7b0jg704viMMlpQI96WsHknCt/3YH0kOEo9zcGkwrFK39ck72rmoehmKqo2RKlilzSy/nJKEV45CT38myJp456fezktHjN5aeMAAAAASUVORK5CYII=
  11. // @description 3/5/2025, 7:16:43 PM
  12. // @namespace https://greasyfork.org/users/1184528
  13. // ==/UserScript==
  14.  
  15. let obslist = []
  16. var textJackList = []
  17. Object.assign(window, console)
  18. const a = loadlib("allfuncs")
  19.  
  20. function replaceText(text) {
  21. var oldtext = text
  22. for (var cb of textJackList) {
  23. text = cb(text)
  24. if (text !== oldtext) {
  25. return (text = replaceText(text))
  26. }
  27. }
  28. return text
  29. }
  30. // Function to handle text changes
  31. function handleTextChange(mutations) {
  32. disableObservers()
  33. mutations.forEach((mutation) => {
  34. if (mutation.type === "childList") {
  35. mutation.addedNodes.forEach((node) => {
  36. if (node.nodeType === Node.TEXT_NODE) {
  37. // Filter text for text nodes
  38. var newtext = replaceText(node.textContent)
  39. if (node.textContent != newtext) {
  40. node.textContent = newtext
  41. // log(1, node.textContent , newtext)
  42. }
  43. } else if (node.nodeType === Node.ELEMENT_NODE) {
  44. // debugger
  45. // If it's an element, check its text content
  46. node.childNodes.forEach((child) => {
  47. if (child.nodeType === Node.TEXT_NODE) {
  48. var newtext = replaceText(child.textContent)
  49. if (child.textContent != newtext) {
  50. child.textContent = newtext
  51. // log(2, child.textContent , newtext)
  52. }
  53. }
  54. })
  55. // Observe any shadow roots
  56. if (node.shadowRoot) {
  57. createObserver(node.shadowRoot)
  58. }
  59. }
  60. })
  61. } else if (mutation.type === "characterData") {
  62. // Filter text for character data changes
  63. mutation.target.textContent = replaceText(
  64. mutation.target.textContent
  65. )
  66. }
  67. })
  68. enableObservers()
  69. }
  70.  
  71. // Create a MutationObserver for the main document
  72. function createObserver(elem) {
  73. var obs = new MutationObserver((mutations) => {
  74. handleTextChange(mutations)
  75. mutations.forEach((mutation) => {
  76. mutation.addedNodes.forEach((node) => {
  77. // If the added node is a shadow host, observe its shadow root
  78. if (node.nodeType === Node.ELEMENT_NODE && node.shadowRoot) {
  79. createObserver(node.shadowRoot)
  80. }
  81. })
  82. })
  83. })
  84.  
  85. // Start observing the document body
  86. obslist.push([
  87. obs,
  88. elem,
  89. {
  90. childList: true,
  91. subtree: true,
  92. characterData: true,
  93. },
  94. ])
  95. }
  96. // Function to enable all observers
  97. function enableObservers() {
  98. try {
  99. disableObservers()
  100. } catch (e) {}
  101. // warn(obslist, 1)
  102. obslist.forEach(([observer, target, opts]) =>
  103. observer.observe(target, opts)
  104. )
  105. }
  106.  
  107. // Function to disable all observers
  108. function disableObservers() {
  109. // warn(obslist, 0)
  110. obslist.forEach(([observer]) => observer.disconnect())
  111. }
  112.  
  113. // Optionally, filter existing text content on page load
  114. function filterExistingText(node) {
  115. disableObservers()
  116. if (node.nodeType === Node.TEXT_NODE) {
  117. node.textContent = replaceText(node.textContent)
  118. } else if (node.nodeType === Node.ELEMENT_NODE) {
  119. node.childNodes.forEach(filterExistingText)
  120. // If the element has a shadow root, filter its content
  121. if (node.shadowRoot) {
  122. filterExistingText(node.shadowRoot)
  123. }
  124. }
  125. enableObservers()
  126. }
  127.  
  128. // Filter existing text in the document
  129. var waitingForBody = false
  130. if (document.body) {
  131. setup()
  132. } else {
  133. waitingForBody = true
  134. }
  135.  
  136. loadlib("libloader").savelib("textjack", function newTextJack(cb) {
  137. textJackList.push(cb)
  138. if (document.body) {
  139. setup()
  140. } else {
  141. waitingForBody = true
  142. }
  143. })
  144. a.bodyload().then(() => {
  145. if (waitingForBody) {
  146. setup()
  147. }
  148. })
  149.  
  150. function setup() {
  151. filterExistingText(document.body)
  152. createObserver(document.body)
  153. enableObservers()
  154. }