// ==UserScript==
// @name ❀ Bilibili 浮岚链接净化器
// @namespace https://bento.me/ranburiedbyacat
// @version 1.0
// @description 加载前清洁链接,移除跟踪参数。
// @author 嵐 @ranburiedbyacat
// @license CC-BY-NC-SA-4.0
// @match *://*.bilibili.com/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
/**
* ───────────────────────────────────────────────
* ① 冗余参数列表
* ───────────────────────────────────────────────
* 功能:存储 B站 URL 中用于追踪、统计或营销的无关参数
* 逻辑:统一收集参数,便于批量删除跟踪参数与陈睿鸡巴
*/
const garbageParams = new Set([
// ────────────── 来源跟踪 ──────────────
'spm_id_from', 'from_source', 'sourceFrom', 'from_spmid', 'csource', 'vd_source', 'source','spm_id_from', 'from_source', 'sourceFrom', 'from_spmid', 'csource', 'vd_source', 'source', 'search_source',
// ────────────── 分享参数 ───────────────
'share_source', 'share_medium', 'share_plat', 'share_session_id', 'share_tag', 'share_from', 'plat_id',
// ────────────── 广告统计 ──────────────
'trackid', 'session_id', 'visit_id', 'unique_k', 'spmid', '-Arouter',
// ────────────── 功能标记 ──────────────
'msource', 'bsource', 'tab', 'is_story_h5', 'hotRank', 'launch_id', 'live_from'
]);
/**
* ───────────────────────────────────────────────
* ② URL 解析工具
* ───────────────────────────────────────────────
* 功能:安全生成 URL 对象
* 逻辑:处理相对路径或省略协议的 URL,解析失败返回 null
*/
function parseURL(str) {
try {
if (typeof str === 'string' && str.includes('.') && !/^[a-z]+:/.test(str)) {
str = str.startsWith("//") ? location.protocol + str : str;
}
return new URL(str, location.href);
} catch (e) {
return null;
}
}
/**
* ───────────────────────────────────────────────
* ③ URL 净化核心函数
* ───────────────────────────────────────────────
* 功能:删除 URL 中的追踪参数并标准化路径
* 逻辑:
* - 仅处理 bilibili.com 域名
* - 将 bilibili.tv 替换为 www.bilibili.com
* - 删除垃圾参数
* - 去除路径尾部多余斜杠
*/
function cleanUrl(urlStr) {
const url = parseURL(urlStr);
if (!url) return urlStr;
if (!/bilibili\.com/.test(url.hostname)) return urlStr;
if (url.hostname.includes('bilibili.tv')) url.hostname = 'www.bilibili.com';
garbageParams.forEach(p => url.searchParams.delete(p));
if (url.pathname.length > 1 && url.pathname.endsWith('/')) {
url.pathname = url.pathname.slice(0, -1);
}
return url.toString();
}
/**
* ───────────────────────────────────────────────
* ④ 地址栏即时替换
* ───────────────────────────────────────────────
* 功能:页面加载前净化地址栏 URL
* 逻辑:对比当前 URL,如不同则用 history.replaceState 更新
*/
function replaceLocation(url) {
if (url !== location.href) {
history.replaceState(history.state, '', url);
}
}
replaceLocation(cleanUrl(location.href));
/**
* ───────────────────────────────────────────────
* ⑤ 链接点击拦截
* ───────────────────────────────────────────────
* 功能:在跳转前净化目标链接并移除追踪
* 逻辑:根据点击类型决定当前页或新标签跳转,同时移除 ping
*/
function handleClick(e) {
const a = e.target.closest('a[href*="bilibili.com"]');
if (!a) return;
e.preventDefault();
const clean = cleanUrl(a.href);
if (a.target === '_blank' || e.ctrlKey || e.metaKey || e.shiftKey) {
window.open(clean, '_blank');
} else {
location.href = clean;
}
}
window.addEventListener('click', handleClick, true);
window.addEventListener('contextmenu', handleClick, false);
/**
* ───────────────────────────────────────────────
* ⑥ window.open 拦截
* ───────────────────────────────────────────────
* 功能:净化通过 JS 打开的新窗口 URL
* 逻辑:调用原 window.open 前先净化 URL
*/
const _open = window.open;
window.open = (url, target, features) => _open.call(window, cleanUrl(url), target || '_blank', features);
/**
* ───────────────────────────────────────────────
* ⑦ SPA 导航拦截
* ───────────────────────────────────────────────
* 功能:净化 pushState / replaceState 内部导航 URL
* 逻辑:在调用原方法前先净化 URL
*/
['pushState', 'replaceState'].forEach(fn => {
const orig = history[fn];
history[fn] = (...args) => {
if (typeof args[2] === 'string') {
args[2] = cleanUrl(args[2]);
}
return orig.apply(history, args);
};
});
/**
* ───────────────────────────────────────────────
* ⑧ Navigation API 拦截
* ───────────────────────────────────────────────
* 功能:净化 navigation.navigate() 导航 URL
* 逻辑:拦截事件,替换目标 URL 并阻止默认导航
*/
if (window.navigation) {
window.navigation.addEventListener('navigate', e => {
const newURL = cleanUrl(e.destination.url);
if (newURL !== e.destination.url) {
e.preventDefault();
if (newURL !== location.href) {
history.replaceState(history.state, '', newURL);
}
}
});
}
/**
* ───────────────────────────────────────────────
* ⑨ 动态节点净化
* ───────────────────────────────────────────────
* 功能:监测页面中新加入的 <a> 标签并即时净化
* 逻辑:净化 href 并移除 ping 属性
*/
const observer = new MutationObserver(muts => {
for (let i = 0; i < muts.length; i++) {
const m = muts[i];
for (let j = 0; j < m.addedNodes.length; j++) {
const node = m.addedNodes[j];
if (node.nodeType !== 1) continue;
const links = node.querySelectorAll ? node.querySelectorAll('a[href*="bilibili.com"]') : [];
for (let k = 0; k < links.length; k++) {
const a = links[k];
a.href = cleanUrl(a.href);
a.removeAttribute('ping');
}
}
}
});
observer.observe(document, { childList: true, subtree: true });
})();