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
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 # 游戏持续时间

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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获取原神抽卡记录需要一定时间

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -69,6 +69,9 @@
- `原神猜语音`不再需要`我猜`,直接回答角色别名即可参与猜猜看
- 异步请求库从`aiohttp`改用`httpx`,需安装依赖库`pip install httpx`
- 修复`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 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
# 图片转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加密
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

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