Greasy Fork is available in English.

Share Links Without Tracking

To remove tracking parameters in links of sharing

  1. // ==UserScript==
  2. // @name Share Links Without Tracking
  3. // @namespace UserScripts
  4. // @match https://*/*
  5. // @match http://*/*
  6. // @version 0.1.3
  7. // @author CY Fung
  8. // @license MIT
  9. // @description To remove tracking parameters in links of sharing
  10. // @run-at document-start
  11. // @allFrames true
  12. // @inject-into page
  13. // ==/UserScript==
  14.  
  15. (function () {
  16. 'use strict';
  17. const win = typeof unsafeWindow === 'object' ? unsafeWindow : this;
  18. const { navigator, Clipboard, DataTransfer, document } = win;
  19.  
  20. function fixByTextContent(textNode) {
  21.  
  22. let t = textNode.textContent;
  23.  
  24. let d = fixByText(t);
  25. if (d && d !== t) textNode.textContent = d;
  26. }
  27.  
  28. function fixByText(t) {
  29.  
  30.  
  31. if (!t) return;
  32. if (!t.includes('http')) return;
  33. let withQ = t.includes('?');
  34. let m;
  35. if (withQ && (m = /^(https?\:\/\/(twitter|x)\.com\/[^\/]+\/status\/[\d]+)\?\w+/.exec(t))) {
  36. return m[1];
  37. }
  38. if (withQ) {
  39. m = /https?\:\/\/[^\s\?\&]+\w(\?[^\s]+)?/.exec(t);
  40. let u = m ? t.indexOf(m[0]) : -1;
  41. let v = m ? t.lastIndexOf(m[0]) : -1;
  42. if (m && v >= 0 && v === u) {
  43.  
  44. let p = null;
  45. try {
  46.  
  47. p = new URL(m[0]);
  48. } catch (e) {
  49.  
  50. }
  51.  
  52. if (p) {
  53. // console.log(p)
  54. let searchParams = p.searchParams;
  55. if (searchParams) {
  56. if (searchParams.has('utm_source') && searchParams.has('utm_medium')) {
  57. // tvb
  58. searchParams.delete('utm_source');
  59. searchParams.delete('utm_medium');
  60. }
  61. searchParams.delete('utm_campaign');
  62. searchParams.delete('utm_term');
  63. searchParams.delete('utm_content');
  64. searchParams.delete('gclid');
  65. searchParams.delete('dclid');
  66. searchParams.delete('fbclid');
  67.  
  68. for (const entry of [...searchParams]) {
  69. const [k, v] = entry;
  70. if (v && typeof v === 'string' && v.includes('refer')) searchParams.delete(k);
  71. }
  72.  
  73. }
  74.  
  75. let pathname1 = p.pathname;
  76. let pathname2 = null;
  77. if (typeof pathname1 === 'string' && pathname1.includes('%')) {
  78. let w = null;
  79. try {
  80. w = decodeURI(pathname1);
  81. } catch (e) { }
  82. if (w && typeof w === 'string' && w.length < pathname1.length) {
  83.  
  84. let w2 = w;
  85. let p2 = pathname1;
  86. w2 = w2.replace(/[\u3400-\uFFFF]+/g, (_) => {
  87. p2 = p2.replace(encodeURI(_));
  88. });
  89. if (w2 === p2) {
  90. pathname2 = w;
  91. }
  92. }
  93. }
  94.  
  95. t = t.replace(m[0], p + "");
  96. if (pathname2) t = t.replace(pathname1, pathname2);
  97. }
  98.  
  99. }
  100.  
  101. return t;
  102. }
  103. }
  104.  
  105. document.execCommand94 = document.execCommand;
  106. document.execCommand = function () {
  107. if (arguments[0] === 'copy') {
  108.  
  109. try {
  110.  
  111. const { anchorNode, focusNode } = window.getSelection();
  112. // console.log(anchorNode, focusNode)
  113. if (anchorNode && anchorNode === focusNode) {
  114. if (anchorNode.firstElementChild === null && anchorNode.firstChild === anchorNode.lastChild) {
  115. fixByTextContent(anchorNode.firstChild)
  116. } else {
  117. let tc1 = anchorNode.textContent;
  118. let em2 = anchorNode.querySelector('textarea');
  119. let tc2 = em2 ? em2.textContent : null;
  120. if (tc1 === tc2 && tc1 && em2.firstElementChild === null && em2.firstChild === em2.lastChild) {
  121. fixByTextContent(em2.firstChild)
  122.  
  123. }
  124. }
  125. }
  126. // let content = range.extractContents(); // Extract content from document
  127.  
  128.  
  129. let selection = window.getSelection();
  130.  
  131. if (selection.rangeCount > 0) {
  132. let ranges = [];
  133.  
  134. for (let i = 0; i < selection.rangeCount; i++) {
  135. let range = selection.getRangeAt(i);
  136. ranges.push(range);
  137. }
  138.  
  139. // Now the "ranges" array contains all the ranges of the selection.
  140. // console.log(ranges);
  141.  
  142. if (ranges.length === 1 && ranges[0].collapsed === true && document.activeElement && (document.activeElement.nodeName === "TEXTAREA" || document.activeElement.nodeName === "INPUT")) {
  143.  
  144.  
  145. let textValue = document.activeElement.value;
  146. if (typeof textValue === 'string') {
  147.  
  148.  
  149.  
  150. // let range = selection.getRangeAt(0); // Get the first range (assuming a single range for simplicity)
  151.  
  152. // let content = range.extractContents(); // Extract content from document
  153.  
  154. let strong = document.createElement(document.activeElement.nodeName); // Create a new <strong> element
  155. let u = fixByText(textValue);
  156.  
  157. strong.value = u ? u : textValue
  158.  
  159. let range = selection.getRangeAt(0); // Get the first range (assuming a single range for simplicity)
  160.  
  161. // let content = range.extractContents(); // Extract content from document
  162.  
  163. // let strong = document.createElement("strong"); // Create a new <strong> element
  164. // strong.appendChild(content); // Append the extracted content inside the <strong> element
  165.  
  166. range.insertNode(strong); // Insert the <strong> element back into the document
  167.  
  168. // If you want the new content to be selected
  169. selection.removeAllRanges(); // Remove existing selection
  170. range.selectNodeContents(strong); // Select the new content
  171. selection.addRange(range); // Add the modified range back to the selection
  172.  
  173. strong.select();
  174. Promise.resolve().then(() => strong.remove())
  175.  
  176.  
  177.  
  178. }
  179.  
  180.  
  181. }
  182.  
  183. }
  184.  
  185. // console.log(555, window.getSelection() + "")
  186.  
  187. } catch (e) {
  188. console.warn(e);
  189. }
  190.  
  191. }
  192. // console.log('execCommand', [...arguments])
  193.  
  194. return this.execCommand94.apply(this, arguments)
  195. }
  196.  
  197.  
  198. Clipboard.prototype.writeText94 = Clipboard.prototype.writeText;
  199. Clipboard.prototype.writeText = function () {
  200. if (typeof arguments[0] === 'string') {
  201. let q = fixByText(arguments[0])
  202. if (q && q !== arguments[0]) arguments[0] = q;
  203. }
  204.  
  205. // console.log('writeText', [...arguments])
  206. return this.writeText94.apply(this, arguments)
  207.  
  208. }
  209.  
  210.  
  211. // console.log(12355, win)
  212. })();