// ==UserScript== // @name 动态管理 // @namespace mscststs // @version 0.31 // @description 动态管理页面 // @author mscststs // @match https://space.bilibili.com/* // @match http://space.bilibili.com/* // @require https://greasyfork.org/scripts/38220-mscststs-tools/code/MSCSTSTS-TOOLS.js?version=713767 // @require https://cdn.jsdelivr.net/npm/axios@1.7.3/dist/axios.min.js // @icon https://static.hdslb.com/images/favicon.ico // @license MIT // @grant none // @downloadURL https://update.greasyfork.icu/scripts/387046/%E5%8A%A8%E6%80%81%E7%AE%A1%E7%90%86.user.js // @updateURL https://update.greasyfork.icu/scripts/387046/%E5%8A%A8%E6%80%81%E7%AE%A1%E7%90%86.meta.js // ==/UserScript== (function () { 'use strict'; // 全局状态 let appState = { showModal: false, loading: false, loadCount: 20, dynamics: [], offset: '', uid: '' }; // 等待页面加载完成 document.addEventListener('DOMContentLoaded', init); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } async function init() { try { const shijiao = await mscststs.wait(".view-switcher__trigger", false, 100); if (!shijiao || !~shijiao.innerText.indexOf("我自己")) { console.log('当前不是自己的个人动态'); return; } await Promise.all([ mscststs.wait(".space-dynamic__right") ]); // 获取用户ID appState.uid = getCurrentUid(); const node = createControlPanel(); document.querySelector("body").append(node); // 绑定事件 bindEvents(); } catch (error) { console.error('初始化失败:', error); } } // 获取当前用户ID function getCurrentUid() { const match = window.location.pathname.match(/\/(\d+)/); return match ? match[1] : ''; } // 创建控制面板DOM结构 function createControlPanel() { const panelHtml = `
`; const div = document.createElement('div'); div.innerHTML = panelHtml; return div.firstElementChild; } // 绑定事件 function bindEvents() { // 打开弹窗 document.getElementById('open-manager-btn').addEventListener('click', showModal); // 关闭弹窗 document.getElementById('close-modal-btn').addEventListener('click', hideModal); // 点击遮罩关闭弹窗 document.getElementById('manager-modal').addEventListener('click', function(e) { if (e.target === this) { hideModal(); } }); // 加载动态 document.getElementById('load-dynamics-btn').addEventListener('click', loadDynamics); // 勾选所有转发 document.getElementById('select-all-forward-btn').addEventListener('click', selectAllForward); // 勾选所有抽奖 document.getElementById('select-all-lottery-btn').addEventListener('click', selectAllLottery); // 批量删除 document.getElementById('batch-delete-btn').addEventListener('click', batchDeleteDynamics); // 批量删除并取关 document.getElementById('batch-delete-unfollow-btn').addEventListener('click', batchDeleteAndUnfollowDynamics); // 清空数据 document.getElementById('clear-data-btn').addEventListener('click', clearData); // 全选 document.getElementById('select-all-checkbox').addEventListener('change', toggleAllSelection); // 加载数量输入 document.getElementById('load-count-input').addEventListener('input', function() { appState.loadCount = parseInt(this.value) || 20; }); // 按钮悬停效果 const openBtn = document.getElementById('open-manager-btn'); openBtn.addEventListener('mouseenter', function() { this.style.transform = 'translateY(-1px)'; this.style.boxShadow = '0 4px 12px rgba(0, 180, 216, 0.4)'; }); openBtn.addEventListener('mouseleave', function() { this.style.transform = 'translateY(0)'; this.style.boxShadow = '0 2px 8px rgba(0, 180, 216, 0.3)'; }); const closeBtn = document.getElementById('close-modal-btn'); closeBtn.addEventListener('mouseenter', function() { this.style.background = '#f0f0f0'; }); closeBtn.addEventListener('mouseleave', function() { this.style.background = 'none'; }); // 绑定查看按钮事件 document.querySelectorAll('.view-btn').forEach(btn => { btn.addEventListener('click', function() { const index = parseInt(this.dataset.index); viewDynamic(appState.dynamics[index]); }); }); // 绑定删除按钮事件 document.querySelectorAll('.delete-btn').forEach(btn => { btn.addEventListener('click', function() { const index = parseInt(this.dataset.index); deleteDynamic(appState.dynamics[index]); }); }); // 绑定删除并取关按钮事件 document.querySelectorAll('.delete-unfollow-btn').forEach(btn => { btn.addEventListener('click', function() { const index = parseInt(this.dataset.index); deleteAndUnfollowDynamic(appState.dynamics[index]); }); }); } // 显示弹窗 function showModal() { appState.showModal = true; document.getElementById('manager-modal').style.display = 'flex'; } // 隐藏弹窗 function hideModal() { appState.showModal = false; document.getElementById('manager-modal').style.display = 'none'; } // 加载动态 async function loadDynamics() { if (!appState.uid) { alert('无法获取用户ID'); return; } const loadBtn = document.getElementById('load-dynamics-btn'); loadBtn.disabled = true; loadBtn.style.opacity = '0.6'; loadBtn.style.cursor = 'not-allowed'; const targetCount = appState.loadCount; let currentOffset = appState.offset; let totalLoadedInThisSession = 0; try { // 循环加载直到达到目标数量或没有更多数据 while (totalLoadedInThisSession < targetCount) { // 更新按钮文本显示进度 loadBtn.textContent = `加载中... (${totalLoadedInThisSession}/${targetCount})`; const response = await spaceHistory(currentOffset); if (response.code !== 0) { alert('加载失败: ' + response.message); break; } const items = response.data.items || []; if (items.length === 0 || !response.data.has_more) { console.log('没有更多动态数据'); break; } // 计算本次需要添加的数量 const remainingCount = targetCount - totalLoadedInThisSession; const itemsToAdd = items.slice(0, remainingCount).map(item => ({ ...item, selected: false })); appState.dynamics = [...appState.dynamics, ...itemsToAdd]; currentOffset = response.data.offset || ''; appState.offset = currentOffset; totalLoadedInThisSession += itemsToAdd.length; console.log(`本次加载 ${itemsToAdd.length} 条动态,累计加载 ${totalLoadedInThisSession} 条`); // 如果没有更多数据(offset为空)或者API返回的数据少于预期,说明已经到底了 if (!currentOffset || !response.data.has_more) { console.log('已加载所有可用的动态数据'); break; } // 如果已经达到目标数量,退出循环 if (totalLoadedInThisSession >= targetCount) { break; } // 添加短暂延迟避免请求过于频繁 await new Promise(resolve => setTimeout(resolve, 500)); } console.log(`加载完成,目标: ${targetCount} 条,实际加载: ${totalLoadedInThisSession} 条,总计: ${appState.dynamics.length} 条`); // 更新UI updateDynamicsTable(); updateDynamicsCount(); // 显示加载结果 if (totalLoadedInThisSession > 0) { const message = totalLoadedInThisSession < targetCount ? `成功加载 ${totalLoadedInThisSession} 条动态(已加载完所有可用数据)` : `成功加载 ${totalLoadedInThisSession} 条动态`; console.log(message); } else { alert('没有新的动态数据'); } } catch (error) { console.error('加载动态失败:', error); alert('加载失败,请检查网络连接'); } finally { loadBtn.disabled = false; loadBtn.textContent = '加载动态'; loadBtn.style.opacity = '1'; loadBtn.style.cursor = 'pointer'; } } // API调用 async function spaceHistory(offset = "") { const url = `https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?offset=${offset}&host_mid=${appState.uid}&timezone_offset=-480&platform=web`; try { const response = await axios.get(url, { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Referer': 'https://space.bilibili.com/' }, withCredentials: true }); return response.data; } catch (error) { if (error.response && error.response.status === 429) { // 429错误重试机制 await new Promise(resolve => setTimeout(resolve, 2000)); return spaceHistory(offset); } throw error; } } // 清空数据 function clearData() { if (confirm('确定要清空所有数据吗?')) { appState.dynamics = []; appState.offset = ''; updateDynamicsTable(); updateDynamicsCount(); } } // 全选/取消全选 function toggleAllSelection() { const checkbox = document.getElementById('select-all-checkbox'); const isChecked = checkbox.checked; appState.dynamics.forEach(item => { item.selected = isChecked; }); // 更新表格中的复选框 const itemCheckboxes = document.querySelectorAll('.item-checkbox'); itemCheckboxes.forEach(cb => { cb.checked = isChecked; }); } // 更新动态表格 function updateDynamicsTable() { const tbody = document.getElementById('dynamics-tbody'); if (appState.dynamics.length === 0) { tbody.innerHTML = ` 暂无数据,请点击"加载动态"获取数据 `; return; } tbody.innerHTML = appState.dynamics.map((item, index) => ` ${index + 1} ${getTypeLabel(item)}
${item.modules.module_dynamic.major && item.modules.module_dynamic.major.archive ? `` : '' }
${getContentTitle(item)}
${getContentDesc(item)}
${item.modules.module_author.pub_time}
`).join(''); // 绑定表格内的事件 bindTableEvents(); } // 绑定表格内的事件 function bindTableEvents() { // 绑定复选框事件 document.querySelectorAll('.item-checkbox').forEach(checkbox => { checkbox.addEventListener('change', function() { const index = parseInt(this.dataset.index); appState.dynamics[index].selected = this.checked; // 更新全选复选框状态 const allSelected = appState.dynamics.every(item => item.selected); const someSelected = appState.dynamics.some(item => item.selected); const selectAllCheckbox = document.getElementById('select-all-checkbox'); selectAllCheckbox.checked = allSelected; selectAllCheckbox.indeterminate = someSelected && !allSelected; }); }); // 绑定查看按钮事件 document.querySelectorAll('.view-btn').forEach(btn => { btn.addEventListener('click', function() { const index = parseInt(this.dataset.index); viewDynamic(appState.dynamics[index]); }); }); // 绑定删除按钮事件 document.querySelectorAll('.delete-btn').forEach(btn => { btn.addEventListener('click', function() { const index = parseInt(this.dataset.index); deleteDynamic(appState.dynamics[index]); }); }); // 绑定删除并取关按钮事件 document.querySelectorAll('.delete-unfollow-btn').forEach(btn => { btn.addEventListener('click', function() { const index = parseInt(this.dataset.index); deleteAndUnfollowDynamic(appState.dynamics[index]); }); }); } // 更新动态数量显示 function updateDynamicsCount() { document.getElementById('dynamics-count').textContent = `已加载: ${appState.dynamics.length} 条动态`; } // 勾选所有转发动态 function selectAllForward() { let forwardCount = 0; appState.dynamics.forEach(item => { if (item.type === 'DYNAMIC_TYPE_FORWARD') { item.selected = true; forwardCount++; } }); if (forwardCount === 0) { alert('暂无转发动态'); return; } // 更新表格中的复选框 const itemCheckboxes = document.querySelectorAll('.item-checkbox'); itemCheckboxes.forEach((cb, index) => { if (appState.dynamics[index] && appState.dynamics[index].type === 'DYNAMIC_TYPE_FORWARD') { cb.checked = true; } }); // 更新全选复选框状态 const allSelected = appState.dynamics.every(item => item.selected); const someSelected = appState.dynamics.some(item => item.selected); const selectAllCheckbox = document.getElementById('select-all-checkbox'); selectAllCheckbox.checked = allSelected; selectAllCheckbox.indeterminate = someSelected && !allSelected; alert(`已勾选 ${forwardCount} 条转发动态`); } // 勾选所有抽奖动态 function selectAllLottery() { let lotteryCount = 0; appState.dynamics.forEach(item => { // 检查是否是转发抽奖动态 if (item.type === 'DYNAMIC_TYPE_FORWARD' && item.orig && item.orig.modules && item.orig.modules.module_dynamic && item.orig.modules.module_dynamic.additional && item.orig.modules.module_dynamic.additional.type === 'ADDITIONAL_TYPE_UPOWER_LOTTERY') { item.selected = true; lotteryCount++; } }); if (lotteryCount === 0) { alert('暂无抽奖动态'); return; } // 更新表格中的复选框 const itemCheckboxes = document.querySelectorAll('.item-checkbox'); itemCheckboxes.forEach((cb, index) => { const item = appState.dynamics[index]; if (item && item.type === 'DYNAMIC_TYPE_FORWARD' && item.orig && item.orig.modules && item.orig.modules.module_dynamic && item.orig.modules.module_dynamic.additional && item.orig.modules.module_dynamic.additional.type === 'ADDITIONAL_TYPE_UPOWER_LOTTERY') { cb.checked = true; } }); // 更新全选复选框状态 const allSelected = appState.dynamics.every(item => item.selected); const someSelected = appState.dynamics.some(item => item.selected); const selectAllCheckbox = document.getElementById('select-all-checkbox'); selectAllCheckbox.checked = allSelected; selectAllCheckbox.indeterminate = someSelected && !allSelected; alert(`已勾选 ${lotteryCount} 条抽奖动态`); } // 获取类型标签 function getTypeLabel(item) { const type = item.type; // 处理转发动态 if (type === 'DYNAMIC_TYPE_FORWARD') { if (item.orig && item.orig.modules && item.orig.modules.module_dynamic) { const origDynamic = item.orig.modules.module_dynamic; // 检查是否是转发抽奖 if (origDynamic.additional && origDynamic.additional.type === 'ADDITIONAL_TYPE_UPOWER_LOTTERY') { return '转发抽奖'; } } return '转发'; } const typeMap = { 'DYNAMIC_TYPE_AV': '视频', 'DYNAMIC_TYPE_WORD': '文字', 'DYNAMIC_TYPE_DRAW': '图片', 'DYNAMIC_TYPE_ARTICLE': '文章', 'DYNAMIC_TYPE_MUSIC': '音频', 'DYNAMIC_TYPE_COMMON_SQUARE': '分享', 'DYNAMIC_TYPE_LIVE': '直播', 'DYNAMIC_TYPE_LIVE_RCMD': '直播推荐' }; return typeMap[type] || '其他'; } // 获取内容标题 function getContentTitle(item) { // 处理转发动态 if (item.type === 'DYNAMIC_TYPE_FORWARD') { if (item.modules.module_dynamic.desc && item.modules.module_dynamic.desc.text) { return `${item.modules.module_dynamic.desc.text}`; } // 如果转发没有文字,显示转发的原动态标题 if (item.orig) { const origTitle = getOriginalContentTitle(item.orig); return `转发:${origTitle}`; } return '转发动态'; } // 处理视频动态 if (item.modules.module_dynamic.major && item.modules.module_dynamic.major.archive) { return item.modules.module_dynamic.major.archive.title; } // 处理图片动态 if (item.modules.module_dynamic.major && item.modules.module_dynamic.major.opus) { if (item.modules.module_dynamic.major.opus.summary) { return item.modules.module_dynamic.major.opus.summary.text || '图片动态'; } } // 处理文字动态 if (item.modules.module_dynamic.desc && item.modules.module_dynamic.desc.text) { return item.modules.module_dynamic.desc.text; } return '无标题'; } // 获取原动态的标题(用于转发) function getOriginalContentTitle(origItem) { if (origItem.modules.module_dynamic.major && origItem.modules.module_dynamic.major.archive) { return origItem.modules.module_dynamic.major.archive.title; } if (origItem.modules.module_dynamic.major && origItem.modules.module_dynamic.major.opus) { if (origItem.modules.module_dynamic.major.opus.summary) { return origItem.modules.module_dynamic.major.opus.summary.text || '图片动态'; } } if (origItem.modules.module_dynamic.desc && origItem.modules.module_dynamic.desc.text) { return origItem.modules.module_dynamic.desc.text; } return '动态内容'; } // 获取内容描述 function getContentDesc(item) { // 处理转发动态 if (item.type === 'DYNAMIC_TYPE_FORWARD' && item.orig) { return getOriginalContentDesc(item.orig); } // 处理视频动态 if (item.modules.module_dynamic.major && item.modules.module_dynamic.major.archive) { return item.modules.module_dynamic.major.archive.desc || ''; } // 处理图片动态描述 if (item.modules.module_dynamic.major && item.modules.module_dynamic.major.opus) { return '图片动态'; } return ''; } // 获取原动态的描述(用于转发) function getOriginalContentDesc(origItem) { if (origItem.modules.module_dynamic.major && origItem.modules.module_dynamic.major.archive) { return origItem.modules.module_dynamic.major.archive.desc || ''; } if (origItem.modules.module_dynamic.major && origItem.modules.module_dynamic.major.opus) { return '图片动态'; } return ''; } // 查看动态 function viewDynamic(item) { // 处理视频动态 if (item.modules.module_dynamic.major && item.modules.module_dynamic.major.archive) { window.open(item.modules.module_dynamic.major.archive.jump_url, '_blank'); return; } // 处理转发动态 if (item.type === 'DYNAMIC_TYPE_FORWARD' && item.orig) { // 如果原动态是视频,跳转到视频 if (item.orig.modules.module_dynamic.major && item.orig.modules.module_dynamic.major.archive) { window.open(item.orig.modules.module_dynamic.major.archive.jump_url, '_blank'); return; } // 如果原动态是图片,跳转到图文 if (item.orig.modules.module_dynamic.major && item.orig.modules.module_dynamic.major.opus) { window.open(item.orig.modules.module_dynamic.major.opus.jump_url, '_blank'); return; } // 跳转到原动态 window.open(`https://t.bilibili.com/${item.orig.id_str}`, '_blank'); return; } // 处理图片动态 if (item.modules.module_dynamic.major && item.modules.module_dynamic.major.opus) { window.open(item.modules.module_dynamic.major.opus.jump_url, '_blank'); return; } // 默认跳转到动态页面 window.open(`https://t.bilibili.com/${item.id_str}`, '_blank'); } // 获取CSRF token function getCSRFToken() { const cookies = document.cookie.split(';'); for (let cookie of cookies) { const [name, value] = cookie.trim().split('='); if (name === 'bili_jct') { return value; } } return ''; } // 删除动态 async function deleteDynamic(item) { const title = getContentTitle(item); if (!confirm(`确定要删除这条动态吗?\n${title}`)) { return; } try { // 获取删除参数 const deleteParams = item.modules.module_more.three_point_items.find( item => item.type === 'THREE_POINT_DELETE' ); if (!deleteParams || !deleteParams.params) { alert('无法获取删除参数'); return; } const { dyn_id_str, dyn_type, rid_str } = deleteParams.params; const csrf = getCSRFToken(); if (!csrf) { alert('未登录或获取CSRF token失败,请先登录B站'); return; } // 调用删除API const response = await fetch( `https://api.bilibili.com/x/dynamic/feed/operate/remove?platform=web&csrf=${csrf}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': '*/*', 'Cache-Control': 'no-cache', 'Pragma': 'no-cache' }, credentials: 'include', body: JSON.stringify({ dyn_id_str, dyn_type, rid_str }) } ); const result = await response.json(); if (result.code === 0) { alert('删除成功!'); // 从本地数据中移除该动态 const index = appState.dynamics.findIndex(d => d.id_str === item.id_str); if (index > -1) { appState.dynamics.splice(index, 1); updateDynamicsTable(); updateDynamicsCount(); } } else { alert(`删除失败: ${result.message || '未知错误'}`); } } catch (error) { console.error('删除失败:', error); if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) { alert('删除失败:网络连接错误或跨域问题'); } else { alert(`删除失败: ${error.message}`); } } } // 批量删除动态 async function batchDeleteDynamics() { const selectedItems = appState.dynamics.filter(item => item.selected); if (selectedItems.length === 0) { alert('请先选择要删除的动态'); return; } if (!confirm(`确定要删除选中的 ${selectedItems.length} 条动态吗?此操作无法撤销!`)) { return; } const csrf = getCSRFToken(); if (!csrf) { alert('未登录或获取CSRF token失败,请先登录B站'); return; } const batchBtn = document.getElementById('batch-delete-btn'); const originalText = batchBtn.textContent; let successCount = 0; let failCount = 0; try { batchBtn.disabled = true; batchBtn.style.opacity = '0.6'; for (let i = 0; i < selectedItems.length; i++) { const item = selectedItems[i]; batchBtn.textContent = `删除中... (${i + 1}/${selectedItems.length})`; try { // 获取删除参数 const deleteParams = item.modules.module_more.three_point_items.find( item => item.type === 'THREE_POINT_DELETE' ); if (!deleteParams || !deleteParams.params) { console.warn(`动态 ${item.id_str} 无法获取删除参数`); failCount++; continue; } const { dyn_id_str, dyn_type, rid_str } = deleteParams.params; // 调用删除API const response = await fetch( `https://api.bilibili.com/x/dynamic/feed/operate/remove?platform=web&csrf=${csrf}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': '*/*', 'Cache-Control': 'no-cache', 'Pragma': 'no-cache' }, credentials: 'include', body: JSON.stringify({ dyn_id_str, dyn_type, rid_str }) } ); const result = await response.json(); if (result.code === 0) { successCount++; // 从本地数据中移除该动态 const index = appState.dynamics.findIndex(d => d.id_str === item.id_str); if (index > -1) { appState.dynamics.splice(index, 1); } } else { console.error(`删除动态 ${item.id_str} 失败:`, result.message); failCount++; } } catch (error) { console.error(`删除动态 ${item.id_str} 出错:`, error); failCount++; } // 添加延迟避免请求过于频繁 if (i < selectedItems.length - 1) { await new Promise(resolve => setTimeout(resolve, 1000)); } } // 更新UI updateDynamicsTable(); updateDynamicsCount(); // 显示结果 let message = `批量删除完成!\n成功: ${successCount} 条`; if (failCount > 0) { message += `\n失败: ${failCount} 条`; } alert(message); } catch (error) { console.error('批量删除失败:', error); alert(`批量删除失败: ${error.message}`); } finally { batchBtn.disabled = false; batchBtn.style.opacity = '1'; batchBtn.textContent = originalText; } } // 批量删除并取关 async function batchDeleteAndUnfollowDynamics() { const selectedItems = appState.dynamics.filter(item => item.selected); if (selectedItems.length === 0) { alert('请先选择要删除的动态'); return; } if (!confirm(`确定要删除选中的 ${selectedItems.length} 条动态并取关对应的用户吗?此操作无法撤销!`)) { return; } const csrf = getCSRFToken(); if (!csrf) { alert('未登录或获取CSRF token失败,请先登录B站'); return; } const batchBtn = document.getElementById('batch-delete-unfollow-btn'); const originalText = batchBtn.textContent; let deleteSuccessCount = 0; let unfollowSuccessCount = 0; let failCount = 0; const processedUsers = new Set(); // 记录已处理的用户,避免重复取关 try { batchBtn.disabled = true; batchBtn.style.opacity = '0.6'; for (let i = 0; i < selectedItems.length; i++) { const item = selectedItems[i]; batchBtn.textContent = `处理中... (${i + 1}/${selectedItems.length})`; try { // 获取删除参数 const deleteParams = item.modules.module_more.three_point_items.find( item => item.type === 'THREE_POINT_DELETE' ); if (!deleteParams || !deleteParams.params) { console.warn(`动态 ${item.id_str} 无法获取删除参数`); failCount++; continue; } const { dyn_id_str, dyn_type, rid_str } = deleteParams.params; // 调用删除API const deleteResponse = await fetch( `https://api.bilibili.com/x/dynamic/feed/operate/remove?platform=web&csrf=${csrf}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': '*/*', 'Cache-Control': 'no-cache', 'Pragma': 'no-cache' }, credentials: 'include', body: JSON.stringify({ dyn_id_str, dyn_type, rid_str }) } ); const deleteResult = await deleteResponse.json(); if (deleteResult.code === 0) { deleteSuccessCount++; // 删除成功,尝试取关目标作者 let targetAuthorUid = item.modules.module_author.mid; let targetAuthorName = item.modules.module_author.name; // 如果是转发动态,获取原动态的作者信息 if (item.type === 'DYNAMIC_TYPE_FORWARD' && item.orig && item.orig.modules && item.orig.modules.module_author) { targetAuthorUid = item.orig.modules.module_author.mid; targetAuthorName = item.orig.modules.module_author.name; } // 检查是否是自己的动态或者已经处理过这个用户 if (targetAuthorUid.toString() !== appState.uid && !processedUsers.has(targetAuthorUid)) { processedUsers.add(targetAuthorUid); const unfollowResult = await unfollowUser(targetAuthorUid); if (unfollowResult.success) { unfollowSuccessCount++; console.log(`成功取关用户 ${targetAuthorName} (${targetAuthorUid})`); } else { console.warn(`取关用户 ${targetAuthorName} (${targetAuthorUid}) 失败: ${unfollowResult.message}`); } // 添加取关操作间的延迟 await new Promise(resolve => setTimeout(resolve, 500)); } // 从本地数据中移除该动态 const index = appState.dynamics.findIndex(d => d.id_str === item.id_str); if (index > -1) { appState.dynamics.splice(index, 1); } } else { console.error(`删除动态 ${item.id_str} 失败:`, deleteResult.message); failCount++; } } catch (error) { console.error(`处理动态 ${item.id_str} 出错:`, error); failCount++; } // 添加延迟避免请求过于频繁 if (i < selectedItems.length - 1) { await new Promise(resolve => setTimeout(resolve, 1000)); } } // 更新UI updateDynamicsTable(); updateDynamicsCount(); // 显示结果 let message = `批量操作完成!\n删除动态成功: ${deleteSuccessCount} 条\n取关用户成功: ${unfollowSuccessCount} 个`; if (failCount > 0) { message += `\n失败: ${failCount} 条`; } alert(message); } catch (error) { console.error('批量删除并取关失败:', error); alert(`批量操作失败: ${error.message}`); } finally { batchBtn.disabled = false; batchBtn.style.opacity = '1'; batchBtn.textContent = originalText; } } // 取关用户 async function unfollowUser(uid) { const csrf = getCSRFToken(); if (!csrf) { throw new Error('未登录或获取CSRF token失败'); } try { const formData = new URLSearchParams(); formData.append('act', '2'); // 2表示取消关注 formData.append('fid', uid.toString()); formData.append('spmid', '333.1365'); formData.append('re_src', '0'); formData.append('csrf', csrf); const response = await fetch( 'https://api.bilibili.com/x/relation/modify?statistics=%7B%22appId%22:100,%22platform%22:5%7D', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*', 'Cache-Control': 'no-cache', 'Pragma': 'no-cache' }, credentials: 'include', body: formData } ); const result = await response.json(); if (result.code === 0) { return { success: true }; } else { return { success: false, message: result.message || '取关失败' }; } } catch (error) { return { success: false, message: error.message }; } } // 删除并取关动态 async function deleteAndUnfollowDynamic(item) { const title = getContentTitle(item); let targetAuthorName = item.modules.module_author.name; let targetAuthorUid = item.modules.module_author.mid; // 如果是转发动态,获取原动态的作者信息 if (item.type === 'DYNAMIC_TYPE_FORWARD' && item.orig && item.orig.modules && item.orig.modules.module_author) { targetAuthorName = item.orig.modules.module_author.name; targetAuthorUid = item.orig.modules.module_author.mid; } if (!confirm(`确定要删除这条动态并取关 "${targetAuthorName}" 吗?\n动态:${title}`)) { return; } try { // 先删除动态 const deleteParams = item.modules.module_more.three_point_items.find( item => item.type === 'THREE_POINT_DELETE' ); if (!deleteParams || !deleteParams.params) { alert('无法获取删除参数'); return; } const { dyn_id_str, dyn_type, rid_str } = deleteParams.params; const csrf = getCSRFToken(); if (!csrf) { alert('未登录或获取CSRF token失败,请先登录B站'); return; } // 调用删除API const deleteResponse = await fetch( `https://api.bilibili.com/x/dynamic/feed/operate/remove?platform=web&csrf=${csrf}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': '*/*', 'Cache-Control': 'no-cache', 'Pragma': 'no-cache' }, credentials: 'include', body: JSON.stringify({ dyn_id_str, dyn_type, rid_str }) } ); const deleteResult = await deleteResponse.json(); if (deleteResult.code === 0) { // 删除成功,尝试取关目标作者 // 检查是否是自己的动态,如果是则跳过取关 if (targetAuthorUid.toString() === appState.uid) { alert('删除成功!(跳过取关自己)'); } else { const unfollowResult = await unfollowUser(targetAuthorUid); if (unfollowResult.success) { alert(`删除动态并取关 "${targetAuthorName}" 成功!`); } else { alert(`删除动态成功,但取关失败: ${unfollowResult.message}`); } } // 从本地数据中移除该动态 const index = appState.dynamics.findIndex(d => d.id_str === item.id_str); if (index > -1) { appState.dynamics.splice(index, 1); updateDynamicsTable(); updateDynamicsCount(); } } else { alert(`删除失败: ${deleteResult.message || '未知错误'}`); } } catch (error) { console.error('删除并取关失败:', error); if (error.name === 'TypeError' && error.message.includes('Failed to fetch')) { alert('操作失败:网络连接错误或跨域问题'); } else { alert(`操作失败: ${error.message}`); } } } })();