- // ==UserScript==
- // @name spm_Track_Block_Tool
- // @namespace _s7util__
- // @version 0.5.8
- // @description:en Remove [spm] track paramter in URL
- // @description 移除链接中的spm跟踪参数
- // @author shc0743
- // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
- // @grant none
- // @license GPL-3.0
- // @supportURL https://github.com/shc0743/MyUtility/issues/new
- // @run-at document-start
- // @match http*://*.bilibili.com/*
- // @match http*://*.baidu.com/*
- // @match http*://*.cctv.com/*
- // @match http*://*.taobao.com/*
- // @match http*://*.alibaba.com/*
- // @exclude http*://*.paypal.com/*
- // @exclude http*://*.alipay.com/*
- // ==/UserScript==
-
- /*
- Description:
- 说明:
-
- This user script removes the spm paramter in <a href> elements.
- 此脚本移除 <a href> 元素中的spm参数。
-
- If it doesn't work, try refreshing it a few times or wait a while.
- 若无法生效,请尝试刷新几次或等一会。
-
- Examples:
- 示例:
-
- https://www.bilibili.com/video/av170001?spm_id_from=114514
- -> https://www.bilibili.com/video/av170001
-
- https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514&query2=data3
- -> https://www.bilibili.com/video/av170001?query1=arg2&query2=data3
-
- https://www.bilibili.com/video/av170001?spm=114514.1919810#hash
- -> https://www.bilibili.com/video/av170001#hash
-
- https://www.bilibili.com/video/av170001?spm=114514.1919810&query2=data3#hash1
- -> https://www.bilibili.com/video/av170001?query2=data3#hash1
- */
-
- (function () {
- 'use strict';
-
- // Your code here...
-
- var track_args_list = [
- { 'domain': '*', 'keyword': 'spm' },
- { 'domain': '*', 'keyword': 'spm_id_from' },
- { 'domain': '*', 'keyword': 'from_source' },
- { 'domain': 'bilibili.com', 'keyword': 'from' },
- { 'domain': 'bilibili.com', 'keyword': 'seid' },
- { 'domain': 'baike.baidu.com', 'keyword': 'fr' },
- { 'domain': 'alibaba.com', 'keyword': 'tracelog' },
- ];
- var unwritable_list = [
- // https://greasyfork.org/zh-CN/scripts/443049/discussions/132536
- { object: window, key: 'goldlog' },
- ];
- try {
- for (let i of unwritable_list) {
- Object.defineProperty(i.object, i.key, {
- get() { return undefined },
- set(value) { void (value) },
- enumerable: false,
- configurable: true
- });
- }
- }
- catch (error) {
- console.warn(error);
- }
-
- return (function (global) {
-
- //var expr = /\?[\s\S]*spm/i;
-
- /**
- * 去除字符串中的spm参数
- * @param {String} str URL to remove spm
- * @returns 去除spm后的结果
- */
- var remove_spm = function (str) {
- if (typeof (str) != 'string') return str;
- var newstr = '';
- var len = str.length;
- // 只去除查询参数部分,避免正常url被替换而导致404
- var hash_part_begin = str.indexOf('#');
- var query_part_begin = str.indexOf('?');
- if (query_part_begin == -1 ||
- (hash_part_begin != -1 && query_part_begin > hash_part_begin))
- { return str; } // 没有查询参数或?在#后面,直接返回
- newstr = str.substring(0, query_part_begin);
- var domain = '';
- {
- let index = str.indexOf('://');
- if (index + 1) {
- index = str.indexOf('/', index + 3);
- if (index + 1) {
- domain = str.substring(0, index);
- }
- }
- }
-
- for (let i = query_part_begin, need_break; i < len; ++i) {
- for (let j = 0; j < track_args_list.length; ++j) {
- if (!(track_args_list[j].domain == '*' ||
- domain.indexOf(track_args_list[j].domain) != -1)) {
- need_break = false;
- break;
- }
- need_break = true;
- if (track_args_list[j].keyword == str.substring(i,
- i + track_args_list[j].keyword.length - 0)) {
- // 检测到
- while ((++i) < len) {
- if (str[i] == '&') { // 不能单独保留一个 & 号
- i++;
- break; // 去掉
- }
- if (str[i] == '#') break; // 保留hash部分
- }
- if (i == len) break; // 越界,直接break,以免url出现undefined
- }
- need_break = false;
- }
- if (need_break) break;
- newstr += str[i];
- }
-
- var _lastchar;
- for (let i = 0; i < newstr.length; ++i) {
- _lastchar = newstr[newstr.length - 1];
- if (_lastchar == '?' || _lastchar == '&') { // 如果移除后只剩下 ? 或 &
- newstr = newstr.substring(0, newstr.length - 1); // 去掉
- } else break;
- }
- // Bug-Fix:
- // https://example.com/example?q1=arg&spm=123#hash1
- // -> https://example.com/example?q1=arg&#hash1
- // Invalid URL syntax at ^^
- newstr = newstr.replace(/\&\#/igm, '#');
- newstr = newstr.replace(/\?\#/igm, '#');
- return newstr;
- }
- var test_spm = function (str) {
- for (let tracker of track_args_list)
- if (new RegExp(tracker, 'i').test(str))
- return true;
- return false;
- };
- var _realwindowopen = window.open;
- var _realhistorypushState = window.history.pushState;
- var _realhistoryreplaceState = window.history.replaceState;
- var _realaconstructor = window.HTMLAnchorElement.prototype.constructor;
-
- var _link_click_test = function (val) {
- if (/\#/.test(val)) return true;
- if (/javascript\:/i.test(val)) return true;
- return false;
- };
- var _link_click = function (event) {
- if (_link_click_test(this.href)) return;
- event.preventDefault();
- // 防止被再次加入spm
- this.href = remove_spm(this.href);
- _realwindowopen(this.href, this.target || '_self');
- return false;
- };
- var _link_mouseover = function () {
- if (test_spm(this.href))
- this.href = remove_spm(this.href);
- };
- var link_clean_worker = function (el) {
- if (test_spm(el.href)) {
- // 链接已经被加入spm , 需要移除
- el.href = remove_spm(el.href);
- }
- el.removeEventListener('click', _link_click);
- el.addEventListener('click', _link_click, true);
- el.removeEventListener('mouseover', _link_mouseover);
- el.addEventListener('mouseover', _link_mouseover, false);
- }
- var linkclickhandlerinit = function () {
- var el = document.querySelectorAll('a[href]');
- for (let i = el.length - 1; i >= 0; --i) {
- link_clean_worker(el[i]);
- }
- };
-
- try {
- let wopen = function (url, target, features) {
- return _realwindowopen.call(window,
- remove_spm(url),
- target,
- features);
- };
- let hp = function (data, title, url) {
- return _realhistorypushState.call(
- window.history, data, title,
- remove_spm(url));
- };
- let hr = function (data, title, url) {
- return _realhistoryreplaceState.call(
- window.history, data, title,
- remove_spm(url));
- };
- /*let a_constructor = function () {
- var href = "";
- let obj = _realaconstructor.apply(this, arguments);
- try {
- Object.defineProperty(obj, 'href', {
- get() { return href },
- set(val) { href = remove_spm(val) },
- enumerable: true,
- configurable: true
- });
- }
- catch (err) {
- console.warn('Error creating element:', err);
- }
- return obj;
- };*/
- wopen.toString =
- hp.toString =
- hr.toString =
- new Function("return 'function () {\\n [native code]\\n}'");
- // 必须定义成 writable 否则一些网站(例如B站收藏夹页面)会出错
- Object.defineProperty(window, 'open', {
- value: wopen,
- writable: true,
- enumerable: true,
- configurable: true
- }); // 重定义window.open 以阻止弹出窗口中的spm
- Object.defineProperty(window.history, 'pushState', {
- value: hp,
- writable: true,
- enumerable: true,
- configurable: true
- }); // 重定义history.pushState
- Object.defineProperty(window.history, 'replaceState', {
- value: hr,
- writable: true,
- enumerable: true,
- configurable: true
- }); // 重定义history.replaceState
- // Object.defineProperty(window.HTMLAnchorElement.prototype,
- // 'constructor', {
- // value: a_constructor,
- // writable: true,
- // enumerable: true,
- // configurable: true
- // }); // 替代setInterval
-
- }
- catch (error) {
- console.warn("This browser doesn't support redefining" +
- " window.open , so [SpmBlockTool] cannot remove" +
- " spm in popup window.\nError:", error);
- }
-
- var DOM_observer;
- let DOM_observer_observe = function () {
- DOM_observer.observe(document.body, {
- attributes: true,
- childList: true,
- subtree: true
- });
- };
- DOM_observer = new MutationObserver(function (args) {
- //debugger
- // console.log('DOM changed: ', args);
- DOM_observer.disconnect();
- for (let i of args) {
- if (i.type == 'attributes') {
- link_clean_worker(i.target);
- }
- else if (i.type == 'childList') {
- for (let j of i.addedNodes) {
- link_clean_worker(j);
- }
- }
- }
- DOM_observer.takeRecords();
- DOM_observer_observe();
- });
-
- window.addEventListener('DOMContentLoaded', function () {
- // window.setInterval(linkclickhandlerinit, 5000);
- new Promise(o => { linkclickhandlerinit(); o() }); // 异步执行
-
- DOM_observer_observe();
- });
-
- // 移除当前页面的spm
- // 当然,实际上spm已经在userscript加载前被发送到服务器,
- // 所以该功能仅美化url.
- // 如果要禁用该功能,删除下面一行开头的斜杠。
- //if(0)
- // Remove spm from current page
- // Of course, in fact, spm has been sent to the server
- // before userscript is loaded, so this function only beautifies the URL.
- // If you want to disable this feature, remove the slash
- // at the beginning of the following line:
- //if(0)
- if (test_spm(location.href)) {
- _realhistoryreplaceState.call(window.history,
- {}, document.title,
- remove_spm(location.href));
- }
-
- /*
- // 测试代码
- var test_urls = [
- 'https://www.bilibili.com/video/BV18X4y1N7Yh',
- 'https://www.bilibili.com/video/BV18X4y1N7Yh?spm_id_from=114514',
- 'https://www.bilibili.com/video/BV18X4y1N7Yh?spm=114514.1919810',
- 'https://www.bilibili.com/video/BV18X4y1N7Yh?spm_id_from=114514.123',
-
- 'https://www.bilibili.com/video/av170001',
- 'https://www.bilibili.com/video/av170001?spm_id_from=114514',
- 'https://www.bilibili.com/video/av170001?spm=114514.1919810',
- 'https://www.bilibili.com/video/av170001?spm_id_from=114514.123',
-
- 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514',
- 'https://www.bilibili.com/video/av170001?query1=arg2&spm=114514.1919810',
- 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514.123',
- 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514',
- 'https://www.bilibili.com/video/av170001?query1=arg2&spm=114514.1919810',
- 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514.123',
-
- 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514&query2=data3',
- 'https://www.bilibili.com/video/av170001?query1=arg2&spm=114514.1919810&query2=data3',
-
- 'https://www.bilibili.com/video/av170001?spm_id_from=114514#hash',
- 'https://www.bilibili.com/video/av170001?query1=arg2&spm_id_from=114514#hash1',
- 'https://www.bilibili.com/video/av170001?query1=arg2&spm=114514.1919810#hash1',
-
- 'https://www.bilibili.com/video/av170001?spm_id_from=114514&query2=data3#hash1',
- 'https://www.bilibili.com/video/av170001?spm=114514.1919810&query2=data3#hash1',
- ];
- for(let i=0;i<test_urls.length;++i){
- let el=document.createElement('a');
- el.href=test_urls[i];
- el.innerHTML=i+1 + '';
- document.documentElement.appendChild(el);
- }
- for(let i=0;i<test_urls.length;++i){
- let el=document.createElement('a');
- el.href=test_urls[i];
- el.innerHTML=i+1 + ' blank';
- el.target='_blank';
- document.documentElement.appendChild(el);
- }
- */
-
- })(window);
-
- })();