Clean URL Query

Trim tracking query params from URL

As of 2024-08-12. See the latest version.

  1. // ==UserScript==
  2. // @name Clean URL Query
  3. // @namespace https://github.com/leesei/userscripts
  4. // @version 1.3.4
  5. // @description Trim tracking query params from URL
  6. // @author leesei@gmail.com
  7. // @license MIT
  8. // @supportURL https://github.com/leesei/userscripts/issues
  9. // @match http*://detail.tmall.com/item.htm*
  10. // @match http*://*.tmall.com/shop/view_shop.htm
  11. // @match http*://item.taobao.com/item.htm*
  12. // @match http*://*.taobao.com/shop/view_shop.htm
  13. // @match http*://*.carousell.com/p/*
  14. // @match http*://*.computerworld.com/*
  15. // @match http*://*.networkworld.com/*
  16. // @match http*://*.infoworld.com/*
  17. // @match http*://*.itprotoday.com/*
  18. // @match http*://*.makeuseof.com/*
  19. // @run-at document-start
  20. // @grant GM_log
  21. // @grant GM_info
  22. // @noframes
  23. // ==/UserScript==
  24.  
  25. function log(level, text) {
  26. GM_log(level + ": " + text);
  27. }
  28.  
  29. function query2json(querystring) {
  30. // remove any preceding url and split
  31. const queries = querystring
  32. .substring(querystring.indexOf("?") + 1)
  33. .split("&");
  34. const params = {},
  35. d = decodeURIComponent;
  36. // match and parse
  37. for (let i = queries.length - 1; i >= 0; i--) {
  38. if (queries[i].length === 0) continue;
  39. const pair = queries[i].split("=");
  40. params[d(pair[0])] = d(pair[1]);
  41. }
  42.  
  43. return params;
  44. }
  45.  
  46. function json2query(json) {
  47. const query = Object.keys(json)
  48. .map(function (key) {
  49. return encodeURIComponent(key) + "=" + encodeURIComponent(json[key]);
  50. })
  51. .join("&");
  52.  
  53. return query ? "?" + query : "";
  54. }
  55.  
  56. // Convert sensible strings to Boolean, useful for parsing URL queries
  57. function string2Boolean(string, defaultTrue) {
  58. // console.log('2bool:', String(string).toLowerCase());
  59. switch (String(string).toLowerCase()) {
  60. case "":
  61. return defaultTrue === undefined ? false : defaultTrue;
  62. case "true":
  63. case "1":
  64. case "yes":
  65. case "y":
  66. return true;
  67. case "false":
  68. case "0":
  69. case "no":
  70. case "n":
  71. return false;
  72. default:
  73. // you could throw an error, but 'undefined' seems a more logical value
  74. return undefined;
  75. }
  76. }
  77.  
  78. (function () {
  79. "use strict";
  80.  
  81. log(
  82. "info",
  83. ">>> [" + GM_info.script.namespace + "] " + GM_info.script.name + " <<<"
  84. );
  85.  
  86. const queries = query2json(location.search);
  87. log("debug", "queries: " + JSON.stringify(queries));
  88.  
  89. if (
  90. queries._skip_clean !== undefined &&
  91. string2Boolean(queries._skip_clean)
  92. ) {
  93. return;
  94. }
  95.  
  96. // retain these query params
  97. const WHITE_LIST = [
  98. "id", // for taobao items
  99. "page", // for article pages
  100. ];
  101. const copy = Object.assign({}, queries);
  102. WHITE_LIST.forEach((key) => delete copy[key]);
  103. log("debug", "copy: " + JSON.stringify(copy));
  104.  
  105. // remove non-whitelisted queries
  106. if (Object.keys(copy).length) {
  107. const _q = {};
  108. WHITE_LIST.forEach((key) => {
  109. if (queries[key]) _q[key] = queries[key];
  110. });
  111. log("debug", "_q: " + JSON.stringify(_q));
  112. location.replace(location.pathname + json2query(_q));
  113. }
  114. })();