update 0.0.7.0

This commit is contained in:
HibiKier
2021-12-16 11:16:28 +08:00
parent b892617824
commit 2653f67193
141 changed files with 2693 additions and 547 deletions
+45
View File
@@ -0,0 +1,45 @@
from nonebot import on_regex
from nonebot.adapters.cqhttp import Bot, MessageEvent
from nonebot.typing import T_State
from nonebot.rule import to_me
from pathlib import Path
__zx_plugin_name__ = "关于"
__plugin_usage__ = """
usage:
想要更加了解真寻吗
指令:
关于
""".strip()
__plugin_des__ = "想要更加了解真寻吗"
__plugin_cmd__ = ["关于"]
__plugin_version__ = 0.1
__plugin_type__ = ("其他",)
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 1,
"default_status": True,
"limit_superuser": False,
"cmd": ["关于"],
}
about = on_regex("^关于$", priority=5, block=True, rule=to_me())
@about.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
ver_file = Path() / '__version__'
version = None
if ver_file.exists():
with open(ver_file, 'r', encoding='utf8') as f:
version = f.read().split(':')[-1].strip()
msg = f"""
『绪山真寻Bot』
版本:{version}
简介:基于Nonebot2与go-cqhttp开发,是一个非常可爱的Bot呀,希望与大家要好好相处
项目地址:https://github.com/HibiKier/zhenxun_bot
文档地址:https://hibikier.github.io/zhenxun_bot/
""".strip()
await about.send(msg)
+4 -1
View File
@@ -75,7 +75,10 @@ class AiMessageManager(StaticData):
:param user_id: 用户id
:param nickname: 用户昵称
"""
if len(self._data[user_id]["message"]) < 2:
try:
if len(self._data[user_id]["message"]) < 2:
return None
except KeyError:
return None
msg = await self._get_user_repeat_message_result(user_id)
if not msg:
+5 -5
View File
@@ -1,5 +1,5 @@
from nonebot.adapters.cqhttp import MessageSegment
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
from utils.message_builder import image
from configs.path_config import IMAGE_PATH
from typing import Optional
@@ -33,14 +33,14 @@ def gen_wbtop_pic(data: dict) -> MessageSegment:
生成微博热搜图片
:param data: 微博热搜数据
"""
bk = CreateImg(700, 32 * 50 + 280, 700, 32, color="#797979")
wbtop_bk = CreateImg(700, 280, background=f"{IMAGE_PATH}/other/webtop.png")
bk = BuildImage(700, 32 * 50 + 280, 700, 32, color="#797979")
wbtop_bk = BuildImage(700, 280, background=f"{IMAGE_PATH}/other/webtop.png")
bk.paste(wbtop_bk)
text_bk = CreateImg(700, 32 * 50, 700, 32, color="#797979")
text_bk = BuildImage(700, 32 * 50, 700, 32, color="#797979")
for i, data in enumerate(data):
title = f"{i+1}. {data['hot_word']}"
hot = data["hot_word_num"]
img = CreateImg(700, 30, font_size=20)
img = BuildImage(700, 30, font_size=20)
w, h = img.getsize(title)
img.text((10, int((30 - h) / 2)), title)
img.text((580, int((30 - h) / 2)), hot)
+7 -7
View File
@@ -1,4 +1,4 @@
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
from configs.path_config import IMAGE_PATH
from utils.http_utils import AsyncHttpx
from pathlib import Path
@@ -35,21 +35,21 @@ async def create_live_des_image(uid: int, title: str, cover: str, tags: str, des
sex = user_info["sex"]
face = user_info["face"]
sign = user_info["sign"]
ava = CreateImg(100, 100, background=BytesIO(await get_pic(face)))
ava = BuildImage(100, 100, background=BytesIO(await get_pic(face)))
ava.circle()
cover = CreateImg(470, 265, background=BytesIO(await get_pic(cover)))
cover = BuildImage(470, 265, background=BytesIO(await get_pic(cover)))
print()
def _create_live_des_image(
title: str,
cover: CreateImg,
cover: BuildImage,
tags: str,
des: str,
user_name: str,
sex: str,
sign: str,
ava: CreateImg,
ava: BuildImage,
):
"""
生成主播简介图片
@@ -66,6 +66,6 @@ def _create_live_des_image(
border = BORDER_PATH / "0.png"
border_img = None
if border.exists():
border_img = CreateImg(1772, 2657, background=border)
bk = CreateImg(1772, 2657, font_size=30)
border_img = BuildImage(1772, 2657, background=border)
bk = BuildImage(1772, 2657, font_size=30)
bk.paste(cover, (0, 100), center_type="by_width")
+4 -1
View File
@@ -23,7 +23,10 @@ async def search_song(song_name: str):
async def get_song_id(song_name: str) -> int:
""" """
r = await search_song(song_name)
return r["result"]["songs"][0]["id"]
try:
return r["result"]["songs"][0]["id"]
except KeyError:
return 0
async def get_song_info(songId: int):
+4 -4
View File
@@ -2,7 +2,7 @@ import psutil
import time
from datetime import datetime
from utils.http_utils import AsyncHttpx
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
from configs.path_config import IMAGE_PATH
from pathlib import Path
import asyncio
@@ -49,7 +49,7 @@ class Check:
async def show(self):
await self.check_all()
A = CreateImg(0, 0, font_size=24)
A = BuildImage(0, 0, font_size=24)
rst = (
f'[Time] {str(datetime.now()).split(".")[0]}\n'
f"-----System-----\n"
@@ -69,10 +69,10 @@ class Check:
if w > width:
width = w
height += 30
A = CreateImg(width + 50, height + 10, font_size=24, font="HWZhongSong.ttf")
A = BuildImage(width + 50, height + 10, font_size=24, font="HWZhongSong.ttf")
A.transparent(1)
A.text((10, 10), rst)
_x = max(width, height)
bk = CreateImg(_x + 100, _x + 100, background=Path(IMAGE_PATH) / "background" / "check" / "0.jpg")
bk = BuildImage(_x + 100, _x + 100, background=Path(IMAGE_PATH) / "background" / "check" / "0.jpg")
bk.paste(A, alpha=True, center_type='center')
return bk.pic2bs4()
+3 -3
View File
@@ -1,5 +1,5 @@
from nonebot.adapters.cqhttp import Bot, Message
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
from configs.path_config import IMAGE_PATH
from utils.message_builder import image
from utils.http_utils import AsyncHttpx
@@ -85,12 +85,12 @@ async def check_update(bot: Bot) -> 'int, str':
update_info = data["body"]
width = 0
height = len(update_info.split('\n')) * 24
A = CreateImg(width, height, font_size=20)
A = BuildImage(width, height, font_size=20)
for m in update_info.split('\n'):
w, h = A.getsize(m)
if w > width:
width = w
A = CreateImg(width + 50, height, font_size=20)
A = BuildImage(width + 50, height, font_size=20)
A.text((10, 10), update_info)
A.save(f'{IMAGE_PATH}/update_info.png')
await bot.send_private_msg(
+1 -1
View File
@@ -65,7 +65,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
img_msg = _text("")
for img in get_message_imgs(event.json()):
img_msg += image(img)
if not text or text in ["帮助"]:
if not text and not img_msg:
await dialogue.send("请发送[滴滴滴]+您要说的内容~", at_sender=True)
else:
group_id = 0
+10 -10
View File
@@ -6,7 +6,7 @@ from configs.path_config import IMAGE_PATH
from utils.http_utils import AsyncHttpx
import nonebot
import pypinyin
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
import platform
from services.log import logger
import random
@@ -98,37 +98,37 @@ async def generate_img(card_set: Union[Set[BaseData], List[BaseData]], game_name
num = 0
for n in star_list:
num += n
A = CreateImg(w, h)
A = BuildImage(w, h)
A.paste(card_img)
return A.pic2bs4()
def _pst(h: int, img_list: list, game_name: str, background_list: list):
card_img = CreateImg(100 * 10, h, 100, 100)
card_img = BuildImage(100 * 10, h, 100, 100)
idx = 0
for img in img_list:
try:
if game_name == 'prts':
bk = CreateImg(100, 100, color=background_list[idx])
b = CreateImg(94, 94, background=img)
bk = BuildImage(100, 100, color=background_list[idx])
b = BuildImage(94, 94, background=img)
bk.paste(b, (3, 3))
b = bk
elif game_name == 'azur' and background_list:
bk = CreateImg(100, 100, background=background_list[idx])
b = CreateImg(98, 90, background=img)
bk = BuildImage(100, 100, background=background_list[idx])
b = BuildImage(98, 90, background=img)
bk.paste(b, (1, 5))
b = bk
else:
try:
b = CreateImg(100, 100, background=img)
b = BuildImage(100, 100, background=img)
except UnidentifiedImageError as e:
logger.warning(f'无法识别图片 已删除图片,下次更新重新下载... e:{e}')
if os.path.exists(img):
os.remove(img)
b = CreateImg(100, 100, color='black')
b = BuildImage(100, 100, color='black')
except FileNotFoundError:
logger.warning(f'{img} not exists')
b = CreateImg(100, 100, color='black')
b = BuildImage(100, 100, color='black')
card_img.paste(b)
idx += 1
return card_img
+10 -3
View File
@@ -5,6 +5,7 @@ from nonebot.typing import T_State
from utils.utils import scheduler, get_bot
from .data_source import get_epic_free
from utils.manager import group_manager
from configs.config import Config
__zx_plugin_name__ = "epic免费游戏"
__plugin_usage__ = """
@@ -24,6 +25,14 @@ __plugin_settings__ = {
"cmd": ["epic"],
}
__plugin_task__ = {"epic_free_game": "epic免费游戏"}
Config.add_plugin_config(
"_task",
"DEFAULT_EPIC_FREE_GAME",
True,
help_="被动 epic免费游戏 进群默认开关状态",
default_value=True,
)
epic = on_command("epic", priority=5, block=True)
@@ -58,9 +67,7 @@ async def _():
if await group_manager.check_group_task_status(g, "epic_free_game"):
try:
msg_list, code = await get_epic_free(bot, GroupMessageEvent)
if code == 200:
if msg_list and code == 200:
await bot.send_group_forward_msg(group_id=g, messages=msg_list)
else:
await bot.send_group_msg(group_id=g, message=msg_list)
except Exception as e:
logger.error(f"GROUP {g} epic免费游戏推送错误 {type(e)}: {e}")
+8 -1
View File
@@ -19,13 +19,20 @@ usage:
重复3次相同的消息时会复读
""".strip()
__plugin_des__ = "群友的本质是什么?是复读机哒!"
__plugin_type__ = ("被动相关",)
__plugin_type__ = ("其他",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {"fudu": "复读"}
__plugin_configs__ = {
"FUDU_PROBABILITY": {"value": 0.7, "help": "复读概率", "default_value": 0.7}
}
Config.add_plugin_config(
"_task",
"DEFAULT_FUDU",
True,
help_="被动 复读 进群默认开关状态",
default_value=True,
)
class Fudu:
+9
View File
@@ -6,6 +6,7 @@ from services.log import logger
from configs.path_config import IMAGE_PATH
from .data_source import get_alc_image
from utils.manager import group_manager
from configs.config import Config
from pathlib import Path
__zx_plugin_name__ = "原神老黄历"
@@ -28,6 +29,14 @@ __plugin_settings__ = {
}
__plugin_task__ = {"genshin_alc": "原神黄历提醒"}
Config.add_plugin_config(
"_task",
"DEFAULT_GENSHIN_ALC",
True,
help_="被动 原神黄历提醒 进群默认开关状态",
default_value=True,
)
almanac = on_command("原神黄历", priority=5, block=True)
+5 -5
View File
@@ -2,7 +2,7 @@ from nonebot import on_command, Driver
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent
from utils.message_builder import image
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
from utils.browser import get_browser
from configs.path_config import IMAGE_PATH
import nonebot
@@ -131,12 +131,12 @@ async def update_image():
height = await asyncio.get_event_loop().run_in_executor(
None, get_background_height, weapons_imgs
)
background_img = CreateImg(1200, height + 100, color="#f6f2ee")
background_img = BuildImage(1200, height + 100, color="#f6f2ee")
current_width = 50
for imgs in [char_imgs, weapons_imgs]:
current_height = 20
for img in imgs:
x = CreateImg(0, 0, background=img)
x = BuildImage(0, 0, background=img)
background_img.paste(x, (current_width, current_height))
current_height += x.size[1]
current_width += 600
@@ -154,8 +154,8 @@ async def update_image():
def get_background_height(weapons_imgs: List[str]) -> int:
height = 0
for weapons in weapons_imgs:
height += CreateImg(0, 0, background=weapons).size[1]
last_weapon = CreateImg(0, 0, background=weapons_imgs[-1])
height += BuildImage(0, 0, background=weapons).size[1]
last_weapon = BuildImage(0, 0, background=weapons_imgs[-1])
w, h = last_weapon.size
last_weapon.crop((0, 0, w, h - 10))
last_weapon.save(weapons_imgs[-1])
+5 -5
View File
@@ -1,6 +1,6 @@
from pathlib import Path
from configs.path_config import IMAGE_PATH, TEXT_PATH
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
from typing import Tuple, List
from math import sqrt, pow
import random
@@ -39,7 +39,7 @@ class Map:
:param planning_route: 是否规划最佳线路
:param ratio: 压缩比率
"""
self.map = CreateImg(0, 0, background=map_path)
self.map = BuildImage(0, 0, background=map_path)
self.resource_name = resource_name
self.center_x = center_point[0]
self.center_y = center_point[1]
@@ -225,13 +225,13 @@ class Map:
# self.map.line(xy, (255, 0, 0), width=3)
# 获取资源图标
def _get_icon_image(self, id_: int) -> "CreateImg":
def _get_icon_image(self, id_: int) -> "BuildImage":
icon = icon_path / f"{id_}.png"
if icon.exists():
return CreateImg(
return BuildImage(
int(50 * self.ratio), int(50 * self.ratio), background=icon
)
return CreateImg(
return BuildImage(
int(50 * self.ratio),
int(50 * self.ratio),
background=f"{icon_path}/box.png",
@@ -3,7 +3,7 @@ from configs.path_config import IMAGE_PATH, TEXT_PATH
from PIL.Image import UnidentifiedImageError
from utils.message_builder import image
from services.log import logger
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
from asyncio.exceptions import TimeoutError
from asyncio import Semaphore
from utils.image_utils import is_valid
@@ -186,11 +186,11 @@ async def download_map_init(
force_flag=flag,
)
idx += 1
_w, h = CreateImg(0, 0, background=f"{map_path}/0.png", ratio=MAP_RATIO).size
_w, h = BuildImage(0, 0, background=f"{map_path}/0.png", ratio=MAP_RATIO).size
w = _w * len(os.listdir(map_path))
map_file = CreateImg(w, h, _w, h, ratio=MAP_RATIO)
map_file = BuildImage(w, h, _w, h, ratio=MAP_RATIO)
for i in range(idx):
map_file.paste(CreateImg(0, 0, background=f"{map_path}/{i}.png", ratio=MAP_RATIO))
map_file.paste(BuildImage(0, 0, background=f"{map_path}/{i}.png", ratio=MAP_RATIO))
map_file.save(f"{map_path}/map.png")
else:
logger.warning(f'获取原神地图失败 msg: {data["message"]}')
@@ -230,10 +230,10 @@ async def download_resource_type():
# 初始化资源图标
def gen_icon(icon: str):
A = CreateImg(0, 0, background=f"{icon_path}/box.png")
B = CreateImg(0, 0, background=f"{icon_path}/box_alpha.png")
A = BuildImage(0, 0, background=f"{icon_path}/box.png")
B = BuildImage(0, 0, background=f"{icon_path}/box_alpha.png")
icon_ = icon_path / f"{icon}"
icon_img = CreateImg(115, 115, background=icon_)
icon_img = BuildImage(115, 115, background=icon_)
icon_img.circle()
B.paste(icon_img, (17, 10), True)
B.paste(A, alpha=True)
+26
View File
@@ -0,0 +1,26 @@
from configs.config import Config
import nonebot
Config.add_plugin_config(
"genshin",
"mhyVersion",
"2.11.1"
)
Config.add_plugin_config(
"genshin",
"salt",
"xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs"
)
Config.add_plugin_config(
"genshin",
"client_type",
"5"
)
nonebot.load_plugins("plugins/genshin/query_user")
@@ -0,0 +1,97 @@
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from utils.utils import get_message_text, is_number
from ..models import Genshin
from services.log import logger
__zx_plugin_name__ = "原神绑定"
__plugin_usage__ = """
usage:
绑定原神uid等数据,cookie极为重要,请谨慎绑定
** 如果对拥有者不熟悉,并不建议添加cookie **
该项目只会对cookie用于”米游社签到“,“原神玩家查询”,“原神便笺查询”
指令:
原神绑定uid [uid]
原神绑定米游社id [mys_id]
原神绑定cookie [cookie] # 该绑定请私聊
原神解绑 [uid]
示例:原神绑定uid 92342233
如果不明白怎么获取cookie请输入“原神绑定cookie”。
""".strip()
__plugin_des__ = "绑定自己的原神uid等"
__plugin_cmd__ = ["原神绑定uid [uid]", "原神绑定米游社id [mys_id]", "原神绑定cookie [cookie]", "原神解绑"]
__plugin_type__ = ("原神相关",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["原神绑定"],
}
bind = on_command(
"原神绑定uid", aliases={"原神绑定米游社id", "原神绑定cookie"}, priority=5, block=True
)
unbind = on_command("原神解绑", priority=5, block=True)
@bind.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
if state["_prefix"]["raw_command"] in ["原神绑定uid", "原神绑定米游社id"]:
if not is_number(msg):
await bind.finish("uid/id必须为纯数字!", at_senders=True)
msg = int(msg)
if state["_prefix"]["raw_command"] == "原神绑定uid":
uid = await Genshin.get_user_uid(event.user_id)
if uid:
await bind.finish(f"您已绑定过uid:{uid},如果希望更换uid,请先发送原神解绑")
flag = await Genshin.add_uid(event.user_id, msg)
if not flag:
await bind.finish("添加失败,该uid可能已存在...")
_x = f"已成功添加原神uid:{msg}"
elif state["_prefix"]["raw_command"] == "原神绑定米游社id":
uid = await Genshin.get_user_uid(event.user_id)
if not uid:
await bind.finish("请先绑定原神uid..")
await Genshin.set_mys_id(uid, msg)
_x = f"已成功为uid:{uid} 设置米游社id:{msg}"
else:
if not msg:
await bind.finish(
"私聊发送!!\n打开https://bbs.mihoyo.com/ys/登录后按F12点击控制台输入document.cookie复制输出的内容即可"
)
if isinstance(event, GroupMessageEvent):
await bind.finish("请立即撤回你的消息并私聊发送!")
uid = await Genshin.get_user_uid(event.user_id)
if not uid:
await bind.finish("请先绑定原神uid..")
if msg.startswith('"'):
msg = msg[1:]
if msg.endswith('"'):
msg = msg[:-1]
await Genshin.set_cookie(uid, msg)
_x = f"已成功为uid:{uid} 设置cookie"
await bind.send(_x)
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" {state['_prefix']['raw_command']}:{msg}"
)
@unbind.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
if await Genshin.delete_user(event.user_id):
await unbind.send("用户数据删除成功...")
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f"原神解绑"
)
else:
await unbind.send("该用户数据不存在..")
@@ -0,0 +1,210 @@
from services.db_context import db
from typing import Optional, Union
class Genshin(db.Model):
__tablename__ = "genshin"
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
uid = db.Column(db.BigInteger())
mys_id = db.Column(db.BigInteger())
cookie = db.Column(db.String(), default="")
today_query_uid = db.Column(db.String(), default="") # 该cookie今日查询的uid
auto_sign = db.Column(db.Boolean(), default=False) # 自动签到
_idx1 = db.Index("genshin_uid_idx1", "user_qq", "uid", unique=True)
@classmethod
async def add_uid(cls, user_qq: int, uid: int):
"""
说明:
添加一个uid
参数:
:param user_qq: 用户qq
:param uid: 原神uid
"""
query = cls.query.where((cls.user_qq == user_qq) & (cls.uid == uid))
user = await query.gino.first()
if not user:
await cls.create(
user_qq=user_qq,
uid=uid,
)
return True
return False
@classmethod
async def set_mys_id(cls, uid: int, mys_id: int) -> bool:
"""
说明:
设置米游社id
参数:
:param uid: 原神uid
:param mys_id: 米游社id
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(mys_id=mys_id).apply()
return True
return False
@classmethod
async def set_cookie(cls, uid: int, cookie: str) -> bool:
"""
说明:
设置cookie
参数:
:param uid: 原神uid
:param cookie: 米游社id
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(cookie=cookie).apply()
return True
return False
@classmethod
async def set_auto_sign(cls, uid: int, flag: bool) -> bool:
"""
说明:
设置米游社自动签到
参数:
:param uid: 原神uid
:param flag: 开关状态
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(auto_sign=flag).apply()
return True
return False
@classmethod
async def get_query_cookie(cls, uid: int) -> Optional[str]:
"""
说明:
获取查询角色信息cookie
参数:
:param uid: 原神uid
"""
# 查找用户今日是否已经查找过,防止重复
query = cls.query.where(cls.today_query_uid.contains(str(uid)))
x = await query.gino.first()
if x:
return x.cookie
for u in [x for x in await cls.query.order_by(db.func.random()).gino.all() if x.cookie]:
if not u.today_query_uid or len(u.today_query_uid[:-1].split()) < 30:
await cls._add_query_uid(uid, u.uid)
return u.cookie
return None
@classmethod
async def get_user_cookie(cls, uid: int, flag: bool = False) -> Optional[str]:
"""
说明:
获取用户cookie
参数:
:param uid:原神uid
:param flag:必须使用自己的cookie
"""
cookie = await cls._get_user_data(None, uid, "cookie")
print(uid, cookie)
if not cookie and not flag:
cookie = await cls.get_query_cookie(uid)
print(uid, cookie)
return cookie
@classmethod
async def get_user_uid(cls, user_qq: int) -> Optional[int]:
"""
说明:
获取用户uid
参数:
:param user_qq:用户qq
"""
return await cls._get_user_data(user_qq, None, "uid")
@classmethod
async def get_user_mys_id(cls, uid: int) -> Optional[int]:
"""
说嘛:
获取用户米游社id
参数:
:param uid:原神id
"""
return await cls._get_user_data(None, uid, "mys_id")
@classmethod
async def delete_user_cookie(cls, uid: int):
"""
说明:
删除用户cookie
参数:
:param uid: 原神uid
"""
query = cls.query.where(cls.uid == uid).with_for_update()
user = await query.gino.first()
if user:
await user.update(cookie="").apply()
@classmethod
async def delete_user(cls, user_qq: int):
"""
说明:
删除用户数据
参数:
:param user_qq: 用户qq
"""
query = cls.query.where(cls.user_qq == user_qq).with_for_update()
user = await query.gino.first()
if not user:
return False
await user.delete()
return True
@classmethod
async def _add_query_uid(cls, uid: int, cookie_uid: int):
"""
说明:
添加每日查询重复uid的cookie
参数:
:param uid: 原神uid
:param cookie_uid: cookie的uid
"""
query = cls.query.where(cls.uid == cookie_uid).with_for_update()
user = await query.gino.first()
await user.update(today_query_uid=cls.today_query_uid + f"{uid} ").apply()
@classmethod
async def _get_user_data(
cls, user_qq: Optional[int], uid: Optional[int], type_: str
) -> Optional[Union[int, str]]:
"""
说明:
获取用户数据
参数:
:param user_qq: 用户qq
:param uid: uid
:param type_: 数据类型
"""
if type_ == "uid":
user = await cls.query.where(cls.user_qq == user_qq).gino.first()
return user.uid if user else None
user = await cls.query.where(cls.uid == uid).gino.first()
if not user:
return None
if type_ == "mys_id":
return user.mys_id
elif type_ == "cookie":
return user.cookie
@classmethod
async def reset_today_query_uid(cls):
for u in await cls.query.with_for_update().gino.all():
if u.today_query_uid:
await u.update(
today_query_uid=""
).apply()
@@ -0,0 +1,53 @@
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from services.log import logger
from .data_source import get_user_memo
from ..models import Genshin
__zx_plugin_name__ = "原神便笺查询"
__plugin_usage__ = """
usage:
通过指定cookie和uid查询事实数据
指令:
原神便笺查询/yss
示例:原神便笺查询 92342233
""".strip()
__plugin_des__ = "不能浪费丝毫体力"
__plugin_cmd__ = ["原神便笺查询/yss"]
__plugin_type__ = ("原神相关",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["原神便笺查询"],
}
query_memo_matcher = on_command("原神便签查询", aliases={"原神便笺查询", "yss"}, priority=5, block=True)
@query_memo_matcher.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
uid = await Genshin.get_user_uid(event.user_id)
if not uid or not await Genshin.get_user_cookie(uid, True):
await query_memo_matcher.finish("请先绑定uid和cookie!")
if isinstance(event, GroupMessageEvent):
uname = event.sender.card or event.sender.nickname
else:
uname = event.sender.nickname
data = await get_user_memo(event.user_id, uid, uname)
if data:
await query_memo_matcher.send(data)
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 使用原神便笺查询 uid:{uid}"
)
else:
await query_memo_matcher.send("未查询到数据...")
@@ -0,0 +1,237 @@
from typing import Optional, Union
from nonebot.adapters.cqhttp import MessageSegment
from configs.config import Config
from asyncio.exceptions import TimeoutError
from services.log import logger
from configs.path_config import IMAGE_PATH
from utils.image_utils import BuildImage
from utils.http_utils import AsyncHttpx
from utils.utils import get_user_avatar
from utils.message_builder import image
from ..utils import get_ds
from ..models import Genshin
from io import BytesIO
from pathlib import Path
from nonebot import Driver
import asyncio
import nonebot
driver: Driver = nonebot.get_driver()
memo_path = Path(IMAGE_PATH) / "genshin" / "genshin_memo"
memo_path.mkdir(exist_ok=True, parents=True)
@driver.on_startup
async def _():
for name, url in zip(
["resin.png", "task.png", "resin_discount.png"],
[
"https://upload-bbs.mihoyo.com/upload/2021/09/29/8819732/54266243c7d15ba31690c8f5d63cc3c6_71491376413333325"
"20.png?x-oss-process=image//resize,s_600/quality,q_80/auto-orient,0/interlace,1/format,png",
"https://patchwiki.biligame.com/images/ys/thumb/c/cc/6k6kuj1kte6m1n7hexqfrn92z6h4yhh.png/60px-委托任务logo.png",
"https://patchwiki.biligame.com/images/ys/d/d9/t1hv6wpucbwucgkhjntmzroh90nmcdv.png",
],
):
file = memo_path / name
if not file.exists():
await AsyncHttpx.download_file(url, file)
logger.info(f"已下载原神便签资源 -> {file}...")
async def get_user_memo(user_id: int, uid: int, uname: str) -> Optional[Union[str, MessageSegment]]:
uid = str(uid)
if uid[0] == "1" or uid[0] == "2":
server_id = "cn_gf01"
elif uid[0] == "5":
server_id = "cn_qd01"
else:
return None
return await parse_data_and_draw(user_id, uid, server_id, uname)
async def get_memo(uid: str, server_id: str) -> "Union[str, dict], int":
try:
req = await AsyncHttpx.get(
url=f"https://api-takumi.mihoyo.com/game_record/app/genshin/api/dailyNote?server={server_id}&role_id={uid}",
headers={
"DS": get_ds(f"role_id={uid}&server={server_id}"),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": Config.get_config("genshin", "client_type"),
"Referer": "https://webstatic.mihoyo.com/",
"Cookie": await Genshin.get_user_cookie(int(uid))
},
)
data = req.json()
if data["message"] == "OK":
return data["data"], 200
return data["message"], 999
except TimeoutError:
return "访问超时,请稍后再试", 997
except Exception as e:
logger.info(f"便签查询获取失败未知错误 {e}:{e}")
return "发生了一些错误,请稍后再试", 998
def create_border(
image_name: str, content: str, notice_text: str, value: str
) -> BuildImage:
border = BuildImage(500, 100, color="#E0D9D1", font="HYWenHei-85W.ttf", font_size=20)
text_bk = BuildImage(350, 96, color="#F5F1EB", font_size=23, font="HYWenHei-85W.ttf")
_x = 70 if image_name == "resin.png" else 50
_px = 10 if image_name == "resin.png" else 20
text_bk.paste(
BuildImage(_x, _x, background=memo_path / image_name),
(_px, 0),
True,
center_type="by_height",
)
text_bk.text((87, 20), content)
text_bk.paste(
BuildImage(
0,
0,
plain_text=notice_text,
font_color=(203, 189, 175),
font="HYWenHei-85W.ttf",
font_size=17,
),
(87, 50),
True,
)
font_width, _ = border.getsize(value)
border.text((350 + 76 - int(font_width / 2), 0), value, center_type="by_height")
border.paste(text_bk, (2, 0), center_type="by_height")
return border
async def parse_data_and_draw(
user_id: int, uid: str, server_id: str, uname: str
) -> Union[str, MessageSegment]:
data, code = await get_memo(uid, server_id)
if code != 200:
return data
user_avatar = BytesIO(await get_user_avatar(user_id))
for x in data["expeditions"]:
file_name = x["avatar_side_icon"].split("_")[-1]
role_avatar = memo_path / "role_avatar" / file_name
if not role_avatar.exists():
await AsyncHttpx.download_file(x["avatar_side_icon"], role_avatar)
return await asyncio.get_event_loop().run_in_executor(
None, _parse_data_and_draw, data, user_avatar, uid, uname
)
def _parse_data_and_draw(
data: dict, user_avatar: BytesIO, uid: int, uname: str
) -> Union[str, MessageSegment]:
current_resin = data["current_resin"] # 当前树脂
max_resin = data["max_resin"] # 最大树脂
resin_recovery_time = data["resin_recovery_time"] # 树脂全部回复时间
finished_task_num = data["finished_task_num"] # 完成的每日任务
total_task_num = data["total_task_num"] # 每日任务总数
remain_resin_discount_num = data["remain_resin_discount_num"] # 值得铭记的强敌总数
resin_discount_num_limit = data["resin_discount_num_limit"] # 剩余值得铭记的强敌
current_expedition_num = data["current_expedition_num"] # 当前挖矿人数
max_expedition_num = data["max_expedition_num"] # 每日挖矿最大人数
expeditions = data["expeditions"] # 挖矿详情
minute, second = divmod(int(resin_recovery_time), 60)
hour, minute = divmod(minute, 60)
A = BuildImage(1030, 520, color="#f1e9e1", font_size=15, font="HYWenHei-85W.ttf")
A.text((10, 15), "原神便笺 | Create By ZhenXun", (198, 186, 177))
ava = BuildImage(100, 100, background=user_avatar)
ava.circle()
A.paste(ava, (40, 40), True)
A.paste(
BuildImage(0, 0, plain_text=uname, font_size=20, font="HYWenHei-85W.ttf"),
(160, 62),
True,
)
A.paste(
BuildImage(
0,
0,
plain_text=f"UID:{uid}",
font_size=15,
font="HYWenHei-85W.ttf",
font_color=(21, 167, 89),
),
(160, 92),
True,
)
border = create_border(
"resin.png",
"原粹树脂",
"将在{:0>2d}:{:0>2d}:{:0>2d}秒后全部恢复".format(hour, minute, second),
f"{current_resin}/{max_resin}",
)
A.paste(border, (10, 155))
border = create_border(
"task.png",
"每日委托",
"今日委托已全部完成" if finished_task_num == total_task_num else "今日委托完成数量不足",
f"{finished_task_num}/{total_task_num}",
)
A.paste(border, (10, 265))
border = create_border(
"resin_discount.png",
"值得铭记的强敌",
"本周剩余消耗减半次数",
f"{remain_resin_discount_num}/{resin_discount_num_limit}",
)
A.paste(border, (10, 375))
expeditions_border = BuildImage(
470, 430, color="#E0D9D1", font="HYWenHei-85W.ttf", font_size=20
)
expeditions_text = BuildImage(
466, 426, color="#F5F1EB", font_size=23, font="HYWenHei-85W.ttf"
)
expeditions_text.text(
(5, 5), f"探索派遣限制{current_expedition_num}/{max_expedition_num}", (100, 100, 98)
)
h = 45
for x in expeditions:
_bk = BuildImage(400, 66, color="#ECE3D8", font="HYWenHei-85W.ttf", font_size=21)
file_name = x["avatar_side_icon"].split("_")[-1]
role_avatar = memo_path / "role_avatar" / file_name
_ava_img = BuildImage(75, 75, background=role_avatar)
_ava_img.circle()
if x["status"] == "Finished":
msg = "探索完成"
font_color = (146, 188, 63)
_circle_color = (146, 188, 63)
else:
minute, second = divmod(int(x["remained_time"]), 60)
hour, minute = divmod(minute, 60)
font_color = (193, 180, 167)
msg = "还剩{:0>2d}小时{:0>2d}分钟{:0>2d}秒".format(hour, minute, second)
_circle_color = "#DE9C58"
_circle_bk = BuildImage(60, 60)
_circle_bk.circle()
a_circle = BuildImage(55, 55, color=_circle_color)
a_circle.circle()
b_circle = BuildImage(47, 47)
b_circle.circle()
a_circle.paste(b_circle, (4, 4), alpha=True)
_circle_bk.paste(a_circle, (4, 4), alpha=True)
_bk.paste(_circle_bk, (25, 0), True, center_type="by_height")
_bk.paste(_ava_img, (19, -13), True)
_bk.text((100, 0), msg, font_color, "by_height")
_bk.circle_corner(20)
expeditions_text.paste(_bk, (25, h), True)
h += 75
expeditions_border.paste(expeditions_text, center_type="center")
A.paste(expeditions_border, (550, 45))
return image(b64=A.pic2bs4())
@@ -0,0 +1,61 @@
from nonebot import on_command
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from services.log import logger
from .data_source import query_role_data
from ..models import Genshin
from utils.utils import get_message_text, is_number
__zx_plugin_name__ = "原神玩家查询"
__plugin_usage__ = """
usage:
通过uid查询原神玩家信息
指令:
原神玩家查询/ys ?[uid]
示例:原神玩家查询 92342233
""".strip()
__plugin_des__ = "请问你们有几个肝?"
__plugin_cmd__ = ["原神玩家查询/ys"]
__plugin_type__ = ("原神相关",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["原神玩家查询"],
}
query_role_info_matcher = on_command("原神玩家查询", aliases={"原神玩家查找", "ys"}, priority=5, block=True)
@query_role_info_matcher.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
if msg:
if not is_number(msg):
await query_role_info_matcher.finish("查询uid必须为数字!")
msg = int(msg)
if not msg:
uid = await Genshin.get_user_uid(event.user_id)
else:
uid = msg
if not uid: # or not await Genshin.get_user_cookie(uid):
await query_role_info_matcher.finish("请先绑定uid和cookie!")
nickname = event.sender.card if event.sender.card else event.sender.nickname
mys_id = await Genshin.get_user_mys_id(uid)
data = await query_role_data(event.user_id, uid, mys_id, nickname)
if data:
await query_role_info_matcher.send(data)
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 使用原神玩家查询 uid:{uid}"
)
else:
await query_role_info_matcher.send("查询失败..")
@@ -0,0 +1,249 @@
from typing import Optional, List, Dict, Union
from .draw_image import init_image, get_genshin_image
from nonebot.adapters.cqhttp import MessageSegment
from ..utils import get_ds, element_mastery
from services.log import logger
from utils.http_utils import AsyncHttpx
from configs.config import Config
from ..models import Genshin
try:
import ujson as json
except ModuleNotFoundError:
import json
async def query_role_data(
user_id: int, uid: int, mys_id: Optional[str] = None, nickname: Optional[str] = None
) -> Optional[Union[MessageSegment, str]]:
uid = str(uid)
if uid[0] == "1" or uid[0] == "2":
server_id = "cn_gf01"
elif uid[0] == "5":
server_id = "cn_qd01"
else:
return None
return await get_image(user_id, uid, server_id, mys_id, nickname)
async def get_image(
user_id: int,
uid: str,
server_id: str,
mys_id: Optional[str] = None,
nickname: Optional[str] = None,
) -> Optional[Union[MessageSegment, str]]:
"""
生成图片
:param user_id:用户qq
:param uid: 用户uid
:param server_id: 服务器
:param mys_id: 米游社id
:param nickname: QQ昵称
:return:
"""
data, code = await get_info(uid, server_id)
if code != 200:
return data
if data:
char_data_list, role_data, world_data_dict, home_data_list = parsed_data(data)
mys_data = await get_mys_data(uid, mys_id)
if mys_data:
nickname = None
if char_data_list:
char_detailed_data = await get_character(
uid, [x["id"] for x in char_data_list], server_id
)
_x = {}
if char_detailed_data:
for char in char_detailed_data["avatars"]:
_x[char["name"]] = {
"weapon": char["weapon"]["name"],
"weapon_image": char["weapon"]["icon"],
"level": char["weapon"]["level"],
"affix_level": char["weapon"]["affix_level"],
}
await init_image(char_data_list, _x)
return await get_genshin_image(
user_id,
uid,
char_data_list,
role_data,
world_data_dict,
home_data_list,
_x,
mys_data,
nickname,
)
return "未找到用户数据..."
# Github-@lulu666lulu https://github.com/Azure99/GenshinPlayerQuery/issues/20
"""
{body:"",query:{"action_ticket": undefined, "game_biz": "hk4e_cn”}}
对应 https://api-takumi.mihoyo.com/binding/api/getUserGameRolesByCookie?game_biz=hk4e_cn //查询米哈游账号下绑定的游戏(game_biz可留空)
{body:"",query:{"uid": 12345(被查询账号米哈游uid)}}
对应 https://api-takumi.mihoyo.com/game_record/app/card/wapi/getGameRecordCard?uid=
{body:"",query:{'role_id': '查询账号的uid(游戏里的)' ,'server': '游戏服务器'}}
对应 https://api-takumi.mihoyo.com/game_record/app/genshin/api/index?server= server信息 &role_id= 游戏uid
{body:"",query:{'role_id': '查询账号的uid(游戏里的)' , 'schedule_type': 1(我这边只看到出现过1和2), 'server': 'cn_gf01'}}
对应 https://api-takumi.mihoyo.com/game_record/app/genshin/api/spiralAbyss?schedule_type=1&server= server信息 &role_id= 游戏uid
{body:"",query:{game_id: 2(目前我知道有崩坏3是1原神是2)}}
对应 https://api-takumi.mihoyo.com/game_record/app/card/wapi/getAnnouncement?game_id= 这个是公告api
b=body q=query
其中b只在post的时候有内容,q只在get的时候有内容
"""
async def get_info(uid_: str, server_id: str) -> "Optional[Union[dict, str]], int":
try:
req = await AsyncHttpx.get(
url=f"https://api-takumi.mihoyo.com/game_record/app/genshin/api/index?server={server_id}&role_id={uid_}",
headers={
"Accept": "application/json, text/plain, */*",
"DS": get_ds(f"role_id={uid_}&server={server_id}"),
"Origin": "https://webstatic.mihoyo.com",
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (Linux; Android 9; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/39.0.0.0 Mobile Safari/537.36 miHoYoBBS/2.2.0",
"x-rpc-client_type": Config.get_config("genshin", "client_type"),
"Referer": "https://webstatic.mihoyo.com/app/community-game-records/index.html?v=6",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,en-US;q=0.8",
"X-Requested-With": "com.mihoyo.hyperion",
"Cookie": await Genshin.get_user_cookie(int(uid_))
},
)
data = req.json()
if data["message"] == "OK":
return data["data"], 200
return data["message"], 999
except Exception as e:
logger.error(f"访问失败,请重试! {type(e)}: {e}")
return None, -1
async def get_character(
uid: str, character_ids: List[str], server_id="cn_gf01"
) -> Optional[dict]:
try:
req = await AsyncHttpx.post(
url="https://api-takumi.mihoyo.com/game_record/app/genshin/api/character",
headers={
"Accept": "application/json, text/plain, */*",
"DS": get_ds(
"",
{
"character_ids": character_ids,
"role_id": uid,
"server": server_id,
},
),
"Origin": "https://webstatic.mihoyo.com",
"Cookie": await Genshin.get_user_cookie(int(uid)),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": "5",
"Referer": "https://webstatic.mihoyo.com/",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,en-US;q=0.8",
"X-Requested-With": "com.mihoyo.hyperion",
},
json={"character_ids": character_ids, "role_id": uid, "server": server_id},
)
data = req.json()
if data["message"] == "OK":
return data["data"]
except Exception as e:
logger.error(f"访问失败,请重试! {type(e)}: {e}")
return None
def parsed_data(
data: dict,
) -> "Optional[List[Dict[str, str]]], Dict[str, str], Optional[List[Dict[str, str]]], Optional[List[Dict[str, str]]]":
"""
解析数据
:param data: 数据
"""
char_data_list = []
for char in data["avatars"]:
_x = {
"id": char["id"],
"image": char["image"],
"name": char["name"],
"element": element_mastery[char["element"].lower()],
"fetter": char["fetter"],
"level": char["level"],
"rarity": char["rarity"],
"actived_constellation_num": char["actived_constellation_num"],
}
char_data_list.append(_x)
role_data = {
"active_day_number": data["stats"]["active_day_number"], # 活跃天数
"achievement_number": data["stats"]["achievement_number"], # 达成成就数量
"win_rate": data["stats"]["win_rate"],
"anemoculus_number": data["stats"]["anemoculus_number"], # 风神瞳已收集
"geoculus_number": data["stats"]["geoculus_number"], # 岩神瞳已收集
"avatar_number": data["stats"]["avatar_number"], # 获得角色数量
"way_point_number": data["stats"]["way_point_number"], # 传送点已解锁
"domain_number": data["stats"]["domain_number"], # 秘境解锁数量
"spiral_abyss": data["stats"]["spiral_abyss"], # 深渊当期进度
"precious_chest_number": data["stats"]["precious_chest_number"], # 珍贵宝箱
"luxurious_chest_number": data["stats"]["luxurious_chest_number"], # 华丽宝箱
"exquisite_chest_number": data["stats"]["exquisite_chest_number"], # 精致宝箱
"magic_chest_number": data["stats"]["magic_chest_number"], # 奇馈宝箱
"common_chest_number": data["stats"]["common_chest_number"], # 普通宝箱
"electroculus_number": data["stats"]["electroculus_number"], # 雷神瞳已收集
}
world_data_dict = {}
for world in data["world_explorations"]:
_x = {
"level": world["level"], # 声望等级
"exploration_percentage": world["exploration_percentage"], # 探索进度
"image": world["icon"],
"name": world["name"],
"offerings": world["offerings"],
}
world_data_dict[world["name"]] = _x
home_data_list = []
for home in data["homes"]:
_x = {
"level": home["level"], # 最大信任等级
"visit_num": home["visit_num"], # 最高历史访客数
"comfort_num": home["comfort_num"], # 最高洞天仙力
"item_num": home["item_num"], # 已获得摆件数量
"name": home["name"],
"icon": home["icon"],
"comfort_level_name": home["comfort_level_name"],
"comfort_level_icon": home["comfort_level_icon"],
}
home_data_list.append(_x)
return char_data_list, role_data, world_data_dict, home_data_list
async def get_mys_data(uid: str, mys_id: Optional[str]) -> Optional[List[Dict]]:
"""
获取用户米游社数据
:param uid: 原神uid
:param mys_id: 米游社id
"""
if mys_id:
try:
req = await AsyncHttpx.get(
url=f"https://api-takumi.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid={mys_id}",
headers={
"DS": get_ds(f"uid={mys_id}"),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1",
"x-rpc-client_type": "5",
"Referer": "https://webstatic.mihoyo.com/",
"Cookie": await Genshin.get_user_cookie(int(uid))
},
)
data = req.json()
if data["message"] == "OK":
return data["data"]["list"]
except Exception as e:
logger.error(f"访问失败,请重试! {type(e)}: {e}")
return None
@@ -0,0 +1,530 @@
from configs.path_config import IMAGE_PATH
from pathlib import Path
from utils.image_utils import BuildImage
from typing import List, Dict, Optional
from utils.message_builder import image
from nonebot.adapters.cqhttp import MessageSegment
from utils.http_utils import AsyncHttpx
from utils.utils import get_user_avatar
from io import BytesIO
import random
import asyncio
import os
image_path = Path(IMAGE_PATH) / "genshin" / "genshin_card"
async def get_genshin_image(
user_id: int,
uid: str,
char_data_list: List[Dict],
role_data: Dict,
world_data_dict: Dict,
home_data_list: List[Dict],
char_detailed_dict: dict = None,
mys_data: Optional[List[Dict]] = None,
nickname: Optional[str] = None,
) -> MessageSegment:
"""
生成图片数据
:param user_id:用户qq
:param uid: 原神uid
:param char_data_list: 角色列表
:param role_data: 玩家数据
:param world_data_dict: 国家数据字典
:param home_data_list: 家园列表
:param char_detailed_dict: 角色武器字典
:param mys_data: 用户米游社数据
:param nickname: 用户昵称
"""
user_ava = BytesIO(await get_user_avatar(user_id))
return await asyncio.get_event_loop().run_in_executor(
None,
_get_genshin_image,
uid,
char_data_list,
role_data,
world_data_dict,
home_data_list,
char_detailed_dict,
mys_data,
nickname,
user_ava,
)
def _get_genshin_image(
uid: str,
char_data_list: List[Dict],
role_data: Dict,
world_data_dict: Dict,
home_data_list: List[Dict],
char_detailed_dict: dict = None,
mys_data: Optional[Dict] = None,
nickname: Optional[str] = None,
user_ava: Optional[BytesIO] = None,
) -> MessageSegment:
"""
生成图片数据
:param uid: 原神uid
:param char_data_list: 角色列表
:param role_data: 玩家数据
:param world_data_dict: 国家数据字典
:param home_data_list: 家园列表
:param char_detailed_dict: 角色武器字典
:param mys_data: 用户米游社数据
:param nickname: 用户昵称
:param user_ava:用户头像
"""
x = 450 if char_detailed_dict else 330
char_height = (
len(char_data_list) / 7
if len(char_data_list) % 7 == 0
else len(char_data_list) / 7 + 1
)
foot = BuildImage(1700, 87, background=image_path / "head.png")
head = BuildImage(1700, 87, background=image_path / "head.png")
head.rotate(180)
middle = BuildImage(
1700, int(1600 + 200 + x * char_height), background=image_path / "middle.png"
)
A = BuildImage(middle.w, middle.h + foot.h + head.h)
A.paste(head, (-5, 0), True)
A.paste(middle, (0, head.h), True)
A.paste(foot, (0, head.h + middle.h), True)
A.crop((0, 0, A.w - 5, A.h))
user_image = get_user_data_image(uid, role_data, mys_data, nickname, user_ava)
home_image = get_home_data_image(home_data_list)
country_image = get_country_data_image(world_data_dict)
char_image, _h = get_char_data_image(char_data_list, char_detailed_dict)
top_bk = BuildImage(user_image.w, user_image.h + home_image.h + 100, color="#F9F6F2")
top_bk.paste(user_image, alpha=True)
top_bk.paste(home_image, (0, user_image.h + 50), alpha=True)
top_bk.paste(country_image, (home_image.w + 100, user_image.h + 50), alpha=True)
bar = BuildImage(1600, 200, font_size=50, color="#F9F6F2", font="HYWenHei-85W.ttf")
bar.text((50, 10), "角色背包", (104, 103, 101))
bar.line((50, 90, 1550, 90), (227, 219, 209), width=10)
if A.h - top_bk.h - bar.h - _h > 200:
_h = A.h - top_bk.h - bar.h - _h - 200
A.crop((0, 0, A.w, A.h - _h))
A.paste(foot, (0, A.h - 87))
A.paste(top_bk, (0, 100), center_type="by_width")
A.paste(bar, (50, top_bk.h + 80))
A.paste(char_image, (0, top_bk.h + bar.h + 10), center_type="by_width")
rand = random.randint(1, 10000)
A.save(Path(IMAGE_PATH) / "temp" / f"genshin_user_card_{rand}.png")
return image(f"genshin_user_card_{rand}.png", "temp")
def get_user_data_image(
uid: str,
role_data: Dict,
mys_data: Optional[Dict] = None,
nickname: Optional[str] = None,
user_ava: Optional[BytesIO] = None,
) -> BuildImage:
"""
画出玩家基本数据
:param uid: 原神uid
:param role_data: 玩家数据
:param mys_data: 玩家米游社数据
:param nickname: 用户昵称
:param user_ava:用户头像
"""
if mys_data:
nickname = [x["nickname"] for x in mys_data if x["game_id"] == 2][0]
region = BuildImage(1440, 450, color="#E3DBD1", font="HYWenHei-85W.ttf")
region.circle_corner(30)
uname_img = BuildImage(
0,
0,
plain_text=nickname,
font_size=40,
color=(255, 255, 255, 0),
font="HYWenHei-85W.ttf",
)
uid_img = BuildImage(
0,
0,
plain_text=f"UID: {uid}",
font_size=25,
color=(255, 255, 255, 0),
font="HYWenHei-85W.ttf",
font_color=(21, 167, 89),
)
ava_bk = BuildImage(270, 270, background=image_path / "cover.png")
# 用户头像
if user_ava:
ava_img = BuildImage(200, 200, background=user_ava)
ava_img.circle()
ava_bk.paste(ava_img, alpha=True, center_type="center")
else:
ava_img = BuildImage(
245,
245,
background=image_path
/ "chars_ava"
/ random.choice(os.listdir(image_path / "chars_ava")),
)
ava_bk.paste(ava_img, (12, 16), alpha=True)
region.paste(uname_img, (int(170 + uid_img.w / 2 - uname_img.w / 2), 305), True)
region.paste(uid_img, (170, 355), True)
region.paste(ava_bk, (int(550 / 2 - ava_bk.w / 2), 40), True)
data_img = BuildImage(
800, 400, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
)
_height = 0
keys = [
["活跃天数", "成就达成", "获得角色", "深境螺旋"],
["华丽宝箱", "珍贵宝箱", "精致宝箱", "普通宝箱"],
["奇馈宝箱", "风神瞳", "岩神瞳", "雷神瞳"],
]
values = [
[
role_data["active_day_number"],
role_data["achievement_number"],
role_data["avatar_number"],
role_data["spiral_abyss"],
],
[
role_data["luxurious_chest_number"],
role_data["precious_chest_number"],
role_data["exquisite_chest_number"],
role_data["common_chest_number"],
],
[
role_data["magic_chest_number"],
role_data["anemoculus_number"],
role_data["geoculus_number"],
role_data["electroculus_number"],
],
]
for key, value in zip(keys, values):
_tmp_data_img = BuildImage(
800, 200, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
)
_width = 10
for k, v in zip(key, value):
t_ = BuildImage(
0,
0,
plain_text=k,
color=(255, 255, 255, 0),
font_color=(138, 143, 143),
font="HYWenHei-85W.ttf",
font_size=30,
)
tmp_ = BuildImage(
t_.w, t_.h + 70, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
)
tmp_.text((0, 0), str(v), center_type="by_width")
tmp_.paste(t_, (0, 50), True, "by_width")
_tmp_data_img.paste(tmp_, (_width if len(key) > 3 else _width + 15, 0))
_width += 200
data_img.paste(_tmp_data_img, (0, _height))
_height += _tmp_data_img.h - 70
region.paste(data_img, (510, 50))
return region
def get_home_data_image(home_data_list: List[Dict]) -> BuildImage:
"""
画出家园数据
:param home_data_list: 家园列表
"""
region = BuildImage(
550, 1050, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
)
try:
region.text(
(0, 30), f'尘歌壶 Lv.{home_data_list[0]["level"]}', center_type="by_width"
)
region.text(
(0, 980), f'仙力: {home_data_list[0]["comfort_num"]}', center_type="by_width"
)
except (IndexError, KeyError):
region.text((0, 30), f"尘歌壶 Lv.0", center_type="by_width")
region.text((0, 980), f"仙力: 0", center_type="by_width")
region.circle_corner(30)
height = 100
homes = os.listdir(image_path / "homes")
homes.remove("lock.png")
homes.sort()
unlock_home = [x["name"] for x in home_data_list]
for i, file in enumerate(homes):
home_img = image_path / "homes" / file
x = BuildImage(500, 250, background=home_img)
if file.split(".")[0] not in unlock_home:
black_img = BuildImage(500, 250, color="black")
lock_img = BuildImage(0, 0, background=image_path / "homes" / "lock.png")
black_img.circle_corner(50)
black_img.transparent(1)
black_img.paste(lock_img, alpha=True, center_type="center")
x.paste(black_img, alpha=True)
else:
black_img = BuildImage(
500, 150, color="black", font="HYWenHei-85W.ttf", font_size=40
)
black_img.text((55, 55), file.split(".")[0], fill=(226, 211, 146))
black_img.transparent(1)
text_img = BuildImage(
0,
0,
plain_text="洞天等级",
font="HYWenHei-85W.ttf",
font_color=(203, 200, 184),
font_size=35,
color=(255, 255, 255, 0),
)
level_img = BuildImage(
0,
0,
plain_text=f'{home_data_list[0]["comfort_level_name"]}',
font="HYWenHei-85W.ttf",
font_color=(211, 213, 207),
font_size=30,
color=(255, 255, 255, 0),
)
black_img.paste(text_img, (270, 25), True)
black_img.paste(level_img, (278, 85), True)
x.paste(black_img, alpha=True, center_type="center")
x.circle_corner(50)
region.paste(x, (0, height), True, "by_width")
height += 300
return region
def get_country_data_image(world_data_dict: Dict) -> BuildImage:
"""
画出国家探索供奉等图像
:param world_data_dict: 国家数据字典
"""
region = BuildImage(790, 1050, color="#F9F6F2")
height = 0
for country in ["蒙德", "龙脊雪山", "璃月", "稻妻"]:
x = BuildImage(790, 250, color="#3A4467")
logo = BuildImage(180, 180, background=image_path / "logo" / f"{country}.png")
tmp_bk = BuildImage(770, 230, color="#606779")
tmp_bk.circle_corner(10)
content_bk = BuildImage(
755, 215, color="#3A4467", font_size=40, font="HYWenHei-85W.ttf"
)
content_bk.paste(logo, (50, 0), True, "by_height")
if country in ["蒙德", "璃月"]:
content_bk.text((300, 40), "探索", fill=(239, 211, 114))
content_bk.text(
(450, 40),
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
fill=(255, 255, 255),
)
content_bk.text((300, 120), "声望", fill=(239, 211, 114))
content_bk.text(
(450, 120),
f"Lv.{world_data_dict[country]['level']}",
fill=(255, 255, 255),
)
elif country in ["龙脊雪山"]:
content_bk.text((300, 40), "探索", fill=(239, 211, 114))
content_bk.text(
(450, 40),
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
fill=(255, 255, 255),
)
content_bk.text((300, 120), "供奉", fill=(239, 211, 114))
content_bk.text(
(450, 120),
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
fill=(255, 255, 255),
)
elif country in ["稻妻"]:
content_bk.text((300, 20), "探索", fill=(239, 211, 114))
content_bk.text(
(450, 20),
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
fill=(255, 255, 255),
)
content_bk.text((300, 85), "声望", fill=(239, 211, 114))
content_bk.text(
(450, 85),
f"Lv.{world_data_dict[country]['level']}",
fill=(255, 255, 255),
)
content_bk.text((300, 150), "神樱", fill=(239, 211, 114))
content_bk.text(
(450, 150),
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
fill=(255, 255, 255),
)
x.paste(tmp_bk, alpha=True, center_type="center")
x.paste(content_bk, alpha=True, center_type="center")
x.circle_corner(20)
region.paste(x, (0, height), center_type="by_width")
height += 267
return region
def get_char_data_image(
char_data_list: List[Dict], char_detailed_dict: dict
) -> "BuildImage, int":
"""
画出角色列表
:param char_data_list: 角色列表
:param char_detailed_dict: 角色武器
"""
x = 420 if char_detailed_dict else 350
_h = x * int(
len(char_data_list) / 7
if len(char_data_list) % 7 == 0
else len(char_data_list) / 7 + 1
)
region = BuildImage(
1600,
_h,
color="#F9F6F2",
)
width = 120
height = 0
idx = 0
for char in char_data_list:
if width + 230 > 1550:
width = 120
height += x
idx += 1
char_img = image_path / "chars" / f'{char["name"]}.png'
char_bk = BuildImage(
270,
500 if char_detailed_dict else 400,
background=image_path / "element.png",
font="HYWenHei-85W.ttf",
font_size=35,
)
char_img = BuildImage(0, 0, background=char_img)
actived_constellation_num = BuildImage(
0,
0,
plain_text=f"命之座: {char['actived_constellation_num']}层",
font="HYWenHei-85W.ttf",
font_size=25,
color=(255, 255, 255, 0),
)
level = BuildImage(
0,
0,
plain_text=f"Lv.{char['level']}",
font="HYWenHei-85W.ttf",
font_size=30,
color=(255, 255, 255, 0),
font_color=(21, 167, 89),
)
love_log = BuildImage(
0,
0,
plain_text="♥",
font="HWZhongSong.ttf",
font_size=40,
color=(255, 255, 255, 0),
font_color=(232, 31, 168),
)
fetter = BuildImage(
0,
0,
plain_text=f'{char["fetter"]}',
font="HYWenHei-85W.ttf",
font_size=30,
color=(255, 255, 255, 0),
font_color=(232, 31, 168),
)
if char_detailed_dict.get(char["name"]):
weapon = BuildImage(
100,
100,
background=image_path
/ "weapons"
/ f'{char_detailed_dict[char["name"]]["weapon"]}.png',
)
weapon_name = BuildImage(
0,
0,
plain_text=f"{char_detailed_dict[char['name']]['weapon']}",
font="HYWenHei-85W.ttf",
font_size=25,
color=(255, 255, 255, 0),
)
weapon_affix_level = BuildImage(
0,
0,
plain_text=f"精炼: {char_detailed_dict[char['name']]['affix_level']}",
font="HYWenHei-85W.ttf",
font_size=20,
color=(255, 255, 255, 0),
)
weapon_level = BuildImage(
0,
0,
plain_text=f"Lv.{char_detailed_dict[char['name']]['level']}",
font="HYWenHei-85W.ttf",
font_size=25,
color=(255, 255, 255, 0),
font_color=(21, 167, 89),
)
char_bk.paste(weapon, (20, 380), True)
char_bk.paste(
weapon_name,
(100 + int((char_bk.w - 22 - weapon.w - weapon_name.w) / 2 - 10), 390),
True,
)
char_bk.paste(
weapon_affix_level,
(
(
100
+ int(
(char_bk.w - 10 - weapon.w - weapon_affix_level.w) / 2 - 10
),
420,
)
),
True,
)
char_bk.paste(
weapon_level,
(
(
100
+ int((char_bk.w - 10 - weapon.w - weapon_level.w) / 2 - 10),
450,
)
),
True,
)
char_bk.paste(char_img, (0, 5), alpha=True, center_type="by_width")
char_bk.text((0, 270), char["name"], center_type="by_width")
char_bk.paste(actived_constellation_num, (0, 310), True, "by_width")
char_bk.paste(level, (60, 340), True)
char_bk.paste(love_log, (155, 330), True)
char_bk.paste(fetter, (180, 340), True)
char_bk.resize(0.8)
region.paste(char_bk, (width, height), True)
width += 230
return region, _h
async def init_image(char_data_list: List[Dict], char_detailed_dict: dict):
"""
下载头像
:param char_data_list: 角色列表
:param char_detailed_dict: 角色武器
"""
for char in char_data_list:
file = image_path / "chars" / f'{char["name"]}.png'
file.parent.mkdir(parents=True, exist_ok=True)
if not file.exists():
await AsyncHttpx.download_file(char["image"], file)
for char in char_detailed_dict.keys():
file = image_path / "weapons" / f'{char_detailed_dict[char]["weapon"]}.png'
file.parent.mkdir(parents=True, exist_ok=True)
if not file.exists():
await AsyncHttpx.download_file(
char_detailed_dict[char]["weapon_image"], file
)
@@ -0,0 +1,17 @@
from utils.utils import scheduler
from ..models import Genshin
from services.log import logger
@scheduler.scheduled_job(
"cron",
hour=0,
minute=1,
)
async def _():
try:
await Genshin.reset_today_query_uid()
logger.warning(f"重置原神查询记录成功..")
except Exception as e:
logger.error(f"重置原神查询记录失败. {type(e)}:{e}")
@@ -0,0 +1,35 @@
from configs.config import Config
import json
import time
import random
import hashlib
def _md5(text):
md5 = hashlib.md5()
md5.update(text.encode())
return md5.hexdigest()
def get_ds(q: str = "", b: dict = None):
if b:
br = json.dumps(b)
else:
br = ""
s = Config.get_config("genshin", "salt")
t = str(int(time.time()))
r = str(random.randint(100000, 200000))
c = _md5("salt=" + s + "&t=" + t + "&r=" + r + "&b=" + br + "&q=" + q)
return t + "," + r + "," + c
element_mastery = {
"anemo": "风",
"pyro": "火",
"geo": "岩",
"electro": "雷",
"cryo": "冰",
"hydro": "水",
"dendro": "草",
"none": "无",
}
+3 -2
View File
@@ -115,6 +115,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
redbag_data[event.group_id]["amount"]
- redbag_data[event.group_id]["open_amount"]
)
await return_gold(event.user_id, event.group_id, amount)
await gold_redbag.send(
f'{redbag_data[event.group_id]["nickname"]}的红包过时未开完,退还{amount}金币...'
)
@@ -137,11 +138,11 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
else:
amount = msg[0]
num = msg[1]
if not is_number(num) or int(num) < 1:
await gold_redbag.finish("红包个数给我输正确啊!", at_sender=True)
flag, amount = await check_gold(event.user_id, event.group_id, amount)
if not flag:
await gold_redbag.finish(amount, at_sender=True)
if not is_number(num) or int(num) < 1:
await gold_redbag.finish("红包个数给我输正确啊!", at_sender=True)
group_member_num = (await bot.get_group_info(group_id=event.group_id))['member_count']
num = int(num)
if num > group_member_num:
+9 -9
View File
@@ -1,6 +1,6 @@
from models.bag_user import BagUser
from utils.utils import is_number, get_user_avatar
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
from configs.path_config import IMAGE_PATH
from .model import RedbagUser
import random
@@ -44,8 +44,8 @@ async def open_redbag(user_id: int, group_id: int, redbag_data: dict):
# 随机红包图片
async def generate_send_redbag_pic(user_id: int, msg: str = '恭喜发财 大吉大利'):
random_redbag = random.choice(os.listdir(f"{IMAGE_PATH}/prts/redbag_2"))
redbag = CreateImg(0, 0, font_size=38, background=f'{IMAGE_PATH}/prts/redbag_2/{random_redbag}')
ava = CreateImg(65, 65, background=BytesIO(await get_user_avatar(user_id)))
redbag = BuildImage(0, 0, font_size=38, background=f'{IMAGE_PATH}/prts/redbag_2/{random_redbag}')
ava = BuildImage(65, 65, background=BytesIO(await get_user_avatar(user_id)))
await asyncio.get_event_loop().run_in_executor(None, ava.circle)
redbag.text((int((redbag.size[0] - redbag.getsize(msg)[0]) / 2), 210), msg, (240, 218, 164))
redbag.paste(ava, (int((redbag.size[0] - ava.size[0])/2), 130), True)
@@ -61,19 +61,19 @@ async def generate_open_redbag_pic(user_id: int, send_user_nickname: str, amount
async def _generate_open_redbag_pic(user_id: int, send_user_nickname: str, amount: int, text: str):
send_user_nickname += '的红包'
amount = str(amount)
head = CreateImg(1000, 980, font_size=30, background=f'{IMAGE_PATH}/prts/redbag_12.png')
size = CreateImg(0, 0, font_size=50).getsize(send_user_nickname)
head = BuildImage(1000, 980, font_size=30, background=f'{IMAGE_PATH}/prts/redbag_12.png')
size = BuildImage(0, 0, font_size=50).getsize(send_user_nickname)
# QQ头像
ava_bk = CreateImg(100 + size[0], 66, color='white', font_size=50)
ava = CreateImg(66, 66, background=BytesIO(await get_user_avatar(user_id)))
ava_bk = BuildImage(100 + size[0], 66, color='white', font_size=50)
ava = BuildImage(66, 66, background=BytesIO(await get_user_avatar(user_id)))
ava_bk.paste(ava)
ava_bk.text((100, 7), send_user_nickname)
# ava_bk.show()
ava_bk_w, ava_bk_h = ava_bk.size
head.paste(ava_bk, (int((1000 - ava_bk_w) / 2), 300))
# 金额
size = CreateImg(0, 0, font_size=150).getsize(amount)
price = CreateImg(size[0], size[1], font_size=150)
size = BuildImage(0, 0, font_size=150).getsize(amount)
price = BuildImage(size[0], size[1], font_size=150)
price.text((0, 0), amount, fill=(209, 171, 108))
# 金币中文
head.paste(price, (int((1000 - size[0]) / 2) - 50, 460))
+13
View File
@@ -1,4 +1,6 @@
from configs.config import Config
from configs.path_config import IMAGE_PATH
from pathlib import Path
import nonebot
@@ -44,5 +46,16 @@ Config.add_plugin_config(
default_value=6,
)
Config.add_plugin_config(
"image_management",
"SHOW_ID",
True,
help_="是否消息显示图片下标id",
default_value=True
)
(Path(IMAGE_PATH) / "image_management").mkdir(parents=True, exist_ok=True)
nonebot.load_plugins("plugins/image_management")
@@ -31,12 +31,17 @@ __plugin_settings__ = {
delete_img = on_command("删除图片", priority=5, rule=to_me(), block=True)
_path = Path(IMAGE_PATH) / "image_management"
@delete_img.args_parser
async def parse(bot: Bot, event: MessageEvent, state: T_State):
if get_message_text(event.json()) in ["取消", "算了"]:
await delete_img.finish("已取消操作..", at_sender=True)
if state["_current_key"] in ["path"]:
if get_message_text(event.json()) not in Config.get_config("image_management", "IMAGE_DIR_LIST"):
if get_message_text(event.json()) not in Config.get_config(
"image_management", "IMAGE_DIR_LIST"
):
await delete_img.reject("此目录不正确,请重新输入目录!")
state[state["_current_key"]] = get_message_text(event.json())
if state["_current_key"] == "id":
@@ -52,7 +57,11 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
args = raw_arg.split(" ")
if args[0] in ["帮助"]:
await delete_img.finish(__plugin_usage__)
if len(args) >= 2 and args[0] in Config.get_config("image_management", "IMAGE_DIR_LIST") and is_number(args[1]):
if (
len(args) >= 2
and args[0] in Config.get_config("image_management", "IMAGE_DIR_LIST")
and is_number(args[1])
):
state["path"] = args[0]
state["id"] = args[1]
@@ -60,18 +69,18 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
@delete_img.got("path", prompt="请输入要删除的目标图库?")
@delete_img.got("id", prompt="请输入要删除的图片id?")
async def arg_handle(bot: Bot, event: MessageEvent, state: T_State):
path = cn2py(state["path"])
img_id = state["id"]
# path = IMAGE_PATH + path
path = Path(IMAGE_PATH) / path
temp = Path(IMAGE_PATH) / "temp"
path = _path / cn2py(state["path"])
if not path.exists() and (path.parent.parent / cn2py(state["path"])).exists():
path = path.parent.parent / cn2py(state["path"])
temp = Path(TEMP_PATH)
max_id = len(os.listdir(path)) - 1
if int(img_id) > max_id or int(img_id) < 0:
await delete_img.finish(f"Id超过上下限,上限:{max_id}", at_sender=True)
try:
if os.path.exists(temp / "delete.jpg"):
os.remove(temp / "delete.jpg")
logger.info("删除图片 delete.jpg 成功")
if (temp / "delete.jpg").exists():
(temp / "delete.jpg").unlink()
logger.info(f"删除{cn2py(state['path'])}图片 {img_id}.jpg 成功")
except Exception as e:
logger.warning(f"删除图片 delete.jpg 失败 e{e}")
try:
@@ -31,6 +31,9 @@ __plugin_settings__ = {
move_img = on_command("移动图片", priority=5, rule=to_me(), block=True)
_path = Path(IMAGE_PATH) / "image_management"
@move_img.args_parser
async def parse(bot: Bot, event: MessageEvent, state: T_State):
if str(event.get_message()) in ["取消", "算了"]:
@@ -72,8 +75,20 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
@move_img.got("id", prompt="要移动的图片id是?")
async def _(bot: Bot, event: MessageEvent, state: T_State):
img_id = state["id"]
source_path = Path(IMAGE_PATH) / cn2py(state["source_path"])
destination_path = Path(IMAGE_PATH) / cn2py(state["destination_path"])
source_path = _path / cn2py(state["source_path"])
destination_path = _path / cn2py(state["destination_path"])
if (
not source_path.exists()
and (source_path.parent.parent / cn2py(state["source_path"])).exists()
):
source_path = source_path.parent.parent / cn2py(state["source_path"])
if (
not destination_path.exists()
and (destination_path.parent.parent / cn2py(state["destination_path"])).exists()
):
destination_path = destination_path.parent.parent / cn2py(
state["destination_path"]
)
destination_path.mkdir(parents=True, exist_ok=True)
max_id = len(os.listdir(source_path)) - 1
des_max_id = len(os.listdir(destination_path))
+30 -16
View File
@@ -6,6 +6,7 @@ from services.log import logger
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from utils.utils import FreqLimiter, cn2py
from pathlib import Path
from configs.config import Config
from utils.manager import group_manager, withdraw_message_manager
import random
@@ -16,7 +17,7 @@ try:
except ModuleNotFoundError:
import json
__zx_plugin_name__ = "发送本地图库图片"
__zx_plugin_name__ = "本地图库"
__plugin_usage__ = f"""
usage:
发送指定图库下的随机或指定id图片
@@ -37,49 +38,61 @@ __plugin_settings__ = {
"cmd": ["发送图片"] + Config.get_config("image_management", "IMAGE_DIR_LIST"),
}
__plugin_task__ = {"pa": "丢人爬"}
__plugin_resources__ = {
"pa": IMAGE_PATH
}
__plugin_resources__ = {"pa": IMAGE_PATH}
Config.add_plugin_config(
"_task",
"DEFAULT_PA",
True,
help_="被动 爬 进群默认开关状态",
default_value=True,
)
_flmt = FreqLimiter(1)
cmd = set(Config.get_config("image_management", "IMAGE_DIR_LIST"))
# print(cmd)
send_img = on_command("img", aliases=cmd, priority=5, block=True)
pa = on_keyword({"丢人爬", "爪巴"}, priority=5, block=True)
pa_reg = on_regex("^爬$", priority=5, block=True)
search_url = "https://api.fantasyzone.cc/tu/search.php"
_path = Path(IMAGE_PATH) / "image_management"
@send_img.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
img_id = get_message_text(event.json())
path = cn2py(state["_prefix"]["raw_command"]) + "/"
path = _path / cn2py(state["_prefix"]["raw_command"])
if state["_prefix"]["raw_command"] in Config.get_config(
"image_management", "IMAGE_DIR_LIST"
):
if not os.path.exists(f"{IMAGE_PATH}/{path}/"):
os.mkdir(f"{IMAGE_PATH}/{path}/")
length = len(os.listdir(IMAGE_PATH + path))
if not path.exists() and (path.parent.parent / cn2py(state["_prefix"]["raw_command"])).exists():
path = Path(IMAGE_PATH) / cn2py(state["_prefix"]["raw_command"])
else:
path.mkdir(parents=True, exist_ok=True)
length = len(os.listdir(path))
if length == 0:
logger.warning(f"图库 {path} 为空,调用取消!")
logger.warning(f'图库 {cn2py(state["_prefix"]["raw_command"])} 为空,调用取消!')
await send_img.finish("该图库中没有图片噢")
index = img_id if img_id else str(random.randint(0, length - 1))
if not is_number(index):
return
if int(index) > length - 1 or int(index) < 0:
await send_img.finish(f"超过当前上下限!({length - 1})")
result = image(f"{index}.jpg", path)
result = image(path / f"{index}.jpg")
if result:
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送{path}:"
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) "
f"发送{cn2py(state['_prefix']['raw_command'])}:"
+ result
)
msg_id = await send_img.send(f"id:{index}" + result)
msg_id = await send_img.send(
f"id:{index}" + result
if Config.get_config("image_management", "SHOW_ID")
else "" + result
)
withdraw_message_manager.withdraw_message(
event,
msg_id,
@@ -88,7 +101,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
else:
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送 {path} 失败"
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) "
f"发送 {cn2py(state['_prefix']['raw_command'])} 失败"
)
await send_img.finish(f"不想给你看Ov|")
@@ -8,11 +8,16 @@ from utils.http_utils import AsyncHttpx
import os
_path = Path(IMAGE_PATH) / "image_management"
async def upload_image_to_local(
img_list: List[str], path: str, user_id: int, group_id: int = 0
img_list: List[str], path_: str, user_id: int, group_id: int = 0
) -> str:
_path = path
path = Path(IMAGE_PATH) / cn2py(path)
_path_name = path_
path = _path / cn2py(path_)
if not path.exists() and (path.parent.parent / cn2py(path_)).exists():
path = path.parent.parent / cn2py(path_)
path.mkdir(parents=True, exist_ok=True)
img_id = len(os.listdir(path))
failed_list = []
@@ -28,15 +33,15 @@ async def upload_image_to_local(
failed_result += str(img) + "\n"
logger.info(
f"USER {user_id} GROUP {group_id}"
f" 上传图片至 {_path} 共 {len(img_list)} 张,失败 {len(failed_list)} 张,id={success_id[:-1]}"
f" 上传图片至 {_path_name} 共 {len(img_list)} 张,失败 {len(failed_list)} 张,id={success_id[:-1]}"
)
if failed_list:
return (
f"这次一共为 {_path}库 添加了 {len(img_list) - len(failed_list)} 张图片\n"
f"这次一共为 {_path_name}库 添加了 {len(img_list) - len(failed_list)} 张图片\n"
f"依次的Id为:{success_id[:-1]}\n上传失败:{failed_result[:-1]}\n{NICKNAME}感谢您对图库的扩充!WW"
)
else:
return (
f"这次一共为 {_path}库 添加了 {len(img_list)} 张图片\n依次的Id为:"
f"这次一共为 {_path_name}库 添加了 {len(img_list)} 张图片\n依次的Id为:"
f"{success_id[:-1]}\n{NICKNAME}感谢您对图库的扩充!WW"
)
+3 -3
View File
@@ -5,7 +5,7 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from utils.message_builder import image
from services.log import logger
from utils.utils import get_message_text
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
__zx_plugin_name__ = "鲁迅说"
__plugin_usage__ = """
@@ -31,7 +31,7 @@ __plugin_block_limit__ = {
luxun = on_command("鲁迅说过", aliases={"鲁迅说"}, priority=5, block=True)
luxun_author = CreateImg(0, 0, plain_text="--鲁迅", font_size=30, font='msyh.ttf', font_color=(255, 255, 255))
luxun_author = BuildImage(0, 0, plain_text="--鲁迅", font_size=30, font='msyh.ttf', font_color=(255, 255, 255))
@luxun.handle()
@@ -46,7 +46,7 @@ async def handle_event(bot: Bot, event: MessageEvent, state: T_State):
content = state["content"].strip()
if content.startswith(",") or content.startswith(","):
content = content[1:]
A = CreateImg(0, 0, font_size=37, background=f'{IMAGE_PATH}/other/luxun.jpg', font='msyh.ttf')
A = BuildImage(0, 0, font_size=37, background=f'{IMAGE_PATH}/other/luxun.jpg', font='msyh.ttf')
x = ""
if len(content) > 40:
await luxun.finish('太长了,鲁迅说不完...')
+5 -5
View File
@@ -6,7 +6,7 @@ from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
from utils.utils import get_message_text, get_message_at, get_user_avatar
from utils.message_builder import image
import re
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
__zx_plugin_name__ = "我有一个朋友"
__plugin_usage__ = """
@@ -60,13 +60,13 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
msg = msg.replace("他", "我").replace("她", "我").replace("它", "我")
x = await get_user_avatar(qq)
if x:
ava = CreateImg(200, 100, background=BytesIO(x))
ava = BuildImage(200, 100, background=BytesIO(x))
else:
ava = CreateImg(200, 100, color=(0, 0, 0))
ava = BuildImage(200, 100, color=(0, 0, 0))
ava.circle()
text = CreateImg(300, 30, font_size=30)
text = BuildImage(300, 30, font_size=30)
text.text((0, 0), user_name)
A = CreateImg(700, 150, font_size=25, color="white")
A = BuildImage(700, 150, font_size=25, color="white")
A.paste(ava, (30, 25), True)
A.paste(text, (150, 38))
A.text((150, 85), msg, (125, 125, 125))
+9
View File
@@ -18,6 +18,7 @@ from .open_cases_c import (
open_shilian_case,
)
from .utils import util_get_buff_price, util_get_buff_img, update_count_daily
from configs.config import Config
__zx_plugin_name__ = "开箱"
__plugin_usage__ = """
@@ -84,6 +85,14 @@ __plugin_configs__ = {
"BUFF_PROXY": {"value": None, "help": "使用代理访问BUFF"},
}
Config.add_plugin_config(
"_task",
"DEFAULT_OPEN_CASE_RESET_REMIND",
True,
help_="被动 每日开箱重置提醒 进群默认开关状态",
default_value=True,
)
cases_name = ["狂牙大行动", "突围大行动", "命悬一线", "裂空", "光谱"]
cases_matcher_group = MatcherGroup(priority=5, permission=GROUP, block=True)
+6 -6
View File
@@ -10,7 +10,7 @@ import random
from .utils import get_price
from .models.buff_prices import BuffPrice
from PIL import Image
from utils.image_utils import alpha2white_pil, CreateImg
from utils.image_utils import alpha2white_pil, BuildImage
from configs.path_config import IMAGE_PATH
import asyncio
from utils.utils import cn2py
@@ -239,7 +239,7 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
):
skin_name += "".join(i)
# img = image(skin_name, "cases/" + case, "png")
wImg = CreateImg(200, 270, 200, 200)
wImg = BuildImage(200, 270, 200, 200)
wImg.paste(
alpha2white_pil(
Image.open(IMAGE_PATH + f"cases/{case}/{skin_name}.png").resize(
@@ -263,7 +263,7 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
logger.warning(
f"USER {user_qq} GROUP {group} 开启{case_name}武器箱 {num} 次, 价格:{uplist[10]}, 数据更新失败"
)
# markImg = CreateImg(1000, h, 200, 270)
# markImg = BuildImage(1000, h, 200, 270)
# for img in img_list:
# markImg.paste(img)
markImg = await asyncio.get_event_loop().run_in_executor(
@@ -284,7 +284,7 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
def paste_markImg(h: int, img_list: list):
markImg = CreateImg(1000, h, 200, 270)
markImg = BuildImage(1000, h, 200, 270)
for img in img_list:
markImg.paste(img)
return markImg
@@ -399,7 +399,7 @@ async def my_knifes_name(user_id: int, group: int):
def _pst_my_knife(w, h, knifes_list):
A = CreateImg(w, h, 540, 600)
A = BuildImage(w, h, 540, 600)
for knife in knifes_list:
case = knife.split("||")[0]
knife = knife.split("||")[1]
@@ -415,7 +415,7 @@ def _pst_my_knife(w, h, knifes_list):
style=pypinyin.NORMAL,
):
skin_name += "".join(i)
knife_img = CreateImg(470, 600, 470, 470, font_size=20)
knife_img = BuildImage(470, 600, 470, 470, font_size=20)
knife_img.paste(
alpha2white_pil(
Image.open(IMAGE_PATH + f"cases/{case}/{skin_name}.png").resize(
+1 -1
View File
@@ -8,10 +8,10 @@ import os
from services.log import logger
from utils.utils import get_bot
from asyncio.exceptions import TimeoutError
import pypinyin
from nonebot.adapters.cqhttp.exception import ActionFailed
from configs.config import Config
from utils.manager import group_manager
from .config import *
url = "https://buff.163.com/api/market/goods"
# proxies = 'http://49.75.59.242:3128'
+12 -3
View File
@@ -8,10 +8,11 @@ from nonebot.adapters.cqhttp.permission import GROUP
from bilibili_api import video
from utils.message_builder import image
from nonebot.adapters.cqhttp.exception import ActionFailed
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
from utils.browser import get_browser
from configs.path_config import IMAGE_PATH
from utils.http_utils import AsyncHttpx
from configs.config import Config
import asyncio
import time
from bilibili_api import settings
@@ -25,10 +26,18 @@ usage:
B站转发解析,解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv,且5分钟内不解析相同url
""".strip()
__plugin_des__ = "B站转发解析"
__plugin_type__ = ("被动相关",)
__plugin_type__ = ("其他",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {"bilibili_parse": "b站转发解析"}
Config.add_plugin_config(
"_task",
"DEFAULT_BILIBILI_PARSE",
True,
help_="被动 B站转发解析 进群默认开关状态",
default_value=True,
)
if get_local_proxy():
settings.proxy = get_local_proxy()
@@ -154,5 +163,5 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
def resize(path: str):
A = CreateImg(0, 0, background=path, ratio=0.5)
A = BuildImage(0, 0, background=path, ratio=0.5)
A.save(path)
+2
View File
@@ -69,6 +69,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
data = (await AsyncHttpx.get(url, params=params, timeout=5)).json()
except TimeoutError:
pass
except Exception as e:
await pid_search.finish(f"发生了一些错误..{type(e)}:{e}")
else:
if not data["width"] and not data["height"]:
await pid_search.finish(f"没有搜索到 PID:{pid} 的图片", at_sender=True)
+8
View File
@@ -57,6 +57,14 @@ Config.add_plugin_config(
default_value=10
)
Config.add_plugin_config(
"pix",
"SHOW_INFO",
True,
help_="是否显示图片的基本信息,如PID等",
default_value=True
)
nonebot.load_plugins("plugins/pix_gallery")
+6 -6
View File
@@ -5,7 +5,7 @@ from asyncio.exceptions import TimeoutError
from .model.pixiv import Pixiv
from typing import List, Optional
from utils.utils import change_pixiv_image_links
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
from utils.http_utils import AsyncHttpx
from services.log import logger
from configs.config import Config
@@ -347,16 +347,16 @@ def gen_keyword_pic(
del img_data["_n_pid"]
del img_data["_n_uid"]
current_width = 0
A = CreateImg(img_width, 1100)
A = BuildImage(img_width, 1100)
for x in list(img_data.keys()):
if img_data[x]["data"]:
img = CreateImg(img_data[x]["width"] * 200, 1100, 200, 1100, font_size=40)
img = BuildImage(img_data[x]["width"] * 200, 1100, 200, 1100, font_size=40)
start_index = 0
end_index = 40
total_index = img_data[x]["width"] * 40
for _ in range(img_data[x]["width"]):
tmp = CreateImg(198, 1100, font_size=20)
text_img = CreateImg(198, 100, font_size=50)
tmp = BuildImage(198, 1100, font_size=20)
text_img = BuildImage(198, 100, font_size=50)
key_str = "\n".join(
[key for key in img_data[x]["data"][start_index:end_index]]
)
@@ -370,7 +370,7 @@ def gen_keyword_pic(
end_index = (
end_index + 40 if end_index + 40 <= total_index else total_index
)
background_img = CreateImg(200, 1100, color="#FFE4C4")
background_img = BuildImage(200, 1100, color="#FFE4C4")
background_img.paste(tmp, (1, 1))
img.paste(background_img)
A.paste(img, (current_width, 0))
+10 -7
View File
@@ -143,14 +143,17 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
uid = img.uid
_img = await get_image(img_url, event.user_id)
if _img:
msg_id = await pix.send(
Message(
f"title:{title}\n"
f"author:{author}\n"
f"PID:{pid}\nUID:{uid}\n"
f"{image(_img, 'temp')}"
if Config.get_config("pix", "SHOW_INFO"):
msg_id = await pix.send(
Message(
f"title:{title}\n"
f"author:{author}\n"
f"PID:{pid}\nUID:{uid}\n"
f"{image(_img, 'temp')}"
)
)
)
else:
msg_id = await pix.send(image(_img, 'temp'))
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查看PIX图库PID: {pid}"
+1 -1
View File
@@ -16,7 +16,7 @@ usage:
戳一戳随机掉落语音或美图萝莉图
""".strip()
__plugin_des__ = "戳一戳发送语音美图萝莉图不美哉?"
__plugin_type__ = ("被动相关",)
__plugin_type__ = ("其他",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
+2 -2
View File
@@ -1,10 +1,10 @@
from .model import RussianUser
from typing import Optional
from utils.data_utils import init_rank
from utils.image_utils import CreateMat
from utils.image_utils import BuildMat
async def rank(group_id: int, itype: str, num: int) -> Optional[CreateMat]:
async def rank(group_id: int, itype: str, num: int) -> Optional[BuildMat]:
all_users = await RussianUser.get_all_user(group_id)
all_user_id = [user.user_qq for user in all_users]
if itype == 'win_rank':
+5
View File
@@ -98,6 +98,11 @@ __plugin_configs__ = {
"value": 10,
"help": "色图下载超时限制(秒)",
"default_value": 10
},
"SHOW_INFO": {
"value": True,
"help": "是否显示色图的基本信息,如PID等",
"default_value": True
}
}
Config.add_plugin_config(
+9 -7
View File
@@ -183,13 +183,15 @@ def gen_message(setu_image: Setu, img_msg: bool = False) -> str:
title = setu_image.title
author = setu_image.author
pid = setu_image.pid
return (
f"id:{local_id}\n"
f"title:{title}\n"
f"author:{author}\n"
f"PID:{pid}\n"
f"{image(f'{local_id}', f'{r18_path if setu_image.is_r18 else path}') if img_msg else ''}"
)
if Config.get_config("send_setu", "SHOW_INFO"):
return (
f"id:{local_id}\n"
f"title:{title}\n"
f"author:{author}\n"
f"PID:{pid}\n"
f"{image(f'{local_id}', f'{r18_path if setu_image.is_r18 else path}') if img_msg else ''}"
)
return f"{image(f'{local_id}', f'{r18_path if setu_image.is_r18 else path}') if img_msg else ''}"
# 罗翔老师!
+4 -4
View File
@@ -1,5 +1,5 @@
from ..models.goods_info import GoodsInfo
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
from utils.utils import is_number
from configs.path_config import IMAGE_PATH
from configs.config import Config
@@ -37,9 +37,9 @@ async def create_shop_help():
w = 1000
h = 400 + len(goods_lst) * 40
h = 1000 if h < 1000 else h
shop_logo = CreateImg(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
shop = CreateImg(w, h, font_size=20)
zhenxun_img = CreateImg(525, 581, background=f"{IMAGE_PATH}/zhenxun/toukan_2.png")
shop_logo = BuildImage(100, 100, background=f"{IMAGE_PATH}/other/shop_text.png")
shop = BuildImage(w, h, font_size=20)
zhenxun_img = BuildImage(525, 581, background=f"{IMAGE_PATH}/zhenxun/toukan_2.png")
shop.paste(zhenxun_img, (780, 100))
shop.paste(shop_logo, (450, 30), True)
shop.text(
+12 -16
View File
@@ -3,6 +3,7 @@ from .group_user_checkin import (
group_user_check,
group_impression_rank,
impression_rank,
check_in_all
)
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
@@ -45,26 +46,18 @@ __plugin_settings__ = {
}
__plugin_cd_limit__ = {}
__plugin_configs__ = {
"MAX_SIGN_GOLD": {
"value": 200,
"help": "签到好感度加成额外获得的最大金币数",
"default_value": 200
},
"SIGN_CARD1_PROB": {
"value": 0.2,
"help": "签到好感度双倍加持卡Ⅰ掉落概率",
"default_value": 0.2
},
"MAX_SIGN_GOLD": {"value": 200, "help": "签到好感度加成额外获得的最大金币数", "default_value": 200},
"SIGN_CARD1_PROB": {"value": 0.2, "help": "签到好感度双倍加持卡Ⅰ掉落概率", "default_value": 0.2},
"SIGN_CARD2_PROB": {
"value": 0.09,
"help": "签到好感度双倍加持卡Ⅱ掉落概率",
"default_value": 0.09
"default_value": 0.09,
},
"SIGN_CARD3_PROB": {
"value": 0.05,
"help": "签到好感度双倍加持卡Ⅲ掉落概率",
"default_value": 0.05
}
"default_value": 0.05,
},
}
@@ -98,6 +91,9 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
await group_user_check_in(nickname, event.user_id, event.group_id),
at_sender=True,
)
if get_message_text(event.json()) == "all":
await check_in_all(nickname, event.user_id)
@my_sign.handle()
@@ -142,12 +138,12 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
@scheduler.scheduled_job(
'interval',
"interval",
hours=1,
)
async def _():
try:
clear_sign_data_pic()
logger.info('清理日常签到图片数据数据完成....')
logger.info("清理日常签到图片数据数据完成....")
except Exception as e:
logger.error(f'清理日常签到图片数据数据失败..{type(e)}: {e}')
logger.error(f"清理日常签到图片数据数据失败..{type(e)}: {e}")
+28 -8
View File
@@ -4,7 +4,7 @@ from models.group_member_info import GroupInfoUser
from models.bag_user import BagUser
from configs.config import NICKNAME
from nonebot.adapters.cqhttp import MessageSegment
from utils.image_utils import CreateImg, CreateMat
from utils.image_utils import BuildImage, BuildMat
from services.db_context import db
from .utils import get_card, SIGN_TODAY_CARD_PATH
from typing import Optional
@@ -39,6 +39,26 @@ async def group_user_check_in(
return await _handle_check_in(nickname, user_qq, group, present) # ok
async def check_in_all(nickname: str, user_qq: int):
"""
说明:
签到所有群
参数:
:param nickname: 昵称
:param user_qq: 用户qq
"""
async with db.transaction():
present = datetime.now()
for u in await SignGroupUser.get_user_all_data(user_qq):
group = u.belonging_group
if not ((
u.checkin_time_last + timedelta(hours=8)
).date() >= present.date() or f"{u}_{group}_sign_{datetime.now().date()}" in os.listdir(
SIGN_TODAY_CARD_PATH
)):
await _handle_check_in(nickname, user_qq, group, present)
async def _handle_check_in(
nickname: str, user_qq: int, group: int, present: datetime
) -> MessageSegment:
@@ -84,7 +104,7 @@ async def group_user_check(nickname: str, user_qq: int, group: int) -> MessageSe
return await get_card(user, nickname, None, gold, "", is_card_view=True)
async def group_impression_rank(group: int, num: int) -> Optional[CreateMat]:
async def group_impression_rank(group: int, num: int) -> Optional[BuildMat]:
user_qq_list, impression_list, _ = await SignGroupUser.get_all_impression(group)
return await init_rank("好感度排行榜", user_qq_list, impression_list, group, num)
@@ -141,9 +161,9 @@ async def _pst(users: list, impressions: list, groups: list):
count = math.ceil(lens / 33)
width = 10
idx = 0
A = CreateImg(1740, 3300, color="#FFE4C4")
A = BuildImage(1740, 3300, color="#FFE4C4")
for _ in range(count):
col_img = CreateImg(550, 3300, 550, 100, color="#FFE4C4")
col_img = BuildImage(550, 3300, 550, 100, color="#FFE4C4")
for _ in range(33 if int(lens / 33) >= 1 else lens % 33 - 1):
idx += 1
if idx > 100:
@@ -164,13 +184,13 @@ async def _pst(users: list, impressions: list, groups: list):
user_name = user_name if len(user_name) < 11 else user_name[:10] + "..."
ava = await get_user_avatar(user)
if ava:
ava = CreateImg(
ava = BuildImage(
50, 50, background=BytesIO(ava)
)
else:
ava = CreateImg(50, 50, color="white")
ava = BuildImage(50, 50, color="white")
ava.circle()
bk = CreateImg(550, 100, color="#FFE4C4", font_size=30)
bk = BuildImage(550, 100, color="#FFE4C4", font_size=30)
font_w, font_h = bk.getsize(f"{idx}")
bk.text((5, int((100 - font_h) / 2)), f"{idx}.")
bk.paste(ava, (55, int((100 - 50) / 2)), True)
@@ -180,7 +200,7 @@ async def _pst(users: list, impressions: list, groups: list):
A.paste(col_img, (width, 0))
lens -= 33
width += 580
W = CreateImg(1740, 3700, color="#FFE4C4", font_size=130)
W = BuildImage(1740, 3700, color="#FFE4C4", font_size=130)
W.paste(A, (0, 260))
font_w, font_h = W.getsize(f"{NICKNAME}的好感度总榜")
W.text((int((1740 - font_w) / 2), int((260 - font_h) / 2)), f"{NICKNAME}的好感度总榜")
+30 -30
View File
@@ -12,7 +12,7 @@ from models.sign_group_user import SignGroupUser
from models.group_member_info import GroupInfoUser
from nonebot.adapters.cqhttp import MessageSegment
from utils.utils import get_user_avatar
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
from utils.message_builder import image
from configs.config import NICKNAME
from pathlib import Path
@@ -112,18 +112,18 @@ def _generate_card(
is_double: bool = False,
is_card_view: bool = False,
) -> MessageSegment:
ava_bk = CreateImg(140, 140, is_alpha=True)
ava_border = CreateImg(
ava_bk = BuildImage(140, 140, is_alpha=True)
ava_border = BuildImage(
140,
140,
background=SIGN_BORDER_PATH / "ava_border_01.png",
)
ava = CreateImg(102, 102, background=ava_bytes)
ava = BuildImage(102, 102, background=ava_bytes)
ava.circle()
ava_bk.paste(ava, center_type="center")
ava_bk.paste(ava_border, alpha=True, center_type="center")
info_img = CreateImg(250, 150, color=(255, 255, 255, 0), font_size=15)
info_img = BuildImage(250, 150, color=(255, 255, 255, 0), font_size=15)
level, next_impression, previous_impression = get_level_and_next_impression(
user.impression
)
@@ -131,8 +131,8 @@ def _generate_card(
info_img.text((0, 20), f"· {NICKNAME}对你的态度:{level2attitude[level]}")
info_img.text((0, 40), f"· 距离升级还差 {next_impression - user.impression:.2f} 好感度")
bar_bk = CreateImg(220, 20, background=SIGN_RESOURCE_PATH / "bar_white.png")
bar = CreateImg(220, 20, background=SIGN_RESOURCE_PATH / "bar.png")
bar_bk = BuildImage(220, 20, background=SIGN_RESOURCE_PATH / "bar_white.png")
bar = BuildImage(220, 20, background=SIGN_RESOURCE_PATH / "bar.png")
bar_bk.paste(
bar,
(
@@ -150,7 +150,7 @@ def _generate_card(
font_size = 30
if "好感度双倍加持卡" in gift:
font_size = 20
gift_border = CreateImg(
gift_border = BuildImage(
270,
100,
background=SIGN_BORDER_PATH / "gift_border_02.png",
@@ -158,20 +158,20 @@ def _generate_card(
)
gift_border.text((0, 0), gift, center_type="center")
bk = CreateImg(
bk = BuildImage(
876,
424,
background=SIGN_BACKGROUND_PATH
/ random.choice(os.listdir(SIGN_BACKGROUND_PATH)),
font_size=25,
)
A = CreateImg(876, 274, background=SIGN_RESOURCE_PATH / "white.png")
line = CreateImg(2, 180, color="black")
A = BuildImage(876, 274, background=SIGN_RESOURCE_PATH / "white.png")
line = BuildImage(2, 180, color="black")
A.transparent(2)
A.paste(ava_bk, (25, 80), True)
A.paste(line, (200, 70))
nickname_img = CreateImg(
nickname_img = BuildImage(
0,
0,
plain_text=nickname,
@@ -184,7 +184,7 @@ def _generate_card(
uid = uid[:4] + " " + uid[4:8] + " " + uid[8:]
else:
uid = "XXXX XXXX XXXX"
uid_img = CreateImg(
uid_img = BuildImage(
0,
0,
plain_text=f"UID: {uid}",
@@ -192,7 +192,7 @@ def _generate_card(
font_size=30,
font_color=(255, 255, 255),
)
sign_day_img = CreateImg(
sign_day_img = BuildImage(
0,
0,
plain_text=f"{user.checkin_count}",
@@ -200,17 +200,17 @@ def _generate_card(
font_size=40,
font_color=(211, 64, 33),
)
lik_text1_img = CreateImg(
lik_text1_img = BuildImage(
0, 0, plain_text="当前", color=(255, 255, 255, 0), font_size=20
)
lik_text2_img = CreateImg(
lik_text2_img = BuildImage(
0,
0,
plain_text=f"好感度:{user.impression:.2f}",
color=(255, 255, 255, 0),
font_size=30,
)
watermark = CreateImg(
watermark = BuildImage(
0,
0,
plain_text=f"{NICKNAME}@{datetime.now().year}",
@@ -218,15 +218,15 @@ def _generate_card(
font_size=15,
font_color=(155, 155, 155),
)
today_data = CreateImg(300, 300, color=(255, 255, 255, 0), font_size=20)
today_data = BuildImage(300, 300, color=(255, 255, 255, 0), font_size=20)
if is_card_view:
today_sign_text_img = CreateImg(
today_sign_text_img = BuildImage(
0, 0, plain_text="", color=(255, 255, 255, 0), font_size=30
)
if impression_list:
impression_list.sort(reverse=True)
index = impression_list.index(user.impression)
rank_img = CreateImg(
rank_img = BuildImage(
0,
0,
plain_text=f"* 此群好感排名第 {index + 1} 位",
@@ -247,7 +247,7 @@ def _generate_card(
_type = "view"
else:
A.paste(gift_border, (570, 140), True)
today_sign_text_img = CreateImg(
today_sign_text_img = BuildImage(
0, 0, plain_text="今日签到", color=(255, 255, 255, 0), font_size=30
)
if is_double:
@@ -262,7 +262,7 @@ def _generate_card(
hour = current_date.hour
minute = current_date.minute
second = current_date.second
data_img = CreateImg(
data_img = BuildImage(
0,
0,
plain_text=f"时间:{data} {weekdays[week]} {hour}:{minute}:{second}",
@@ -296,14 +296,14 @@ def generate_progress_bar_pic():
bg_2 = (254, 1, 254)
bg_1 = (0, 245, 246)
bk = CreateImg(1000, 50, is_alpha=True)
img_x = CreateImg(50, 50, color=bg_2)
bk = BuildImage(1000, 50, is_alpha=True)
img_x = BuildImage(50, 50, color=bg_2)
img_x.circle()
img_x.crop((25, 0, 50, 50))
img_y = CreateImg(50, 50, color=bg_1)
img_y = BuildImage(50, 50, color=bg_1)
img_y.circle()
img_y.crop((0, 0, 25, 50))
A = CreateImg(950, 50)
A = BuildImage(950, 50)
width, height = A.size
step_r = (bg_2[0] - bg_1[0]) / width
@@ -321,12 +321,12 @@ def generate_progress_bar_pic():
bk.paste(img_x, (975, 0), True)
bk.save(SIGN_RESOURCE_PATH / "bar.png")
A = CreateImg(950, 50)
bk = CreateImg(1000, 50, is_alpha=True)
img_x = CreateImg(50, 50)
A = BuildImage(950, 50)
bk = BuildImage(1000, 50, is_alpha=True)
img_x = BuildImage(50, 50)
img_x.circle()
img_x.crop((25, 0, 50, 50))
img_y = CreateImg(50, 50)
img_y = BuildImage(50, 50)
img_y.circle()
img_y.crop((0, 0, 25, 50))
bk.paste(img_y, (0, 0), True)
+6 -6
View File
@@ -5,7 +5,7 @@ from nonebot.typing import T_State
from pathlib import Path
from configs.path_config import DATA_PATH, IMAGE_PATH
from utils.utils import get_message_text
from utils.image_utils import CreateMat
from utils.image_utils import BuildMat
from utils.message_builder import image
from utils.manager import plugins2settings_manager
import asyncio
@@ -202,7 +202,7 @@ async def generate_statistics_img(
except KeyError:
count.append(0)
week_lst = ["7" if i == "0" else i for i in week_lst]
bar_graph = CreateMat(
bar_graph = BuildMat(
y=count,
mat_type="line",
title=f"{name} 周 {plugin} 功能调用统计【为7天统计】",
@@ -226,7 +226,7 @@ async def generate_statistics_img(
day_lst.append(i)
count = [data[str(day_lst[i])][plugin] for i in range(30)]
day_lst = [str(x + 1) for x in day_lst]
bar_graph = CreateMat(
bar_graph = BuildMat(
y=count,
mat_type="line",
title=f"{name} 月 {plugin} 功能调用统计【为30天统计】",
@@ -246,12 +246,12 @@ async def generate_statistics_img(
return bar_graph.pic2bs4()
async def init_bar_graph(data: dict, title: str) -> CreateMat:
async def init_bar_graph(data: dict, title: str) -> BuildMat:
return await asyncio.get_event_loop().run_in_executor(None, _init_bar_graph, data, title)
def _init_bar_graph(data: dict, title: str) -> CreateMat:
bar_graph = CreateMat(
def _init_bar_graph(data: dict, title: str) -> BuildMat:
bar_graph = BuildMat(
y=[data[x] for x in data.keys() if data[x] != 0],
mat_type="barh",
title=title,
+2 -2
View File
@@ -9,7 +9,7 @@ from nonebot.typing import T_State
from utils.utils import get_message_imgs
from pathlib import Path
from utils.utils import is_number, get_message_text
from utils.image_utils import CreateImg, pic2b64
from utils.image_utils import BuildImage, pic2b64
from configs.config import NICKNAME
from utils.http_utils import AsyncHttpx
import cv2
@@ -83,7 +83,7 @@ for i in range(len(method_list)):
method_oper.append(method_list[i])
method_oper.append(str(i + 1))
update_img_help = CreateImg(960, 700, font_size=24)
update_img_help = BuildImage(960, 700, font_size=24)
update_img_help.text((10, 10), __plugin_usage__)
update_img_help.save(IMAGE_PATH + "update_img_help.png")
+4 -4
View File
@@ -4,7 +4,7 @@ from nonebot import on_command
from utils.utils import get_message_imgs, get_message_text, is_chinese
from utils.message_builder import image
from configs.path_config import TEMP_PATH
from utils.image_utils import CreateImg
from utils.image_utils import BuildImage
from services.log import logger
from utils.http_utils import AsyncHttpx
from pathlib import Path
@@ -57,12 +57,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
):
await w2b_img.finish("下载图片失败...请稍后再试...")
msg = await get_translate(msg)
w2b = CreateImg(0, 0, background=Path(TEMP_PATH) / f"{event.user_id}_w2b.png")
w2b = BuildImage(0, 0, background=Path(TEMP_PATH) / f"{event.user_id}_w2b.png")
w2b.convert("L")
msg_sp = msg.split("<|>")
w, h = w2b.size
add_h, font_size = init_h_font_size(h)
bg = CreateImg(w, h + add_h, color="black", font_size=font_size)
bg = BuildImage(w, h + add_h, color="black", font_size=font_size)
bg.paste(w2b)
chinese_msg = formalization_msg(msg)
if not bg.check_font_size(chinese_msg):
@@ -84,7 +84,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
)
def centered_text(img: CreateImg, text: str, add_h: int):
def centered_text(img: BuildImage, text: str, add_h: int):
top_h = img.h - add_h + (img.h / 100)
bottom_h = img.h - (img.h / 100)
text_sp = text.split("<|>")
+2 -2
View File
@@ -59,11 +59,11 @@ show_word = on_command("显示词条", aliases={"查看词条"}, priority=5, blo
@add_word.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
msg = str(event.get_message()).strip()
r = re.search(r"^问(.+)\s?答(.*)", msg)
r = re.search(r"^问(.+)\s?答([\s\S]*)", msg)
if not r:
await add_word.finish("未检测到词条问题...")
problem = r.group(1).strip()
answer = r.group(2).strip()
answer = msg.split('答', maxsplit=1)[-1]
if not answer:
await add_word.finish("未检测到词条回答...")
idx = 0
+1 -1
View File
@@ -54,4 +54,4 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询疫情失败"
)
else:
await yiqing.send(f"{NICKNAME}只支持国内的疫情查询喔...")
await yiqing.send(f"{NICKNAME}没有查到{msg}的疫情查询...")