This commit is contained in:
CMHopeSunshine 2022-05-20 18:44:18 +08:00
parent b25415e341
commit 04f93b6eb0
36 changed files with 551 additions and 469 deletions

View File

@ -1,16 +1,17 @@
import asyncio import asyncio
from . import util
from typing import Union
from pathlib import Path from pathlib import Path
from nonebot import on_command from typing import Union
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 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 # 游戏持续时间 setting_time = config.paimon_guess_voice # 游戏持续时间

View File

@ -6,12 +6,13 @@
import json import json
import os import os
from pathlib import Path 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(__file__).parent / 'voice'
OUT_PUT = Path() / 'data' / 'LittlePaimon' / 'guess_voice' / 'voice' OUT_PUT = Path() / 'data' / 'LittlePaimon' / 'guess_voice' / 'voice'

View File

@ -1,19 +1,20 @@
import os
import random
import datetime import datetime
import json import json
from apscheduler.triggers.date import DateTrigger import os
from typing import List import random
from pathlib import Path from pathlib import Path
from typing import List
from apscheduler.triggers.date import DateTrigger
from nonebot import get_bot, require, logger 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 import on_regex
from nonebot.adapters.onebot.v11 import GroupMessageEvent 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 .download_data import voice_list_by_mys, voice_detail_by_mys
from .util import get_path, require_file
scheduler = require('nonebot_plugin_apscheduler').scheduler scheduler = require('nonebot_plugin_apscheduler').scheduler

View File

@ -1,7 +1,9 @@
import os import os
from pathlib import Path from pathlib import Path
import aiofiles import aiofiles
from ..utils.http_util import aiorequests
from utils import aiorequests
def get_path(dirname, filename): def get_path(dirname, filename):

View File

@ -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 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') res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res', 'voice')
chat_lmt = FreqLimiter2(60) chat_lmt = FreqLimiter2(60)

View File

@ -1,13 +1,15 @@
import re 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_info import *
from .gacha_res import more_ten 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__ = ''' __usage__ = '''
1.[抽n十连xx池]抽n次xx池的十连最多同时5次 1.[抽n十连xx池]抽n次xx池的十连最多同时5次

View File

@ -1,5 +1,5 @@
import os 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') 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') 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") 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") All_STAR_PATH = os.path.join(RES_PATH, "DIY_gacha_pool", "all_star.json")
user_info = {} user_info = load_json(path=USER_INFO_PATH)
role_1_pool = {} role_1_pool = load_json(path=ROLE_1_PATH)
role_2_pool = {} role_2_pool = load_json(path=ROLE_2_PATH)
weapon_pool = {} weapon_pool = load_json(path=WEAPON_PATH)
all_star = {} all_star = load_json(path=All_STAR_PATH)
def save_user_info(): def save_user_info():
with open(USER_INFO_PATH, 'w', encoding='UTF-8') as f: save_json(data=user_info, path=USER_INFO_PATH)
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)
def init_user_info(uid: str): def init_user_info(uid: str):

View File

@ -1,13 +1,13 @@
import datetime
import json import json
import os import os
import datetime
import numpy
import random import random
import numpy
from PIL import Image, PngImagePlugin, ImageDraw, ImageFont 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 .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') 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') 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 user_info[uid]["gacha_list"]["wish_%s_up" % rank] += 1
role['rank'] = rank role['rank'] = rank
else: else:
role = random.choice(gacha_data['r%s_prob_list' % rank])
while True: while True:
role = random.choice(gacha_data['r%s_prob_list' % rank]) role = random.choice(gacha_data['r%s_prob_list' % rank])
if role['is_up'] == 0: if role['is_up'] == 0:
@ -246,4 +245,5 @@ async def more_ten(uid, gacha_data, num, sd):
draw = ImageDraw.Draw(img) draw = ImageDraw.Draw(img)
draw.text((27, 575 * num - 30), ('@%s %s Created By LittlePaimon' % (str(sd.nickname), time_str)), font=time_font, draw.text((27, 575 * num - 30), ('@%s %s Created By LittlePaimon' % (str(sd.nickname), time_str)), font=time_font,
fill="#8E8E8E") fill="#8E8E8E")
return pil2b64(img, 75)
return MessageBuild.Image(img, quality=75)

View File

@ -1,8 +1,10 @@
from .meta_data import *
import time
import os import os
import time
import xlsxwriter import xlsxwriter
from .meta_data import *
data_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'user_data', 'gacha_log_data') data_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'user_data', 'gacha_log_data')

View File

@ -2,13 +2,16 @@ import json
import os import os
import re import re
from typing import Union from typing import Union
from nonebot import on_command from nonebot import on_command
from nonebot.params import CommandArg
from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent, GroupMessageEvent 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 .gacha_logs import get_data
from .get_img import get_gacha_log_img from .get_img import get_gacha_log_img
from .api import toApi, checkApi from pathlib import Path
__usage__ = ''' __usage__ = '''
1.[获取抽卡记录 (uid) (url)]提供url获取原神抽卡记录需要一定时间 1.[获取抽卡记录 (uid) (url)]提供url获取原神抽卡记录需要一定时间

View File

@ -1,5 +1,6 @@
from urllib import parse from urllib import parse
from ..utils.http_util import aiorequests
from utils import aiorequests
def toApi(url): def toApi(url):

View File

@ -1,10 +1,11 @@
import os
import json import json
import os
from asyncio import sleep from asyncio import sleep
from utils import aiorequests
from .UIGF_and_XLSX import convertUIGF, writeXLSX
from .api import getApi from .api import getApi
from .meta_data import gachaQueryTypeIds, gachaQueryTypeDict 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') data_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'user_data', 'gacha_log_data')

View File

@ -1,8 +1,9 @@
from PIL import Image, ImageDraw, ImageFont
import os import os
from ..utils.util import pil2b64
from ..utils.character_alias import get_short_name from PIL import Image, ImageDraw, ImageFont
from nonebot.adapters.onebot.v11 import MessageSegment
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') 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 break
if not img: if not img:
return '这个池子没有抽卡记录哦' return '这个池子没有抽卡记录哦'
total_height = (img.size)[1] total_height = img.size[1]
else: else:
img_list = [] img_list = []
total_height = 0 total_height = 0
@ -129,17 +130,15 @@ async def get_gacha_log_img(gacha_data, pool):
p_img = await draw_gacha_log(pd) p_img = await draw_gacha_log(pd)
if p_img: if p_img:
img_list.append(p_img) img_list.append(p_img)
total_height += (p_img.size)[1] total_height += p_img.size[1]
if not img_list: if not img_list:
return '没有找到任何抽卡记录诶!' return '没有找到任何抽卡记录诶!'
img = Image.new('RGBA', (768, total_height), (0, 0, 0, 255)) img = Image.new('RGBA', (768, total_height), (0, 0, 0, 255))
for i in img_list: for i in img_list:
img.paste(i, (0, now_height)) img.paste(i, (0, now_height))
now_height += (i.size)[1] now_height += i.size[1]
img_draw = ImageDraw.Draw(img) img_draw = ImageDraw.Draw(img)
img_draw.text((595, 44), f'UID:{gacha_data["uid"]}', font=get_font(16), fill='black') 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_draw.text((530, total_height - 45), 'Created by LittlePaimon', font=get_font(16), fill='black')
img = pil2b64(img, 95) return MessageBuild.Image(img)
img = MessageSegment.image(img)
return img

View File

@ -1,27 +1,31 @@
import datetime import datetime
import re
import random import random
from collections import defaultdict import re
from asyncio import sleep from asyncio import sleep
from collections import defaultdict
from nonebot import on_command, require, logger, get_bot 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 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 nonebot.params import CommandArg
from .get_data import get_monthinfo_data, get_player_card_data, get_chara_detail_data, get_chara_skill_data 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_abyss_info import draw_abyss_card
from .draw_daily_note import draw_daily_note_card from .draw_daily_note import draw_daily_note_card
from .draw_month_info import draw_monthinfo_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 .draw_player_card import draw_player_card, draw_all_chara_card, draw_chara_card
from ..utils.character_alias import get_id_by_alias from .get_data import get_bind_game, get_sign_info, sign, get_sign_list, get_abyss_data, get_daily_note_data
from ..utils.util import get_uid_in_msg, check_cookie, exception_handler from .get_data import get_monthinfo_data, get_player_card_data, get_chara_detail_data, get_chara_skill_data
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
scheduler = require('nonebot_plugin_apscheduler').scheduler scheduler = require('nonebot_plugin_apscheduler').scheduler

View File

@ -1,9 +1,10 @@
import datetime import datetime
import os import os
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
from nonebot.adapters.onebot.v11 import MessageSegment
from ..utils.util import pil2b64 from utils import aiorequests
from ..utils.http_util import aiorequests from utils.message_util import MessageBuild
res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res') 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)) total_img.alpha_composite(floor_img, (5, 5 + 524 + 5 + h))
h += 1210 h += 1210
total_img = pil2b64(total_img, 75) return MessageBuild.Image(total_img, quality=75)
total_img = MessageSegment.image(total_img)
return total_img

View File

@ -1,11 +1,12 @@
import random
import datetime import datetime
import os import os
from PIL import Image, ImageDraw, ImageFont import random
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from nonebot.adapters.onebot.v11 import MessageSegment from PIL import Image, ImageDraw, ImageFont
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') 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)) bg_img.alpha_composite(role_img, (1220, 200))
now = datetime.datetime.now().strftime('%m月%d%H:%M') 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_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) return MessageBuild.Image(bg_img, size=0.35, quality=70)
bg_img = pil2b64(bg_img, 70)
bg_img = MessageSegment.image(bg_img)
return bg_img

View File

@ -1,9 +1,9 @@
import random
from PIL import Image, ImageDraw, ImageFont
import os import os
import random
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from ..utils.util import pil2b64 from PIL import Image, ImageDraw, ImageFont
from nonebot.adapters.onebot.v11 import MessageSegment from utils.message_util import MessageBuild
res_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'res') 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((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_draw.text((167, 900), 'Created by LittlePaimon', font=get_font(21), fill='#27384C')
bg_img = pil2b64(bg_img, 70) return MessageBuild.Image(bg_img, quality=70)
bg_img = MessageSegment.image(bg_img)
return bg_img

View File

@ -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 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') 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 break
else: else:
nocha = '*这uid关闭了角色详情显示派蒙看不到哦' nocha = '*这uid关闭了角色详情显示派蒙看不到哦'
bg_img = pil2b64(bg_img, 80) return MessageBuild.Image(bg_img, quality=80) + MessageBuild.Text(nocha)
bg_img = MessageSegment.image(bg_img) + nocha
return bg_img
# ysa # ysa
@ -335,9 +336,7 @@ async def draw_all_chara_card(data, uid):
n += 1 n += 1
bg_img.paste(bg_bottom, (0, 382 + col * 474 - 50)) bg_img.paste(bg_bottom, (0, 382 + col * 474 - 50))
bg_img = pil2b64(bg_img, 55) return MessageBuild.Image(bg_img, size=0.9, quality=70)
bg_img = MessageSegment.image(bg_img)
return bg_img
# ysc # 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( weapon_bg = Image.open(os.path.join(res_path, 'other', f'star{character["weapon"]["rarity"]}.png')).resize(
(100, 100)) (100, 100))
weapon_name = character['weapon']['icon'].split('/')[-1] weapon_icon = await aiorequests.get_img(url=character['weapon']['icon'], size=(100, 100), mode='RGBA')
weapon_icon = Image.open(os.path.join(res_path, 'weapon', weapon_name)).resize((100, 100))
bg_img.alpha_composite(weapon_bg, (293, 175)) bg_img.alpha_composite(weapon_bg, (293, 175))
bg_img.alpha_composite(weapon_icon, (293, 175)) bg_img.alpha_composite(weapon_icon, (293, 175))
bg_img.alpha_composite(shadow.resize((50, 25)), (344, 250)) 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 i += 1
bg_draw.text((330, 371), 'Created by LittlePaimon', font=get_font(20), fill='white') 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 MessageBuild.Image(bg_img, size=0.95, quality=80)
return bg_img

View File

@ -1,6 +1,7 @@
from ..utils.util import get_headers, get_sign_headers, cache, get_use_cookie, get_own_cookie, check_retcode 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.db_util import update_cookie_cache
from ..utils.http_util import aiorequests from utils.decorator import cache
from utils import aiorequests
import datetime import datetime
import re import re

View File

@ -1,6 +1,6 @@
import random import random
from asyncio import sleep from asyncio import sleep
from ..utils.config import config from utils.config import config
from nonebot import get_driver from nonebot import get_driver
from nonebot.message import event_preprocessor from nonebot.message import event_preprocessor
from nonebot.adapters.onebot.v11 import Bot, FriendRequestEvent, GroupRequestEvent from nonebot.adapters.onebot.v11 import Bot, FriendRequestEvent, GroupRequestEvent

View File

@ -2,9 +2,10 @@ from urllib.parse import quote
from nonebot import on_command from nonebot import on_command
from nonebot.params import CommandArg from nonebot.params import CommandArg
from nonebot.adapters.onebot.v11 import MessageEvent from nonebot.adapters.onebot.v11 import MessageEvent
from ..utils.util import FreqLimiter, get_id from utils.auth_util import FreqLimiter
from ..utils.config import config from utils.message_util import get_message_id
from ..utils.http_util import aiorequests from utils.config import config
from utils import aiorequests
couplets = on_command('对联', aliases={'对对联'}, priority=13, block=True) 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()): async def couplets_handler(event: MessageEvent, msg=CommandArg()):
if not msg: if not msg:
await couplets.finish('请输入对联内容') await couplets.finish('请输入对联内容')
if not couplets_limit.check(get_id(event)): if not couplets_limit.check(get_message_id(event)):
await couplets.finish(f'对联冷却ing(剩余{couplets_limit.left_time(get_id(event))}秒)') await couplets.finish(f'对联冷却ing(剩余{couplets_limit.left_time(get_message_id(event))}秒)')
else: else:
msg = str(msg).split(' ') msg = str(msg).split(' ')
word = msg[0].strip() word = msg[0].strip()
@ -25,7 +26,7 @@ async def couplets_handler(event: MessageEvent, msg=CommandArg()):
except: except:
num = 1 num = 1
num = num if num < 10 else 10 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)) text = quote(str(word))
url = f'https://ai-backend.binwang.me/v0.2/couplet/{text}' url = f'https://ai-backend.binwang.me/v0.2/couplet/{text}'
res = await aiorequests.get(url=url) res = await aiorequests.get(url=url)

View File

@ -2,8 +2,9 @@ import re
from nonebot import on_command, require, get_bot, logger from nonebot import on_command, require, get_bot, logger
from nonebot.params import CommandArg from nonebot.params import CommandArg
from nonebot.adapters.onebot.v11 import MessageEvent, MessageSegment from nonebot.adapters.onebot.v11 import MessageEvent, MessageSegment
from ..utils.util import load_data, save_data, get_id from utils import aiorequests
from ..utils.http_util 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) 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时间 # 匹配msg中的xx:xx时间
time_str = re.search(r'(\d{1,2}):(\d{2})', msg) time_str = re.search(r'(\d{1,2}):(\d{2})', msg)
if time_str: if time_str:
push_data = load_data('news60s_push.json') push_data = load_json('news60s_push.json')
push_id = str(get_id(event)) push_id = str(get_message_id(event))
push_data[push_id] = { push_data[push_id] = {
'type': event.message_type, 'type': event.message_type,
'hour': int(time_str.group(1)), 'hour': int(time_str.group(1)),
@ -31,26 +32,27 @@ async def news60s_pic_handler(event: MessageEvent, msg=CommandArg()):
} }
if event.message_type == 'guild': if event.message_type == 'guild':
push_data[push_id]['guild_id'] = event.guild_id push_data[push_id]['guild_id'] = event.guild_id
if scheduler.get_job('60sNews' + str(get_id(event))): if scheduler.get_job('60sNews' + str(get_message_id(event))):
scheduler.remove_job('60sNews' + str(get_id(event))) scheduler.remove_job('60sNews' + str(get_message_id(event)))
scheduler.add_job( scheduler.add_job(
func=news60s_push_task, func=news60s_push_task,
trigger='cron', trigger='cron',
hour=int(time_str.group(1)), hour=int(time_str.group(1)),
minute=int(time_str.group(2)), minute=int(time_str.group(2)),
id='60sNews' + str(get_id(event)), id='60sNews' + str(get_message_id(event)),
args=(str(get_id(event)), args=(str(get_message_id(event)),
push_data[str(get_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) await news60s_pic.finish('开启60s读世界推送成功', at_sender=True)
else: else:
await news60s_pic.finish('请给出正确的时间格式为12:00', at_sender=True) await news60s_pic.finish('请给出正确的时间格式为12:00', at_sender=True)
elif msg.startswith('关闭推送'): elif msg.startswith('关闭推送'):
push_data = load_data('news60s_push.json') push_data = load_json('news60s_push.json')
del push_data[str(get_id(event))] del push_data[str(get_message_id(event))]
scheduler.remove_job('60sNews' + str(get_id(event))) if scheduler.get_job('60sNews' + str(get_message_id(event))):
save_data(push_data, 'news60s_push.json') scheduler.remove_job('60sNews' + str(get_message_id(event)))
save_json(push_data, 'news60s_push.json')
await news60s_pic.finish('关闭60s读世界推送成功', at_sender=True) 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}') 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( scheduler.add_job(
func=news60s_push_task, func=news60s_push_task,
trigger='cron', trigger='cron',

View File

@ -2,8 +2,8 @@ import random
from nonebot import on_command from nonebot import on_command
from nonebot.params import CommandArg from nonebot.params import CommandArg
from nonebot.adapters.onebot.v11 import Message, MessageEvent, MessageSegment from nonebot.adapters.onebot.v11 import Message, MessageEvent, MessageSegment
from ..utils.util import FreqLimiter from utils.auth_util import FreqLimiter
from ..utils.http_util import aiorequests from utils import aiorequests
order_pic = on_command('点菜', aliases={'点餐', '食谱', '我想吃'}, priority=13, block=True) order_pic = on_command('点菜', aliases={'点餐', '食谱', '我想吃'}, priority=13, block=True)
order_lmt = FreqLimiter(10) order_lmt = FreqLimiter(10)

View File

@ -2,8 +2,10 @@ import random
from nonebot import on_command, on_regex from nonebot import on_command, on_regex
from nonebot.params import RegexGroup from nonebot.params import RegexGroup
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, MessageSegment from nonebot.adapters.onebot.v11 import Bot, MessageEvent, MessageSegment
from ..utils.config import config from utils.config import config
from ..utils.util import FreqLimiter, auto_withdraw, get_id 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) cat_lmt = FreqLimiter(config.paimon_cat_cd)
ecy_lmt = FreqLimiter(config.paimon_ecy_cd) ecy_lmt = FreqLimiter(config.paimon_ecy_cd)
@ -16,11 +18,11 @@ ys_img = on_command('原神壁纸', aliases={'来点原神图', '来点原神壁
@cat_img.handle() @cat_img.handle()
async def cat_img_handler(event: MessageEvent): async def cat_img_handler(event: MessageEvent):
if not cat_lmt.check(get_id(event)): if not cat_lmt.check(get_message_id(event)):
await cat_img.finish(f'猫片冷却ing(剩余{cat_lmt.left_time(get_id(event))}秒)') await cat_img.finish(f'猫片冷却ing(剩余{cat_lmt.left_time(get_message_id(event))}秒)')
else: else:
await cat_img.send('派蒙努力找图ing..请稍候...') 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/' url = 'http://edgecats.net/'
await cat_img.finish(MessageSegment.image(file=url)) 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' url = 'https://iw233.cn/api.php?sort=pc'
else: else:
url = '' url = ''
if not ecy_lmt.check(get_id(event)): if not ecy_lmt.check(get_message_id(event)):
await ecy_img.finish(f'二次元图片冷却ing(剩余{ecy_lmt.left_time(get_id(event))}秒)') await ecy_img.finish(f'二次元图片冷却ing(剩余{ecy_lmt.left_time(get_message_id(event))}秒)')
elif url: elif url:
await ecy_img.send('派蒙努力找图ing..请稍候...') 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)) 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.dujin.org/img/yuanshen/',
'https://api.dreamofice.cn/random-v0/img.php?game=ys' 'https://api.dreamofice.cn/random-v0/img.php?game=ys'
] ]
if not ys_lmt.check(get_id(event)): if not ys_lmt.check(get_message_id(event)):
await ys_img.finish(f'原神壁纸冷却ing(剩余{ys_lmt.left_time(get_id(event))}秒)') await ys_img.finish(f'原神壁纸冷却ing(剩余{ys_lmt.left_time(get_message_id(event))}秒)')
else: else:
await ys_img.send('派蒙努力找图ing..请稍候...') 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))) await ys_img.finish(MessageSegment.image(file=random.choice(urls)))

View File

@ -1,14 +1,16 @@
import os 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 re
import time 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__ = ''' __usage__ = '''
1.[xx角色攻略]查看西风驿站出品的角色一图流攻略 1.[xx角色攻略]查看西风驿站出品的角色一图流攻略
2.[xx角色材料]查看惜月出品的角色材料统计 2.[xx角色材料]查看惜月出品的角色材料统计
@ -70,7 +72,7 @@ async def genshinAttribute(event: MessageEvent):
if name in ['风主', '岩主', '雷主'] or realname: if name in ['风主', '岩主', '雷主'] or realname:
name = realname[1][0] if name not in ['风主', '岩主', '雷主'] else name name = realname[1][0] if name not in ['风主', '岩主', '雷主'] else name
img = await get_blue_pic(name) img = await get_blue_pic(name)
await attribute.finish(MessageSegment.image(file=img)) await attribute.finish(img)
else: else:
await attribute.finish(f'没有找到{name}的参考面板', at_sender=True) await attribute.finish(f'没有找到{name}的参考面板', at_sender=True)

View File

@ -1,4 +1,4 @@
from ..utils.http_util import aiorequests from utils import aiorequests
# 数据源自微信公众号原神创意工坊 # 数据源自微信公众号原神创意工坊
headers = { headers = {

View File

@ -1,9 +1,10 @@
from PIL import Image, ImageDraw, ImageFont
import os 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 .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') 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)) bg_img.alpha_composite(role_img, (130 + 204 * r, 180 + 240 * n))
r += 1 r += 1
n += 1 n += 1
bg_img = pil2b64(bg_img, 75)
bg_img = MessageSegment.image(bg_img) return MessageBuild.Image(bg_img, quality=75)
return bg_img

View File

@ -1,5 +1,5 @@
from ..utils.util import pil2b64 from utils import aiorequests
from ..utils.http_util import aiorequests from utils.message_util import MessageBuild
blue = { blue = {
'胡桃': ['', (0, 1886)], '胡桃': ['', (0, 1886)],
@ -62,6 +62,5 @@ async def get_blue_pic(name):
if c[0] == name: if c[0] == name:
img = await aiorequests.get_img(url=f'https://static.cherishmoon.fun/LittlePaimon/blue/{c[1][0]}.jpg') 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 = img.crop((0, int(c[1][1][0]), 1080, int(c[1][1][1])))
img = pil2b64(img, 100) return MessageBuild.Image(img)
return img
return None return None

View File

@ -69,6 +69,9 @@
- `原神猜语音`不再需要`我猜`,直接回答角色别名即可参与猜猜看 - `原神猜语音`不再需要`我猜`,直接回答角色别名即可参与猜猜看
- 异步请求库从`aiohttp`改用`httpx`,需安装依赖库`pip install httpx` - 异步请求库从`aiohttp`改用`httpx`,需安装依赖库`pip install httpx`
- 修复`60秒读世界`在频道无法关闭推送的BUG - 修复`60秒读世界`在频道无法关闭推送的BUG
+ 5.20
- 修复`ysc`缺少资源问题
- 封装部分常用方法,优化导包
## 功能列表 ## 功能列表

View File

@ -0,0 +1,4 @@
import os
import sys
sys.path.insert(0, os.path.dirname(__file__))

104
utils/aiorequests.py Normal file
View File

@ -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

View File

@ -1,109 +1,18 @@
import hashlib
from collections import defaultdict
from io import BytesIO
from pathlib import Path
import random
import base64 import base64
import datetime import hashlib
from time import time
import re
import string
import functools
import inspect
import json import json
import asyncio import random
from json import JSONDecodeError import string
from nonebot import get_bot from collections import defaultdict
from time import time
from nonebot import logger from nonebot import logger
from nonebot.exception import FinishedException
from nonebot.adapters.onebot.v11 import MessageEvent, Message from . import aiorequests
from nonebot.adapters.onebot.v11.exception import ActionFailed 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_private_cookie, delete_cookie
from .db_util import get_public_cookie, limit_public_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 .message_util import send_cookie_delete_msg
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
# 冷却时间限制器 # 冷却时间限制器
@ -138,19 +47,6 @@ class FreqLimiter2:
return int(self.next_time[key1][key2] - time()) + 1 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 # 获取可用的cookie
async def get_use_cookie(user_id, uid='', mys_id='', action=''): async def get_use_cookie(user_id, uid='', mys_id='', action=''):
cache_cookie = await get_cookie_cache(uid, 'uid') cache_cookie = await get_cookie_cache(uid, 'uid')
@ -222,44 +118,6 @@ async def check_retcode(data, cookie, uid):
return True return True
# 图片转b64q为质量压缩比例
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<uid>(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加密 # md5加密
def md5(text: str) -> str: def md5(text: str) -> str:
md5 = hashlib.md5() md5 = hashlib.md5()
@ -348,43 +206,5 @@ async def check_cookie(cookie):
return True 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

91
utils/decorator.py Normal file
View File

@ -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

41
utils/file_handler.py Normal file
View File

@ -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)

View File

@ -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

99
utils/message_util.py Normal file
View File

@ -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<uid>(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