Skip to content

水群报告

1. 插件简介

插件名称 父类 触发关键词 触发权限 内容
ActReportPlugin StandardPlugin '-myact' None 获取本人水群报告

2. 示范样例

3. 代码分析

代码位于 plugins/groupActReport.py

class ActReportPlugin(StandardPlugin): 
    def judgeTrigger(self, msg:str, data:Any) -> bool:
        return msg == '-myact' and data['message_type'] == 'group'
    def executeEvent(self, msg:str, data:Any) -> Union[None, str]:
        imgPath = getMyActivity(data['user_id'], data['group_id'])
        imgPath = imgPath if os.path.isabs(imgPath) else os.path.join(ROOT_PATH, imgPath)
        send(data['group_id'], '[CQ:image,file=files://%s]'%imgPath, data['message_type'])
        return "OK"
    def getPluginInfo(self, )->Any:
        return {
            'name': 'ActReport',
            'description': '我的水群报告',
            'commandDescription': '-myact',
            'usePlace': ['group', ],
            'showInHelp': True,
            'pluginConfigTableNames': [],
            'version': '1.0.0',
            'author': 'Unicorn',
        }

def getMyActivity(user_id, group_id):
    messageNumber = 0
    messageWithBotNumber = 0
    messageDescript = ''
    messageMedal = []
    messageWithBotMedal = []
    messageImgEmjMedal = []
    try:
        mydb = mysql.connector.connect(**sqlConfig)
        mycursor = mydb.cursor()
        mycursor.execute("SELECT time, message FROM BOT_DATA.messageRecord where user_id=%d and group_id=%d"%(user_id, group_id))
        result=list(mycursor)
        # 消息数量
        messageNumber = len(result)
        # 消息-时间图
        time_mes = {}
        time_meswithbot = {}
        time_meswithimgemoji = {} #图片类动画表情
        st:datetime.datetime = result[0][0]
        et:datetime.datetime = result[-1][0]
        for time, message in result:
            time: datetime.datetime
            message: str
            message = message.strip()
            t = time.strftime('%Y-%m-%d')
            y = time_mes.get(t,0)
            y += 1
            time_mes[t] = y
            if startswith_in(message.strip(),['-ddl','-canvas','签到','祈愿','-help','-st','-lib','-hs','-mdd','-jwc','-dekt','-mc','-sjmc','-fdc','-tjmc','-mclive','-sjmclive','-fdmclive','小马,','小🦄,','小马,','小🦄,','-mycoins','-mytrans','决斗','接受决斗','ttzf','izf','-myact']):
                y = time_meswithbot.get(t,0)
                y += 1
                time_meswithbot[t] = y
            # pattern= re.compile(r'^\[CQ\:image\,file.*subType\=1\,.*\]')
            if ('[CQ:image,file' in message and 'subType=1' in message):
                y = time_meswithimgemoji.get(t,0)
                y += 1
                time_meswithimgemoji[t] = y
        ct:datetime.datetime = deepcopy(st)
        while (ct<et):
            ct += datetime.timedelta(days=1)
            if ct>datetime.datetime.now():
                break
            t = ct.strftime('%Y-%m-%d')
            y = time_mes.get(t,0)
            if y==0:
                time_mes[t] = 0
            y = time_meswithbot.get(t,0)
            if y==0:
                time_meswithbot[t] = 0
            y = time_meswithimgemoji.get(t,0)
            if y==0:
                time_meswithimgemoji[t] = 0
        # sorted(time_mes.keys())
        x_list = list(time_mes.keys())
        y_list = list(time_mes.values())
        x_list = [datetime.datetime.strptime(x,'%Y-%m-%d') for x in x_list]
        # 消息最多的天
        y_max = max(y_list)
        x_max = x_list[y_list.index(y_max)].strftime('%Y 年 %m 月 %d 日')
        # 平均消息
        y_avg = messageNumber / (int((et.date()-st.date()).days)+1)
        if (y_max <= 5):
            messageDescript = '你是本群的潜水员,日最多发送信息少于 5 条'
            messageMedal.append('🎖️ 资深潜水')
        else:
            if y_avg<15:
                messageDescript = '你在本群低调内敛,平均每日发送信息 %.2f 条'%(y_avg)
            elif y_avg<50:
                messageDescript = '你在本群比较活跃,平均每日发送信息 %.2f 条'%(y_avg)
            else:
                messageDescript = '你在本群侃侃而谈,平均每日发送信息 %.2f 条'%(y_avg)
                messageMedal.append('🎖️ 水群大师')
            messageDescript += '\n%s,你一共发送了 %d 条信息'%(x_max, y_max)
        if messageNumber >=3000:
            messageMedal.append('🎖️ 活跃元老')
        elif y_max >=300:
            messageMedal.append('🎖️ 谈天说地')

        plt.figure(figsize=(10, 3)) 
        plt.bar(x_list, y_list, color='#87CEEB')
        ax = plt.gca()
        ax.set_facecolor('#E8F8FF')
        plt.xticks(rotation=25,size=9)
        time_dis_path = BytesIO()
        plt.margins(0.002, 0.1)
        plt.subplots_adjust(top=1,bottom=0,left=0,right=1,hspace=0,wspace=0) 
        plt.savefig(time_dis_path, dpi=200, bbox_inches='tight')
        card_content1 = [
            ('subtitle','共发送信息 %d\n'%(messageNumber),PALETTE_SJTU_BLUE),
            ('separator',),
            ('illustration', time_dis_path),
            ('body', messageDescript)
        ]
        if len(messageMedal) > 0:
            card_content1.append(('subtitle', '  '.join(messageMedal), PALETTE_SJTU_BLUE))

        # Bot互动-时间图
        x_list = list(time_meswithbot.keys())
        y_list = list(time_meswithbot.values())
        x_list = [datetime.datetime.strptime(x,'%Y-%m-%d') for x in x_list]
        messageWithBotNumber = sum(y_list)

        # Bot互动-奖章
        if (messageWithBotNumber>=500):
            messageWithBotMedal.append('🎖️ 高级测试工程师')
        elif (messageWithBotNumber>=200):
            messageWithBotMedal.append('🎖️ 中级测试工程师')
        elif (messageWithBotNumber>=50):
            messageWithBotMedal.append('🎖️ 初级测试工程师')
        if (messageWithBotNumber / messageNumber > 0.4):
            messageWithBotMedal.append('🎖️ 信息熵操纵者')
        plt.figure(figsize=(10, 3)) 
        plt.bar(x_list, y_list, color='#F8AC51')
        ax = plt.gca()
        ax.set_facecolor('#FFEFDD')
        plt.xticks(rotation=25,size=9)
        time_dis2_path = BytesIO()
        plt.margins(0.002, 0.1)
        plt.subplots_adjust(top=1,bottom=0,left=0,right=1,hspace=0,wspace=0) 
        plt.savefig(time_dis2_path, dpi=200, bbox_inches='tight')
        card_content2 = [
            ('subtitle','与小🦄共互动 %d\n'%(messageWithBotNumber),PALETTE_SJTU_ORANGE),
            ('separator',),
            ('illustration', time_dis2_path)
        ]
        if len(messageWithBotMedal) > 0:
            card_content2.append(('subtitle', '  '.join(messageWithBotMedal), PALETTE_SJTU_ORANGE))

        # 图片信息-时间图
        x_list = list(time_meswithimgemoji.keys())
        y_list = list(time_meswithimgemoji.values())
        x_list = [datetime.datetime.strptime(x,'%Y-%m-%d') for x in x_list]
        messageImgEmojiNumber = sum(y_list)
        if (messageImgEmojiNumber>=500):
            messageImgEmjMedal.append('🎖️ 表情包之神')
        plt.figure(figsize=(10, 3)) 
        plt.bar(x_list, y_list, color='#7DC473')
        ax = plt.gca()
        ax.set_facecolor('#E5FBE2')
        plt.xticks(rotation=25,size=9)
        time_dis3_path = BytesIO()
        plt.margins(0.002, 0.1)
        plt.subplots_adjust(top=1,bottom=0,left=0,right=1,hspace=0,wspace=0) 
        plt.savefig(time_dis3_path, dpi=200, bbox_inches='tight')
        plt.close()
        card_content3 = [
            ('subtitle','共发送动画表情 %d\n'%(messageImgEmojiNumber),PALETTE_SJTU_GREEN),
            ('separator',),
            ('illustration', time_dis3_path)
        ]
        if len(messageImgEmjMedal) > 0:
            card_content3.append(('subtitle', '  '.join(messageImgEmjMedal), PALETTE_SJTU_GREEN))

        img_avatar = Image.open(BytesIO(get_avatar_pic(user_id)))
        # 生成卡片图
        ActCards = ResponseImage(
            titleColor = PALETTE_SJTU_BLUE,
            title = '我的水群报告',
            layout = 'normal',
            width = 880,
            cardBodyFont= ImageFont.truetype(os.path.join(FONTS_PATH, 'SourceHanSansCN-Medium.otf'), 24),
            cardSubtitleFont= ImageFont.truetype(os.path.join(FONTS_PATH, 'SourceHanSansCN-Medium.otf'), 30),
        )
        ActCards.addCardList([
            ResponseImage.RichContentCard(
                raw_content=[
                    ('subtitle','ID : %d'%(user_id)),
                    ('separator',),
                    ('keyword','群 : %d'%(group_id))
                ],
                icon = img_avatar
            ),
            ResponseImage.RichContentCard(
                raw_content = card_content1
            ),
            ResponseImage.RichContentCard(
                raw_content = card_content2
            ),
            ResponseImage.RichContentCard(
                raw_content = card_content3
            )
        ])
        save_path = (os.path.join(SAVE_TMP_PATH, f'{user_id}_{group_id}_actReport.png'))
        ActCards.generateImage(save_path)
        return save_path
    except mysql.connector.Error as e:
        warning("mysql error in getMyActivity: {}".format(e))
    except BaseException as e:
        warning("error in getMyActivity: {}".format(e))