// ==UserScript== // @name 检测B站直播弹幕拦截(AI修复版) // @namespace http://tampermonkey.net/ // @version 1.2.1 // @description 修复之前版本无法发送弹幕和@的问题;优化了弹窗 // @author 熊孩子 // @match https://live.bilibili.com/* // @grant unsafeWindow // @run-at document-start // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/537096/%E6%A3%80%E6%B5%8BB%E7%AB%99%E7%9B%B4%E6%92%AD%E5%BC%B9%E5%B9%95%E6%8B%A6%E6%88%AA%28AI%E4%BF%AE%E5%A4%8D%E7%89%88%29.user.js // @updateURL https://update.greasyfork.icu/scripts/537096/%E6%A3%80%E6%B5%8BB%E7%AB%99%E7%9B%B4%E6%92%AD%E5%BC%B9%E5%B9%95%E6%8B%A6%E6%88%AA%28AI%E4%BF%AE%E5%A4%8D%E7%89%88%29.meta.js // ==/UserScript== (function() { 'use strict'; console.log('[弹幕检测] 脚本已加载'); // 拦截fetch请求 const originFetch = unsafeWindow.fetch; unsafeWindow.fetch = async function(input, init) { // 备份原始请求 const originalRequest = () => originFetch.call(this, input, init); try { // 检查是否为弹幕发送请求 const isMessageSend = typeof input === 'string' && ( input.includes('/msg/send') || input.includes('/api/sendmsg') ); if (!isMessageSend) { return originalRequest(); } console.log('[弹幕检测] 捕获到发送请求:', input); // 提取消息内容 let msgContent = ''; if (init && init.body) { try { // 尝试不同格式解析 if (typeof init.body === 'string') { const bodyParams = new URLSearchParams(init.body); msgContent = bodyParams.get('msg') || bodyParams.get('text') || '未能获取消息内容'; } else if (init.body instanceof FormData) { // 使用迭代器同步解析FormData const bodyParams = new URLSearchParams(); for (const [key, value] of init.body.entries()) { bodyParams.append(key, value); } msgContent = bodyParams.get('msg') || bodyParams.get('text') || '未能获取消息内容'; } } catch (e) { console.warn('[弹幕检测] 解析请求体失败:', e); } } // 发送原始请求并检查结果 const response = await originalRequest(); const clonedResponse = response.clone(); // 异步处理响应 clonedResponse.json().then(result => { console.log('[弹幕检测] 响应数据:', result); // 统一处理code字段(兼容字符串/数字类型) const code = typeof result.code === 'string' ? parseInt(result.code) : result.code; // 更全面的响应检查 if (code !== 0) { // 一般错误情况 showPrompt("发送失败", `错误码: ${code}, 消息: ${result.message || result.msg || '未知错误'}`, msgContent); } else if (result.msg === "f" || result.data?.msg_type === -1) { showPrompt("全站屏蔽", result.message || result.msg || '弹幕被全站屏蔽', msgContent); } else if (result.msg === "k" || result.data?.msg_type === -2) { showPrompt("主播屏蔽", result.message || result.msg || '弹幕被主播屏蔽', msgContent); } }).catch(error => { console.error('[弹幕检测] 解析响应失败:', error); }); return response; } catch (error) { console.error('[弹幕检测] 请求处理异常:', error); return originalRequest(); } }; // 拦截XMLHttpRequest const originXHROpen = XMLHttpRequest.prototype.open; const originXHRSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.open = function() { this._dmUrl = arguments[1]; return originXHROpen.apply(this, arguments); }; XMLHttpRequest.prototype.send = function(body) { // 检查是否是弹幕发送请求 const isMessageSend = typeof this._dmUrl === 'string' && ( this._dmUrl.includes('/msg/send') || this._dmUrl.includes('/api/sendmsg') ); if (isMessageSend) { console.log('[弹幕检测] 捕获到XHR发送请求:', this._dmUrl); // 尝试提取消息内容 let msgContent = ''; if (body) { try { if (typeof body === 'string') { const bodyParams = new URLSearchParams(body); msgContent = bodyParams.get('msg') || bodyParams.get('text') || '未能获取消息内容'; } else if (body instanceof FormData) { const bodyParams = new URLSearchParams(); for (const [key, value] of body.entries()) { bodyParams.append(key, value); } msgContent = bodyParams.get('msg') || bodyParams.get('text') || '未能获取消息内容'; } } catch (e) { console.warn('[弹幕检测] 解析XHR请求体失败:', e); } } // 保存消息内容 this._dmContent = msgContent; // 监听响应 const originalOnload = this.onload; this.onload = function() { try { // 尝试解析响应 const result = JSON.parse(this.responseText); console.log('[弹幕检测] XHR响应数据:', result); // 统一处理code字段(兼容字符串/数字类型) const code = typeof result.code === 'string' ? parseInt(result.code) : result.code; // 检查响应状态 if (code !== 0) { showPrompt("发送失败", `错误码: ${code}, 消息: ${result.message || result.msg || '未知错误'}`, this._dmContent); } else if (result.msg === "f" || result.data?.msg_type === -1) { showPrompt("全站屏蔽", result.message || result.msg || '弹幕被全站屏蔽', this._dmContent); } else if (result.msg === "k" || result.data?.msg_type === -2) { showPrompt("主播屏蔽", result.message || result.msg || '弹幕被主播屏蔽', this._dmContent); } } catch (e) { console.error('[弹幕检测] 解析XHR响应失败:', e); } // 调用原始的onload处理程序 if (originalOnload) { originalOnload.call(this); } }; } return originXHRSend.apply(this, arguments); }; // 改进的提示框显示函数 function showPrompt(type, reason, msg) { console.log(`[弹幕检测] ${type}: ${reason}, 内容: ${msg}`); const showModal = () => { const modal = document.createElement('div'); modal.style = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 20px; background: white; border: 2px solid red; z-index: 999999; box-shadow: 0 0 10px rgba(0,0,0,0.5); font-family: Arial, sans-serif; border-radius: 8px; max-width: 90%; width: 400px; `; // 创建一个唯一ID,避免ID冲突 const textareaId = 'prompt-textarea-' + Date.now(); const notificationId = 'copy-notification-' + Date.now(); modal.innerHTML = `
弹幕内容: