豆瓣小组清新空气计划

抓取用户豆瓣黑名单,在后台存储并自动屏蔽黑名单用户的帖子

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name         豆瓣小组清新空气计划
// @version      0.0.2
// @license      MIT
// @namespace    https://greasyfork.org/users/1384897
// @description  抓取用户豆瓣黑名单,在后台存储并自动屏蔽黑名单用户的帖子
// @author       ✌
// @match        https://www.douban.com/group/*
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==
(function() {
  const utils = {
    // 通过 Tampermonkey 后台保存配置
    saveConfig: config => {
      GM_setValue('douban_group_enhance_config', config);
      console.log('保存黑名单到后台: ', config);
    },
    // 从 Tampermonkey 后台获取配置
    getConfig: () => {
      const config = GM_getValue('douban_group_enhance_config', { blackUserList: [] });
      console.log('从后台加载黑名单: ', config);
      return config;
    }
  }

  // 手动抓取豆瓣黑名单
  const fetchBlacklist = async () => {
    let start = 0;
    let userIdList = [];
    let hasNextPage = true;

    console.log('开始抓取豆瓣黑名单...');

    while (hasNextPage) {
      const url = `https://www.douban.com/contacts/blacklist?start=${start}`;
      console.log('请求黑名单页面: ', url);

      const response = await fetch(url, {
        credentials: 'include' // 保持登录状态
      });

      if (response.ok) {
        console.log('黑名单页面响应成功,解析中...');
        const text = await response.text();
        const parser = new DOMParser();
        const doc = parser.parseFromString(text, 'text/html');

        // 从页面中提取用户ID
        const userLinks = doc.querySelectorAll('dl.obu dd a');

        if (userLinks.length === 0) {
          console.log('没有找到更多用户,终止抓取。');
          break; // 没有更多用户数据,终止抓取
        }

        userLinks.forEach(link => {
          const userProfileUrl = link.getAttribute('href');
          const userId = userProfileUrl.split('/').filter(v => v).pop(); // 提取user_id
          userIdList.push(userId);
          console.log('抓取到用户ID: ', userId);
        });

        // 检查是否还有下一页
        hasNextPage = !!doc.querySelector('.next');
        start += 72; // 下一页的起始值增加
        console.log('是否有下一页: ', hasNextPage);
      } else {
        console.error('请求黑名单页面失败: ', response.status);
        hasNextPage = false; // 请求失败则终止抓取
      }
    }

    console.log('黑名单抓取完成: ', userIdList);
    return userIdList;
  }

  // 更新黑名单配置
  const updateBlacklistConfig = async () => {
    console.log('手动更新黑名单配置...');
    const blackUserIds = await fetchBlacklist();
    const config = { blackUserList: blackUserIds };

    utils.saveConfig(config); // 保存配置到 Tampermonkey 后台
    console.log("黑名单用户ID已更新: ", blackUserIds);
  }

  // 屏蔽用户功能
  const runFiltUser = (config) => {
    console.log('开始运行屏蔽用户功能...');
    $('.olt tr td:nth-child(2) a').each(function() {
      const $this = $(this);
      const userProfileUrl = $this.attr('href'); // 获取用户个人主页链接
      const userId = userProfileUrl.split('/').filter(v => v).pop(); // 提取用户ID
      const isBlackUser = id => (config.blackUserList || []).includes(id); // 使用ID判断是否在黑名单
      if (isBlackUser(userId)) {
        console.log("屏蔽首页发帖:", userId);
        $this.parents('tr').hide(); // 隐藏发帖行
      }
    });
  }

  // 帖子内屏蔽黑名单用户
  const runFilterBlackUser = (config, self) => {
    const userProfileUrl = self.find('h4 a').attr('href'); // 获取发帖用户的个人主页链接
    const userId = userProfileUrl.split('/').filter(v => v).pop(); // 提取user_id
    const isBlackUser = id => (config.blackUserList || []).includes(id);
    if (isBlackUser(userId)) {
      console.log("屏蔽回帖人: ", userId);
      self.hide(); // 隐藏发帖
      return;
    }

    const isFiltBeReplyedUser = config.filtBeReplyedBlackUser;
    if (isFiltBeReplyedUser) {
      const replyQuote = self.find('.reply-quote');
      if (replyQuote != null) {
        const replyProfileUrl = replyQuote.find('.reply-quote-content .pubdate a').attr('href');
        const replyUserId = replyProfileUrl.split('/').filter(v => v).pop(); // 回复的用户ID
        if (isBlackUser(replyUserId)) {
          console.log("屏蔽回复: ", replyUserId);
          self.hide(); // 隐藏回复
          return;
        }
      }
    }
  }

const addButtonToPage = () => {
    const buttonHtml = `
      <button id="updateBlacklistButton" style="position:fixed; bottom:20px; left:20px; padding:12px 20px; background-color:#409EFF; color:#fff; border:none; border-radius:5px; box-shadow:0 4px 8px rgba(0,0,0,0.1); font-size:14px; cursor:pointer; transition:background-color 0.3s ease;">
        更新黑名单
      </button>
      <div id="balloon" style="display:none; position:fixed; bottom:90px; left:20px; transform:translateX(10px); font-size:30px; letter-spacing:-5px; text-align:center;">
        🎈🎈🎈
      </div>
    `;
    $('body').append(buttonHtml);

    $('#updateBlacklistButton').hover(
      function() {
        $('#balloon').css('display', 'block').css('opacity', '1');
      },
      function() {
        $('#balloon').css('opacity', '0');
        setTimeout(() => {
          $('#balloon').css('display', 'none');
        }, 300);
      }
    );

    // 点击按钮时更新黑名单
    $('#updateBlacklistButton').click(async () => {
      $('#updateBlacklistButton').text('更新中...');
      await updateBlacklistConfig();
      $('#updateBlacklistButton').text('更新黑名单');
    });
  }

  // 脚本初始化
  const init = () => {
    console.log('初始化增强脚本...');
    const config = utils.getConfig(); // 从后台获取黑名单配置
    runFiltUser(config); // 屏蔽首页用户
    $('#comments li').each(function() {
      const $this = $(this);
      runFilterBlackUser(config, $this); // 屏蔽帖子内用户
    });
  }

  addButtonToPage();

  init();
})();