// ==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}`);
}
}
}
})();