diff --git a/Guess_voice/__init__.py b/Guess_voice/__init__.py index ea139bb..33cf6a7 100644 --- a/Guess_voice/__init__.py +++ b/Guess_voice/__init__.py @@ -1,16 +1,17 @@ import asyncio -from . import util -from typing import Union from pathlib import Path -from nonebot import on_command -from nonebot.permission import SUPERUSER -from nonebot.params import CommandArg -from nonebot.exception import FinishedException -from nonebot.adapters.onebot.v11 import PrivateMessageEvent, GroupMessageEvent, MessageSegment, Bot, permission -from .handler import Guess, get_random_voice -from . import download_data -from ..utils.config import config +from typing import Union +from nonebot import on_command +from nonebot.adapters.onebot.v11 import PrivateMessageEvent, GroupMessageEvent, MessageSegment, Bot +from nonebot.exception import FinishedException +from nonebot.params import CommandArg +from nonebot.permission import SUPERUSER + +from utils.config import config +from . import download_data +from . import util +from .handler import Guess, get_random_voice setting_time = config.paimon_guess_voice # 游戏持续时间 diff --git a/Guess_voice/download_data.py b/Guess_voice/download_data.py index 6ea8fb8..b8fdc08 100644 --- a/Guess_voice/download_data.py +++ b/Guess_voice/download_data.py @@ -6,12 +6,13 @@ import json import os from pathlib import Path -from bs4 import BeautifulSoup -from sqlitedict import SqliteDict # TODO 加入requirements -from .util import get_path -from nonebot import logger -from ..utils.http_util import aiorequests +from bs4 import BeautifulSoup +from nonebot import logger +from sqlitedict import SqliteDict # TODO 加入requirements + +from utils import aiorequests +from .util import get_path # OUT_PUT = Path(__file__).parent / 'voice' OUT_PUT = Path() / 'data' / 'LittlePaimon' / 'guess_voice' / 'voice' diff --git a/Guess_voice/handler.py b/Guess_voice/handler.py index 9adce8c..4363dc2 100644 --- a/Guess_voice/handler.py +++ b/Guess_voice/handler.py @@ -1,19 +1,20 @@ -import os -import random import datetime import json -from apscheduler.triggers.date import DateTrigger -from typing import List +import os +import random from pathlib import Path +from typing import List + +from apscheduler.triggers.date import DateTrigger from nonebot import get_bot, require, logger -from nonebot.adapters.onebot.v11 import MessageSegment, escape -from sqlitedict import SqliteDict -from .util import get_path, require_file -from nonebot.rule import Rule from nonebot import on_regex from nonebot.adapters.onebot.v11 import GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageSegment, escape +from nonebot.rule import Rule +from sqlitedict import SqliteDict from .download_data import voice_list_by_mys, voice_detail_by_mys +from .util import get_path, require_file scheduler = require('nonebot_plugin_apscheduler').scheduler diff --git a/Guess_voice/util.py b/Guess_voice/util.py index e1d575d..f638cd6 100644 --- a/Guess_voice/util.py +++ b/Guess_voice/util.py @@ -1,7 +1,9 @@ import os from pathlib import Path + import aiofiles -from ..utils.http_util import aiorequests + +from utils import aiorequests def get_path(dirname, filename): diff --git a/Paimon_Chat/__init__.py b/Paimon_Chat/__init__.py index 30cb3f9..c1c0120 100644 --- a/Paimon_Chat/__init__.py +++ b/Paimon_Chat/__init__.py @@ -1,13 +1,14 @@ -from nonebot import on_regex, logger -from nonebot.exception import FinishedException -from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageSegment -from ..utils.util import FreqLimiter2 -from ..utils.config import config -from .chat_list import chat_list -from pathlib import Path -import random import os +import random +from pathlib import Path +from nonebot import on_regex, logger +from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageSegment +from nonebot.exception import FinishedException + +from utils.config import config +from utils.auth_util import FreqLimiter2 +from .chat_list import chat_list res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res', 'voice') chat_lmt = FreqLimiter2(60) diff --git a/Paimon_Gacha/__init__.py b/Paimon_Gacha/__init__.py index e4dc564..c198e71 100644 --- a/Paimon_Gacha/__init__.py +++ b/Paimon_Gacha/__init__.py @@ -1,13 +1,15 @@ import re +from typing import Dict, Union + +from nonebot import on_command, on_regex +from nonebot.adapters.onebot.v11 import MessageSegment, MessageEvent, GroupMessageEvent +from nonebot.params import RegexDict + +from utils.config import config +from utils import aiorequests +from utils.auth_util import FreqLimiter from .gacha_info import * from .gacha_res import more_ten -from ..utils.config import config -from ..utils.util import FreqLimiter -from ..utils.http_util import aiorequests -from typing import Dict, Union -from nonebot import on_command, on_regex -from nonebot.params import RegexDict -from nonebot.adapters.onebot.v11 import MessageSegment, MessageEvent, GroupMessageEvent __usage__ = ''' 1.[抽n十连xx池]抽n次xx池的十连,最多同时5次 diff --git a/Paimon_Gacha/gacha_info.py b/Paimon_Gacha/gacha_info.py index fe604f0..753cc7b 100644 --- a/Paimon_Gacha/gacha_info.py +++ b/Paimon_Gacha/gacha_info.py @@ -1,5 +1,5 @@ import os -import json +from utils.file_handler import load_json, save_json RES_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res', 'gacha_res') USER_INFO_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'user_data', 'user_gacha_info.json') @@ -8,35 +8,15 @@ ROLE_2_PATH = os.path.join(RES_PATH, "DIY_gacha_pool", "role_2.json") WEAPON_PATH = os.path.join(RES_PATH, "DIY_gacha_pool", "weapon.json") All_STAR_PATH = os.path.join(RES_PATH, "DIY_gacha_pool", "all_star.json") -user_info = {} -role_1_pool = {} -role_2_pool = {} -weapon_pool = {} -all_star = {} +user_info = load_json(path=USER_INFO_PATH) +role_1_pool = load_json(path=ROLE_1_PATH) +role_2_pool = load_json(path=ROLE_2_PATH) +weapon_pool = load_json(path=WEAPON_PATH) +all_star = load_json(path=All_STAR_PATH) def save_user_info(): - with open(USER_INFO_PATH, 'w', encoding='UTF-8') as f: - json.dump(user_info, f, ensure_ascii=False) - - -if not os.path.exists(USER_INFO_PATH): - save_user_info() - -with open(USER_INFO_PATH, 'r', encoding='UTF-8') as f: - user_info = json.load(f) - -with open(ROLE_1_PATH, 'r', encoding='UTF-8') as f: - role_1_pool = json.load(f) - -with open(ROLE_2_PATH, 'r', encoding='UTF-8') as f: - role_2_pool = json.load(f) - -with open(WEAPON_PATH, 'r', encoding='UTF-8') as f: - weapon_pool = json.load(f) - -with open(All_STAR_PATH, 'r', encoding='UTF-8') as f: - all_star = json.load(f) + save_json(data=user_info, path=USER_INFO_PATH) def init_user_info(uid: str): diff --git a/Paimon_Gacha/gacha_res.py b/Paimon_Gacha/gacha_res.py index e65c0ac..c0aec65 100644 --- a/Paimon_Gacha/gacha_res.py +++ b/Paimon_Gacha/gacha_res.py @@ -1,13 +1,13 @@ +import datetime import json import os - -import datetime -import numpy import random + +import numpy from PIL import Image, PngImagePlugin, ImageDraw, ImageFont +from utils.message_util import MessageBuild from .gacha_info import init_user_info, user_info, save_user_info -from ..utils.util import pil2b64 RES_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res', 'gacha_res') font_path = os.path.join(RES_PATH, 'zh-cn.ttf') @@ -117,7 +117,6 @@ def once(uid, gacha_data): user_info[uid]["gacha_list"]["wish_%s_up" % rank] += 1 role['rank'] = rank else: - role = random.choice(gacha_data['r%s_prob_list' % rank]) while True: role = random.choice(gacha_data['r%s_prob_list' % rank]) if role['is_up'] == 0: @@ -246,4 +245,5 @@ async def more_ten(uid, gacha_data, num, sd): draw = ImageDraw.Draw(img) draw.text((27, 575 * num - 30), ('@%s %s Created By LittlePaimon' % (str(sd.nickname), time_str)), font=time_font, fill="#8E8E8E") - return pil2b64(img, 75) + + return MessageBuild.Image(img, quality=75) diff --git a/Paimon_Gacha_Log/UIGF_and_XLSX.py b/Paimon_Gacha_Log/UIGF_and_XLSX.py index cdbc1b9..a069d34 100644 --- a/Paimon_Gacha_Log/UIGF_and_XLSX.py +++ b/Paimon_Gacha_Log/UIGF_and_XLSX.py @@ -1,8 +1,10 @@ -from .meta_data import * -import time import os +import time + import xlsxwriter +from .meta_data import * + data_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'user_data', 'gacha_log_data') diff --git a/Paimon_Gacha_Log/__init__.py b/Paimon_Gacha_Log/__init__.py index 29f6122..fc4a6a3 100644 --- a/Paimon_Gacha_Log/__init__.py +++ b/Paimon_Gacha_Log/__init__.py @@ -2,13 +2,16 @@ import json import os import re from typing import Union + from nonebot import on_command -from nonebot.params import CommandArg from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent, GroupMessageEvent -from ..utils.util import get_uid_in_msg +from nonebot.params import CommandArg + +from utils.message_util import get_uid_in_msg +from .api import toApi, checkApi from .gacha_logs import get_data from .get_img import get_gacha_log_img -from .api import toApi, checkApi +from pathlib import Path __usage__ = ''' 1.[获取抽卡记录 (uid) (url)]提供url,获取原神抽卡记录,需要一定时间 diff --git a/Paimon_Gacha_Log/api.py b/Paimon_Gacha_Log/api.py index c909d87..01d470e 100644 --- a/Paimon_Gacha_Log/api.py +++ b/Paimon_Gacha_Log/api.py @@ -1,5 +1,6 @@ from urllib import parse -from ..utils.http_util import aiorequests + +from utils import aiorequests def toApi(url): diff --git a/Paimon_Gacha_Log/gacha_logs.py b/Paimon_Gacha_Log/gacha_logs.py index 994d9e8..c42f1d6 100644 --- a/Paimon_Gacha_Log/gacha_logs.py +++ b/Paimon_Gacha_Log/gacha_logs.py @@ -1,10 +1,11 @@ -import os import json +import os from asyncio import sleep + +from utils import aiorequests +from .UIGF_and_XLSX import convertUIGF, writeXLSX from .api import getApi from .meta_data import gachaQueryTypeIds, gachaQueryTypeDict -from .UIGF_and_XLSX import convertUIGF, writeXLSX -from ..utils.http_util import aiorequests data_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'user_data', 'gacha_log_data') diff --git a/Paimon_Gacha_Log/get_img.py b/Paimon_Gacha_Log/get_img.py index eb23d38..13eabbd 100644 --- a/Paimon_Gacha_Log/get_img.py +++ b/Paimon_Gacha_Log/get_img.py @@ -1,8 +1,9 @@ -from PIL import Image, ImageDraw, ImageFont import os -from ..utils.util import pil2b64 -from ..utils.character_alias import get_short_name -from nonebot.adapters.onebot.v11 import MessageSegment + +from PIL import Image, ImageDraw, ImageFont + +from utils.character_alias import get_short_name +from utils.message_util import MessageBuild res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res') @@ -120,7 +121,7 @@ async def get_gacha_log_img(gacha_data, pool): break if not img: return '这个池子没有抽卡记录哦' - total_height = (img.size)[1] + total_height = img.size[1] else: img_list = [] total_height = 0 @@ -129,17 +130,15 @@ async def get_gacha_log_img(gacha_data, pool): p_img = await draw_gacha_log(pd) if p_img: img_list.append(p_img) - total_height += (p_img.size)[1] + total_height += p_img.size[1] if not img_list: return '没有找到任何抽卡记录诶!' img = Image.new('RGBA', (768, total_height), (0, 0, 0, 255)) for i in img_list: img.paste(i, (0, now_height)) - now_height += (i.size)[1] + now_height += i.size[1] img_draw = ImageDraw.Draw(img) img_draw.text((595, 44), f'UID:{gacha_data["uid"]}', font=get_font(16), fill='black') img_draw.text((530, total_height - 45), 'Created by LittlePaimon', font=get_font(16), fill='black') - img = pil2b64(img, 95) - img = MessageSegment.image(img) - return img + return MessageBuild.Image(img) diff --git a/Paimon_Info/__init__.py b/Paimon_Info/__init__.py index a63c58a..48adc97 100644 --- a/Paimon_Info/__init__.py +++ b/Paimon_Info/__init__.py @@ -1,27 +1,31 @@ import datetime -import re import random -from collections import defaultdict +import re from asyncio import sleep +from collections import defaultdict + from nonebot import on_command, require, logger, get_bot -from nonebot.params import CommandArg -from nonebot.rule import to_me -from nonebot.permission import SUPERUSER from nonebot.adapters.onebot.v11 import MessageEvent, Message, Bot -from .get_data import get_bind_game, get_sign_info, sign, get_sign_list, get_abyss_data, get_daily_note_data -from .get_data import get_monthinfo_data, get_player_card_data, get_chara_detail_data, get_chara_skill_data +from nonebot.params import CommandArg +from nonebot.permission import SUPERUSER +from nonebot.rule import to_me + +from utils.character_alias import get_id_by_alias +from utils.config import config +from utils.db_util import get_auto_sign, delete_auto_sign +from utils.db_util import insert_public_cookie, update_private_cookie, delete_cookie_cache, delete_private_cookie, \ + update_last_query, reset_public_cookie +from utils.db_util import update_note_remind2, update_note_remind, get_note_remind, delete_note_remind, \ + update_day_remind_count, get_private_cookie, add_auto_sign +from utils.auth_util import check_cookie +from utils.decorator import exception_handler +from utils.message_util import get_uid_in_msg from .draw_abyss_info import draw_abyss_card from .draw_daily_note import draw_daily_note_card from .draw_month_info import draw_monthinfo_card from .draw_player_card import draw_player_card, draw_all_chara_card, draw_chara_card -from ..utils.character_alias import get_id_by_alias -from ..utils.util import get_uid_in_msg, check_cookie, exception_handler -from ..utils.db_util import update_note_remind2, update_note_remind, get_note_remind, delete_note_remind, \ - update_day_remind_count, get_private_cookie, add_auto_sign -from ..utils.db_util import insert_public_cookie, update_private_cookie, delete_cookie_cache, delete_private_cookie, \ - update_last_query, reset_public_cookie -from ..utils.db_util import get_auto_sign, delete_auto_sign -from ..utils.config import config +from .get_data import get_bind_game, get_sign_info, sign, get_sign_list, get_abyss_data, get_daily_note_data +from .get_data import get_monthinfo_data, get_player_card_data, get_chara_detail_data, get_chara_skill_data scheduler = require('nonebot_plugin_apscheduler').scheduler diff --git a/Paimon_Info/draw_abyss_info.py b/Paimon_Info/draw_abyss_info.py index 46185bb..b4b5506 100644 --- a/Paimon_Info/draw_abyss_info.py +++ b/Paimon_Info/draw_abyss_info.py @@ -1,9 +1,10 @@ import datetime import os + from PIL import Image, ImageDraw, ImageFont -from nonebot.adapters.onebot.v11 import MessageSegment -from ..utils.util import pil2b64 -from ..utils.http_util import aiorequests + +from utils import aiorequests +from utils.message_util import MessageBuild res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res') @@ -189,6 +190,4 @@ async def draw_abyss_card(data, uid, floor_num): total_img.alpha_composite(floor_img, (5, 5 + 524 + 5 + h)) h += 1210 - total_img = pil2b64(total_img, 75) - total_img = MessageSegment.image(total_img) - return total_img + return MessageBuild.Image(total_img, quality=75) diff --git a/Paimon_Info/draw_daily_note.py b/Paimon_Info/draw_daily_note.py index 32abbe4..148de61 100644 --- a/Paimon_Info/draw_daily_note.py +++ b/Paimon_Info/draw_daily_note.py @@ -1,11 +1,12 @@ -import random import datetime import os -from PIL import Image, ImageDraw, ImageFont +import random + import matplotlib.pyplot as plt -from nonebot.adapters.onebot.v11 import MessageSegment -from ..utils.util import pil2b64 -from ..utils.http_util import aiorequests +from PIL import Image, ImageDraw, ImageFont + +from utils import aiorequests +from utils.message_util import MessageBuild res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res') @@ -147,7 +148,4 @@ async def draw_daily_note_card(data, uid): bg_img.alpha_composite(role_img, (1220, 200)) now = datetime.datetime.now().strftime('%m月%d日%H:%M') bg_draw.text((554, 1794), 'Created by LittlePaimon·' + now, fill='#5680d2', font=get_font(40, '优设标题黑.ttf')) - bg_img = bg_img.resize((int(bg_img.size[0] * 0.35), int(bg_img.size[1] * 0.35)), Image.ANTIALIAS) - bg_img = pil2b64(bg_img, 70) - bg_img = MessageSegment.image(bg_img) - return bg_img + return MessageBuild.Image(bg_img, size=0.35, quality=70) diff --git a/Paimon_Info/draw_month_info.py b/Paimon_Info/draw_month_info.py index 65731f9..f7a6b8b 100644 --- a/Paimon_Info/draw_month_info.py +++ b/Paimon_Info/draw_month_info.py @@ -1,9 +1,9 @@ -import random -from PIL import Image, ImageDraw, ImageFont import os +import random + import matplotlib.pyplot as plt -from ..utils.util import pil2b64 -from nonebot.adapters.onebot.v11 import MessageSegment +from PIL import Image, ImageDraw, ImageFont +from utils.message_util import MessageBuild res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res') @@ -111,6 +111,4 @@ async def draw_monthinfo_card(data): bg_draw.text((49, 857), f'本月相比上个月,原石{ysstr},摩拉{mlstr}', font=get_font(23), fill='#27384C') bg_draw.text((167, 900), 'Created by LittlePaimon', font=get_font(21), fill='#27384C') - bg_img = pil2b64(bg_img, 70) - bg_img = MessageSegment.image(bg_img) - return bg_img + return MessageBuild.Image(bg_img, quality=70) diff --git a/Paimon_Info/draw_player_card.py b/Paimon_Info/draw_player_card.py index 66854ce..e72dd3e 100644 --- a/Paimon_Info/draw_player_card.py +++ b/Paimon_Info/draw_player_card.py @@ -1,9 +1,12 @@ -import os, random, re -from PIL import Image, ImageDraw, ImageFont -from ..utils.util import pil2b64 -from nonebot.adapters.onebot.v11 import MessageSegment import copy -from ..utils.http_util import aiorequests +import os +import random +import re + +from PIL import Image, ImageDraw, ImageFont + +from utils import aiorequests +from utils.message_util import MessageBuild res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res') @@ -248,9 +251,7 @@ async def draw_player_card(data, chara_data, uid, nickname="旅行者"): break else: nocha = '*这uid关闭了角色详情显示,派蒙看不到哦' - bg_img = pil2b64(bg_img, 80) - bg_img = MessageSegment.image(bg_img) + nocha - return bg_img + return MessageBuild.Image(bg_img, quality=80) + MessageBuild.Text(nocha) # ysa @@ -335,9 +336,7 @@ async def draw_all_chara_card(data, uid): n += 1 bg_img.paste(bg_bottom, (0, 382 + col * 474 - 50)) - bg_img = pil2b64(bg_img, 55) - bg_img = MessageSegment.image(bg_img) - return bg_img + return MessageBuild.Image(bg_img, size=0.9, quality=70) # ysc @@ -443,8 +442,7 @@ async def draw_chara_card(data, skill_data, chara_name, uid): # 武器 weapon_bg = Image.open(os.path.join(res_path, 'other', f'star{character["weapon"]["rarity"]}.png')).resize( (100, 100)) - weapon_name = character['weapon']['icon'].split('/')[-1] - weapon_icon = Image.open(os.path.join(res_path, 'weapon', weapon_name)).resize((100, 100)) + weapon_icon = await aiorequests.get_img(url=character['weapon']['icon'], size=(100, 100), mode='RGBA') bg_img.alpha_composite(weapon_bg, (293, 175)) bg_img.alpha_composite(weapon_icon, (293, 175)) bg_img.alpha_composite(shadow.resize((50, 25)), (344, 250)) @@ -516,6 +514,5 @@ async def draw_chara_card(data, skill_data, chara_name, uid): i += 1 bg_draw.text((330, 371), 'Created by LittlePaimon', font=get_font(20), fill='white') - bg_img = pil2b64(bg_img, 70) - bg_img = MessageSegment.image(bg_img) - return bg_img + + return MessageBuild.Image(bg_img, size=0.95, quality=80) diff --git a/Paimon_Info/get_data.py b/Paimon_Info/get_data.py index 4126e8f..1363289 100644 --- a/Paimon_Info/get_data.py +++ b/Paimon_Info/get_data.py @@ -1,6 +1,7 @@ -from ..utils.util import get_headers, get_sign_headers, cache, get_use_cookie, get_own_cookie, check_retcode -from ..utils.db_util import update_cookie_cache -from ..utils.http_util import aiorequests +from utils.auth_util import get_headers, get_sign_headers, get_use_cookie, get_own_cookie, check_retcode +from utils.db_util import update_cookie_cache +from utils.decorator import cache +from utils import aiorequests import datetime import re diff --git a/Paimon_Plugins/auto_handle.py b/Paimon_Plugins/auto_handle.py index d3ce148..482abd9 100644 --- a/Paimon_Plugins/auto_handle.py +++ b/Paimon_Plugins/auto_handle.py @@ -1,6 +1,6 @@ import random from asyncio import sleep -from ..utils.config import config +from utils.config import config from nonebot import get_driver from nonebot.message import event_preprocessor from nonebot.adapters.onebot.v11 import Bot, FriendRequestEvent, GroupRequestEvent diff --git a/Paimon_Plugins/couplets.py b/Paimon_Plugins/couplets.py index ed4f3cf..07ea549 100644 --- a/Paimon_Plugins/couplets.py +++ b/Paimon_Plugins/couplets.py @@ -2,9 +2,10 @@ from urllib.parse import quote from nonebot import on_command from nonebot.params import CommandArg from nonebot.adapters.onebot.v11 import MessageEvent -from ..utils.util import FreqLimiter, get_id -from ..utils.config import config -from ..utils.http_util import aiorequests +from utils.auth_util import FreqLimiter +from utils.message_util import get_message_id +from utils.config import config +from utils import aiorequests couplets = on_command('对联', aliases={'对对联'}, priority=13, block=True) @@ -15,8 +16,8 @@ couplets_limit = FreqLimiter(config.paimon_couplets_cd) async def couplets_handler(event: MessageEvent, msg=CommandArg()): if not msg: await couplets.finish('请输入对联内容') - if not couplets_limit.check(get_id(event)): - await couplets.finish(f'对联冷却ing(剩余{couplets_limit.left_time(get_id(event))}秒)') + if not couplets_limit.check(get_message_id(event)): + await couplets.finish(f'对联冷却ing(剩余{couplets_limit.left_time(get_message_id(event))}秒)') else: msg = str(msg).split(' ') word = msg[0].strip() @@ -25,7 +26,7 @@ async def couplets_handler(event: MessageEvent, msg=CommandArg()): except: num = 1 num = num if num < 10 else 10 - couplets_limit.start_cd(get_id(event), config.paimon_couplets_cd) + couplets_limit.start_cd(get_message_id(event), config.paimon_couplets_cd) text = quote(str(word)) url = f'https://ai-backend.binwang.me/v0.2/couplet/{text}' res = await aiorequests.get(url=url) diff --git a/Paimon_Plugins/news.py b/Paimon_Plugins/news.py index 9b67734..4fef289 100644 --- a/Paimon_Plugins/news.py +++ b/Paimon_Plugins/news.py @@ -2,8 +2,9 @@ import re from nonebot import on_command, require, get_bot, logger from nonebot.params import CommandArg from nonebot.adapters.onebot.v11 import MessageEvent, MessageSegment -from ..utils.util import load_data, save_data, get_id -from ..utils.http_util import aiorequests +from utils import aiorequests +from utils.file_handler import load_json, save_json +from utils.message_util import get_message_id news60s_pic = on_command('早报', aliases={'今日早报', '今日新闻', '60s读世界'}, priority=13, block=True) @@ -22,8 +23,8 @@ async def news60s_pic_handler(event: MessageEvent, msg=CommandArg()): # 匹配msg中的xx:xx时间 time_str = re.search(r'(\d{1,2}):(\d{2})', msg) if time_str: - push_data = load_data('news60s_push.json') - push_id = str(get_id(event)) + push_data = load_json('news60s_push.json') + push_id = str(get_message_id(event)) push_data[push_id] = { 'type': event.message_type, 'hour': int(time_str.group(1)), @@ -31,26 +32,27 @@ async def news60s_pic_handler(event: MessageEvent, msg=CommandArg()): } if event.message_type == 'guild': push_data[push_id]['guild_id'] = event.guild_id - if scheduler.get_job('60sNews' + str(get_id(event))): - scheduler.remove_job('60sNews' + str(get_id(event))) + if scheduler.get_job('60sNews' + str(get_message_id(event))): + scheduler.remove_job('60sNews' + str(get_message_id(event))) scheduler.add_job( func=news60s_push_task, trigger='cron', hour=int(time_str.group(1)), minute=int(time_str.group(2)), - id='60sNews' + str(get_id(event)), - args=(str(get_id(event)), - push_data[str(get_id(event))]) + id='60sNews' + str(get_message_id(event)), + args=(str(get_message_id(event)), + push_data[str(get_message_id(event))]) ) - save_data(push_data, 'news60s_push.json') + save_json(push_data, 'news60s_push.json') await news60s_pic.finish('开启60s读世界推送成功', at_sender=True) else: await news60s_pic.finish('请给出正确的时间,格式为12:00', at_sender=True) elif msg.startswith('关闭推送'): - push_data = load_data('news60s_push.json') - del push_data[str(get_id(event))] - scheduler.remove_job('60sNews' + str(get_id(event))) - save_data(push_data, 'news60s_push.json') + push_data = load_json('news60s_push.json') + del push_data[str(get_message_id(event))] + if scheduler.get_job('60sNews' + str(get_message_id(event))): + scheduler.remove_job('60sNews' + str(get_message_id(event))) + save_json(push_data, 'news60s_push.json') await news60s_pic.finish('关闭60s读世界推送成功', at_sender=True) @@ -71,7 +73,7 @@ async def news60s_push_task(push_id, push_data: dict): logger.exception(f'{push_data["type"]}的{push_id}的60秒读世界推送失败:{e}') -for push_id, push_data in load_data('news60s_push.json').items(): +for push_id, push_data in load_json('news60s_push.json').items(): scheduler.add_job( func=news60s_push_task, trigger='cron', diff --git a/Paimon_Plugins/order.py b/Paimon_Plugins/order.py index 0a7c17d..53ff790 100644 --- a/Paimon_Plugins/order.py +++ b/Paimon_Plugins/order.py @@ -2,8 +2,8 @@ import random from nonebot import on_command from nonebot.params import CommandArg from nonebot.adapters.onebot.v11 import Message, MessageEvent, MessageSegment -from ..utils.util import FreqLimiter -from ..utils.http_util import aiorequests +from utils.auth_util import FreqLimiter +from utils import aiorequests order_pic = on_command('点菜', aliases={'点餐', '食谱', '我想吃'}, priority=13, block=True) order_lmt = FreqLimiter(10) diff --git a/Paimon_Plugins/random_img.py b/Paimon_Plugins/random_img.py index 315ad15..4a2048d 100644 --- a/Paimon_Plugins/random_img.py +++ b/Paimon_Plugins/random_img.py @@ -2,8 +2,10 @@ import random from nonebot import on_command, on_regex from nonebot.params import RegexGroup from nonebot.adapters.onebot.v11 import Bot, MessageEvent, MessageSegment -from ..utils.config import config -from ..utils.util import FreqLimiter, auto_withdraw, get_id +from utils.config import config +from utils.auth_util import FreqLimiter +from utils.message_util import get_message_id +from utils.decorator import auto_withdraw cat_lmt = FreqLimiter(config.paimon_cat_cd) ecy_lmt = FreqLimiter(config.paimon_ecy_cd) @@ -16,11 +18,11 @@ ys_img = on_command('原神壁纸', aliases={'来点原神图', '来点原神壁 @cat_img.handle() async def cat_img_handler(event: MessageEvent): - if not cat_lmt.check(get_id(event)): - await cat_img.finish(f'猫片冷却ing(剩余{cat_lmt.left_time(get_id(event))}秒)') + if not cat_lmt.check(get_message_id(event)): + await cat_img.finish(f'猫片冷却ing(剩余{cat_lmt.left_time(get_message_id(event))}秒)') else: await cat_img.send('派蒙努力找图ing..请稍候...') - cat_lmt.start_cd(get_id(event), config.paimon_cat_cd) + cat_lmt.start_cd(get_message_id(event), config.paimon_cat_cd) url = 'http://edgecats.net/' await cat_img.finish(MessageSegment.image(file=url)) @@ -49,11 +51,11 @@ async def ecy_img_handler(bot: Bot, event: MessageEvent, regexGroup=RegexGroup() url = 'https://iw233.cn/api.php?sort=pc' else: url = '' - if not ecy_lmt.check(get_id(event)): - await ecy_img.finish(f'二次元图片冷却ing(剩余{ecy_lmt.left_time(get_id(event))}秒)') + if not ecy_lmt.check(get_message_id(event)): + await ecy_img.finish(f'二次元图片冷却ing(剩余{ecy_lmt.left_time(get_message_id(event))}秒)') elif url: await ecy_img.send('派蒙努力找图ing..请稍候...') - ecy_lmt.start_cd(get_id(event), config.paimon_ecy_cd) + ecy_lmt.start_cd(get_message_id(event), config.paimon_ecy_cd) return await ecy_img.send(MessageSegment.image(file=url)) @@ -64,9 +66,9 @@ async def ys_img_handler(event: MessageEvent): 'https://api.dujin.org/img/yuanshen/', 'https://api.dreamofice.cn/random-v0/img.php?game=ys' ] - if not ys_lmt.check(get_id(event)): - await ys_img.finish(f'原神壁纸冷却ing(剩余{ys_lmt.left_time(get_id(event))}秒)') + if not ys_lmt.check(get_message_id(event)): + await ys_img.finish(f'原神壁纸冷却ing(剩余{ys_lmt.left_time(get_message_id(event))}秒)') else: await ys_img.send('派蒙努力找图ing..请稍候...') - ys_lmt.start_cd(get_id(event), config.paimon_ysp_cd) + ys_lmt.start_cd(get_message_id(event), config.paimon_ysp_cd) await ys_img.finish(MessageSegment.image(file=random.choice(urls))) \ No newline at end of file diff --git a/Paimon_Wiki/__init__.py b/Paimon_Wiki/__init__.py index 70a0a1e..47bb52c 100644 --- a/Paimon_Wiki/__init__.py +++ b/Paimon_Wiki/__init__.py @@ -1,14 +1,16 @@ import os -from nonebot import on_endswith, on_command, on_regex -from nonebot.params import RegexDict -from nonebot.adapters.onebot.v11 import MessageSegment, MessageEvent -from ..utils.character_alias import get_id_by_alias -from ..utils.util import exception_handler -from .blue import get_blue_pic -from .abyss_rate_draw import draw_rate_rank, draw_teams_rate import re import time +from nonebot import on_endswith, on_command, on_regex +from nonebot.adapters.onebot.v11 import MessageSegment, MessageEvent +from nonebot.params import RegexDict + +from utils.character_alias import get_id_by_alias +from utils.decorator import exception_handler +from .abyss_rate_draw import draw_rate_rank, draw_teams_rate +from .blue import get_blue_pic + __usage__ = ''' 1.[xx角色攻略]查看西风驿站出品的角色一图流攻略 2.[xx角色材料]查看惜月出品的角色材料统计 @@ -70,7 +72,7 @@ async def genshinAttribute(event: MessageEvent): if name in ['风主', '岩主', '雷主'] or realname: name = realname[1][0] if name not in ['风主', '岩主', '雷主'] else name img = await get_blue_pic(name) - await attribute.finish(MessageSegment.image(file=img)) + await attribute.finish(img) else: await attribute.finish(f'没有找到{name}的参考面板', at_sender=True) diff --git a/Paimon_Wiki/abyss_rate_data.py b/Paimon_Wiki/abyss_rate_data.py index b977909..1fbbbaa 100644 --- a/Paimon_Wiki/abyss_rate_data.py +++ b/Paimon_Wiki/abyss_rate_data.py @@ -1,4 +1,4 @@ -from ..utils.http_util import aiorequests +from utils import aiorequests # 数据源自微信公众号原神创意工坊 headers = { diff --git a/Paimon_Wiki/abyss_rate_draw.py b/Paimon_Wiki/abyss_rate_draw.py index b7925b6..55cc32c 100644 --- a/Paimon_Wiki/abyss_rate_draw.py +++ b/Paimon_Wiki/abyss_rate_draw.py @@ -1,9 +1,10 @@ -from PIL import Image, ImageDraw, ImageFont import os -from nonebot.adapters.onebot.v11 import MessageSegment + +from PIL import Image, ImageDraw, ImageFont + +from utils.character_alias import get_id_by_alias +from utils.message_util import MessageBuild from .abyss_rate_data import get_rate, get_formation_rate -from ..utils.util import pil2b64 -from ..utils.character_alias import get_id_by_alias res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res') @@ -73,7 +74,6 @@ async def draw_teams_rate(floor='上半半'): bg_img.alpha_composite(role_img, (130 + 204 * r, 180 + 240 * n)) r += 1 n += 1 - bg_img = pil2b64(bg_img, 75) - bg_img = MessageSegment.image(bg_img) - return bg_img + + return MessageBuild.Image(bg_img, quality=75) diff --git a/Paimon_Wiki/blue.py b/Paimon_Wiki/blue.py index 7ad2024..deeffac 100644 --- a/Paimon_Wiki/blue.py +++ b/Paimon_Wiki/blue.py @@ -1,5 +1,5 @@ -from ..utils.util import pil2b64 -from ..utils.http_util import aiorequests +from utils import aiorequests +from utils.message_util import MessageBuild blue = { '胡桃': ['火', (0, 1886)], @@ -62,6 +62,5 @@ async def get_blue_pic(name): if c[0] == name: img = await aiorequests.get_img(url=f'https://static.cherishmoon.fun/LittlePaimon/blue/{c[1][0]}.jpg') img = img.crop((0, int(c[1][1][0]), 1080, int(c[1][1][1]))) - img = pil2b64(img, 100) - return img + return MessageBuild.Image(img) return None diff --git a/README.md b/README.md index 750e816..f4371e8 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,9 @@ - `原神猜语音`不再需要`我猜`,直接回答角色别名即可参与猜猜看 - 异步请求库从`aiohttp`改用`httpx`,需安装依赖库`pip install httpx` - 修复`60秒读世界`在频道无法关闭推送的BUG ++ 5.20 + - 修复`ysc`缺少资源问题 + - 封装部分常用方法,优化导包 ## 功能列表 diff --git a/__init__.py b/__init__.py index e69de29..e669d95 100644 --- a/__init__.py +++ b/__init__.py @@ -0,0 +1,4 @@ +import os +import sys + +sys.path.insert(0, os.path.dirname(__file__)) diff --git a/utils/aiorequests.py b/utils/aiorequests.py new file mode 100644 index 0000000..0c38d2f --- /dev/null +++ b/utils/aiorequests.py @@ -0,0 +1,104 @@ +import base64 +from typing import Dict, Optional, Any, Union, Tuple +from pathlib import Path +from io import BytesIO +from PIL import Image +import httpx + + +async def get(url: str, + *, + headers: Optional[Dict[str, str]] = None, + params: Optional[Dict[str, Any]] = None, + timeout: Optional[int] = 20, + **kwargs) -> httpx.Response: + """ + 说明: + httpx的get请求封装 + 参数: + :param url: url + :param headers: 请求头 + :param params: params + :param timeout: 超时时间 + """ + async with httpx.AsyncClient() as client: + return await client.get(url, + headers=headers, + params=params, + timeout=timeout, + **kwargs) + + +async def post(url: str, + *, + headers: Optional[Dict[str, str]] = None, + params: Optional[Dict[str, Any]] = None, + data: Optional[Dict[str, Any]] = None, + json: Optional[Dict[str, Union[Any, str]]] = None, + timeout: Optional[int] = 20, + **kwargs) -> httpx.Response: + """ + 说明: + httpx的post请求封装 + 参数: + :param url: url + :param headers: 请求头 + :param params: params + :param data: data + :param json: json + :param timeout: 超时时间 + """ + async with httpx.AsyncClient() as client: + return await client.post(url, + headers=headers, + params=params, + data=data, + json=json, + timeout=timeout, + **kwargs) + + +async def get_img(url: str, + *, + headers: Optional[Dict[str, str]] = None, + params: Optional[Dict[str, Any]] = None, + timeout: Optional[int] = 20, + save_path: Optional[Union[str, Path]] = None, + size: Optional[Tuple[int, int]] = None, + mode: Optional[str] = None, + to_b64: bool = False, + **kwargs) -> Union[str, Image.Image]: + """ + 说明: + httpx的get请求封装,获取图片 + 参数: + :param url: url + :param headers: 请求头 + :param params: params + :param timeout: 超时时间 + :param save_path: 保存路径,为空则不保存 + :param size: 图片尺寸,为空则不做修改 + :param mode: 图片模式,为空则不做修改 + :param to_b64: 是否转b64 + """ + async with httpx.AsyncClient() as client: + resp = await client.get(url, + + headers=headers, + params=params, + timeout=timeout, + **kwargs) + if to_b64: + return 'base64://' + base64.b64encode(resp.read()).decode() + else: + img = Image.open(BytesIO(resp.read())) + if size: + img = img.resize(size, Image.ANTIALIAS) + if mode: + img = img.convert(mode) + if save_path: + if isinstance(save_path, str): + save_path = Path(save_path) + save_path.parent.mkdir(parents=True, exist_ok=True) + img.save(save_path) + return img diff --git a/utils/util.py b/utils/auth_util.py similarity index 53% rename from utils/util.py rename to utils/auth_util.py index 5a6ceea..6f82b2e 100644 --- a/utils/util.py +++ b/utils/auth_util.py @@ -1,109 +1,18 @@ -import hashlib -from collections import defaultdict -from io import BytesIO -from pathlib import Path -import random import base64 -import datetime -from time import time -import re -import string -import functools -import inspect +import hashlib import json -import asyncio -from json import JSONDecodeError -from nonebot import get_bot +import random +import string +from collections import defaultdict +from time import time + from nonebot import logger -from nonebot.exception import FinishedException -from nonebot.adapters.onebot.v11 import MessageEvent, Message -from nonebot.adapters.onebot.v11.exception import ActionFailed + +from . import aiorequests +from .db_util import get_cookie_cache, update_cookie_cache, delete_cookie_cache from .db_util import get_private_cookie, delete_cookie from .db_util import get_public_cookie, limit_public_cookie -from .db_util import get_cookie_cache, update_cookie_cache, delete_cookie_cache -from .db_util import get_last_query, update_last_query -from .http_util import aiorequests - - -def auto_withdraw(seconds: int = -1): - def wrapper(func): - - @functools.wraps(func) - async def wrapped(**kwargs): - try: - message_id = await func(**kwargs) - if message_id and seconds >= 1: - await asyncio.sleep(seconds) - await get_bot().delete_msg(message_id=message_id['message_id']) - except Exception as e: - raise e - - return wrapped - - return wrapper - - -# 缓存装饰器 ttl为过期时间 参数use_cache决定是否使用缓存,默认为True -def cache(ttl=datetime.timedelta(hours=1), **kwargs): - def wrap(func): - cache_data = {} - - @functools.wraps(func) - async def wrapped(*args, **kw): - nonlocal cache_data - bound = inspect.signature(func).bind(*args, **kw) - bound.apply_defaults() - ins_key = '|'.join(['%s_%s' % (k, v) for k, v in bound.arguments.items()]) - default_data = {"time": None, "value": None} - data = cache_data.get(ins_key, default_data) - now = datetime.datetime.now() - if 'use_cache' not in kw: - kw['use_cache'] = True - if not kw['use_cache'] or not data['time'] or now - data['time'] > ttl: - try: - data['value'] = await func(*args, **kw) - data['time'] = now - cache_data[ins_key] = data - except Exception as e: - raise e - return data['value'] - - return wrapped - - return wrap - - -# 异常处理装饰器 -def exception_handler(): - def wrapper(func): - - @functools.wraps(func) - async def wrapped(**kwargs): - event = kwargs['event'] - try: - await func(**kwargs) - except FinishedException: - raise - except ActionFailed: - logger.exception('账号可能被风控,消息发送失败') - await get_bot().send(event, f'派蒙可能被风控,也可能是没有该图片资源,消息发送失败') - except JSONDecodeError: - await get_bot().send(event, '派蒙获取信息失败,重试一下吧') - # except IndexError or KeyError as e: - # await get_bot().send(event, f'派蒙获取信息失败,请确认参数无误,{e}') - # except TypeError or AttributeError as e: - # await get_bot().send(event, f'派蒙好像没有该UID的绑定信息, {e}') - except FileNotFoundError as e: - file_name = re.search(r'\'(.*)\'', str(e)).group(1) - file_name = file_name.replace('\\\\', '/').split('/') - file_name = file_name[-2] + '\\' + file_name[-1] - await get_bot().send(event, f"派蒙缺少{file_name}资源,请联系开发者补充") - except Exception as e: - await get_bot().send(event, f'派蒙好像出了点问题,{e}') - - return wrapped - - return wrapper +from .message_util import send_cookie_delete_msg # 冷却时间限制器 @@ -138,19 +47,6 @@ class FreqLimiter2: return int(self.next_time[key1][key2] - time()) + 1 -# # 从网络url中获取图片 -# async def get_pic(url: str, size: tuple = None, mode: str = None): -# async with ClientSession() as session: -# res = await session.get(url) -# res = await res.read() -# img = Image.open(BytesIO(res)) -# if size: -# img = img.resize(size) -# if mode: -# img = img.convert(mode) -# return img - - # 获取可用的cookie async def get_use_cookie(user_id, uid='', mys_id='', action=''): cache_cookie = await get_cookie_cache(uid, 'uid') @@ -222,44 +118,6 @@ async def check_retcode(data, cookie, uid): return True -# 图片转b64,q为质量(压缩比例) -def pil2b64(data, q=85): - bio = BytesIO() - data = data.convert("RGB") - data.save(bio, format='JPEG', quality=q) - base64_str = base64.b64encode(bio.getvalue()).decode() - return 'base64://' + base64_str - - -# 获取message中的艾特对象 -async def get_at_target(msg): - for msg_seg in msg: - if msg_seg.type == "at": - return msg_seg.data['qq'] - return None - - -# message预处理,获取uid、干净的msg、user_id、是否缓存 -async def get_uid_in_msg(event: MessageEvent, msg: Message): - msg = str(msg).strip() - if not msg: - uid = await get_last_query(str(event.user_id)) - return uid, '', str(event.user_id), True - user_id = await get_at_target(event.message) or str(event.user_id) - msg = re.sub(r'\[CQ.*?\]', '', msg) - use_cache = False if '-r' in msg else True - msg = msg.replace('-r', '').strip() - find_uid = r'(?P(1|2|5)\d{8})' - for msg_seg in event.message: - if msg_seg.type == 'text': - match = re.search(find_uid, msg_seg.data['text']) - if match: - await update_last_query(user_id, match.group('uid'), 'uid') - return match.group('uid'), msg.replace(match.group('uid'), '').strip(), user_id, use_cache - uid = await get_last_query(user_id) - return uid, msg.strip(), user_id, use_cache - - # md5加密 def md5(text: str) -> str: md5 = hashlib.md5() @@ -348,43 +206,5 @@ async def check_cookie(cookie): return True -# 向超级用户私聊发送cookie删除信息 -async def send_cookie_delete_msg(cookie_info): - msg = '' - if cookie_info['type'] == 'public': - msg = f'公共池的{cookie_info["no"]}号cookie已失效' - elif cookie_info['type'] == 'private': - if cookie_info['uid']: - msg = f'用户{cookie_info["user_id"]}的uid{cookie_info["uid"]}的cookie已失效' - elif cookie_info['mys_id']: - msg = f'用户{cookie_info["user_id"]}的mys_id{cookie_info["mys_id"]}的cookie已失效' - if msg: - logger.info(f'---{msg}---') - for superuser in get_bot().config.superusers: - try: - await get_bot().send_private_msg(user_id=superuser, message=msg + ',派蒙帮你删除啦!') - except Exception as e: - logger.error(f'发送cookie删除消息失败: {e}') -def load_data(data_file): - data_path = Path() / 'data' / 'LittlePaimon' / data_file - if not data_path.exists(): - save_data({}, data_file) - return json.load(data_path.open('r', encoding='utf-8')) - - -def save_data(data, data_file): - data_path = Path() / 'data' / 'LittlePaimon' / data_file - data_path.parent.mkdir(parents=True, exist_ok=True) - json.dump(data, data_path.open('w', encoding='utf-8'), ensure_ascii=False, indent=2) - - -def get_id(event): - if event.message_type == 'private': - return event.user_id - elif event.message_type == 'group': - return event.group_id - elif event.message_type == 'guild': - return event.channel_id - diff --git a/utils/decorator.py b/utils/decorator.py new file mode 100644 index 0000000..77853ab --- /dev/null +++ b/utils/decorator.py @@ -0,0 +1,91 @@ +import asyncio +import functools +import datetime +import inspect +import re +from json import JSONDecodeError + +from nonebot import get_bot, logger +from nonebot.adapters.onebot.v11 import ActionFailed +from nonebot.exception import FinishedException + + +def auto_withdraw(seconds: int = -1): + def wrapper(func): + + @functools.wraps(func) + async def wrapped(**kwargs): + try: + message_id = await func(**kwargs) + if message_id and seconds >= 1: + await asyncio.sleep(seconds) + await get_bot().delete_msg(message_id=message_id['message_id']) + except Exception as e: + raise e + + return wrapped + + return wrapper + + +# 缓存装饰器 ttl为过期时间 参数use_cache决定是否使用缓存,默认为True +def cache(ttl=datetime.timedelta(hours=1)): + def wrap(func): + cache_data = {} + + @functools.wraps(func) + async def wrapped(*args, **kw): + nonlocal cache_data + bound = inspect.signature(func).bind(*args, **kw) + bound.apply_defaults() + ins_key = '|'.join(['%s_%s' % (k, v) for k, v in bound.arguments.items()]) + default_data = {"time": None, "value": None} + data = cache_data.get(ins_key, default_data) + now = datetime.datetime.now() + if 'use_cache' not in kw: + kw['use_cache'] = True + if not kw['use_cache'] or not data['time'] or now - data['time'] > ttl: + try: + data['value'] = await func(*args, **kw) + data['time'] = now + cache_data[ins_key] = data + except Exception as e: + raise e + return data['value'] + + return wrapped + + return wrap + + +# 异常处理装饰器 +def exception_handler(): + def wrapper(func): + + @functools.wraps(func) + async def wrapped(**kwargs): + event = kwargs['event'] + try: + await func(**kwargs) + except FinishedException: + raise + except ActionFailed: + logger.exception('账号可能被风控,消息发送失败') + await get_bot().send(event, f'派蒙可能被风控,也可能是没有该图片资源,消息发送失败') + except JSONDecodeError: + await get_bot().send(event, '派蒙获取信息失败,重试一下吧') + # except IndexError or KeyError as e: + # await get_bot().send(event, f'派蒙获取信息失败,请确认参数无误,{e}') + # except TypeError or AttributeError as e: + # await get_bot().send(event, f'派蒙好像没有该UID的绑定信息, {e}') + except FileNotFoundError as e: + file_name = re.search(r'\'(.*)\'', str(e)).group(1) + file_name = file_name.replace('\\\\', '/').split('/') + file_name = file_name[-2] + '\\' + file_name[-1] + await get_bot().send(event, f"派蒙缺少{file_name}资源,请联系开发者补充") + except Exception as e: + await get_bot().send(event, f'派蒙好像出了点问题,{e}') + + return wrapped + + return wrapper diff --git a/utils/file_handler.py b/utils/file_handler.py new file mode 100644 index 0000000..a721c57 --- /dev/null +++ b/utils/file_handler.py @@ -0,0 +1,41 @@ +from pathlib import Path +from PIL import Image +from typing import Union, Optional, Tuple +import json + + +def load_image( + path: Union[Path, str], + *, + size: Optional[Union[Tuple[int, int], float]] = None, + mode: Optional[str] = 'RGB' +): + img = Image.open(path) + if size: + if isinstance(size, float): + img = img.resize((int(img.size[0] * size), int(img.size[1] * size)), Image.ANTIALIAS) + elif isinstance(size, tuple): + img = img.resize(size, Image.ANTIALIAS) + img = img.convert(mode) + return img + + +def load_json(file: str = None, path: Union[Path, str] = None, encoding: str = 'utf-8'): + if file and not path: + path = Path() / 'data' / 'LittlePaimon' / file + elif path: + if isinstance(path, str): + path = Path(path) + if not path.exists(): + save_json({}, file, path, encoding) + return json.load(path.open('r', encoding=encoding)) + + +def save_json(data, file: str = None, path: Union[Path, str] = None, encoding: str = 'utf-8'): + if file and not path: + path = Path() / 'data' / 'LittlePaimon' / file + elif path: + if isinstance(path, str): + path = Path(path) + path.parent.mkdir(parents=True, exist_ok=True) + json.dump(data, path.open('w', encoding=encoding), ensure_ascii=False, indent=4) diff --git a/utils/http_util.py b/utils/http_util.py deleted file mode 100644 index f2257d0..0000000 --- a/utils/http_util.py +++ /dev/null @@ -1,77 +0,0 @@ -import base64 -from typing import Dict, Optional, Any, Union, Tuple -from pathlib import Path -from io import BytesIO -from PIL import Image -import httpx - - -class aiorequests: - - @classmethod - async def get(cls, - url: str, - *, - headers: Optional[Dict[str, str]] = None, - params: Optional[Dict[str, Any]] = None, - timeout: Optional[int] = 20, - **kwargs) -> httpx.Response: - async with httpx.AsyncClient() as client: - return await client.get(url, - headers=headers, - params=params, - timeout=timeout, - **kwargs) - - @classmethod - async def post(cls, - url: str, - *, - headers: Optional[Dict[str, str]] = None, - params: Optional[Dict[str, Any]] = None, - data: Optional[Dict[str, Any]] = None, - json: Optional[Dict[str, Union[Any, str]]] = None, - timeout: Optional[int] = 20, - **kwargs) -> httpx.Response: - async with httpx.AsyncClient() as client: - return await client.post(url, - headers=headers, - params=params, - data=data, - json=json, - timeout=timeout, - **kwargs) - - @classmethod - async def get_img(cls, - url: str, - *, - headers: Optional[Dict[str, str]] = None, - params: Optional[Dict[str, Any]] = None, - timeout: Optional[int] = 20, - save_path: Optional[Union[str, Path]] = None, - size: Optional[Tuple[int, int]] = None, - mode: Optional[str] = None, - to_b64: bool = False, - **kwargs) -> Union[str, Image.Image]: - async with httpx.AsyncClient() as client: - resp = await client.get(url, - - headers=headers, - params=params, - timeout=timeout, - **kwargs) - if to_b64: - return 'base64://' + base64.b64encode(resp.read()).decode() - else: - img = Image.open(BytesIO(resp.read())) - if size: - img = img.resize(size, Image.ANTIALIAS) - if mode: - img = img.convert(mode) - if save_path: - if isinstance(save_path, str): - save_path = Path(save_path) - save_path.parent.mkdir(parents=True, exist_ok=True) - img.save(save_path) - return img diff --git a/utils/message_util.py b/utils/message_util.py new file mode 100644 index 0000000..121ebf5 --- /dev/null +++ b/utils/message_util.py @@ -0,0 +1,99 @@ +# 获取message中的艾特对象 +import re +import base64 + +from PIL import Image +from pathlib import Path +from typing import Union, Optional, Tuple +from io import BytesIO + +from nonebot import get_bot, logger +from nonebot.adapters.onebot.v11 import MessageEvent, Message, MessageSegment + +from .db_util import get_last_query, update_last_query +from .file_handler import load_image + + +class MessageBuild: + + @classmethod + def Image(cls, + img: Union[Image.Image, Path, str], + *, + size: Optional[Union[Tuple[int, int], float]] = None, + quality: Optional[int] = 100, + mode: Optional[str] = 'RGB' + ) -> MessageSegment: + if isinstance(img, str) or isinstance(img, Path): + img = load_image(path=img, size=size, mode=mode) + bio = BytesIO() + img = img.convert(mode) + img.save(bio, format='JPEG' if mode == 'RGB' else 'PNG', quality=quality) + img_b64 = 'base64://' + base64.b64encode(bio.getvalue()).decode() + return MessageSegment.image(img_b64) + + @classmethod + def Text(cls, text: str) -> MessageSegment: + # TODO 过滤负面文本 + return MessageSegment.text(text) + + @classmethod + def Record(cls, path: str) -> MessageSegment: + # TODO 网络语音 + return MessageSegment.record(path) + + +async def get_at_target(msg): + for msg_seg in msg: + if msg_seg.type == "at": + return msg_seg.data['qq'] + return None + + +# message预处理,获取uid、干净的msg、user_id、是否缓存 +async def get_uid_in_msg(event: MessageEvent, msg: Message): + msg = str(msg).strip() + if not msg: + uid = await get_last_query(str(event.user_id)) + return uid, '', str(event.user_id), True + user_id = await get_at_target(event.message) or str(event.user_id) + msg = re.sub(r'\[CQ.*?\]', '', msg) + use_cache = False if '-r' in msg else True + msg = msg.replace('-r', '').strip() + find_uid = r'(?P(1|2|5)\d{8})' + for msg_seg in event.message: + if msg_seg.type == 'text': + match = re.search(find_uid, msg_seg.data['text']) + if match: + await update_last_query(user_id, match.group('uid'), 'uid') + return match.group('uid'), msg.replace(match.group('uid'), '').strip(), user_id, use_cache + uid = await get_last_query(user_id) + return uid, msg.strip(), user_id, use_cache + + +# 向超级用户私聊发送cookie删除信息 +async def send_cookie_delete_msg(cookie_info): + msg = '' + if cookie_info['type'] == 'public': + msg = f'公共池的{cookie_info["no"]}号cookie已失效' + elif cookie_info['type'] == 'private': + if cookie_info['uid']: + msg = f'用户{cookie_info["user_id"]}的uid{cookie_info["uid"]}的cookie已失效' + elif cookie_info['mys_id']: + msg = f'用户{cookie_info["user_id"]}的mys_id{cookie_info["mys_id"]}的cookie已失效' + if msg: + logger.info(f'---{msg}---') + for superuser in get_bot().config.superusers: + try: + await get_bot().send_private_msg(user_id=superuser, message=msg + ',派蒙帮你删除啦!') + except Exception as e: + logger.error(f'发送cookie删除消息失败: {e}') + + +def get_message_id(event): + if event.message_type == 'private': + return event.user_id + elif event.message_type == 'group': + return event.group_id + elif event.message_type == 'guild': + return event.channel_id