1. 程式人生 > 其它 >Nonebot2外掛:逝世表情包(1)

Nonebot2外掛:逝世表情包(1)

前言已經懶得寫辣,總之把入門教程官方文件都看一遍

純小白,排版混亂,邏輯重複,程式碼屎山,隨時跑路

廣告 長期招租,快來404群玩(720053992)

0.廢話文集

搓表情包的想法之前看群裡的bot可以生成就好想搞了,只是一直鴿——

總之官方商店裡有強大的petpet和memes兩個外掛,已經足夠滿足大部分的表情包生成需求了(實際看下來常用的就兩三個)


總而言之,這篇將會是實現的是下面這個表情包

0.5 水準備

使用了python的PIL(pillow)庫來生成圖片,(openCV的對著類似實現函式做下就好了吧)

用到了requests庫(用於獲取使用者頭像)

1.startswith!

設定的指令觸發格式為"設定的命令起始符+找+@使用者/qq號碼+需要填寫的欄位(非必須)"

使用on_command()

作為事件響應器

大概前面
import nonebot
import requests
from nonebot.rule import *
from nonebot import *
from nonebot.plugin import on_keyword
from nonebot.adapters.onebot.v11 import Bot, Event, MessageEvent, GroupMessageEvent
from nonebot.adapters.onebot.v11.message import Message
import os
import re
import PIL
from PIL import Image, ImageDraw, ImageFont


async def handle_rule(bot: Bot, event: Event) -> bool:
    with open("白名單群聊txt", encoding='utf-8') as file:  # 提取白名單群檔案中的群號
        white_block = []
        for line in file:
            line = line.strip()
            line = re.split("[ |#]", line)  # 可能會有'#'註釋或者空格分割
            white_block.append(line[0])  # 新建一個表給它扔進去
    try:
        whatever, group_id, user_id = event.get_session_id().split('_')  # 獲取當前群聊id,發起人id,返回的格式為group_groupid_userid
    except:  # 如果上面報錯了,意味著發起的是私聊,返回格式為userid
        group_id = None
        user_id = event.get_session_id()
    if group_id in white_block or group_id == None:
        return True
    else:
        return False


ct_pic_find = on_command({"找"}, rule=handle_rule, priority=50)


@ct_pic_find.handle()
async def ct_pic_find_handle(bot: Bot, event: Event):
    try:
        whatever, group_id, user_id = event.get_session_id().split('_')  # 獲取當前群聊id,發起人id,返回的格式為group_groupid_userid
        data = await bot.call_api('get_group_member_list', **{
            'group_id': int(group_id)
        })
    except:  # 如果上面報錯了,意味著發起的是私聊,返回格式為userid
        group_id = None
        user_id = event.get_session_id()
    find_message = str(event.get_message()).replace('/找', '').split()
    '''
    nb2會過濾訊息段中的第一個@自己的訊息,所以那自己bot試的注意下(比如我查了半天報錯)
    上面這段按照指令格式進行分段
    '''
    if "[CQ" in find_message[0]:  # 簡單粗暴地判斷下第一個分類是不是@類
        for sbwwww in event.get_message():
            if sbwwww.type == 'at':
                pic_id = sbwwww.data['qq']
                break  # 讀取完第一個退出即可
        '''
        Nb2的Messagement類會可以直接提取cq碼的型別
        這樣就可以直接獲取@的物件了
        https://github.com/botuniverse/onebot-11/tree/master/message
        Nb2的Message適配Onebot v11協議,所以好好看看上面的文件吧
        同樣的,file(圖片快取名稱和地址),flash(閃照)等等都會用到
        下面這段是還沒啃透時自己的寫法,使用正則匹配獲取@的id號碼(要用\轉義下[])
        pic_id = re.search('(?<=\[CQ:at,qq=).*?(?=\])', find_message[0]).group()
        '''
    else:  # 如果不是@的人的形式,判斷是否為中間給定的是否為QQ號的形式
        try:
            if find_message[0].isnumeric():  # 判斷是否為全為數字字元
                pic_id = find_message[0]
            else:
                await ct_pic_find.finish(Message("你找誰啊...."))
        except:
            await ct_pic_find.finish(Message("你找誰啊...."))
    try:
        pic_name = find_message[1]  # 接著獲取名字(請問看見xxx了嗎)
    except:
        pic_name = ''
    if pic_name == '':  # 如果使用者沒有輸入想要生成的名字,那麼預設為群聊暱稱,其次為QQ暱稱
        if isinstance(event, GroupMessageEvent):  # 判斷是否為群聊事件
            for j in data:
                if str(j['user_id']) == pic_id:  # 如果想找的人在群聊內
                    if j['card'] != '':  # 判斷是否存在群暱稱,並賦值
                        pic_name = j['card']
                    else:
                        pic_name = j['nickname']
        if pic_name == '':  # 如果是私聊事件或者不在群聊內
            data = await bot.call_api('get_stranger_info',
                                      **{'user_id': int(pic_id)})  # 參考go-cqhttp的官方api說明,獲取陌生人的相關個人資料
            pic_name = data['nickname']
    user_name = pic_name

接著來對圖片進行處理,示例中的表情包是(900,800),其中使用者頭像為(600,600),字號使用為("simhei", 50)

點我看程式碼~
user_url = f"http://q1.qlogo.cn/g?b=qq&nk={pic_id}&s=640"
'''
這個url獲取的是任意一個使用者的高清頭像,pic_id就是指定的QQ號,之後會常用
'''
picfile = requests.get(user_url)
open(f"你頭像圖片存放的地址", "wb").write(picfile.content)  # 從網上下載圖片並儲存到本地,若存在會覆寫的
user_pic = Image.open(f"你頭像圖片存放的地址") # 準備複製
user_image = Image.new(mode="RGB", size=(900, 800), color="white") # 生成一塊900*800的白色畫布,具體自己定
user_pic = user_pic.resize((600, 600)) # 把獲取到的使用者圖片resize一下,因為大部分圖片並不是600*600
user_image.paste(user_pic, (150, 100)) # 放到指定位置,按照自己預留給文字的位置算一下(下面所有的涉及到位置的都建議使用自己的喜好)
# 新增文字
draw = ImageDraw.Draw(user_image)
font = ImageFont.truetype("simhei", 50)
word = f'請問你們看見{user_name}了嗎' # 文案自己定
w, h = font.getsize(word) # 獲取指定大小和文字後的欄位長度,用於生成居中字型
# 引數:位置、文字、填充、字型
draw.text(xy=((900 - w) / 2, (100 - h) / 2), text=word, fill='black', font=font)
word = '非常可愛,簡直是小天使,讓大家都看看'
w, h = font.getsize(word)
draw.text(xy=((900 - w) / 2, 700 + (100 - h) / 2), text=word, fill='black', font=font)
user_image.save(f"生成完的表情包存放的地址")
user_url = f"file:///生成完的表情包存放的地址"
await ct_pic_find.finish(Message(f"[CQ:image,file={user_url},id=40000]"))

示例:大概就頭圖吧

2.大概問題

  1. 頭像的位置大小和想要生成的字型型別都可以按照自己的需求改,只要計算預留出足夠的空間即可
  2. 考慮到有的群友id實屬逆天(的長度),生成第一行的時候可以考慮先獲取總共的位元組數,然後按照預留的寬度大小計算出最適合的字型大小(不過更簡單的是按比例直接生成更大的畫布?)
  3. 對id中的特殊字元不太適應