尝试阻止Bilibili直播页面检测浏览器标签页切换或页面离开。
// ==UserScript==
// @name Bilibili Live - Prevent Tab/Browser Detection
// @namespace http://tampermonkey.net/
// @version 1.2
// @description 尝试阻止Bilibili直播页面检测浏览器标签页切换或页面离开。
// @author ChatGPT
// @match https://live.bilibili.com/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
console.log("[Bilibili Live Detection Blocker] Script initialized.");
// --- 策略 1: 劫持 document.hidden 和 document.visibilityState ---
// 这个策略对于很多网站的隐藏/可见性检测非常有效
try {
Object.defineProperty(document, 'hidden', {
get: function() { return false; },
configurable: true // 允许重新定义
});
Object.defineProperty(document, 'visibilityState', {
get: function() { return 'visible'; },
configurable: true // 允许重新定义
});
console.log("[Bilibili Live Detection Blocker] document.hidden and visibilityState spoofed.");
} catch (e) {
console.error("[Bilibili Live Detection Blocker] Failed to spoof document.hidden/visibilityState:", e);
}
// --- 策略 2: 阻止 visibilitychange 事件触发 ---
// 通过阻止事件冒泡和默认行为的封装函数
const preventEvent = (eventType) => {
// 使用 addEventListener 的 UseCapture = true (捕获阶段) 更早地拦截事件
window.addEventListener(eventType, function(e) {
e.stopImmediatePropagation(); // 阻止同类型事件的后续监听器被调用
// e.preventDefault(); // 对于一些可取消的事件,可以阻止其默认行为,但对于 visibilitychange 通常不必要
// console.log(`[Bilibili Live Detection Blocker] Prevented ${eventType} event.`);
}, true); // `true` 表示在捕获阶段执行
};
// 针对 visibilitychange 事件
preventEvent('visibilitychange');
console.log("[Bilibili Live Detection Blocker] Prevented 'visibilitychange' event listeners.");
// --- 策略 3: 阻止 blur/focus 事件触发 (针对窗口失去/获得焦点) ---
// 页面切换标签页时,整个窗口可能不会失去焦点,但当浏览器最小化或切换到其他应用程序时,窗口可能会失去焦点。
// 这两个事件对于检测窗口激活状态很重要。
preventEvent('blur');
preventEvent('focus'); // 虽然主要目的是阻止检测离开,但如果 focus 也被检测,也一并处理
console.log("[Bilibili Live Detection Blocker] Prevented 'blur' and 'focus' event listeners.");
// --- 策略 4: 劫持 requestAnimationFrame (不常用,但某些高级检测可能用到) ---
// 如果网站通过检测 requestAnimationFrame 是否暂停来判断页面是否激活,这个策略会有用。
// 但通常不建议无差别劫持,因为它可能影响页面动画性能。
// 在这里暂时不启用,因为可能不是主要检测手段,且可能带来副作用。
// let originalRequestAnimationFrame = window.requestAnimationFrame;
// window.requestAnimationFrame = function(callback) {
// // 可以在这里加一个判断,例如在特定条件下才调用原始的 requestAnimationFrame
// // 例如:如果页面不是真的隐藏,就正常调用
// // 但为了阻止检测,我们假设它总是可见的
// return originalRequestAnimationFrame.call(window, callback);
// };
// console.log("[Bilibili Live Detection Blocker] Potentially spoofed requestAnimationFrame (disabled by default).");
// --- 策略 5: 劫持 Page Visibility API 的事件监听方法 ---
// 这样可以阻止通过 document.addEventListener('visibilitychange', ...) 注册的监听器
// 尽管策略2已经通过捕获阶段阻止了事件,但这个方法提供了另一种层面的保护
const original_addEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener, options) {
// console.log(`[Bilibili Live Detection Blocker] addEventListener called for: ${type}`);
if (this === document) { // 只作用于 document 对象
if (type === 'visibilitychange' || type === 'blur' || type === 'focus') {
// 不注册这些事件的监听器 或者 注册一个空函数
console.log(`[Bilibili Live Detection Blocker] Blocked registration of ${type} listener on document.`);
return; // 阻止原生的监听器被注册
}
}
original_addEventListener.call(this, type, listener, options);
};
console.log("[Bilibili Live Detection Blocker] Modified EventTarget.prototype.addEventListener to block specific document events.");
// --- 策略 6: 阻止 unload/beforeunload 事件 (防止页面关闭前的提示或数据上报) ---
// 虽然不是直接的标签页切换检测,但可以阻止页面关闭时的触发
preventEvent('beforeunload');
preventEvent('unload');
console.log("[Bilibili Live Detection Blocker] Prevented 'beforeunload' and 'unload' event listeners.");
console.log("[Bilibili Live Detection Blocker] All detection prevention strategies applied.");
})();