动态管理

动态管理页面

// ==UserScript==
// @name         动态管理
// @namespace    mscststs
// @version      0.31
// @description  动态管理页面
// @author       mscststs
// @match        https://space.bilibili.com/*
// @match        http://space.bilibili.com/*
// @require      https://greasyfork.runtimutd.eu.org/scripts/38220-mscststs-tools/code/MSCSTSTS-TOOLS.js?version=713767
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js
// @icon         https://static.hdslb.com/images/favicon.ico
// @license      MIT
// @grant        none
// ==/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 = `
        <div id="dynamic-manager" class="msc_panel" style="
          position: fixed;
          bottom: 20px;
          right: 20px;
          z-index: 9999;
        ">
          <button id="open-manager-btn" style="
            background: linear-gradient(135deg, #00b4d8, #0077b6);
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            transition: all 0.3s ease;
            box-shadow: 0 2px 8px rgba(0, 180, 216, 0.3);
          ">
            📊 动态管理
          </button>
          
          <!-- 管理面板弹窗 -->
          <div id="manager-modal" style="
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            z-index: 10000;
            display: none;
            align-items: center;
            justify-content: center;
          ">
            <div style="
              background: white;
              border-radius: 12px;
              width: 95%;
              max-width: 1400px;
              max-height: 90%;
              overflow: hidden;
              box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
            ">
              <!-- 头部 -->
              <div style="
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 20px 30px;
                border-bottom: 1px solid #e1e1e1;
                background: linear-gradient(135deg, #f8f9fa, #e9ecef);
              ">
                <h2 style="margin: 0; color: #333;">动态管理面板</h2>
                <button id="close-modal-btn" style="
                  background: none;
                  border: none;
                  font-size: 24px;
                  cursor: pointer;
                  color: #666;
                  width: 30px;
                  height: 30px;
                  display: flex;
                  align-items: center;
                  justify-content: center;
                  border-radius: 50%;
                  transition: all 0.2s;
                ">×</button>
              </div>
              
              <!-- 操作区域 -->
              <div style="padding: 20px 30px; border-bottom: 1px solid #e1e1e1;">
                <div style="display: flex; gap: 15px; align-items: center; flex-wrap: wrap;">
                  <div style="display: flex; align-items: center; gap: 10px;">
                    <label style="font-weight: 500; color: #333;">加载数量:</label>
                    <input 
                      id="load-count-input" 
                      type="number" 
                      min="1" 
                      max="100" 
                      value="20"
                      style="
                        width: 80px;
                        padding: 6px 10px;
                        border: 1px solid #ddd;
                        border-radius: 4px;
                        font-size: 14px;
                      "
                    >
                  </div>
                  <button 
                    id="load-dynamics-btn"
                    style="
                      background: #28a745;
                      color: white;
                      border: none;
                      padding: 8px 16px;
                      border-radius: 4px;
                      cursor: pointer;
                      font-size: 14px;
                      transition: all 0.2s;
                    "
                  >
                    加载动态
                  </button>
                  <button 
                    id="select-all-forward-btn"
                    style="
                      background: #17a2b8;
                      color: white;
                      border: none;
                      padding: 8px 16px;
                      border-radius: 4px;
                      cursor: pointer;
                      font-size: 14px;
                      margin-right: 10px;
                    "
                  >
                    勾选所有转发
                  </button>
                  <button 
                    id="select-all-lottery-btn"
                    style="
                      background: #fd7e14;
                      color: white;
                      border: none;
                      padding: 8px 16px;
                      border-radius: 4px;
                      cursor: pointer;
                      font-size: 14px;
                      margin-right: 10px;
                    "
                  >
                    勾选所有抽奖
                  </button>
                  <button 
                    id="batch-delete-btn"
                    style="
                      background: #dc3545;
                      color: white;
                      border: none;
                      padding: 8px 16px;
                      border-radius: 4px;
                      cursor: pointer;
                      font-size: 14px;
                      margin-right: 10px;
                    "
                  >
                    批量删除
                  </button>
                  <button 
                    id="batch-delete-unfollow-btn"
                    style="
                      background: #e74c3c;
                      color: white;
                      border: none;
                      padding: 8px 16px;
                      border-radius: 4px;
                      cursor: pointer;
                      font-size: 14px;
                      margin-right: 10px;
                    "
                  >
                    删除并取关
                  </button>
                  <button 
                    id="clear-data-btn"
                    style="
                      background: #dc3545;
                      color: white;
                      border: none;
                      padding: 8px 16px;
                      border-radius: 4px;
                      cursor: pointer;
                      font-size: 14px;
                    "
                  >
                    清空数据
                  </button>
                  <div id="dynamics-count" style="margin-left: auto; color: #666;">
                    已加载: 0 条动态
                  </div>
                </div>
              </div>
              
              <!-- 表格区域 -->
              <div style="padding: 0; max-height: 600px; overflow-y: auto;">
                <table id="dynamics-table" style="width: 100%; border-collapse: collapse; table-layout: fixed;">
                  <thead style="background: #f8f9fa; position: sticky; top: 0;">
                    <tr>
                      <th style="padding: 12px; text-align: left; border-bottom: 1px solid #ddd; font-weight: 600; width: 80px;">
                        <input 
                          type="checkbox" 
                          id="select-all-checkbox"
                          style="margin-right: 8px;"
                        >
                        选择
                      </th>
                      <th style="padding: 12px; text-align: left; border-bottom: 1px solid #ddd; font-weight: 600; width: 80px;">类型</th>
                      <th style="padding: 12px; text-align: left; border-bottom: 1px solid #ddd; font-weight: 600; width: 500px;">内容</th>
                      <th style="padding: 12px; text-align: left; border-bottom: 1px solid #ddd; font-weight: 600; width: 120px;">发布时间</th>
                      <th style="padding: 12px; text-align: left; border-bottom: 1px solid #ddd; font-weight: 600; width: 120px;">操作</th>
                    </tr>
                  </thead>
                  <tbody id="dynamics-tbody">
                    <tr>
                      <td colspan="5" style="padding: 40px; text-align: center; color: #999;">
                        暂无数据,请点击"加载动态"获取数据
                      </td>
                    </tr>
                  </tbody>
                </table>
              </div>
            </div>
          </div>
        </div>
      `;
  
      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 = `
          <tr>
            <td colspan="5" style="padding: 40px; text-align: center; color: #999;">
              暂无数据,请点击"加载动态"获取数据
            </td>
          </tr>
        `;
        return;
      }
      
      tbody.innerHTML = appState.dynamics.map((item, index) => `
        <tr style="border-bottom: 1px solid #eee;">
          <td style="padding: 12px;">
            <input 
              type="checkbox" 
              class="item-checkbox"
              data-index="${index}"
              ${item.selected ? 'checked' : ''}
              style="margin-right: 8px;"
            >
            ${index + 1}
          </td>
          <td style="padding: 12px;">
            <span style="
              display: inline-block;
              padding: 2px 8px;
              background: #e3f2fd;
              color: #1976d2;
              border-radius: 12px;
              font-size: 12px;
              white-space: nowrap;
            ">
              ${getTypeLabel(item)}
            </span>
          </td>
          <td style="padding: 12px; word-wrap: break-word; overflow: hidden;">
            <div style="display: flex; align-items: center; gap: 10px;">
              ${item.modules.module_dynamic.major && item.modules.module_dynamic.major.archive ? 
                `<img src="${item.modules.module_dynamic.major.archive.cover}" style="width: 60px; height: 40px; object-fit: cover; border-radius: 4px; flex-shrink: 0;">` : ''
              }
              <div style="overflow: hidden; flex: 1; min-width: 0;">
                <div style="font-weight: 500; margin-bottom: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="${getContentTitle(item)}">
                  ${getContentTitle(item)}
                </div>
                <div style="font-size: 12px; color: #666; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;" title="${getContentDesc(item)}">
                  ${getContentDesc(item)}
                </div>
              </div>
            </div>
          </td>
          <td style="padding: 12px; color: #666; font-size: 14px; white-space: nowrap;">
            ${item.modules.module_author.pub_time}
          </td>
          <td style="padding: 12px;">
            <div style="display: flex; gap: 8px;">
              <button 
                class="view-btn"
                data-index="${index}"
                style="
                  background: #007bff;
                  color: white;
                  border: none;
                  padding: 4px 8px;
                  border-radius: 3px;
                  cursor: pointer;
                  font-size: 12px;
                  white-space: nowrap;
                "
              >
                查看
              </button>
              <button 
                class="delete-btn"
                data-index="${index}"
                style="
                  background: #dc3545;
                  color: white;
                  border: none;
                  padding: 4px 8px;
                  border-radius: 3px;
                  cursor: pointer;
                  font-size: 12px;
                  white-space: nowrap;
                "
              >
                删除
              </button>
              <button 
                class="delete-unfollow-btn"
                data-index="${index}"
                style="
                  background: #e74c3c;
                  color: white;
                  border: none;
                  padding: 4px 6px;
                  border-radius: 3px;
                  cursor: pointer;
                  font-size: 12px;
                  white-space: nowrap;
                "
              >
                删除并取关
              </button>
            </div>
          </td>
        </tr>
      `).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}`);
        }
      }
    }
  
  })();