spm_Track_Block_Tool

移除链接中的spm跟踪参数

目前为 2023-02-05 提交的版本。查看 最新版本

// ==UserScript==
// @name         spm_Track_Block_Tool
// @namespace    _s7util__
// @version      0.5.11
// @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': 'bilibili.com', 'keyword': 'vd_source' },
        { 'domain': 'baike.baidu.com', 'keyword': 'fr' },
        { 'domain': 'alibaba.com', 'keyword': 'tracelog' },
    ];
    var unwritable_list = [
        // https://gf.qytechs.cn/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 _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);
        }
    }
    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));
        };
        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

    }
    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));
    }

    // https://gf.qytechs.cn/zh-CN/scripts/443049/discussions/156657
    // https://gf.qytechs.cn/zh-CN/scripts/443049/discussions/132536
    setInterval(function () {
        // 确认过了,只是检查页面有没有跟踪参数,不进行大范围DOM访问,性能开销可以忽略
        if (test_spm(location.href)) {
            _realhistoryreplaceState.call(window.history,
                {}, document.title,
                remove_spm(location.href));
        }
    }, 800);

    /*
    // 测试代码
    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);

})();

QingJ © 2025

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