This commit is contained in:
hibiki 2021-08-04 15:19:45 +08:00
parent b62399e203
commit 910af434ae
22 changed files with 571 additions and 700 deletions

View File

@ -2,6 +2,7 @@ from utils.utils import scheduler, get_bot
from .data_source import update_member_info from .data_source import update_member_info
from services.log import logger from services.log import logger
from models.group_info import GroupInfo from models.group_info import GroupInfo
from asyncpg.exceptions import ConnectionDoesNotExistError
# 自动更新群员信息 # 自动更新群员信息
@ -37,5 +38,5 @@ async def _():
if g not in all_group: if g not in all_group:
await update_member_info(g) await update_member_info(g)
logger.info(f"快速更新群信息以及权限:{g}") logger.info(f"快速更新群信息以及权限:{g}")
except IndexError: except (IndexError, ConnectionDoesNotExistError):
pass pass

View File

@ -150,7 +150,7 @@ def no_result() -> str:
random.choice( random.choice(
[ [
"你在说啥子?", "你在说啥子?",
f"纯洁的{list(get_bot().config.nickname)[0]}没听懂", f"纯洁的小真寻没听懂",
"下次再告诉你(下次一定)", "下次再告诉你(下次一定)",
"你觉得我听懂了吗?嗯?", "你觉得我听懂了吗?嗯?",
"我!不!知!道!", "我!不!知!道!",

View File

@ -4,27 +4,34 @@ from models.friend_user import FriendUser
from datetime import datetime from datetime import datetime
from configs.config import AUTO_ADD_FRIEND from configs.config import AUTO_ADD_FRIEND
from nonebot.adapters.cqhttp.exception import ActionFailed from nonebot.adapters.cqhttp.exception import ActionFailed
from utils.utils import scheduler
__plugin_name__ = "好友群聊处理请求 [Hidden]" __plugin_name__ = "好友群聊处理请求 [Hidden]"
friend_req = on_request(priority=5) friend_req = on_request(priority=5)
exists_list = []
@friend_req.handle() @friend_req.handle()
async def _(bot: Bot, event: FriendRequestEvent, state: dict): async def _(bot: Bot, event: FriendRequestEvent, state: dict):
user = await bot.get_stranger_info(user_id=event.user_id) global exists_list
nickname = user["nickname"] if f"{event.user_id}" not in exists_list:
await bot.send_private_msg( exists_list.append(f"{event.user_id}")
user_id=int(list(bot.config.superusers)[0]), user = await bot.get_stranger_info(user_id=event.user_id)
message=f"*****一份好友申请*****\n" nickname = user["nickname"]
f"昵称:{nickname}({event.user_id})\n" await bot.send_private_msg(
f"自动同意:{'' if AUTO_ADD_FRIEND else '×'}\n" user_id=int(list(bot.config.superusers)[0]),
f"日期:{str(datetime.now()).split('.')[0]}\n" message=f"*****一份好友申请*****\n"
f"备注:{event.comment}", f"昵称:{nickname}({event.user_id})\n"
) f"自动同意:{'' if AUTO_ADD_FRIEND else '×'}\n"
if AUTO_ADD_FRIEND: f"日期:{str(datetime.now()).split('.')[0]}\n"
await bot.set_friend_add_request(flag=event.flag, approve=True) f"备注:{event.comment}",
await FriendUser.add_friend_info(user["user_id"], user["nickname"]) )
if AUTO_ADD_FRIEND:
await bot.set_friend_add_request(flag=event.flag, approve=True)
await FriendUser.add_friend_info(user["user_id"], user["nickname"])
group_req = on_request(priority=5, block=True) group_req = on_request(priority=5, block=True)
@ -32,6 +39,7 @@ group_req = on_request(priority=5, block=True)
@group_req.handle() @group_req.handle()
async def _(bot: Bot, event: GroupRequestEvent, state: dict): async def _(bot: Bot, event: GroupRequestEvent, state: dict):
global exists_list
if event.sub_type == "invite": if event.sub_type == "invite":
if str(event.user_id) in bot.config.superusers: if str(event.user_id) in bot.config.superusers:
try: try:
@ -41,17 +49,28 @@ async def _(bot: Bot, event: GroupRequestEvent, state: dict):
except ActionFailed: except ActionFailed:
pass pass
else: else:
nickname = await FriendUser.get_user_name(event.user_id) if f"{event.user_id}:{event.group_id}" not in exists_list:
await bot.send_private_msg( exists_list.append(f"{event.user_id}:{event.group_id}")
user_id=int(list(bot.config.superusers)[0]), nickname = await FriendUser.get_user_name(event.user_id)
message=f"*****一份入群申请*****\n" await bot.send_private_msg(
f"申请人:{nickname}({event.user_id})\n" user_id=int(list(bot.config.superusers)[0]),
f"群聊:{event.group_id}\n" message=f"*****一份入群申请*****\n"
f"邀请日期:{str(datetime.now()).split('.')[0]}", f"申请人:{nickname}({event.user_id})\n"
) f"群聊:{event.group_id}\n"
await bot.send_private_msg( f"邀请日期:{str(datetime.now()).split('.')[0]}",
user_id=event.user_id, )
message="想要邀请我偷偷入群嘛~已经提醒真寻的管理员大人了\n" await bot.send_private_msg(
"请确保已经群主或群管理沟通过!\n" user_id=event.user_id,
"等待管理员处理吧!", message="想要邀请我偷偷入群嘛~已经提醒真寻的管理员大人了\n"
) "请确保已经群主或群管理沟通过!\n"
"等待管理员处理吧!",
)
@scheduler.scheduled_job(
"interval",
minutes=5,
)
async def _():
global exists_list
exists_list = []

View File

@ -1,7 +1,7 @@
from pathlib import Path from pathlib import Path
from configs.path_config import IMAGE_PATH, TXT_PATH from configs.path_config import IMAGE_PATH, TXT_PATH
from utils.image_utils import CreateImg from utils.image_utils import CreateImg
from typing import Tuple from typing import Tuple, List
from math import sqrt, pow from math import sqrt, pow
import random import random
@ -28,6 +28,7 @@ class Map:
deviation: Tuple[int, int] = (25, 51), deviation: Tuple[int, int] = (25, 51),
padding: int = 100, padding: int = 100,
planning_route: bool = False, planning_route: bool = False,
ratio: float = 1,
): ):
""" """
参数 参数
@ -36,14 +37,21 @@ class Map:
:param deviation: 坐标误差 :param deviation: 坐标误差
:param padding: 截图外边距 :param padding: 截图外边距
:param planning_route: 是否规划最佳线路 :param planning_route: 是否规划最佳线路
:param ratio: 压缩比率
""" """
self.map = CreateImg(0, 0, background=map_path) self.map = CreateImg(0, 0, background=map_path)
self.resource_name = resource_name self.resource_name = resource_name
self.center_x = center_point[0] self.center_x = center_point[0]
self.center_y = center_point[1] self.center_y = center_point[1]
self.deviation = deviation self.deviation = deviation
self.padding = padding self.padding = int(padding * ratio)
self.planning_route = planning_route self.planning_route = planning_route
self.ratio = ratio
self.deviation = (
int(self.deviation[0] * ratio),
int(self.deviation[1] * ratio),
)
data = json.load(open(resource_label_file, "r", encoding="utf8")) data = json.load(open(resource_label_file, "r", encoding="utf8"))
# 资源 id # 资源 id
@ -67,27 +75,27 @@ class Map:
# 资源坐标 # 资源坐标
data = json.load(open(resource_point_file, "r", encoding="utf8")) data = json.load(open(resource_point_file, "r", encoding="utf8"))
self.resource_point = [ self.resource_point = [
( Resources(
self.center_x + int(data[x]["x_pos"]), int((self.center_x + data[x]["x_pos"]) * ratio),
self.center_y + int(data[x]["y_pos"]), int((self.center_y + data[x]["y_pos"]) * ratio),
) )
for x in data for x in data
if x != "CENTER_POINT" and data[x]["label_id"] == self.resource_id if x != "CENTER_POINT" and data[x]["label_id"] == self.resource_id
] ]
# 传送锚点坐标 # 传送锚点坐标
self.teleport_anchor_point = [ self.teleport_anchor_point = [
( Resources(
self.center_x + int(data[x]["x_pos"]), int((self.center_x + data[x]["x_pos"]) * ratio),
self.center_y + int(data[x]["y_pos"]), int((self.center_y + data[x]["y_pos"]) * ratio),
) )
for x in data for x in data
if x != "CENTER_POINT" and data[x]["label_id"] == self.teleport_anchor_id if x != "CENTER_POINT" and data[x]["label_id"] == self.teleport_anchor_id
] ]
# 神像坐标 # 神像坐标
self.teleport_god_point = [ self.teleport_god_point = [
( Resources(
self.center_x + int(data[x]["x_pos"]), int((self.center_x + data[x]["x_pos"]) * ratio),
self.center_y + int(data[x]["y_pos"]), int((self.center_y + data[x]["y_pos"]) * ratio),
) )
for x in data for x in data
if x != "CENTER_POINT" and data[x]["label_id"] == self.teleport_god_id if x != "CENTER_POINT" and data[x]["label_id"] == self.teleport_god_id
@ -95,21 +103,23 @@ class Map:
# 将地图上生成资源图标 # 将地图上生成资源图标
def generate_resource_icon_in_map(self) -> int: def generate_resource_icon_in_map(self) -> int:
x_list = [x[0] for x in self.resource_point] x_list = [x.x for x in self.resource_point]
y_list = [x[1] for x in self.resource_point] y_list = [x.y for x in self.resource_point]
min_width = min(x_list) - self.padding min_width = min(x_list) - self.padding
max_width = max(x_list) + self.padding max_width = max(x_list) + self.padding
min_height = min(y_list) - self.padding min_height = min(y_list) - self.padding
max_height = max(y_list) + self.padding max_height = max(y_list) + self.padding
self._generate_transfer_icon((min_width, min_height, max_width, max_height))
for res in self.resource_point:
icon = self._get_icon_image(self.resource_id)
self.map.paste(
icon, (res.x - self.deviation[0], res.y - self.deviation[1]), True
)
if self.planning_route: if self.planning_route:
self._generate_best_route() self._generate_best_route()
self._generate_transfer_icon((min_width, min_height, max_width, max_height))
for x, y in self.resource_point:
icon = self._get_icon_image(self.resource_id)
self.map.paste(icon, (x - self.deviation[0], y - self.deviation[1]), True)
self.map.crop((min_width, min_height, max_width, max_height)) self.map.crop((min_width, min_height, max_width, max_height))
rand = random.randint(1, 10000) rand = random.randint(1, 10000)
self.map.save(f'{IMAGE_PATH}/temp/genshin_map_{rand}.png') self.map.save(f"{IMAGE_PATH}/temp/genshin_map_{rand}.png")
return rand return rand
# 资源数量 # 资源数量
@ -119,40 +129,98 @@ class Map:
# 生成传送锚点和神像 # 生成传送锚点和神像
def _generate_transfer_icon(self, box: Tuple[int, int, int, int]): def _generate_transfer_icon(self, box: Tuple[int, int, int, int]):
min_width, min_height, max_width, max_height = box min_width, min_height, max_width, max_height = box
for points in [self.teleport_anchor_point, self.teleport_god_point]: for resources in [self.teleport_anchor_point, self.teleport_god_point]:
id_ = ( id_ = (
self.teleport_anchor_id self.teleport_anchor_id
if points == self.teleport_anchor_point if resources == self.teleport_anchor_point
else self.teleport_god_id else self.teleport_god_id
) )
for x, y in points: for res in resources:
if min_width < x < max_width and min_height < y < max_height: if min_width < res.x < max_width and min_height < res.y < max_height:
icon = self._get_icon_image(id_) icon = self._get_icon_image(id_)
self.map.paste( self.map.paste(
icon, (x - self.deviation[0], y - self.deviation[1]), True icon,
(res.x - self.deviation[0], res.y - self.deviation[1]),
True,
) )
# 生成最优路线(说是最优其实就是直线最短) # 生成最优路线(说是最优其实就是直线最短)
def _generate_best_route(self): def _generate_best_route(self):
for x, y in self.resource_point: resources_route = []
min_deviation = 999999 # 先连上最近的资源路径
xy = None for res in self.resource_point:
for points in [ # 拿到最近的资源
self.resource_point, current_res, _ = res.get_resource_distance(
self.teleport_anchor_point, self.resource_point
self.teleport_god_point, + self.teleport_anchor_point
]: + self.teleport_god_point
for r_x, r_y in points: )
distance = int(sqrt(pow(abs(r_x - x), 2) + pow(abs(r_y - y), 2))) self.map.line(
if distance < min_deviation and x != r_x and y != r_y: (current_res.x, current_res.y, res.x, res.y), (255, 0, 0), width=1
min_deviation = distance )
xy = (x, y, r_x, r_y) resources_route.append((current_res, res))
teleport_list = self.teleport_anchor_point + self.teleport_god_point
for res1, res2 in resources_route:
point_list = [x for x in resources_route if res1 in x or res2 in x]
if not list(set(point_list).intersection(set(teleport_list))):
if res1 not in teleport_list and res2 not in teleport_list:
# while True:
# tmp = [x for x in point_list]
# break
teleport1, distance1 = res1.get_resource_distance(teleport_list)
teleport2, distance2 = res2.get_resource_distance(teleport_list)
if distance1 > distance2:
self.map.line(
(teleport1.x, teleport1.y, res1.x, res1.y),
(255, 0, 0),
width=1,
)
else:
self.map.line(
(teleport2.x, teleport2.y, res2.x, res2.y),
(255, 0, 0),
width=1,
)
self.map.line(xy, (255, 0, 0), width=3) # self.map.line(xy, (255, 0, 0), width=3)
# 获取资源图标 # 获取资源图标
def _get_icon_image(self, id_: int) -> "CreateImg": def _get_icon_image(self, id_: int) -> "CreateImg":
icon = icon_path / f"{id_}.png" icon = icon_path / f"{id_}.png"
if icon.exists(): if icon.exists():
return CreateImg(50, 50, background=icon) return CreateImg(
return CreateImg(50, 50, background=f"{icon_path}/box.png") int(50 * self.ratio), int(50 * self.ratio), background=icon
)
return CreateImg(
int(50 * self.ratio),
int(50 * self.ratio),
background=f"{icon_path}/box.png",
)
# def _get_shortest_path(self, res: 'Resources', res_2: 'Resources'):
# 资源类
class Resources:
def __init__(self, x: int, y: int):
self.x = x
self.y = y
def get_distance(self, x: int, y: int):
return int(sqrt(pow(abs(self.x - x), 2) + pow(abs(self.y - y), 2)))
# 拿到资源在该列表中的最短路径
def get_resource_distance(self, resources: List["Resources"]) -> "Resources, int":
current_res = None
min_distance = 999999
for res in resources:
distance = self.get_distance(res.x, res.y)
if distance < min_distance and res != self:
current_res = res
min_distance = distance
return current_res, min_distance

View File

@ -16,6 +16,7 @@ import nonebot
import aiohttp import aiohttp
import aiofiles import aiofiles
import os import os
try: try:
import ujson as json import ujson as json
except ModuleNotFoundError: except ModuleNotFoundError:
@ -38,20 +39,29 @@ CENTER_POINT: Optional[Tuple[int, int]] = None
resource_name_list: List[str] = [] resource_name_list: List[str] = []
MAP_RATIO = 0.5
# 查找资源 # 查找资源
async def query_resource(resource_name: str) -> str: async def query_resource(resource_name: str) -> str:
global CENTER_POINT
planning_route: bool = False planning_route: bool = False
if resource_name and resource_name[-2:] == "路径": if resource_name and resource_name[-2:] == "路径":
resource_name = resource_name[:-2].strip() resource_name = resource_name[:-2].strip()
planning_route = True planning_route = True
if not resource_name or resource_name not in resource_name_list: if not resource_name or resource_name not in resource_name_list:
return f"未查找到 {resource_name} 资源,可通过 “原神资源列表” 获取全部资源名称.." return f"未查找到 {resource_name} 资源,可通过 “原神资源列表” 获取全部资源名称.."
map_ = Map(resource_name, CENTER_POINT, planning_route=planning_route) map_ = Map(
resource_name, CENTER_POINT, planning_route=planning_route, ratio=MAP_RATIO
)
count = map_.get_resource_count() count = map_.get_resource_count()
rand = await asyncio.get_event_loop().run_in_executor(None, map_.generate_resource_icon_in_map) rand = await asyncio.get_event_loop().run_in_executor(
return f"{image(f'genshin_map_{rand}.png', 'temp')}" \ None, map_.generate_resource_icon_in_map
f"\n\n{resource_name} 一共找到 {count} 个位置点\n※ 数据来源于米游社wiki" )
return (
f"{image(f'genshin_map_{rand}.png', 'temp')}"
f"\n\n{resource_name} 一共找到 {count} 个位置点\n※ 数据来源于米游社wiki"
)
# 原神资源列表 # 原神资源列表
@ -76,7 +86,7 @@ async def init(flag: bool = False):
global CENTER_POINT, resource_name_list global CENTER_POINT, resource_name_list
semaphore = asyncio.Semaphore(10) semaphore = asyncio.Semaphore(10)
async with aiohttp.ClientSession(headers=get_user_agent()) as session: async with aiohttp.ClientSession(headers=get_user_agent()) as session:
await download_map_init(session, semaphore, flag) await download_map_init(session, semaphore, MAP_RATIO, flag)
await download_resource_data(session, semaphore) await download_resource_data(session, semaphore)
await download_resource_type(session) await download_resource_type(session)
if not CENTER_POINT: if not CENTER_POINT:
@ -137,42 +147,57 @@ async def download_resource_data(session: ClientSession, semaphore: Semaphore):
# 下载原神地图并拼图 # 下载原神地图并拼图
async def download_map_init(session: ClientSession, semaphore: Semaphore, flag: bool = False): async def download_map_init(
global CENTER_POINT session: ClientSession, semaphore: Semaphore, ratio: float = 1, flag: bool = False
):
global CENTER_POINT, MAP_RATIO
map_path.mkdir(exist_ok=True, parents=True) map_path.mkdir(exist_ok=True, parents=True)
_map = map_path / "map.png"
if os.path.getsize(_map) > 1024 * 1024 * 30:
_map.unlink()
async with session.get(MAP_URL, timeout=5) as response: async with session.get(MAP_URL, timeout=5) as response:
if response.status == 200: if response.status == 200:
data = await response.json() data = await response.json()
if data["message"] == "OK": if data["message"] == "OK":
data = json.loads(data["data"]["info"]["detail"]) data = json.loads(data["data"]["info"]["detail"])
CENTER_POINT = (data["origin"][0], data["origin"][1]) CENTER_POINT = (data["origin"][0], data["origin"][1])
# padding_w, padding_h = data['padding'] if not _map.exists():
data = data["slices"] # padding_w, padding_h = data['padding']
idx = 0 data = data["slices"]
for x in data: idx = 0
idj = 0 for x in data:
for j in x: idj = 0
await download_image( for j in x:
j["url"], await download_image(
f"{map_path}/{idx}_{idj}.png", j["url"],
session, f"{map_path}/{idx}_{idj}.png",
semaphore, session,
force_flag=flag semaphore,
) force_flag=flag,
idj += 1 )
idx += 1 idj += 1
map_width, map_height = CreateImg( idx += 1
0, 0, background=f"{map_path}/0_0.png" map_width, map_height = CreateImg(
).size 0, 0, background=f"{map_path}/0_0.png"
lens = len([x for x in os.listdir(f"{map_path}") if x.startswith("0")]) ).size
background_image = CreateImg( map_width = map_width * MAP_RATIO
map_width * lens, map_height * lens, map_width, map_height map_height = map_height * MAP_RATIO
) lens = len(
for i in range(idx): [x for x in os.listdir(f"{map_path}") if x.startswith("0")]
for j in range(idj): )
x = CreateImg(0, 0, background=f"{map_path}/{i}_{j}.png") background_image = CreateImg(
background_image.paste(x) map_width * lens, map_height * lens, map_width, map_height
background_image.save(f"{map_path}/map.png") )
for i in range(idx):
for j in range(idj):
x = CreateImg(
0,
0,
background=f"{map_path}/{i}_{j}.png",
ratio=MAP_RATIO,
)
background_image.paste(x)
background_image.save(f"{map_path}/map.png")
else: else:
logger.warning(f'获取原神地图失败 msg: {data["message"]}') logger.warning(f'获取原神地图失败 msg: {data["message"]}')
else: else:
@ -238,3 +263,8 @@ async def download_image(
logger.warning(f"原神图片打开错误..已删除,等待下次更新... file: {path}") logger.warning(f"原神图片打开错误..已删除,等待下次更新... file: {path}")
if os.path.exists(path): if os.path.exists(path):
os.remove(path) os.remove(path)
#
# def _get_point_ratio():
#

View File

@ -3,6 +3,7 @@ from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
from nonebot.adapters.cqhttp.permission import GROUP from nonebot.adapters.cqhttp.permission import GROUP
from utils.utils import get_message_text, is_number, get_message_imgs, get_local_proxy from utils.utils import get_message_text, is_number, get_message_imgs, get_local_proxy
from nonebot.typing import T_State from nonebot.typing import T_State
from asyncio.exceptions import TimeoutError
import time import time
from nonebot.adapters.cqhttp.exception import ActionFailed from nonebot.adapters.cqhttp.exception import ActionFailed
from configs.path_config import DATA_PATH, IMAGE_PATH from configs.path_config import DATA_PATH, IMAGE_PATH
@ -47,13 +48,16 @@ def save_data():
async def download_img_and_hash(url, group_id): async def download_img_and_hash(url, group_id):
async with aiohttp.ClientSession() as session: try:
async with session.get(url, proxy=get_local_proxy(), timeout=10) as response: async with aiohttp.ClientSession() as session:
async with aiofiles.open( async with session.get(url, proxy=get_local_proxy(), timeout=10) as response:
IMAGE_PATH + f"temp/mute_{group_id}_img.jpg", "wb" async with aiofiles.open(
) as f: IMAGE_PATH + f"temp/mute_{group_id}_img.jpg", "wb"
await f.write(await response.read()) ) as f:
return str(get_img_hash(IMAGE_PATH + f"temp/mute_{group_id}_img.jpg")) await f.write(await response.read())
return str(get_img_hash(IMAGE_PATH + f"temp/mute_{group_id}_img.jpg"))
except TimeoutError:
return ''
mute_dict = {} mute_dict = {}

View File

@ -36,7 +36,7 @@ flmt = FreqLimiter(60)
# 在 Matcher 运行前检测其是否启用 # 在 Matcher 运行前检测其是否启用
@run_preprocessor @run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State): async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if not isinstance(event, MessageEvent): if not isinstance(event, MessageEvent) and matcher.module != 'poke':
return return
plugin = matcher.module plugin = matcher.module
group_id = _get_group_id(event) group_id = _get_group_id(event)

View File

@ -1,4 +1,4 @@
from nonebot import on_message, on_command from nonebot import on_message
from services.log import logger from services.log import logger
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
from nonebot.typing import T_State from nonebot.typing import T_State
@ -26,6 +26,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
event.json() event.json()
): ):
data = json.loads(get_message_json(event.json())[0]["data"]) data = json.loads(get_message_json(event.json())[0]["data"])
print(data)
if data: if data:
if data.get("desc") == "哔哩哔哩": if data.get("desc") == "哔哩哔哩":
async with aiohttp.ClientSession(headers=get_user_agent()) as session: async with aiohttp.ClientSession(headers=get_user_agent()) as session:

View File

@ -11,7 +11,7 @@ from models.pixiv import Pixiv
import random import random
pix = on_command("pix", aliases={'PIX'}, priority=5, block=True) pix = on_command("pix", aliases={"PIX"}, priority=5, block=True)
@pix.handle() @pix.handle()
@ -60,4 +60,4 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
logger.info( logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查看PIX图库PID: {pid}" f" 查看PIX图库PID: {pid}"
) )

View File

@ -2,7 +2,7 @@ from configs.path_config import IMAGE_PATH
from utils.message_builder import image from utils.message_builder import image
from services.log import logger from services.log import logger
from aiohttp.client_exceptions import ClientConnectorError from aiohttp.client_exceptions import ClientConnectorError
from utils.image_utils import get_img_hash from utils.image_utils import get_img_hash, compressed_image
from asyncpg.exceptions import UniqueViolationError from asyncpg.exceptions import UniqueViolationError
from utils.utils import get_local_proxy from utils.utils import get_local_proxy
from asyncio.exceptions import TimeoutError from asyncio.exceptions import TimeoutError
@ -10,6 +10,7 @@ from typing import List, Optional
from models.setu import Setu from models.setu import Setu
import aiohttp import aiohttp
import aiofiles import aiofiles
import asyncio
import os import os
import random import random
@ -26,18 +27,15 @@ r18_path = "_r18/"
# 获取url # 获取url
async def get_setu_urls( async def get_setu_urls(
tags: List[str], num: int = 1, r18: int = 0, command: str = '' tags: List[str], num: int = 1, r18: int = 0, command: str = ""
) -> "List[str], List[str], List[tuple], int": ) -> "List[str], List[str], List[tuple], int":
tags = tags[:20] if len(tags) > 20 else tags tags = tags[:20] if len(tags) > 20 else tags
params = { params = {
"r18": r18, # 添加r18参数 0为否1为是2为混合 "r18": r18, # 添加r18参数 0为否1为是2为混合
"tag": "|".join(tags), # 若指定tag "tag": "|".join(tags), # 若指定tag
"num": 100, # 一次返回的结果数量范围为1到10不提供 APIKEY 时固定为1 "num": 100, # 一次返回的结果数量范围为1到10不提供 APIKEY 时固定为1
"size1200": "original", # 是否使用 master_1200 缩略图,以节省流量或提升加载速度 "size": ["original"], # 是否使用 master_1200 缩略图,以节省流量或提升加载速度
} }
urls = []
text_list = []
add_databases_list = []
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
for count in range(3): for count in range(3):
logger.info(f"get_setu_url: count --> {count}") logger.info(f"get_setu_url: count --> {count}")
@ -49,36 +47,13 @@ async def get_setu_urls(
data = await response.json() data = await response.json()
if not data["error"]: if not data["error"]:
data = data["data"] data = data["data"]
for i in range(len(data)): (
img_url = data[i]["urls"]["original"] urls,
img_url = ( text_list,
img_url.replace("i.pixiv.cat", "i.pximg.net") add_databases_list,
if "i.pixiv.cat" in img_url ) = await asyncio.get_event_loop().run_in_executor(
else img_url None, _setu_data_process, data, command
) )
title = data[i]["title"]
author = data[i]["author"]
pid = data[i]["pid"]
urls.append(img_url)
text_list.append(
f"title{title}\nauthor{author}\nPID{pid}"
)
tags = []
for j in range(len(data[i]["tags"])):
tags.append(data[i]["tags"][j])
if command != '色图r':
if 'R-18' in tags:
tags.remove('R-18')
add_databases_list.append(
(
title,
author,
pid,
"",
img_url,
",".join(tags),
)
)
num = num if num < len(data) else len(data) num = num if num < len(data) else len(data)
random_idx = random.sample(range(len(data)), num) random_idx = random.sample(range(len(data)), num)
x_urls = [] x_urls = []
@ -101,7 +76,9 @@ headers = {
} }
async def search_online_setu(url_: str, id_: int = None, path_: str = None) -> "MessageSegment, int": async def search_online_setu(
url_: str, id_: int = None, path_: str = None
) -> "MessageSegment, int":
if "i.pixiv.cat" in url_: if "i.pixiv.cat" in url_:
url_ = url_.replace("i.pixiv.cat", "i.pximg.net") url_ = url_.replace("i.pixiv.cat", "i.pximg.net")
async with aiohttp.ClientSession(headers=headers) as session: async with aiohttp.ClientSession(headers=headers) as session:
@ -110,18 +87,25 @@ async def search_online_setu(url_: str, id_: int = None, path_: str = None) -> "
try: try:
async with session.get(url_, proxy=get_local_proxy(), timeout=3) as res: async with session.get(url_, proxy=get_local_proxy(), timeout=3) as res:
if res.status == 200: if res.status == 200:
index = str(random.randint(1, 100000)) if id_ is None else id_ index = random.randint(1, 100000) if id_ is None else id_
path_ = 'temp' if path_ is None else path_ path_ = "temp" if not path_ else path_
if id_: file = f"{index}_temp_setu.jpg" if not path_ else f"{index}.jpg"
file = f'{index}.jpg' async with aiofiles.open(
else: f"{IMAGE_PATH}/{path_}/{file}", "wb"
file = f'{index}_temp_setu.jpg' ) as f:
async with aiofiles.open(f'{IMAGE_PATH}/{path_}/{file}', "wb") as f:
try: try:
await f.write(await res.read()) await f.write(await res.read())
except TimeoutError: except TimeoutError:
# return '\n这图没下载过来~(网太差?)', -1, False
continue continue
if id_ is not None:
if (
os.path.getsize(f"{IMAGE_PATH}/{path_}/{index}.jpg")
> 1024 * 1024 * 1.5
):
compressed_image(
os.path.join(path_, f"{index}.jpg"),
os.path.join(path_, f"{index}.jpg"),
)
logger.info(f"下载 lolicon图片 {url_} 成功, id{index}") logger.info(f"下载 lolicon图片 {url_} 成功, id{index}")
return image(file, path_), index return image(file, path_), index
else: else:
@ -152,7 +136,7 @@ async def add_data_to_database(lst: List[tuple]):
if tmp: if tmp:
for x in tmp: for x in tmp:
try: try:
r18 = 1 if 'R-18' in x[5] else 0 r18 = 1 if "R-18" in x[5] else 0
idx = await Setu.get_image_count(r18) idx = await Setu.get_image_count(r18)
await Setu.add_setu_data( await Setu.add_setu_data(
idx, idx,
@ -229,3 +213,39 @@ async def find_img_index(img_url, user_id):
f"PID{setu_img.pid}" f"PID{setu_img.pid}"
) )
return "该图不在色图库中或色图库未更新!" return "该图不在色图库中或色图库未更新!"
# 处理色图数据
def _setu_data_process(data: dict, command: str) -> "list, list, list":
urls = []
text_list = []
add_databases_list = []
for i in range(len(data)):
img_url = data[i]["urls"]["original"]
img_url = (
img_url.replace("i.pixiv.cat", "i.pximg.net")
if "i.pixiv.cat" in img_url
else img_url
)
title = data[i]["title"]
author = data[i]["author"]
pid = data[i]["pid"]
urls.append(img_url)
text_list.append(f"title{title}\nauthor{author}\nPID{pid}")
tags = []
for j in range(len(data[i]["tags"])):
tags.append(data[i]["tags"][j])
if command != "色图r":
if "R-18" in tags:
tags.remove("R-18")
add_databases_list.append(
(
title,
author,
pid,
"",
img_url,
",".join(tags),
)
)
return urls, text_list, add_databases_list

View File

@ -19,7 +19,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
@gold_rank.handle() @gold_rank.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State): async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
all_users = await BagUser.get_all_users(event.group_id) all_users = await BagUser.get_all_users(event.group_id)
all_user_id = [user.qq for user in all_users] all_user_id = [user.user_qq for user in all_users]
all_user_data = [user.gold for user in all_users] all_user_data = [user.gold for user in all_users]
await gold_rank.finish( await gold_rank.finish(
"金币排行:\n" + await init_rank(all_user_id, all_user_data, event.group_id) "金币排行:\n" + await init_rank(all_user_id, all_user_data, event.group_id)

View File

@ -92,7 +92,7 @@ async def _(
# print(f'model --> {model}') # print(f'model --> {model}')
for plugin in plugins2info_dict: for plugin in plugins2info_dict:
if plugin == model: if plugin == model:
print(f'plugin --> {plugin}') # print(f'plugin --> {plugin}')
try: try:
group_id = str(event.group_id) group_id = str(event.group_id)
except AttributeError: except AttributeError:

View File

@ -4,7 +4,7 @@ from models.level_user import LevelUser
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message from nonebot.adapters.cqhttp import Bot, MessageEvent, Message
from nonebot.rule import to_me from nonebot.rule import to_me
from utils.utils import get_message_at, get_message_text, is_number, get_bot from utils.utils import get_message_at, get_message_text, is_number, get_bot, scheduler
from services.log import logger from services.log import logger
from .data_source import open_remind, close_remind from .data_source import open_remind, close_remind
from models.group_info import GroupInfo from models.group_info import GroupInfo
@ -234,3 +234,17 @@ def _clear_data() -> float:
file_size = 0 file_size = 0
size += file_size size += file_size
return float(size) return float(size)
# 早上好
@scheduler.scheduled_job(
"cron",
hour=1,
minute=1,
)
async def _():
size = await asyncio.get_event_loop().run_in_executor(
None, _clear_data
)
logger.info('自动清理临时数据完成,' + "共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))

View File

@ -12,15 +12,22 @@ __plugin_name__ = "更新色图 [Hidden]"
__plugin_usage__ = '' __plugin_usage__ = ''
exists_flag = False
update_setu = on_command("更新色图", rule=to_me(), permission=SUPERUSER, priority=1, block=True) update_setu = on_command("更新色图", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
@update_setu.handle() @update_setu.handle()
async def _(bot: Bot, event: Event, state: T_State): async def _(bot: Bot, event: Event, state: T_State):
global exists_flag
if DOWNLOAD_SETU: if DOWNLOAD_SETU:
await update_setu.send("开始更新色图...", at_sender=True) if not exists_flag:
await update_setu.finish(await update_setu_img(), at_sender=True) exists_flag = True
await update_setu.send("开始更新色图...", at_sender=True)
await update_setu.send(await update_setu_img(), at_sender=True)
exists_flag = False
else:
await update_setu.finish("色图正在更新....")
else: else:
await update_setu.finish('更新色图配置未开启') await update_setu.finish('更新色图配置未开启')
@ -32,5 +39,6 @@ async def _(bot: Bot, event: Event, state: T_State):
minute=30, minute=30,
) )
async def _(): async def _():
if DOWNLOAD_SETU: global exists_flag
if DOWNLOAD_SETU and not exists_flag:
await update_setu_img() await update_setu_img()

View File

@ -25,53 +25,54 @@ async def update_old_setu_data():
path = Path(TXT_PATH) path = Path(TXT_PATH)
setu_data_file = path / "setu_data.json" setu_data_file = path / "setu_data.json"
r18_data_file = path / "r18_setu_data.json" r18_data_file = path / "r18_setu_data.json"
index = 0 if setu_data_file.exists() or r18_data_file.exists():
r18_index = 0 index = 0
count = 0 r18_index = 0
fail_count = 0 count = 0
for file in [setu_data_file, r18_data_file]: fail_count = 0
if file.exists(): for file in [setu_data_file, r18_data_file]:
data = json.load(open(file, "r", encoding="utf8")) if file.exists():
for x in data: data = json.load(open(file, "r", encoding="utf8"))
if file == setu_data_file: for x in data:
idx = index if file == setu_data_file:
if 'R-18' in data[x]["tags"]: idx = index
data[x]["tags"].remove('R-18') if 'R-18' in data[x]["tags"]:
else: data[x]["tags"].remove('R-18')
idx = r18_index
img_url = (
data[x]["img_url"].replace("i.pixiv.cat", "i.pximg.net")
if "i.pixiv.cat" in data[x]["img_url"]
else data[x]["img_url"]
)
# idx = r18_index if 'R-18' in data[x]["tags"] else index
try:
await Setu.add_setu_data(
idx,
data[x]["title"],
data[x]["author"],
data[x]["pid"],
data[x]["img_hash"],
img_url,
",".join(data[x]["tags"]),
)
count += 1
if 'R-18' in data[x]["tags"]:
r18_index += 1
else: else:
index += 1 idx = r18_index
logger.info(f'添加旧色图数据成功 PID{data[x]["pid"]} index{idx}....') img_url = (
except UniqueViolationError: data[x]["img_url"].replace("i.pixiv.cat", "i.pximg.net")
fail_count += 1 if "i.pixiv.cat" in data[x]["img_url"]
logger.info(f'添加旧色图数据失败,色图重复 PID{data[x]["pid"]} index{idx}....') else data[x]["img_url"]
file.unlink() )
setu_url_path = path / "setu_url.json" # idx = r18_index if 'R-18' in data[x]["tags"] else index
setu_r18_url_path = path / "setu_r18_url.json" try:
if setu_url_path.exists(): await Setu.add_setu_data(
setu_url_path.unlink() idx,
if setu_r18_url_path.exists(): data[x]["title"],
setu_r18_url_path.unlink() data[x]["author"],
logger.info(f"更新旧色图数据完成,成功更新数据:{count} 条,累计失败:{fail_count}") data[x]["pid"],
data[x]["img_hash"],
img_url,
",".join(data[x]["tags"]),
)
count += 1
if 'R-18' in data[x]["tags"]:
r18_index += 1
else:
index += 1
logger.info(f'添加旧色图数据成功 PID{data[x]["pid"]} index{idx}....')
except UniqueViolationError:
fail_count += 1
logger.info(f'添加旧色图数据失败,色图重复 PID{data[x]["pid"]} index{idx}....')
file.unlink()
setu_url_path = path / "setu_url.json"
setu_r18_url_path = path / "setu_r18_url.json"
if setu_url_path.exists():
setu_url_path.unlink()
if setu_r18_url_path.exists():
setu_r18_url_path.unlink()
logger.info(f"更新旧色图数据完成,成功更新数据:{count} 条,累计失败:{fail_count}")
headers = { headers = {
@ -142,7 +143,6 @@ async def update_setu_img():
break break
except (TimeoutError, ClientConnectorError) as e: except (TimeoutError, ClientConnectorError) as e:
logger.warning(f"{image.local_id}.jpg 更新失败 ..{type(e)}{e}") logger.warning(f"{image.local_id}.jpg 更新失败 ..{type(e)}{e}")
pass
except Exception as e: except Exception as e:
_success -= 1 _success -= 1
logger.error(f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}") logger.error(f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}")
@ -151,6 +151,8 @@ async def update_setu_img():
error_info.append( error_info.append(
f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}" f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}"
) )
else:
logger.info(f'更新色图 {image.local_id}.jpg 已存在')
await get_bot().send_private_msg( await get_bot().send_private_msg(
user_id=int(list(get_bot().config.superusers)[0]), user_id=int(list(get_bot().config.superusers)[0]),
message=f'{str(datetime.now()).split(".")[0]} 更新 色图 完成,实际更新 {_success} 张,以下为更新时未知错误:\n' message=f'{str(datetime.now()).split(".")[0]} 更新 色图 完成,实际更新 {_success} 张,以下为更新时未知错误:\n'

View File

@ -1,10 +1,9 @@
from nonebot import on_regex from nonebot import on_regex
from .data_source import get_weather_of_city from .data_source import get_weather_of_city, update_city, get_city_list
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from jieba import posseg from jieba import posseg
from services.log import logger from services.log import logger
from nonebot.typing import T_State from nonebot.typing import T_State
from .config import city_list
import re import re
from utils.utils import get_message_text from utils.utils import get_message_text
@ -26,14 +25,9 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
msg += "" msg += ""
city = "" city = ""
if msg: if msg:
citys = [] city_list = get_city_list()
for x in city_list.keys():
for city in city_list[x]:
citys.append(city)
for word in posseg.lcut(msg): for word in posseg.lcut(msg):
if word.word in city_list.keys(): if word.flag == "ns" or word.word[:-1] in city_list:
await weather.finish("不要查一个省的天气啊,这么大查起来很累人的..", at_sender=True)
if word.flag == "ns" or word.word[:-1] in citys:
city = str(word.word).strip() city = str(word.word).strip()
break break
if word.word == "火星": if word.word == "火星":

View File

@ -1,327 +0,0 @@
city_list = {
"北京": ["北京"],
"天津": ["天津"],
"山西": ["太原", "阳泉", "晋城", "长治", "临汾", "运城", "忻州", "吕梁", "晋中", "大同", "朔州"],
"河北": [
"沧州",
"石家庄",
"唐山",
"保定",
"廊坊",
"衡水",
"邯郸",
"邢台",
"张家口",
"辛集",
"秦皇岛",
"定州",
"承德",
"涿州",
],
"山东": [
"济南",
"淄博",
"聊城",
"德州",
"滨州",
"济宁",
"菏泽",
"枣庄",
"烟台",
"威海",
"泰安",
"青岛",
"临沂",
"莱芜",
"东营",
"潍坊",
"日照",
],
"河南": [
"郑州",
"新乡",
"鹤壁",
"安阳",
"焦作",
"濮阳",
"开封",
"驻马店",
"商丘",
"三门峡",
"南阳",
"洛阳",
"周口",
"许昌",
"信阳",
"漯河",
"平顶山",
"济源",
],
"广东": [
"珠海",
"中山",
"肇庆",
"深圳",
"清远",
"揭阳",
"江门",
"惠州",
"河源",
"广州",
"佛山",
"东莞",
"潮州",
"汕尾",
"梅州",
"阳江",
"云浮",
"韶关",
"湛江",
"汕头",
"茂名",
],
"浙江": ["舟山", "温州", "台州", "绍兴", "衢州", "宁波", "丽水", "金华", "嘉兴", "湖州", "杭州"],
"宁夏": ["中卫", "银川", "吴忠", "石嘴山", "固原"],
"江苏": [
"镇江",
"扬州",
"盐城",
"徐州",
"宿迁",
"无锡",
"苏州",
"南通",
"南京",
"连云港",
"淮安",
"常州",
"泰州",
],
"湖南": [
"长沙",
"邵阳",
"怀化",
"株洲",
"张家界",
"永州",
"益阳",
"湘西",
"娄底",
"衡阳",
"郴州",
"岳阳",
"常德",
"湘潭",
],
"吉林": ["长春", "长春", "通化", "松原", "四平", "辽源", "吉林", "延边", "白山", "白城"],
"福建": ["漳州", "厦门", "福州", "三明", "莆田", "宁德", "南平", "龙岩", "泉州"],
"甘肃": [
"张掖",
"陇南",
"兰州",
"嘉峪关",
"白银",
"武威",
"天水",
"庆阳",
"平凉",
"临夏",
"酒泉",
"金昌",
"甘南",
"定西",
],
"陕西": ["榆林", "西安", "延安", "咸阳", "渭南", "铜川", "商洛", "汉中", "宝鸡", "安康"],
"辽宁": [
"营口",
"铁岭",
"沈阳",
"盘锦",
"辽阳",
"锦州",
"葫芦岛",
"阜新",
"抚顺",
"丹东",
"大连",
"朝阳",
"本溪",
"鞍山",
],
"江西": ["鹰潭", "宜春", "上饶", "萍乡", "南昌", "景德镇", "吉安", "抚州", "新余", "九江", "赣州"],
"黑龙江": [
"伊春",
"七台河",
"牡丹江",
"鸡西",
"黑河",
"鹤岗",
"哈尔滨",
"大兴安岭",
"绥化",
"双鸭山",
"齐齐哈尔",
"佳木斯",
"大庆",
],
"安徽": [
"宣城",
"铜陵",
"六安",
"黄山",
"淮南",
"合肥",
"阜阳",
"亳州",
"安庆",
"池州",
"宿州",
"芜湖",
"马鞍山",
"淮北",
"滁州",
"蚌埠",
],
"湖北": [
"孝感",
"武汉",
"十堰",
"荆门",
"黄冈",
"襄阳",
"咸宁",
"随州",
"黄石",
"恩施",
"鄂州",
"荆州",
"宜昌",
"潜江",
"天门",
"神农架",
"仙桃",
],
"青海": ["西宁", "海西", "海东", "玉树", "黄南", "海南", "海北", "果洛"],
"新疆": [
"乌鲁木齐",
"克州",
"阿勒泰",
"五家渠",
"石河子",
"伊犁",
"吐鲁番",
"塔城",
"克拉玛依",
"喀什",
"和田",
"哈密",
"昌吉",
"博尔塔拉",
"阿克苏",
"巴音郭楞",
"阿拉尔",
"图木舒克",
"铁门关",
],
"贵州": ["铜仁", "黔东南", "贵阳", "安顺", "遵义", "黔西南", "黔南", "六盘水", "毕节"],
"四川": [
"遂宁",
"攀枝花",
"眉山",
"凉山",
"成都",
"巴中",
"广安",
"自贡",
"甘孜",
"资阳",
"宜宾",
"雅安",
"内江",
"南充",
"绵阳",
"泸州",
"凉山",
"乐山",
"广元",
"甘孜",
"德阳",
"达州",
"阿坝",
],
"上海": ["上海"],
"广西": [
"南宁",
"贵港",
"玉林",
"梧州",
"钦州",
"柳州",
"来宾",
"贺州",
"河池",
"桂林",
"防城港",
"崇左",
"北海",
"百色",
],
"西藏": ["拉萨", "山南", "日喀则", "那曲", "林芝", "昌都", "阿里"],
"云南": [
"昆明",
"红河",
"大理",
"玉溪",
"昭通",
"西双版纳",
"文山",
"曲靖",
"普洱",
"怒江",
"临沧",
"丽江",
"红河",
"迪庆",
"德宏",
"大理",
"楚雄",
"保山",
],
"内蒙古": [
"呼和浩特",
"乌兰察布",
"兴安",
"赤峰",
"呼伦贝尔",
"锡林郭勒",
"乌海",
"通辽",
"巴彦淖尔",
"阿拉善",
"鄂尔多斯",
"包头",
],
"海南": [
"海口",
"三沙",
"三亚",
"临高",
"五指山",
"陵水",
"文昌",
"万宁",
"白沙",
"乐东",
"澄迈",
"屯昌",
"定安",
"东方",
"保亭",
"琼中",
"琼海",
"儋州",
"昌江",
],
"重庆": ["重庆"],
"台湾": ["台北", "高雄", "基隆", "台中", "台南", "新竹", "嘉义", "新北", "桃园"],
}

View File

@ -1,21 +1,99 @@
import requests from services.log import logger
from utils.message_builder import image from utils.message_builder import image
from utils.user_agent import get_user_agent
from configs.path_config import TXT_PATH
from asyncio.exceptions import TimeoutError
from typing import List
from nonebot import Driver
from pathlib import Path
import aiohttp
import ujson as json
import nonebot
driver: Driver = nonebot.get_driver()
china_city = Path(TXT_PATH) / "china_city.json"
try:
with open(china_city, "r", encoding="utf8") as f:
data = json.load(f)
except FileNotFoundError:
data = {}
async def get_weather_of_city(city) -> str: async def get_weather_of_city(city: str) -> str:
url = "http://wthrcdn.etouch.cn/weather_mini?city=" + city code = _check_exists_city(city)
data_json = requests.get(url).json() if code == 999:
if "desc" in data_json: return "不要查一个省份的天气啊,很累人的!"
if data_json["desc"] == "invilad-citykey": elif code == 998:
return "你为啥不查火星的天气呢?小真寻只支持国内天气查询!!" + image("shengqi", "zhenxun") return "真寻只可以查询国内的天气喔..."
elif data_json["desc"] == "OK":
w_type = data_json["data"]["forecast"][0]["type"]
w_max = data_json["data"]["forecast"][0]["high"][3:]
w_min = data_json["data"]["forecast"][0]["low"][3:]
fengli = data_json["data"]["forecast"][0]["fengli"][9:-3]
ganmao = data_json["data"]["ganmao"]
fengxiang = data_json["data"]["forecast"][0]["fengxiang"]
repass = f"{city}的天气是 {w_type}\n最高温度: {w_max}\n最低温度: {w_min}\n风力: {fengli} {fengxiang}\n{ganmao}"
return repass
else: else:
return "好像出错了?" async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(
f"http://wthrcdn.etouch.cn/weather_mini?city={city}", timeout=5
) as res:
data_json = json.loads(await res.text(encoding="utf8"))
if "desc" in data_json:
if data_json["desc"] == "invilad-citykey":
return "你为啥不查火星的天气呢?小真寻只支持国内天气查询!!" + image(
"shengqi", "zhenxun"
)
elif data_json["desc"] == "OK":
w_type = data_json["data"]["forecast"][0]["type"]
w_max = data_json["data"]["forecast"][0]["high"][3:]
w_min = data_json["data"]["forecast"][0]["low"][3:]
fengli = data_json["data"]["forecast"][0]["fengli"][9:-3]
ganmao = data_json["data"]["ganmao"]
fengxiang = data_json["data"]["forecast"][0]["fengxiang"]
repass = f"{city}的天气是 {w_type}\n最高温度: {w_max}\n最低温度: {w_min}\n风力: {fengli} {fengxiang}\n{ganmao}"
return repass
else:
return "好像出错了?"
# 更新城市
@driver.on_startup
async def update_city():
global data
try:
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(
"http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
) as res:
provinces_data = json.loads(await res.text(encoding="utf8"))
for province in provinces_data.keys():
data[provinces_data[province]] = []
async with session.get(
f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
timeout=5,
) as res:
city_data = json.loads(await res.text(encoding="utf8"))
for city in city_data.keys():
data[provinces_data[province]].append(city_data[city])
with open(china_city, "w", encoding="utf8") as f:
json.dump(data, f, indent=4, ensure_ascii=False)
logger.info("自动更新城市列表完成.....")
except TimeoutError:
logger.info("自动更新城市列表超时.....")
# 城市是否存在或是否是省份
def _check_exists_city(city: str) -> int:
city = city if city[-1] != "" else city[:-1]
for province in data.keys():
# 查询省份了
if city == province and len(data[province]) != 1:
return 999
for city_ in data[province]:
if city_ == city:
return 200
return 998
def get_city_list() -> List[str]:
global data
city_list = []
for p in data.keys():
for c in data[p]:
city_list.append(c)
return city_list

View File

@ -1,10 +1,8 @@
from nonebot import on_command from nonebot import on_command
from .data_source import get_yiqing_data, clear_data from .data_source import get_yiqing_data
from services.log import logger from services.log import logger
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from nonebot.typing import T_State from nonebot.typing import T_State
from .config import city_list
from utils.utils import scheduler
__plugin_name__ = "疫情查询" __plugin_name__ = "疫情查询"
__plugin_usage__ = "查询疫情帮助:\n\t对我说 查询疫情 省份/城市,我会回复疫情的实时数据\n\t示例: 查询疫情 温州" __plugin_usage__ = "查询疫情帮助:\n\t对我说 查询疫情 省份/城市,我会回复疫情的实时数据\n\t示例: 查询疫情 温州"
@ -16,43 +14,16 @@ yiqing = on_command("疫情", aliases={"查询疫情", "疫情查询"}, priority
@yiqing.handle() @yiqing.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State): async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = str(event.get_message()).strip() msg = str(event.get_message()).strip()
if not msg or msg in ["帮助"]: result = await get_yiqing_data(msg)
await yiqing.finish(__plugin_usage__) if result:
if msg: await yiqing.send(result)
if msg in city_list.keys(): logger.info(
province = msg f"(USER {event.user_id}, GROUP "
city = "" f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询疫情: {msg}"
else: )
for key in city_list.keys():
if msg in city_list.get(key):
province = key
city = msg
break
else: else:
await yiqing.finish(__plugin_usage__) await yiqing.send("查询失败!!!!", at_sender=True)
try: logger.info(
result = await get_yiqing_data(province, city) f"(USER {event.user_id}, GROUP "
if result: f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询疫情失败"
await yiqing.send(result) )
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询疫情:"
+ result
)
else:
await yiqing.send("查询失败!!!!", at_sender=True)
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询疫情失败"
)
except UnboundLocalError:
await yiqing.finish("参数正确吗?只要一个参数啊", at_sender=True)
@scheduler.scheduled_job(
"cron",
hour=0,
minute=1,
)
async def _():
clear_data()

View File

@ -1,34 +0,0 @@
city_list = {
"北京": ["北京"],
"天津": ["天津"],
"山西": ["太原", "阳泉", "晋城", "长治", "临汾", "运城", "忻州", "吕梁", "晋中", "大同", "朔州"],
"河北": ["沧州", "石家庄", "唐山", "保定", "廊坊", "衡水", "邯郸", "邢台", "张家口", "辛集", "秦皇岛", "定州", "承德", "涿州"],
"山东": ["济南", "淄博", "聊城", "德州", "滨州", "济宁", "菏泽", "枣庄", "烟台", "威海", "泰安", "青岛", "临沂", "莱芜", "东营", "潍坊", "日照"],
"河南": ["郑州", "新乡", "鹤壁", "安阳", "焦作", "濮阳", "开封", "驻马店", "商丘", "三门峡", "南阳", "洛阳", "周口", "许昌", "信阳", "漯河", "平顶山", "济源"],
"广东": ["珠海", "中山", "肇庆", "深圳", "清远", "揭阳", "江门", "惠州", "河源", "广州", "佛山", "东莞", "潮州", "汕尾", "梅州", "阳江", "云浮", "韶关", "湛江", "汕头", "茂名"],
"浙江": ["舟山", "温州", "台州", "绍兴", "衢州", "宁波", "丽水", "金华", "嘉兴", "湖州", "杭州"],
"宁夏": ["中卫", "银川", "吴忠", "石嘴山", "固原"],
"江苏": ["镇江", "扬州", "盐城", "徐州", "宿迁", "无锡", "苏州", "南通", "南京", "连云港", "淮安", "常州", "泰州"],
"湖南": ["长沙", "邵阳", "怀化", "株洲", "张家界", "永州", "益阳", "湘西", "娄底", "衡阳", "郴州", "岳阳", "常德", "湘潭"],
"吉林": ["长春", "长春", "通化", "松原", "四平", "辽源", "吉林", "延边", "白山", "白城"],
"福建": ["漳州", "厦门", "福州", "三明", "莆田", "宁德", "南平", "龙岩", "泉州"],
"甘肃": ["张掖", "陇南", "兰州", "嘉峪关", "白银", "武威", "天水", "庆阳", "平凉", "临夏", "酒泉", "金昌", "甘南", "定西"],
"陕西": ["榆林", "西安", "延安", "咸阳", "渭南", "铜川", "商洛", "汉中", "宝鸡", "安康"],
"辽宁": ["营口", "铁岭", "沈阳", "盘锦", "辽阳", "锦州", "葫芦岛", "阜新", "抚顺", "丹东", "大连", "朝阳", "本溪", "鞍山"],
"江西": ["鹰潭", "宜春", "上饶", "萍乡", "南昌", "景德镇", "吉安", "抚州", "新余", "九江", "赣州"],
"黑龙江": ["伊春", "七台河", "牡丹江", "鸡西", "黑河", "鹤岗", "哈尔滨", "大兴安岭", "绥化", "双鸭山", "齐齐哈尔", "佳木斯", "大庆"],
"安徽": ["宣城", "铜陵", "六安", "黄山", "淮南", "合肥", "阜阳", "亳州", "安庆", "池州", "宿州", "芜湖", "马鞍山", "淮北", "滁州", "蚌埠"],
"湖北": ["孝感", "武汉", "十堰", "荆门", "黄冈", "襄阳", "咸宁", "随州", "黄石", "恩施", "鄂州", "荆州", "宜昌", "潜江", "天门", "神农架", "仙桃"],
"青海": ["西宁", "海西", "海东", "玉树", "黄南", "海南", "海北", "果洛"],
"新疆": ["乌鲁木齐", "克州", "阿勒泰", "五家渠", "石河子", "伊犁", "吐鲁番", "塔城", "克拉玛依", "喀什", "和田", "哈密", "昌吉", "博尔塔拉", "阿克苏", "巴音郭楞", "阿拉尔", "图木舒克", "铁门关"],
"贵州": ["铜仁", "黔东南", "贵阳", "安顺", "遵义", "黔西南", "黔南", "六盘水", "毕节"],
"四川": ["遂宁", "攀枝花", "眉山", "凉山", "成都", "巴中", "广安", "自贡", "甘孜", "资阳", "宜宾", "雅安", "内江", "南充", "绵阳", "泸州", "凉山", "乐山", "广元", "甘孜", "德阳", "达州", "阿坝"],
"上海": ["上海"],
"广西": ["南宁", "贵港", "玉林", "梧州", "钦州", "柳州", "来宾", "贺州", "河池", "桂林", "防城港", "崇左", "北海", "百色"],
"西藏": ["拉萨", "山南", "日喀则", "那曲", "林芝", "昌都", "阿里"],
"云南": ["昆明", "红河", "大理", "玉溪", "昭通", "西双版纳", "文山", "曲靖", "普洱", "怒江", "临沧", "丽江", "红河", "迪庆", "德宏", "大理", "楚雄", "保山"],
"内蒙古": ["呼和浩特", "乌兰察布", "兴安", "赤峰", "呼伦贝尔", "锡林郭勒", "乌海", "通辽", "巴彦淖尔", "阿拉善", "鄂尔多斯", "包头"],
"海南": ["海口", "三沙", "三亚", "临高", "五指山", "陵水", "文昌", "万宁", "白沙", "乐东", "澄迈", "屯昌", "定安", "东方", "保亭", "琼中", "琼海", "儋州", "昌江"],
"重庆": ["重庆"],
"台湾": ["台北", "高雄", "基隆", "台中", "台南", "新竹", "嘉义", "新北", "桃园"]
}

View File

@ -1,67 +1,88 @@
from datetime import datetime
import aiohttp
from utils.user_agent import get_user_agent from utils.user_agent import get_user_agent
import json
import os
from configs.path_config import TXT_PATH from configs.path_config import TXT_PATH
from utils.utils import get_local_proxy from typing import List
from pathlib import Path
import ujson as json
import aiohttp
china_city = Path(TXT_PATH) / "china_city.json"
try:
with open(china_city, "r", encoding="utf8") as f:
data = json.load(f)
except FileNotFoundError:
data = {}
url = "https://api.yimian.xyz/coro/" url = "https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5"
async def get_yiqing_data(province, city_=""): async def get_yiqing_data(area: str):
if not os.path.exists(TXT_PATH + "yiqing/"): global data
os.mkdir(TXT_PATH + "yiqing/") province = None
if not os.path.exists(TXT_PATH + "yiqing/" + str(datetime.now().date()) + ".json"): city = None
async with aiohttp.ClientSession(headers=get_user_agent()) as session: province_type = ""
async with session.get(url, proxy=get_local_proxy(), timeout=7) as response: if area == '中国':
datalist = await response.json() province = area
with open( province_type = ""
TXT_PATH + "yiqing/" + str(datetime.now().date()) + ".json", "w" elif area in data.keys():
) as f: province = area
json.dump(datalist, f) if len(data[area]) == 1:
datalist = json.load( province_type = ""
open(TXT_PATH + "yiqing/" + str(datetime.now().date()) + ".json", "r") city = ""
) else:
result = "" for p in data.keys():
for data in datalist: if area in data[p]:
if data["provinceShortName"] == province: province = p
if city_ == "": city = area
result = ( if not province and not city:
province return "小真寻只支持国内的疫情查询喔..."
+ "疫情数据:\n现存确诊: " async with aiohttp.ClientSession(headers=get_user_agent()) as session:
+ str(data["currentConfirmedCount"]) async with session.get(url, timeout=7) as response:
+ "\n累计确诊: " epidemic_data = json.loads((await response.json())["data"])
+ str(data["confirmedCount"]) last_update_time = epidemic_data["lastUpdateTime"]
+ "\n治愈: " if area == "中国":
+ str(data["curedCount"]) data_ = epidemic_data["areaTree"][0]
+ "\n死亡: "
+ str(data["deadCount"])
)
break
else: else:
for city in data["cities"]: data_ = [
if city["cityName"] == city_: x
result = ( for x in epidemic_data["areaTree"][0]["children"]
city_ if x["name"] == province
+ "疫情数据:\n现存确诊: " ][0]
+ str(city["currentConfirmedCount"]) if city:
+ "\n累计确诊: " try:
+ str(city["confirmedCount"]) data_ = [x for x in data_["children"] if x["name"] == city][0]
+ "\n治愈: " except IndexError:
+ str(city["curedCount"]) return '未查询到...'
+ "\n死亡: " confirm = data_["total"]["confirm"] # 累计确诊
+ str(city["deadCount"]) heal = data_["total"]["heal"] # 累计治愈
) dead = data_["total"]["dead"] # 累计死亡
break dead_rate = data_["total"]["deadRate"] # 死亡率
return result heal_rate = data_["total"]["healRate"] # 治愈率
now_confirm = data_["total"]["nowConfirm"] # 目前确诊
suspect = data_["total"]["suspect"] # 疑似
add_confirm = data_["today"]["confirm"] # 新增确诊
x = f"{city}" if city else f'{province}{province_type}'
return (
f"{x} 疫情数据:\n"
f"\t目前确诊:\n"
f"\t\t确诊人数:{now_confirm}(+{add_confirm})\n"
f"\t\t疑似人数:{suspect}\n"
f"==================\n"
f"\t累计数据:\n"
f"\t\t确诊人数:{confirm}\n"
f"\t\t治愈人数:{heal}\n"
f"\t\t死亡人数:{dead}\n"
f"\t治愈率:{heal_rate}%\n"
f"\t死亡率:{dead_rate}%\n"
f"更新日期:{last_update_time}"
)
def clear_data(): def get_city_list() -> List[str]:
for file in os.listdir(TXT_PATH + "yiqing/"): global data
os.remove(TXT_PATH + "yiqing/" + file) city_list = []
for p in data.keys():
for c in data[p]:
if __name__ == "__main__": city_list.append(c)
print(get_yiqing_data("浙江", city_="")) return city_list

View File

@ -285,7 +285,8 @@ class CreateImg:
""" """
说明 说明
检查文本所需宽度是否大于图片宽度 检查文本所需宽度是否大于图片宽度
:param word: 文本内容 参数
:param word: 文本内容
""" """
return self.ttfont.getsize(word)[0] > self.w return self.ttfont.getsize(word)[0] > self.w