Decode Hex strings on Voz

Decode Hex, Base64

当前为 2024-08-24 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Decode Hex strings on Voz
  3. // @namespace Decode Hex strings on Voz
  4. // @version 4.0
  5. // @icon https://www.google.com/s2/favicons?sz=64&domain=voz.vn
  6. // @author kylyte
  7. // @description Decode Hex, Base64
  8. // @match https://voz.vn/t/*
  9. // @run-at document-idle
  10. // @license GPL-3.0
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. function decodeHex(hexString) {
  17. hexString = hexString.replace(/\s+/g, '');
  18. if (!/^[0-9A-Fa-f]{2,}$/.test(hexString)) return hexString;
  19. let hexStr = '';
  20. try {
  21. for (let i = 0; i < hexString.length; i += 2) {
  22. hexStr += String.fromCharCode(parseInt(hexString.substr(i, 2), 16));
  23. }
  24. if (/^[\x20-\x7E]*$/.test(hexStr) && hexStr.length > 3) {
  25. return hexStr;
  26. } else {
  27. return hexString;
  28. }
  29. } catch {
  30. return hexString;
  31. }
  32. }
  33.  
  34. function decodeBase64(base64String) {
  35. if (!/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/.test(base64String)) return base64String;
  36. try {
  37. let binaryString = atob(base64String);
  38. if (/^[\x20-\x7E]*$/.test(binaryString) && binaryString.length > 3) {
  39. return binaryString;
  40. } else {
  41. return base64String;
  42. }
  43. } catch {
  44. return base64String;
  45. }
  46. }
  47.  
  48. function createClickableLink(url) {
  49. return `<a href="${url}" target="_blank" class="link link--external" rel="nofollow ugc noopener">${url}</a>`;
  50. }
  51.  
  52. function decodeContent(elements, regex, decodeFunc) {
  53. elements.forEach(element => {
  54. const excludedSelectors = [
  55. '.fr-box.bbWrapper.fr-ltr.fr-basic.fr-top',
  56. '.tooltip.tooltip--basic',
  57. '.bbImage',
  58. '.bbMediaJustifier',
  59. '.link'
  60. ];
  61. if (excludedSelectors.some(selector => element.closest(selector))) return;
  62. let walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);
  63. let textNode;
  64. let replacementNodes = [];
  65. while (textNode = walker.nextNode()) {
  66. let content = textNode.nodeValue;
  67. let matches = content.match(regex);
  68. if (matches) {
  69. let newContent = content;
  70. matches.forEach(match => {
  71. let decoded = decodeFunc(match);
  72. if (decoded.startsWith('https://')) {
  73. newContent = newContent.replace(new RegExp(escapeRegExp(match), 'g'), createClickableLink(decoded));
  74. } else {
  75. newContent = newContent.replace(new RegExp(escapeRegExp(match), 'g'), decoded);
  76. }
  77. });
  78. replacementNodes.push({node: textNode, newContent});
  79. }
  80. }
  81. replacementNodes.forEach(({node, newContent}) => {
  82. const tempDiv = document.createElement('div');
  83. tempDiv.innerHTML = newContent;
  84. node.parentNode.replaceChild(tempDiv, node);
  85. });
  86. });
  87. }
  88.  
  89. function escapeRegExp(string) {
  90. return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  91. }
  92.  
  93. function main() {
  94. let elements = document.querySelectorAll('.bbWrapper');
  95. decodeContent(elements, /\b([0-9A-Fa-f]{2}\s*){4,}\b/g, decodeHex);
  96. decodeContent(elements, /(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})/g, decodeBase64);
  97. }
  98.  
  99. main();
  100. })();