spm_Track_Block_Tool

移除链接中的spm跟踪参数

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

  1. // ==UserScript==
  2. // @name spm_Track_Block_Tool
  3. // @namespace _s7util__
  4. // @version 0.5.9
  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.  
  26. This user script removes the spm paramter in <a href> elements.
  27. 此脚本移除 <a href> 元素中的spm参数。
  28.  
  29. If it doesn't work, try refreshing it a few times or wait a while.
  30. 若无法生效,请尝试刷新几次或等一会。
  31.  
  32. Examples:
  33. 示例:
  34.  
  35. https://www.bilibili.com/video/av170001?spm_id_from=114514
  36. -> https://www.bilibili.com/video/av170001
  37.  
  38. https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514&query2=data3
  39. -> https://www.bilibili.com/video/av170001?query1=arg2&query2=data3
  40.  
  41. https://www.bilibili.com/video/av170001?spm=114514.1919810#hash
  42. -> https://www.bilibili.com/video/av170001#hash
  43.  
  44. https://www.bilibili.com/video/av170001?spm=114514.1919810&query2=data3#hash1
  45. -> https://www.bilibili.com/video/av170001?query2=data3#hash1
  46. */
  47.  
  48. (function () {
  49. 'use strict';
  50.  
  51. // Your code here...
  52.  
  53. var track_args_list = [
  54. { 'domain': '*', 'keyword': 'spm' },
  55. { 'domain': '*', 'keyword': 'spm_id_from' },
  56. { 'domain': '*', 'keyword': 'from_source' },
  57. { 'domain': 'bilibili.com', 'keyword': 'from' },
  58. { 'domain': 'bilibili.com', 'keyword': 'seid' },
  59. { 'domain': 'baike.baidu.com', 'keyword': 'fr' },
  60. { 'domain': 'alibaba.com', 'keyword': 'tracelog' },
  61. ];
  62. var unwritable_list = [
  63. // https://gf.qytechs.cn/zh-CN/scripts/443049/discussions/132536
  64. { object: window, key: 'goldlog' },
  65. ];
  66. try {
  67. for (let i of unwritable_list) {
  68. Object.defineProperty(i.object, i.key, {
  69. get() { return undefined },
  70. set(value) { void (value) },
  71. enumerable: false,
  72. configurable: true
  73. });
  74. }
  75. }
  76. catch (error) {
  77. console.warn(error);
  78. }
  79.  
  80. return (function (global) {
  81.  
  82. //var expr = /\?[\s\S]*spm/i;
  83.  
  84. /**
  85. * 去除字符串中的spm参数
  86. * @param {String} str URL to remove spm
  87. * @returns 去除spm后的结果
  88. */
  89. var remove_spm = function (str) {
  90. if (typeof (str) != 'string') return str;
  91. var newstr = '';
  92. var len = str.length;
  93. // 只去除查询参数部分,避免正常url被替换而导致404
  94. var hash_part_begin = str.indexOf('#');
  95. var query_part_begin = str.indexOf('?');
  96. if (query_part_begin == -1 ||
  97. (hash_part_begin != -1 && query_part_begin > hash_part_begin))
  98. { return str; } // 没有查询参数或?在#后面,直接返回
  99. newstr = str.substring(0, query_part_begin);
  100. var domain = '';
  101. {
  102. let index = str.indexOf('://');
  103. if (index + 1) {
  104. index = str.indexOf('/', index + 3);
  105. if (index + 1) {
  106. domain = str.substring(0, index);
  107. }
  108. }
  109. }
  110.  
  111. for (let i = query_part_begin, need_break; i < len; ++i) {
  112. for (let j = 0; j < track_args_list.length; ++j) {
  113. if (!(track_args_list[j].domain == '*' ||
  114. domain.indexOf(track_args_list[j].domain) != -1)) {
  115. need_break = false;
  116. break;
  117. }
  118. need_break = true;
  119. if (track_args_list[j].keyword == str.substring(i,
  120. i + track_args_list[j].keyword.length - 0)) {
  121. // 检测到
  122. while ((++i) < len) {
  123. if (str[i] == '&') { // 不能单独保留一个 & 号
  124. i++;
  125. break; // 去掉
  126. }
  127. if (str[i] == '#') break; // 保留hash部分
  128. }
  129. if (i == len) break; // 越界,直接break,以免url出现undefined
  130. }
  131. need_break = false;
  132. }
  133. if (need_break) break;
  134. newstr += str[i];
  135. }
  136.  
  137. var _lastchar;
  138. for (let i = 0; i < newstr.length; ++i) {
  139. _lastchar = newstr[newstr.length - 1];
  140. if (_lastchar == '?' || _lastchar == '&') { // 如果移除后只剩下 ? 或 &
  141. newstr = newstr.substring(0, newstr.length - 1); // 去掉
  142. } else break;
  143. }
  144. // Bug-Fix:
  145. // https://example.com/example?q1=arg&spm=123#hash1
  146. // -> https://example.com/example?q1=arg&#hash1
  147. // Invalid URL syntax at ^^
  148. newstr = newstr.replace(/\&\#/igm, '#');
  149. newstr = newstr.replace(/\?\#/igm, '#');
  150. return newstr;
  151. }
  152. var test_spm = function (str) {
  153. for (let tracker of track_args_list) {
  154. if (new RegExp(tracker, 'i').test(str)) {
  155. return true;
  156. }
  157. }
  158. return false;
  159. };
  160. var _realwindowopen = window.open;
  161. var _realhistorypushState = window.history.pushState;
  162. var _realhistoryreplaceState = window.history.replaceState;
  163.  
  164. /*var _link_click_test = function (val) {
  165. if (/\#/.test(val)) return true;
  166. if (/javascript\:/i.test(val)) return true;
  167. return false;
  168. };
  169. var _link_click = function (event) {
  170. if (_link_click_test(this.href)) return;
  171. event.preventDefault();
  172. // 防止被再次加入spm
  173. this.href = remove_spm(this.href);
  174. _realwindowopen(this.href, this.target || '_self');
  175. return false;
  176. };*/
  177. var _link_mouseover = function () {
  178. if (test_spm(this.href)) this.href = remove_spm(this.href);
  179. };
  180. var link_clean_worker = function (el) {
  181. if (test_spm(el.href)) {
  182. // 链接已经被加入spm , 需要移除
  183. el.href = remove_spm(el.href);
  184. }
  185. }
  186. var linkclickhandlerinit = function () {
  187. var el = document.querySelectorAll('a[href]');
  188. for (let i = el.length - 1; i >= 0; --i) {
  189. link_clean_worker(el[i]);
  190. }
  191. };
  192.  
  193. try {
  194. let wopen = function (url, target, features) {
  195. return _realwindowopen.call(window,
  196. remove_spm(url),
  197. target,
  198. features);
  199. };
  200. let hp = function (data, title, url) {
  201. return _realhistorypushState.call(
  202. window.history, data, title,
  203. remove_spm(url));
  204. };
  205. let hr = function (data, title, url) {
  206. return _realhistoryreplaceState.call(
  207. window.history, data, title,
  208. remove_spm(url));
  209. };
  210. wopen.toString =
  211. hp.toString =
  212. hr.toString =
  213. new Function("return 'function () {\\n [native code]\\n}'");
  214. // 必须定义成 writable 否则一些网站(例如B站收藏夹页面)会出错
  215. Object.defineProperty(window, 'open', {
  216. value: wopen,
  217. writable: true,
  218. enumerable: true,
  219. configurable: true
  220. }); // 重定义window.open 以阻止弹出窗口中的spm
  221. Object.defineProperty(window.history, 'pushState', {
  222. value: hp,
  223. writable: true,
  224. enumerable: true,
  225. configurable: true
  226. }); // 重定义history.pushState
  227. Object.defineProperty(window.history, 'replaceState', {
  228. value: hr,
  229. writable: true,
  230. enumerable: true,
  231. configurable: true
  232. }); // 重定义history.replaceState
  233.  
  234. }
  235. catch (error) {
  236. console.warn("This browser doesn't support redefining" +
  237. " window.open , so [SpmBlockTool] cannot remove" +
  238. " spm in popup window.\nError:", error);
  239. }
  240.  
  241. var DOM_observer;
  242. let DOM_observer_observe = function () {
  243. DOM_observer.observe(document.body, {
  244. attributes: true,
  245. childList: true,
  246. subtree: true
  247. });
  248. };
  249. DOM_observer = new MutationObserver(function (args) {
  250. //debugger
  251. // console.log('DOM changed: ', args);
  252. DOM_observer.disconnect();
  253. for (let i of args) {
  254. if (i.type == 'attributes') {
  255. link_clean_worker(i.target);
  256. }
  257. else if (i.type == 'childList') {
  258. for (let j of i.addedNodes) {
  259. link_clean_worker(j);
  260. }
  261. }
  262. }
  263. DOM_observer.takeRecords();
  264. DOM_observer_observe();
  265. });
  266.  
  267. window.addEventListener('DOMContentLoaded', function () {
  268. // window.setInterval(linkclickhandlerinit, 5000);
  269. new Promise(o => { linkclickhandlerinit(); o() }); // 异步执行
  270.  
  271. DOM_observer_observe();
  272. });
  273.  
  274. // 移除当前页面的spm
  275. // 当然,实际上spm已经在userscript加载前被发送到服务器,
  276. // 所以该功能仅美化url.
  277. // 如果要禁用该功能,删除下面一行开头的斜杠。
  278. //if(0)
  279. // Remove spm from current page
  280. // Of course, in fact, spm has been sent to the server
  281. // before userscript is loaded, so this function only beautifies the URL.
  282. // If you want to disable this feature, remove the slash
  283. // at the beginning of the following line:
  284. //if(0)
  285. if (test_spm(location.href)) {
  286. _realhistoryreplaceState.call(window.history,
  287. {}, document.title,
  288. remove_spm(location.href));
  289. }
  290.  
  291. /*
  292. // 测试代码
  293. var test_urls = [
  294. 'https://www.bilibili.com/video/BV18X4y1N7Yh',
  295. 'https://www.bilibili.com/video/BV18X4y1N7Yh?spm_id_from=114514',
  296. 'https://www.bilibili.com/video/BV18X4y1N7Yh?spm=114514.1919810',
  297. 'https://www.bilibili.com/video/BV18X4y1N7Yh?spm_id_from=114514.123',
  298.  
  299. 'https://www.bilibili.com/video/av170001',
  300. 'https://www.bilibili.com/video/av170001?spm_id_from=114514',
  301. 'https://www.bilibili.com/video/av170001?spm=114514.1919810',
  302. 'https://www.bilibili.com/video/av170001?spm_id_from=114514.123',
  303.  
  304. 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514',
  305. 'https://www.bilibili.com/video/av170001?query1=arg2&spm=114514.1919810',
  306. 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514.123',
  307. 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514',
  308. 'https://www.bilibili.com/video/av170001?query1=arg2&spm=114514.1919810',
  309. 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514.123',
  310.  
  311. 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514&query2=data3',
  312. 'https://www.bilibili.com/video/av170001?query1=arg2&spm=114514.1919810&query2=data3',
  313.  
  314. 'https://www.bilibili.com/video/av170001?spm_id_from=114514#hash',
  315. 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514#hash1',
  316. 'https://www.bilibili.com/video/av170001?query1=arg2&spm=114514.1919810#hash1',
  317.  
  318. 'https://www.bilibili.com/video/av170001?spm_id_from=114514&query2=data3#hash1',
  319. 'https://www.bilibili.com/video/av170001?spm=114514.1919810&query2=data3#hash1',
  320. ];
  321. for(let i=0;i<test_urls.length;++i){
  322. let el=document.createElement('a');
  323. el.href=test_urls[i];
  324. el.innerHTML=i+1 + '';
  325. document.documentElement.appendChild(el);
  326. }
  327. for(let i=0;i<test_urls.length;++i){
  328. let el=document.createElement('a');
  329. el.href=test_urls[i];
  330. el.innerHTML=i+1 + ' blank';
  331. el.target='_blank';
  332. document.documentElement.appendChild(el);
  333. }
  334. */
  335.  
  336. })(window);
  337.  
  338. })();

QingJ © 2025

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