Facebook HEX

Convert HEX to text, in a post or comment on Facebook.

  1. // ==UserScript==
  2. // @name Facebook HEX
  3. // @name:vi Facebook HEX
  4. // @namespace https://lelinhtinh.github.io
  5. // @description Convert HEX to text, in a post or comment on Facebook.
  6. // @description:vi Chuyển đổi HEX thành URL hoặc text, trong bài viết hoặc bình luận trên Facebook.
  7. // @version 1.0.0
  8. // @icon https://i.imgur.com/oz5CjJe.png
  9. // @author lelinhtinh
  10. // @oujs:author baivong
  11. // @license MIT; https://baivong.mit-license.org/license.txt
  12. // @match https://*.facebook.com/*
  13. // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js?v=a834d46
  14. // @noframes
  15. // @supportURL https://github.com/lelinhtinh/Userscript/issues
  16. // @run-at document-idle
  17. // @grant GM.openInTab
  18. // @grant GM_openInTab
  19. // ==/UserScript==
  20.  
  21. /**
  22. * If `false`, open in new tab after clicking on decoded link.
  23. * @type {boolean} true or false
  24. */
  25. const COPY_ONLY = false;
  26.  
  27. /**
  28. * Makes the tab being opened inside a incognito mode/private mode window.
  29. * Currently, only works with Tampermonkey BETA.
  30. * @type {boolean} true or false
  31. */
  32. const PRIVATE = true;
  33.  
  34. /* === DO NOT CHANGE === */
  35. function fallbackCopyTextToClipboard(text) {
  36. let textArea = document.createElement('textarea');
  37. textArea.value = text;
  38.  
  39. textArea.style.top = '0';
  40. textArea.style.left = '0';
  41. textArea.style.position = 'fixed';
  42.  
  43. document.body.appendChild(textArea);
  44. textArea.focus();
  45. textArea.select();
  46.  
  47. try {
  48. document.execCommand('copy');
  49. } catch (err) {
  50. console.error('Fallback: Oops, unable to copy', err);
  51. }
  52.  
  53. document.body.removeChild(textArea);
  54. }
  55.  
  56. function copyTextToClipboard(text) {
  57. if (!navigator.clipboard) {
  58. fallbackCopyTextToClipboard(text);
  59. return;
  60. }
  61.  
  62. navigator.clipboard.writeText(text).catch((err) => {
  63. console.error('Async: Could not copy text', err);
  64. });
  65. }
  66.  
  67. function validURL(url) {
  68. try {
  69. const uri = new URL(url);
  70. return !!uri.host && uri.host.includes('.');
  71. } catch (e) {
  72. return false;
  73. }
  74. }
  75.  
  76. function cleanWordBreak(post) {
  77. if (post.querySelector('.word_break') !== null) {
  78. post.querySelectorAll('wbr').forEach((e) => e.remove());
  79.  
  80. post.querySelectorAll('span').forEach((span) => {
  81. if (span.querySelector('span, img') !== null) return;
  82. const text = document.createTextNode(span.textContent);
  83. span.parentNode.replaceChild(text, span);
  84. });
  85. }
  86. }
  87.  
  88. function renderResult(post, data) {
  89. const { content, result } = data;
  90. if (!content || !result) return;
  91.  
  92. copyTextToClipboard(result);
  93.  
  94. post.innerHTML = post.innerHTML.replace(
  95. content,
  96. `
  97. <strong
  98. class="fb-hex${validURL(result) ? ' fb-hex-link' : ''}"
  99. title="Copied to clipboard${COPY_ONLY ? '' : '\nClick to open in new tab'}"
  100. style="cursor:pointer"
  101. >${result}</strong>
  102. `,
  103. );
  104. }
  105.  
  106. function handle(post) {
  107. if (post.querySelector('.fb-hex') !== null) return;
  108. cleanWordBreak(post);
  109.  
  110. const handleURL = URL.createObjectURL(
  111. new Blob(
  112. [
  113. '(',
  114. function () {
  115. self.onmessage = (e) => {
  116. function hex2ascii(hex) {
  117. if (!(typeof hex === 'number' || typeof hex == 'string')) return '';
  118.  
  119. hex = hex.toString().replace(/\s+/gi, '');
  120. const stack = [];
  121.  
  122. for (let i = 0; i < hex.length; i += 2) {
  123. const code = parseInt(hex.substr(i, 2), 16);
  124. if (!isNaN(code) && code !== 0) {
  125. stack.push(String.fromCharCode(code));
  126. }
  127. }
  128.  
  129. return stack.join('');
  130. }
  131.  
  132. function getResult(content) {
  133. content = content.match(/\b[a-f0-9\s]{12,}\b/i);
  134. if (content === null) return {};
  135.  
  136. content = content[0].trim();
  137. const result = hex2ascii(content);
  138.  
  139. return { content, result };
  140. }
  141.  
  142. self.postMessage(getResult(e.data));
  143. };
  144. }.toString(),
  145. ')()',
  146. ],
  147. {
  148. type: 'application/javascript',
  149. },
  150. ),
  151. );
  152. const worker = new Worker(handleURL);
  153.  
  154. worker.onmessage = (e) => {
  155. if (!e.data) return;
  156. renderResult(post, e.data);
  157. };
  158. worker.postMessage(post.textContent);
  159. }
  160.  
  161. function getPost(e) {
  162. const target = e.target;
  163.  
  164. if (target.getAttribute('role') === 'button') return;
  165. const role = target.closest('[role]');
  166. if (role.getAttribute('role') !== 'article') return;
  167.  
  168. const post = target.closest('p, span, [dir="auto"], [data-ft] > div[style]');
  169. if (post === null) return;
  170.  
  171. const parent = post.parentNode;
  172. if (parent.querySelector('.word_break') !== null) {
  173. handle(parent);
  174. return;
  175. }
  176.  
  177. handle(post);
  178. }
  179.  
  180. document.addEventListener('click', getPost);
  181.  
  182. function decodedClicking(e) {
  183. const target = e.target;
  184. if (!target.classList.contains('fb-hex')) return;
  185.  
  186. const result = target.textContent;
  187. copyTextToClipboard(result);
  188.  
  189. if (COPY_ONLY) return;
  190. if (!target.classList.contains('fb-hex-link')) return;
  191.  
  192. GM.openInTab(result, {
  193. active: true,
  194. insert: true,
  195. incognito: PRIVATE,
  196. });
  197. }
  198.  
  199. document.addEventListener('click', decodedClicking);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址