原神黄历改为PIL

This commit is contained in:
HibiKier 2022-12-31 17:15:14 +08:00
parent 2070014021
commit b0606feff3
6 changed files with 178 additions and 50 deletions

2
.gitignore vendored
View File

@ -163,3 +163,5 @@ configs/config.yaml
./.env.dev
plugins/csgo_server/
plugins/activity/
!/resources/image/genshin/alc/back.png
!/data/genshin_alc/

View File

@ -303,6 +303,7 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
* 修复epic报错优化简介 [@pull/1226](https://github.com/HibiKier/zhenxun_bot/pull/1226)
* 修复词条在某些回答下出错
* 原神黄历改为PIL
### 2022/12/27 \[v0.1.6.6]

View File

@ -1,11 +1,13 @@
from utils.utils import get_bot, scheduler
from configs.config import Config
from configs.path_config import IMAGE_PATH
from nonebot import on_command
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
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 utils.message_builder import image
from utils.utils import get_bot, scheduler
from ._data_source import build_alc_image
__zx_plugin_name__ = "原神老黄历"
__plugin_usage__ = """
@ -35,25 +37,16 @@ Config.add_plugin_config(
default_value=True,
)
almanac = on_command("原神黄历", priority=15, block=True)
ALC_PATH = IMAGE_PATH / "genshin" / "alc"
ALC_PATH.mkdir(parents=True, exist_ok=True)
almanac = on_command("原神黄历", priority=5, block=True)
@almanac.handle()
async def _(event: MessageEvent,):
alc_img = await get_alc_image(ALC_PATH)
if alc_img:
mes = alc_img + "\n ※ 黄历数据来源于 genshin.pub"
await almanac.send(mes)
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送查看原神黄历"
)
else:
await almanac.send("黄历图片下载失败...")
async def _(event: MessageEvent):
await almanac.send(image(b64=await build_alc_image()))
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 发送查看原神黄历"
)
@scheduler.scheduled_job(
@ -67,9 +60,9 @@ async def _():
if bot:
gl = await bot.get_group_list()
gl = [g["group_id"] for g in gl]
alc_img = await get_alc_image(ALC_PATH)
alc_img = image(b64=await build_alc_image())
if alc_img:
mes = "[[_task|genshin_alc]]" + alc_img + "\n ※ 黄历数据来源于 genshin.pub"
mes = "[[_task|genshin_alc]]" + alc_img
for gid in gl:
if group_manager.check_group_task_status(gid, "genshin_alc"):
await bot.send_group_msg(group_id=int(gid), message="" + mes)

View File

@ -0,0 +1,129 @@
import os
import random
from dataclasses import dataclass
from datetime import datetime
from typing import List, Tuple, Union
import ujson as json
from configs.path_config import DATA_PATH, IMAGE_PATH
from utils.image_utils import BuildImage
CONFIG_PATH = DATA_PATH / "genshin_alc" / "config.json"
ALC_PATH = IMAGE_PATH / "genshin" / "alc"
ALC_PATH.mkdir(exist_ok=True, parents=True)
BACKGROUND_PATH = ALC_PATH / "back.png"
chinese = {
"0": "",
"1": "",
"2": "",
"3": "",
"4": "",
"5": "",
"6": "",
"7": "",
"8": "",
"9": "",
}
@dataclass
class Fortune:
title: str
desc: str
def random_fortune() -> Tuple[List[Fortune], List[Fortune]]:
"""
说明:
随机运势
"""
data = json.load(CONFIG_PATH.open("r", encoding="utf8"))
fortune_data = {}
good_fortune = []
bad_fortune = []
while len(fortune_data) < 6:
r = random.choice(list(data.keys()))
if r not in fortune_data:
fortune_data[r] = data[r]
for i, k in enumerate(fortune_data):
if i < 3:
good_fortune.append(
Fortune(title=k, desc=random.choice(fortune_data[k]["buff"]))
)
else:
bad_fortune.append(
Fortune(title=k, desc=random.choice(fortune_data[k]["debuff"]))
)
return good_fortune, bad_fortune
def int2cn(v: Union[str, int]):
"""
说明:
数字转中文
参数:
:param v: str
"""
return "".join([chinese[x] for x in str(v)])
async def build_alc_image() -> str:
"""
说明:
构造今日运势图片
"""
for file in os.listdir(ALC_PATH):
if file not in ["back.png", f"{datetime.now().date()}"]:
(ALC_PATH / file).unlink()
path = ALC_PATH / f"{datetime.now().date()}.png"
if path.exists():
return BuildImage(0, 0, background=path).pic2bs4()
good_fortune, bad_fortune = random_fortune()
background = BuildImage(
0, 0, background=BACKGROUND_PATH, font="HYWenHei-85W.ttf", font_size=30
)
now = datetime.now()
await background.atext((78, 145), str(now.year), fill="#8d7650ff")
month = str(now.month)
month_w = 358
if now.month < 10:
month_w = 373
elif now.month != 10:
month = "0" + month[-1]
await background.atext((month_w, 145), f"{int2cn(month)}", fill="#8d7650ff")
day = str(now.day)
if now.day > 10 and day[-1] != "0":
day = day[0] + "0" + day[-1]
day_str = f"{int2cn(day)}"
day_w = 193
if (n := len(day_str)) == 3:
day_w = 207
elif n == 2:
day_w = 228
await background.atext(
(day_w, 145), f"{int2cn(day)}", fill="#f7f8f2ff", font_size=35
)
fortune_h = 230
for fortune in good_fortune:
await background.atext(
(150, fortune_h), fortune.title, fill="#756141ff", font_size=25
)
await background.atext(
(150, fortune_h + 28), fortune.desc, fill="#b5b3acff", font_size=19
)
fortune_h += 55
fortune_h += 4
for fortune in bad_fortune:
await background.atext(
(150, fortune_h), fortune.title, fill="#756141ff", font_size=25
)
await background.atext(
(150, fortune_h + 28), fortune.desc, fill="#b5b3acff", font_size=19
)
fortune_h += 55
await background.asave(path)
return background.pic2bs4()

View File

@ -1,26 +0,0 @@
from utils.message_builder import image
from datetime import datetime
from pathlib import Path
from utils.http_utils import AsyncPlaywright
from nonebot.adapters.onebot.v11 import MessageSegment
from typing import Optional
import os
url = "https://genshin.pub"
async def get_alc_image(path: Path) -> Optional[MessageSegment]:
"""
截取黄历
:param path: 存储路径
"""
date = datetime.now().date()
for file in os.listdir(path):
if f"{date}.png" != file:
file = path / file
file.unlink()
if f"{date}.png" in os.listdir(path):
return image(f"{date}.png", "genshin/alc")
return await AsyncPlaywright.screenshot(
url, path / f"{date}.png", ".GSAlmanacs_gs_almanacs__3qT_A"
)

View File

@ -8,6 +8,8 @@ from io import BytesIO
from math import ceil
from pathlib import Path
from typing import List, Literal, Optional, Tuple, Union, Callable, Awaitable
from PIL.ImageFont import FreeTypeFont
from nonebot.utils import is_coroutine_callable
import cv2
@ -184,6 +186,7 @@ class BuildImage:
self._current_w = 0
self._current_h = 0
self.uid = uuid.uuid1()
self.font_name = font
self.font = ImageFont.truetype(str(FONT_PATH / font), int(font_size))
if not plain_text and not color:
color = (255, 255, 255)
@ -237,6 +240,17 @@ class BuildImage:
asyncio.set_event_loop(new_loop)
self.loop = asyncio.get_event_loop()
@classmethod
def load_font(cls, font: str, font_size: int) -> FreeTypeFont:
"""
说明:
加载字体
参数:
:param font: 字体名称
:param font_size: 字体大小
"""
return ImageFont.truetype(str(FONT_PATH / font), font_size)
async def apaste(
self,
img: "BuildImage" or Image,
@ -379,6 +393,9 @@ class BuildImage:
text: str,
fill: Union[str, Tuple[int, int, int]] = (0, 0, 0),
center_type: Optional[Literal["center", "by_height", "by_width"]] = None,
font: Union[FreeTypeFont, str] = None,
font_size: Optional[int] = None,
**kwargs
):
"""
说明:
@ -388,8 +405,10 @@ class BuildImage:
:param text: 文字内容
:param fill: 文字颜色
:param center_type: 居中类型可能的值 center: 完全居中by_width: 水平居中by_height: 垂直居中
:param font: 字体
:param font_size: 字体大小
"""
await self.loop.run_in_executor(None, self.text, pos, text, fill, center_type)
await self.loop.run_in_executor(None, self.text, pos, text, fill, center_type, font, font_size, **kwargs)
def text(
self,
@ -397,6 +416,9 @@ class BuildImage:
text: str,
fill: Union[str, Tuple[int, int, int]] = (0, 0, 0),
center_type: Optional[Literal["center", "by_height", "by_width"]] = None,
font: Union[FreeTypeFont, str] = None,
font_size: Optional[int] = None,
**kwargs
):
"""
说明:
@ -406,6 +428,8 @@ class BuildImage:
:param text: 文字内容
:param fill: 文字颜色
:param center_type: 居中类型可能的值 center: 完全居中by_width: 水平居中by_height: 垂直居中
:param font: 字体
:param font_size: 字体大小
"""
if center_type:
if center_type not in ["center", "by_height", "by_width"]:
@ -424,7 +448,12 @@ class BuildImage:
h = int((h - ttf_h) / 2)
w = pos[0]
pos = (w, h)
self.draw.text(pos, text, fill=fill, font=self.font)
if font:
if isinstance(font, str):
font = self.load_font(font, font_size)
elif font_size:
font = self.load_font(self.font_name, font_size)
self.draw.text(pos, text, fill=fill, font=font or self.font, **kwargs)
async def asave(self, path: Optional[Union[str, Path]] = None):
"""