spm_Track_Block_Tool

移除链接中的spm跟踪参数

当前为 2022-05-01 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name spm_Track_Block_Tool
  3. // @namespace _s7util__
  4. // @version 0.5.6
  5. // @description:en Remove [spm] track paramter in URL
  6. // @description 移除链接中的spm跟踪参数
  7. // @author shc0743
  8. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  9. // @grant none
  10. // @license GPL-3.0
  11. // @supportURL https://github.com/shc0743/MyUtility/issues/new
  12. // @run-at document-start
  13. // @match http*://*.bilibili.com/*
  14. // @match http*://*.baidu.com/*
  15. // @match http*://*.cctv.com/*
  16. // @match http*://*.taobao.com/*
  17. // @match http*://*.alibaba.com/*
  18. // @exclude http*://*.paypal.com/*
  19. // @exclude http*://*.alipay.com/*
  20. // ==/UserScript==
  21.  
  22. /*
  23. Description:
  24. 说明:
  25. This user script removes the spm paramter in <a href> elements.
  26. 此脚本移除 <a href> 元素中的spm参数。
  27. If it doesn't work, try refreshing it a few times or wait a while.
  28. 若无法生效,请尝试刷新几次或等一会。
  29. Examples:
  30. 示例:
  31. https://www.bilibili.com/video/av170001?spm_id_from=114514
  32. -> https://www.bilibili.com/video/av170001
  33. https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514&query2=data3
  34. -> https://www.bilibili.com/video/av170001?query1=arg2&query2=data3
  35. https://www.bilibili.com/video/av170001?spm=114514.1919810#hash
  36. -> https://www.bilibili.com/video/av170001#hash
  37. https://www.bilibili.com/video/av170001?spm=114514.1919810&query2=data3#hash1
  38. -> https://www.bilibili.com/video/av170001?query2=data3#hash1
  39. */
  40.  
  41. (function () {
  42. 'use strict';
  43.  
  44. // Your code here...
  45.  
  46. var track_args_list = [
  47. { 'domain': '*', 'keyword': 'spm' },
  48. { 'domain': '*', 'keyword': 'spm_id_from' },
  49. { 'domain': '*', 'keyword': 'from_source' },
  50. { 'domain': 'bilibili.com', 'keyword': 'from' },
  51. { 'domain': 'bilibili.com', 'keyword': 'seid' },
  52. { 'domain': 'baike.baidu.com', 'keyword': 'fr' },
  53. { 'domain': 'alibaba.com', 'keyword': 'tracelog' },
  54. ];
  55.  
  56. return (function (global) {
  57.  
  58. //var expr = /\?[\s\S]*spm/i;
  59.  
  60. /**
  61. * 去除字符串中的spm参数
  62. * @param {String} str URL to remove spm
  63. * @returns 去除spm后的结果
  64. */
  65. var remove_spm = function (str) {
  66. if (typeof (str) != 'string') return str;
  67. var newstr = '';
  68. var len = str.length;
  69. // 只去除查询参数部分,避免正常url被替换而导致404
  70. var hash_part_begin = str.indexOf('#');
  71. var query_part_begin = str.indexOf('?');
  72. if (query_part_begin == -1 ||
  73. (hash_part_begin != -1 && query_part_begin > hash_part_begin))
  74. { return str; } // 没有查询参数或?在#后面,直接返回
  75. newstr = str.substring(0, query_part_begin);
  76. var domain = '';
  77. {
  78. let index = str.indexOf('://');
  79. if (index + 1) {
  80. index = str.indexOf('/', index + 3);
  81. if (index + 1) {
  82. domain = str.substring(0, index);
  83. }
  84. }
  85. }
  86.  
  87. for (let i = query_part_begin, need_break; i < len; ++i) {
  88. for (let j = 0; j < track_args_list.length; ++j) {
  89. if (!(track_args_list[j].domain == '*' ||
  90. domain.indexOf(track_args_list[j].domain) != -1)) {
  91. need_break = false;
  92. break;
  93. }
  94. need_break = true;
  95. if (track_args_list[j].keyword == str.substring(i,
  96. i + track_args_list[j].keyword.length - 0)) {
  97. // 检测到
  98. while ((++i) < len) {
  99. if (str[i] == '&') { // 不能单独保留一个 & 号
  100. i++;
  101. break; // 去掉
  102. }
  103. if (str[i] == '#') break; // 保留hash部分
  104. }
  105. if (i == len) break; // 越界,直接break,以免url出现undefined
  106. }
  107. need_break = false;
  108. }
  109. if (need_break) break;
  110. newstr += str[i];
  111. }
  112.  
  113. var _lastchar;
  114. for (let i = 0; i < newstr.length; ++i) {
  115. _lastchar = newstr[newstr.length - 1];
  116. if (_lastchar == '?' || _lastchar == '&') { // 如果移除后只剩下 ? 或 &
  117. newstr = newstr.substring(0, newstr.length - 1); // 去掉
  118. } else break;
  119. }
  120. // Bug-Fix:
  121. // https://example.com/example?q1=arg&spm=123#hash1
  122. // -> https://example.com/example?q1=arg&#hash1
  123. // Invalid URL syntax at ^^
  124. newstr = newstr.replace(/\&\#/igm, '#');
  125. newstr = newstr.replace(/\?\#/igm, '#');
  126. return newstr;
  127. }
  128. var test_spm = function (str) {
  129. for (let tracker of track_args_list)
  130. if (new RegExp(tracker, 'i').test(str))
  131. return true;
  132. return false;
  133. };
  134. var _realwindowopen = window.open;
  135. var _realhistorypushState = window.history.pushState;
  136. var _realhistoryreplaceState = window.history.replaceState;
  137.  
  138. var _link_click = function (event) {
  139. if (!(/http/i.test(this.href))) return;
  140. event.preventDefault();
  141. // 防止被再次加入spm
  142. this.href = remove_spm(this.href);
  143. _realwindowopen(this.href, this.target || '_self');
  144. return false;
  145. };
  146. var _link_mouseover = function () {
  147. if (test_spm(this.href))
  148. this.href = remove_spm(this.href);
  149. };
  150. var linkclickhandlerinit = function () {
  151. var el = document.querySelectorAll('a[href]');
  152. for (let i = el.length - 1; i >= 0; --i) {
  153. if (test_spm(el[i].href)) {
  154. // 链接已经被加入spm , 需要移除
  155. el[i].href = remove_spm(el[i].href);
  156. }
  157. el[i].removeEventListener('click', _link_click);
  158. el[i].addEventListener('click', _link_click, true);
  159. el[i].removeEventListener('mouseover', _link_mouseover);
  160. el[i].addEventListener('mouseover', _link_mouseover, false);
  161. }
  162. };
  163. {
  164. try {
  165. let wopen = function (url, target, features) {
  166. return _realwindowopen.call(window,
  167. remove_spm(url),
  168. target,
  169. features);
  170. };
  171. let hp = function (data, title, url) {
  172. return _realhistorypushState.call(
  173. window.history, data, title,
  174. remove_spm(url));
  175. };
  176. let hr = function (data, title, url) {
  177. return _realhistoryreplaceState.call(
  178. window.history, data, title,
  179. remove_spm(url));
  180. };
  181. wopen.toString =
  182. hp.toString =
  183. hr.toString =
  184. function () {
  185. return `function () {\n [native code]\n}`
  186. };
  187. // 必须定义成 writable 否则一些网站(例如B站收藏夹页面)会出错
  188. Object.defineProperty(window, 'open', {
  189. value: wopen,
  190. writable: true,
  191. enumerable: true,
  192. configurable: true
  193. }); // 重定义window.open 以阻止弹出窗口中的spm
  194. Object.defineProperty(window.history, 'pushState', {
  195. value: hp,
  196. writable: true,
  197. enumerable: true,
  198. configurable: true
  199. }); // 重定义history.pushState
  200. Object.defineProperty(window.history, 'replaceState', {
  201. value: hr,
  202. writable: true,
  203. enumerable: true,
  204. configurable: true
  205. }); // 重定义history.replaceState
  206. }
  207. catch (error) {
  208. console.warn("This browser doesn't support redefining" +
  209. " window.open , so [SpmBlockTool] cannot remove" +
  210. " spm in popup window.\nError:", error);
  211. }
  212. }
  213. window.addEventListener('load', function (event) {
  214. window.setInterval(linkclickhandlerinit, 5000);
  215. window.setTimeout(linkclickhandlerinit, 1000);
  216. window.setTimeout(linkclickhandlerinit, 500);
  217. window.setTimeout(linkclickhandlerinit, 1);
  218. });
  219.  
  220. // 移除当前页面的spm
  221. // 当然,实际上spm已经在userscript加载前被发送到服务器,
  222. // 所以该功能仅美化url.
  223. // 如果要禁用该功能,删除下面一行开头的斜杠。
  224. //if(0)
  225. // Remove spm from current page
  226. // Of course, in fact, spm has been sent to the server
  227. // before userscript is loaded, so this function only beautifies the URL.
  228. // If you want to disable this feature, remove the slash
  229. // at the beginning of the following line:
  230. //if(0)
  231. if (test_spm(location.href)) {
  232. _realhistoryreplaceState.call(window.history,
  233. {}, document.title,
  234. remove_spm(location.href));
  235. }
  236.  
  237. /*
  238. var test_urls = [
  239. 'https://www.bilibili.com/video/BV18X4y1N7Yh',
  240. 'https://www.bilibili.com/video/BV18X4y1N7Yh?spm_id_from=114514',
  241. 'https://www.bilibili.com/video/BV18X4y1N7Yh?spm=114514.1919810',
  242. 'https://www.bilibili.com/video/BV18X4y1N7Yh?spm_id_from=114514.123',
  243.  
  244. 'https://www.bilibili.com/video/av170001',
  245. 'https://www.bilibili.com/video/av170001?spm_id_from=114514',
  246. 'https://www.bilibili.com/video/av170001?spm=114514.1919810',
  247. 'https://www.bilibili.com/video/av170001?spm_id_from=114514.123',
  248.  
  249. 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514',
  250. 'https://www.bilibili.com/video/av170001?query1=arg2&spm=114514.1919810',
  251. 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514.123',
  252. 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514',
  253. 'https://www.bilibili.com/video/av170001?query1=arg2&spm=114514.1919810',
  254. 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514.123',
  255.  
  256. 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514&query2=data3',
  257. 'https://www.bilibili.com/video/av170001?query1=arg2&spm=114514.1919810&query2=data3',
  258.  
  259. 'https://www.bilibili.com/video/av170001?spm_id_from=114514#hash',
  260. 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514#hash1',
  261. 'https://www.bilibili.com/video/av170001?query1=arg2&spm=114514.1919810#hash1',
  262.  
  263. 'https://www.bilibili.com/video/av170001?spm_id_from=114514&query2=data3#hash1',
  264. 'https://www.bilibili.com/video/av170001?spm=114514.1919810&query2=data3#hash1',
  265. ];
  266. for(let i=0;i<test_urls.length;++i){
  267. let el=document.createElement('a');
  268. el.href=test_urls[i];
  269. el.innerHTML=i+1 + '';
  270. document.documentElement.appendChild(el);
  271. }
  272. for(let i=0;i<test_urls.length;++i){
  273. let el=document.createElement('a');
  274. el.href=test_urls[i];
  275. el.innerHTML=i+1 + ' blank';
  276. el.target='_blank';
  277. document.documentElement.appendChild(el);
  278. }
  279. */
  280.  
  281. })(window);
  282.  
  283. })();