// ==UserScript==
// @name spm_Track_Block_Tool
// @namespace _s7util__
// @version 0.5.4
// @description:en Remove [spm] track paramter in URL
// @description 移除链接中的spm跟踪参数
// @author shc0743
// @match http*://*/*
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant none
// @license GPL-3.0
// @supportURL https://github.com/shc0743/MyUtility/issues/new
// @run-at document-start
// ==/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' },
];
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 _link_click = function (event) {
if (!(/http/i.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 linkclickhandlerinit = function () {
var el = document.querySelectorAll('a[href]');
for (let i = el.length - 1; i >= 0; --i) {
if (test_spm(el[i].href)) {
// 链接已经被加入spm , 需要移除
el[i].href = remove_spm(el[i].href);
}
el[i].removeEventListener('click', _link_click);
el[i].addEventListener('click', _link_click, true);
el[i].removeEventListener('mouseover', _link_mouseover);
el[i].addEventListener('mouseover', _link_mouseover, false);
}
};
window.addEventListener('load', function (event) {
window.setInterval(linkclickhandlerinit, 5000);
window.setTimeout(linkclickhandlerinit, 1000);
window.setTimeout(linkclickhandlerinit, 500);
window.setTimeout(linkclickhandlerinit, 1);
try {
var wopen = function (url, target, features) {
return _realwindowopen.call(window,
remove_spm(url),
target,
features);
};
var hp = function (data, title, url) {
return _realhistorypushState.call(
window.history, data, title,
remove_spm(url));
};
var hr = function (data, title, url) {
return _realhistoryreplaceState.call(
window.history, data, title,
remove_spm(url));
};
wopen.toString =
hp.toString =
hr.toString =
function () {
return `function () {\n [native code]\n}`
};
Object.defineProperty(window, 'open', {
value: wopen,
writable: false,
enumerable: true,
configurable: true
}); // 重定义window.open 以阻止弹出窗口中的spm
Object.defineProperty(window.history, 'pushState', {
value: hp,
writable: false,
enumerable: true,
configurable: true
}); // 重定义history.pushState
Object.defineProperty(window.history, 'replaceState', {
value: hr,
writable: false,
enumerable: true,
configurable: true
}); // 重定义history.replaceState
}
catch (error) {
console.warn("This browser doesn't support redefining" +
" window.open , so [SpmBlockTool] cannot remove" +
" spm in popup window.\nError:", error);
}
});
// 移除当前页面的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);
})();