// ==UserScript== // @name BiliBili稿件批量举报实验型号 // @namespace https://bbs.tampermonkey.net.cn/ // @version 1.1.1 Prototype // @description 批量举报B站稿件(请谨慎使用) // @author You // @match https://space.bilibili.com/* // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @connect api.bilibili.com // @connect www.bilibili.com // ==/UserScript== const SubmitText = '涉嫌考试作弊,违法违规。' GM_registerMenuCommand("自动举报所有稿件", fuckBilibiliShitVideo, "h"); let csrfText = '' // 更健壮的CSRF获取方式 function getCsrf() { if (!csrfText) { const cookies = document.cookie.split(';') for (const cookie of cookies) { const [key, value] = cookie.trim().split('=') if (key === 'bili_jct') { csrfText = decodeURIComponent(value) break } } } if (!csrfText) { throw new Error('未找到CSRF token,请确保已登录') } return csrfText } // 改用GM_xmlhttpRequest并添加Promise封装 function fuckVideo(aid) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "POST", url: 'https://api.bilibili.com/x/web-interface/appeal/v2/submit', headers: { "Content-Type": "application/x-www-form-urlencoded" }, data: new URLSearchParams({ aid: aid, attach: "", block_author: false, csrf: getCsrf(), desc: SubmitText, tid: 2 }).toString(), onload: (response) => { try { const data = JSON.parse(response.responseText) if (data.code === 0) { resolve(true) } else { reject(new Error(`API错误: ${data.message}`)) } } catch (e) { reject(new Error('响应解析失败')) } }, onerror: (error) => reject(error) }) }) } // 添加错误处理和更安全的aid提取 async function getVideoAid(url) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ url: url, method: "GET", onload: function(xhr) { try { const match = xhr.responseText.match(/"aid":"?(\d+)"?/) if (match && match[1]) { resolve(match[1]) } else { reject(new Error('未找到视频aid')) } } catch (e) { reject(e) } }, onerror: (error) => reject(error) }) }) } // 添加延迟防止请求过频 async function getPageAllVideoAid() { const idList = [...document.querySelectorAll('.bili-cover-card')] .map(dom => dom.href) .filter(url => url && url.includes('video/BV')) for (const [index, url] of idList.entries()) { try { const aid = await getVideoAid(url) await fuckVideo(aid) console.log(`已处理第 ${index + 1}/${idList.length} 个稿件`) // 添加1秒间隔防止请求过频 await new Promise(r => setTimeout(r, 1000)) } catch (error) { console.error(`处理失败(${url}):`, error) } } } // 添加全局错误处理 async function fuckBilibiliShitVideo() { if (!confirm('确定要批量举报本页所有稿件吗?此操作不可逆!')) return try { await getPageAllVideoAid() alert('本页稿件处理完成,请查看控制台了解详情') } catch (error) { alert('操作失败: ' + error.message) } }