Greasy Fork

来自缓存

班固米加一贴贴投票增加柱状图

自动识别贴贴投票,在主楼附上一个图。缺点是原理大概是无差别扫前五层,可能有错误识别。

// ==UserScript==
// @name         班固米加一贴贴投票增加柱状图
// @version      0.1
// @description  自动识别贴贴投票,在主楼附上一个图。缺点是原理大概是无差别扫前五层,可能有错误识别。
// @match        https://bgm.tv/group/topic/*
// @match        https://bamgumi.tv/group/topic/*
// @match        https://chii.in/group/topic/*
// @grant        none
// @namespace https://greasyfork.org/users/919437
// ==/UserScript==

(function () {
  'use strict';

  const replyList = $('#comment_list>div');
  let title = '';
  let options = [];

  // 为了适配所有情况,这里用比较蠢的暴力遍历
  // 直接递归一层寻找前五层所有有 +1 贴贴数大于 2 的回复或者子回复提取成投票选项
  replyList.slice(0, 5).each(function () {
    // 扫首层回复
    const cnt1 = getReplyElementPlusOneCnt($(this));
    if (cnt1 >= 2) {
      const messageDiv = $(this).find('.message');
      const messageContent = messageDiv.text();
      const option = messageContent.trim();
      const optionPair = [option, parseInt(cnt1)];
      options.push(optionPair);
    }

    // 递归扫一层
    const subReplyDivs = $(this).find('.topic_sub_reply>.sub_reply_bg');
    subReplyDivs.each(function () {
      const subReplyMsg = $(this).find('.cmt_sub_content');
      const subContent = subReplyMsg.text();

      // 统计帖帖: 1. 只统计 +1 类型帖帖的数量,应该是选择 data-like-value=140就行
      const cnt2 = getReplyElementPlusOneCnt($(this));
      if (cnt2 >= 2) {
        const option = subContent.trim();
        const optionPair = [option, parseInt(cnt2)];
        options.push(optionPair);
      }
    });
  });

  // log titile and opts
  console.log(title, options)

  // 先在主楼提供一个可视化投票的组件和投票按钮

  const votingComponent = createVotingComponent(title, options);
  // Append the voting component to the .postTopic div
  $('.postTopic').append(votingComponent);

  // 最后再移除 {vote} 楼层

})();

function getReplyElementPlusOneCnt(element) {
  const replyId = element.attr('id').slice(-7);

  const plusOneReactionCntElement = element.find('.item').
    filter('[data-like-value="140"]').filter(`[data-like-related-id="${replyId}"]`).find('.num');

  const cnt = plusOneReactionCntElement.text() || '0';
  return parseInt(cnt);
}

function createVotingComponent(title, votingData) {
  const maxVotes = Math.max(...votingData.map(option => option[1]));

  let html = `
      <style>
        .voting-container {
          display: flex;
          flex-direction: column;
          align-items: flex-start;
          width: 100%;
          max-width: 600px;
          margin: 0 auto;
          font-family: Arial, sans-serif;
          color: #555;
        }
  
        .voting-title {
          font-size: 20px;
          font-weight: bold;
          margin-bottom: 10px;
        }
  
        .voting-bar {
          display: flex;
          align-items: center;
          width: 100%;
          margin-bottom: 8px;
        }
  
        .bar {
          position: relative;
          height: 30px;
          background-color: #e0e0e0;
          border-radius: 15px;
          overflow: hidden;
          width: 70%;
        }
  
        .bar-fill {
          height: 100%;
          background-color: #9ccc65;
          border-radius: 15px;
          transition: width 0.3s ease;
        }
  
        .option-text {
          margin-left: 10px;
          font-size: 14px;
          color: #333;
        }
  
        .vote-count {
          margin-left: 10px;
          font-size: 14px;
          font-weight: bold;
        }
      </style>
      <div class="voting-container">
        <div class="voting-title">${title}</div>
    `;

  votingData.forEach(option => {
    const [optionText, voteCount] = option;
    const barWidth = (voteCount / maxVotes) * 100;

    html += `
        <div class="voting-bar">
          <div class="bar">
            <div class="bar-fill" style="width: ${barWidth}%"></div>
          </div>
          <span class="option-text">${optionText}</span>
          <span class="vote-count">${voteCount} votes</span>
        </div>
      `;
  });

  html += '</div>';

  return html;
}


// --- note ---

// 之前想写一个完全封装功能的,但是后面没动力写了,也感觉不是很有写的必要
// 这版算是 fork 了一个泛用性更强的,还是 enhanced 导向的脚本受众更多一点

// 这个其实也是矛盾的,如果只是简单的识别规则,那还是注定办法完美识别投票

// todo
// - [ ] 小 bug,回复里有引用的话(在楼中楼回复了另一个回复),最好去掉。暂时还没去掉