From 7dd68cf1ef13740ba022f2d1405ed475a20894a1 Mon Sep 17 00:00:00 2001 From: HibiKier <775757368@qq.com> Date: Sat, 19 Feb 2022 18:20:19 +0800 Subject: [PATCH] fit nonebot.beta2 --- README.md | 17 +- __version__ | 2 +- .../{data_source.py => _data_source.py} | 638 ++--- .../admin_bot_manage/admin_config.py | 5 +- .../custom_welcome_message.py | 20 +- basic_plugins/admin_bot_manage/rule.py | 9 +- basic_plugins/admin_bot_manage/switch_rule.py | 35 +- basic_plugins/admin_bot_manage/timing_task.py | 2 +- .../update_group_member_info.py | 9 +- basic_plugins/admin_help/__init__.py | 2 +- basic_plugins/admin_help/data_source.py | 11 +- basic_plugins/apscheduler/__init__.py | 28 +- basic_plugins/ban/__init__.py | 145 +- basic_plugins/ban/data_source.py | 69 + basic_plugins/broadcast/__init__.py | 22 +- basic_plugins/group_handle/__init__.py | 55 +- basic_plugins/help/__init__.py | 18 +- basic_plugins/help/data_source.py | 18 +- basic_plugins/hooks/{utils.py => _utils.py} | 96 +- basic_plugins/hooks/auth_hook.py | 16 +- basic_plugins/hooks/ban_hook.py | 6 +- basic_plugins/hooks/chkdsk_hook.py | 4 +- basic_plugins/hooks/other_hook.py | 7 +- basic_plugins/hooks/task_hook.py | 24 + basic_plugins/hooks/withdraw_message_hook.py | 4 +- basic_plugins/init_plugin_config/__init__.py | 4 +- .../init_plugin_config/check_plugin_status.py | 2 +- .../init_plugin_config/init_plugins_config.py | 25 +- .../init_plugin_config/init_plugins_data.py | 40 +- .../init_plugin_config/init_plugins_limit.py | 24 +- .../init_plugins_resources.py | 10 +- .../init_plugins_settings.py | 30 +- basic_plugins/invite_manager/__init__.py | 10 +- basic_plugins/nickname.py | 19 +- basic_plugins/scripts.py | 9 +- basic_plugins/shop/buy.py | 14 +- basic_plugins/shop/gold.py | 14 +- basic_plugins/shop/my_props.py | 7 +- basic_plugins/shop/shop_handle/__init__.py | 22 +- basic_plugins/shop/use/__init__.py | 14 +- basic_plugins/shop/use/data_source.py | 4 +- basic_plugins/super_cmd/bot_friend_group.py | 45 +- basic_plugins/super_cmd/clear_data.py | 19 +- basic_plugins/super_cmd/data_source.py | 74 - basic_plugins/super_cmd/exec_sql.py | 9 +- basic_plugins/super_cmd/manager_group.py | 42 +- basic_plugins/super_cmd/reload_setting.py | 4 +- .../super_cmd/set_admin_permissions.py | 14 +- basic_plugins/super_cmd/super_task_switch.py | 14 +- .../super_cmd/update_friend_group_info.py | 6 +- basic_plugins/super_help/__init__.py | 7 +- basic_plugins/super_help/data_source.py | 11 +- basic_plugins/update_info.py | 4 +- bot.py | 5 +- configs/path_config.py | 46 +- configs/utils/__init__.py | 14 + plugins/about.py | 4 +- plugins/aconfig/__init__.py | 19 +- plugins/ai/__init__.py | 15 +- plugins/ai/data_source.py | 8 +- .../alapi/{data_source.py => _data_source.py} | 98 +- plugins/alapi/comments_163.py | 13 +- plugins/alapi/cover.py | 11 +- plugins/alapi/jitang.py | 13 +- plugins/alapi/poetry.py | 7 +- plugins/alapi/wbtop.py | 13 +- plugins/bilibili_sub/__init__.py | 31 +- plugins/bilibili_sub/data_source.py | 3 +- plugins/bilibili_sub/utils.py | 3 +- plugins/bt/__init__.py | 63 +- plugins/bt/data_source.py | 6 +- plugins/c_song/__init__.py | 7 +- plugins/check/__init__.py | 4 +- plugins/check/data_source.py | 3 +- plugins/check_zhenxun_update/__init__.py | 11 +- plugins/check_zhenxun_update/data_source.py | 2 +- plugins/coser/__init__.py | 10 +- plugins/dialogue/__init__.py | 39 +- plugins/draw_card/__init__.py | 272 +- plugins/draw_card/announcement.py | 139 +- plugins/draw_card/async_update_game_info.py | 39 +- plugins/draw_card/azur_handle.py | 25 +- plugins/draw_card/config.py | 494 +--- plugins/draw_card/count_manager.py | 113 + plugins/draw_card/fgo_handle.py | 37 +- plugins/draw_card/genshin_handle.py | 208 +- plugins/draw_card/guardian_handle.py | 33 +- plugins/draw_card/init_card_pool.py | 179 +- plugins/draw_card/onmyoji_handle.py | 13 +- plugins/draw_card/pcr_handle.py | 20 +- plugins/draw_card/pretty_handle.py | 25 +- plugins/draw_card/prts_handle.py | 22 +- plugins/draw_card/rule.py | 46 +- plugins/draw_card/update_game_info.py | 72 +- .../draw_card/update_game_requests_info.py | 187 +- plugins/draw_card/update_game_simple_info.py | 223 +- plugins/draw_card/util.py | 273 +- plugins/epic/__init__.py | 6 +- plugins/fake_msg.py | 10 +- plugins/fudu.py | 25 +- plugins/genshin/almanac/__init__.py | 10 +- plugins/genshin/almanac/data_source.py | 2 +- plugins/genshin/material_remind/__init__.py | 32 +- .../genshin/query_resource_points/__init__.py | 20 +- plugins/genshin/query_resource_points/map.py | 9 +- .../query_resource_points/query_resource.py | 19 +- .../{models => _models}/__init__.py | 30 + .../query_user/{utils => _utils}/__init__.py | 0 plugins/genshin/query_user/bind/__init__.py | 28 +- .../query_user/genshin_sign/__init__.py | 16 +- .../query_user/genshin_sign/data_source.py | 4 +- .../query_user/genshin_sign/init_task.py | 14 +- .../genshin/query_user/query_memo/__init__.py | 7 +- .../query_user/query_memo/data_source.py | 9 +- .../genshin/query_user/query_role/__init__.py | 14 +- .../query_user/query_role/data_source.py | 6 +- .../query_user/query_role/draw_image.py | 11 +- .../reset_today_query_user_data/__init__.py | 2 +- .../query_user/resin_remind/__init__.py | 49 +- .../query_user/resin_remind/init_task.py | 166 +- plugins/gold_redbag/__init__.py | 38 +- plugins/group_last_chat/__init__.py | 7 +- plugins/group_last_chat/data_source.py | 4 +- plugins/group_welcome_msg.py | 15 +- plugins/image_management/__init__.py | 2 +- .../image_management/delete_image/__init__.py | 65 +- .../image_management/move_image/__init__.py | 100 +- .../image_management/send_image/__init__.py | 51 +- plugins/image_management/send_image/rule.py | 2 +- .../image_management/upload_image/__init__.py | 125 +- .../upload_image/data_source.py | 3 +- plugins/luxun/__init__.py | 10 +- plugins/mute.py | 45 +- plugins/my_info/__init__.py | 9 +- plugins/nbnhhsh.py | 9 +- .../nonebot_plugin_picsearcher/__init__.py | 180 -- plugins/nonebot_plugin_picsearcher/ascii2d.py | 63 - plugins/nonebot_plugin_picsearcher/ex.py | 107 - .../nonebot_plugin_picsearcher/formdata.py | 27 - plugins/nonebot_plugin_picsearcher/iqdb.py | 79 - .../nonebot_plugin_picsearcher/saucenao.py | 117 - plugins/nonebot_plugin_picsearcher/trace.py | 89 - plugins/nonebot_plugin_picsearcher/yandex.py | 53 - plugins/one_friend/__init__.py | 29 +- plugins/open_cases/__init__.py | 76 +- plugins/open_cases/open_cases_c.py | 8 +- plugins/open_cases/utils.py | 42 +- plugins/parse_bilibili_json.py | 30 +- plugins/pid_search.py | 32 +- plugins/pix_gallery/__init__.py | 5 - .../{data_source.py => _data_source.py} | 792 +++--- .../pix_gallery/{model => _model}/__init__.py | 2 +- .../{model => _model}/omega_pixiv_illusts.py | 306 +-- .../pix_gallery/{model => _model}/pixiv.py | 340 +-- .../{model => _model}/pixiv_keyword_user.py | 254 +- plugins/pix_gallery/pix.py | 18 +- plugins/pix_gallery/pix_add_keyword.py | 27 +- plugins/pix_gallery/pix_pass_del_keyword.py | 30 +- plugins/pix_gallery/pix_show_info.py | 17 +- plugins/pix_gallery/pix_update.py | 24 +- plugins/pixiv_rank_search/__init__.py | 16 +- plugins/poke/__init__.py | 15 +- plugins/quotations.py | 2 +- plugins/roll.py | 11 +- plugins/russian/__init__.py | 89 +- plugins/search_anime/__init__.py | 21 +- plugins/search_buff_skin_price/__init__.py | 50 +- plugins/send_dinggong_voice/__init__.py | 6 +- plugins/send_setu_/{model.py => _model.py} | 396 +-- plugins/send_setu_/send_setu/__init__.py | 79 +- plugins/send_setu_/send_setu/data_source.py | 35 +- plugins/send_setu_/update_setu/__init__.py | 4 +- plugins/send_setu_/update_setu/data_source.py | 30 +- plugins/server_ip.py | 2 +- plugins/sign_in/__init__.py | 27 +- plugins/sign_in/config.py | 9 +- plugins/sign_in/group_user_checkin.py | 2 +- plugins/sign_in/utils.py | 2 +- plugins/statistics/__init__.py | 11 +- plugins/statistics/statistics_handle.py | 58 +- plugins/statistics/statistics_hook.py | 10 +- plugins/translate/__init__.py | 10 +- plugins/update_gocqhttp/__init__.py | 2 +- plugins/update_picture.py | 201 +- plugins/weather/__init__.py | 9 +- plugins/weather/data_source.py | 3 +- plugins/what_anime/__init__.py | 26 +- plugins/white2black_image.py | 15 +- plugins/withdraw.py | 4 +- .../{data_source.py => _data_source.py} | 0 plugins/word_bank/{rule.py => _rule.py} | 2 +- plugins/word_bank/message_handle.py | 15 +- plugins/word_bank/model.py | 2 +- plugins/word_bank/word_hanlde.py | 37 +- plugins/yiqing/__init__.py | 9 +- plugins/yiqing/data_source.py | 17 +- plugins/yiqing/other_than.py | 10 +- poetry.lock | 2202 +++++++++++++++++ pyproject.toml | 44 + requirements.txt | 75 - services/log.py | 4 +- update_info.json | 5 +- utils/browser.py | 7 +- utils/http_utils.py | 17 +- utils/image_utils.py | 410 ++- utils/manager/__init__.py | 19 +- utils/manager/group_manager.py | 3 +- utils/manager/requests_manager.py | 4 +- utils/manager/resources_manager.py | 3 +- utils/manager/withdraw_message_manager.py | 2 +- utils/message_builder.py | 38 +- utils/utils.py | 54 +- 212 files changed, 6857 insertions(+), 5615 deletions(-) rename basic_plugins/admin_bot_manage/{data_source.py => _data_source.py} (90%) mode change 100755 => 100644 create mode 100644 basic_plugins/ban/data_source.py rename basic_plugins/hooks/{utils.py => _utils.py} (92%) mode change 100755 => 100644 create mode 100644 basic_plugins/hooks/task_hook.py delete mode 100755 basic_plugins/super_cmd/data_source.py rename plugins/alapi/{data_source.py => _data_source.py} (87%) mode change 100755 => 100644 create mode 100644 plugins/draw_card/count_manager.py rename plugins/genshin/query_user/{models => _models}/__init__.py (92%) rename plugins/genshin/query_user/{utils => _utils}/__init__.py (100%) delete mode 100755 plugins/nonebot_plugin_picsearcher/__init__.py delete mode 100755 plugins/nonebot_plugin_picsearcher/ascii2d.py delete mode 100755 plugins/nonebot_plugin_picsearcher/ex.py delete mode 100755 plugins/nonebot_plugin_picsearcher/formdata.py delete mode 100755 plugins/nonebot_plugin_picsearcher/iqdb.py delete mode 100755 plugins/nonebot_plugin_picsearcher/saucenao.py delete mode 100755 plugins/nonebot_plugin_picsearcher/trace.py delete mode 100755 plugins/nonebot_plugin_picsearcher/yandex.py rename plugins/pix_gallery/{data_source.py => _data_source.py} (96%) mode change 100755 => 100644 rename plugins/pix_gallery/{model => _model}/__init__.py (50%) mode change 100755 => 100644 rename plugins/pix_gallery/{model => _model}/omega_pixiv_illusts.py (96%) mode change 100755 => 100644 rename plugins/pix_gallery/{model => _model}/pixiv.py (96%) mode change 100755 => 100644 rename plugins/pix_gallery/{model => _model}/pixiv_keyword_user.py (96%) mode change 100755 => 100644 rename plugins/send_setu_/{model.py => _model.py} (96%) mode change 100755 => 100644 rename plugins/word_bank/{data_source.py => _data_source.py} (100%) rename plugins/word_bank/{rule.py => _rule.py} (83%) create mode 100644 poetry.lock create mode 100644 pyproject.toml delete mode 100644 requirements.txt diff --git a/README.md b/README.md index 326a1a53..f09a15e9 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,6 @@ ## 声明 此项目仅用于学习交流,请勿用于非法用途 -## Gitee同步 -# [Gitee](https://gitee.com/two_Dimension/zhenxun_bot) - ## 未完成的文档 # [传送门](https://hibikier.github.io/zhenxun_bot/) @@ -36,7 +33,7 @@ [AkashiCoin/nonebot_plugins_zhenxun_bot](https://github.com/AkashiCoin/nonebot_plugins_zhenxun_bot) ## 来点优点? -一.作为bot: + * 实现了许多功能,且提供了大量功能管理命令 * 通过Config配置项将所有插件配置统计保存至config.yaml,利于统一用户修改 * 方便增删插件,原生nonebot2 matcher,不需要额外修改,仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息` @@ -233,6 +230,17 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__ ## 更新 +### 2022/2/19 \[v0.1.2] (nonebot beta2!) + +* 适配nonebot.beta2 +* 删除图片搜索 nonebot_plugin_picsearcher +* 新增图片搜索 search_image +* 替换cos api +* 原神签到树脂提醒新增绑定群里,在某群绑定uid就会在某群发送提醒信息(有好友则私聊,需要重新绑定uid +* 优化BuildImage.circle()锯齿问题 [@pull/109](https://github.com/HibiKier/zhenxun_bot/pull/109) +* epic restful 替换 [@pull/119](https://github.com/HibiKier/zhenxun_bot/pull/119) +* fix: 修复远古时期残留的epic推送问题 [@pull/122](https://github.com/HibiKier/zhenxun_bot/pull/122) + ### 2021/2/11 * 修复pix不使用反代无法下载图片 @@ -326,7 +334,6 @@ __..... 更多更新信息请查看文档__ ## Todo -- [ ] docker容器 - [ ] web管理 ## 感谢 diff --git a/__version__ b/__version__ index 38a0893e..33872297 100644 --- a/__version__ +++ b/__version__ @@ -1 +1 @@ -__version__: v0.1.1 \ No newline at end of file +__version__: v0.1.2 \ No newline at end of file diff --git a/basic_plugins/admin_bot_manage/data_source.py b/basic_plugins/admin_bot_manage/_data_source.py old mode 100755 new mode 100644 similarity index 90% rename from basic_plugins/admin_bot_manage/data_source.py rename to basic_plugins/admin_bot_manage/_data_source.py index 6d32cebc..3ddb2dff --- a/basic_plugins/admin_bot_manage/data_source.py +++ b/basic_plugins/admin_bot_manage/_data_source.py @@ -1,319 +1,319 @@ -from typing import List -from nonebot.adapters.cqhttp.message import MessageSegment -from services.log import logger -from configs.path_config import DATA_PATH -from utils.message_builder import image -from utils.utils import get_local_proxy, get_bot -from pathlib import Path -from models.group_member_info import GroupInfoUser -from datetime import datetime -from services.db_context import db -from models.level_user import LevelUser -from configs.config import Config -from utils.manager import group_manager, plugins2settings_manager, plugins_manager -from utils.image_utils import BuildImage -from utils.http_utils import AsyncHttpx -import asyncio -import time -import os - -try: - import ujson as json -except ModuleNotFoundError: - import json - - -async def group_current_status(group_id: int) -> str: - """ - 获取当前所有通知的开关 - :param group_id: 群号 - """ - rst = "[被动技能 状态]\n" - _data = group_manager.get_task_data() - for task in _data.keys(): - rst += f'{_data[task]}: {"√" if await group_manager.check_group_task_status(group_id, task) else "×"}\n' - return rst.strip() - - -custom_welcome_msg_json = ( - Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json" -) - - -async def custom_group_welcome( - msg: str, imgs: List[str], user_id: int, group_id: int -) -> str: - """ - 替换群欢迎消息 - :param msg: 欢迎消息文本 - :param imgs: 欢迎消息图片,只取第一张 - :param user_id: 用户id,用于log记录 - :param group_id: 群号 - """ - img_result = "" - img = imgs[0] if imgs else "" - result = "" - if os.path.exists(DATA_PATH + f"custom_welcome_msg/{group_id}.jpg"): - os.remove(DATA_PATH + f"custom_welcome_msg/{group_id}.jpg") - if not custom_welcome_msg_json.exists(): - custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True) - data = {} - else: - try: - data = json.load(open(custom_welcome_msg_json, "r")) - except FileNotFoundError: - data = {} - try: - if msg: - data[str(group_id)] = str(msg) - json.dump( - data, open(custom_welcome_msg_json, "w"), indent=4, ensure_ascii=False - ) - logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}") - result += msg - if img: - await AsyncHttpx.download_file( - img, DATA_PATH + f"custom_welcome_msg/{group_id}.jpg" - ) - img_result = image(abspath=DATA_PATH + f"custom_welcome_msg/{group_id}.jpg") - logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息图片") - except Exception as e: - logger.error(f"GROUP {group_id} 替换群消息失败 e:{e}") - return "替换群消息失败.." - return f"替换群欢迎消息成功:\n{result}" + img_result - - -task_data = None - - -async def change_group_switch(cmd: str, group_id: int, is_super: bool = False): - global task_data - """ - 修改群功能状态 - :param cmd: 功能名称 - :param group_id: 群号 - :param is_super: 是否位超级用户,超级用户用于私聊开关功能状态 - """ - if not task_data: - task_data = group_manager.get_task_data() - group_help_file = Path(DATA_PATH) / "group_help" / f"{group_id}.png" - status = cmd[:2] - cmd = cmd[2:] - type_ = "plugin" - modules = plugins2settings_manager.get_plugin_module(cmd, True) - if cmd == "全部被动": - for task in task_data: - if status == "开启": - if not await group_manager.check_group_task_status(group_id, task): - await group_manager.open_group_task(group_id, task) - else: - if await group_manager.check_group_task_status(group_id, task): - await group_manager.close_group_task(group_id, task) - if group_help_file.exists(): - group_help_file.unlink() - return f"已 {status} 全部被动技能!" - if cmd == "全部功能": - for f in plugins2settings_manager.get_data(): - if status == "开启": - group_manager.unblock_plugin(f, group_id) - else: - group_manager.block_plugin(f, group_id) - return f"已 {status} 全部功能!" - if cmd in [task_data[x] for x in task_data.keys()]: - type_ = "task" - modules = [x for x in task_data.keys() if task_data[x] == cmd] - for module in modules: - if is_super: - module = f"{module}:super" - if status == "开启": - if type_ == "task": - if await group_manager.check_group_task_status(group_id, module): - return f"被动 {task_data[module]} 正处于开启状态!不要重复开启." - await group_manager.open_group_task(group_id, module) - else: - if group_manager.get_plugin_status(module, group_id): - return f"功能 {cmd} 正处于开启状态!不要重复开启." - group_manager.unblock_plugin(module, group_id) - else: - if type_ == "task": - if not await group_manager.check_group_task_status(group_id, module): - return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭." - await group_manager.close_group_task(group_id, module) - else: - if not group_manager.get_plugin_status(module, group_id): - return f"功能 {cmd} 正处于关闭状态!不要重复关闭." - group_manager.block_plugin(module, group_id) - if group_help_file.exists(): - group_help_file.unlink() - if is_super: - for file in os.listdir(Path(DATA_PATH) / "group_help"): - file = Path(DATA_PATH) / "group_help" / file - file.unlink() - else: - _help_image = Path(DATA_PATH) / "group_help" / f"{group_id}.png" - if _help_image.exists(): - _help_image.unlink() - return f"{status} {cmd} 功能!" - - -def set_plugin_status(cmd: str, block_type: str = "all"): - """ - 设置插件功能状态(超级用户使用) - :param cmd: 功能名称 - :param block_type: 限制类型, 'all': 私聊+群里, 'private': 私聊, 'group': 群聊 - """ - status = cmd[:2] - cmd = cmd[2:] - module = plugins2settings_manager.get_plugin_module(cmd) - if status == "开启": - plugins_manager.unblock_plugin(module) - else: - plugins_manager.block_plugin(module, block_type=block_type) - for file in os.listdir(Path(DATA_PATH) / "group_help"): - file = Path(DATA_PATH) / "group_help" / file - file.unlink() - - -async def get_plugin_status(): - """ - 获取功能状态 - """ - return await asyncio.get_event_loop().run_in_executor(None, _get_plugin_status) - - -def _get_plugin_status() -> MessageSegment: - """ - 合成功能状态图片 - """ - rst = "\t功能\n" - flag_str = "状态".rjust(4) + "\n" - for module in plugins_manager.get_data(): - flag = plugins_manager.get_plugin_block_type(module) - flag = flag.upper() + " CLOSE" if flag else "OPEN" - try: - plugin_name = plugins_manager.get(module)["plugin_name"] - if ( - "[Hidden]" in plugin_name - or "[Admin]" in plugin_name - or "[Superuser]" in plugin_name - ): - continue - rst += f"{plugin_name}" - except KeyError: - rst += f"{module}" - if plugins_manager.get(module)["error"]: - rst += "[ERROR]" - rst += "\n" - flag_str += f"{flag}\n" - height = len(rst.split("\n")) * 24 - a = BuildImage(250, height, font_size=20) - a.text((10, 10), rst) - b = BuildImage(200, height, font_size=20) - b.text((10, 10), flag_str) - A = BuildImage(500, height) - A.paste(a) - A.paste(b, (270, 0)) - return image(b64=A.pic2bs4()) - - -async def update_member_info(group_id: int, remind_superuser: bool = False) -> bool: - """ - 更新群成员信息 - :param group_id: 群号 - :param remind_superuser: 失败信息提醒超级用户 - """ - bot = get_bot() - _group_user_list = await bot.get_group_member_list(group_id=group_id) - _error_member_list = [] - _exist_member_list = [] - # try: - for user_info in _group_user_list: - if user_info["card"] == "": - nickname = user_info["nickname"] - else: - nickname = user_info["card"] - async with db.transaction(): - # 更新权限 - if ( - user_info["role"] - in [ - "owner", - "admin", - ] - and not await LevelUser.is_group_flag(user_info["user_id"], group_id) - ): - await LevelUser.set_level( - user_info["user_id"], - user_info["group_id"], - Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"), - ) - if str(user_info["user_id"]) in bot.config.superusers: - await LevelUser.set_level( - user_info["user_id"], user_info["group_id"], 9 - ) - user = await GroupInfoUser.get_member_info( - user_info["user_id"], user_info["group_id"] - ) - if user: - if user.user_name != nickname: - await user.update(user_name=nickname).apply() - logger.info( - f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新群昵称成功" - ) - _exist_member_list.append(int(user_info["user_id"])) - continue - join_time = datetime.strptime( - time.strftime( - "%Y-%m-%d %H:%M:%S", time.localtime(user_info["join_time"]) - ), - "%Y-%m-%d %H:%M:%S", - ) - if await GroupInfoUser.add_member_info( - user_info["user_id"], - user_info["group_id"], - nickname, - join_time, - ): - _exist_member_list.append(int(user_info["user_id"])) - logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功") - else: - _error_member_list.append( - f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败\n" - ) - _del_member_list = list( - set(_exist_member_list).difference( - set(await GroupInfoUser.get_group_member_id_list(group_id)) - ) - ) - if _del_member_list: - for del_user in _del_member_list: - if await GroupInfoUser.delete_member_info(del_user, group_id): - logger.info(f"退群用户{del_user} 所属{group_id} 已删除") - else: - logger.info(f"退群用户{del_user} 所属{group_id} 删除失败") - if _error_member_list and remind_superuser: - result = "" - for error_user in _error_member_list: - result += error_user - await bot.send_private_msg( - user_id=int(list(bot.config.superusers)[0]), message=result[:-1] - ) - return True - - -def set_group_bot_status(group_id: int, status: bool) -> str: - """ - 设置群聊bot开关状态 - :param group_id: 群号 - :param status: 状态 - """ - if status: - if group_manager.check_group_bot_status(group_id): - return "我还醒着呢!" - group_manager.turn_on_group_bot_status(group_id) - return "呜..醒来了..." - else: - group_manager.shutdown_group_bot_status(group_id) - # for x in group_manager.get_task_data(): - # group_manager.close_group_task(group_id, x) - return "那我先睡觉了..." +from typing import List +from nonebot.adapters.onebot.v11.message import MessageSegment +from services.log import logger +from configs.path_config import DATA_PATH +from utils.message_builder import image +from utils.utils import get_bot +from pathlib import Path +from models.group_member_info import GroupInfoUser +from datetime import datetime +from services.db_context import db +from models.level_user import LevelUser +from configs.config import Config +from utils.manager import group_manager, plugins2settings_manager, plugins_manager +from utils.image_utils import BuildImage +from utils.http_utils import AsyncHttpx +import asyncio +import time +import os + +try: + import ujson as json +except ModuleNotFoundError: + import json + + +async def group_current_status(group_id: int) -> str: + """ + 获取当前所有通知的开关 + :param group_id: 群号 + """ + rst = "[被动技能 状态]\n" + _data = group_manager.get_task_data() + for task in _data.keys(): + rst += f'{_data[task]}: {"√" if await group_manager.check_group_task_status(group_id, task) else "×"}\n' + return rst.strip() + + +custom_welcome_msg_json = ( + Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json" +) + + +async def custom_group_welcome( + msg: str, imgs: List[str], user_id: int, group_id: int +) -> str: + """ + 替换群欢迎消息 + :param msg: 欢迎消息文本 + :param imgs: 欢迎消息图片,只取第一张 + :param user_id: 用户id,用于log记录 + :param group_id: 群号 + """ + img_result = "" + img = imgs[0] if imgs else "" + result = "" + if (DATA_PATH / f"custom_welcome_msg/{group_id}.jpg").exists(): + (DATA_PATH / f"custom_welcome_msg/{group_id}.jpg").unlink() + if not custom_welcome_msg_json.exists(): + custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True) + data = {} + else: + try: + data = json.load(open(custom_welcome_msg_json, "r")) + except FileNotFoundError: + data = {} + try: + if msg: + data[str(group_id)] = str(msg) + json.dump( + data, open(custom_welcome_msg_json, "w"), indent=4, ensure_ascii=False + ) + logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}") + result += msg + if img: + await AsyncHttpx.download_file( + img, DATA_PATH / "custom_welcome_msg" / f"{group_id}.jpg" + ) + img_result = image(abspath=DATA_PATH / "custom_welcome_msg" / f"{group_id}.jpg") + logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息图片") + except Exception as e: + logger.error(f"GROUP {group_id} 替换群消息失败 e:{e}") + return "替换群消息失败.." + return f"替换群欢迎消息成功:\n{result}" + img_result + + +task_data = None + + +async def change_group_switch(cmd: str, group_id: int, is_super: bool = False): + global task_data + """ + 修改群功能状态 + :param cmd: 功能名称 + :param group_id: 群号 + :param is_super: 是否位超级用户,超级用户用于私聊开关功能状态 + """ + if not task_data: + task_data = group_manager.get_task_data() + group_help_file = DATA_PATH / "group_help" / f"{group_id}.png" + status = cmd[:2] + cmd = cmd[2:] + type_ = "plugin" + modules = plugins2settings_manager.get_plugin_module(cmd, True) + if cmd == "全部被动": + for task in task_data: + if status == "开启": + if not await group_manager.check_group_task_status(group_id, task): + await group_manager.open_group_task(group_id, task) + else: + if await group_manager.check_group_task_status(group_id, task): + await group_manager.close_group_task(group_id, task) + if group_help_file.exists(): + group_help_file.unlink() + return f"已 {status} 全部被动技能!" + if cmd == "全部功能": + for f in plugins2settings_manager.get_data(): + if status == "开启": + group_manager.unblock_plugin(f, group_id) + else: + group_manager.block_plugin(f, group_id) + return f"已 {status} 全部功能!" + if cmd in [task_data[x] for x in task_data.keys()]: + type_ = "task" + modules = [x for x in task_data.keys() if task_data[x] == cmd] + for module in modules: + if is_super: + module = f"{module}:super" + if status == "开启": + if type_ == "task": + if await group_manager.check_group_task_status(group_id, module): + return f"被动 {task_data[module]} 正处于开启状态!不要重复开启." + await group_manager.open_group_task(group_id, module) + else: + if group_manager.get_plugin_status(module, group_id): + return f"功能 {cmd} 正处于开启状态!不要重复开启." + group_manager.unblock_plugin(module, group_id) + else: + if type_ == "task": + if not await group_manager.check_group_task_status(group_id, module): + return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭." + await group_manager.close_group_task(group_id, module) + else: + if not group_manager.get_plugin_status(module, group_id): + return f"功能 {cmd} 正处于关闭状态!不要重复关闭." + group_manager.block_plugin(module, group_id) + if group_help_file.exists(): + group_help_file.unlink() + if is_super: + for file in os.listdir(DATA_PATH / "group_help"): + file = DATA_PATH / "group_help" / file + file.unlink() + else: + _help_image = DATA_PATH / "group_help" / f"{group_id}.png" + if _help_image.exists(): + _help_image.unlink() + return f"{status} {cmd} 功能!" + + +def set_plugin_status(cmd: str, block_type: str = "all"): + """ + 设置插件功能状态(超级用户使用) + :param cmd: 功能名称 + :param block_type: 限制类型, 'all': 私聊+群里, 'private': 私聊, 'group': 群聊 + """ + status = cmd[:2] + cmd = cmd[2:] + module = plugins2settings_manager.get_plugin_module(cmd) + if status == "开启": + plugins_manager.unblock_plugin(module) + else: + plugins_manager.block_plugin(module, block_type=block_type) + for file in os.listdir(DATA_PATH / "group_help"): + file = DATA_PATH / "group_help" / file + file.unlink() + + +async def get_plugin_status(): + """ + 获取功能状态 + """ + return await asyncio.get_event_loop().run_in_executor(None, _get_plugin_status) + + +def _get_plugin_status() -> MessageSegment: + """ + 合成功能状态图片 + """ + rst = "\t功能\n" + flag_str = "状态".rjust(4) + "\n" + for module in plugins_manager.get_data(): + flag = plugins_manager.get_plugin_block_type(module) + flag = flag.upper() + " CLOSE" if flag else "OPEN" + try: + plugin_name = plugins_manager.get(module)["plugin_name"] + if ( + "[Hidden]" in plugin_name + or "[Admin]" in plugin_name + or "[Superuser]" in plugin_name + ): + continue + rst += f"{plugin_name}" + except KeyError: + rst += f"{module}" + if plugins_manager.get(module)["error"]: + rst += "[ERROR]" + rst += "\n" + flag_str += f"{flag}\n" + height = len(rst.split("\n")) * 24 + a = BuildImage(250, height, font_size=20) + a.text((10, 10), rst) + b = BuildImage(200, height, font_size=20) + b.text((10, 10), flag_str) + A = BuildImage(500, height) + A.paste(a) + A.paste(b, (270, 0)) + return image(b64=A.pic2bs4()) + + +async def update_member_info(group_id: int, remind_superuser: bool = False) -> bool: + """ + 更新群成员信息 + :param group_id: 群号 + :param remind_superuser: 失败信息提醒超级用户 + """ + bot = get_bot() + _group_user_list = await bot.get_group_member_list(group_id=group_id) + _error_member_list = [] + _exist_member_list = [] + # try: + for user_info in _group_user_list: + if user_info["card"] == "": + nickname = user_info["nickname"] + else: + nickname = user_info["card"] + async with db.transaction(): + # 更新权限 + if ( + user_info["role"] + in [ + "owner", + "admin", + ] + and not await LevelUser.is_group_flag(user_info["user_id"], group_id) + ): + await LevelUser.set_level( + user_info["user_id"], + user_info["group_id"], + Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"), + ) + if str(user_info["user_id"]) in bot.config.superusers: + await LevelUser.set_level( + user_info["user_id"], user_info["group_id"], 9 + ) + user = await GroupInfoUser.get_member_info( + user_info["user_id"], user_info["group_id"] + ) + if user: + if user.user_name != nickname: + await user.update(user_name=nickname).apply() + logger.info( + f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新群昵称成功" + ) + _exist_member_list.append(int(user_info["user_id"])) + continue + join_time = datetime.strptime( + time.strftime( + "%Y-%m-%d %H:%M:%S", time.localtime(user_info["join_time"]) + ), + "%Y-%m-%d %H:%M:%S", + ) + if await GroupInfoUser.add_member_info( + user_info["user_id"], + user_info["group_id"], + nickname, + join_time, + ): + _exist_member_list.append(int(user_info["user_id"])) + logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功") + else: + _error_member_list.append( + f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败\n" + ) + _del_member_list = list( + set(_exist_member_list).difference( + set(await GroupInfoUser.get_group_member_id_list(group_id)) + ) + ) + if _del_member_list: + for del_user in _del_member_list: + if await GroupInfoUser.delete_member_info(del_user, group_id): + logger.info(f"退群用户{del_user} 所属{group_id} 已删除") + else: + logger.info(f"退群用户{del_user} 所属{group_id} 删除失败") + if _error_member_list and remind_superuser: + result = "" + for error_user in _error_member_list: + result += error_user + await bot.send_private_msg( + user_id=int(list(bot.config.superusers)[0]), message=result[:-1] + ) + return True + + +def set_group_bot_status(group_id: int, status: bool) -> str: + """ + 设置群聊bot开关状态 + :param group_id: 群号 + :param status: 状态 + """ + if status: + if group_manager.check_group_bot_status(group_id): + return "我还醒着呢!" + group_manager.turn_on_group_bot_status(group_id) + return "呜..醒来了..." + else: + group_manager.shutdown_group_bot_status(group_id) + # for x in group_manager.get_task_data(): + # group_manager.close_group_task(group_id, x) + return "那我先睡觉了..." diff --git a/basic_plugins/admin_bot_manage/admin_config.py b/basic_plugins/admin_bot_manage/admin_config.py index b3ca2380..a1bc200a 100755 --- a/basic_plugins/admin_bot_manage/admin_config.py +++ b/basic_plugins/admin_bot_manage/admin_config.py @@ -1,7 +1,6 @@ from nonebot import on_notice from services.log import logger -from nonebot.adapters.cqhttp import Bot, GroupAdminNoticeEvent -from nonebot.typing import T_State +from nonebot.adapters.onebot.v11 import GroupAdminNoticeEvent from models.level_user import LevelUser from models.group_member_info import GroupInfoUser from configs.config import Config @@ -16,7 +15,7 @@ admin_notice = on_notice(priority=5) @admin_notice.handle() -async def _(bot: Bot, event: GroupAdminNoticeEvent, state: T_State): +async def _(event: GroupAdminNoticeEvent): try: nickname = ( await GroupInfoUser.get_member_info(event.user_id, event.group_id) diff --git a/basic_plugins/admin_bot_manage/custom_welcome_message.py b/basic_plugins/admin_bot_manage/custom_welcome_message.py index 6d50842d..5b656b5d 100755 --- a/basic_plugins/admin_bot_manage/custom_welcome_message.py +++ b/basic_plugins/admin_bot_manage/custom_welcome_message.py @@ -1,9 +1,9 @@ from nonebot import on_command -from utils.utils import get_message_text, get_message_img -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from .data_source import custom_group_welcome -from nonebot.adapters.cqhttp.permission import GROUP +from utils.utils import get_message_img +from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message +from nonebot.params import CommandArg +from ._data_source import custom_group_welcome +from nonebot.adapters.onebot.v11.permission import GROUP from configs.config import Config from services.log import logger @@ -35,14 +35,14 @@ custom_welcome = on_command( @custom_welcome.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent, arg: Message = CommandArg()): try: - msg = get_message_text(event.json()) - imgs = get_message_img(event.json()) - if not msg and not imgs: + msg = arg.extract_plain_text().strip() + img = get_message_img(event.json()) + if not msg and not img: await custom_welcome.finish(__plugin_usage__) await custom_welcome.send( - await custom_group_welcome(msg, imgs, event.user_id, event.group_id), + await custom_group_welcome(msg, img, event.user_id, event.group_id), at_sender=True, ) logger.info(f"USER {event.user_id} GROUP {event.group_id} 自定义群欢迎消息:{msg}") diff --git a/basic_plugins/admin_bot_manage/rule.py b/basic_plugins/admin_bot_manage/rule.py index 2139213d..c1b26bf2 100755 --- a/basic_plugins/admin_bot_manage/rule.py +++ b/basic_plugins/admin_bot_manage/rule.py @@ -1,5 +1,4 @@ -from nonebot.adapters.cqhttp import Bot, Event -from nonebot.typing import T_State +from nonebot.adapters.onebot.v11 import Event from utils.manager import group_manager, plugins2settings_manager from utils.utils import get_message_text from services.log import logger @@ -7,12 +6,10 @@ from services.log import logger cmd = [] -def switch_rule(bot: Bot, event: Event, state: T_State) -> bool: +def switch_rule(event: Event) -> bool: """ 检测文本是否是关闭功能命令 - :param bot: pass :param event: pass - :param state: pass """ global cmd try: @@ -34,7 +31,7 @@ def switch_rule(bot: Bot, event: Event, state: T_State) -> bool: cmd.append(f"关闭 {x}") except KeyError: pass - msg = get_message_text(event.json()).split() + msg = get_message_text(event.json()) msg = msg[0] if msg else "" return msg in cmd except Exception as e: diff --git a/basic_plugins/admin_bot_manage/switch_rule.py b/basic_plugins/admin_bot_manage/switch_rule.py index 7c3bf3a7..b9c52a9e 100755 --- a/basic_plugins/admin_bot_manage/switch_rule.py +++ b/basic_plugins/admin_bot_manage/switch_rule.py @@ -1,7 +1,8 @@ +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent, GROUP, Message from nonebot import on_command, on_message, on_regex from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent, GROUP -from .data_source import ( +from nonebot.params import CommandArg +from ._data_source import ( change_group_switch, set_plugin_status, get_plugin_status, @@ -13,7 +14,6 @@ from configs.config import NICKNAME, Config from utils.utils import get_message_text, is_number from nonebot.permission import SUPERUSER from .rule import switch_rule -import re __zx_plugin_name__ = "群功能开关 [Admin]" @@ -65,19 +65,19 @@ group_status = on_regex("^(休息吧|醒来)$", permission=GROUP, priority=5, bl @switch_rule_matcher.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - _cmd = get_message_text(event.json()).split()[0] +async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): + _cmd = arg.extract_plain_text().strip().split()[0] if isinstance(event, GroupMessageEvent): await switch_rule_matcher.send(await change_group_switch(_cmd, event.group_id)) logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用群功能管理命令 {_cmd}") else: if str(event.user_id) in bot.config.superusers: - block_type = " ".join(get_message_text(event.json()).split()[1:]) + block_type = " ".join(arg.extract_plain_text().strip().split()[1:]) block_type = block_type if block_type else "a" if is_number(block_type): if not int(block_type) in [ g["group_id"] - for g in await bot.get_group_list(self_id=int(bot.self_id)) + for g in await bot.get_group_list() ]: await switch_rule_matcher.finish(f"{NICKNAME}未加入群聊:{block_type}") await change_group_switch(_cmd, int(block_type), True) @@ -104,22 +104,21 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @plugins_status.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): await plugins_status.send(await get_plugin_status()) @group_task_status.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): await group_task_status.send(await group_current_status(event.group_id)) @group_status.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - r = re.search("^(休息吧|醒来)$", get_message_text(event.json())) - if r: - if r.group(1) == "休息吧": - msg = set_group_bot_status(event.group_id, False) - else: - msg = set_group_bot_status(event.group_id, True) - await group_status.send(msg) - logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用总开关命令:{r.group(1)}") +async def _(event: GroupMessageEvent, state: T_State): + cmd = state["_matched_groups"][0] + if cmd == "休息吧": + msg = set_group_bot_status(event.group_id, False) + else: + msg = set_group_bot_status(event.group_id, True) + await group_status.send(msg) + logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用总开关命令:{cmd}") diff --git a/basic_plugins/admin_bot_manage/timing_task.py b/basic_plugins/admin_bot_manage/timing_task.py index 7761385d..840a44ad 100755 --- a/basic_plugins/admin_bot_manage/timing_task.py +++ b/basic_plugins/admin_bot_manage/timing_task.py @@ -1,5 +1,5 @@ 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 models.group_info import GroupInfo from asyncpg.exceptions import ConnectionDoesNotExistError, UndefinedColumnError diff --git a/basic_plugins/admin_bot_manage/update_group_member_info.py b/basic_plugins/admin_bot_manage/update_group_member_info.py index c7258a36..b5a71c94 100755 --- a/basic_plugins/admin_bot_manage/update_group_member_info.py +++ b/basic_plugins/admin_bot_manage/update_group_member_info.py @@ -1,7 +1,6 @@ from nonebot import on_command, on_notice -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent -from .data_source import update_member_info +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent +from ._data_source import update_member_info __zx_plugin_name__ = "更新群组成员列表 [Admin]" __plugin_usage__ = """ @@ -25,7 +24,7 @@ refresh_member_group = on_command( @refresh_member_group.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): if await update_member_info(event.group_id): await refresh_member_group.finish("更新群员信息成功!", at_sender=True) else: @@ -36,6 +35,6 @@ group_increase_handle = on_notice(priority=1, block=False) @group_increase_handle.handle() -async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict): +async def _(bot: Bot, event: GroupIncreaseNoticeEvent): if event.user_id == int(bot.self_id): await update_member_info(event.group_id) diff --git a/basic_plugins/admin_help/__init__.py b/basic_plugins/admin_help/__init__.py index 0b110162..e2f3ddd5 100755 --- a/basic_plugins/admin_help/__init__.py +++ b/basic_plugins/admin_help/__init__.py @@ -1,7 +1,7 @@ from nonebot import on_command from nonebot.typing import T_State from nonebot.adapters import Bot -from nonebot.adapters.cqhttp import GroupMessageEvent +from nonebot.adapters.onebot.v11 import GroupMessageEvent from utils.message_builder import image from .data_source import create_help_image, admin_help_image diff --git a/basic_plugins/admin_help/data_source.py b/basic_plugins/admin_help/data_source.py index 5535ae98..e17fae08 100755 --- a/basic_plugins/admin_help/data_source.py +++ b/basic_plugins/admin_help/data_source.py @@ -3,8 +3,7 @@ from configs.path_config import IMAGE_PATH from services.log import logger from utils.utils import get_matchers from utils.manager import group_manager -from nonebot.adapters.cqhttp import Bot -from pathlib import Path +from nonebot.adapters.onebot.v11 import Bot from nonebot import Driver import asyncio import nonebot @@ -12,9 +11,9 @@ import nonebot driver: Driver = nonebot.get_driver() -background = Path(IMAGE_PATH) / "background" / "0.png" +background = IMAGE_PATH / "background" / "0.png" -admin_help_image = Path(IMAGE_PATH) / 'admin_help_img.png' +admin_help_image = IMAGE_PATH / 'admin_help_img.png' @driver.on_bot_connect @@ -42,7 +41,7 @@ def _create_help_image(): width = 0 _plugin_level = {} for matcher in _matchers: - _plugin = nonebot.plugin.get_plugin(matcher.module) + _plugin = nonebot.plugin.get_plugin(matcher.plugin_name) _module = _plugin.module try: plugin_name = _module.__getattribute__("__zx_plugin_name__") @@ -71,7 +70,7 @@ def _create_help_image(): x = len(f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd)) * 23 width = width if width > x else x except AttributeError: - logger.warning(f"获取管理插件 {matcher.module}: {plugin_name} 设置失败...") + logger.warning(f"获取管理插件 {matcher.plugin_name}: {plugin_name} 设置失败...") help_str = "* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" \ "[权限等级] 管理员帮助:\n\n" x = list(_plugin_level.keys()) diff --git a/basic_plugins/apscheduler/__init__.py b/basic_plugins/apscheduler/__init__.py index 487025b6..93d34f7d 100755 --- a/basic_plugins/apscheduler/__init__.py +++ b/basic_plugins/apscheduler/__init__.py @@ -4,7 +4,7 @@ from nonebot import on_message from services.log import logger from models.group_info import GroupInfo from models.friend_user import FriendUser -from nonebot.adapters.cqhttp.exception import ActionFailed +from nonebot.adapters.onebot.v11.exception import ActionFailed from configs.config import NICKNAME, Config from utils.manager import group_manager from pathlib import Path @@ -57,12 +57,11 @@ async def _(): gl = await bot.get_group_list() gl = [g["group_id"] for g in gl] for g in gl: - if await group_manager.check_group_task_status(g, 'zwa'): - result = image("zao.jpg", "zhenxun") - try: - await bot.send_group_msg(group_id=g, message="早上好" + result) - except ActionFailed: - logger.warning(f"{g} 群被禁言中,无法发送早安") + result = image("zao.jpg", "zhenxun") + try: + await bot.send_group_msg(group_id=g, message="[[_task|zwa]]早上好" + result) + except ActionFailed: + logger.warning(f"{g} 群被禁言中,无法发送早安") except Exception as e: logger.error(f"早晚安错误 e:{e}") @@ -79,14 +78,13 @@ async def _(): gl = await bot.get_group_list() gl = [g["group_id"] for g in gl] for g in gl: - if await group_manager.check_group_task_status(g, 'zwa'): - result = image("sleep.jpg", "zhenxun") - try: - await bot.send_group_msg( - group_id=g, message=f"{NICKNAME}要睡觉了,你们也要早点睡呀" + result - ) - except ActionFailed: - logger.warning(f"{g} 群被禁言中,无法发送晚安") + result = image("sleep.jpg", "zhenxun") + try: + await bot.send_group_msg( + group_id=g, message=f"[[_task|zwa]]{NICKNAME}要睡觉了,你们也要早点睡呀" + result + ) + except ActionFailed: + logger.warning(f"{g} 群被禁言中,无法发送晚安") except Exception as e: logger.error(f"早晚安错误 e:{e}") diff --git a/basic_plugins/ban/__init__.py b/basic_plugins/ban/__init__.py index a9f6f567..2a28e3bb 100755 --- a/basic_plugins/ban/__init__.py +++ b/basic_plugins/ban/__init__.py @@ -1,12 +1,13 @@ +from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent, MessageEvent, Message, Bot +from nonebot.params import CommandArg, Command from nonebot import on_command from models.ban_user import BanUser from models.level_user import LevelUser -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot -from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent, MessageEvent -from utils.utils import get_message_at, get_message_text, is_number +from typing import Tuple +from utils.utils import get_message_at, is_number from configs.config import NICKNAME, Config from nonebot.permission import SUPERUSER +from .data_source import parse_ban_time, a_ban from services.log import logger @@ -61,62 +62,35 @@ super_ban = on_command('b了', permission=SUPERUSER, priority=5, block=True) @ban.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): + cmd = cmd[0] result = "" qq = get_message_at(event.json()) if qq: qq = qq[0] user_name = await bot.get_group_member_info(group_id=event.group_id, user_id=qq) - user_name = user_name['card'] if user_name['card'] else user_name['nickname'] - msg = get_message_text(event.json()) - if msg: - msg = msg.split() - if len(msg) == 2: - if not is_number(msg[0].strip()) or not is_number(msg[1].strip()): - await ban.finish("参数必须是数字!", at_sender=True) - time = int(msg[0]) * 60 * 60 + int(msg[1]) * 60 - else: - if not is_number(msg[0].strip()): - await ban.finish("参数必须是数字!", at_sender=True) - time = int(msg[0]) * 60 * 60 - else: - time = -1 - if state["_prefix"]["raw_command"] in [".ban", "/ban"]: + user_name = user_name['card'] or user_name['nickname'] + msg = arg.extract_plain_text().strip() + time = parse_ban_time(msg) + if isinstance(time, str): + await ban.finish(time, at_sender=True) + if cmd in [".ban", "/ban"]: if ( - await LevelUser.get_user_level(event.user_id, event.group_id) - <= await LevelUser.get_user_level(qq, event.group_id) - and str(event.user_id) not in bot.config.superusers + await LevelUser.get_user_level(event.user_id, event.group_id) + <= await LevelUser.get_user_level(qq, event.group_id) + and str(event.user_id) not in bot.config.superusers ): await ban.finish( f"您的权限等级比对方低或相等, {NICKNAME}不能为您使用此功能!", at_sender=True, ) - if await BanUser.ban( - qq, await LevelUser.get_user_level(event.user_id, event.group_id), time - ): - logger.info( - f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time/60} 分钟" - ) - result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!" - if time != -1: - result += f"将在 {time/60} 分钟后解封" - else: - time = await BanUser.check_ban_time(qq) - if is_number(time): - time = abs(int(time)) - if time < 60: - time = str(time) + " 秒" - else: - time = str(int(time / 60)) + " 分钟" - else: - time += " 分钟" - result = f"{user_name} 已在黑名单!预计 {time}后解封" + result = await a_ban(qq, time, user_name, event) else: if ( - await BanUser.check_ban_level( - qq, await LevelUser.get_user_level(event.user_id, event.group_id) - ) - and str(event.user_id) not in bot.config.superusers + await BanUser.check_ban_level( + qq, await LevelUser.get_user_level(event.user_id, event.group_id) + ) + and str(event.user_id) not in bot.config.superusers ): await ban.finish( f"ban掉 {user_name} 的管理员权限比您高,无法进行unban", at_sender=True @@ -130,78 +104,53 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): result = f"{user_name} 不在黑名单!" else: await ban.finish("艾特人了吗??", at_sender=True) - await ban.finish(result, at_sender=True) + await ban.send(result, at_sender=True) @ban.handle() -async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): - if str(event.user_id) in bot.config.superusers: - msg = get_message_text(event.json()) - msg = msg.split() - if is_number(msg[0]): - qq = int(msg[0]) - if state["_prefix"]["raw_command"] in [".ban", "/ban"]: - hour = 0 - minute = 0 - if len(msg) > 1 and is_number(msg[1]): - hour = int(msg[1]) - if len(msg) > 2 and is_number(msg[2]): - minute = int(msg[2]) - time = hour * 60 * 60 + minute * 60 - time = time if time else -1 - if await BanUser.ban( - qq, 9, time - ): - logger.info( - f"USER {event.user_id} 将 USER {qq} 封禁 时长 {time/60} 分钟" - ) - result = f"已经将 {qq} 加入{NICKNAME}的黑名单了!" - if time != -1: - result += f"将在 {time/60} 分钟后解封" - else: - result += f"将在 ∞ 分钟后解封" - await ban.send(result) +async def _(bot: Bot, event: PrivateMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): + cmd = cmd[0] + msg = arg.extract_plain_text().strip() + if msg: + if str(event.user_id) in bot.config.superusers: + if is_number(arg.extract_plain_text().strip().split()[0]): + qq = int(msg[0]) + msg = msg[1:] + if cmd in [".ban", "/ban"]: + time = parse_ban_time(msg) + if isinstance(time, str): + await ban.finish(time) + result = await a_ban(qq, time, str(qq), event, 9) else: - time = await BanUser.check_ban_time(qq) - if is_number(time): - time = abs(int(time)) - if time < 60: - time = str(time) + " 秒" - else: - time = str(int(time / 60)) + " 分钟" + if await BanUser.unban(qq): + logger.info( + f"USER {event.user_id} 将 USER {qq} 解禁" + ) + result = f"已经把 {qq} 从黑名单中删除了!" else: - time += " 分钟" - await ban.send(f"{qq} 已在黑名单!预计 {time}后解封") - else: - if await BanUser.unban(qq): - logger.info( - f"USER {event.user_id} 将 USER {qq} 解禁" - ) - result = f"已经把 {qq} 从黑名单中删除了!" - else: - result = f"{qq} 不在黑名单!" + result = f"{qq} 不在黑名单!" await ban.send(result) - else: - await ban.finish('qq号必须是数字!\n格式:.ban [qq] [hour]? [minute]?', at_sender=True) + else: + await ban.finish('qq号必须是数字!\n格式:.ban [qq] [hour]? [minute]?', at_sender=True) @super_ban.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): if isinstance(event, GroupMessageEvent): qq = get_message_at(event.json()) else: - qq = get_message_text(event.json()) + qq = arg.extract_plain_text().strip() if not is_number(qq): await super_ban.finish("对象qq必须为纯数字...") qq = [qq] if qq: qq = qq[0] user = await bot.get_group_member_info(group_id=event.group_id, user_id=qq) - user_name = user['card'] if user['card'] else user['nickname'] + user_name = user['card'] or user['nickname'] if not await BanUser.ban(qq, 10, 99999999): await BanUser.unban(qq) await BanUser.ban(qq, 10, 99999999) await ban.send(f"已将 {user_name} 拉入黑名单!") else: - await super_ban.send('需要艾特被super ban的对象..') + await super_ban.send('需要添加被super ban的对象,可以使用at或者指定qq..') diff --git a/basic_plugins/ban/data_source.py b/basic_plugins/ban/data_source.py new file mode 100644 index 00000000..17efa578 --- /dev/null +++ b/basic_plugins/ban/data_source.py @@ -0,0 +1,69 @@ +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent +from configs.config import NICKNAME +from models.level_user import LevelUser +from utils.utils import is_number +from models.ban_user import BanUser +from services.log import logger +from typing import Union + + +def parse_ban_time(msg: str) -> Union[int, str]: + """ + 解析ban时长 + :param msg: 文本消息 + """ + if not msg: + return -1 + msg = msg.split() + if len(msg) == 1: + if not is_number(msg[0].strip()): + return "参数必须是数字!" + return int(msg[0]) * 60 * 60 + else: + if not is_number(msg[0].strip()) or not is_number(msg[1].strip()): + return "参数必须是数字!" + return int(msg[0]) * 60 * 60 + int(msg[1]) * 60 + + +async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_level: int = None) -> str: + """ + ban + :param qq: qq + :param time: ban时长 + :param user_name: ban用户昵称 + :param event: event + :param ban_level: ban级别 + """ + if isinstance(event, GroupMessageEvent): + ban_level = await LevelUser.get_user_level(event.user_id, event.group_id) + if await BanUser.ban(qq, ban_level, time): + logger.info( + f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time / 60} 分钟" + ) + result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!" + if time != -1: + result += f"将在 {time / 60} 分钟后解封" + else: + result += f"将在 ∞ 分钟后解封" + else: + time = await BanUser.check_ban_time(qq) + if is_number(time): + time = abs(int(time)) + if time < 60: + time = str(time) + " 秒" + else: + time = str(int(time / 60)) + " 分钟" + else: + time += " 分钟" + result = f"{user_name} 已在黑名单!预计 {time}后解封" + return result + + + + + + + + + + diff --git a/basic_plugins/broadcast/__init__.py b/basic_plugins/broadcast/__init__.py index 1d5b3d3c..0ff5666d 100755 --- a/basic_plugins/broadcast/__init__.py +++ b/basic_plugins/broadcast/__init__.py @@ -1,13 +1,14 @@ +from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent from nonebot import on_command -from nonebot.typing import T_State -from nonebot.adapters import Bot, Event from nonebot.permission import SUPERUSER -import asyncio -from utils.utils import get_message_text, get_message_img +from nonebot.params import CommandArg +from utils.utils import get_message_img from services.log import logger from utils.message_builder import image from utils.manager import group_manager from configs.config import Config +import asyncio + __zx_plugin_name__ = "广播 [Superuser]" __plugin_usage__ = """ @@ -33,14 +34,13 @@ broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True) @broadcast.handle() -async def _(bot: Bot, event: Event, state: T_State): - msg = get_message_text(event.json()) - imgs = get_message_img(event.json()) +async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() + img_list = get_message_img(event.json()) rst = "" - for img in imgs: + for img in img_list: rst += image(img) - sid = bot.self_id - gl = await bot.get_group_list(self_id=sid) + gl = await bot.get_group_list() gl = [ g["group_id"] for g in gl @@ -56,7 +56,7 @@ async def _(bot: Bot, event: Event, state: T_State): await broadcast.send(f"已播报至 {int(cnt / g_cnt * 100)}% 的群聊") x += 0.25 try: - await bot.send_group_msg(self_id=sid, group_id=g, message=msg + rst) + await bot.send_group_msg(group_id=g, message=msg + rst) logger.info(f"GROUP {g} 投递广播成功") except Exception as e: logger.error(f"GROUP {g} 投递广播失败:{type(e)}") diff --git a/basic_plugins/group_handle/__init__.py b/basic_plugins/group_handle/__init__.py index 59abf8cb..c4583aff 100755 --- a/basic_plugins/group_handle/__init__.py +++ b/basic_plugins/group_handle/__init__.py @@ -4,12 +4,12 @@ from utils.message_builder import image from models.group_member_info import GroupInfoUser from datetime import datetime from services.log import logger -from nonebot.adapters.cqhttp import ( +from nonebot.adapters.onebot.v11 import ( Bot, GroupIncreaseNoticeEvent, GroupDecreaseNoticeEvent, ) -from nonebot.adapters.cqhttp.exception import ActionFailed +from nonebot.adapters.onebot.v11.exception import ActionFailed from utils.manager import group_manager, plugins2settings_manager, requests_manager from configs.config import NICKNAME from models.group_info import GroupInfo @@ -66,7 +66,7 @@ add_group = on_request(priority=1, block=False) @group_increase_handle.handle() -async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict): +async def _(bot: Bot, event: GroupIncreaseNoticeEvent): if event.user_id == int(bot.self_id): group = await GroupInfo.get_group_info(event.group_id) # 群聊不存在或被强制拉群,退出该群 @@ -112,9 +112,7 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict): logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败") # 群欢迎消息 - if await group_manager.check_group_task_status( - event.group_id, "group_welcome" - ) and _flmt.check(event.group_id): + if _flmt.check(event.group_id): _flmt.start_cd(event.group_id) msg = "" img = "" @@ -129,23 +127,25 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict): if msg.find("[at]") != -1: msg = msg.replace("[at]", "") at_flag = True - if os.path.exists(DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"): + if (DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg").exists(): img = image( - abspath=DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg" + abspath=DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg" ) if msg or img: + msg = msg.strip() + img + msg = "\n" + msg if at_flag else msg await group_increase_handle.send( - "\n" + msg.strip() + img, at_sender=at_flag + "[[_task|group_welcome]]" + msg, at_sender=at_flag ) else: await group_increase_handle.send( - "新人快跑啊!!本群现状↓(快使用自定义!)" - + image(random.choice(os.listdir(IMAGE_PATH + "qxz/")), "qxz") + "[[_task|group_welcome]]新人快跑啊!!本群现状↓(快使用自定义!)" + + image(random.choice(os.listdir(IMAGE_PATH / "qxz")), "qxz") ) @group_decrease_handle.handle() -async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict): +async def _(bot: Bot, event: GroupDecreaseNoticeEvent): # 被踢出群 if event.sub_type == "kick_me": group_id = event.group_id @@ -180,21 +180,16 @@ async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict): logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除成功") else: logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除失败") - if await group_manager.check_group_task_status( - event.group_id, "refund_group_remind" - ): - rst = "" - if event.sub_type == "leave": - rst = f"{user_name}离开了我们..." - if event.sub_type == "kick": - operator = await bot.get_group_member_info( - user_id=event.operator_id, group_id=event.group_id - ) - operator_name = ( - operator["card"] if operator["card"] else operator["nickname"] - ) - rst = f"{user_name} 被 {operator_name} 送走了." - try: - await group_decrease_handle.send(f"{rst}") - except ActionFailed: - return + rst = "" + if event.sub_type == "leave": + rst = f"{user_name}离开了我们..." + if event.sub_type == "kick": + operator = await bot.get_group_member_info( + user_id=event.operator_id, group_id=event.group_id + ) + operator_name = operator["card"] if operator["card"] else operator["nickname"] + rst = f"{user_name} 被 {operator_name} 送走了." + try: + await group_decrease_handle.send(f"[[_task|refund_group_remind]]{rst}") + except ActionFailed: + return diff --git a/basic_plugins/help/__init__.py b/basic_plugins/help/__init__.py index b747cb05..36ba10f4 100755 --- a/basic_plugins/help/__init__.py +++ b/basic_plugins/help/__init__.py @@ -1,24 +1,24 @@ from nonebot import on_command -from nonebot.adapters.cqhttp import ( +from nonebot.adapters.onebot.v11 import ( Bot, MessageEvent, - GroupMessageEvent + GroupMessageEvent, + Message ) +from nonebot.params import CommandArg from nonebot.typing import T_State from nonebot.rule import to_me from configs.path_config import IMAGE_PATH, DATA_PATH from utils.message_builder import image from .data_source import create_help_img, get_plugin_help -from utils.utils import get_message_text -from pathlib import Path import os __zx_plugin_name__ = "帮助" -group_help_path = Path(DATA_PATH) / "group_help" -help_image = Path(IMAGE_PATH) / "help.png" -simple_help_image = Path(IMAGE_PATH) / "simple_help.png" +group_help_path = DATA_PATH / "group_help" +help_image = IMAGE_PATH / "help.png" +simple_help_image = IMAGE_PATH / "simple_help.png" if help_image.exists(): help_image.unlink() if simple_help_image.exists(): @@ -44,8 +44,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @simple_help.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(bot: Bot, event: MessageEvent, state: T_State, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() is_super = False if msg: if '-super' in msg: diff --git a/basic_plugins/help/data_source.py b/basic_plugins/help/data_source.py index fe25a262..bf178a83 100755 --- a/basic_plugins/help/data_source.py +++ b/basic_plugins/help/data_source.py @@ -16,9 +16,9 @@ import nonebot import os -random_bk_path = Path(IMAGE_PATH) / "background" / "help" / "simple_help" +random_bk_path = IMAGE_PATH / "background" / "help" / "simple_help" -background = Path(IMAGE_PATH) / "background" / "0.png" +background = IMAGE_PATH / "background" / "0.png" async def create_help_img( @@ -55,7 +55,7 @@ def _create_help_img( # 插件分类 for matcher in _matchers: plugin_name = None - _plugin = nonebot.plugin.get_plugin(matcher.module) + _plugin = nonebot.plugin.get_plugin(matcher.plugin_name) _module = _plugin.module try: plugin_name = _module.__getattribute__("__zx_plugin_name__") @@ -74,10 +74,10 @@ def _create_help_img( plugin_type = ("normal",) text_type = 0 if plugins2settings_manager.get( - matcher.module - ) and plugins2settings_manager[matcher.module].get("plugin_type"): + matcher.plugin_name + ) and plugins2settings_manager[matcher.plugin_name].get("plugin_type"): plugin_type = tuple( - plugins2settings_manager.get_plugin_data(matcher.module)[ + plugins2settings_manager.get_plugin_data(matcher.plugin_name)[ "plugin_type" ] ) @@ -111,7 +111,7 @@ def _create_help_img( logger.warning(f"{type(e)}: {e}") else: matchers_data[plugin_type][plugin_name] = { - "modules": matcher.module, + "modules": matcher.plugin_name, "des": plugin_des, "cmd": plugin_cmd, "text_type": text_type, @@ -129,7 +129,7 @@ def _create_help_img( _des_tmp[plugin_des] = plugin_name except AttributeError as e: if plugin_name not in _plugin_name_tmp: - logger.warning(f"获取功能 {matcher.module}: {plugin_name} 设置失败...e:{e}") + logger.warning(f"获取功能 {matcher.plugin_name}: {plugin_name} 设置失败...e:{e}") if plugin_name not in _plugin_name_tmp: _plugin_name_tmp.append(plugin_name) help_img_list = [] @@ -357,7 +357,7 @@ def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]: bk = BuildImage( width, height, - background=Path(IMAGE_PATH) / "background" / "1.png", + background=IMAGE_PATH / "background" / "1.png", ) A.paste(bk, alpha=True) A.text((int(width * 0.048), int(height * 0.21)), result) diff --git a/basic_plugins/hooks/utils.py b/basic_plugins/hooks/_utils.py old mode 100755 new mode 100644 similarity index 92% rename from basic_plugins/hooks/utils.py rename to basic_plugins/hooks/_utils.py index 7860b42e..55d08d08 --- a/basic_plugins/hooks/utils.py +++ b/basic_plugins/hooks/_utils.py @@ -1,48 +1,48 @@ -from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent -from utils.manager import plugins2block_manager, StaticData -import time - - -class StatusMessageManager(StaticData): - - def __init__(self): - super().__init__(None) - - def add(self, id_: int): - self._data[id_] = time.time() - - def delete(self, id_: int): - if self._data.get(id_): - del self._data[id_] - - def check(self, id_: int, t: int = 30) -> bool: - if self._data.get(id_): - if time.time() - self._data[id_] > t: - del self._data[id_] - return True - return False - return True - - -status_message_manager = StatusMessageManager() - - -def set_block_limit_false(event, module): - """ - 设置用户block为false - :param event: event - :param module: 插件模块 - """ - if plugins2block_manager.check_plugin_block_status(module): - plugin_block_data = plugins2block_manager.get_plugin_block_data(module) - check_type = plugin_block_data["check_type"] - limit_type = plugin_block_data["limit_type"] - if not ( - (isinstance(event, GroupMessageEvent) and check_type == "private") - or (isinstance(event, PrivateMessageEvent) and check_type == "group") - ): - block_type_ = event.user_id - if limit_type == "group" and isinstance(event, GroupMessageEvent): - block_type_ = event.group_id - plugins2block_manager.set_false(block_type_, module) - +from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent +from utils.manager import plugins2block_manager, StaticData +import time + + +class StatusMessageManager(StaticData): + + def __init__(self): + super().__init__(None) + + def add(self, id_: int): + self._data[id_] = time.time() + + def delete(self, id_: int): + if self._data.get(id_): + del self._data[id_] + + def check(self, id_: int, t: int = 30) -> bool: + if self._data.get(id_): + if time.time() - self._data[id_] > t: + del self._data[id_] + return True + return False + return True + + +status_message_manager = StatusMessageManager() + + +def set_block_limit_false(event, module): + """ + 设置用户block为false + :param event: event + :param module: 插件模块 + """ + if plugins2block_manager.check_plugin_block_status(module): + plugin_block_data = plugins2block_manager.get_plugin_block_data(module) + check_type = plugin_block_data["check_type"] + limit_type = plugin_block_data["limit_type"] + if not ( + (isinstance(event, GroupMessageEvent) and check_type == "private") + or (isinstance(event, PrivateMessageEvent) and check_type == "group") + ): + block_type_ = event.user_id + if limit_type == "group" and isinstance(event, GroupMessageEvent): + block_type_ = event.group_id + plugins2block_manager.set_false(block_type_, module) + diff --git a/basic_plugins/hooks/auth_hook.py b/basic_plugins/hooks/auth_hook.py index a93b0b03..5ae54682 100755 --- a/basic_plugins/hooks/auth_hook.py +++ b/basic_plugins/hooks/auth_hook.py @@ -1,6 +1,6 @@ from nonebot.matcher import Matcher from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException -from nonebot.adapters.cqhttp.exception import ActionFailed +from nonebot.adapters.onebot.v11.exception import ActionFailed from models.friend_user import FriendUser from models.group_member_info import GroupInfoUser from models.bag_user import BagUser @@ -13,10 +13,10 @@ from utils.manager import ( plugins2block_manager, plugins2count_manager ) -from .utils import set_block_limit_false, status_message_manager +from ._utils import set_block_limit_false, status_message_manager from nonebot.typing import T_State from typing import Optional -from nonebot.adapters.cqhttp import ( +from nonebot.adapters.onebot.v11 import ( Bot, MessageEvent, GroupMessageEvent, @@ -43,7 +43,7 @@ ignore_rst_module = ["ai", "poke", "dialogue"] # 权限检测 @run_preprocessor async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): - module = matcher.module + module = matcher.plugin_name plugins2info_dict = plugins2settings_manager.get_data() # 功能的金币检测 ####################################### # 功能的金币检测 ####################################### @@ -83,7 +83,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): except AttributeError: pass # 群黑名单检测 群总开关检测 - if isinstance(event, GroupMessageEvent) or matcher.module == "poke": + if isinstance(event, GroupMessageEvent) or matcher.plugin_name == "poke": try: if group_manager.get_group_level(event.group_id) < 0: raise IgnoredException("群黑名单") @@ -354,15 +354,15 @@ async def _( event: Event, state: T_State, ): - if not isinstance(event, MessageEvent) and matcher.module != "poke": + if not isinstance(event, MessageEvent) and matcher.plugin_name != "poke": return - module = matcher.module + module = matcher.plugin_name set_block_limit_false(event, module) async def init_rst(rst: str, event: MessageEvent): if "[uname]" in rst: - uname = event.sender.card if event.sender.card else event.sender.nickname + uname = event.sender.card or event.sender.nickname rst = rst.replace("[uname]", uname) if "[nickname]" in rst: if isinstance(event, GroupMessageEvent): diff --git a/basic_plugins/hooks/ban_hook.py b/basic_plugins/hooks/ban_hook.py index b3f2ac7e..757a7ed6 100755 --- a/basic_plugins/hooks/ban_hook.py +++ b/basic_plugins/hooks/ban_hook.py @@ -1,8 +1,8 @@ from nonebot.matcher import Matcher from nonebot.message import run_preprocessor, IgnoredException -from nonebot.adapters.cqhttp.exception import ActionFailed +from nonebot.adapters.onebot.v11.exception import ActionFailed from nonebot.typing import T_State -from nonebot.adapters.cqhttp import ( +from nonebot.adapters.onebot.v11 import ( Bot, MessageEvent, GroupMessageEvent, @@ -83,4 +83,4 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): ) except ActionFailed: pass - raise IgnoredException("用户处于黑名单中") \ No newline at end of file + raise IgnoredException("用户处于黑名单中") diff --git a/basic_plugins/hooks/chkdsk_hook.py b/basic_plugins/hooks/chkdsk_hook.py index e04d20c4..c530631c 100755 --- a/basic_plugins/hooks/chkdsk_hook.py +++ b/basic_plugins/hooks/chkdsk_hook.py @@ -1,8 +1,8 @@ from nonebot.matcher import Matcher from nonebot.message import run_preprocessor, IgnoredException -from nonebot.adapters.cqhttp.exception import ActionFailed +from nonebot.adapters.onebot.v11.exception import ActionFailed from nonebot.typing import T_State -from nonebot.adapters.cqhttp import ( +from nonebot.adapters.onebot.v11 import ( Bot, MessageEvent, GroupMessageEvent, diff --git a/basic_plugins/hooks/other_hook.py b/basic_plugins/hooks/other_hook.py index b2d617f5..1fccfc50 100755 --- a/basic_plugins/hooks/other_hook.py +++ b/basic_plugins/hooks/other_hook.py @@ -1,8 +1,8 @@ from nonebot.matcher import Matcher from nonebot.message import run_preprocessor, IgnoredException from nonebot.typing import T_State -from .utils import status_message_manager -from nonebot.adapters.cqhttp import ( +from ._utils import status_message_manager +from nonebot.adapters.onebot.v11 import ( Bot, MessageEvent, PrivateMessageEvent, @@ -24,7 +24,7 @@ async def _(matcher: Matcher, bot: Bot, event: PrivateMessageEvent, state: T_Sta async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): if not isinstance(event, MessageEvent): return - if matcher.type == "message" and matcher.module == "ai": + if matcher.type == "message" and matcher.plugin_name == "ai": if ( isinstance(event, GroupMessageEvent) and not status_message_manager.check(event.group_id) @@ -35,7 +35,6 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): isinstance(event, PrivateMessageEvent) and not status_message_manager.check(event.user_id) ): - print(status_message_manager) status_message_manager.delete(event.user_id) raise IgnoredException("有命令就别说话了") diff --git a/basic_plugins/hooks/task_hook.py b/basic_plugins/hooks/task_hook.py new file mode 100644 index 00000000..7f3e372f --- /dev/null +++ b/basic_plugins/hooks/task_hook.py @@ -0,0 +1,24 @@ +from nonebot.exception import MockApiException +from nonebot.adapters.onebot.v11 import Bot, MessageSegment +from utils.manager import group_manager +from utils.utils import get_message_text +from typing import Dict, Any +import re + + +@Bot.on_calling_api +async def handle_api_call(bot: Bot, api: str, data: Dict[str, Any]): + r = None + if ( + (api == "send_msg" and data["message"] == "group_id" or api == "send_group_msg") + and (r := re.search("^\[\[_task\|(.*)]]", get_message_text(data["message"]))) + and r.group(1) in group_manager.get_task_data().keys() + ): + task = r.group(1) + group_id = data["group_id"] + if not await group_manager.check_group_task_status(group_id, task): + raise MockApiException(f"被动技能 {task} 处于关闭状态...") + else: + msg = str(data["message"][0]) + msg = msg.replace(f"[[_task|{task}]]", "") + data["message"][0] = MessageSegment.text(msg) diff --git a/basic_plugins/hooks/withdraw_message_hook.py b/basic_plugins/hooks/withdraw_message_hook.py index d91ef8d3..92cbc861 100755 --- a/basic_plugins/hooks/withdraw_message_hook.py +++ b/basic_plugins/hooks/withdraw_message_hook.py @@ -2,7 +2,7 @@ from nonebot.matcher import Matcher from nonebot.message import run_postprocessor from typing import Optional from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, Event +from nonebot.adapters.onebot.v11 import Bot, Event from utils.manager import withdraw_message_manager import asyncio @@ -25,4 +25,4 @@ async def _( async def _withdraw_message(bot: Bot, id_: int, time: int): await asyncio.sleep(time) - await bot.delete_msg(message_id=id_, self_id=int(bot.self_id)) + await bot.delete_msg(message_id=id_) diff --git a/basic_plugins/init_plugin_config/__init__.py b/basic_plugins/init_plugin_config/__init__.py index 65156ada..65d9d63d 100755 --- a/basic_plugins/init_plugin_config/__init__.py +++ b/basic_plugins/init_plugin_config/__init__.py @@ -11,7 +11,7 @@ from .init_plugins_limit import ( ) from .init import init from .check_plugin_status import check_plugin_status -from nonebot.adapters.cqhttp import Bot +from nonebot.adapters.onebot.v11 import Bot from configs.path_config import DATA_PATH from services.log import logger from pathlib import Path @@ -33,7 +33,7 @@ def _(): 初始化数据 """ _flag = False - config_file = Path(DATA_PATH) / "configs" / "plugins2config.yaml" + config_file = DATA_PATH / "configs" / "plugins2config.yaml" if not config_file.exists(): _flag = True init() diff --git a/basic_plugins/init_plugin_config/check_plugin_status.py b/basic_plugins/init_plugin_config/check_plugin_status.py index c8cbee77..2163eace 100755 --- a/basic_plugins/init_plugin_config/check_plugin_status.py +++ b/basic_plugins/init_plugin_config/check_plugin_status.py @@ -1,5 +1,5 @@ from utils.manager import plugins_manager -from nonebot.adapters.cqhttp import Bot +from nonebot.adapters.onebot.v11 import Bot async def check_plugin_status(bot: Bot): diff --git a/basic_plugins/init_plugin_config/init_plugins_config.py b/basic_plugins/init_plugin_config/init_plugins_config.py index c1fc94c9..bf0dff4b 100755 --- a/basic_plugins/init_plugin_config/init_plugins_config.py +++ b/basic_plugins/init_plugin_config/init_plugins_config.py @@ -15,14 +15,14 @@ def init_plugins_config(data_path): """ 初始化插件数据配置 """ - plugins2config_file = Path(data_path) / "configs" / "plugins2config.yaml" + plugins2config_file = data_path / "configs" / "plugins2config.yaml" plugins2config_file.parent.mkdir(parents=True, exist_ok=True) _data = {} if plugins2config_file.exists(): _data = _yaml.load(open(plugins2config_file, "r", encoding="utf8")) _matchers = get_matchers() for matcher in _matchers: - _plugin = nonebot.plugin.get_plugin(matcher.module) + _plugin = nonebot.plugin.get_plugin(matcher.plugin_name) try: _module = _plugin.module except AttributeError: @@ -39,16 +39,16 @@ def init_plugins_config(data_path): if ( plugin_version is None or ( - _data.get(matcher.module) - and _data[matcher.module].keys() != plugin_configs.keys() + _data.get(matcher.plugin_name) + and _data[matcher.plugin_name].keys() != plugin_configs.keys() ) - or plugin_version > plugins_manager.get(matcher.module)["version"] - or matcher.module not in _data.keys() + or plugin_version > plugins_manager.get(matcher.plugin_name)["version"] + or matcher.plugin_name not in _data.keys() ): for key in plugin_configs: if isinstance(plugin_configs[key], dict): Config.add_plugin_config( - matcher.module, + matcher.plugin_name, key, plugin_configs[key].get("value"), help_=plugin_configs[key].get("help"), @@ -56,12 +56,12 @@ def init_plugins_config(data_path): _override=True, ) else: - Config.add_plugin_config(matcher.module, key, plugin_configs[key]) + Config.add_plugin_config(matcher.plugin_name, key, plugin_configs[key]) else: - plugin_configs = _data[matcher.module] + plugin_configs = _data[matcher.plugin_name] for key in plugin_configs: Config.add_plugin_config( - matcher.module, + matcher.plugin_name, key, plugin_configs[key]["value"], help_=plugin_configs[key]["help"], @@ -99,7 +99,10 @@ def init_plugins_config(data_path): if _data.get(plugin) and k in _data[plugin].keys(): Config.set_config(plugin, k, _data[plugin][k]) if level2module := Config.get_level2module(plugin, k): - admin_manager.set_admin_level(level2module, _data[plugin][k]) + try: + admin_manager.set_admin_level(level2module, _data[plugin][k]) + except KeyError: + logger.warning(f"{level2module} 设置权限等级失败:{_data[plugin][k]}") _tmp_data[plugin][k] = Config.get_config(plugin, k) Config.save() temp_file = Path() / "configs" / "temp_config.yaml" diff --git a/basic_plugins/init_plugin_config/init_plugins_data.py b/basic_plugins/init_plugin_config/init_plugins_data.py index ca17eaa0..784f9f89 100755 --- a/basic_plugins/init_plugin_config/init_plugins_data.py +++ b/basic_plugins/init_plugin_config/init_plugins_data.py @@ -17,27 +17,27 @@ def init_plugins_data(data_path): """ 初始化插件数据信息 """ - plugin2data_file = Path(data_path) / "manager" / "plugin_manager.json" + plugin2data_file = data_path / "manager" / "plugin_manager.json" plugin2data_file.parent.mkdir(parents=True, exist_ok=True) _data = {} if plugin2data_file.exists(): _data = json.load(open(plugin2data_file, "r", encoding="utf8")) _matchers = get_matchers() for matcher in _matchers: - _plugin = nonebot.plugin.get_plugin(matcher.module) + _plugin = nonebot.plugin.get_plugin(matcher.plugin_name) try: _module = _plugin.module except AttributeError: - if matcher.module not in _data.keys(): + if matcher.plugin_name not in _data.keys(): plugins_manager.add_plugin_data( - matcher.module, matcher.module, error=True + matcher.plugin_name, matcher.plugin_name, error=True ) else: - plugins_manager.set_module_data(matcher.module, "error", True) - plugin_data = plugins_manager.get(matcher.module) + plugins_manager.set_module_data(matcher.plugin_name, "error", True) + plugin_data = plugins_manager.get(matcher.plugin_name) if plugin_data: plugins_manager.set_module_data( - matcher.module, "version", plugin_data.get("version") + matcher.plugin_name, "version", plugin_data.get("version") ) else: try: @@ -47,36 +47,36 @@ def init_plugins_data(data_path): try: plugin_name = _module.__getattribute__("__zx_plugin_name__") except AttributeError: - plugin_name = matcher.module + plugin_name = matcher.plugin_name try: plugin_author = _module.__getattribute__("__plugin_author__") except AttributeError: plugin_author = None - if matcher.module in plugins_manager.keys(): - plugins_manager.set_module_data(matcher.module, "error", False) - if matcher.module not in plugins_manager.keys(): + if matcher.plugin_name in plugins_manager.keys(): + plugins_manager.set_module_data(matcher.plugin_name, "error", False) + if matcher.plugin_name not in plugins_manager.keys(): plugins_manager.add_plugin_data( - matcher.module, + matcher.plugin_name, plugin_name=plugin_name, author=plugin_author, version=plugin_version, ) - elif plugins_manager[matcher.module]["version"] is None or ( + elif plugins_manager[matcher.plugin_name]["version"] is None or ( plugin_version is not None - and plugin_version > plugins_manager[matcher.module]["version"] + and plugin_version > plugins_manager[matcher.plugin_name]["version"] ): plugins_manager.set_module_data( - matcher.module, "plugin_name", plugin_name + matcher.plugin_name, "plugin_name", plugin_name ) - plugins_manager.set_module_data(matcher.module, "author", plugin_author) + plugins_manager.set_module_data(matcher.plugin_name, "author", plugin_author) plugins_manager.set_module_data( - matcher.module, "version", plugin_version + matcher.plugin_name, "version", plugin_version ) - if matcher.module in _data.keys(): + if matcher.plugin_name in _data.keys(): plugins_manager.set_module_data( - matcher.module, "error", _data[matcher.module]["error"] + matcher.plugin_name, "error", _data[matcher.plugin_name]["error"] ) plugins_manager.set_module_data( - matcher.module, "plugin_name", _data[matcher.module]["plugin_name"] + matcher.plugin_name, "plugin_name", _data[matcher.plugin_name]["plugin_name"] ) plugins_manager.save() diff --git a/basic_plugins/init_plugin_config/init_plugins_limit.py b/basic_plugins/init_plugin_config/init_plugins_limit.py index f507b4c5..f1059f8a 100755 --- a/basic_plugins/init_plugin_config/init_plugins_limit.py +++ b/basic_plugins/init_plugin_config/init_plugins_limit.py @@ -17,18 +17,18 @@ def init_plugins_cd_limit(data_path): """ 加载 cd 限制 """ - plugins2cd_file = Path(data_path) / "configs" / "plugins2cd.yaml" + plugins2cd_file = data_path / "configs" / "plugins2cd.yaml" plugins2cd_file.parent.mkdir(exist_ok=True, parents=True) _data = {} _matchers = get_matchers() for matcher in _matchers: - if not plugins2cd_manager.get_plugin_cd_data(matcher.module): - _plugin = nonebot.plugin.get_plugin(matcher.module) + if not plugins2cd_manager.get_plugin_cd_data(matcher.plugin_name): + _plugin = nonebot.plugin.get_plugin(matcher.plugin_name) try: _module = _plugin.module plugin_cd_limit = _module.__getattribute__("__plugin_cd_limit__") plugins2cd_manager.add_cd_limit( - matcher.module, data_dict=plugin_cd_limit + matcher.plugin_name, data_dict=plugin_cd_limit ) except AttributeError: pass @@ -65,18 +65,18 @@ def init_plugins_block_limit(data_path): """ 加载阻塞限制 """ - plugins2block_file = Path(data_path) / "configs" / "plugins2block.yaml" + plugins2block_file = data_path / "configs" / "plugins2block.yaml" plugins2block_file.parent.mkdir(exist_ok=True, parents=True) _data = {} _matchers = get_matchers() for matcher in _matchers: - if not plugins2block_manager.get_plugin_block_data(matcher.module): - _plugin = nonebot.plugin.get_plugin(matcher.module) + if not plugins2block_manager.get_plugin_block_data(matcher.plugin_name): + _plugin = nonebot.plugin.get_plugin(matcher.plugin_name) try: _module = _plugin.module plugin_block_limit = _module.__getattribute__("__plugin_block_limit__") plugins2block_manager.add_block_limit( - matcher.module, data_dict=plugin_block_limit + matcher.plugin_name, data_dict=plugin_block_limit ) except AttributeError: pass @@ -113,18 +113,18 @@ def init_plugins_count_limit(data_path): """ 加载次数限制 """ - plugins2count_file = Path(data_path) / "configs" / "plugins2count.yaml" + plugins2count_file = data_path / "configs" / "plugins2count.yaml" plugins2count_file.parent.mkdir(exist_ok=True, parents=True) _data = {} _matchers = get_matchers() for matcher in _matchers: - if not plugins2count_manager.get_plugin_count_data(matcher.module): - _plugin = nonebot.plugin.get_plugin(matcher.module) + if not plugins2count_manager.get_plugin_count_data(matcher.plugin_name): + _plugin = nonebot.plugin.get_plugin(matcher.plugin_name) try: _module = _plugin.module plugin_count_limit = _module.__getattribute__("__plugin_count_limit__") plugins2count_manager.add_count_limit( - matcher.module, data_dict=plugin_count_limit + matcher.plugin_name, data_dict=plugin_count_limit ) except AttributeError: pass diff --git a/basic_plugins/init_plugin_config/init_plugins_resources.py b/basic_plugins/init_plugin_config/init_plugins_resources.py index 1fdfa4b3..0285f293 100755 --- a/basic_plugins/init_plugin_config/init_plugins_resources.py +++ b/basic_plugins/init_plugin_config/init_plugins_resources.py @@ -11,13 +11,13 @@ def init_plugins_resources(): """ _tmp = [] for matcher in get_matchers(): - if matcher.module not in _tmp: - _tmp.append(matcher.module) - _plugin = nonebot.plugin.get_plugin(matcher.module) + if matcher.plugin_name not in _tmp: + _tmp.append(matcher.plugin_name) + _plugin = nonebot.plugin.get_plugin(matcher.plugin_name) try: _module = _plugin.module except AttributeError: - logger.warning(f"插件 {matcher.module} 加载失败...,资源控制未加载...") + logger.warning(f"插件 {matcher.plugin_name} 加载失败...,资源控制未加载...") else: try: resources = _module.__getattribute__("__plugin_resources__") @@ -26,7 +26,7 @@ def init_plugins_resources(): else: path = Path(_module.__getattribute__("__file__")).parent for resource in resources.keys(): - resources_manager.add_resource(matcher.module, (path / resource).absolute(), resources[resource]) + resources_manager.add_resource(matcher.plugin_name, path / resource, resources[resource]) resources_manager.save() resources_manager.start_move() diff --git a/basic_plugins/init_plugin_config/init_plugins_settings.py b/basic_plugins/init_plugin_config/init_plugins_settings.py index 55203d32..dfabbe28 100755 --- a/basic_plugins/init_plugin_config/init_plugins_settings.py +++ b/basic_plugins/init_plugin_config/init_plugins_settings.py @@ -14,7 +14,7 @@ def init_plugins_settings(data_path: str): """ 初始化插件设置,从插件中获取 __zx_plugin_name__,__plugin_cmd__,__plugin_settings__ """ - plugins2settings_file = Path(data_path) / "configs" / "plugins2settings.yaml" + plugins2settings_file = data_path / "configs" / "plugins2settings.yaml" plugins2settings_file.parent.mkdir(exist_ok=True, parents=True) _matchers = get_matchers() _tmp_module = {} @@ -29,12 +29,12 @@ def init_plugins_settings(data_path: str): logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}") _tmp_module[x] = "" for matcher in _matchers: - if matcher.module not in plugins2settings_manager.keys(): - _plugin = nonebot.plugin.get_plugin(matcher.module) + if matcher.plugin_name not in plugins2settings_manager.keys(): + _plugin = nonebot.plugin.get_plugin(matcher.plugin_name) try: _module = _plugin.module except AttributeError: - logger.warning(f"插件 {matcher.module} 加载失败...,插件控制未加载.") + logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.") else: try: plugin_name = _module.__getattribute__("__zx_plugin_name__") @@ -51,23 +51,23 @@ def init_plugins_settings(data_path: str): if level is None: level = 5 admin_manager.add_admin_plugin_settings( - matcher.module, cmd, level + matcher.plugin_name, cmd, level ) if ( "[hidden]" in plugin_name.lower() or "[admin]" in plugin_name.lower() or "[superuser]" in plugin_name.lower() - or matcher.module in plugins2settings_manager.keys() + or matcher.plugin_name in plugins2settings_manager.keys() ): continue except AttributeError: - if matcher.module not in _tmp: + if matcher.plugin_name not in _tmp: logger.warning( - f"获取插件 {matcher.module} __zx_plugin_name__ 失败...,插件控制未加载." + f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载." ) else: try: - _tmp_module[matcher.module] = plugin_name + _tmp_module[matcher.plugin_name] = plugin_name plugin_settings = _module.__getattribute__( "__plugin_settings__" ) @@ -79,13 +79,13 @@ def init_plugins_settings(data_path: str): ): plugin_settings["cmd"].append(plugin_name) if plugins2settings_manager.get( - matcher.module - ) and plugins2settings_manager[matcher.module].get( + matcher.plugin_name + ) and plugins2settings_manager[matcher.plugin_name].get( "plugin_type" ): plugin_type = tuple( plugins2settings_manager.get_plugin_data( - matcher.module + matcher.plugin_name )["plugin_type"] ) else: @@ -95,15 +95,15 @@ def init_plugins_settings(data_path: str): ) except AttributeError: plugin_type = ("normal",) - if plugin_settings and matcher.module: + if plugin_settings and matcher.plugin_name: plugins2settings_manager.add_plugin_settings( - matcher.module, + matcher.plugin_name, plugin_type=plugin_type, **plugin_settings, ) except AttributeError: pass - _tmp.append(matcher.module) + _tmp.append(matcher.plugin_name) _tmp_data = {"PluginSettings": plugins2settings_manager.get_data()} with open(plugins2settings_file, "w", encoding="utf8") as wf: yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True) diff --git a/basic_plugins/invite_manager/__init__.py b/basic_plugins/invite_manager/__init__.py index 857cac4a..b3067606 100755 --- a/basic_plugins/invite_manager/__init__.py +++ b/basic_plugins/invite_manager/__init__.py @@ -1,5 +1,5 @@ from nonebot import on_request, on_message -from nonebot.adapters.cqhttp import ( +from nonebot.adapters.onebot.v11 import ( Bot, FriendRequestEvent, GroupRequestEvent, @@ -8,7 +8,7 @@ from nonebot.adapters.cqhttp import ( from models.friend_user import FriendUser from datetime import datetime from configs.config import NICKNAME, Config -from nonebot.adapters.cqhttp.exception import ActionFailed +from nonebot.adapters.onebot.v11.exception import ActionFailed from utils.manager import requests_manager from models.group_info import GroupInfo from utils.utils import scheduler @@ -31,7 +31,7 @@ exists_data = {"private": {}, "group": {}} @friend_req.handle() -async def _(bot: Bot, event: FriendRequestEvent, state: dict): +async def _(bot: Bot, event: FriendRequestEvent): global exists_data if exists_data["private"].get(event.user_id): if time.time() - exists_data["private"][event.user_id] < 60 * 5: @@ -66,7 +66,7 @@ async def _(bot: Bot, event: FriendRequestEvent, state: dict): @group_req.handle() -async def _(bot: Bot, event: GroupRequestEvent, state: dict): +async def _(bot: Bot, event: GroupRequestEvent): global exists_data if event.sub_type == "invite": if str(event.user_id) in bot.config.superusers: @@ -125,7 +125,7 @@ async def _(bot: Bot, event: GroupRequestEvent, state: dict): @x.handle() -async def _(bot: Bot, event: MessageEvent, state: dict): +async def _(event: MessageEvent): await asyncio.sleep(0.1) r = re.search(r'groupcode="(.*?)"', str(event.get_message())) if r: diff --git a/basic_plugins/nickname.py b/basic_plugins/nickname.py index bb8ef1e0..ca7e94a7 100755 --- a/basic_plugins/nickname.py +++ b/basic_plugins/nickname.py @@ -1,15 +1,14 @@ +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, PrivateMessageEvent, Message from nonebot import on_command from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, PrivateMessageEvent from nonebot.rule import to_me -from utils.utils import get_message_text from models.group_member_info import GroupInfoUser from models.friend_user import FriendUser -import random from models.ban_user import BanUser from services.log import logger from configs.config import NICKNAME, Config - +from nonebot.params import CommandArg +import random __zx_plugin_name__ = "昵称系统" __plugin_usage__ = f""" @@ -48,8 +47,8 @@ cancel_nickname = on_command("取消昵称", rule=to_me(), priority=5, block=Tru @nickname.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() if not msg: await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True) if len(msg) > 10: @@ -103,7 +102,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @my_nickname.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): try: nickname_ = await GroupInfoUser.get_group_member_nickname( event.user_id, event.group_id @@ -124,7 +123,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): ) ) else: - nickname_ = event.sender.card if event.sender.card else event.sender.nickname + nickname_ = event.sender.card or event.sender.nickname await my_nickname.send( random.choice( ["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"] @@ -158,7 +157,7 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): @cancel_nickname.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): nickname_ = await GroupInfoUser.get_group_member_nickname( event.user_id, event.group_id ) @@ -181,7 +180,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @cancel_nickname.handle() -async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): +async def _(event: PrivateMessageEvent): nickname_ = await FriendUser.get_friend_nickname(event.user_id) if nickname_: await cancel_nickname.send( diff --git a/basic_plugins/scripts.py b/basic_plugins/scripts.py index b45569c6..d602ccb6 100755 --- a/basic_plugins/scripts.py +++ b/basic_plugins/scripts.py @@ -7,14 +7,13 @@ from nonebot import Driver from services.db_context import db from models.group_info import GroupInfo from models.bag_user import BagUser -from nonebot.adapters.cqhttp import Bot +from nonebot.adapters.onebot.v11 import Bot from services.log import logger from configs.path_config import TEXT_PATH from asyncio.exceptions import TimeoutError from typing import List from utils.http_utils import AsyncHttpx from utils.utils import scheduler -from pathlib import Path import nonebot try: @@ -32,7 +31,7 @@ async def update_city(): 部分插件需要中国省份城市 这里直接更新,避免插件内代码重复 """ - china_city = Path(TEXT_PATH) / "china_city.json" + china_city = TEXT_PATH / "china_city.json" data = {} if not china_city.exists(): try: @@ -105,6 +104,10 @@ async def _(): "ALTER TABLE genshin ADD resin_recovery_time timestamp with time zone;", "genshin" ), # 新增原神自动签到字段 + ( + "ALTER TABLE genshin ADD bind_group Integer;", + "genshin" + ), # 新增原神群号绑定字段 ] for sql in sql_str: try: diff --git a/basic_plugins/shop/buy.py b/basic_plugins/shop/buy.py index 430a0fa6..0f723fbc 100644 --- a/basic_plugins/shop/buy.py +++ b/basic_plugins/shop/buy.py @@ -1,11 +1,11 @@ from nonebot import on_command from services.log import logger -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from nonebot.typing import T_State -from utils.utils import get_message_text, is_number +from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message +from nonebot.params import CommandArg +from utils.utils import is_number from models.bag_user import BagUser from services.db_context import db -from nonebot.adapters.cqhttp.permission import GROUP +from nonebot.adapters.onebot.v11.permission import GROUP from models.goods_info import GoodsInfo import time @@ -37,9 +37,9 @@ buy = on_command("购买", aliases={"购买道具"}, priority=5, block=True, per @buy.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent, arg: Message = CommandArg()): goods = None - if get_message_text(event.json()) in ["神秘药水"]: + if arg.extract_plain_text().strip() in ["神秘药水"]: await buy.finish("你们看看就好啦,这是不可能卖给你们的~", at_sender=True) goods_list = [ x @@ -50,7 +50,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): x.goods_name for x in goods_list ] - msg = get_message_text(event.json()).split() + msg = arg.extract_plain_text().strip().split() num = 1 if len(msg) > 1: if is_number(msg[1]) and int(msg[1]) > 0: diff --git a/basic_plugins/shop/gold.py b/basic_plugins/shop/gold.py index e748c9b5..1bc048a9 100644 --- a/basic_plugins/shop/gold.py +++ b/basic_plugins/shop/gold.py @@ -1,11 +1,11 @@ from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from nonebot.typing import T_State -from nonebot.adapters.cqhttp.permission import GROUP +from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message +from nonebot.params import CommandArg +from nonebot.adapters.onebot.v11.permission import GROUP from utils.data_utils import init_rank from models.bag_user import BagUser from utils.message_builder import image -from utils.utils import get_message_text, is_number +from utils.utils import is_number __zx_plugin_name__ = "商店 - 我的金币" __plugin_usage__ = """ @@ -33,13 +33,13 @@ gold_rank = on_command("金币排行", priority=5, block=True, permission=GROUP) @my_gold.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): await my_gold.finish(await BagUser.get_user_total_gold(event.user_id, event.group_id)) @gold_rank.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - num = get_message_text(event.json()) +async def _(event: GroupMessageEvent, arg: Message = CommandArg()): + num = arg.extract_plain_text().strip() if is_number(num) and 51 > int(num) > 10: num = int(num) else: diff --git a/basic_plugins/shop/my_props.py b/basic_plugins/shop/my_props.py index 8d8d686d..f19a8e10 100644 --- a/basic_plugins/shop/my_props.py +++ b/basic_plugins/shop/my_props.py @@ -1,9 +1,8 @@ from nonebot import on_command from services.log import logger -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from nonebot.typing import T_State +from nonebot.adapters.onebot.v11 import GroupMessageEvent from models.bag_user import BagUser -from nonebot.adapters.cqhttp.permission import GROUP +from nonebot.adapters.onebot.v11.permission import GROUP __zx_plugin_name__ = "商店 - 我的道具" @@ -30,7 +29,7 @@ my_props = on_command("我的道具", priority=5, block=True, permission=GROUP) @my_props.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): props = await BagUser.get_property(event.user_id, event.group_id) if props: rst = "" diff --git a/basic_plugins/shop/shop_handle/__init__.py b/basic_plugins/shop/shop_handle/__init__.py index 74082045..7e680229 100644 --- a/basic_plugins/shop/shop_handle/__init__.py +++ b/basic_plugins/shop/shop_handle/__init__.py @@ -1,11 +1,11 @@ +from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info +from nonebot.adapters.onebot.v11 import MessageEvent, Message from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent -from nonebot.typing import T_State from configs.path_config import IMAGE_PATH from utils.message_builder import image -from .data_source import create_shop_help, delete_goods, update_goods, register_goods, parse_goods_info from nonebot.permission import SUPERUSER -from utils.utils import get_message_text, is_number +from utils.utils import is_number +from nonebot.params import CommandArg from nonebot.plugin import export from services.log import logger import os @@ -67,13 +67,13 @@ shop_update_goods = on_command("修改商品", priority=5, permission=SUPERUSER, @shop_help.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(): await shop_help.send(image(b64=await create_shop_help())) @shop_add_goods.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() if msg: data = parse_goods_info(msg) if isinstance(data, str): @@ -94,8 +94,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @shop_del_goods.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() if msg: name = "" id_ = 0 @@ -115,8 +115,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @shop_update_goods.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() if msg: data = parse_goods_info(msg) if isinstance(data, str): diff --git a/basic_plugins/shop/use/__init__.py b/basic_plugins/shop/use/__init__.py index 0b85ce41..69cc8540 100644 --- a/basic_plugins/shop/use/__init__.py +++ b/basic_plugins/shop/use/__init__.py @@ -1,10 +1,10 @@ from nonebot import on_command from services.log import logger -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from nonebot.typing import T_State -from utils.utils import is_number, get_message_text +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message +from nonebot.params import CommandArg +from utils.utils import is_number from models.bag_user import BagUser -from nonebot.adapters.cqhttp.permission import GROUP +from nonebot.adapters.onebot.v11.permission import GROUP from services.db_context import db from nonebot.plugin import export from .data_source import effect, register_use, func_manager @@ -38,10 +38,8 @@ use_props = on_command("使用道具", priority=5, block=True, permission=GROUP) @use_props.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - msg = get_message_text(event.json()) - if msg in ["", "帮助"]: - await use_props.finish(__plugin_usage__) +async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() num = 1 msg_sp = msg.split() if len(msg_sp) > 1 and is_number(msg_sp[-1]) and int(msg_sp[-1]) > 0: diff --git a/basic_plugins/shop/use/data_source.py b/basic_plugins/shop/use/data_source.py index bab56b75..899eea39 100644 --- a/basic_plugins/shop/use/data_source.py +++ b/basic_plugins/shop/use/data_source.py @@ -1,6 +1,6 @@ -from nonebot.adapters.cqhttp import GroupMessageEvent, MessageSegment +from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageSegment from services.log import logger -from nonebot.adapters.cqhttp import Bot +from nonebot.adapters.onebot.v11 import Bot from typing import Optional, Union import asyncio diff --git a/basic_plugins/super_cmd/bot_friend_group.py b/basic_plugins/super_cmd/bot_friend_group.py index ff4b16ab..7ef4b00f 100755 --- a/basic_plugins/super_cmd/bot_friend_group.py +++ b/basic_plugins/super_cmd/bot_friend_group.py @@ -1,9 +1,10 @@ from nonebot import on_command from nonebot.permission import SUPERUSER -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, Message +from nonebot.adapters.onebot.v11 import Bot, Message +from nonebot.params import Command, CommandArg +from typing import Tuple from nonebot.rule import to_me -from utils.utils import get_message_text, is_number +from utils.utils import is_number from utils.manager import requests_manager from utils.message_builder import image from models.group_info import GroupInfo @@ -57,37 +58,30 @@ cls_request = on_command("查看所有请求", permission=SUPERUSER, priority=1, @cls_group.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - gl = await bot.get_group_list(self_id=int(bot.self_id)) +async def _(bot: Bot): + gl = await bot.get_group_list() msg = ["{group_id} {group_name}".format_map(g) for g in gl] msg = "\n".join(msg) msg = f"bot:{bot.self_id}\n| 群号 | 群名 | 共{len(gl)}个群\n" + msg - await bot.send_private_msg( - self_id=int(bot.self_id), - user_id=int(list(bot.config.superusers)[0]), - message=msg, - ) + await cls_group.send(msg) @cls_friend.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - gl = await bot.get_friend_list(self_id=int(bot.self_id)) +async def _(bot: Bot): + gl = await bot.get_friend_list() msg = ["{user_id} {nickname}".format_map(g) for g in gl] msg = "\n".join(msg) msg = f"| QQ号 | 昵称 | 共{len(gl)}个好友\n" + msg - await bot.send_private_msg( - self_id=int(bot.self_id), - user_id=int(list(bot.config.superusers)[0]), - message=msg, - ) + await cls_friend.send(msg) @friend_handle.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - id_ = get_message_text(event.json()) +async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): + cmd = cmd[0] + id_ = arg.extract_plain_text().strip() if is_number(id_): id_ = int(id_) - if state["_prefix"]["raw_command"][:2] == "同意": + if cmd[:2] == "同意": if await requests_manager.approve(bot, id_, "private"): await friend_handle.send("同意好友请求成功..") else: @@ -102,11 +96,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @group_handle.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - id_ = get_message_text(event.json()) +async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): + cmd = cmd[0] + id_ = arg.extract_plain_text().strip() if is_number(id_): id_ = int(id_) - if state["_prefix"]["raw_command"][:2] == "同意": + if cmd[:2] == "同意": rid = await requests_manager.approve(bot, id_, "group") if rid: await friend_handle.send("同意群聊请求成功..") @@ -133,7 +128,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @cls_request.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): _str = "" for type_ in ["private", "group"]: msg = await requests_manager.show(type_) @@ -147,6 +142,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @clear_request.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): requests_manager.clear() await cls_request.send("已清空所有好友/群聊请求..") diff --git a/basic_plugins/super_cmd/clear_data.py b/basic_plugins/super_cmd/clear_data.py index d7571954..8fcd7bfc 100755 --- a/basic_plugins/super_cmd/clear_data.py +++ b/basic_plugins/super_cmd/clear_data.py @@ -1,7 +1,5 @@ from nonebot import on_command from nonebot.permission import SUPERUSER -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent from configs.path_config import TEMP_PATH from nonebot.rule import to_me from utils.utils import scheduler @@ -35,7 +33,7 @@ resources_manager.add_temp_dir(TEMP_PATH) @clear_data.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): await clear_data.send("开始清理临时数据....") size = await asyncio.get_event_loop().run_in_executor(None, _clear_data) await clear_data.send("共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024)) @@ -47,13 +45,14 @@ def _clear_data() -> float: if dir_.exists(): for file in os.listdir(dir_): file = dir_ / file - try: - if time.time() - os.path.getatime(file) > 300: - file_size = os.path.getsize(file) - file.unlink() - size += file_size - except Exception as e: - logger.error(f"清理临时数据错误...{type(e)}:{e}") + if file.is_file(): + try: + if time.time() - os.path.getatime(file) > 300: + file_size = os.path.getsize(file) + file.unlink() + size += file_size + except Exception as e: + logger.error(f"清理临时数据错误...{type(e)}:{e}") return float(size) diff --git a/basic_plugins/super_cmd/data_source.py b/basic_plugins/super_cmd/data_source.py deleted file mode 100755 index 53244823..00000000 --- a/basic_plugins/super_cmd/data_source.py +++ /dev/null @@ -1,74 +0,0 @@ - - -# async def open_remind(group: int, name: str) -> str: -# _name = "" -# if name == "zwa": -# _name = "早晚安" -# if name == "dz": -# _name = "地震播报" -# if name == "hy": -# _name = "群欢迎" -# if name == "kxcz": -# _name = "开箱重置提醒" -# if name == "gb": -# _name = "广播" -# if await GroupRemind.get_status(group, name): -# return f"该群已经开启过 {_name} 通知,请勿重复开启!" -# if await GroupRemind.set_status(group, name, True): -# return f"成功开启 {_name} 通知!0v0" -# else: -# return f"开启 {_name} 通知失败了..." -# -# -# async def close_remind(group: int, name: str) -> str: -# _name = "" -# if name == "zwa": -# _name = "早晚安" -# if name == "dz": -# _name = "地震播报" -# if name == "hy": -# _name = "群欢迎" -# if name == "kxcz": -# _name = "开箱重置提醒" -# if name == "gb": -# _name = "广播" -# if not await GroupRemind.get_status(group, name): -# return f"该群已经取消过 {_name} 通知,请勿重复取消!" -# if await GroupRemind.set_status(group, name, False): -# return f"成功关闭 {_name} 通知!0v0" -# else: -# return f"关闭 {_name} 通知失败了..." - - -# cmd_list = ['总开关', '签到', '发送图片', '色图', '黑白草图', 'coser', '鸡汤/语录', '骂我', '开箱', '鲁迅说', '假消息', '商店系统', -# '操作图片', '查询皮肤', '天气', '疫情', '识番', '搜番', '点歌', 'pixiv', 'rss', '方舟一井', '查干员', '骰子娘', '原神一井'] -# -# -# def check_group_switch_json(group_id): -# if not os.path.exists(DATA_PATH + f'rule/group_switch/'): -# os.mkdir(DATA_PATH + f'rule/group_switch/') -# if not os.path.exists(DATA_PATH + f'rule/group_switch/{group_id}.json'): -# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'w', encoding='utf8') as f: -# data = {} -# for cmd in cmd_list: -# data[cmd] = True -# f.write(json.dumps(data, ensure_ascii=False)) -# else: -# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'r', encoding='utf8') as f: -# try: -# data = json.load(f) -# except ValueError: -# data = {} -# if len(data.keys()) - 1 != len(cmd_list): -# for cmd in cmd_list: -# if cmd not in data.keys(): -# data[cmd] = True -# with open(DATA_PATH + f'rule/group_switch/{group_id}.json', 'w', encoding='utf8') as wf: -# wf.write(json.dumps(data, ensure_ascii=False)) -# reload(data) -# for file in os.listdir(DATA_PATH + 'group_help'): -# os.remove(DATA_PATH + f'group_help/{file}') - - -def reload(data): - static_group_dict = data diff --git a/basic_plugins/super_cmd/exec_sql.py b/basic_plugins/super_cmd/exec_sql.py index 4b44f251..fd660b5b 100644 --- a/basic_plugins/super_cmd/exec_sql.py +++ b/basic_plugins/super_cmd/exec_sql.py @@ -1,10 +1,9 @@ +from nonebot.adapters.onebot.v11 import Message from nonebot import on_command from nonebot.permission import SUPERUSER -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent from nonebot.rule import to_me from services.db_context import db -from utils.utils import get_message_text +from nonebot.params import CommandArg from services.log import logger __zx_plugin_name__ = "执行sql [Superuser]" @@ -26,8 +25,8 @@ exec_ = on_command("exec", rule=to_me(), permission=SUPERUSER, priority=1, block @exec_.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - sql = get_message_text(event.json()) +async def _(arg: Message = CommandArg()): + sql = arg.extract_plain_text().strip() async with db.transaction(): try: query = db.text(sql) diff --git a/basic_plugins/super_cmd/manager_group.py b/basic_plugins/super_cmd/manager_group.py index e6af40c8..7ed821cd 100755 --- a/basic_plugins/super_cmd/manager_group.py +++ b/basic_plugins/super_cmd/manager_group.py @@ -1,14 +1,16 @@ +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GROUP, GroupMessageEvent, Message from nonebot import on_command, on_regex from nonebot.permission import SUPERUSER from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GROUP, GroupMessageEvent from nonebot.rule import to_me -from utils.utils import get_message_text, is_number +from utils.utils import is_number from utils.manager import group_manager, plugins2settings_manager from models.group_info import GroupInfo from services.log import logger from configs.config import NICKNAME -from nonebot.adapters.cqhttp.exception import ActionFailed +from nonebot.adapters.onebot.v11.exception import ActionFailed +from nonebot.params import Command, CommandArg +from typing import Tuple __zx_plugin_name__ = "管理群操作 [Superuser]" @@ -65,8 +67,8 @@ group_auth = on_command( @del_group.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - group_id = get_message_text(event.json()) +async def _(bot: Bot, arg: Message = CommandArg()): + group_id = arg.extract_plain_text().strip() if group_id: if is_number(group_id): try: @@ -84,8 +86,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @add_group_level.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() group_id = 0 level = 0 if not msg: @@ -109,7 +111,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @my_group_level.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): level = group_manager.get_group_level(event.group_id) tmp = "" data = plugins2settings_manager.get_data() @@ -125,17 +127,18 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @what_up_group_level.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(): await what_up_group_level.finish( f"[此功能用于防止内鬼,如果引起不便那真是抱歉了]\n" f"目前提高群权限的方法:\n" f"\t1.管理员修改权限" ) @manager_group_whitelist.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()).split() +async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): + cmd = cmd[0] + msg = arg.extract_plain_text().strip() all_group = [ - g["group_id"] for g in await bot.get_group_list(self_id=int(bot.self_id)) + g["group_id"] for g in await bot.get_group_list() ] group_list = [] for group in msg: @@ -143,20 +146,20 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): group_list.append(int(group)) if group_list: for group in group_list: - if state["_prefix"]["raw_command"] in ["添加群白名单"]: + if cmd in ["添加群白名单"]: group_manager.add_group_white_list(group) else: group_manager.delete_group_white_list(group) group_list = [str(x) for x in group_list] await manager_group_whitelist.send( - "已成功将 " + "\n".join(group_list) + " " + state["_prefix"]["raw_command"] + "已成功将 " + "\n".join(group_list) + " " + cmd ) else: await manager_group_whitelist.send(f"添加失败,请检查{NICKNAME}是否已加入这些群聊或重复添加/删除群白单名") @show_group_whitelist.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): x = group_manager.get_group_white_list() x = [str(g) for g in x] if x: @@ -166,13 +169,14 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @group_auth.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()).split() +async def _(bot: Bot, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): + cmd = cmd[0] + msg = arg.extract_plain_text().strip().split() for group_id in msg: if not is_number(group_id): await group_auth.send(f"{group_id}非纯数字,已跳过该项..") group_id = int(group_id) - if state["_prefix"]["raw_command"][:2] == "添加": + if cmd[:2] == "添加": if await GroupInfo.get_group_info(group_id): await GroupInfo.set_group_flag(group_id, 1) else: @@ -196,5 +200,5 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): if await GroupInfo.get_group_info(group_id): await GroupInfo.set_group_flag(group_id, 0) await group_auth.send( - f'已为 {group_id} {state["_prefix"]["raw_command"][:2]}群认证..' + f'已为 {group_id} {cmd[:2]}群认证..' ) diff --git a/basic_plugins/super_cmd/reload_setting.py b/basic_plugins/super_cmd/reload_setting.py index aab55d0c..acbd616e 100755 --- a/basic_plugins/super_cmd/reload_setting.py +++ b/basic_plugins/super_cmd/reload_setting.py @@ -7,10 +7,8 @@ from utils.manager import ( plugins2block_manager, group_manager, ) -from nonebot.typing import T_State from configs.config import Config from services.log import logger -from nonebot.adapters.cqhttp import Bot, MessageEvent from utils.utils import scheduler @@ -51,7 +49,7 @@ reload_plugins_manager = on_command( @reload_plugins_manager.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): plugins2settings_manager.reload() plugins2cd_manager.reload() plugins2block_manager.reload() diff --git a/basic_plugins/super_cmd/set_admin_permissions.py b/basic_plugins/super_cmd/set_admin_permissions.py index 97598636..7bbbfeae 100755 --- a/basic_plugins/super_cmd/set_admin_permissions.py +++ b/basic_plugins/super_cmd/set_admin_permissions.py @@ -1,11 +1,12 @@ from nonebot import on_command from nonebot.permission import SUPERUSER from models.level_user import LevelUser -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, Message -from utils.utils import get_message_at, get_message_text, is_number +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message +from utils.utils import get_message_at, is_number from services.log import logger from utils.message_builder import at +from nonebot.params import Command, CommandArg +from typing import Tuple __zx_plugin_name__ = "用户权限管理 [Superuser]" __plugin_usage__ = """ @@ -36,11 +37,12 @@ super_cmd = on_command( @super_cmd.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): + cmd = cmd[0] group_id = -1 level = 0 try: - args = get_message_text(event.json()).split() + args = arg.extract_plain_text().strip().split() qq = get_message_at(event.json()) flag = -1 if not qq: @@ -65,7 +67,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): qq = qq[0] group_id = event.group_id flag = 2 - if state["_prefix"]["raw_command"][:2] == "添加": + if cmd[:2] == "添加": if await LevelUser.set_level(qq, group_id, level, 1): result = "添加管理成功, 权限: " + str(level) else: diff --git a/basic_plugins/super_cmd/super_task_switch.py b/basic_plugins/super_cmd/super_task_switch.py index 01fb0eca..ba1df382 100755 --- a/basic_plugins/super_cmd/super_task_switch.py +++ b/basic_plugins/super_cmd/super_task_switch.py @@ -1,11 +1,12 @@ from nonebot import on_command from nonebot.permission import SUPERUSER -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message from nonebot.rule import to_me -from utils.utils import get_message_text, is_number +from utils.utils import is_number from services.log import logger from utils.manager import group_manager +from nonebot.params import Command, CommandArg +from typing import Tuple __zx_plugin_name__ = "超级用户被动开关 [Superuser]" @@ -34,8 +35,9 @@ oc_gb = on_command( @oc_gb.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - group = get_message_text(event.json()) +async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): + cmd = cmd[0] + group = arg.extract_plain_text().strip() if group: if is_number(group): group = int(group) @@ -44,7 +46,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): break else: await oc_gb.finish("没有加入这个群...", at_sender=True) - if state["_prefix"]["raw_command"] == "开启广播通知": + if cmd == "开启广播通知": logger.info(f"USER {event.user_id} 开启了 GROUP {group} 的广播") await oc_gb.finish(await group_manager.open_group_task(group, "broadcast",), at_sender=True) else: diff --git a/basic_plugins/super_cmd/update_friend_group_info.py b/basic_plugins/super_cmd/update_friend_group_info.py index 273bdfe8..c0479624 100755 --- a/basic_plugins/super_cmd/update_friend_group_info.py +++ b/basic_plugins/super_cmd/update_friend_group_info.py @@ -1,7 +1,5 @@ from nonebot import on_command from nonebot.permission import SUPERUSER -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent from nonebot.rule import to_me from utils.utils import get_bot from services.log import logger @@ -34,7 +32,7 @@ update_friend_info = on_command( @update_group_info.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): bot = get_bot() gl = await bot.get_group_list() gl = [g["group_id"] for g in gl] @@ -57,7 +55,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @update_friend_info.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): num = 0 rst = "" fl = await get_bot().get_friend_list() diff --git a/basic_plugins/super_help/__init__.py b/basic_plugins/super_help/__init__.py index 1bdbaf69..6dbe286f 100755 --- a/basic_plugins/super_help/__init__.py +++ b/basic_plugins/super_help/__init__.py @@ -1,18 +1,15 @@ from nonebot import on_command from nonebot.permission import SUPERUSER -from nonebot.typing import T_State -from nonebot.adapters import Bot, Event from nonebot.rule import to_me from configs.path_config import IMAGE_PATH from utils.message_builder import image from .data_source import create_help_image -from pathlib import Path __zx_plugin_name__ = '超级用户帮助 [Superuser]' -superuser_help_image = Path(IMAGE_PATH) / 'superuser_help.png' +superuser_help_image = IMAGE_PATH / 'superuser_help.png' if superuser_help_image.exists(): superuser_help_image.unlink() @@ -23,7 +20,7 @@ super_help = on_command( @super_help.handle() -async def _(bot: Bot, event: Event, state: T_State): +async def _(): if not superuser_help_image.exists(): await create_help_image() x = image(superuser_help_image) diff --git a/basic_plugins/super_help/data_source.py b/basic_plugins/super_help/data_source.py index 4138bf5c..e7e559a5 100755 --- a/basic_plugins/super_help/data_source.py +++ b/basic_plugins/super_help/data_source.py @@ -2,8 +2,7 @@ from utils.image_utils import BuildImage from configs.path_config import IMAGE_PATH from services.log import logger from utils.utils import get_matchers -from nonebot.adapters.cqhttp import Bot -from pathlib import Path +from nonebot.adapters.onebot.v11 import Bot from nonebot import Driver import asyncio import nonebot @@ -11,9 +10,9 @@ import nonebot driver: Driver = nonebot.get_driver() -background = Path(IMAGE_PATH) / "background" / "0.png" +background = IMAGE_PATH / "background" / "0.png" -superuser_help_image = Path(IMAGE_PATH) / "superuser_help.png" +superuser_help_image = IMAGE_PATH / "superuser_help.png" @driver.on_bot_connect @@ -36,7 +35,7 @@ def _create_help_image(): for matcher in _matchers: plugin_name = "" try: - _plugin = nonebot.plugin.get_plugin(matcher.module) + _plugin = nonebot.plugin.get_plugin(matcher.plugin_name) _module = _plugin.module try: plugin_name = _module.__getattribute__("__zx_plugin_name__") @@ -68,7 +67,7 @@ def _create_help_image(): width = width if width > x else x except Exception as e: logger.warning( - f"获取超级用户插件 {matcher.module}: {plugin_name} 设置失败... {type(e)}:{e}" + f"获取超级用户插件 {matcher.plugin_name}: {plugin_name} 设置失败... {type(e)}:{e}" ) height = len(help_str.split("\n")) * 33 width += 500 diff --git a/basic_plugins/update_info.py b/basic_plugins/update_info.py index 8d11d144..7c19d86c 100755 --- a/basic_plugins/update_info.py +++ b/basic_plugins/update_info.py @@ -1,6 +1,4 @@ from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, Event -from nonebot.typing import T_State from utils.message_builder import image @@ -27,7 +25,7 @@ update_info = on_command("更新信息", aliases={"更新日志"}, priority=5, b @update_info.handle() -async def _(bot: Bot, event: Event, state: T_State): +async def _(): img = image("update_info.png") if img: await update_info.finish(image("update_info.png")) diff --git a/bot.py b/bot.py index ca579075..da616b77 100644 --- a/bot.py +++ b/bot.py @@ -1,11 +1,10 @@ import nonebot -from nonebot.adapters.cqhttp import Bot as CQHTTPBot +from nonebot.adapters.onebot.v11 import Adapter from services.db_context import init, disconnect - nonebot.init() driver = nonebot.get_driver() -driver.register_adapter("cqhttp", CQHTTPBot) +driver.register_adapter(Adapter) config = driver.config driver.on_startup(init) driver.on_shutdown(disconnect) diff --git a/configs/path_config.py b/configs/path_config.py index 7bae46d4..6cb7bc1e 100644 --- a/configs/path_config.py +++ b/configs/path_config.py @@ -1,41 +1,45 @@ from pathlib import Path +import os # 图片路径 -IMAGE_PATH = Path("resources/img/") -# 音频路径 -VOICE_PATH = Path("resources/voice/") +IMAGE_PATH = Path() / "resources" / "image" +# 语音路径 +RECORD_PATH = Path() / "resources" / "record" # 文本路径 -TEXT_PATH = Path("resources/txt/") +TEXT_PATH = Path() / "resources" / "text" # 日志路径 -LOG_PATH = Path("log/") +LOG_PATH = Path() / "log" # 字体路径 -FONT_PATH = Path("resources/ttf/") +FONT_PATH = Path() / "resources" / "font" # 数据路径 -DATA_PATH = Path("data/") -# 临时图片路径 -TEMP_PATH = Path("resources/img/temp/") +DATA_PATH = Path() / "data" +# 临时数据路径 +TEMP_PATH = Path() / "resources" / "temp" -def init_path(): - global IMAGE_PATH, VOICE_PATH, TEXT_PATH, LOG_PATH, FONT_PATH, DATA_PATH, TEMP_PATH +def load_path(): + old_img_dir = Path() / "resources" / "img" + if not IMAGE_PATH.exists() and old_img_dir.exists(): + os.rename(old_img_dir, IMAGE_PATH) + old_voice_dir = Path() / "resources" / "voice" + if not RECORD_PATH.exists() and old_voice_dir.exists(): + os.rename(old_voice_dir, RECORD_PATH) + old_ttf_dir = Path() / "resources" / "ttf" + if not FONT_PATH.exists() and old_ttf_dir.exists(): + os.rename(old_ttf_dir, FONT_PATH) + old_txt_dir = Path() / "resources" / "txt" + if not TEXT_PATH.exists() and old_txt_dir.exists(): + os.rename(old_txt_dir, TEXT_PATH) IMAGE_PATH.mkdir(parents=True, exist_ok=True) - VOICE_PATH.mkdir(parents=True, exist_ok=True) + RECORD_PATH.mkdir(parents=True, exist_ok=True) TEXT_PATH.mkdir(parents=True, exist_ok=True) LOG_PATH.mkdir(parents=True, exist_ok=True) FONT_PATH.mkdir(parents=True, exist_ok=True) DATA_PATH.mkdir(parents=True, exist_ok=True) TEMP_PATH.mkdir(parents=True, exist_ok=True) - IMAGE_PATH = str(IMAGE_PATH.absolute()) + '/' - VOICE_PATH = str(VOICE_PATH.absolute()) + '/' - TEXT_PATH = str(TEXT_PATH.absolute()) + '/' - LOG_PATH = str(LOG_PATH.absolute()) + '/' - FONT_PATH = str(FONT_PATH.absolute()) + '/' - DATA_PATH = str(DATA_PATH.absolute()) + '/' - TEMP_PATH = str(TEMP_PATH.absolute()) + '/' - -init_path() +load_path() diff --git a/configs/utils/__init__.py b/configs/utils/__init__.py index 739d2118..d6158b3d 100644 --- a/configs/utils/__init__.py +++ b/configs/utils/__init__.py @@ -153,6 +153,20 @@ class ConfigsManager: self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True ) + def reload(self): + """ + 重新加载配置文件 + """ + _yaml = YAML() + temp_file = Path() / "configs" / "config.yaml" + if temp_file.exists(): + with open(temp_file, "r", encoding="utf8") as f: + temp = _yaml.load(f) + for key in temp.keys(): + for k in temp[key].keys(): + self._data[key][k]["value"] = temp[key][k] + self.save() + def get_admin_level_data(self): """ 获取管理插件等级 diff --git a/plugins/about.py b/plugins/about.py index d6833922..5feb5941 100644 --- a/plugins/about.py +++ b/plugins/about.py @@ -1,6 +1,4 @@ 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 @@ -29,7 +27,7 @@ about = on_regex("^关于$", priority=5, block=True, rule=to_me()) @about.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): ver_file = Path() / '__version__' version = None if ver_file.exists(): diff --git a/plugins/aconfig/__init__.py b/plugins/aconfig/__init__.py index a7dd57d3..27afa36e 100755 --- a/plugins/aconfig/__init__.py +++ b/plugins/aconfig/__init__.py @@ -1,15 +1,14 @@ -import random -from nonebot import on_keyword -import os from utils.message_builder import image from configs.path_config import IMAGE_PATH from nonebot import on_command from nonebot.rule import to_me -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent -from nonebot.adapters.cqhttp.permission import GROUP +from nonebot.adapters.onebot.v11 import GroupMessageEvent +from nonebot.adapters.onebot.v11.permission import GROUP from utils.utils import FreqLimiter from configs.config import NICKNAME +import random +from nonebot import on_keyword +import os __zx_plugin_name__ = "基本设置 [Hidden]" @@ -25,12 +24,12 @@ config_play_game = on_keyword({"打游戏"}, permission=GROUP, priority=1, block @config_play_game.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): if not _flmt.check(event.group_id): return _flmt.start_cd(event.group_id) await config_play_game.finish( - image(random.choice(os.listdir(IMAGE_PATH + "dayouxi/")), "dayouxi") + image(random.choice(os.listdir(IMAGE_PATH / "dayouxi")), "dayouxi") ) @@ -40,7 +39,7 @@ self_introduction = on_command( @self_introduction.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): if NICKNAME.find('真寻') != -1: result = ( "我叫绪山真寻\n" @@ -57,6 +56,6 @@ my_wife = on_keyword({"老婆"}, rule=to_me(), priority=5, block=True) @my_wife.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): await my_wife.finish(image("laopo.jpg", "other")) diff --git a/plugins/ai/__init__.py b/plugins/ai/__init__.py index 37bc87b0..322ee02f 100755 --- a/plugins/ai/__init__.py +++ b/plugins/ai/__init__.py @@ -1,17 +1,16 @@ from nonebot import on_message -from nonebot.adapters.cqhttp import ( +from nonebot.adapters.onebot.v11 import ( Bot, GroupMessageEvent, Message, MessageEvent, ) from nonebot.rule import to_me -from nonebot.typing import T_State - +from nonebot.params import CommandArg from models.friend_user import FriendUser from models.group_member_info import GroupInfoUser from services.log import logger -from utils.utils import get_message_text, get_message_img +from utils.utils import get_message_img from .data_source import get_chat_result, hello, no_result from configs.config import NICKNAME, Config @@ -36,15 +35,15 @@ __plugin_configs__ = { }, } Config.add_plugin_config( - "alapi", "ALAPI_TOKEN", None, help_="在https://admin.alapi.cn/user/login登录后获取token" + "alapi", "ALAPI_TOKEN", None, help_="在 https://admin.alapi.cn/user/login 登录后获取token" ) ai = on_message(rule=to_me(), priority=8) @ai.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() img = get_message_img(event.json()) if "CQ:xml" in str(event.get_message()): return @@ -69,7 +68,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): nickname = await FriendUser.get_friend_nickname(event.user_id) if not nickname: if isinstance(event, GroupMessageEvent): - nickname = event.sender.card if event.sender.card else event.sender.nickname + nickname = event.sender.card or event.sender.nickname else: nickname = event.sender.nickname result = await get_chat_result(msg, img, event.user_id, nickname) diff --git a/plugins/ai/data_source.py b/plugins/ai/data_source.py index 893f316a..30221678 100755 --- a/plugins/ai/data_source.py +++ b/plugins/ai/data_source.py @@ -20,7 +20,7 @@ check_url = "https://v2.alapi.cn/api/censor/text" index = 0 -anime_data = json.load(open(DATA_PATH + "anime.json", "r", encoding="utf8")) +anime_data = json.load(open(DATA_PATH / "anime.json", "r", encoding="utf8")) async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str) -> str: @@ -139,7 +139,7 @@ async def xie_ai(text: str) -> str: content = content.replace("{br}", "\n") if "提示" in content: content = content[: content.find("提示")] - if "淘宝" in content: + if "淘宝" in content or "taobao.com" in content: return "" while True: r = re.search("{face:(.*)}", content) @@ -170,7 +170,7 @@ def hello() -> str: "呼呼,叫俺干嘛", ) ) - img = random.choice(os.listdir(IMAGE_PATH + "zai/")) + img = random.choice(os.listdir(IMAGE_PATH / "zai")) if img[-4:] == ".gif": result += image(img, "zai") else: @@ -193,7 +193,7 @@ def no_result() -> str: "我!不!知!道!", ] ) - + image(random.choice(os.listdir(IMAGE_PATH + "noresult/")), "noresult") + + image(random.choice(os.listdir(IMAGE_PATH / "noresult")), "noresult") ) diff --git a/plugins/alapi/data_source.py b/plugins/alapi/_data_source.py old mode 100755 new mode 100644 similarity index 87% rename from plugins/alapi/data_source.py rename to plugins/alapi/_data_source.py index 26296c65..69f83aec --- a/plugins/alapi/data_source.py +++ b/plugins/alapi/_data_source.py @@ -1,49 +1,49 @@ -from nonebot.adapters.cqhttp import MessageSegment -from utils.image_utils import BuildImage -from utils.message_builder import image -from configs.path_config import IMAGE_PATH -from typing import Optional -from configs.config import Config -from utils.http_utils import AsyncHttpx - - -async def get_data(url: str, params: Optional[dict] = None) -> "Union[dict, str], int": - """ - 获取ALAPI数据 - :param url: 请求链接 - :param params: 参数 - """ - if not params: - params = {} - params["token"] = Config.get_config("alapi", "ALAPI_TOKEN") - try: - data = (await AsyncHttpx.get(url, params=params, timeout=5)).json() - if data["code"] == 200: - if not data["data"]: - return "没有搜索到...", 997 - return data, 200 - else: - return f'发生了错误...code:{data["code"]}', 999 - except TimeoutError: - return "超时了....", 998 - - -def gen_wbtop_pic(data: dict) -> MessageSegment: - """ - 生成微博热搜图片 - :param data: 微博热搜数据 - """ - 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 = 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 = 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) - text_bk.paste(img) - bk.paste(text_bk, (0, 280)) - return image(b64=bk.pic2bs4()) +from nonebot.adapters.onebot.v11 import MessageSegment +from utils.image_utils import BuildImage +from utils.message_builder import image +from configs.path_config import IMAGE_PATH +from typing import Optional, Tuple, Union +from configs.config import Config +from utils.http_utils import AsyncHttpx + + +async def get_data(url: str, params: Optional[dict] = None) -> Tuple[Union[dict, str], int]: + """ + 获取ALAPI数据 + :param url: 请求链接 + :param params: 参数 + """ + if not params: + params = {} + params["token"] = Config.get_config("alapi", "ALAPI_TOKEN") + try: + data = (await AsyncHttpx.get(url, params=params, timeout=5)).json() + if data["code"] == 200: + if not data["data"]: + return "没有搜索到...", 997 + return data, 200 + else: + return f'发生了错误...code:{data["code"]}', 999 + except TimeoutError: + return "超时了....", 998 + + +def gen_wbtop_pic(data: dict) -> MessageSegment: + """ + 生成微博热搜图片 + :param data: 微博热搜数据 + """ + 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 = 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 = 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) + text_bk.paste(img) + bk.paste(text_bk, (0, 280)) + return image(b64=bk.pic2bs4()) diff --git a/plugins/alapi/comments_163.py b/plugins/alapi/comments_163.py index ac43c1d2..2176162f 100755 --- a/plugins/alapi/comments_163.py +++ b/plugins/alapi/comments_163.py @@ -1,7 +1,6 @@ -from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent -from nonebot.typing import T_State -from .data_source import get_data +from nonebot import on_regex +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent +from ._data_source import get_data from services.log import logger __zx_plugin_name__ = "网易云热评" @@ -23,8 +22,8 @@ __plugin_settings__ = { } -comments_163 = on_command( - "网易云热评", aliases={"网易云评论", "到点了", "12点了"}, priority=5, block=True +comments_163 = on_regex( + "^(网易云热评|网易云评论|到点了|12点了)$", priority=5, block=True ) @@ -32,7 +31,7 @@ comments_163_url = "https://v2.alapi.cn/api/comment" @comments_163.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent): data, code = await get_data(comments_163_url) if code != 200: await comments_163.finish(data, at_sender=True) diff --git a/plugins/alapi/cover.py b/plugins/alapi/cover.py index 9f83a452..75cd3713 100755 --- a/plugins/alapi/cover.py +++ b/plugins/alapi/cover.py @@ -1,9 +1,8 @@ from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent -from nonebot.typing import T_State +from nonebot.adapters.onebot.v11 import MessageEvent, Message, GroupMessageEvent from utils.message_builder import image -from utils.utils import get_message_text -from .data_source import get_data +from nonebot.params import CommandArg +from ._data_source import get_data from services.log import logger __zx_plugin_name__ = "b封面" @@ -32,8 +31,8 @@ cover_url = "https://v2.alapi.cn/api/bilibili/cover" @cover.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() params = {"c": msg} data, code = await get_data(cover_url, params) if code != 200: diff --git a/plugins/alapi/jitang.py b/plugins/alapi/jitang.py index 3fe58ab7..4d907684 100755 --- a/plugins/alapi/jitang.py +++ b/plugins/alapi/jitang.py @@ -1,10 +1,7 @@ -from nonebot import on_command +from nonebot import on_regex from services.log import logger -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent -from nonebot.typing import T_State -from utils.http_utils import AsyncHttpx -from configs.config import Config -from .data_source import get_data +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent +from ._data_source import get_data __zx_plugin_name__ = "鸡汤" @@ -28,11 +25,11 @@ __plugin_settings__ = { url = "https://v2.alapi.cn/api/soul" -jitang = on_command("鸡汤", aliases={"毒鸡汤"}, priority=5, block=True) +jitang = on_regex("^毒?鸡汤$", priority=5, block=True) @jitang.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent): try: data, code = await get_data(url) if code != 200: diff --git a/plugins/alapi/poetry.py b/plugins/alapi/poetry.py index 8773117b..1c6ff10d 100755 --- a/plugins/alapi/poetry.py +++ b/plugins/alapi/poetry.py @@ -1,8 +1,7 @@ from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent -from nonebot.typing import T_State +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent from services.log import logger -from .data_source import get_data +from ._data_source import get_data __zx_plugin_name__ = "古诗" __plugin_usage__ = """usage: @@ -27,7 +26,7 @@ poetry_url = "https://v2.alapi.cn/api/shici" @poetry.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent): data, code = await get_data(poetry_url) if code != 200: await poetry.finish(data, at_sender=True) diff --git a/plugins/alapi/wbtop.py b/plugins/alapi/wbtop.py index 9d7ced17..bcbf4294 100755 --- a/plugins/alapi/wbtop.py +++ b/plugins/alapi/wbtop.py @@ -1,11 +1,10 @@ from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent -from nonebot.typing import T_State +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message +from nonebot.params import CommandArg from services.log import logger -from .data_source import get_data, gen_wbtop_pic -from utils.utils import get_message_text, is_number +from ._data_source import get_data, gen_wbtop_pic +from utils.utils import is_number from configs.path_config import IMAGE_PATH -from utils.message_builder import image from utils.http_utils import AsyncPlaywright import asyncio @@ -38,9 +37,9 @@ wbtop_data = [] @wbtop.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent, arg: Message = CommandArg()): global wbtop_data - msg = get_message_text(event.json()) + msg = arg.extract_plain_text().strip() if not wbtop_data or not msg: data, code = await get_data(wbtop_url) if code != 200: diff --git a/plugins/bilibili_sub/__init__.py b/plugins/bilibili_sub/__init__.py index c7d316d0..bcfe16d2 100755 --- a/plugins/bilibili_sub/__init__.py +++ b/plugins/bilibili_sub/__init__.py @@ -1,6 +1,6 @@ from nonebot import on_command from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent, Message +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message from .data_source import ( add_live_sub, delete_sub, @@ -13,10 +13,11 @@ from .data_source import ( ) from models.level_user import LevelUser from configs.config import Config -from utils.utils import get_message_text, is_number, scheduler, get_bot +from utils.utils import is_number, scheduler, get_bot from typing import Optional from services.log import logger from nonebot import Driver +from nonebot.params import CommandArg, ArgPlainText import nonebot __zx_plugin_name__ = "B站订阅" @@ -68,18 +69,9 @@ async def _(): sub_manager = SubManager() -@add_sub.args_parser -async def _(bot: Bot, event: MessageEvent, state: T_State): - season_data = state["season_data"] - msg = get_message_text(event.json()) - if not is_number(msg) or int(msg) < 1 or int(msg) > len(season_data): - await add_sub.reject("Id必须为数字且在范围内!请重新输入...") - state["id"] = season_data[int(msg) - 1]["media_id"] - - @add_sub.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()).split() +async def _(event: MessageEvent, state: T_State, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip().split() if len(msg) < 2: await add_sub.finish("参数不完全,请查看订阅帮助...") sub_type = msg[0] @@ -121,10 +113,13 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @add_sub.got("id") -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent, state: T_State, id_: str = ArgPlainText("id")): + season_data = state["season_data"] + if not is_number(id_) or int(id_) < 1 or int(id_) > len(season_data): + await add_sub.reject_arg("id", "Id必须为数字且在范围内!请重新输入...") + id_ = season_data[int(id_) - 1]["media_id"] sub_type = state["sub_type"] sub_user = state["sub_user"] - id_ = state["id"] if sub_type in ["主播", "直播"]: await add_sub.send(await add_live_sub(id_, sub_user)) elif sub_type.lower() in ["up", "用户"]: @@ -141,8 +136,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @del_sub.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() if not is_number(msg): await del_sub.finish("Id必须为数字!", at_sender=True) id_ = ( @@ -162,7 +157,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @show_sub_info.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent): if isinstance(event, GroupMessageEvent): id_ = f"{event.group_id}" else: diff --git a/plugins/bilibili_sub/data_source.py b/plugins/bilibili_sub/data_source.py index affdb537..e3a8645a 100755 --- a/plugins/bilibili_sub/data_source.py +++ b/plugins/bilibili_sub/data_source.py @@ -8,7 +8,6 @@ from utils.message_builder import image from bilibili_api.user import User from bilibili_api import user from typing import Optional -from pathlib import Path from configs.path_config import IMAGE_PATH from datetime import datetime from utils.browser import get_browser @@ -20,7 +19,7 @@ import random bilibili_search_url = "https://api.bilibili.com/x/web-interface/search/all/v2" -dynamic_path = Path(IMAGE_PATH) / "bilibili_sub" / "dynamic" +dynamic_path = IMAGE_PATH / "bilibili_sub" / "dynamic" dynamic_path.mkdir(exist_ok=True, parents=True) diff --git a/plugins/bilibili_sub/utils.py b/plugins/bilibili_sub/utils.py index 42699de1..74b2cd99 100755 --- a/plugins/bilibili_sub/utils.py +++ b/plugins/bilibili_sub/utils.py @@ -1,12 +1,11 @@ from utils.image_utils import BuildImage from configs.path_config import IMAGE_PATH from utils.http_utils import AsyncHttpx -from pathlib import Path from bilibili_api import user from io import BytesIO -BORDER_PATH = Path(IMAGE_PATH) / "border" +BORDER_PATH = IMAGE_PATH / "border" BORDER_PATH.mkdir(parents=True, exist_ok=True) diff --git a/plugins/bt/__init__.py b/plugins/bt/__init__.py index baecd6e3..2c85a504 100755 --- a/plugins/bt/__init__.py +++ b/plugins/bt/__init__.py @@ -1,12 +1,12 @@ from nonebot import on_command from .data_source import get_bt_info from services.log import logger -from nonebot.typing import T_State -from nonebot.adapters import Bot -from nonebot.adapters.cqhttp import PrivateMessageEvent -from utils.utils import get_message_text -from nonebot.adapters.cqhttp.permission import PRIVATE +from nonebot.adapters.onebot.v11 import PrivateMessageEvent, Message +from nonebot.adapters.onebot.v11.permission import PRIVATE from asyncio.exceptions import TimeoutError +from utils.utils import is_number +from nonebot.params import CommandArg, ArgStr +from nonebot.typing import T_State __zx_plugin_name__ = "磁力搜索" __plugin_usage__ = """ @@ -28,9 +28,7 @@ __plugin_settings__ = { "limit_superuser": False, "cmd": ["bt", "磁力搜索", "Bt", "BT"], } -__plugin_block_limit__ = { - "rst": "您有bt任务正在进行,请等待结束." -} +__plugin_block_limit__ = {"rst": "您有bt任务正在进行,请等待结束."} __plugin_configs__ = { "BT_MAX_NUM": { "value": 10, @@ -43,44 +41,37 @@ __plugin_configs__ = { bt = on_command("bt", permission=PRIVATE, priority=5, block=True) -@bt.args_parser -async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): - if str(event.get_message()) in ["取消", "算了"]: - await bt.finish("已取消操作..", at_sender=True) - msg = get_message_text(event.json()) - if not msg: - await bt.reject("你想搜索什么呢?", at_sender=True) - state["keyword"] = msg - state["page"] = "1" - - @bt.handle() -async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): - mp = get_message_text(event.json()) - if not mp: - return - mp = mp.split() - if len(mp) == 2: - state["keyword"] = mp[0] - state["page"] = mp[1] +async def _(state: T_State, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip().split() + if msg: + keyword = None + page = 1 + if n := len(msg): + keyword = msg[0] + if n > 1 and is_number(msg[1]) and int(msg[1]) > 0: + page = int(msg[1]) + state["keyword"] = keyword + state["page"] = page else: - state["keyword"] = mp[0] - state["page"] = "1" + state["page"] = 1 -@bt.got("keyword", prompt="虚空磁力?查什么GKD") -async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): - keyword = state["keyword"] - page = state["page"] - await bt.send("开始搜索....", at_sender=True) +@bt.got("keyword", prompt="请输入要查询的内容!") +async def _( + event: PrivateMessageEvent, + state: T_State, + keyword: str = ArgStr("keyword"), + page: str = ArgStr("page"), +): send_flag = False try: - async for title, itype, create_time, file_size, link in get_bt_info( + async for title, type_, create_time, file_size, link in get_bt_info( keyword, page ): await bt.send( f"标题:{title}\n" - f"类型:{itype}\n" + f"类型:{type_}\n" f"创建时间:{create_time}\n" f"文件大小:{file_size}\n" f"种子:{link}" diff --git a/plugins/bt/data_source.py b/plugins/bt/data_source.py index ddec06f5..42513987 100755 --- a/plugins/bt/data_source.py +++ b/plugins/bt/data_source.py @@ -12,7 +12,7 @@ if platform.system() == "Windows": url = "http://www.eclzz.world" -async def get_bt_info(keyword: str, page: str): +async def get_bt_info(keyword: str, page: int): """ 获取资源信息 :param keyword: 关键词 @@ -34,11 +34,11 @@ async def get_bt_info(keyword: str, page: str): .strip() ) spans = divs[2].find_all("span") - itype = spans[0].text + type_ = spans[0].text create_time = spans[1].find("b").text file_size = spans[2].find("b").text link = await get_download_link(divs[0].find("a")["href"]) - yield title, itype, create_time, file_size, link + yield title, type_, create_time, file_size, link async def get_download_link(_url: str) -> str: diff --git a/plugins/c_song/__init__.py b/plugins/c_song/__init__.py index d398d59a..0f8df8a6 100755 --- a/plugins/c_song/__init__.py +++ b/plugins/c_song/__init__.py @@ -1,5 +1,6 @@ from .music_163 import get_song_id, get_song_info -from nonebot.adapters.cqhttp import Bot, Event, GroupMessageEvent +from nonebot.adapters.onebot.v11 import Bot, Event, GroupMessageEvent, Message +from nonebot.params import CommandArg from nonebot.typing import T_State from services.log import logger from nonebot import on_command @@ -29,8 +30,8 @@ music = on_command("点歌", priority=5, block=True) @music.handle() -async def handle_first_receive(bot: Bot, event: Event, state: T_State): - args = str(event.get_message()).strip() +async def handle_first_receive(state: T_State, arg: Message = CommandArg()): + args = arg.extract_plain_text().strip() if args: state["song_name"] = args diff --git a/plugins/check/__init__.py b/plugins/check/__init__.py index dd008217..153512ad 100755 --- a/plugins/check/__init__.py +++ b/plugins/check/__init__.py @@ -1,7 +1,5 @@ from nonebot import on_command from .data_source import Check -from nonebot.adapters.cqhttp import Bot, Event -from nonebot.typing import T_State from nonebot.rule import to_me from nonebot.permission import SUPERUSER from utils.message_builder import image @@ -29,5 +27,5 @@ check_ = on_command( @check_.handle() -async def _(bot: Bot, event: Event, state: T_State): +async def _(): await check_.send(image(b64=await check.show())) diff --git a/plugins/check/data_source.py b/plugins/check/data_source.py index b843b8c8..cf24a4dc 100755 --- a/plugins/check/data_source.py +++ b/plugins/check/data_source.py @@ -4,7 +4,6 @@ from datetime import datetime from utils.http_utils import AsyncHttpx from utils.image_utils import BuildImage from configs.path_config import IMAGE_PATH -from pathlib import Path import asyncio from services.log import logger @@ -73,6 +72,6 @@ class Check: A.transparent(1) A.text((10, 10), rst) _x = max(width, height) - bk = BuildImage(_x + 100, _x + 100, background=Path(IMAGE_PATH) / "background" / "check" / "0.jpg") + bk = BuildImage(_x + 100, _x + 100, background=IMAGE_PATH / "background" / "check" / "0.jpg") bk.paste(A, alpha=True, center_type='center') return bk.pic2bs4() diff --git a/plugins/check_zhenxun_update/__init__.py b/plugins/check_zhenxun_update/__init__.py index 19633fd6..706ef971 100755 --- a/plugins/check_zhenxun_update/__init__.py +++ b/plugins/check_zhenxun_update/__init__.py @@ -1,4 +1,4 @@ -from nonebot.adapters.cqhttp import Bot, MessageEvent +from nonebot.adapters.onebot.v11 import Bot from nonebot.typing import T_State from nonebot.permission import SUPERUSER from nonebot import on_command @@ -45,7 +45,7 @@ restart = on_command( @update_zhenxun.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(bot: Bot): try: code, error = await check_update(bot) if error: @@ -67,13 +67,13 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @restart.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): if str(platform.system()).lower() == "windows": await restart.finish("暂无windows重启脚本...") @restart.got("flag", prompt="确定是否重启真寻?(重启失败咱们将失去联系,请谨慎!)") -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(state: T_State): flag = state["flag"] if flag.lower() in ["true", "是", "好", "确定", "确定是"]: await restart.send("开始重启真寻..请稍等...") @@ -107,8 +107,7 @@ async def _(): await bot.send_private_msg( user_id=int(list(bot.config.superusers)[0]), message=f"检测到真寻版本更新\n" - f"当前版本:{_version},最新版本:{latest_version}\n" - f"尝试自动更新...", + f"当前版本:{_version},最新版本:{latest_version}", ) # try: # code = await check_update(bot) diff --git a/plugins/check_zhenxun_update/data_source.py b/plugins/check_zhenxun_update/data_source.py index 77cb0cca..19a06055 100755 --- a/plugins/check_zhenxun_update/data_source.py +++ b/plugins/check_zhenxun_update/data_source.py @@ -1,4 +1,4 @@ -from nonebot.adapters.cqhttp import Bot, Message +from nonebot.adapters.onebot.v11 import Bot, Message from utils.image_utils import BuildImage from configs.path_config import IMAGE_PATH from utils.message_builder import image diff --git a/plugins/coser/__init__.py b/plugins/coser/__init__.py index 5c37c2d7..4b797b0a 100755 --- a/plugins/coser/__init__.py +++ b/plugins/coser/__init__.py @@ -1,6 +1,6 @@ -from nonebot import on_command +from nonebot import on_regex from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent +from nonebot.adapters.onebot.v11 import Bot, MessageEvent from utils.message_builder import image from services.log import logger from utils.manager import withdraw_message_manager @@ -31,12 +31,10 @@ __plugin_configs__ = { }, } -coser = on_command( - "cos", aliases={"coser", "括丝", "COS", "Cos", "cOS", "coS"}, priority=5, block=True -) +coser = on_regex("^(cos|COS|coser|括丝)$", priority=5, block=True) -url = "http://iw233.cn/API/cos.php" +url = "https://api.iyk0.com/cos" @coser.handle() diff --git a/plugins/dialogue/__init__.py b/plugins/dialogue/__init__.py index 58d85b5f..f7d1de7a 100755 --- a/plugins/dialogue/__init__.py +++ b/plugins/dialogue/__init__.py @@ -1,12 +1,12 @@ from nonebot import on_command -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent from nonebot.permission import SUPERUSER -from utils.utils import get_message_text, is_number, get_message_img +from utils.utils import is_number, get_message_img from utils.message_builder import image from utils.message_builder import text as _text from services.log import logger from utils.message_builder import at +from nonebot.params import CommandArg __zx_plugin_name__ = "联系管理员" @@ -58,10 +58,8 @@ reply = on_command("/t", priority=1, permission=SUPERUSER, block=True) @dialogue.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - uid = event.user_id - coffee = int(list(bot.config.superusers)[0]) - text = get_message_text(event.json()) +async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): + text = arg.extract_plain_text().strip() img_msg = _text("") for img in get_message_img(event.json()): img_msg += image(img) @@ -76,17 +74,18 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): group_name = (await bot.get_group_info(group_id=event.group_id))[ "group_name" ] - nickname = event.sender.card if event.sender.card else event.sender.nickname - await bot.send_private_msg( - user_id=coffee, - message=_text( - f"*****一份交流报告*****\n" - f"昵称:{nickname}({uid})\n" - f"群聊:{group_name}({group_id})\n" - f"消息:{text}" + nickname = event.sender.card or event.sender.nickname + for coffee in bot.config.superusers: + await bot.send_private_msg( + user_id=int(coffee), + message=_text( + f"*****一份交流报告*****\n" + f"昵称:{nickname}({event.user_id})\n" + f"群聊:{group_name}({group_id})\n" + f"消息:{text}" + ) + + img_msg, ) - + img_msg, - ) await dialogue.send( _text(f"您的话已发送至管理员!\n======\n{text}") + img_msg, at_sender=True ) @@ -99,12 +98,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): "msg": _text(text) + img_msg, } # print(dialogue_data) - logger.info(f"Q{uid}@群{group_id} 联系管理员:{coffee} text:{text}") + logger.info(f"Q{event.user_id}@群{group_id} 联系管理员:text:{text}") @reply.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() if not msg: result = "*****待回复消息总览*****\n" for key in dialogue_data.keys(): diff --git a/plugins/draw_card/__init__.py b/plugins/draw_card/__init__.py index 4a2a1126..4163c950 100755 --- a/plugins/draw_card/__init__.py +++ b/plugins/draw_card/__init__.py @@ -1,16 +1,13 @@ from nonebot import on_regex, on_keyword -from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message from nonebot.permission import SUPERUSER from nonebot.typing import T_State -from .genshin_handle import ( - genshin_draw, - update_genshin_info, - reset_count, - reload_genshin_pool, -) +from nonebot.params import RegexGroup +from utils.utils import scheduler +from .genshin_handle import genshin_draw, update_genshin_info, reset_count, reload_genshin_pool from .prts_handle import update_prts_info, prts_draw, reload_prts_pool from .pretty_handle import update_pretty_info, pretty_draw, reload_pretty_pool -from .guardian_handle import update_guardian_info, guardian_draw +from .guardian_handle import update_guardian_info, guardian_draw, reload_guardian_pool from .pcr_handle import update_pcr_info, pcr_draw from .azur_handle import update_azur_info, azur_draw from .fgo_handle import update_fgo_info, fgo_draw @@ -18,21 +15,12 @@ from .onmyoji_handle import update_onmyoji_info, onmyoji_draw from .update_game_info import update_info from .util import is_number, check_num from .rule import is_switch -from .config import ( - PRTS_FLAG, - PRETTY_FLAG, - GUARDIAN_FLAG, - GENSHIN_FLAG, - PCR_FLAG, - AZUR_FLAG, - FGO_FLAG, - ONMYOJI_FLAG, -) +from .config import draw_config from .async_update_game_info import async_update_game +from typing import Tuple, Any import re import asyncio -from utils.utils import scheduler -from services.log import logger + __zx_plugin_name__ = "游戏抽卡" __plugin_usage__ = """ @@ -101,81 +89,44 @@ __plugin_settings__ = { "cmd": ["游戏抽卡", "抽卡"], } +prts = on_regex(r'.*?方舟([1-9|一][0-9]{0,2}[抽|井|连])', rule=is_switch('prts'), priority=5, block=True) +prts_update = on_keyword({'更新方舟信息', '更新明日方舟信息'}, permission=SUPERUSER, priority=1, block=True) +prts_up_reload = on_keyword({'重载方舟卡池'}, priority=1, block=True) -prts = on_regex( - r".*?方舟[1-9|一][0-9]{0,2}[抽|井]", rule=is_switch("prts"), priority=5, block=True -) -prts_update = on_keyword( - {"更新方舟信息", "更新明日方舟信息"}, permission=SUPERUSER, priority=1, block=True -) -prts_up_reload = on_keyword({"重载方舟卡池"}, priority=1, block=True) +genshin = on_regex(r'.*?原神(武器|角色)?池?[1-9|一][0-9]{0,2}[抽|井|连]', rule=is_switch('genshin'), priority=5, block=True) +genshin_update = on_keyword({'更新原神信息'}, permission=SUPERUSER, priority=1, block=True) +genshin_reset = on_keyword({'重置原神抽卡'}, priority=1, block=True) +genshin_up_reload = on_keyword({'重载原神卡池'}, priority=1, block=True) -genshin = on_regex( - ".*?原神(武器|角色)?池?[1-9|一][0-9]{0,2}[抽|井]", - rule=is_switch("genshin"), - priority=5, - block=True, -) -genshin_update = on_keyword({"更新原神信息"}, permission=SUPERUSER, priority=1, block=True) -genshin_reset = on_keyword({"重置原神抽卡"}, priority=1, block=True) -genshin_up_reload = on_keyword({"重载原神卡池"}, priority=1, block=True) +pretty = on_regex(r'.*?马娘卡?[1-9|一][0-9]{0,2}[抽|井|连]', rule=is_switch('pretty'), priority=5, block=True) +pretty_update = on_keyword({'更新马娘信息', '更新赛马娘信息'}, permission=SUPERUSER, priority=1, block=True) +pretty_up_reload = on_keyword({'重载赛马娘卡池'}, priority=1, block=True) -pretty = on_regex( - ".*?马娘卡?[1-9|一][0-9]{0,2}[抽|井]", rule=is_switch("pretty"), priority=5, block=True -) -pretty_update = on_keyword( - {"更新马娘信息", "更新赛马娘信息"}, permission=SUPERUSER, priority=1, block=True -) -pretty_up_reload = on_keyword({"重载赛马娘卡池"}, priority=1, block=True) +guardian = on_regex(r'.*?坎公骑冠剑武?器?[1-9|一][0-9]{0,2}[抽|井|连]', rule=is_switch('guardian'), priority=5, block=True) +guardian_update = on_keyword({'更新坎公骑冠剑信息'}, permission=SUPERUSER, priority=1, block=True) +guardian_up_reload = on_keyword({'重载坎公骑冠剑卡池'}, priority=1, block=True) -guardian = on_regex( - ".*?坎公骑冠剑武?器?[1-9|一][0-9]{0,2}[抽|井]", - rule=is_switch("guardian"), - priority=5, - block=True, -) -guardian_update = on_keyword( - {"更新坎公骑冠剑信息"}, permission=SUPERUSER, priority=1, block=True -) +pcr = on_regex(r'.*?(pcr|公主连结|公主连接|公主链接|公主焊接)[1-9|一][0-9]{0,2}[抽|井|连]', rule=is_switch('pcr'), priority=5, block=True) +pcr_update = on_keyword({'更新pcr信息', '更新公主连结信息'}, permission=SUPERUSER, priority=1, block=True) -pcr = on_regex( - ".*?(pcr|公主连结|公主连接|公主链接|公主焊接)[1-9|一][0-9]{0,2}[抽|井]", - rule=is_switch("pcr"), - priority=5, - block=True, -) -pcr_update = on_keyword( - {"更新pcr信息", "更新公主连结信息"}, permission=SUPERUSER, priority=1, block=True -) +azur = on_regex(r'.*?碧蓝航?线?(轻型|重型|特型)池?[1-9|一][0-9]{0,2}[抽|连]', rule=is_switch('azur'), priority=5, block=True) +azur_update = on_keyword({'更新碧蓝信息', '更新碧蓝航线信息'}, permission=SUPERUSER, priority=1, block=True) -azur = on_regex( - ".*?碧蓝航?线?(轻型|重型|特型)池?[1-9|一][0-9]{0,2}[抽]", - rule=is_switch("azur"), - priority=5, - block=True, -) -azur_update = on_keyword( - {"更新碧蓝信息", "更新碧蓝航线信息"}, permission=SUPERUSER, priority=1, block=True -) +fgo = on_regex(r'.*?fgo[1-9|一][0-9]{0,2}[抽|连]', rule=is_switch('fgo'), priority=5, block=True) +fgo_update = on_keyword({'更新fgo信息'}, permission=SUPERUSER, priority=1, block=True) -fgo = on_regex( - ".*?fgo[1-9|一][0-9]{0,2}[抽]", rule=is_switch("fgo"), priority=5, block=True -) -fgo_update = on_keyword({"更新fgo信息"}, permission=SUPERUSER, priority=1, block=True) - -onmyoji = on_regex( - ".*?阴阳师[1-9|一][0-9]{0,2}[抽]", rule=is_switch("onmyoji"), priority=5, block=True -) -onmyoji_update = on_keyword({"更新阴阳师信息"}, permission=SUPERUSER, priority=1, block=True) +onmyoji = on_regex(r'.*?阴阳师[1-9|一][0-9]{0,2}[抽|连]', rule=is_switch('onmyoji'), priority=5, block=True) +onmyoji_update = on_keyword({'更新阴阳师信息'}, permission=SUPERUSER, priority=1, block=True) @prts.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(bot: Bot, event: MessageEvent, state: T_State, reg: Tuple[Any, ...] = RegexGroup()): msg = str(event.get_message()).strip() - if msg in ["方舟一井", "方舟1井"]: + print(reg) + if msg in ['方舟一井', '方舟1井']: num = 300 else: - rmsg = re.search(r".*?方舟(.*)抽", msg) + rmsg = re.search(r'.*?方舟(.*)[抽|连]', msg) if rmsg: num, flag = check_num(rmsg.group(1), 300) if not flag: @@ -183,31 +134,28 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): else: return await prts.send(await prts_draw(int(num)), at_sender=True) - logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 方舟 {num}抽" - ) @prts_up_reload.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): text = await reload_prts_pool() - await prts_up_reload.finish(Message(f"重载完成!\n{text}")) + await prts_up_reload.finish(Message(f'重载完成!\n{text}')) @genshin.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - rmsg = re.search(r".*?原神(武器|角色)?池?(.*)[抽|井]", msg) + rmsg = re.search(r'.*?原神(武器|角色)?池?(.*)[抽|井|连]', msg) if rmsg: pool_name = rmsg.group(1) - if pool_name == "武器": - pool_name = "arms" - elif pool_name == "角色": - pool_name = "char" + if pool_name == '武器': + pool_name = 'arms' + elif pool_name == '角色': + pool_name = 'char' else: - pool_name = "" + pool_name = '' num = rmsg.group(2) - if msg.find("一井") != -1 or msg.find("1井") != -1: + if msg.find('一井') != -1 or msg.find('1井') != -1: num = 180 else: num, flag = check_num(num, 180) @@ -215,94 +163,89 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): await genshin.finish(num, at_sender=True) else: return - await genshin.send( - await genshin_draw(event.user_id, int(num), pool_name), at_sender=True - ) - logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 原神 {num}抽" - ) + await genshin.send(await genshin_draw(event.user_id, int(num), pool_name), at_sender=True) @genshin_up_reload.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): text = await reload_genshin_pool() - await genshin_reset.finish(Message(f"重载成功!\n{text}")) + await genshin_reset.finish(Message(f'重载成功!\n{text}')) @genshin_reset.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): reset_count(event.user_id) - await genshin_reset.send("重置了原神抽卡次数", at_sender=True) + await genshin_reset.send('重置了原神抽卡次数', at_sender=True) @pretty.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - if msg.find("1井") != -1 or msg.find("一井") != -1: + if msg.find('1井') != -1 or msg.find('一井') != -1: num = 200 if msg.find("卡") == -1: - pool_name = "char" + pool_name = 'char' else: - pool_name = "card" + pool_name = 'card' else: - rmsg = re.search(r".*?马娘(.*)抽", msg) + rmsg = re.search(r'.*?马娘(.*)[抽|连]', msg) if rmsg: num = rmsg.group(1) - if num[0] == "卡": + if num[0] == '卡': num = num[1:] - pool_name = "card" + pool_name = 'card' else: - pool_name = "char" + pool_name = 'char' num, flag = check_num(num, 200) if not flag: await pretty.finish(num, at_sender=True) else: return await pretty.send(await pretty_draw(int(num), pool_name), at_sender=True) - logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 赛马娘 {num}抽" - ) @pretty_up_reload.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): text = await reload_pretty_pool() - await genshin_reset.finish(Message(f"重载成功!\n{text}")) + await genshin_reset.finish(Message(f'重载成功!\n{text}')) @guardian.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - pool_name = "char" - if msg.find("1井") != -1 or msg.find("一井") != -1: + pool_name = 'char' + if msg.find('1井') != -1 or msg.find('一井') != -1: num = 300 - if msg.find("武器") != -1: - pool_name = "arms" + if msg.find('武器') != -1: + pool_name = 'arms' else: - rmsg = re.search(r".*?坎公骑冠剑(.*)抽", msg) + rmsg = re.search(r'.*?坎公骑冠剑(.*)[抽|连]', msg) if rmsg: num = rmsg.group(1) - if num.find("武器") != -1: - pool_name = "arms" - num = num.replace("武器", "") + if num.find('武器') != -1: + pool_name = 'arms' + num = num.replace('武器', '') num, flag = check_num(num, 300) if not flag: await guardian.finish(num, at_sender=True) else: return await guardian.send(await guardian_draw(int(num), pool_name), at_sender=True) - logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 坎公骑冠剑 {num}抽" - ) + + +@guardian_up_reload.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State): + text = await reload_guardian_pool() + await genshin_reset.finish(Message(f'重载成功!\n{text}')) @pcr.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - if msg.find("1井") != -1 or msg.find("一井") != -1: + if msg.find('1井') != -1 or msg.find('一井') != -1: num = 300 else: - rmsg = re.search(r".*?(pcr|公主连结)(.*)[抽|井]", msg) + rmsg = re.search(r'.*?(pcr|公主连结)(.*)[抽|井|连]', msg) if rmsg: num, flag = check_num(rmsg.group(2), 300) if not flag: @@ -310,15 +253,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): else: return await pcr.send(await pcr_draw(int(num)), at_sender=True) - logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 公主连结 {num}抽" - ) @azur.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - rmsg = re.search(".*?碧蓝航?线?(轻型|重型|特型)池?(.*)[抽]", msg) + rmsg = re.search(r'.*?碧蓝航?线?(轻型|重型|特型)池?(.*)[抽|连]', msg) if rmsg: pool_name = rmsg.group(1) num, flag = check_num(rmsg.group(2), 300) @@ -327,15 +267,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): else: return await azur.send(await azur_draw(int(num), pool_name), at_sender=True) - logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 碧蓝航线 {num}抽" - ) @fgo.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - rmsg = re.search(".*?fgo(.*)抽", msg) + rmsg = re.search(r'.*?fgo(.*)[抽|连]', msg) if rmsg: num, flag = check_num(rmsg.group(1), 300) if not flag: @@ -343,15 +280,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): else: return await fgo.send(await fgo_draw(int(num)), at_sender=True) - logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) fgo {num}抽" - ) @onmyoji.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - rmsg = re.search(".*?阴阳师(.*)抽", msg) + rmsg = re.search(r'.*?阴阳师(.*)[抽|连]', msg) if rmsg: num, flag = check_num(rmsg.group(1), 300) if not flag: @@ -359,118 +293,122 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): else: return await onmyoji.send(await onmyoji_draw(int(num)), at_sender=True) - logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 阴阳师 {num}抽" - ) @prts_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_prts_info() - await prts_update.finish("更新完成!") + await prts_update.finish('更新完成!') @genshin_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_genshin_info() - await genshin_update.finish("更新完成!") + await genshin_update.finish('更新完成!') @pretty_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_pretty_info() - await genshin_update.finish("更新完成!") + await genshin_update.finish('更新完成!') @guardian_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_guardian_info() - await genshin_update.finish("更新完成!") + await genshin_update.finish('更新完成!') @pcr_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_pcr_info() - await genshin_update.finish("更新完成!") + await genshin_update.finish('更新完成!') @azur_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_azur_info() - await genshin_update.finish("更新完成!") + await genshin_update.finish('更新完成!') @fgo_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_fgo_info() - await genshin_update.finish("更新完成!") + await genshin_update.finish('更新完成!') @onmyoji_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_onmyoji_info() - await genshin_update.finish("更新完成!") + await genshin_update.finish('更新完成!') # 更新资源 @scheduler.scheduled_job( - "cron", + 'cron', hour=4, minute=1, ) async def _(): tasks = [] - if PRTS_FLAG: + if draw_config.PRTS_FLAG: tasks.append(asyncio.ensure_future(update_prts_info())) - if GENSHIN_FLAG: + if draw_config.GENSHIN_FLAG: tasks.append(asyncio.ensure_future(update_genshin_info())) - if PRETTY_FLAG: + if draw_config.PRETTY_FLAG: tasks.append(asyncio.ensure_future(update_pretty_info())) - if GUARDIAN_FLAG: + if draw_config.GUARDIAN_FLAG: tasks.append(asyncio.ensure_future(update_guardian_info())) - if PCR_FLAG: + if draw_config.PCR_FLAG: tasks.append(asyncio.ensure_future(update_pcr_info())) - if AZUR_FLAG: + if draw_config.AZUR_FLAG: tasks.append(asyncio.ensure_future(update_azur_info())) - if FGO_FLAG: + if draw_config.FGO_FLAG: tasks.append(asyncio.ensure_future(update_fgo_info())) - if ONMYOJI_FLAG: + if draw_config.ONMYOJI_FLAG: tasks.append(asyncio.ensure_future(update_onmyoji_info())) await asyncio.gather(*tasks) - logger.info("draw_card 抽卡自动更新完成...") # 每天四点重载方舟up卡池 @scheduler.scheduled_job( - "cron", + 'cron', hour=4, minute=1, ) async def _(): - if PRTS_FLAG: + if draw_config.PRTS_FLAG: await reload_prts_pool() - logger.info("自动重载方舟卡池UP成功") # 每天四点重载赛马娘up卡池 @scheduler.scheduled_job( - "cron", + 'cron', hour=4, minute=1, ) async def _(): - if PRETTY_FLAG: + if draw_config.PRETTY_FLAG: await reload_pretty_pool() - logger.info("自动重载赛马娘UP成功") # 每天下午六点点重载原神up卡池 @scheduler.scheduled_job( - "cron", + 'cron', hour=18, minute=1, ) async def _(): - if PRTS_FLAG: + if draw_config.PRTS_FLAG: await reload_genshin_pool() - logger.info("自动重载原神卡池UP成功") + + +# 重载坎公骑冠剑卡池 +@scheduler.scheduled_job( + 'cron', + hour=4, + minute=1, +) +async def _(): + if draw_config.GUARDIAN_FLAG: + await reload_guardian_pool() diff --git a/plugins/draw_card/announcement.py b/plugins/draw_card/announcement.py index cb8b1813..2bf84da2 100755 --- a/plugins/draw_card/announcement.py +++ b/plugins/draw_card/announcement.py @@ -1,11 +1,11 @@ from bs4 import BeautifulSoup -from datetime import datetime, timedelta -from .config import DRAW_PATH -from pathlib import Path -from asyncio.exceptions import TimeoutError -from services.log import logger -from utils.http_utils import AsyncHttpx import re +from datetime import datetime, timedelta +from .config import DRAW_DATA_PATH +from asyncio.exceptions import TimeoutError +from nonebot.log import logger +from utils.http_utils import AsyncHttpx + try: import ujson as json except ModuleNotFoundError: @@ -13,10 +13,10 @@ except ModuleNotFoundError: headers = {'User-Agent': '"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)"'} -prts_up_char = Path(DRAW_PATH + "/draw_card_up/prts_up_char.json") -genshin_up_char = Path(DRAW_PATH + "/draw_card_up/genshin_up_char.json") -pretty_up_char = Path(DRAW_PATH + "/draw_card_up/pretty_up_char.json") -guardian_up_char = Path(DRAW_PATH + "/draw_card_up/guardian_up_char.json") +prts_up_char = DRAW_DATA_PATH / "draw_card_up" / "prts_up_char.json" +genshin_up_char = DRAW_DATA_PATH / "draw_card_up" / "genshin_up_char.json" +pretty_up_char = DRAW_DATA_PATH / "draw_card_up" / "pretty_up_char.json" +guardian_up_char = DRAW_DATA_PATH / "draw_card_up" / "guardian_up_char.json" prts_url = "https://ak.hypergryph.com/news.html" genshin_url = "https://wiki.biligame.com/ys/%E7%A5%88%E6%84%BF" @@ -26,37 +26,37 @@ guardian_url = "https://wiki.biligame.com/gt/%E9%A6%96%E9%A1%B5" # 是否过时 def is_expired(data: dict): - try: - times = data['time'].split('-') - for i in range(len(times)): - times[i] = str(datetime.now().year) + '-' + times[i].split('日')[0].strip().replace('月', '-') - start_date = datetime.strptime(times[0], '%Y-%m-%d').date() - end_date = datetime.strptime(times[1], '%Y-%m-%d').date() - now = datetime.now().date() - except ValueError: - return False + times = data['time'].split('-') + for i in range(len(times)): + times[i] = str(datetime.now().year) + '-' + times[i].split('日')[0].strip().replace('月', '-') + start_date = datetime.strptime(times[0], '%Y-%m-%d').date() + end_date = datetime.strptime(times[1], '%Y-%m-%d').date() + now = datetime.now().date() return not start_date <= now <= end_date # 检查写入 def check_write(data: dict, up_char_file): - if is_expired(data['char']): - for x in list(data.keys()): - data[x]['title'] = '' - else: - with open(up_char_file, 'w', encoding='utf8') as f: - json.dump(data, f, indent=4, ensure_ascii=False) - if not up_char_file.exists(): - with open(up_char_file, 'w', encoding='utf8') as f: - json.dump(data, f, indent=4, ensure_ascii=False) - else: - with open(up_char_file, 'r', encoding='utf8') as f: - old_data = json.load(f) - if is_expired(old_data['char']): - return old_data + try: + if is_expired(data['char']): + for x in list(data.keys()): + data[x]['title'] = '' else: with open(up_char_file, 'w', encoding='utf8') as f: json.dump(data, f, indent=4, ensure_ascii=False) + if not up_char_file.exists(): + with open(up_char_file, 'w', encoding='utf8') as f: + json.dump(data, f, indent=4, ensure_ascii=False) + else: + with open(up_char_file, 'r', encoding='utf8') as f: + old_data = json.load(f) + if is_expired(old_data['char']): + return old_data + else: + with open(up_char_file, 'w', encoding='utf8') as f: + json.dump(data, f, indent=4, ensure_ascii=False) + except ValueError: + pass return data @@ -66,17 +66,22 @@ class PrtsAnnouncement: self.game_name = '明日方舟' async def _get_announcement_text(self): - text = (await AsyncHttpx.get(prts_url)).text - soup = BeautifulSoup(text, 'lxml') + res = await AsyncHttpx.get(prts_url, timeout=7) + soup = BeautifulSoup(res.text, 'lxml') ol = soup.find('ol', {'class': 'articleList active', 'data-category-key': 'LATEST'}) for li in ol: - itype = li.find('span', {'class': 'articleItemCate'}).text - if itype == '活动': + type_ = li.find('span', {'class': 'articleItemCate'}).text + if type_ == '活动': a = li.find('a')['href'] - return (await AsyncHttpx.get(f'https://ak.hypergryph.com{a}')).text - + return (await AsyncHttpx.get(f'https://ak.hypergryph.com{a}', timeout=7)).text + async def update_up_char(self): prts_up_char.parent.mkdir(parents=True, exist_ok=True) + if prts_up_char.exists(): + with open(prts_up_char, 'r', encoding='utf8') as f: + data = json.load(f) + if not data.get('char'): + prts_up_char.unlink() try: data = {'char': {'up_char': {'6': {}, '5': {}, '4': {}}, 'title': '', 'time': '', 'pool_img': ''}} text = await self._get_announcement_text() @@ -145,7 +150,7 @@ class GenshinAnnouncement: self.game_name = '原神' async def _get_announcement_text(self): - return (await AsyncHttpx.get(genshin_url)).text + return (await AsyncHttpx.get(genshin_url, timeout=7)).text async def update_up_char(self): genshin_up_char.parent.mkdir(exist_ok=True, parents=True) @@ -162,34 +167,34 @@ class GenshinAnnouncement: trs = table.find('tbody').find_all('tr') pool_img = trs[0].find('th').find('img') if pool_img['title'].find('角色活动') == -1: - itype = 'arms' + type_ = 'arms' else: - itype = 'char' + type_ = 'char' try: - data[itype]['pool_img'] = str(pool_img['srcset']).split(' ')[0] + data[type_]['pool_img'] = str(pool_img['srcset']).split(' ')[0] except KeyError: - data[itype]['pool_img'] = pool_img['src'] - data[itype]['title'] = str(pool_img['title']).split(f'期{"角色" if itype == "char" else "武器"}')[0][:-3] - data[itype]['time'] = trs[1].find('td').text - if data[itype]['time'][-1] == '\n': - data[itype]['time'] = data[itype]['time'][:-1] - if '版本更新后' in data[itype]['time']: - sp = data[itype]['time'].split('~') + data[type_]['pool_img'] = pool_img['src'] + data[type_]['title'] = str(pool_img['title']).split(f'期{"角色" if type_ == "char" else "武器"}')[0][:-3] + data[type_]['time'] = trs[1].find('td').text + if data[type_]['time'][-1] == '\n': + data[type_]['time'] = data[type_]['time'][:-1] + if '版本更新后' in data[type_]['time']: + sp = data[type_]['time'].split('~') end_time = datetime.strptime(sp[1].strip(), "%Y/%m/%d %H:%M") start_time = end_time - timedelta(days=20) - data[itype]['time'] = start_time.strftime('%Y/%m/%d') + ' ~ ' + end_time.strftime('%Y/%m/%d') + data[type_]['time'] = start_time.strftime('%Y/%m/%d') + ' ~ ' + end_time.strftime('%Y/%m/%d') tmp = '' - for tm in data[itype]['time'].split('~'): + for tm in data[type_]['time'].split('~'): date_time_sp = tm.split('/') date_time_sp[2] = date_time_sp[2].strip().replace(' ', '日 ') tmp += date_time_sp[1] + '月' + date_time_sp[2] + ' - ' - data[itype]['time'] = tmp[:-2].strip() + data[type_]['time'] = tmp[:-2].strip() for a in trs[2].find('td').find_all('a'): char_name = a['title'] - data[itype]['up_char']['5'][char_name] = "50" + data[type_]['up_char']['5'][char_name] = "50" for a in trs[3].find('td').find_all('a'): char_name = a['title'] - data[itype]['up_char']['4'][char_name] = "50" + data[type_]['up_char']['4'][char_name] = "50" except TimeoutError: logger.warning(f'更新原神UP池信息超时...') if genshin_up_char.exists(): @@ -214,10 +219,9 @@ class PrettyAnnouncement: self.game_name = '赛马娘' async def _get_announcement_text(self): - text = (await AsyncHttpx.get(pretty_url)).text - soup = BeautifulSoup(text, 'lxml') + res = await AsyncHttpx.get(pretty_url, timeout=7) + soup = BeautifulSoup(res.text, 'lxml') divs = soup.find('div', {'id': 'mw-content-text'}).find('div').find_all('div') - title = " " for div in divs: a = div.find('a') try: @@ -227,10 +231,9 @@ class PrettyAnnouncement: if title.find('新角色追加') != -1: url = a['href'] break - return (await AsyncHttpx.get(f'https://wiki.biligame.com/{url}')).text, title[:-2] + return (await AsyncHttpx.get(f'https://wiki.biligame.com/{url}', timeout=7)).text, title[:-2] async def update_up_char(self): - pretty_up_char.parent.mkdir(exist_ok=True, parents=True) data = { 'char': {'up_char': {'3': {}, '2': {}, '1': {}}, 'title': '', 'time': '', 'pool_img': ''}, 'card': {'up_char': {'3': {}, '2': {}, '1': {}}, 'title': '', 'time': '', 'pool_img': ''} @@ -243,12 +246,14 @@ class PrettyAnnouncement: context = soup.find('div', {'class': 'mw-parser-output'}) data['char']['title'] = title data['card']['title'] = title - r = re.search(r'(\d{1,2}/\d{1,2} \d{1,2}:\d{1,2} ~ \d{1,2}/\d{1,2} \d{1,2}:\d{1,2})', str(context.text)) - if r: - time = str(r.group(1)) + for big in context.find_all('big'): + r = re.search(r'\d{1,2}/\d{1,2} \d{1,2}:\d{1,2}', str(big.text)) + if r: + time = str(big.text) + break else: - logger.error('赛马娘UP无法找到活动日期....取消更新UP池子...') - return check_write(data, pretty_up_char) + logger.warning('赛马娘UP无法找到活动日期....取消更新UP池子...') + return time = time.replace('~', '-').replace('/', '月').split(' ') time = time[0] + '日 ' + time[1] + ' - ' + time[3] + '日 ' + time[4] data['char']['time'] = time @@ -309,7 +314,7 @@ class PrettyAnnouncement: if star == 'R': data['card']['up_char']['1'][char_name] = '70' # 日文->中文 - with open(DRAW_PATH + 'pretty_card.json', 'r', encoding='utf8') as f: + with open(DRAW_DATA_PATH / 'pretty_card.json', 'r', encoding='utf8') as f: all_data = json.load(f) for star in data['card']['up_char'].keys(): for name in list(data['card']['up_char'][star].keys()): @@ -338,7 +343,7 @@ class GuardianAnnouncement: self.game_name = '坎公骑冠剑' async def _get_announcement_text(self): - return (await AsyncHttpx.get(guardian_url)).text + return (await AsyncHttpx.get(guardian_url, timeout=7)).text async def update_up_char(self): data = { diff --git a/plugins/draw_card/async_update_game_info.py b/plugins/draw_card/async_update_game_info.py index efb9e92d..c6dad146 100755 --- a/plugins/draw_card/async_update_game_info.py +++ b/plugins/draw_card/async_update_game_info.py @@ -1,7 +1,6 @@ import asyncio import nonebot -import os -from services.log import logger +from nonebot.log import logger from .pcr_handle import update_pcr_info, init_pcr_data from .azur_handle import update_azur_info, init_azur_data from .prts_handle import update_prts_info, init_prts_data @@ -10,11 +9,10 @@ from .guardian_handle import update_guardian_info, init_guardian_data from .genshin_handle import update_genshin_info, init_genshin_data from .fgo_handle import update_fgo_info, init_fgo_data from .onmyoji_handle import update_onmyoji_info, init_onmyoji_data -from .config import DRAW_PATH, PRTS_FLAG, PRETTY_FLAG, GUARDIAN_FLAG, PCR_FLAG, AZUR_FLAG, GENSHIN_FLAG, FGO_FLAG, \ - ONMYOJI_FLAG +from .config import draw_config, DRAW_DATA_PATH -driver: nonebot.Driver = nonebot.get_driver() +driver = nonebot.get_driver() @driver.on_startup @@ -22,49 +20,44 @@ async def async_update_game(): tasks = [] init_lst = [init_pcr_data, init_pretty_data, init_azur_data, init_prts_data, init_genshin_data, init_guardian_data, init_fgo_data, init_onmyoji_data] - if PRTS_FLAG and not os.path.exists(DRAW_PATH + 'prts.json'): + if draw_config.PRTS_FLAG and not (DRAW_DATA_PATH / 'prts.json').exists(): tasks.append(asyncio.ensure_future(update_prts_info())) init_lst.remove(init_prts_data) - if PRETTY_FLAG and (not os.path.exists(DRAW_PATH + 'pretty.json') or - not os.path.exists(DRAW_PATH + 'pretty_card.json')): + if draw_config.PRETTY_FLAG and (not (DRAW_DATA_PATH / 'pretty.json').exists() or + not (DRAW_DATA_PATH / 'pretty_card.json').exists()): tasks.append(asyncio.ensure_future(update_pretty_info())) init_lst.remove(init_pretty_data) - if GUARDIAN_FLAG and not os.path.exists(DRAW_PATH + 'guardian.json'): + if draw_config.GUARDIAN_FLAG and not (DRAW_DATA_PATH / 'guardian.json').exists(): tasks.append(asyncio.ensure_future(update_guardian_info())) + init_lst.remove(init_guardian_data) - if PCR_FLAG and not os.path.exists(DRAW_PATH + 'pcr.json'): + if draw_config.PCR_FLAG and not (DRAW_DATA_PATH / 'pcr.json').exists(): tasks.append(asyncio.ensure_future(update_pcr_info())) init_lst.remove(init_pcr_data) - if GENSHIN_FLAG and (not os.path.exists(DRAW_PATH + 'genshin.json') or - not os.path.exists(DRAW_PATH + 'genshin_arms.json')): + if draw_config.GENSHIN_FLAG and (not (DRAW_DATA_PATH / 'genshin.json').exists() or + not (DRAW_DATA_PATH / 'genshin_arms.json').exists()): tasks.append(asyncio.ensure_future(update_genshin_info())) init_lst.remove(init_genshin_data) - if AZUR_FLAG and not os.path.exists(DRAW_PATH + 'azur.json'): + if draw_config.AZUR_FLAG and not (DRAW_DATA_PATH / 'azur.json').exists(): tasks.append(asyncio.ensure_future(update_azur_info())) init_lst.remove(init_azur_data) - if FGO_FLAG and (not os.path.exists(DRAW_PATH + 'fgo.json') or - not os.path.exists(DRAW_PATH + 'fgo_card.json')): + if draw_config.FGO_FLAG and (not (DRAW_DATA_PATH / 'fgo.json').exists() or + not (DRAW_DATA_PATH / 'fgo_card.json').exists()): tasks.append(asyncio.ensure_future(update_fgo_info())) init_lst.remove(init_fgo_data) - if ONMYOJI_FLAG and not os.path.exists(DRAW_PATH + 'onmyoji.json'): + if draw_config.ONMYOJI_FLAG and not (DRAW_DATA_PATH / 'onmyoji.json').exists(): tasks.append(asyncio.ensure_future(update_onmyoji_info())) init_lst.remove(init_onmyoji_data) - try: await asyncio.gather(*tasks) for func in init_lst: await func() except asyncio.exceptions.CancelledError: - logger.info('更新异常:CancelledError,再次更新...') + logger.warning('更新异常:CancelledError,再次更新...') await async_update_game() - - - - - diff --git a/plugins/draw_card/azur_handle.py b/plugins/draw_card/azur_handle.py index 01a18b27..bf4ce191 100755 --- a/plugins/draw_card/azur_handle.py +++ b/plugins/draw_card/azur_handle.py @@ -1,9 +1,8 @@ - -from nonebot.adapters.cqhttp import MessageSegment +from nonebot.adapters.onebot.v11 import MessageSegment import random from .update_game_simple_info import update_simple_info from .util import generate_img, init_star_rst, BaseData, set_list, get_star, max_card, format_card_information -from .config import AZUR_ONE_P, AZUR_TWO_P, AZUR_THREE_P, AZUR_FOUR_P, AZUR_FLAG, DRAW_PATH +from .config import draw_config, DRAW_DATA_PATH from dataclasses import dataclass from .init_card_pool import init_game_pool try: @@ -16,7 +15,7 @@ ALL_CHAR = [] @dataclass class AzurChar(BaseData): - itype: str # 舰娘类型 + type_: str # 舰娘类型 async def azur_draw(count: int, pool_name: str): @@ -42,22 +41,22 @@ async def update_azur_info(): async def init_azur_data(): global ALL_CHAR - if AZUR_FLAG: - with open(DRAW_PATH + 'azur.json', 'r', encoding='utf8') as f: + if draw_config.AZUR_FLAG: + with (DRAW_DATA_PATH / 'azur.json').open('r', encoding='utf8') as f: azur_dict = json.load(f) ALL_CHAR = init_game_pool('azur', azur_dict, AzurChar) # 抽取卡池 -def _get_azur_card(pool_name: str): +def _get_azur_card(pool_name: str, mode: int = 1): global ALL_CHAR + azur_config = draw_config.azur if pool_name == '轻型': - itype = ['驱逐', '轻巡', '维修'] + type_ = ['驱逐', '轻巡', '维修'] elif pool_name == '重型': - itype = ['重巡', '战列', '战巡', '重炮'] + type_ = ['重巡', '战列', '战巡', '重炮'] else: - itype = ['维修', '潜艇', '重巡', '轻航', '航母'] - star = get_star([4, 3, 2, 1], [AZUR_FOUR_P, AZUR_THREE_P, AZUR_TWO_P, AZUR_ONE_P]) - chars = [x for x in ALL_CHAR if x.star == star and x.itype in itype and not x.limited] + type_ = ['维修', '潜艇', '重巡', '轻航', '航母'] + star = get_star([4, 3, 2, 1], [azur_config.AZUR_FOUR_P, azur_config.AZUR_THREE_P, azur_config.AZUR_TWO_P, azur_config.AZUR_ONE_P]) + chars = [x for x in ALL_CHAR if x.star == star and x.type_ in type_ and not x.limited] return random.choice(chars), 4 - star - diff --git a/plugins/draw_card/config.py b/plugins/draw_card/config.py index e3a91db0..78648f2f 100755 --- a/plugins/draw_card/config.py +++ b/plugins/draw_card/config.py @@ -1,6 +1,7 @@ import nonebot -from pathlib import Path -from configs.path_config import DATA_PATH +from nonebot.log import logger +from pydantic import BaseModel, Extra, ValidationError +from configs.path_config import IMAGE_PATH, DATA_PATH from configs.config import Config try: @@ -9,133 +10,111 @@ except ModuleNotFoundError: import json -DRAW_PATH = DATA_PATH + "/draw_card/" - -_draw_config = Path(rf"{DRAW_PATH}/draw_card_config/draw_card_config.json") +# 原神 +class GenshinConfig(BaseModel, extra=Extra.ignore): + GENSHIN_FIVE_P: float = 0.006 + GENSHIN_FOUR_P: float = 0.051 + GENSHIN_THREE_P: float = 0.43 + GENSHIN_G_FIVE_P: float = 0.13 + GENSHIN_G_FOUR_P: float = 0.016 + I72_ADD: float = 0.0585 -for game_flag, game_name in zip( - [ - "PRTS_FLAG", - "GENSHIN_FLAG", - "PRETTY_FLAG", - "GUARDIAN_FLAG", - "PCR_FLAG", - "AZUR_FLAG", - "FGO_FLAG", - "ONMYOJI_FLAG", - "PCR_TAI", - ], - ["明日方舟", "原神", "赛马娘", "坎公骑冠剑", "公主连结", "碧蓝航线", "命运-冠位指定(FGO)", "阴阳师", "pcr台服卡池"], -): - Config.add_plugin_config( - "draw_card", - game_flag, - True, - name="游戏抽卡", - help_=f"{game_name} 抽卡开关", - default_value=True, - ) -Config.add_plugin_config( - "draw_card", "SEMAPHORE", 5, help_=f"异步数据下载数量限制", default_value=5 -) -PRTS_FLAG = Config.get_config("draw_card", "PRTS_FLAG") -GENSHIN_FLAG = Config.get_config("draw_card", "GENSHIN_FLAG") -PRETTY_FLAG = Config.get_config("draw_card", "PRETTY_FLAG") -GUARDIAN_FLAG = Config.get_config("draw_card", "GUARDIAN_FLAG") -PCR_FLAG = Config.get_config("draw_card", "PCR_FLAG") -AZUR_FLAG = Config.get_config("draw_card", "AZUR_FLAG") -FGO_FLAG = Config.get_config("draw_card", "FGO_FLAG") -ONMYOJI_FLAG = Config.get_config("draw_card", "ONMYOJI_FLAG") - -PCR_TAI = Config.get_config("draw_card", "PCR_TAI") -SEMAPHORE = Config.get_config("draw_card", "SEMAPHORE") +# 明日方舟 +class PrtsConfig(BaseModel, extra=Extra.ignore): + PRTS_SIX_P: float = 0.02 + PRTS_FIVE_P: float = 0.08 + PRTS_FOUR_P: float = 0.48 + PRTS_THREE_P: float = 0.42 -# 方舟概率 -PRTS_SIX_P = 0.02 -PRTS_FIVE_P = 0.08 -PRTS_FOUR_P = 0.48 -PRTS_THREE_P = 0.42 +# 赛马娘 +class PrettyConfig(BaseModel, extra=Extra.ignore): + PRETTY_THREE_P: float = 0.03 + PRETTY_TWO_P: float = 0.18 + PRETTY_ONE_P: float = 0.79 -# 原神概率 -GENSHIN_FIVE_P = 0.006 -GENSHIN_FOUR_P = 0.051 -GENSHIN_THREE_P = 0.43 -# 保底概率 -GENSHIN_G_FIVE_P = 0.016 -GENSHIN_G_FOUR_P = 0.13 -# 72抽后增加的概率 -I72_ADD = 0.0585 - -# 赛马娘概率 -PRETTY_THREE_P = 0.03 -PRETTY_TWO_P = 0.18 -PRETTY_ONE_P = 0.79 # 坎公骑冠剑 -# 角色概率 -GUARDIAN_THREE_CHAR_P = 0.0275 -GUARDIAN_TWO_CHAR_P = 0.19 -GUARDIAN_ONE_CHAR_P = 0.7825 -# UP角色 -GUARDIAN_THREE_CHAR_UP_P = 0.01375 -GUARDIAN_THREE_CHAR_OTHER_P = 0.01375 -# 武器概率 -GUARDIAN_EXCLUSIVE_ARMS_P = 0.03 -GUARDIAN_FIVE_ARMS_P = 0.03 -GUARDIAN_FOUR_ARMS_P = 0.09 -GUARDIAN_THREE_ARMS_P = 0.27 -GUARDIAN_TWO_ARMS_P = 0.58 -# UP武器 -GUARDIAN_EXCLUSIVE_ARMS_UP_P = 0.01 -GUARDIAN_EXCLUSIVE_ARMS_OTHER_P = 0.02 +class GuardianConfig(BaseModel, extra=Extra.ignore): + GUARDIAN_THREE_CHAR_P: float = 0.0275 + GUARDIAN_TWO_CHAR_P: float = 0.19 + GUARDIAN_ONE_CHAR_P: float = 0.7825 + GUARDIAN_THREE_CHAR_UP_P: float = 0.01375 + GUARDIAN_THREE_CHAR_OTHER_P: float = 0.01375 + GUARDIAN_EXCLUSIVE_ARMS_P: float = 0.03 + GUARDIAN_FIVE_ARMS_P: float = 0.03 + GUARDIAN_FOUR_ARMS_P: float = 0.09 + GUARDIAN_THREE_ARMS_P: float = 0.27 + GUARDIAN_TWO_ARMS_P: float = 0.58 + GUARDIAN_EXCLUSIVE_ARMS_UP_P: float = 0.01 + GUARDIAN_EXCLUSIVE_ARMS_OTHER_P: float = 0.02 + + +# 公主连结 +class PcrConfig(BaseModel, extra=Extra.ignore): + PCR_THREE_P: float = 0.025 + PCR_TWO_P: float = 0.18 + PCR_ONE_P: float = 0.795 + PCR_G_THREE_P: float = 0.025 + PCR_G_TWO_P: float = 0.975 -# PCR -PCR_THREE_P = 0.025 -PCR_TWO_P = 0.18 -PCR_ONE_P = 0.795 -# 保底 -PCR_G_THREE_P = 0.025 -PCR_G_TWO_P = 0.975 # 碧蓝航线 -AZUR_FIVE_P = 0.012 -AZUR_FOUR_P = 0.07 -AZUR_THREE_P = 0.12 -AZUR_TWO_P = 0.51 -AZUR_ONE_P = 0.3 +class AzurConfig(BaseModel, extra=Extra.ignore): + AZUR_FIVE_P: float = 0.012 + AZUR_FOUR_P: float = 0.07 + AZUR_THREE_P: float = 0.12 + AZUR_TWO_P: float = 0.51 + AZUR_ONE_P: float = 0.3 + + +# 命运-冠位指定 +class FgoConfig(BaseModel, extra=Extra.ignore): + FGO_SERVANT_FIVE_P: float = 0.01 + FGO_SERVANT_FOUR_P: float = 0.03 + FGO_SERVANT_THREE_P: float = 0.4 + FGO_CARD_FIVE_P: float = 0.04 + FGO_CARD_FOUR_P: float = 0.12 + FGO_CARD_THREE_P: float = 0.4 -# FGO -FGO_SERVANT_FIVE_P = 0.01 -FGO_SERVANT_FOUR_P = 0.03 -FGO_SERVANT_THREE_P = 0.4 -FGO_CARD_FIVE_P = 0.04 -FGO_CARD_FOUR_P = 0.12 -FGO_CARD_THREE_P = 0.4 # 阴阳师 -ONMYOJI_SP = 0.0025 -ONMYOJI_SSR = 0.01 -ONMYOJI_SR = 0.2 -ONMYOJI_R = 0.7875 +class OnmyojiConfig(BaseModel, extra=Extra.ignore): + ONMYOJI_SP: float = 0.0025 + ONMYOJI_SSR: float = 0.01 + ONMYOJI_SR: float = 0.2 + ONMYOJI_R: float = 0.7875 -path_dict = { - "genshin": "原神", - "prts": "明日方舟", - "pretty": "赛马娘", - "guardian": "坎公骑冠剑", - "pcr": "公主连结", - "azur": "碧蓝航线", - "fgo": "命运-冠位指定", - "onmyoji": "阴阳师", -} +class PathDict(BaseModel, extra=Extra.ignore): + genshin: str = "原神" + prts: str = "明日方舟" + pretty: str = "赛马娘" + guardian: str = "坎公骑冠剑" + pcr: str = "公主连结" + azur: str = "碧蓝航线" + fgo: str = "命运-冠位指定" + onmyoji: str = "阴阳师" -driver: nonebot.Driver = nonebot.get_driver() -config_default_data = { - "path_dict": { +class DrawConfig(BaseModel, extra=Extra.ignore): + # 开关 + PRTS_FLAG: bool = Config.get_config("draw_card", "PRTS_FLAG") + GENSHIN_FLAG: bool = Config.get_config("draw_card", "GENSHIN_FLAG") + PRETTY_FLAG: bool = Config.get_config("draw_card", "PRETTY_FLAG") + GUARDIAN_FLAG: bool = Config.get_config("draw_card", "GUARDIAN_FLAG") + PCR_FLAG: bool = Config.get_config("draw_card", "PCR_FLAG") + AZUR_FLAG: bool = Config.get_config("draw_card", "AZUR_FLAG") + FGO_FLAG: bool = Config.get_config("draw_card", "FGO_FLAG") + ONMYOJI_FLAG: bool = Config.get_config("draw_card", "ONMYOJI_FLAG") + + # 其他配置 + PCR_TAI: bool = Config.get_config("draw_card", "PCR_TAI") + SEMAPHORE: int = Config.get_config("draw_card", "SEMAPHORE") + + # 路径 + path_dict: dict = { "genshin": "原神", "prts": "明日方舟", "pretty": "赛马娘", @@ -144,268 +123,41 @@ config_default_data = { "azur": "碧蓝航线", "fgo": "命运-冠位指定", "onmyoji": "阴阳师", - }, - "prts": { - "PRTS_SIX_P": 0.02, - "PRTS_FIVE_P": 0.08, - "PRTS_FOUR_P": 0.48, - "PRTS_THREE_P": 0.42, - }, - "genshin": { - "GENSHIN_FIVE_P": 0.006, - "GENSHIN_FOUR_P": 0.051, - "GENSHIN_THREE_P": 0.43, - "GENSHIN_G_FIVE_P": 0.13, - "GENSHIN_G_FOUR_P": 0.016, - "I72_ADD": 0.0585, - }, - "pretty": { - "PRETTY_THREE_P": 0.03, - "PRETTY_TWO_P": 0.18, - "PRETTY_ONE_P": 0.79, - }, - "guardian": { - "GUARDIAN_THREE_CHAR_P": 0.0275, - "GUARDIAN_TWO_CHAR_P": 0.19, - "GUARDIAN_ONE_CHAR_P": 0.7825, - "GUARDIAN_THREE_CHAR_UP_P": 0.01375, - "GUARDIAN_THREE_CHAR_OTHER_P": 0.01375, - "GUARDIAN_EXCLUSIVE_ARMS_P": 0.03, - "GUARDIAN_FIVE_ARMS_P": 0.03, - "GUARDIAN_FOUR_ARMS_P": 0.09, - "GUARDIAN_THREE_ARMS_P": 0.27, - "GUARDIAN_TWO_ARMS_P": 0.58, - "GUARDIAN_EXCLUSIVE_ARMS_UP_P": 0.01, - "GUARDIAN_EXCLUSIVE_ARMS_OTHER_P": 0.02, - }, - "pcr": { - "PCR_THREE_P": 0.025, - "PCR_TWO_P": 0.18, - "PCR_ONE_P": 0.795, - }, - "azur": { - "AZUR_FIVE_P": 0.012, - "AZUR_FOUR_P": 0.07, - "AZUR_THREE_P": 0.12, - "AZUR_TWO_P": 0.51, - "AZUR_ONE_P": 0.3, - }, - "fgo": { - "FGO_SERVANT_FIVE_P": 0.01, - "FGO_SERVANT_FOUR_P": 0.03, - "FGO_SERVANT_THREE_P": 0.4, - "FGO_CARD_FIVE_P": 0.04, - "FGO_CARD_FOUR_P": 0.12, - "FGO_CARD_THREE_P": 0.4, - }, - "onmyoji": { - "ONMYOJI_SP": 0.0025, - "ONMYOJI_SSR": 0.01, - "ONMYOJI_SR": 0.2, - "ONMYOJI_R": 0.7875, - }, -} + } + + # 抽卡概率 + prts: PrtsConfig = PrtsConfig() + genshin: GenshinConfig = GenshinConfig() + pretty: PrettyConfig = PrettyConfig() + guardian: GuardianConfig = GuardianConfig() + pcr: PcrConfig = PcrConfig() + azur: AzurConfig = AzurConfig() + fgo: FgoConfig = FgoConfig() + onmyoji: OnmyojiConfig = OnmyojiConfig() + + +driver = nonebot.get_driver() +global_config = driver.config +DRAW_DATA_PATH = DATA_PATH / "draw_card" +DRAW_IMAGE_PATH = IMAGE_PATH / "draw_card" +# DRAW_PATH = Path(draw_path) if draw_path else Path("data/draw_card").absolute() +config_path = DRAW_DATA_PATH / "draw_card_config" / "draw_card_config.json" + +draw_config: Config = DrawConfig() @driver.on_startup def check_config(): - global PRTS_SIX_P, PRTS_FOUR_P, PRTS_FIVE_P, PRTS_THREE_P, GENSHIN_G_FIVE_P, config_default_data, GENSHIN_G_FOUR_P, GENSHIN_FOUR_P, GENSHIN_FIVE_P, I72_ADD, path_dict, PRETTY_THREE_P, PRETTY_ONE_P, PRETTY_TWO_P, GENSHIN_THREE_P, GUARDIAN_THREE_CHAR_P, GUARDIAN_TWO_CHAR_P, GUARDIAN_ONE_CHAR_P, GUARDIAN_THREE_CHAR_UP_P, GUARDIAN_THREE_CHAR_OTHER_P, GUARDIAN_EXCLUSIVE_ARMS_P, GUARDIAN_FIVE_ARMS_P, GUARDIAN_FOUR_ARMS_P, GUARDIAN_THREE_ARMS_P, GUARDIAN_TWO_ARMS_P, GENSHIN_FLAG, PRTS_FLAG, PRETTY_FLAG, GUARDIAN_FLAG, GUARDIAN_EXCLUSIVE_ARMS_UP_P, GUARDIAN_EXCLUSIVE_ARMS_OTHER_P, DRAW_PATH, PCR_THREE_P, PCR_TWO_P, PCR_ONE_P, AZUR_FOUR_P, AZUR_THREE_P, AZUR_TWO_P, AZUR_ONE_P, AZUR_FIVE_P, FGO_CARD_FIVE_P, FGO_CARD_FOUR_P, FGO_CARD_THREE_P, FGO_SERVANT_THREE_P, FGO_SERVANT_FOUR_P, FGO_SERVANT_FIVE_P, ONMYOJI_R, ONMYOJI_SP, ONMYOJI_SSR, ONMYOJI_SR - _draw_config.parent.mkdir(parents=True, exist_ok=True) - try: - data = json.load(open(_draw_config, "r", encoding="utf8")) - except (FileNotFoundError, ValueError): - _draw_config.parent.mkdir(parents=True, exist_ok=True) - json.dump( - config_default_data, - open(_draw_config, "w", encoding="utf8"), - indent=4, - ensure_ascii=False, - ) - print("draw_card:配置文件不存在或格式错误,已重新生成配置文件.....") - else: + global draw_config - try: - PRTS_SIX_P = float(data["prts"]["PRTS_SIX_P"]) - PRTS_FIVE_P = float(data["prts"]["PRTS_FIVE_P"]) - PRTS_FOUR_P = float(data["prts"]["PRTS_FOUR_P"]) - PRTS_THREE_P = float(data["prts"]["PRTS_THREE_P"]) - except KeyError: - data["prts"] = {} - data["prts"]["PRTS_SIX_P"] = config_default_data["prts"]["PRTS_SIX_P"] - data["prts"]["PRTS_FIVE_P"] = config_default_data["prts"]["PRTS_FIVE_P"] - data["prts"]["PRTS_FOUR_P"] = config_default_data["prts"]["PRTS_FOUR_P"] - data["prts"]["PRTS_THREE_P"] = config_default_data["prts"]["PRTS_THREE_P"] + if not config_path.exists(): + config_path.parent.mkdir(parents=True, exist_ok=True) + draw_config = DrawConfig() + logger.warning("draw_card:配置文件不存在,已重新生成配置文件.....") - try: - GENSHIN_FIVE_P = float(data["genshin"]["GENSHIN_FIVE_P"]) - GENSHIN_FOUR_P = float(data["genshin"]["GENSHIN_FOUR_P"]) - GENSHIN_THREE_P = float(data["genshin"]["GENSHIN_THREE_P"]) - GENSHIN_G_FIVE_P = float(data["genshin"]["GENSHIN_G_FIVE_P"]) - GENSHIN_G_FOUR_P = float(data["genshin"]["GENSHIN_G_FOUR_P"]) - I72_ADD = float(data["genshin"]["I72_ADD"]) - except KeyError: - data["genshin"] = {} - data["genshin"]["GENSHIN_FIVE_P"] = config_default_data["genshin"][ - "GENSHIN_FIVE_P" - ] - data["genshin"]["GENSHIN_FOUR_P"] = config_default_data["genshin"][ - "GENSHIN_FOUR_P" - ] - data["genshin"]["GENSHIN_THREE_P"] = config_default_data["genshin"][ - "GENSHIN_THREE_P" - ] - data["genshin"]["GENSHIN_G_FIVE_P"] = config_default_data["genshin"][ - "GENSHIN_G_FIVE_P" - ] - data["genshin"]["GENSHIN_G_FOUR_P"] = config_default_data["genshin"][ - "GENSHIN_G_FOUR_P" - ] - data["genshin"]["I72_ADD"] = config_default_data["genshin"]["I72_ADD"] - - try: - PRETTY_THREE_P = float(data["pretty"]["PRETTY_THREE_P"]) - PRETTY_TWO_P = float(data["pretty"]["PRETTY_TWO_P"]) - PRETTY_ONE_P = float(data["pretty"]["PRETTY_ONE_P"]) - except KeyError: - data["pretty"] = {} - data["pretty"]["PRETTY_THREE_P"] = config_default_data["pretty"][ - "PRETTY_THREE_P" - ] - data["pretty"]["PRETTY_TWO_P"] = config_default_data["pretty"][ - "PRETTY_TWO_P" - ] - data["pretty"]["PRETTY_ONE_P"] = config_default_data["pretty"][ - "PRETTY_ONE_P" - ] - - try: - GUARDIAN_THREE_CHAR_P = float(data["guardian"]["GUARDIAN_THREE_CHAR_P"]) - GUARDIAN_TWO_CHAR_P = float(data["guardian"]["GUARDIAN_TWO_CHAR_P"]) - GUARDIAN_ONE_CHAR_P = float(data["guardian"]["GUARDIAN_ONE_CHAR_P"]) - GUARDIAN_THREE_CHAR_UP_P = float( - data["guardian"]["GUARDIAN_THREE_CHAR_UP_P"] - ) - GUARDIAN_THREE_CHAR_OTHER_P = float( - data["guardian"]["GUARDIAN_THREE_CHAR_OTHER_P"] - ) - GUARDIAN_EXCLUSIVE_ARMS_P = float( - data["guardian"]["GUARDIAN_EXCLUSIVE_ARMS_P"] - ) - GUARDIAN_FIVE_ARMS_P = float(data["guardian"]["GUARDIAN_FIVE_ARMS_P"]) - GUARDIAN_FOUR_ARMS_P = float(data["guardian"]["GUARDIAN_FOUR_ARMS_P"]) - GUARDIAN_THREE_ARMS_P = float(data["guardian"]["GUARDIAN_THREE_ARMS_P"]) - GUARDIAN_TWO_ARMS_P = float(data["guardian"]["GUARDIAN_TWO_ARMS_P"]) - GUARDIAN_EXCLUSIVE_ARMS_UP_P = float( - data["guardian"]["GUARDIAN_EXCLUSIVE_ARMS_UP_P"] - ) - GUARDIAN_EXCLUSIVE_ARMS_OTHER_P = float( - data["guardian"]["GUARDIAN_EXCLUSIVE_ARMS_OTHER_P"] - ) - except KeyError: - data["guardian"] = {} - data["guardian"]["GUARDIAN_THREE_CHAR_P"] = config_default_data["guardian"][ - "GUARDIAN_THREE_CHAR_P" - ] - data["guardian"]["GUARDIAN_TWO_CHAR_P"] = config_default_data["guardian"][ - "GUARDIAN_TWO_CHAR_P" - ] - data["guardian"]["GUARDIAN_ONE_CHAR_P"] = config_default_data["guardian"][ - "GUARDIAN_ONE_CHAR_P" - ] - data["guardian"]["GUARDIAN_THREE_CHAR_UP_P"] = config_default_data[ - "guardian" - ]["GUARDIAN_THREE_CHAR_UP_P"] - data["guardian"]["GUARDIAN_THREE_CHAR_OTHER_P"] = config_default_data[ - "guardian" - ]["GUARDIAN_THREE_CHAR_OTHER_P"] - data["guardian"]["GUARDIAN_EXCLUSIVE_ARMS_P"] = config_default_data[ - "guardian" - ]["GUARDIAN_EXCLUSIVE_ARMS_P"] - data["guardian"]["GUARDIAN_FIVE_ARMS_P"] = config_default_data["guardian"][ - "GUARDIAN_FIVE_ARMS_P" - ] - data["guardian"]["GUARDIAN_FOUR_ARMS_P"] = config_default_data["guardian"][ - "GUARDIAN_FOUR_ARMS_P" - ] - data["guardian"]["GUARDIAN_THREE_ARMS_P"] = config_default_data["guardian"][ - "GUARDIAN_THREE_ARMS_P" - ] - data["guardian"]["GUARDIAN_TWO_ARMS_P"] = config_default_data["guardian"][ - "GUARDIAN_TWO_ARMS_P" - ] - data["guardian"]["GUARDIAN_EXCLUSIVE_ARMS_UP_P"] = config_default_data[ - "guardian" - ]["GUARDIAN_EXCLUSIVE_ARMS_UP_P"] - data["guardian"]["GUARDIAN_EXCLUSIVE_ARMS_OTHER_P"] = config_default_data[ - "guardian" - ]["GUARDIAN_EXCLUSIVE_ARMS_OTHER_P"] - - try: - PCR_THREE_P = float(data["pcr"]["PCR_THREE_P"]) - PCR_TWO_P = float(data["pcr"]["PCR_TWO_P"]) - PCR_ONE_P = float(data["pcr"]["PCR_ONE_P"]) - except KeyError: - data["pcr"] = {} - data["pcr"]["PCR_THREE_P"] = config_default_data["pcr"]["PCR_THREE_P"] - data["pcr"]["PCR_TWO_P"] = config_default_data["pcr"]["PCR_TWO_P"] - data["pcr"]["PCR_ONE_P"] = config_default_data["pcr"]["PCR_ONE_P"] - - try: - AZUR_FIVE_P = float(data["azur"]["AZUR_FIVE_P"]) - AZUR_FOUR_P = float(data["azur"]["AZUR_FOUR_P"]) - AZUR_THREE_P = float(data["azur"]["AZUR_THREE_P"]) - AZUR_TWO_P = float(data["azur"]["AZUR_TWO_P"]) - AZUR_ONE_P = float(data["azur"]["AZUR_ONE_P"]) - except KeyError: - data["azur"] = {} - data["azur"]["AZUR_FIVE_P"] = config_default_data["azur"]["AZUR_FIVE_P"] - data["azur"]["AZUR_FOUR_P"] = config_default_data["azur"]["AZUR_FOUR_P"] - data["azur"]["AZUR_THREE_P"] = config_default_data["azur"]["AZUR_THREE_P"] - data["azur"]["AZUR_TWO_P"] = config_default_data["azur"]["AZUR_TWO_P"] - data["azur"]["AZUR_ONE_P"] = config_default_data["azur"]["AZUR_ONE_P"] - - try: - FGO_SERVANT_FIVE_P = float(data["fgo"]["FGO_SERVANT_FIVE_P"]) - FGO_SERVANT_FOUR_P = float(data["fgo"]["FGO_SERVANT_FOUR_P"]) - FGO_SERVANT_THREE_P = float(data["fgo"]["FGO_SERVANT_THREE_P"]) - FGO_CARD_FIVE_P = float(data["fgo"]["FGO_CARD_FIVE_P"]) - FGO_CARD_FOUR_P = float(data["fgo"]["FGO_CARD_FOUR_P"]) - FGO_CARD_THREE_P = float(data["fgo"]["FGO_CARD_THREE_P"]) - except KeyError: - data["fgo"] = {} - data["fgo"]["FGO_SERVANT_FIVE_P"] = config_default_data["fgo"][ - "FGO_SERVANT_FIVE_P" - ] - data["fgo"]["FGO_SERVANT_FOUR_P"] = config_default_data["fgo"][ - "FGO_SERVANT_FOUR_P" - ] - data["fgo"]["FGO_SERVANT_THREE_P"] = config_default_data["fgo"][ - "FGO_SERVANT_THREE_P" - ] - data["fgo"]["FGO_CARD_FIVE_P"] = config_default_data["fgo"][ - "FGO_CARD_FIVE_P" - ] - data["fgo"]["FGO_CARD_FOUR_P"] = config_default_data["fgo"][ - "FGO_CARD_FOUR_P" - ] - data["fgo"]["FGO_CARD_THREE_P"] = config_default_data["fgo"][ - "FGO_CARD_THREE_P" - ] - - try: - ONMYOJI_SP = float(data["onmyoji"]["ONMYOJI_SP"]) - ONMYOJI_SSR = float(data["onmyoji"]["ONMYOJI_SSR"]) - ONMYOJI_SR = float(data["onmyoji"]["ONMYOJI_SR"]) - ONMYOJI_R = float(data["onmyoji"]["ONMYOJI_R"]) - except KeyError: - data["onmyoji"] = {} - data["onmyoji"]["ONMYOJI_SP"] = config_default_data["onmyoji"]["ONMYOJI_SP"] - data["onmyoji"]["ONMYOJI_SSR"] = config_default_data["onmyoji"][ - "ONMYOJI_SSR" - ] - data["onmyoji"]["ONMYOJI_SR"] = config_default_data["onmyoji"]["ONMYOJI_SR"] - data["onmyoji"]["ONMYOJI_R"] = config_default_data["onmyoji"]["ONMYOJI_R"] - - json.dump( - data, open(_draw_config, "w", encoding="utf8"), indent=4, ensure_ascii=False - ) + json.dump( + draw_config.dict(), + config_path.open("w", encoding="utf8"), + indent=4, + ensure_ascii=False, + ) diff --git a/plugins/draw_card/count_manager.py b/plugins/draw_card/count_manager.py new file mode 100644 index 00000000..093375ea --- /dev/null +++ b/plugins/draw_card/count_manager.py @@ -0,0 +1,113 @@ +from typing import Optional, Union + + +class DrawCountManager: + """ + 抽卡统计保底 + """ + + def __init__(self, game_draw_count_rule: tuple, star2name: tuple): + """ + 初始化保底统计 + + 例如:DrawCountManager((10, 90, 180), ("4", "5", "5")) + + 抽卡保底需要的次数和返回的对应名称,例如星级等 + + """ + # 只有保底 + self._data = {} + self._guarantee_tuple = game_draw_count_rule + self._star2name = star2name + + def increase(self, key: int, value: int = 1): + """ + 用户抽卡次数加1 + """ + if self._data.get(key) is None: + self._data[key] = { + "count": value, + } + for x in range(len(self._guarantee_tuple)): + self._data[key][f"count_{x}"] = 0 + else: + self._data[key][f"count"] += value + if self._data[key][f"count"] > self._guarantee_tuple[-1]: + self._data[key][f"count"] = self._data[key][f"count"] % self._guarantee_tuple[-1] + + def reset(self, key: int): + """ + 清空记录 + """ + del self._data[key] + + def set_count(self, key: int, type_: int, count: int): + if self._data.get(key): + self._data[key][f"count_{type_}"] = count + + def check(self, key: int, *args) -> Optional[Union[str, int]]: + """ + 是否保底 + """ + pass + + def get_user_count(self, key: int, type_: Optional[int] = None) -> int: + """ + 获取用户当前抽卡次数 + """ + if self._data.get(key): + if type_ is None: + return self._data[key]["count"] + return self._data[key][f"count_{type_}"] + return 0 + + def record_count(self, key: int, type_: int): + """ + 抽出对应星级后记录当前次数 + """ + if self._data.get(key): + self._data[key][f"count_{type_}"] = self._data[key]["count"] + + +class GenshinCountManager(DrawCountManager): + + def increase(self, key: int, value: int = 1): + """ + 用户抽卡次数加1 + """ + if self._data.get(key) is None: + self._data[key] = { + "is_up": False, + "count": value, + } + for x in range(len(self._guarantee_tuple)): + self._data[key][f"count_{x}"] = 0 + else: + self._data[key][f"count"] += value + if self._data[key][f"count"] > self._guarantee_tuple[-1]: + self._data[key][f"count"] = self._data[key][f"count"] % 180 + + def set_is_up(self, key: int, value: bool): + if self._data.get(key): + self._data[key]["is_up"] = value + + def is_up(self, key: int) -> bool: + if self._data.get(key): + return self._data[key]["is_up"] + return False + + def check(self, key: int, *args) -> Optional[Union[str, int]]: + """ + 是否保底 + """ + # print(self._data) + if self._data.get(key): + for i in [1, 0]: + count = self._data[key]["count"] + if count - self._data[key][f"count_{i}"] == self._guarantee_tuple[i]: + if i in [2, 1]: + # print("clean four count") + self._data[key][f"count_0"] = self._data[key]['count'] + self._data[key][f"count_{i}"] = self._data[key]['count'] + return self._star2name[i] + return None diff --git a/plugins/draw_card/fgo_handle.py b/plugins/draw_card/fgo_handle.py index f78aca24..f52583ef 100755 --- a/plugins/draw_card/fgo_handle.py +++ b/plugins/draw_card/fgo_handle.py @@ -1,10 +1,8 @@ - -from nonebot.adapters.cqhttp import MessageSegment +from nonebot.adapters.onebot.v11 import MessageSegment import random from .update_game_requests_info import update_requests_info from .util import generate_img, init_star_rst, BaseData, set_list, get_star, max_card -from .config import FGO_CARD_FOUR_P, FGO_CARD_FIVE_P, FGO_CARD_THREE_P, FGO_SERVANT_THREE_P, \ - FGO_SERVANT_FIVE_P, FGO_SERVANT_FOUR_P, FGO_FLAG, DRAW_PATH +from .config import DRAW_DATA_PATH, draw_config from dataclasses import dataclass from .init_card_pool import init_game_pool @@ -45,11 +43,11 @@ async def update_fgo_info(): async def init_fgo_data(): global ALL_CHAR, ALL_CARD - if FGO_FLAG: - with open(DRAW_PATH + 'fgo.json', 'r', encoding='utf8') as f: + if draw_config.FGO_FLAG: + with (DRAW_DATA_PATH / 'fgo.json').open('r', encoding='utf8') as f: fgo_dict = json.load(f) ALL_CHAR = init_game_pool('fgo', fgo_dict, FgoChar) - with open(DRAW_PATH + 'fgo_card.json', 'r', encoding='utf8') as f: + with (DRAW_DATA_PATH / 'fgo_card.json').open('r', encoding='utf8') as f: fgo_dict = json.load(f) ALL_CARD = init_game_pool('fgo', fgo_dict, FgoChar) @@ -57,21 +55,22 @@ async def init_fgo_data(): # 抽取卡池 def _get_fgo_card(mode: int = 1): global ALL_CHAR, ALL_CARD + fgo_config = draw_config.fgo if mode == 1: - star = get_star([8, 7, 6, 5, 4, 3], [FGO_SERVANT_FIVE_P, FGO_SERVANT_FOUR_P, FGO_SERVANT_THREE_P, - FGO_CARD_FIVE_P, FGO_CARD_FOUR_P, FGO_CARD_THREE_P]) + star = get_star([8, 7, 6, 5, 4, 3], [fgo_config.FGO_SERVANT_FIVE_P, fgo_config.FGO_SERVANT_FOUR_P, fgo_config.FGO_SERVANT_THREE_P, + fgo_config.FGO_CARD_FIVE_P, fgo_config.FGO_CARD_FOUR_P, fgo_config.FGO_CARD_THREE_P]) elif mode == 2: - star = get_star([5, 4], [FGO_CARD_FIVE_P, FGO_CARD_FOUR_P]) + star = get_star([5, 4], [fgo_config.FGO_CARD_FIVE_P, fgo_config.FGO_CARD_FOUR_P]) else: - star = get_star([8, 7, 6], [FGO_SERVANT_FIVE_P, FGO_SERVANT_FOUR_P, FGO_SERVANT_THREE_P]) + star = get_star([8, 7, 6], [fgo_config.FGO_SERVANT_FIVE_P, fgo_config.FGO_SERVANT_FOUR_P, fgo_config.FGO_SERVANT_THREE_P]) if star > 5: - itype = 'servant' + type_ = 'servant' star -= 3 chars = [x for x in ALL_CHAR if x.star == star if not x.limited] else: - itype = 'card' + type_ = 'card' chars = [x for x in ALL_CARD if x.star == star if not x.limited] - return random.choice(chars), 5 - star, itype + return random.choice(chars), 5 - star, type_ # 整理数据 @@ -88,18 +87,18 @@ def _format_card_information(count: int): card_count += 1 # 四星卡片保底 if card_count == 9: - obj, code, itype = _get_fgo_card(2) + obj, code, type_ = _get_fgo_card(2) # 三星从者保底 elif servant_count == 10: - obj, code, itype = _get_fgo_card(3) + obj, code, type_ = _get_fgo_card(3) _count = 0 # 普通抽 else: - obj, code, itype = _get_fgo_card() + obj, code, type_ = _get_fgo_card() star_list[code] += 1 - if itype == 'card' and code < 2: + if type_ == 'card' and code < 2: card_count = 0 - if itype == 'servant': + if type_ == 'servant': servant_count = 0 if code == 0: max_star_lst.append(obj.name) diff --git a/plugins/draw_card/genshin_handle.py b/plugins/draw_card/genshin_handle.py index e1353347..12bb8eea 100755 --- a/plugins/draw_card/genshin_handle.py +++ b/plugins/draw_card/genshin_handle.py @@ -1,25 +1,16 @@ -import os -from nonebot.adapters.cqhttp import MessageSegment, Message +from nonebot.adapters.onebot.v11 import MessageSegment, Message import random from .update_game_info import update_info from .util import ( generate_img, - init_star_rst, + init_rst, BaseData, set_list, get_star, init_up_char, ) -from .config import ( - GENSHIN_FIVE_P, - GENSHIN_FOUR_P, - GENSHIN_G_FIVE_P, - GENSHIN_G_FOUR_P, - GENSHIN_THREE_P, - I72_ADD, - DRAW_PATH, - GENSHIN_FLAG, -) +from .config import DRAW_DATA_PATH, draw_config +from .count_manager import GenshinCountManager from dataclasses import dataclass from .init_card_pool import init_game_pool from .announcement import GenshinAnnouncement @@ -32,9 +23,11 @@ except ModuleNotFoundError: announcement = GenshinAnnouncement() -genshin_five = {} -genshin_count = {} -genshin_pl_count = {} +draw_count_manager = GenshinCountManager((10, 90), ("4", "5")) + +# genshin_five = {} +# genshin_count = {} +# genshin_pl_count = {} ALL_CHAR = [] ALL_ARMS = [] @@ -42,6 +35,7 @@ ALL_ARMS = [] UP_CHAR = [] UP_ARMS = [] + _CURRENT_CHAR_POOL_TITLE = "" _CURRENT_ARMS_POOL_TITLE = "" POOL_IMG = "" @@ -54,15 +48,12 @@ class GenshinChar(BaseData): async def genshin_draw(user_id: int, count: int, pool_name: str): # 0 1 2 - cnlist = ["★★★★★", "★★★★", "★★★"] + star = ["★★★★★", "★★★★", "★★★"] ( char_list, - five_list, - five_index_list, - char_dict, - star_list, + five_dict, + star_num_list, ) = _format_card_information(count, user_id, pool_name) - temp = "" title = "" up_type = [] up_list = [] @@ -81,7 +72,7 @@ async def genshin_draw(user_id: int, count: int, pool_name: str): tmp += f'五星UP:{" ".join(x.operators)} \n' elif x.star == 4: tmp += f'四星UP:{" ".join(x.operators)}' - rst = init_star_rst(star_list, cnlist, five_list, five_index_list, up_list) + rst = init_rst(five_dict, star_num_list, star, up_list) pool_info = f"当前up池:{title}\n{tmp}" if title else "" if count > 90: char_list = set_list(char_list) @@ -89,12 +80,10 @@ async def genshin_draw(user_id: int, count: int, pool_name: str): pool_info + "\n" + MessageSegment.image( - "base64://" + await generate_img(char_list, "genshin", star_list) + "base64://" + await generate_img(char_list, "genshin", star_num_list) ) - + "\n" - + rst[:-1] - + temp[:-1] - + f'\n距离保底发还剩 {90 - genshin_count[user_id] if genshin_count.get(user_id) else "^"} 抽' + + rst + + f'\n距离保底发还剩 {draw_count_manager.get_user_count(user_id, 1) % 90} 抽' + "\n【五星:0.6%,四星:5.1%\n第72抽开始五星概率每抽加0.585%】" ) @@ -117,15 +106,13 @@ async def update_genshin_info(): async def init_genshin_data(): global ALL_CHAR, ALL_ARMS - if GENSHIN_FLAG: - if not os.path.exists(DRAW_PATH + "genshin.json") or not os.path.exists( - DRAW_PATH + "genshin_arms.json" - ): + if draw_config.GENSHIN_FLAG: + if not (DRAW_DATA_PATH / "genshin.json").exists() or not (DRAW_DATA_PATH / "genshin_arms.json").exists(): await update_genshin_info() else: - with open(DRAW_PATH + "genshin.json", "r", encoding="utf8") as f: + with (DRAW_DATA_PATH / "genshin.json").open("r", encoding="utf8") as f: genshin_dict = json.load(f) - with open(DRAW_PATH + "genshin_arms.json", "r", encoding="utf8") as f: + with (DRAW_DATA_PATH / "genshin_arms.json").open("r", encoding="utf8") as f: genshin_ARMS_dict = json.load(f) ALL_CHAR = init_game_pool("genshin", genshin_dict, GenshinChar) ALL_ARMS = init_game_pool("genshin_arms", genshin_ARMS_dict, GenshinChar) @@ -133,47 +120,52 @@ async def init_genshin_data(): # 抽取卡池 -def _get_genshin_card(mode: int = 1, pool_name: str = "", add: float = 0.0): +def _get_genshin_card(mode: int = 1, pool_name: str = "", add: float = 0.0, is_up: bool = False): + """ + mode 1:普通抽 2:四星保底 3:五星保底 + """ global ALL_ARMS, ALL_CHAR, UP_ARMS, UP_CHAR, _CURRENT_ARMS_POOL_TITLE, _CURRENT_CHAR_POOL_TITLE + genshin_config = draw_config.genshin if mode == 1: star = get_star( - [5, 4, 3], [GENSHIN_FIVE_P + add, GENSHIN_FOUR_P, GENSHIN_THREE_P] + [5, 4, 3], [genshin_config.GENSHIN_FIVE_P + add, genshin_config.GENSHIN_FOUR_P, genshin_config.GENSHIN_THREE_P] ) elif mode == 2: - star = get_star([5, 4], [GENSHIN_G_FIVE_P + add, GENSHIN_G_FOUR_P]) + star = get_star([5, 4], [genshin_config.GENSHIN_G_FIVE_P + add, genshin_config.GENSHIN_G_FOUR_P]) else: star = 5 if pool_name == "char": data_lst = UP_CHAR flag = _CURRENT_CHAR_POOL_TITLE - itype_all_lst = ALL_CHAR + [ + type_all_lst = ALL_CHAR + [ x for x in ALL_ARMS if x.star == star and x.star < 5 ] elif pool_name == "arms": data_lst = UP_ARMS flag = _CURRENT_ARMS_POOL_TITLE - itype_all_lst = ALL_ARMS + [ + type_all_lst = ALL_ARMS + [ x for x in ALL_CHAR if x.star == star and x.star < 5 ] else: data_lst = "" flag = "" - itype_all_lst = "" + type_all_lst = "" all_lst = ALL_ARMS + ALL_CHAR # 是否UP try: - if flag and star > 3 and pool_name: + if flag and star > 3: # 获取up角色列表 up_char_lst = [x.operators for x in data_lst if x.star == star][0] + # print(up_char_lst) # 成功获取up角色 - if random.random() < 0.5: + if random.random() < 0.5 or is_up: up_char_name = random.choice(up_char_lst) acquire_char = [x for x in all_lst if x.name == up_char_name][0] else: # 无up all_char_lst = [ x - for x in itype_all_lst + for x in type_all_lst if x.star == star and x.name not in up_char_lst and not x.limited ] acquire_char = random.choice(all_char_lst) @@ -187,62 +179,94 @@ def _get_genshin_card(mode: int = 1, pool_name: str = "", add: float = 0.0): def _format_card_information(_count: int, user_id, pool_name): - char_list = [] - star_list = [0, 0, 0] - five_index_list = [] - five_list = [] - five_dict = {} - _start_add_count = 72 if pool_name == "char" else 62 - _x = 90 if pool_name == "char" else 80 # 保底 + char_list = [] # 获取角色列表 + star_num_list = [0, 0, 0] # 各个星级数量 + five_dict = {} # 五星数量 add = 0.0 - if genshin_count.get(user_id) and _count <= _x: - f_count = genshin_count[user_id] - else: - f_count = 0 - if genshin_pl_count.get(user_id) and _count <= _x: - count = genshin_pl_count[user_id] - else: - count = 0 - for i in range(_count): - count += 1 - f_count += 1 - # 十连保底 - if count == 10 and f_count != _x: - if f_count >= _start_add_count: - add += I72_ADD - char, code = _get_genshin_card(2, pool_name, add=add) - count = 0 - # 大保底 - elif f_count == _x: - char, code = _get_genshin_card(3, pool_name) + pool = UP_CHAR if pool_name == 'char' else UP_ARMS + for _ in range(_count): + draw_count_manager.increase(user_id) + star = draw_count_manager.check(user_id) + if (draw_count_manager.get_user_count(user_id) - draw_count_manager.get_user_count(user_id, 1)) % 90 >= 72: + add += draw_config.genshin.I72_ADD + if star: + star = int(star) + if star == 4: + char, code = _get_genshin_card(2, pool_name, add=add) + draw_count_manager.record_count(user_id, 0) + else: + char, code = _get_genshin_card(3, pool_name, add, draw_count_manager.is_up(user_id)) else: - if f_count >= _start_add_count: - add += I72_ADD - char, code = _get_genshin_card(pool_name=pool_name, add=add) - if code == 1: - count = 0 - star_list[code] += 1 + char, code = _get_genshin_card(1, pool_name, add, draw_count_manager.is_up(user_id)) if code == 0: - if _count <= _x: - genshin_five[user_id] = f_count - add = 0.0 - f_count = 0 - five_list.append(char.name) - five_index_list.append(i) - try: - five_dict[char.name] += 1 - except KeyError: - five_dict[char.name] = 1 + add = 0 + if not five_dict.get(char.name): + five_dict[char.name] = [draw_count_manager.get_user_count(user_id)] + else: + five_dict[char.name].append(draw_count_manager.get_user_count(user_id) % 90) + draw_count_manager.set_count(user_id, 2, draw_count_manager.get_user_count(user_id, 1)) + draw_count_manager.record_count(user_id, 0) + draw_count_manager.record_count(user_id, 1) + if char.name not in [x.operators for x in pool if x.star == 5][0]: + draw_count_manager.set_is_up(user_id, True) + else: + draw_count_manager.set_is_up(user_id, False) + star_num_list[code] += 1 char_list.append(char) - if _count <= _x: - genshin_count[user_id] = f_count - genshin_pl_count[user_id] = count - return char_list, five_list, five_index_list, five_dict, star_list + return char_list, five_dict, star_num_list + + + + + + + # if genshin_count.get(user_id) and _count <= 90: + # f_count = genshin_count[user_id] + # else: + # f_count = 0 + # if genshin_pl_count.get(user_id) and _count <= 90: + # count = genshin_pl_count[user_id] + # else: + # count = 0 + # for i in range(_count): + # count += 1 + # f_count += 1 + # # 十连保底 + # if count == 10 and f_count != 90: + # if f_count >= 72: + # add += I72_ADD + # char, code = _get_genshin_card(2, pool_name, add=add) + # count = 0 + # # 大保底 + # elif f_count == 90: + # char, code = _get_genshin_card(3, pool_name) + # else: + # if f_count >= 72: + # add += I72_ADD + # char, code = _get_genshin_card(pool_name=pool_name, add=add) + # if code == 1: + # count = 0 + # star_list[code] += 1 + # if code == 0: + # if _count <= 90: + # genshin_five[user_id] = f_count + # add = 0.0 + # f_count = 0 + # five_list.append(char.name) + # five_index_list.append(i) + # try: + # five_dict[char.name] += 1 + # except KeyError: + # five_dict[char.name] = 1 + # char_list.append(char) + # if _count <= 90: + # genshin_count[user_id] = f_count + # genshin_pl_count[user_id] = count + # return char_list, five_list, five_index_list, five_dict, star_list def reset_count(user_id: int): - genshin_count[user_id] = 0 - genshin_pl_count[user_id] = 0 + draw_count_manager.reset(user_id) # 获取up和概率 diff --git a/plugins/draw_card/guardian_handle.py b/plugins/draw_card/guardian_handle.py index dfc2f501..5df7e48f 100755 --- a/plugins/draw_card/guardian_handle.py +++ b/plugins/draw_card/guardian_handle.py @@ -1,17 +1,12 @@ - -import os -from nonebot.adapters.cqhttp import MessageSegment, Message +from nonebot.adapters.onebot.v11 import MessageSegment, Message from .update_game_info import update_info -from .announcement import GuardianAnnouncement from .util import init_star_rst, generate_img, max_card, BaseData,\ set_list, get_star, format_card_information, init_up_char import random -from .config import DRAW_PATH, GUARDIAN_ONE_CHAR_P, GUARDIAN_TWO_CHAR_P, GUARDIAN_THREE_CHAR_P, \ - GUARDIAN_THREE_CHAR_UP_P, GUARDIAN_TWO_ARMS_P, GUARDIAN_FIVE_ARMS_P, GUARDIAN_THREE_CHAR_OTHER_P, \ - GUARDIAN_FOUR_ARMS_P, GUARDIAN_THREE_ARMS_P, GUARDIAN_EXCLUSIVE_ARMS_P, GUARDIAN_EXCLUSIVE_ARMS_UP_P, \ - GUARDIAN_EXCLUSIVE_ARMS_OTHER_P, GUARDIAN_FLAG +from .config import DRAW_DATA_PATH, draw_config from dataclasses import dataclass from .init_card_pool import init_game_pool +from .announcement import GuardianAnnouncement try: import ujson as json except ModuleNotFoundError: @@ -96,13 +91,13 @@ async def update_guardian_info(): async def init_guardian_data(): global ALL_CHAR, ALL_ARMS - if GUARDIAN_FLAG: - if not os.path.exists(DRAW_PATH + 'guardian.json') or not os.path.exists(DRAW_PATH + 'guardian_arms.json'): + if draw_config.GUARDIAN_FLAG: + if not (DRAW_DATA_PATH / 'guardian.json').exists() or not (DRAW_DATA_PATH / 'guardian_arms.json').exists(): await update_guardian_info() else: - with open(DRAW_PATH + 'guardian.json', 'r', encoding='utf8') as f: + with (DRAW_DATA_PATH / 'guardian.json').open('r', encoding='utf8') as f: guardian_char_dict = json.load(f) - with open(DRAW_PATH + 'guardian_arms.json', 'r', encoding='utf8') as f: + with (DRAW_DATA_PATH / 'guardian_arms.json').open('r', encoding='utf8') as f: guardian_arms_dict = json.load(f) ALL_CHAR = init_game_pool('guardian', guardian_char_dict, GuardianChar) ALL_ARMS = init_game_pool('guardian_arms', guardian_arms_dict, GuardianArms) @@ -112,21 +107,22 @@ async def init_guardian_data(): # 抽取卡池 def _get_guardian_card(pool_name: str = '', mode: int = 1): global ALL_ARMS, ALL_CHAR, UP_ARMS, UP_CHAR, _CURRENT_ARMS_POOL_TITLE, _CURRENT_CHAR_POOL_TITLE + guardian_config = draw_config.guardian if pool_name == 'char': if mode == 1: - star = get_star([3, 2, 1], [GUARDIAN_THREE_CHAR_P, GUARDIAN_TWO_CHAR_P, GUARDIAN_ONE_CHAR_P]) + star = get_star([3, 2, 1], [guardian_config.GUARDIAN_THREE_CHAR_P, guardian_config.GUARDIAN_TWO_CHAR_P, guardian_config.GUARDIAN_ONE_CHAR_P]) else: - star = get_star([3, 2], [GUARDIAN_THREE_CHAR_P, GUARDIAN_TWO_CHAR_P]) + star = get_star([3, 2], [guardian_config.GUARDIAN_THREE_CHAR_P, guardian_config.GUARDIAN_TWO_CHAR_P]) up_lst = UP_CHAR flag = _CURRENT_CHAR_POOL_TITLE _max_star = 3 all_data = ALL_CHAR else: if mode == 1: - star = get_star([5, 4, 3, 2], [GUARDIAN_FIVE_ARMS_P, GUARDIAN_FOUR_ARMS_P, - GUARDIAN_THREE_ARMS_P, GUARDIAN_TWO_ARMS_P]) + star = get_star([5, 4, 3, 2], [guardian_config.GUARDIAN_FIVE_ARMS_P, guardian_config.GUARDIAN_FOUR_ARMS_P, + guardian_config.GUARDIAN_THREE_ARMS_P, guardian_config.GUARDIAN_TWO_ARMS_P]) else: - star = get_star([5, 4], [GUARDIAN_FIVE_ARMS_P, GUARDIAN_FOUR_ARMS_P]) + star = get_star([5, 4], [guardian_config.GUARDIAN_FIVE_ARMS_P, guardian_config.GUARDIAN_FOUR_ARMS_P]) up_lst = UP_ARMS flag = _CURRENT_ARMS_POOL_TITLE _max_star = 5 @@ -158,3 +154,6 @@ async def _guardian_init_up_char(): async def reload_guardian_pool(): await _guardian_init_up_char() return Message(f'当前UP池子:{_CURRENT_CHAR_POOL_TITLE} & {_CURRENT_ARMS_POOL_TITLE}') + + + diff --git a/plugins/draw_card/init_card_pool.py b/plugins/draw_card/init_card_pool.py index f875b02a..65c73310 100755 --- a/plugins/draw_card/init_card_pool.py +++ b/plugins/draw_card/init_card_pool.py @@ -1,137 +1,204 @@ from typing import Any -from .config import DATA_PATH -from utils.utils import is_number -from pathlib import Path -from services.log import logger +from .config import DRAW_DATA_PATH +from .util import is_number +from nonebot.log import logger + try: import ujson as json except ModuleNotFoundError: import json -def init_game_pool(game: str, data: dict, Operator: Any): +def init_game_pool(game: str, data: dict, operator: Any): tmp_lst = [] - if game == 'prts': + if game == "prts": for key in data.keys(): limited = False recruit_only = False event_only = False - if '限定寻访' in data[key]['获取途径']: + if "限定寻访" in data[key]["获取途径"]: limited = True - if '干员寻访' not in data[key]['获取途径'] and '公开招募' in data[key]['获取途径']: + if "干员寻访" not in data[key]["获取途径"] and "公开招募" in data[key]["获取途径"]: recruit_only = True - if '活动获取' in data[key]['获取途径']: + if "活动获取" in data[key]["获取途径"]: event_only = True - if '干员寻访' not in data[key]['获取途径'] and '凭证交易所' == data[key]['获取途径'][0]: + if "干员寻访" not in data[key]["获取途径"] and "凭证交易所" == data[key]["获取途径"][0]: limited = True - if '干员寻访' not in data[key]['获取途径'] and '信用累计奖励' == data[key]['获取途径'][0]: + if "干员寻访" not in data[key]["获取途径"] and "信用累计奖励" == data[key]["获取途径"][0]: limited = True - if key.find('阿米娅') != -1: + if key.find("阿米娅") != -1: continue try: - tmp_lst.append(Operator(name=key, star=int(data[key]['星级']), - limited=limited, recruit_only=recruit_only, event_only=event_only)) + tmp_lst.append( + operator( + name=key, + star=int(data[key]["星级"]), + limited=limited, + recruit_only=recruit_only, + event_only=event_only, + ) + ) except Exception as e: logger.warning(f"明日方舟导入角色 {key} 数据错误:{type(e)}:{e}") - if game == 'genshin': + if game == "genshin": for key in data.keys(): - if key.find('旅行者') != -1: + if key.find("旅行者") != -1: continue limited = False - if data[key]['常驻/限定'] == '限定UP': + if data[key]["常驻/限定"] == "限定UP": limited = True try: - tmp_lst.append(Operator(name=key, star=int(data[key]['稀有度'][:1]), limited=limited)) + tmp_lst.append( + operator(name=key, star=int(data[key]["稀有度"][:1]), limited=limited) + ) except Exception as e: logger.warning(f"原神导入角色 {key} 数据错误:{type(e)}:{e}") - if game == 'genshin_arms': + if game == "genshin_arms": for key in data.keys(): - if data[key]['获取途径'].find('祈愿') != -1: + if data[key]["获取途径"].find("祈愿") != -1: limited = False - if data[key]['获取途径'].find('限定祈愿') != -1: + if data[key]["获取途径"].find("限定祈愿") != -1: limited = True try: - tmp_lst.append(Operator(name=key, star=int(data[key]['稀有度'][:1]), limited=limited)) + tmp_lst.append( + operator( + name=key, star=int(data[key]["稀有度"][:1]), limited=limited + ) + ) except Exception as e: logger.warning(f"原神导入武器 {key} 数据错误:{type(e)}:{e}") - if game == 'pretty': + if game == "pretty": for key in data.keys(): try: - tmp_lst.append(Operator(name=key, star=data[key]['初始星级'], limited=False)) + tmp_lst.append( + operator(name=key, star=data[key]["初始星级"], limited=False) + ) except Exception as e: logger.warning(f"赛马娘导入角色 {key} 数据错误:{type(e)}:{e}") - if game == 'pretty_card': + if game == "pretty_card": for key in data.keys(): limited = False - if '卡池' not in data[key]['获取方式']: + if "卡池" not in data[key]["获取方式"]: limited = True - if not data[key]['获取方式']: + if not data[key]["获取方式"]: limited = False try: - tmp_lst.append(Operator(name=data[key]['中文名'], star=len(data[key]['稀有度']), limited=limited)) + tmp_lst.append( + operator( + name=data[key]["中文名"], + star=len(data[key]["稀有度"]), + limited=limited, + ) + ) except Exception as e: logger.warning(f"赛马娘导入卡片 {key} 数据错误:{type(e)}:{e}") - if game in ['guardian', 'guardian_arms']: + if game in ["guardian", "guardian_arms"]: for key in data.keys(): - tmp_lst.append(Operator(name=data[key]['名称'], star=int(data[key]['星级']), limited=False)) - if game == 'pcr': + tmp_lst.append( + operator(name=data[key]["名称"], star=int(data[key]["星级"]), limited=False) + ) + if game == "pcr": for key in data.keys(): limited = False - if key.find('(') != -1: + if key.find("(") != -1: limited = True try: - tmp_lst.append(Operator(name=data[key]['名称'], star=int(data[key]['星级']), limited=limited)) + tmp_lst.append( + operator( + name=data[key]["名称"], star=int(data[key]["星级"]), limited=limited + ) + ) except Exception as e: logger.warning(f"公主连接导入角色 {key} 数据错误:{type(e)}:{e}") - if game == 'azur': + if game == "azur": for key in data.keys(): - if is_number(data[key]['星级']): + if is_number(data[key]["星级"]): limited = False - if '可以建造' not in data[key]['获取途径']: + if "可以建造" not in data[key]["获取途径"]: limited = True try: - tmp_lst.append(Operator(name=data[key]['名称'], star=int(data[key]['星级']), - limited=limited, itype=data[key]['类型'])) + tmp_lst.append( + operator( + name=data[key]["名称"], + star=int(data[key]["星级"]), + limited=limited, + type_=data[key]["类型"], + ) + ) except Exception as e: logger.warning(f"碧蓝航线导入角色 {key} 数据错误:{type(e)}:{e}") - if game in ['fgo', 'fgo_card']: + if game in ["fgo", "fgo_card"]: for key in data.keys(): limited = False try: - if "圣晶石召唤" not in data[key]['入手方式'] and "圣晶石召唤(Story卡池)" not in data[key]['入手方式']: + if ( + "圣晶石召唤" not in data[key]["入手方式"] + and "圣晶石召唤(Story卡池)" not in data[key]["入手方式"] + ): limited = True except KeyError: pass try: - tmp_lst.append(Operator(name=data[key]['名称'], star=int(data[key]['星级']), limited=limited)) + tmp_lst.append( + operator( + name=data[key]["名称"], star=int(data[key]["星级"]), limited=limited + ) + ) except Exception as e: logger.warning(f"FGO导入角色 {key} 数据错误:{type(e)}:{e}") - if game == 'onmyoji': + if game == "onmyoji": for key in data.keys(): limited = False - if key in ['奴良陆生', '卖药郎', '鬼灯', '阿香', '蜜桃&芥子', '犬夜叉', '杀生丸', '桔梗', '朽木露琪亚', '黑崎一护', - '灶门祢豆子', '灶门炭治郎']: + if key in [ + "奴良陆生", + "卖药郎", + "鬼灯", + "阿香", + "蜜桃&芥子", + "犬夜叉", + "杀生丸", + "桔梗", + "朽木露琪亚", + "黑崎一护", + "灶门祢豆子", + "灶门炭治郎", + ]: limited = True try: - tmp_lst.append(Operator(name=data[key]['名称'], star=data[key]['星级'], limited=limited)) + tmp_lst.append( + operator( + name=data[key]["名称"], star=data[key]["星级"], limited=limited + ) + ) except Exception as e: logger.warning(f"阴阳师导入角色 {key} 数据错误:{type(e)}:{e}") # print(tmp_lst) char_name_lst = [x.name for x in tmp_lst] - up_char_file = Path(f'{DATA_PATH}/draw_card/draw_card_up/{game.split("_")[0]}_up_char.json') + up_char_file = ( + DRAW_DATA_PATH + / f"draw_card" + / "draw_card_up" + / f"{game.split('_')[0]}_up_char.json" + ) if up_char_file.exists(): - data = json.load(open(up_char_file, 'r', encoding='utf8')) - if len(game.split('_')) == 1: - key = 'char' + data = json.load(open(up_char_file, "r", encoding="utf8")) + if len(game.split("_")) == 1: + key = "char" else: key = list(data.keys())[1] - for x in data[key]['up_char']: - for char in data[key]['up_char'][x]: + for x in data[key]["up_char"]: + for char in data[key]["up_char"][x]: if char not in char_name_lst: - if game.find('prts') != -1: - tmp_lst.append(Operator(name=char, star=int(x), - recruit_only=False, event_only=False, limited=False)) + if game.find("prts") != -1: + tmp_lst.append( + operator( + name=char, + star=int(x), + recruit_only=False, + event_only=False, + limited=False, + ) + ) else: - tmp_lst.append(Operator(name=char, star=int(x), limited=False)) + tmp_lst.append(operator(name=char, star=int(x), limited=False)) return tmp_lst - diff --git a/plugins/draw_card/onmyoji_handle.py b/plugins/draw_card/onmyoji_handle.py index 7b468f0a..c0f0be9d 100755 --- a/plugins/draw_card/onmyoji_handle.py +++ b/plugins/draw_card/onmyoji_handle.py @@ -1,9 +1,8 @@ - -from nonebot.adapters.cqhttp import MessageSegment +from nonebot.adapters.onebot.v11 import MessageSegment import random from .update_game_requests_info import update_requests_info from .util import generate_img, init_star_rst, BaseData, set_list, get_star, max_card -from .config import ONMYOJI_SR, ONMYOJI_SSR, ONMYOJI_SP, ONMYOJI_R, DRAW_PATH, ONMYOJI_FLAG +from .config import DRAW_DATA_PATH, draw_config from dataclasses import dataclass from .init_card_pool import init_game_pool try: @@ -39,8 +38,8 @@ async def update_onmyoji_info(): async def init_onmyoji_data(): global ALL_CHAR - if ONMYOJI_FLAG: - with open(DRAW_PATH + 'onmyoji.json', 'r', encoding='utf8') as f: + if draw_config.ONMYOJI_FLAG: + with (DRAW_DATA_PATH / 'onmyoji.json').open('r', encoding='utf8') as f: azur_dict = json.load(f) ALL_CHAR = init_game_pool('onmyoji', azur_dict, OnmyojiChar) @@ -56,7 +55,8 @@ onmyoji_star = { # 抽取卡池 def _get_onmyoji_card(): global ALL_CHAR - star = get_star([5, 4, 3, 2], [ONMYOJI_SP, ONMYOJI_SSR, ONMYOJI_SR, ONMYOJI_R]) + onmyoji_config = draw_config.onmyoji + star = get_star([5, 4, 3, 2], [onmyoji_config.ONMYOJI_SP, onmyoji_config.ONMYOJI_SSR, onmyoji_config.ONMYOJI_SR, onmyoji_config.ONMYOJI_R]) chars = [x for x in ALL_CHAR if x.star == onmyoji_star[star] and not x.limited] return random.choice(chars), 5 - star @@ -79,4 +79,3 @@ def format_card_information(count: int): obj_dict[obj.name] = 1 obj_list.append(obj) return obj_list, obj_dict, star_list, rst - diff --git a/plugins/draw_card/pcr_handle.py b/plugins/draw_card/pcr_handle.py index c48c8a5a..2612f49f 100755 --- a/plugins/draw_card/pcr_handle.py +++ b/plugins/draw_card/pcr_handle.py @@ -1,13 +1,16 @@ -import ujson as json -from nonebot.adapters.cqhttp import MessageSegment +from nonebot.adapters.onebot.v11 import MessageSegment import random from .update_game_info import update_info from .update_game_simple_info import update_simple_info from .util import generate_img, init_star_rst, BaseData, set_list, get_star, max_card -from .config import PCR_TWO_P, PCR_THREE_P, PCR_ONE_P, DRAW_PATH, PCR_FLAG, PCR_G_TWO_P, PCR_G_THREE_P, PCR_TAI +from .config import DRAW_DATA_PATH, draw_config from dataclasses import dataclass from .init_card_pool import init_game_pool +try: + import ujson as json +except ModuleNotFoundError: + import json ALL_CHAR = [] @@ -30,7 +33,7 @@ async def pcr_draw(count: int): async def update_pcr_info(): global ALL_CHAR - if PCR_TAI: + if draw_config.PCR_TAI: url = 'https://wiki.biligame.com/pcr/角色图鉴' data, code = await update_simple_info(url, 'pcr') else: @@ -42,8 +45,8 @@ async def update_pcr_info(): async def init_pcr_data(): global ALL_CHAR - if PCR_FLAG: - with open(DRAW_PATH + 'pcr.json', 'r', encoding='utf8') as f: + if draw_config.PCR_FLAG: + with (DRAW_DATA_PATH / 'pcr.json').open('r', encoding='utf8') as f: pcr_dict = json.load(f) ALL_CHAR = init_game_pool('pcr', pcr_dict, PcrChar) @@ -51,10 +54,11 @@ async def init_pcr_data(): # 抽取卡池 def _get_pcr_card(mode: int = 1): global ALL_CHAR + pcr_config = draw_config.pcr if mode == 2: - star = get_star([3, 2], [PCR_G_THREE_P, PCR_G_TWO_P]) + star = get_star([3, 2], [pcr_config.PCR_G_THREE_P, pcr_config.PCR_G_TWO_P]) else: - star = get_star([3, 2, 1], [PCR_THREE_P, PCR_TWO_P, PCR_ONE_P]) + star = get_star([3, 2, 1], [pcr_config.PCR_THREE_P, pcr_config.PCR_TWO_P, pcr_config.PCR_ONE_P]) chars = [x for x in ALL_CHAR if x.star == star and not x.limited] return random.choice(chars), 3 - star diff --git a/plugins/draw_card/pretty_handle.py b/plugins/draw_card/pretty_handle.py index 5e74f4c5..c57635a4 100755 --- a/plugins/draw_card/pretty_handle.py +++ b/plugins/draw_card/pretty_handle.py @@ -1,13 +1,12 @@ - -from .update_game_info import update_info +from nonebot.adapters.onebot.v11 import MessageSegment from .announcement import PrettyAnnouncement +from .update_game_info import update_info from .util import init_star_rst, generate_img, max_card, BaseData, \ set_list, get_star, format_card_information, init_up_char import random -from .config import PRETTY_THREE_P, PRETTY_TWO_P, DRAW_PATH, PRETTY_ONE_P, PRETTY_FLAG +from .config import DRAW_DATA_PATH, draw_config from dataclasses import dataclass from .init_card_pool import init_game_pool -from nonebot.adapters.cqhttp import MessageSegment, Message try: import ujson as json @@ -74,7 +73,8 @@ async def pretty_draw(count: int, pool_name): rst = init_star_rst(star_list, cnlist, three_list, three_olist, up_list) if count > 90: obj_list = set_list(obj_list) - return pool_info + MessageSegment.image("base64://" + await generate_img(obj_list, 'pretty', star_list)) \ + return pool_info + MessageSegment.image( + "base64://" + await generate_img(obj_list, 'pretty', star_list)) \ + '\n' + rst[:-1] + '\n' + max_card(obj_dict) @@ -93,10 +93,10 @@ async def update_pretty_info(): async def init_pretty_data(): global ALL_CHAR, ALL_CARD - if PRETTY_FLAG: - with open(DRAW_PATH + 'pretty.json', 'r', encoding='utf8') as f: + if draw_config.PRETTY_FLAG: + with (DRAW_DATA_PATH / 'pretty.json').open('r', encoding='utf8') as f: pretty_char_dict = json.load(f) - with open(DRAW_PATH + 'pretty_card.json', 'r', encoding='utf8') as f: + with (DRAW_DATA_PATH / 'pretty_card.json').open('r', encoding='utf8') as f: pretty_card_dict = json.load(f) ALL_CHAR = init_game_pool('pretty', pretty_char_dict, PrettyChar) ALL_CARD = init_game_pool('pretty_card', pretty_card_dict, PrettyChar) @@ -106,10 +106,11 @@ async def init_pretty_data(): # 抽取卡池 def _get_pretty_card(pool_name: str, mode: int = 1): global ALL_CHAR, ALL_CARD, _CURRENT_CHAR_POOL_TITLE, _CURRENT_CARD_POOL_TITLE + pretty_config = draw_config.pretty if mode == 1: - star = get_star([3, 2, 1], [PRETTY_THREE_P, PRETTY_TWO_P, PRETTY_ONE_P]) + star = get_star([3, 2, 1], [pretty_config.PRETTY_THREE_P, pretty_config.PRETTY_TWO_P, pretty_config.PRETTY_ONE_P]) else: - star = get_star([3, 2], [PRETTY_THREE_P, PRETTY_TWO_P]) + star = get_star([3, 2], [pretty_config.PRETTY_THREE_P, pretty_config.PRETTY_TWO_P]) if pool_name == 'card': title = _CURRENT_CARD_POOL_TITLE up_data = UP_CARD @@ -127,7 +128,6 @@ def _get_pretty_card(pool_name: str, mode: int = 1): acquire_operator = random.choice(all_up_star) if pool_name == 'char': acquire_operator = acquire_operator.split(']')[1] - print(acquire_operator) acquire_operator = [x for x in data if x.name == acquire_operator][0] else: acquire_operator = random.choice([x for x in data if x.star == star and not x.limited]) @@ -144,6 +144,5 @@ async def _pretty_init_up_char(): async def reload_pretty_pool(): await _pretty_init_up_char() - return Message(f'当前UP池子:{_CURRENT_CHAR_POOL_TITLE} & {_CURRENT_CARD_POOL_TITLE} {POOL_IMG}') - + return f'当前UP池子:{_CURRENT_CHAR_POOL_TITLE} & {_CURRENT_CARD_POOL_TITLE} {POOL_IMG}' diff --git a/plugins/draw_card/prts_handle.py b/plugins/draw_card/prts_handle.py index 8a87ed8b..48ff8490 100755 --- a/plugins/draw_card/prts_handle.py +++ b/plugins/draw_card/prts_handle.py @@ -1,14 +1,12 @@ - -from nonebot.adapters.cqhttp import MessageSegment, Message +from nonebot.adapters.onebot.v11 import MessageSegment, Message import random -from .config import PRTS_FIVE_P, PRTS_FOUR_P, PRTS_SIX_P, PRTS_THREE_P, DRAW_PATH, PRTS_FLAG +from .config import DRAW_DATA_PATH, draw_config from .update_game_info import update_info from .util import generate_img, init_star_rst, max_card, BaseData, UpEvent, set_list, get_star from .init_card_pool import init_game_pool -from pathlib import Path from .announcement import PrtsAnnouncement -from services.log import logger from dataclasses import dataclass +from nonebot.log import logger try: import ujson as json except ModuleNotFoundError: @@ -17,8 +15,6 @@ except ModuleNotFoundError: announcement = PrtsAnnouncement() -up_char_file = Path() / "data" / "draw_card" / "draw_card_up" / "prts_up_char.json" - prts_dict = {} UP_OPERATOR = [] ALL_OPERATOR = [] @@ -71,8 +67,8 @@ async def update_prts_info(): async def init_prts_data(): global prts_dict, ALL_OPERATOR - if PRTS_FLAG: - with open(DRAW_PATH + 'prts.json', 'r', encoding='utf8') as f: + if draw_config.PRTS_FLAG: + with (DRAW_DATA_PATH / 'prts.json').open('r', encoding='utf8') as f: prts_dict = json.load(f) ALL_OPERATOR = init_game_pool('prts', prts_dict, Operator) await _init_up_char() @@ -80,7 +76,8 @@ async def init_prts_data(): # 抽取干员 def _get_operator_card(add: float): - star = get_star([6, 5, 4, 3], [PRTS_SIX_P + add, PRTS_FIVE_P, PRTS_FOUR_P, PRTS_THREE_P]) + prts_config = draw_config.prts + star = get_star([6, 5, 4, 3], [prts_config.PRTS_SIX_P + add, prts_config.PRTS_FIVE_P, prts_config.PRTS_FOUR_P, prts_config.PRTS_THREE_P]) if _CURRENT_POOL_TITLE: zooms = [x.zoom for x in UP_OPERATOR if x.star == star] zoom = 0 @@ -92,12 +89,11 @@ def _get_operator_card(add: float): else: weight = z up_operator_name = "" - # UP + # UPs try: - if random.random() < zoom: + if 0 < zoom: up_operators = [x.operators for x in UP_OPERATOR if x.star == star and x.zoom < 1][0] up_operator_name = random.choice(up_operators) - # print(up_operator_name) acquire_operator = [x for x in ALL_OPERATOR if x.name == up_operator_name][0] else: all_star_operators = [x for x in ALL_OPERATOR if x.star == star diff --git a/plugins/draw_card/rule.py b/plugins/draw_card/rule.py index 899bc1dd..c5ecb0f4 100755 --- a/plugins/draw_card/rule.py +++ b/plugins/draw_card/rule.py @@ -1,36 +1,28 @@ from nonebot.rule import Rule -from nonebot.adapters.cqhttp import Bot, MessageEvent +from nonebot.adapters.onebot.v11 import Bot, MessageEvent from nonebot.typing import T_State -from .config import ( - GENSHIN_FLAG, - PRTS_FLAG, - PRETTY_FLAG, - GUARDIAN_FLAG, - PCR_FLAG, - AZUR_FLAG, - FGO_FLAG, - ONMYOJI_FLAG, -) +from .config import draw_config def is_switch(game_name: str) -> Rule: + async def _is_switch(bot: Bot, event: MessageEvent, state: T_State) -> bool: - if game_name == "prts": - return PRTS_FLAG - if game_name == "genshin": - return GENSHIN_FLAG - if game_name == "pretty": - return PRETTY_FLAG - if game_name == "guardian": - return GUARDIAN_FLAG - if game_name == "pcr": - return PCR_FLAG - if game_name == "azur": - return AZUR_FLAG - if game_name == "fgo": - return FGO_FLAG - if game_name == "onmyoji": - return ONMYOJI_FLAG + if game_name == 'prts': + return draw_config.PRTS_FLAG + if game_name == 'genshin': + return draw_config.GENSHIN_FLAG + if game_name == 'pretty': + return draw_config.PRETTY_FLAG + if game_name == 'guardian': + return draw_config.GUARDIAN_FLAG + if game_name == 'pcr': + return draw_config.PCR_FLAG + if game_name == 'azur': + return draw_config.AZUR_FLAG + if game_name == 'fgo': + return draw_config.FGO_FLAG + if game_name == 'onmyoji': + return draw_config.ONMYOJI_FLAG else: return False diff --git a/plugins/draw_card/update_game_info.py b/plugins/draw_card/update_game_info.py index 1246dc69..5ce5835c 100755 --- a/plugins/draw_card/update_game_info.py +++ b/plugins/draw_card/update_game_info.py @@ -1,12 +1,12 @@ -from .config import DRAW_PATH +from typing import Tuple +from .config import DRAW_DATA_PATH from asyncio.exceptions import TimeoutError from bs4 import BeautifulSoup from .util import download_img from urllib.parse import unquote -from services.log import logger from .util import remove_prohibited_str from utils.http_utils import AsyncHttpx -from httpx import ConnectTimeout, CloseError +from nonebot.log import logger import bs4 import re try: @@ -18,15 +18,16 @@ except ModuleNotFoundError: headers = {'User-Agent': '"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)"'} -async def update_info(url: str, game_name: str, info_list: list = None) -> 'dict, int': +async def update_info(url: str, game_name: str, info_list: list = None) -> Tuple[dict, int]: + info_path = DRAW_DATA_PATH / f"{game_name}.json" try: - with open(DRAW_PATH + f'{game_name}.json', 'r', encoding='utf8') as f: + with info_path.open('r', encoding='utf8') as f: data = json.load(f) except (ValueError, FileNotFoundError): data = {} try: - text = (await AsyncHttpx.get(url)).text - soup = BeautifulSoup(text, 'lxml') + response = await AsyncHttpx.get(url, timeout=7) + soup = BeautifulSoup(response.text, 'lxml') _tbody = get_tbody(soup, game_name, url) trs = _tbody.find_all('tr') att_dict, start_index, index = init_attr(game_name) @@ -58,13 +59,10 @@ async def update_info(url: str, game_name: str, info_list: list = None) -> 'dict data[name] = member_dict logger.info(f'{name} is update...') data = await _last_check(data, game_name) - except (TimeoutError, ConnectTimeout, CloseError): + except TimeoutError: logger.warning(f'更新 {game_name} 超时...') return {}, 999 - except Exception as e: - logger.error(f"更新 {game_name} 未知错误 {type(e)}:{e}") - return {}, 998 - with open(DRAW_PATH + f'{game_name}.json', 'w', encoding='utf8') as wf: + with info_path.open('w', encoding='utf8') as wf: wf.write(json.dumps(data, ensure_ascii=False, indent=4)) return data, 200 @@ -99,21 +97,25 @@ def _find_last_tag(element: bs4.element.Tag, attr: str, game_name: str) -> str: # 获取大图(小图快爬) async def _modify_avatar_url(game_name: str, char_name: str): - # if game_name == 'prts': - # async with session.get(f'https://wiki.biligame.com/arknights/{char_name}', timeout=7) as res: - # soup = BeautifulSoup(await res.text(), 'lxml') - # try: - # img_url = str(soup.find('img', {'class': 'img-bg'})['srcset']).split(' ')[-2] - # except KeyError: - # img_url = str(soup.find('img', {'class': 'img-bg'})['src']) - # return img_url + if game_name == 'prts': + res = await AsyncHttpx.get(f'https://wiki.biligame.com/arknights/{char_name}', timeout=7) + soup = BeautifulSoup(res.text, 'lxml') + try: + img_url = str(soup.find('img', {'class': 'img-bg'})['srcset']).split(' ')[-2] + except KeyError: + img_url = str(soup.find('img', {'class': 'img-bg'})['src']) + return img_url if game_name == 'genshin': return None if game_name == 'pretty_card': - text = (await AsyncHttpx.get(f'https://wiki.biligame.com/umamusume/{char_name}')).text - soup = BeautifulSoup(text, 'lxml') - img_url = soup.find('div', {'class': 'support_card-left'}).find('div').find('img').get('src') - return img_url + res = await AsyncHttpx.get(f'https://wiki.biligame.com/umamusume/{char_name}', timeout=7) + soup = BeautifulSoup(res.text, 'lxml') + try: + img_url = soup.find('div', {'class': 'support_card-left'}).find('div').find('img').get('src') + return img_url + except AttributeError: + logger.warning("pretty_card 获取大图像失败") + return None if game_name == 'guardian': # 未上传图片太多,换成像素图 # async with session.get(f'https://wiki.biligame.com/gt/{char_name}', timeout=7) as res: @@ -124,7 +126,7 @@ async def _modify_avatar_url(game_name: str, char_name: str): # except KeyError: # img_url = str(soup.find('img', {'class': 'img-kk'})['src']) # except TypeError: - # logger.info(f'{char_name} 图片还未上传,跳过...') + # print(f'{char_name} 图片还未上传,跳过...') # img_url = '' # return img_url return None @@ -133,18 +135,17 @@ async def _modify_avatar_url(game_name: str, char_name: str): # 数据最后处理(是否需要额外数据或处理数据) async def _last_check(data: dict, game_name: str): # if game_name == 'prts': - # url = 'https://wiki.biligame.com/arknights/' # tasks = [] # for key in data.keys(): - # tasks.append(asyncio.ensure_future(_async_update_prts_extra_info(url, key, session))) + # tasks.append(asyncio.ensure_future(_async_update_prts_extra_info(key, session))) # asyResult = await asyncio.gather(*tasks) # for x in asyResult: # for key in x.keys(): # data[key]['获取途径'] = x[key]['获取途径'] if game_name == 'genshin': for key in data.keys(): - text = (await AsyncHttpx.get(f'https://wiki.biligame.com/ys/{key}')).text - soup = BeautifulSoup(text, 'lxml') + res = await AsyncHttpx.get(f'https://wiki.biligame.com/ys/{key}', timeout=7) + soup = BeautifulSoup(res.text, 'lxml') _trs = '' for table in soup.find_all('table', {'class': 'wikitable'}): if str(table).find('常驻/限定') != -1: @@ -193,6 +194,13 @@ def intermediate_check(member_dict: dict, key: str, game_name: str, td: bs4.elem if game_name == 'pretty': if key == '初始星级': member_dict['初始星级'] = len(td.find_all('img')) + if game_name == 'pretty_card': + if key == '获取方式': + obtain = [] + for x in str(td.text).replace('\n', '').strip().split('、'): + if x: + obtain.append(x) + member_dict['获取方式'] = obtain if game_name == 'guardian': if key == '头像': member_dict['星级'] = str(td.find('span').find('img')['alt'])[-5] @@ -257,7 +265,7 @@ def get_tbody(soup: bs4.BeautifulSoup, game_name: str, url: str): return _tbody -# async def _async_update_prts_extra_info(url: str, key: str, session: aiohttp.ClientSession): +# async def _async_update_prts_extra_info(key: str, session: aiohttp.ClientSession): # for i in range(10): # try: # async with session.get(f'https://wiki.biligame.com/arknights/{key}', timeout=7) as res: @@ -277,11 +285,11 @@ def get_tbody(soup: bs4.BeautifulSoup, game_name: str, url: str): # if r: # text += r.group(1) + ' ' # obtain[i] = obtain[i].split('')[-1] -# logger.info(f'明日方舟获取额外信息 {key}...{obtain}') +# print(f'明日方舟获取额外信息 {key}...{obtain}') # x = {key: {}} # x[key]['获取途径'] = obtain # return x # except TimeoutError: -# logger.warning(f'访问{url}{key} 第 {i}次 超时...已再次访问') +# print(f'访问 https://wiki.biligame.com/arknights/{key} 第 {i}次 超时...已再次访问') # return {} diff --git a/plugins/draw_card/update_game_requests_info.py b/plugins/draw_card/update_game_requests_info.py index 5d9590a1..ceb4b73b 100755 --- a/plugins/draw_card/update_game_requests_info.py +++ b/plugins/draw_card/update_game_requests_info.py @@ -1,63 +1,61 @@ -from .config import DRAW_PATH, SEMAPHORE +from .config import DRAW_DATA_PATH, draw_config from asyncio.exceptions import TimeoutError from .util import download_img from bs4 import BeautifulSoup from .util import remove_prohibited_str from utils.http_utils import AsyncHttpx -from services.log import logger -from httpx import ConnectTimeout, CloseError +from nonebot.log import logger import asyncio - try: import ujson as json except ModuleNotFoundError: import json -headers = { - "User-Agent": '"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)"' -} +headers = {'User-Agent': '"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)"'} async def update_requests_info(game_name: str): + info_path = DRAW_DATA_PATH / f"{game_name}.json" try: - with open(DRAW_PATH + f"{game_name}.json", "r", encoding="utf8") as f: + with info_path.open('r', encoding='utf8') as f: data = json.load(f) except (ValueError, FileNotFoundError): data = {} try: - if game_name in ["fgo", "fgo_card"]: - if game_name == "fgo": - url = "http://fgo.vgtime.com/servant/ajax?card=&wd=&ids=&sort=12777&o=desc&pn=" + if game_name in ['fgo', 'fgo_card']: + if game_name == 'fgo': + url = 'http://fgo.vgtime.com/servant/ajax?card=&wd=&ids=&sort=12777&o=desc&pn=' else: - url = "http://fgo.vgtime.com/equipment/ajax?wd=&ids=&sort=12958&o=desc&pn=" + url = 'http://fgo.vgtime.com/equipment/ajax?wd=&ids=&sort=12958&o=desc&pn=' for i in range(9999): - text = (await AsyncHttpx.get(f"{url}{i}")).text - fgo_data = json.loads(text) - if int(fgo_data["nums"]) == 0: + response = await AsyncHttpx.get(f'{url}{i}', timeout=7) + fgo_data = json.loads(response.text) + if int(fgo_data['nums']) == 0: break - for x in fgo_data["data"]: - x["name"] = remove_prohibited_str(x["name"]) - key = x["name"] + for x in fgo_data['data']: + x['name'] = remove_prohibited_str(x['name']) + key = x['name'] data = add_to_data(data, x, game_name) - await download_img(data[key]["头像"], game_name, key) - logger.info(f"{key} is update...") - if game_name == "onmyoji": - url = "https://yys.res.netease.com/pc/zt/20161108171335/js/app/all_shishen.json?v74=" - onmyoji_data = (await AsyncHttpx.get(f"{url}")).json() + await download_img(data[key]['头像'], game_name, key) + logger.info(f'{key} is update...') + if game_name == 'onmyoji': + url = 'https://yys.res.netease.com/pc/zt/20161108171335/js/app/all_shishen.json?v74=' + response = await AsyncHttpx.get(url, timeout=7) + onmyoji_data = response.json() for x in onmyoji_data: - x["name"] = remove_prohibited_str(x["name"]) - key = x["name"] + x['name'] = remove_prohibited_str(x['name']) + key = x['name'] data = add_to_data(data, x, game_name) - logger.info(f"{key} is update...") + logger.info(f'{key} is update...') data = await _last_check(data, game_name) - except (TimeoutError, ConnectTimeout, CloseError): - logger.warning(f"更新 {game_name} 超时...") + except TimeoutError: + logger.warning(f'更新 {game_name} 超时...') return {}, 999 except Exception as e: - logger.error(f"更新 {game_name} 未知错误 {type(e)}:{e}") - return {}, 998 - with open(DRAW_PATH + f"{game_name}.json", "w", encoding="utf8") as wf: + logger.warning(f'更新 {game_name} 失败 {type(e)}:{e}...') + return {}, 999 + with info_path.open('w', encoding='utf8') as wf: json.dump(data, wf, ensure_ascii=False, indent=4) return data, 200 @@ -65,67 +63,62 @@ async def update_requests_info(game_name: str): # 添加到字典 def add_to_data(data: dict, x: dict, game_name: str) -> dict: member_dict = {} - if game_name == "fgo": + if game_name == 'fgo': member_dict = { - "id": x["id"], - "card_id": x["charid"], - "头像": x["icon"], - "名称": x["name"], - "职阶": x["classes"], - "星级": x["star"], - "hp": x["lvmax4hp"], - "atk": x["lvmax4atk"], - "card_quick": x["cardquick"], - "card_arts": x["cardarts"], - "card_buster": x["cardbuster"], - "宝具": x["tprop"], + 'id': x['id'], + 'card_id': x['charid'], + '头像': x['icon'], + '名称': x['name'], + '职阶': x['classes'], + '星级': x['star'], + 'hp': x['lvmax4hp'], + 'atk': x['lvmax4atk'], + 'card_quick': x['cardquick'], + 'card_arts': x['cardarts'], + 'card_buster': x['cardbuster'], + '宝具': x['tprop'], } - if game_name == "fgo_card": + if game_name == 'fgo_card': member_dict = { - "id": x["id"], - "card_id": x["equipid"], - "头像": x["icon"], - "名称": x["name"], - "星级": x["star"], - "hp": x["lvmax_hp"], - "atk": x["lvmax_atk"], - "skill_e": x["skill_e"].split("
")[:-1], + 'id': x['id'], + 'card_id': x['equipid'], + '头像': x['icon'], + '名称': x['name'], + '星级': x['star'], + 'hp': x['lvmax_hp'], + 'atk': x['lvmax_atk'], + 'skill_e': x['skill_e'].split('
')[: -1], } - if game_name == "onmyoji": + if game_name == 'onmyoji': member_dict = { - "id": x["id"], - "名称": x["name"], - "星级": x["level"], + 'id': x['id'], + '名称': x['name'], + '星级': x['level'], } - data[member_dict["名称"]] = member_dict + data[member_dict['名称']] = member_dict return data # 获取额外数据 async def _last_check(data: dict, game_name: str) -> dict: - if game_name == "fgo": - url = "http://fgo.vgtime.com/servant/" + if game_name == 'fgo': + url = 'http://fgo.vgtime.com/servant/' tasks = [] - semaphore = asyncio.Semaphore(SEMAPHORE) + semaphore = asyncio.Semaphore(draw_config.SEMAPHORE) for key in data.keys(): - tasks.append( - asyncio.ensure_future( - _async_update_fgo_extra_info(url, key, data[key]["id"], semaphore) - ) - ) - asyResult = await asyncio.gather(*tasks) - for x in asyResult: + tasks.append(asyncio.ensure_future( + _async_update_fgo_extra_info(url, key, data[key]['id'], semaphore))) + result = await asyncio.gather(*tasks) + for x in result: for key in x.keys(): - data[key]["入手方式"] = x[key]["入手方式"] - if game_name == "onmyoji": - url = "https://yys.163.com/shishen/{}.html" + data[key]['入手方式'] = x[key]['入手方式'] + if game_name == 'onmyoji': + url = 'https://yys.163.com/shishen/{}.html' for key in data.keys(): - text = (await AsyncHttpx.get(f'{url.format(data[key]["id"])}')).text - soup = BeautifulSoup(text, "lxml") - data[key]["头像"] = ( - "https:" + soup.find("div", {"class": "pic_wrap"}).find("img")["src"] - ) - await download_img(data[key]["头像"], game_name, key) + response = await AsyncHttpx.get(f'{url.format(data[key]["id"])}', timeout=7) + soup = BeautifulSoup(response.text, 'lxml') + data[key]['头像'] = "https:" + soup.find('div', {'class': 'pic_wrap'}).find('img')['src'] + await download_img(data[key]['头像'], game_name, key) return data @@ -134,28 +127,30 @@ async def _async_update_fgo_extra_info(url: str, key: str, _id: str, semaphore): async with semaphore: for i in range(10): try: - text = (await AsyncHttpx.get(f"{url}{_id}")).text - soup = BeautifulSoup(text, "lxml") - obtain = ( - soup.find("table", {"class": "uk-table uk-codex-table"}) - .find_all("td")[-1] - .text - ) - if obtain.find("限时活动免费获取 活动结束后无法获得") != -1: - obtain = ["活动获取"] - elif obtain.find("非限时UP无法获得") != -1: - obtain = ["限时召唤"] + response = await AsyncHttpx.get(f'{url}{_id}', timeout=7) + soup = BeautifulSoup(response.text, 'lxml') + obtain = soup.find('table', {'class': 'uk-table uk-codex-table'}).find_all('td')[-1].text + if obtain.find('限时活动免费获取 活动结束后无法获得') != -1: + obtain = ['活动获取'] + elif obtain.find('非限时UP无法获得') != -1: + obtain = ['限时召唤'] else: - if obtain.find("&") != -1: - obtain = obtain.strip().split("&") + if obtain.find('&') != -1: + obtain = obtain.strip().split('&') else: - obtain = obtain.strip().split(" ") - logger.info(f"Fgo获取额外信息 {key}....{obtain}") + obtain = obtain.strip().split(' ') + logger.info(f'Fgo获取额外信息 {key}....{obtain}') x = {key: {}} - x[key]["入手方式"] = obtain + x[key]['入手方式'] = obtain return x - except (TimeoutError, ConnectTimeout, CloseError): - logger.warning(f"访问{url}{_id} 第 {i}次 超时...已再次访问") + except TimeoutError: + logger.warning(f'访问{url}{_id} 第 {i}次 超时...已再次访问') except Exception as e: - logger.error(f"访问{url}{_id} 第 {i}次 未知错误 {type(e)}:{e}...已再次访问") + logger.warning(f'访问{url}{_id} 第 {i}次 发生错误:{e}...已再次访问') return {} + + + + + + diff --git a/plugins/draw_card/update_game_simple_info.py b/plugins/draw_card/update_game_simple_info.py index 60abc324..f7cdcf45 100755 --- a/plugins/draw_card/update_game_simple_info.py +++ b/plugins/draw_card/update_game_simple_info.py @@ -1,12 +1,12 @@ -from .config import DRAW_PATH, SEMAPHORE +from typing import Tuple +from .config import DRAW_DATA_PATH, draw_config from asyncio.exceptions import TimeoutError from bs4 import BeautifulSoup from .util import download_img from .util import remove_prohibited_str from urllib.parse import unquote -from services.log import logger from utils.http_utils import AsyncHttpx -from httpx import ConnectTimeout, CloseError +from nonebot.log import logger import bs4 import asyncio @@ -15,18 +15,21 @@ try: except ModuleNotFoundError: import json -headers = {'User-Agent': '"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)"'} +headers = { + "User-Agent": '"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)"' +} -async def update_simple_info(url: str, game_name: str) -> 'dict, int': +async def update_simple_info(url: str, game_name: str) -> Tuple[dict, int]: + info_path = DRAW_DATA_PATH / f"{game_name}.json" try: - with open(DRAW_PATH + f'{game_name}.json', 'r', encoding='utf8') as f: + with info_path.open("r", encoding="utf8") as f: data = json.load(f) except (ValueError, FileNotFoundError): data = {} try: - text = (await AsyncHttpx.get(url)).text - soup = BeautifulSoup(text, 'lxml') + response = await AsyncHttpx.get(url, timeout=7) + soup = BeautifulSoup(response.text, "lxml") divs = get_char_divs(soup, game_name) for div in divs: type_lst = get_type_lst(div, game_name) @@ -38,161 +41,185 @@ async def update_simple_info(url: str, game_name: str) -> 'dict, int': continue for char in contents[1:]: try: - data = await retrieve_char_data(char, game_name, data, index) + data = await retrieve_char_data( + char, game_name, data, index + ) except AttributeError: continue index += 1 data = await _last_check(data, game_name) - except (TimeoutError, ConnectTimeout, CloseError): - logger.warning(f'更新 {game_name} 超时...') + except TimeoutError: + logger.warning(f"更新 {game_name} 超时...") return {}, 999 - with open(DRAW_PATH + f'{game_name}.json', 'w', encoding='utf8') as wf: + with info_path.open("w", encoding="utf8") as wf: wf.write(json.dumps(data, ensure_ascii=False, indent=4)) return data, 200 # 获取所有包含需要图片的divs def get_char_divs(soup: bs4.BeautifulSoup, game_name: str) -> bs4.element.ResultSet: - if game_name == 'pcr': - return soup.find_all('div', {'class': 'tabbertab'}) - if game_name == 'azur': - return soup.find_all('div', {'class': 'resp-tabs'}) + # if game_name == "pcr": + # return soup.find_all("div", {"class": "tabbertab"}) + if game_name in ["azur", "pcr"]: + return soup.find_all("div", {"class": "resp-tabs"}) # 拿到所有类型 def get_type_lst(div: bs4.element.Tag, game_name: str): - if game_name in ['pcr', 'azur']: - return div.find('div', {'class': 'resp-tabs-container'}).find_all('div', {'class': 'resp-tab-content'}) + if game_name in ["pcr", "azur"]: + return div.find("div", {"class": "resp-tabs-container"}).find_all( + "div", {"class": "resp-tab-content"} + ) # 获取所有角色div def get_char_lst_contents(char_lst: bs4.element.Tag, game_name: str): contents = [] - # logger.info(len(char_lst.find_all('tr'))) - if game_name == 'pcr': + # print(len(char_lst.find_all('tr'))) + if game_name == "pcr": contents = char_lst.contents - if game_name == 'azur': - contents = char_lst.find('table').find('tbody').contents[-1].find('td').contents - return [x for x in contents if x != '\n'] + if game_name == "azur": + contents = char_lst.find("table").find("tbody").contents[-1].find("td").contents + return [x for x in contents if x != "\n"] # 额外数据 -async def _last_check(data: dict, game_name: str) -> dict: - if game_name == 'azur': +async def _last_check( + data: dict, game_name: str +) -> dict: + if game_name == "azur": idx = 1 for url in [ - 'https://patchwiki.biligame.com/images/blhx/thumb/1/15/pxho13xsnkyb546tftvh49etzdh74cf.png/60px' - '-舰娘头像外框普通.png', - 'https://patchwiki.biligame.com/images/blhx/thumb/a/a9/k8t7nx6c8pan5vyr8z21txp45jxeo66.png/60px' - '-舰娘头像外框稀有.png', - 'https://patchwiki.biligame.com/images/blhx/thumb/a/a5/5whkzvt200zwhhx0h0iz9qo1kldnidj.png/60px' - '-舰娘头像外框精锐.png', - 'https://patchwiki.biligame.com/images/blhx/thumb/a/a2/ptog1j220x5q02hytpwc8al7f229qk9.png/60px-' - '舰娘头像外框超稀有.png' - 'https://patchwiki.biligame.com/images/blhx/thumb/0/0f/n28p7p3opfn5mhgjyio55ljsllhknwz.png/60px-' - '舰娘头像外框精锐META.png' + "https://patchwiki.biligame.com/images/blhx/thumb/1/15/pxho13xsnkyb546tftvh49etzdh74cf.png/60px" + "-舰娘头像外框普通.png", + "https://patchwiki.biligame.com/images/blhx/thumb/a/a9/k8t7nx6c8pan5vyr8z21txp45jxeo66.png/60px" + "-舰娘头像外框稀有.png", + "https://patchwiki.biligame.com/images/blhx/thumb/a/a5/5whkzvt200zwhhx0h0iz9qo1kldnidj.png/60px" + "-舰娘头像外框精锐.png", + "https://patchwiki.biligame.com/images/blhx/thumb/a/a2/ptog1j220x5q02hytpwc8al7f229qk9.png/60px-" + "舰娘头像外框超稀有.png", ]: - await download_img(url, 'azur', f'{idx}_star') + await download_img(url, "azur", f"{idx}_star") idx += 1 tasks = [] - semaphore = asyncio.Semaphore(SEMAPHORE) + semaphore = asyncio.Semaphore(draw_config.SEMAPHORE) for key in data.keys(): - tasks.append(asyncio.ensure_future(_async_update_azur_extra_info(key, semaphore))) - asyResult = await asyncio.gather(*tasks) - for x in asyResult: + tasks.append( + asyncio.ensure_future( + _async_update_azur_extra_info(key, semaphore) + ) + ) + result = await asyncio.gather(*tasks) + for x in result: for key in x.keys(): - data[key]['获取途径'] = x[key]['获取途径'] + data[key]["获取途径"] = x[key]["获取途径"] return data azur_type = { - '0': '驱逐', - '1': '轻巡', - '2': '重巡', - '3': '超巡', - '4': '战巡', - '5': '战列', - '6': '航母', - '7': '航站', - '8': '轻航', - '9': '重炮', - '10': '维修', - '11': '潜艇', - '12': '运输', + "0": "驱逐", + "1": "轻巡", + "2": "重巡", + "3": "超巡", + "4": "战巡", + "5": "战列", + "6": "航母", + "7": "航站", + "8": "轻航", + "9": "重炮", + "10": "维修", + "11": "潜艇", + "12": "运输", } # 整理数据 -async def retrieve_char_data(char: bs4.element.Tag, game_name: str, data: dict, index: int = 0) -> dict: +async def retrieve_char_data( + char: bs4.element.Tag, + game_name: str, + data: dict, + index: int = 0, +) -> dict: member_dict = {} - if game_name == 'pcr': + if game_name == "pcr": member_dict = { - '头像': unquote(char.find('img', {'class': 'img-kk'})['src']), - '名称': remove_prohibited_str(char.find('a')['title']), - '星级': 3 - index} - if game_name == 'azur': - char = char.find('div').find('div').find('div') - avatar_img = char.find('a').find('img') - char = char.find('div') + "头像": unquote(char.find("a").find("img")["src"]), + "名称": remove_prohibited_str(char.find("a")["title"]), + "星级": 3 - index, + } + if game_name == "azur": + char = char.find("div").find("div").find("div") + avatar_img = char.find("a").find("img") + char = char.find("div") try: - member_dict['名称'] = remove_prohibited_str(char.find('a')['title']) + member_dict["名称"] = remove_prohibited_str(char.find("a")["title"]) except TypeError: - member_dict['名称'] = char.find('a')['title'][:-4] + member_dict["名称"] = char.find("a")["title"][:-4] try: - member_dict['头像'] = unquote(str(avatar_img['srcset']).split(' ')[-2]) + member_dict["头像"] = unquote(str(avatar_img["srcset"]).split(" ")[-2]) except KeyError: - member_dict['头像'] = unquote(str(avatar_img['src']).split(' ')[-2]) + member_dict["头像"] = unquote(str(avatar_img["src"]).split(" ")[-2]) except TypeError: - member_dict['头像'] = "img link not find..." + member_dict["头像"] = "img link not find..." logger.warning(f'{member_dict["名称"]} 图片缺失....') - star = char.find('img')['alt'] - if star == '舰娘头像外框普通.png': + star = char.find("img")["alt"] + if star == "舰娘头像外框普通.png": star = 1 - elif star == '舰娘头像外框稀有.png': + elif star == "舰娘头像外框稀有.png": star = 2 - elif star == '舰娘头像外框精锐.png': + elif star == "舰娘头像外框精锐.png": star = 3 - elif star == '舰娘头像外框超稀有.png': + elif star == "舰娘头像外框超稀有.png": star = 4 - elif star == '舰娘头像外框海上传奇.png': + elif star == "舰娘头像外框海上传奇.png": star = 5 - elif star in ['舰娘头像外框最高方案.png', '舰娘头像外框决战方案.png', '舰娘头像外框超稀有META.png', '舰娘头像外框精锐META.png']: + elif star in [ + "舰娘头像外框最高方案.png", + "舰娘头像外框决战方案.png", + "舰娘头像外框超稀有META.png", + "舰娘头像外框精锐META.png", + ]: star = 6 else: star = 6 - member_dict['星级'] = star - member_dict['类型'] = azur_type[str(index)] - await download_img(member_dict['头像'], game_name, member_dict['名称']) - data[member_dict['名称']] = member_dict + member_dict["星级"] = star + member_dict["类型"] = azur_type[str(index)] + await download_img(member_dict["头像"], game_name, member_dict["名称"]) + data[member_dict["名称"]] = member_dict logger.info(f'{member_dict["名称"]} is update...') return data -async def _async_update_azur_extra_info(key: str, semaphore): - if key[-1] == '改': - return {key: {'获取途径': ['无法建造']}} +async def _async_update_azur_extra_info( + key: str, semaphore +): + if key[-1] == "改": + return {key: {"获取途径": ["无法建造"]}} async with semaphore: for i in range(20): try: - text = (await AsyncHttpx.get(f'https://wiki.biligame.com/blhx/{key}')).text - soup = BeautifulSoup(text, 'lxml') + res = await AsyncHttpx.get(f"https://wiki.biligame.com/blhx/{key}", timeout=7) + soup = BeautifulSoup(res.text, "lxml") try: - construction_time = str(soup.find('table', {'class': 'wikitable sv-general'}).find('tbody')) - x = {key: {'获取途径': []}} - if construction_time.find('无法建造') != -1: - x[key]['获取途径'].append('无法建造') - elif construction_time.find('活动已关闭') != -1: - x[key]['获取途径'].append('活动限定') + construction_time = str( + soup.find("table", {"class": "wikitable sv-general"}).find( + "tbody" + ) + ) + x = {key: {"获取途径": []}} + if construction_time.find("无法建造") != -1: + x[key]["获取途径"].append("无法建造") + elif construction_time.find("活动已关闭") != -1: + x[key]["获取途径"].append("活动限定") else: - x[key]['获取途径'].append('可以建造') + x[key]["获取途径"].append("可以建造") logger.info(f'碧蓝航线获取额外信息 {key}...{x[key]["获取途径"]}') except AttributeError: - x = {key: {'获取途径': []}} - logger.warning(f'碧蓝航线获取额外信息错误 {key}...{[]}') + x = {key: {"获取途径": []}} + logger.warning(f"碧蓝航线获取额外信息错误 {key}...{[]}") return x - except (TimeoutError, ConnectTimeout, CloseError): - logger.warning(f'访问 https://wiki.biligame.com/blhx/{key} 第 {i}次 超时/失败...已再次访问') - except Exception as e: - logger.error(f'访问 https://wiki.biligame.com/blhx/{key} 第 {i}次 未知错误 {type(e)}:{e}...已再次访问') + except TimeoutError: + logger.warning( + f"访问 https://wiki.biligame.com/blhx/{key} 第 {i}次 超时...已再次访问" + ) return {} - diff --git a/plugins/draw_card/util.py b/plugins/draw_card/util.py index 759771d2..9bfb9c57 100755 --- a/plugins/draw_card/util.py +++ b/plugins/draw_card/util.py @@ -1,34 +1,26 @@ -from nonebot.adapters.cqhttp import MessageSegment -from typing import List, Union, Set -from pathlib import Path -from .config import path_dict -from configs.path_config import IMAGE_PATH -from utils.http_utils import AsyncHttpx -import nonebot -import pypinyin -from utils.image_utils import BuildImage import platform -from services.log import logger +from asyncio.exceptions import TimeoutError +from utils.utils import cn2py +from utils.http_utils import AsyncHttpx +from typing import List, Tuple, Union, Set +from .config import draw_config, DRAW_IMAGE_PATH +import nonebot +from PIL import UnidentifiedImageError +from utils.image_utils import BuildImage +from nonebot.adapters.onebot.v11 import MessageSegment +from nonebot.log import logger import random from dataclasses import dataclass import os import asyncio -from PIL import UnidentifiedImageError -try: - import ujson as json -except ModuleNotFoundError: - import json -driver: nonebot.Driver = nonebot.get_driver() +driver = nonebot.get_driver() loop = asyncio.get_event_loop() -headers = {'User-Agent': '"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)"'} - - @dataclass class BaseData: name: str @@ -44,47 +36,52 @@ class UpEvent: async def download_img(url: str, path: str, name: str) -> bool: - path = path.split('_')[0] + path = path.split("_")[0] codename = cn2py(name) - file = Path(IMAGE_PATH + f'/draw_card/{path}/{codename}.png') - if not file.exists(): - file.parent.mkdir(exist_ok=True, parents=True) + img_path = DRAW_IMAGE_PATH / f"{path}" / f"{codename}.png" + if not img_path.exists(): try: - if await AsyncHttpx.download_file(url, IMAGE_PATH + f'/draw_card/{path}/{codename}.png'): - logger.info(f'下载 {path_dict[path]} 图片成功,名称:{name},url:{url}') + if await AsyncHttpx.download_file(url, img_path): + logger.info( + f"下载 {draw_config.path_dict[path]} 图片成功,名称:{name},url:{url}" + ) return True - except Exception as e: - logger.warning(f'下载 {path_dict[path]} 链接错误 {type(e)}:{e},名称:{name},url:{url}') + except TimeoutError: + logger.warning(f"下载 {draw_config.path_dict[path]} 图片超时,名称:{name},url:{url}") + # logger.info(f'{path_dict[path]} 图片 {name} 已存在') return False @driver.on_startup def _check_dir(): - for dir_name in path_dict.keys(): - _p = Path(IMAGE_PATH + f'/draw_card/' + dir_name) - if not _p.exists(): - _p.mkdir(parents=True, exist_ok=True) + for dir_name in draw_config.path_dict.keys(): + dir_path = DRAW_IMAGE_PATH / f"{dir_name}" + if not dir_path.exists(): + dir_path.mkdir(parents=True, exist_ok=True) -async def generate_img(card_set: Union[Set[BaseData], List[BaseData]], game_name: str, star_list: list) -> str: +async def generate_img( + card_set: Union[Set[BaseData], List[BaseData]], game_name: str, star_list: list +) -> str: # try: img_list = [] background_list = [] for x in card_set: - if game_name == 'prts': + if game_name == "prts": if x.star == 6: - background_list.append('#FFD700') + background_list.append("#FFD700") elif x.star == 5: - background_list.append('#DAA520') + background_list.append("#DAA520") elif x.star == 4: - background_list.append('#9370D8') + background_list.append("#9370D8") else: - background_list.append('white') - if game_name == 'azur': - if os.path.exists(IMAGE_PATH + f'/draw_card/{game_name}/{x.star}_star.png'): - background_list.append(IMAGE_PATH + f'/draw_card/{game_name}/{x.star}_star.png') - pyname = cn2py(x.name) - img_list.append(IMAGE_PATH + f'/draw_card/{game_name}/{pyname}.png') + background_list.append("white") + img_path = DRAW_IMAGE_PATH / f"{game_name}" / f"{x.star}_star.png" + if game_name == "azur": + if img_path.exists(): + background_list.append(str(img_path)) + py_name = cn2py(x.name) + img_list.append(str(DRAW_IMAGE_PATH / f"{game_name}" / f"{py_name}.png")) img_len = len(img_list) w = 100 * 10 if img_len <= 10: @@ -94,7 +91,9 @@ async def generate_img(card_set: Union[Set[BaseData], List[BaseData]], game_name h = 100 * int(img_len / 10) else: h = 100 * int(img_len / 10) + 100 - card_img = await asyncio.get_event_loop().run_in_executor(None, _pst, h, img_list, game_name, background_list) + card_img = await asyncio.get_event_loop().run_in_executor( + None, _pst, h, img_list, game_name, background_list + ) num = 0 for n in star_list: num += n @@ -108,12 +107,12 @@ def _pst(h: int, img_list: list, game_name: str, background_list: list): idx = 0 for img in img_list: try: - if game_name == 'prts': + if game_name == "prts": 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: + elif game_name == "azur" and background_list: bk = BuildImage(100, 100, background=background_list[idx]) b = BuildImage(98, 90, background=img) bk.paste(b, (1, 5)) @@ -122,38 +121,75 @@ def _pst(h: int, img_list: list, game_name: str, background_list: list): try: b = BuildImage(100, 100, background=img) except UnidentifiedImageError as e: - logger.warning(f'无法识别图片 已删除图片,下次更新重新下载... e:{e}') + logger.warning(f"无法识别图片 已删除图片,下次更新重新下载... e:{e}") if os.path.exists(img): os.remove(img) - b = BuildImage(100, 100, color='black') + b = BuildImage(100, 100, color="black") except FileNotFoundError: - logger.warning(f'{img} not exists') - b = BuildImage(100, 100, color='black') + logger.warning(f"{img} not exists") + b = BuildImage(100, 100, color="black") card_img.paste(b) idx += 1 return card_img -def init_star_rst(star_list: list, cnlist: list, max_star_list: list, max_star_index_list: list, up_list: list = None) -> str: +# 初始化输出数据 +def init_star_rst( + star_list: list, + cnlist: list, + max_star_list: list, + max_star_index_list: list, + up_list: list = None, +) -> str: if not up_list: up_list = [] - rst = '' + rst = "" for i in range(len(star_list)): if star_list[i]: - rst += f'[{cnlist[i]}×{star_list[i]}] ' - rst += '\n' + rst += f"[{cnlist[i]}×{star_list[i]}] " + rst += "\n" for i in range(len(max_star_list)): if max_star_list[i] in up_list: - rst += f'第 {max_star_index_list[i]+1} 抽获取UP {max_star_list[i]}\n' + rst += f"第 {max_star_index_list[i]+1} 抽获取UP {max_star_list[i]}\n" else: - rst += f'第 {max_star_index_list[i]+1} 抽获取 {max_star_list[i]}\n' + rst += f"第 {max_star_index_list[i]+1} 抽获取 {max_star_list[i]}\n" return rst +# 更好的初始化 +def init_rst( + max_star_char_dict: dict, + star_num_list: List[int], + star: List[str], + up_list: list = None, +): + # print(max_star_char_dict) + # print(star_num_list) + # print(up_list) + up_list = up_list if up_list else [] + rst = "" + for i in range(len(star_num_list)): + if star_num_list[i]: + rst += f"[{star[i]}×{star_num_list[i]}] " + rst += "\n" + _tmp = [] + for name in max_star_char_dict.keys(): + _tmp += max_star_char_dict[name] + for index in sorted(_tmp): + for name in max_star_char_dict.keys(): + if index in max_star_char_dict[name]: + if name in up_list: + rst += f"第 {index} 抽获取UP {name}\n" + else: + rst += f"第 {index} 抽获取 {name}\n" + print(rst) + return rst[:-1] if rst else "" + + def max_card(_dict: dict): _max_value = max(_dict.values()) _max_user = list(_dict.keys())[list(_dict.values()).index(_max_value)] - return f'抽取到最多的是{_max_user},共抽取了{_max_value}次' + return f"抽取到最多的是{_max_user},共抽取了{_max_value}次" # ThreeHighest = nlargest(3, operator_dict, key=operator_dict.get) # rst = '最喜欢你的前三位是干员是:\n' # for name in ThreeHighest: @@ -161,6 +197,55 @@ def max_card(_dict: dict): # return rst[:-1] +# 获取up和概率 +async def init_up_char(announcement): + UP_CHAR = [] + UP_ARMS = [] + tmp = "" + up_char_dict = await announcement.update_up_char() + for x in list(up_char_dict.keys()): + tmp += up_char_dict[x]["title"] + "[\n]" + tmp = tmp.split("[\n]") + _CURRENT_CHAR_POOL_TITLE = tmp[0] + if len(up_char_dict) > 1: + _CURRENT_ARMS_POOL_TITLE = tmp[1] + else: + _CURRENT_ARMS_POOL_TITLE = "" + POOL_IMG = "" + x = [x for x in list(up_char_dict.keys())] + if _CURRENT_CHAR_POOL_TITLE: + POOL_IMG += MessageSegment.image(up_char_dict[x[0]]["pool_img"]) + try: + if _CURRENT_ARMS_POOL_TITLE: + POOL_IMG += MessageSegment.image(up_char_dict[x[1]]["pool_img"]) + except (IndexError, KeyError): + pass + logger.info( + f"成功获取{announcement.game_name}当前up信息...当前up池: {_CURRENT_CHAR_POOL_TITLE} & {_CURRENT_ARMS_POOL_TITLE}" + ) + for key in up_char_dict.keys(): + for star in up_char_dict[key]["up_char"].keys(): + up_char_lst = [] + for char in up_char_dict[key]["up_char"][star].keys(): + up_char_lst.append(char) + if up_char_lst: + if key == "char": + UP_CHAR.append( + UpEvent(star=int(star), operators=up_char_lst, zoom=0) + ) + else: + UP_ARMS.append( + UpEvent(star=int(star), operators=up_char_lst, zoom=0) + ) + return ( + _CURRENT_CHAR_POOL_TITLE, + _CURRENT_ARMS_POOL_TITLE, + POOL_IMG, + UP_CHAR, + UP_ARMS, + ) + + def is_number(s) -> bool: try: float(s) @@ -169,6 +254,7 @@ def is_number(s) -> bool: pass try: import unicodedata + unicodedata.numeric(s) return True except (TypeError, ValueError): @@ -176,13 +262,6 @@ def is_number(s) -> bool: return False -def cn2py(word) -> str: - temp = "" - for i in pypinyin.pinyin(word, style=pypinyin.NORMAL): - temp += ''.join(i) - return temp - - def set_list(lst: List[BaseData]) -> list: tmp = [] name_lst = [] @@ -193,6 +272,7 @@ def set_list(lst: List[BaseData]) -> list: return tmp +# 获取星级 def get_star(star_lst: List[int], probability_lst: List[float]) -> int: rand = random.random() add = 0 @@ -206,49 +286,14 @@ def get_star(star_lst: List[int], probability_lst: List[float]) -> int: return star_lst[i] -# 获取up和概率 -async def init_up_char(announcement): - UP_CHAR = [] - UP_ARMS = [] - tmp = '' - up_char_dict = await announcement.update_up_char() - for x in list(up_char_dict.keys()): - tmp += up_char_dict[x]['title'] + '[\n]' - tmp = tmp.split('[\n]') - _CURRENT_CHAR_POOL_TITLE = tmp[0] - if len(up_char_dict) > 1: - _CURRENT_ARMS_POOL_TITLE = tmp[1] - else: - _CURRENT_ARMS_POOL_TITLE = '' - POOL_IMG = '' - x = [x for x in list(up_char_dict.keys())] - if _CURRENT_CHAR_POOL_TITLE: - POOL_IMG += MessageSegment.image(up_char_dict[x[0]]['pool_img']) - try: - if _CURRENT_ARMS_POOL_TITLE: - POOL_IMG += MessageSegment.image(up_char_dict[x[1]]['pool_img']) - except (IndexError, KeyError): - pass - logger.info(f'成功获取{announcement.game_name}当前up信息...当前up池: {_CURRENT_CHAR_POOL_TITLE} & {_CURRENT_ARMS_POOL_TITLE}') - for key in up_char_dict.keys(): - for star in up_char_dict[key]['up_char'].keys(): - up_char_lst = [] - for char in up_char_dict[key]['up_char'][star].keys(): - up_char_lst.append(char) - if up_char_lst: - if key == 'char': - UP_CHAR.append(UpEvent(star=int(star), operators=up_char_lst, zoom=0)) - else: - UP_ARMS.append(UpEvent(star=int(star), operators=up_char_lst, zoom=0)) - return _CURRENT_CHAR_POOL_TITLE, _CURRENT_ARMS_POOL_TITLE, POOL_IMG, UP_CHAR, UP_ARMS - - # 整理数据 -def format_card_information(count: int, star_list: List[int], func, pool_name: str = '', guaranteed: bool = True): - max_star_lst = [] # 获取的最高星级角色列表 - max_index_lst = [] # 获取最高星级角色的次数 - obj_list = [] # 获取所有角色 - obj_dict = {} # 获取角色次数字典 +def format_card_information( + count: int, star_list: List[int], func, pool_name: str = "", guaranteed: bool = True +): + max_star_lst = [] # 获取的最高星级角色列表 + max_index_lst = [] # 获取最高星级角色的次数 + obj_list = [] # 获取所有角色 + obj_dict = {} # 获取角色次数字典 _count = -1 if guaranteed: _count = 0 @@ -285,28 +330,28 @@ def format_card_information(count: int, star_list: List[int], func, pool_name: s # 检测次数是否合法 -def check_num(num: str, max_num: int) -> 'str, bool': +def check_num(num: str, max_num: int) -> Tuple[str, bool]: if is_number(num): try: num = int(num) except ValueError: - return '必!须!是!数!字!', False + return "必!须!是!数!字!", False if num > max_num: - return '一井都满不足不了你嘛!快爬开!', False + return "一井都满不足不了你嘛!快爬开!", False if num < 1: - return '虚空抽卡???', False + return "虚空抽卡???", False else: return str(num), True # 移除windows和linux下特殊字符 -def remove_prohibited_str(name: str): - if platform.system().lower() == 'windows': - tmp = '' +def remove_prohibited_str(name: str) -> str: + if platform.system().lower() == "windows": + tmp = "" for i in name: - if i not in ['\\', '/', ':', '*', '?', '"', '<', '>', '|']: + if i not in ["\\", "/", ":", "*", "?", '"', "<", ">", "|"]: tmp += i name = tmp else: - name = name.replace('/', '\\') + name = name.replace("/", "\\") return name diff --git a/plugins/epic/__init__.py b/plugins/epic/__init__.py index 34301248..9c8f0377 100755 --- a/plugins/epic/__init__.py +++ b/plugins/epic/__init__.py @@ -1,6 +1,6 @@ -from nonebot import on_command +from nonebot import on_regex from services.log import logger -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent from nonebot.typing import T_State from utils.utils import scheduler, get_bot from .data_source import get_epic_free @@ -33,7 +33,7 @@ Config.add_plugin_config( default_value=True, ) -epic = on_command("epic", priority=5, block=True) +epic = on_regex("^epic$", priority=5, block=True) @epic.handle() diff --git a/plugins/fake_msg.py b/plugins/fake_msg.py index aab9575b..44d16314 100755 --- a/plugins/fake_msg.py +++ b/plugins/fake_msg.py @@ -1,7 +1,7 @@ -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message +from nonebot.params import CommandArg from nonebot import on_command -from utils.utils import get_message_img, get_message_text +from utils.utils import get_message_img from utils.message_builder import share from services.log import logger @@ -30,8 +30,8 @@ fake_msg = on_command("假消息", priority=5, block=True) @fake_msg.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()).split(" ") +async def _(event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip().split() img = get_message_img(event.json()) if len(msg) > 1: if len(msg) == 2: diff --git a/plugins/fudu.py b/plugins/fudu.py index a150ecb9..bbab722e 100755 --- a/plugins/fudu.py +++ b/plugins/fudu.py @@ -1,16 +1,17 @@ -from nonebot.adapters.cqhttp.permission import GROUP -from configs.path_config import IMAGE_PATH +from nonebot.adapters.onebot.v11.permission import GROUP +from configs.path_config import TEMP_PATH from utils.image_utils import get_img_hash import random from utils.message_builder import image from nonebot import on_message -from utils.utils import get_message_text, get_message_img -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent +from utils.utils import get_message_img +from nonebot.params import CommandArg, Command +from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message from configs.config import Config from utils.http_utils import AsyncHttpx from utils.manager import group_manager from services.log import logger +from typing import Tuple __zx_plugin_name__ = "复读" @@ -80,18 +81,18 @@ fudu = on_message(permission=GROUP, priority=9) @fudu.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): if ( event.is_tome() - or state["_prefix"]["raw_command"] + or cmd or not await group_manager.check_group_task_status(event.group_id, "fudu") ): return - if get_message_text(event.json()): - if get_message_text(event.json()).find("@可爱的小真寻") != -1: + if arg.extract_plain_text().strip(): + if arg.extract_plain_text().strip().find("@可爱的小真寻") != -1: await fudu.finish("复制粘贴的虚空艾特?", at_sender=True) img = get_message_img(event.json()) - msg = get_message_text(event.json()) + msg = arg.extract_plain_text().strip() if not img and not msg: return if img: @@ -130,9 +131,9 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): async def get_fudu_img_hash(url, group_id): try: if await AsyncHttpx.download_file( - url, IMAGE_PATH + f"temp/compare_{group_id}_img.jpg" + url, TEMP_PATH / f"compare_{group_id}_img.jpg" ): - img_hash = get_img_hash(IMAGE_PATH + f"temp/compare_{group_id}_img.jpg") + img_hash = get_img_hash(TEMP_PATH / f"compare_{group_id}_img.jpg") return str(img_hash) else: logger.warning(f"复读下载图片失败...") diff --git a/plugins/genshin/almanac/__init__.py b/plugins/genshin/almanac/__init__.py index 743a1d00..d367293f 100755 --- a/plugins/genshin/almanac/__init__.py +++ b/plugins/genshin/almanac/__init__.py @@ -1,13 +1,11 @@ from utils.utils import get_bot, scheduler from nonebot import on_command -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent +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 pathlib import Path __zx_plugin_name__ = "原神老黄历" __plugin_usage__ = """ @@ -40,12 +38,12 @@ Config.add_plugin_config( almanac = on_command("原神黄历", priority=5, block=True) -ALC_PATH = Path(IMAGE_PATH) / "genshin" / "alc" +ALC_PATH = IMAGE_PATH / "genshin" / "alc" ALC_PATH.mkdir(parents=True, exist_ok=True) @almanac.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent,): alc_img = await get_alc_image(ALC_PATH) if alc_img: mes = alc_img + "\n ※ 黄历数据来源于 genshin.pub" @@ -71,7 +69,7 @@ async def _(): gl = [g["group_id"] for g in gl] alc_img = await get_alc_image(ALC_PATH) if alc_img: - mes = alc_img + "\n ※ 黄历数据来源于 genshin.pub" + mes = "[[_task|genshin_alc]]" + alc_img + "\n ※ 黄历数据来源于 genshin.pub" for gid in gl: if await group_manager.check_group_task_status(gid, "genshin_alc"): await bot.send_group_msg(group_id=int(gid), message="" + mes) diff --git a/plugins/genshin/almanac/data_source.py b/plugins/genshin/almanac/data_source.py index 85dc2e58..4c0544f0 100755 --- a/plugins/genshin/almanac/data_source.py +++ b/plugins/genshin/almanac/data_source.py @@ -2,7 +2,7 @@ from utils.message_builder import image from datetime import datetime from pathlib import Path from utils.http_utils import AsyncPlaywright -from nonebot.adapters.cqhttp import MessageSegment +from nonebot.adapters.onebot.v11 import MessageSegment from typing import Optional import os diff --git a/plugins/genshin/material_remind/__init__.py b/plugins/genshin/material_remind/__init__.py index 05cca0ac..df64ee27 100755 --- a/plugins/genshin/material_remind/__init__.py +++ b/plugins/genshin/material_remind/__init__.py @@ -1,6 +1,5 @@ from nonebot import on_command, Driver -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, Message, GroupMessageEvent from utils.message_builder import image from utils.image_utils import BuildImage from utils.browser import get_browser @@ -8,7 +7,6 @@ from configs.path_config import IMAGE_PATH import nonebot from services.log import logger from nonebot.permission import SUPERUSER -from pathlib import Path from typing import List from datetime import datetime, timedelta import os @@ -49,12 +47,12 @@ super_cmd = on_command("更新原神今日素材", permission=SUPERUSER, priorit @material.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent): if time.strftime("%w") == "0": await material.send("今天是周日,所有材料副本都开放了。") return file_name = str((datetime.now() - timedelta(hours=4)).date()) - if not (Path(IMAGE_PATH) / "genshin" / "material" / f"{file_name}.png").exists(): + if not (IMAGE_PATH / "genshin" / "material" / f"{file_name}.png").exists(): await update_image() await material.send( Message( @@ -69,7 +67,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @super_cmd.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): if await update_image(): await super_cmd.send("更新成功...") logger.info(f"更新每日天赋素材成功...") @@ -119,26 +117,26 @@ async def update_image(): for _ in range(index * 3): await div.press("PageUp") file_list = os.listdir(f"{IMAGE_PATH}/genshin/material") - char_imgs = [ + char_img = [ f"{IMAGE_PATH}/genshin/material/{x}" for x in file_list if x.startswith("char") ] - weapons_imgs = [ + weapons_img = [ f"{IMAGE_PATH}/genshin/material/{x}" for x in file_list if x.startswith("weapons") ] - char_imgs.sort() - weapons_imgs.sort() + char_img.sort() + weapons_img.sort() height = await asyncio.get_event_loop().run_in_executor( - None, get_background_height, weapons_imgs + None, get_background_height, weapons_img ) background_img = BuildImage(1200, height + 100, color="#f6f2ee") current_width = 50 - for imgs in [char_imgs, weapons_imgs]: + for img_list in [char_img, weapons_img]: current_height = 20 - for img in imgs: + for img in img_list: x = BuildImage(0, 0, background=img) background_img.paste(x, (current_width, current_height)) current_height += x.size[1] @@ -155,14 +153,14 @@ async def update_image(): # 获取背景高度以及修改最后一张图片的黑边 -def get_background_height(weapons_imgs: List[str]) -> int: +def get_background_height(weapons_img: List[str]) -> int: height = 0 - for weapons in weapons_imgs: + for weapons in weapons_img: height += BuildImage(0, 0, background=weapons).size[1] - last_weapon = BuildImage(0, 0, background=weapons_imgs[-1]) + last_weapon = BuildImage(0, 0, background=weapons_img[-1]) w, h = last_weapon.size last_weapon.crop((0, 0, w, h - 10)) - last_weapon.save(weapons_imgs[-1]) + last_weapon.save(weapons_img[-1]) return height diff --git a/plugins/genshin/query_resource_points/__init__.py b/plugins/genshin/query_resource_points/__init__.py index 20c919e0..fcee9511 100755 --- a/plugins/genshin/query_resource_points/__init__.py +++ b/plugins/genshin/query_resource_points/__init__.py @@ -1,11 +1,11 @@ from nonebot import on_command, on_regex from .query_resource import get_resource_type_list, query_resource, init, check_resource_exists -from utils.utils import get_message_text, scheduler -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent, Message -from nonebot.typing import T_State +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message +from utils.utils import scheduler from services.log import logger from configs.config import NICKNAME from nonebot.permission import SUPERUSER +from nonebot.params import CommandArg import re try: @@ -51,8 +51,8 @@ update_info = on_command("更新原神资源信息", permission=SUPERUSER, prior @qr.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - resource_name = get_message_text(event.json()) +async def _(event: MessageEvent, arg: Message = CommandArg()): + resource_name = arg.extract_plain_text().strip() if check_resource_exists(resource_name): await qr.send("正在生成位置....") resource = await query_resource(resource_name) @@ -66,9 +66,9 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @rex_qr.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) - if msg.find("在哪") != -1: +async def _(event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() + if "在哪" in msg: rs = re.search("(.*)在哪.*?", msg) resource_name = rs.group(1) if rs else "" else: @@ -86,7 +86,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @qr_lst.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(bot: Bot, event: MessageEvent): txt = get_resource_type_list() txt_list = txt.split("\n") if isinstance(event, GroupMessageEvent): @@ -113,7 +113,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @update_info.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): await init(True) await update_info.send("更新原神资源信息完成...") diff --git a/plugins/genshin/query_resource_points/map.py b/plugins/genshin/query_resource_points/map.py index 59c837e5..83122f2f 100755 --- a/plugins/genshin/query_resource_points/map.py +++ b/plugins/genshin/query_resource_points/map.py @@ -1,4 +1,3 @@ -from pathlib import Path from configs.path_config import IMAGE_PATH, TEXT_PATH from utils.image_utils import BuildImage from typing import Tuple, List @@ -10,10 +9,10 @@ try: except ModuleNotFoundError: import json -icon_path = Path(IMAGE_PATH) / "genshin" / "genshin_icon" -map_path = Path(IMAGE_PATH) / "genshin" / "map" / "map.png" -resource_label_file = Path(TEXT_PATH) / "genshin" / "resource_label_file.json" -resource_point_file = Path(TEXT_PATH) / "genshin" / "resource_point_file.json" +icon_path = IMAGE_PATH / "genshin" / "genshin_icon" +map_path = IMAGE_PATH / "genshin" / "map" / "map.png" +resource_label_file = TEXT_PATH / "genshin" / "resource_label_file.json" +resource_point_file = TEXT_PATH / "genshin" / "resource_point_file.json" class Map: diff --git a/plugins/genshin/query_resource_points/query_resource.py b/plugins/genshin/query_resource_points/query_resource.py index 717a6652..7415a6b1 100755 --- a/plugins/genshin/query_resource_points/query_resource.py +++ b/plugins/genshin/query_resource_points/query_resource.py @@ -9,7 +9,6 @@ from asyncio import Semaphore from utils.image_utils import is_valid from utils.http_utils import AsyncHttpx from httpx import ConnectTimeout -from pathlib import Path from .map import Map import asyncio import nonebot @@ -26,11 +25,11 @@ LABEL_URL = "https://api-static.mihoyo.com/common/blackboard/ys_obc/v1/map/label POINT_LIST_URL = "https://api-static.mihoyo.com/common/blackboard/ys_obc/v1/map/point/list?map_id=2&app_sn=ys_obc" MAP_URL = "https://api-static.mihoyo.com/common/map_user/ys_obc/v1/map/info?map_id=2&app_sn=ys_obc&lang=zh-cn" -icon_path = Path(IMAGE_PATH) / "genshin" / "genshin_icon" -map_path = Path(IMAGE_PATH) / "genshin" / "map" -resource_label_file = Path(TEXT_PATH) / "genshin" / "resource_label_file.json" -resource_point_file = Path(TEXT_PATH) / "genshin" / "resource_point_file.json" -resource_type_file = Path(TEXT_PATH) / "genshin" / "resource_type_file.json" +icon_path = IMAGE_PATH / "genshin" / "genshin_icon" +map_path = IMAGE_PATH / "genshin" / "map" +resource_label_file = TEXT_PATH / "genshin" / "resource_label_file.json" +resource_point_file = TEXT_PATH / "genshin" / "resource_point_file.json" +resource_type_file = TEXT_PATH / "genshin" / "resource_type_file.json" # 地图中心坐标 CENTER_POINT: Optional[Tuple[int, int]] = None @@ -115,7 +114,7 @@ async def download_resource_data(semaphore: Semaphore): icon_path.mkdir(parents=True, exist_ok=True) resource_label_file.parent.mkdir(parents=True, exist_ok=True) try: - response = await AsyncHttpx.get(POINT_LIST_URL) + response = await AsyncHttpx.get(POINT_LIST_URL, timeout=5) if response.status_code == 200: data = response.json() if data["message"] == "OK": @@ -167,7 +166,7 @@ async def download_map_init( if _map.exists() and os.path.getsize(_map) > 1024 * 1024 * 30: _map.unlink() try: - response = await AsyncHttpx.get(MAP_URL) + response = await AsyncHttpx.get(MAP_URL, timeout=5) if response.status_code == 200: data = response.json() if data["message"] == "OK": @@ -206,7 +205,7 @@ async def download_map_init( async def download_resource_type(): resource_type_file.parent.mkdir(parents=True, exist_ok=True) try: - response = await AsyncHttpx.get(LABEL_URL) + response = await AsyncHttpx.get(LABEL_URL, timeout=5) if response.status_code == 200: data = response.json() if data["message"] == "OK": @@ -252,7 +251,7 @@ async def download_image( async with semaphore: try: if not os.path.exists(path) or not is_valid or force_flag: - if await AsyncHttpx.download_file(img_url, path): + if await AsyncHttpx.download_file(img_url, path, timeout=5): logger.info(f"下载原神资源图标:{img_url}") if gen_flag: gen_icon(path) diff --git a/plugins/genshin/query_user/models/__init__.py b/plugins/genshin/query_user/_models/__init__.py similarity index 92% rename from plugins/genshin/query_user/models/__init__.py rename to plugins/genshin/query_user/_models/__init__.py index 04add021..71d11a76 100644 --- a/plugins/genshin/query_user/models/__init__.py +++ b/plugins/genshin/query_user/_models/__init__.py @@ -18,6 +18,7 @@ class Genshin(db.Model): auto_sign_time = db.Column(db.DateTime(timezone=True)) resin_remind = db.Column(db.Boolean(), default=False) # 树脂提醒 resin_recovery_time = db.Column(db.DateTime(timezone=True)) # 满树脂提醒日期 + bind_group = db.Column(db.BigInteger()) _idx1 = db.Index("genshin_uid_idx1", "user_qq", "uid", unique=True) @@ -56,6 +57,35 @@ class Genshin(db.Model): return True return False + @classmethod + async def set_bind_group(cls, uid: int, bind_group) -> bool: + """ + 说明: + 绑定group_id,除私聊外的提醒将在此群发送 + 参数: + :param uid: uid + :param bind_group: 群号 + """ + query = cls.query.where(cls.uid == uid).with_for_update() + user = await query.gino.first() + if user: + await user.update(bind_group=bind_group).apply() + return True + return False + + @classmethod + async def get_bind_group(cls, uid: int) -> Optional[int]: + """ + 说明: + 获取用户绑定的群聊 + 参数: + :param uid: uid + """ + user = await cls.query.where(cls.uid == uid).gino.first() + if user: + return user.bind_group + return None + @classmethod async def set_cookie(cls, uid: int, cookie: str) -> bool: """ diff --git a/plugins/genshin/query_user/utils/__init__.py b/plugins/genshin/query_user/_utils/__init__.py similarity index 100% rename from plugins/genshin/query_user/utils/__init__.py rename to plugins/genshin/query_user/_utils/__init__.py diff --git a/plugins/genshin/query_user/bind/__init__.py b/plugins/genshin/query_user/bind/__init__.py index 27230596..2c81784f 100644 --- a/plugins/genshin/query_user/bind/__init__.py +++ b/plugins/genshin/query_user/bind/__init__.py @@ -1,9 +1,10 @@ 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 nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message +from utils.utils import is_number +from .._models import Genshin from services.log import logger +from nonebot.params import CommandArg, Command +from typing import Tuple __zx_plugin_name__ = "原神绑定" @@ -40,13 +41,14 @@ 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"]: +async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): + cmd = cmd[0] + msg = arg.extract_plain_text().strip() + if cmd 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": + if cmd == "原神绑定uid": uid = await Genshin.get_user_uid(event.user_id) if uid: await bind.finish(f"您已绑定过uid:{uid},如果希望更换uid,请先发送原神解绑") @@ -54,7 +56,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): if not flag: await bind.finish("添加失败,该uid可能已存在...") _x = f"已成功添加原神uid:{msg}" - elif state["_prefix"]["raw_command"] == "原神绑定米游社id": + elif cmd == "原神绑定米游社id": uid = await Genshin.get_user_uid(event.user_id) if not uid: await bind.finish("请先绑定原神uid..") @@ -63,7 +65,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): else: if not msg: await bind.finish( - "私聊发送!!\n打开https://bbs.mihoyo.com/ys/\n登录后按F12点击控制台输入document.cookie复制输出的内容即可" + "私聊发送!!\n打开 https://bbs.mihoyo.com/ys/\n登录后按F12点击控制台输入document.cookie复制输出的内容即可" ) if isinstance(event, GroupMessageEvent): await bind.finish("请立即撤回你的消息并私聊发送!") @@ -76,16 +78,18 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): msg = msg[:-1] await Genshin.set_cookie(uid, msg) _x = f"已成功为uid:{uid} 设置cookie" + if isinstance(event, GroupMessageEvent): + await Genshin.set_bind_group(uid, event.group_id) 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}" + f" {cmd}:{msg}" ) @unbind.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent): if await Genshin.delete_user(event.user_id): await unbind.send("用户数据删除成功...") logger.info( diff --git a/plugins/genshin/query_user/genshin_sign/__init__.py b/plugins/genshin/query_user/genshin_sign/__init__.py index 61af62cd..654bd15d 100644 --- a/plugins/genshin/query_user/genshin_sign/__init__.py +++ b/plugins/genshin/query_user/genshin_sign/__init__.py @@ -1,11 +1,12 @@ from .data_source import get_sign_reward_list, genshin_sign -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent from nonebot import on_command -from nonebot.typing import T_State from services.log import logger from .init_task import add_job, scheduler, _sign from apscheduler.jobstores.base import JobLookupError -from ..models import Genshin +from .._models import Genshin +from nonebot.params import Command +from typing import Tuple __zx_plugin_name__ = "原神自动签到" @@ -19,7 +20,7 @@ usage: 原神我硬签 """.strip() __plugin_des__ = "原神懒人签到" -__plugin_cmd__ = ["开/关原神自动签到", "原神我硬签"] +__plugin_cmd__ = ["开启/关闭原神自动签到", "原神我硬签"] __plugin_type__ = ("原神相关",) __plugin_version__ = 0.1 __plugin_author__ = "HibiKier" @@ -37,13 +38,14 @@ genshin_matcher = on_command( @genshin_matcher.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()): + cmd = cmd[0] uid = await Genshin.get_user_uid(event.user_id) if not uid or not await Genshin.get_user_cookie(uid, True): await genshin_matcher.finish("请先绑定uid和cookie!") if "account_id" not in await Genshin.get_user_cookie(uid, True): await genshin_matcher.finish("请更新cookie!") - if state["_prefix"]["raw_command"] == "原神我硬签": + if cmd == "原神我硬签": try: msg = await genshin_sign(uid) logger.info( @@ -77,7 +79,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): scheduler.remove_job(f"genshin_auto_sign_{uid}_{event.user_id}_{i}") except JobLookupError: pass - if state["_prefix"]["raw_command"][0] == "开": + if cmd[0] == "开": await Genshin.set_auto_sign(uid, True) next_date = await Genshin.random_sign_time(uid) add_job(event.user_id, uid, next_date) diff --git a/plugins/genshin/query_user/genshin_sign/data_source.py b/plugins/genshin/query_user/genshin_sign/data_source.py index 66c58fe5..737c7ea6 100644 --- a/plugins/genshin/query_user/genshin_sign/data_source.py +++ b/plugins/genshin/query_user/genshin_sign/data_source.py @@ -1,8 +1,8 @@ from utils.http_utils import AsyncHttpx from configs.config import Config from services.log import logger -from ..utils import random_hex, get_old_ds -from ..models import Genshin +from .._utils import random_hex, get_old_ds +from .._models import Genshin from typing import Optional, Dict diff --git a/plugins/genshin/query_user/genshin_sign/init_task.py b/plugins/genshin/query_user/genshin_sign/init_task.py index 5371764a..4a362eb7 100644 --- a/plugins/genshin/query_user/genshin_sign/init_task.py +++ b/plugins/genshin/query_user/genshin_sign/init_task.py @@ -4,7 +4,7 @@ from utils.message_builder import at from services.log import logger from utils.utils import scheduler, get_bot from apscheduler.jobstores.base import ConflictingIdError -from ..models import Genshin +from .._models import Genshin from datetime import datetime, timedelta from nonebot import Driver import nonebot @@ -103,8 +103,10 @@ async def _sign(user_id: int, uid: int, count: int): if user_id in [x["user_id"] for x in await bot.get_friend_list()]: await bot.send_private_msg(user_id=user_id, message=msg) else: - group_list = await GroupInfoUser.get_user_all_group(user_id) - if group_list: - await bot.send_group_msg( - group_id=group_list[0], message=at(user_id) + msg - ) + if not (group_id := await Genshin.get_bind_group(uid)): + group_list = await GroupInfoUser.get_user_all_group(user_id) + if group_list: + group_id = group_list[0] + await bot.send_group_msg( + group_id=group_id, message=at(user_id) + msg + ) diff --git a/plugins/genshin/query_user/query_memo/__init__.py b/plugins/genshin/query_user/query_memo/__init__.py index 410d7cb2..e8e7975b 100644 --- a/plugins/genshin/query_user/query_memo/__init__.py +++ b/plugins/genshin/query_user/query_memo/__init__.py @@ -1,9 +1,8 @@ from nonebot import on_command -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent from services.log import logger from .data_source import get_user_memo, get_memo -from ..models import Genshin +from .._models import Genshin from nonebot.plugin import export @@ -37,7 +36,7 @@ query_memo_matcher = on_command("原神便签查询", aliases={"原神便笺查 @query_memo_matcher.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent): 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!") diff --git a/plugins/genshin/query_user/query_memo/data_source.py b/plugins/genshin/query_user/query_memo/data_source.py index 45a3f402..aa4fef60 100644 --- a/plugins/genshin/query_user/query_memo/data_source.py +++ b/plugins/genshin/query_user/query_memo/data_source.py @@ -1,5 +1,5 @@ from typing import Optional, Union -from nonebot.adapters.cqhttp import MessageSegment +from nonebot.adapters.onebot.v11 import MessageSegment from configs.config import Config from asyncio.exceptions import TimeoutError from services.log import logger @@ -8,10 +8,9 @@ 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 .._utils import get_ds +from .._models import Genshin from io import BytesIO -from pathlib import Path from nonebot import Driver import asyncio import nonebot @@ -20,7 +19,7 @@ import nonebot driver: Driver = nonebot.get_driver() -memo_path = Path(IMAGE_PATH) / "genshin" / "genshin_memo" +memo_path = IMAGE_PATH / "genshin" / "genshin_memo" memo_path.mkdir(exist_ok=True, parents=True) diff --git a/plugins/genshin/query_user/query_role/__init__.py b/plugins/genshin/query_user/query_role/__init__.py index 48155ce5..e4623e79 100644 --- a/plugins/genshin/query_user/query_role/__init__.py +++ b/plugins/genshin/query_user/query_role/__init__.py @@ -1,10 +1,10 @@ from nonebot import on_command -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message 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 +from .._models import Genshin +from utils.utils import is_number +from nonebot.params import CommandArg __zx_plugin_name__ = "原神玩家查询" @@ -33,8 +33,8 @@ query_role_info_matcher = on_command("原神玩家查询", aliases={"原神玩 @query_role_info_matcher.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() if msg: if not is_number(msg): await query_role_info_matcher.finish("查询uid必须为数字!") @@ -45,7 +45,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): 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 + nickname = event.sender.card or 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: diff --git a/plugins/genshin/query_user/query_role/data_source.py b/plugins/genshin/query_user/query_role/data_source.py index ff25b21a..8ecdb447 100644 --- a/plugins/genshin/query_user/query_role/data_source.py +++ b/plugins/genshin/query_user/query_role/data_source.py @@ -1,11 +1,11 @@ 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 nonebot.adapters.onebot.v11 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 +from .._models import Genshin try: import ujson as json diff --git a/plugins/genshin/query_user/query_role/draw_image.py b/plugins/genshin/query_user/query_role/draw_image.py index 4d4c1e4f..eb7dfa8a 100644 --- a/plugins/genshin/query_user/query_role/draw_image.py +++ b/plugins/genshin/query_user/query_role/draw_image.py @@ -1,9 +1,8 @@ -from configs.path_config import IMAGE_PATH -from pathlib import Path +from configs.path_config import IMAGE_PATH, TEMP_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 nonebot.adapters.onebot.v11 import MessageSegment from utils.http_utils import AsyncHttpx from utils.utils import get_user_avatar from io import BytesIO @@ -12,7 +11,7 @@ import asyncio import os -image_path = Path(IMAGE_PATH) / "genshin" / "genshin_card" +image_path = IMAGE_PATH / "genshin" / "genshin_card" async def get_genshin_image( @@ -109,8 +108,8 @@ def _get_genshin_image( A.paste(char_image, (0, top_bk.h + bar.h + 10), center_type="by_width") rand = random.randint(1, 10000) A.resize(0.8) - A.save(Path(IMAGE_PATH) / "temp" / f"genshin_user_card_{rand}.png") - return image(f"genshin_user_card_{rand}.png", "temp") + A.save(TEMP_PATH / f"genshin_user_card_{rand}.png") + return image(TEMP_PATH / f"genshin_user_card_{rand}.png") def get_user_data_image( diff --git a/plugins/genshin/query_user/reset_today_query_user_data/__init__.py b/plugins/genshin/query_user/reset_today_query_user_data/__init__.py index 0c2c24d0..867e1982 100644 --- a/plugins/genshin/query_user/reset_today_query_user_data/__init__.py +++ b/plugins/genshin/query_user/reset_today_query_user_data/__init__.py @@ -1,5 +1,5 @@ from utils.utils import scheduler -from ..models import Genshin +from .._models import Genshin from services.log import logger diff --git a/plugins/genshin/query_user/resin_remind/__init__.py b/plugins/genshin/query_user/resin_remind/__init__.py index 4cf2f927..84951461 100644 --- a/plugins/genshin/query_user/resin_remind/__init__.py +++ b/plugins/genshin/query_user/resin_remind/__init__.py @@ -1,20 +1,19 @@ from nonebot import on_command -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent from apscheduler.jobstores.base import JobLookupError from services.log import logger from .init_task import scheduler, add_job -from ..models import Genshin -from datetime import datetime -import random -import asyncio -import pytz +from .._models import Genshin +from nonebot.params import Command +from typing import Tuple __zx_plugin_name__ = "原神树脂提醒" __plugin_usage__ = """ usage: 即将满树脂的提醒 + 会在 120-140 140-160 160 以及溢出指定部分时提醒, + 共提醒3-4次 指令: 开原神树脂提醒 关原神树脂提醒 @@ -30,12 +29,25 @@ __plugin_settings__ = { "limit_superuser": False, "cmd": ["原神树脂提醒", "关原神树脂提醒", "开原神树脂提醒"], } +__plugin_configs__ = { + "AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND": { + "value": True, + "help": "当请求连续三次失败时,关闭用户的树脂提醒", + "default_value": True + }, + "CUSTOM_RESIN_OVERFLOW_REMIND": { + "value": 20, + "help": "自定义树脂溢出指定数量时的提醒,空值是为关闭", + "default_value": None + } +} resin_remind = on_command("开原神树脂提醒", aliases={"关原神树脂提醒"}, priority=5, block=True) @resin_remind.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()): + cmd = cmd[0] uid = await Genshin.get_user_uid(event.user_id) if not uid or not await Genshin.get_user_cookie(uid, True): await resin_remind.finish("请先绑定uid和cookie!") @@ -43,7 +55,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): scheduler.remove_job(f"genshin_resin_remind_{uid}_{event.user_id}") except JobLookupError: pass - if state["_prefix"]["raw_command"][0] == "开": + if cmd == "开": await Genshin.set_resin_remind(uid, True) add_job(event.user_id, uid) logger.info( @@ -62,22 +74,3 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): ) await resin_remind.send("已关闭原神树脂提醒..", at_sender=True) - -@scheduler.scheduled_job( - "interval", - minutes=30, -) -async def _(): - for u in await Genshin.get_all_resin_remind_user(): - if u.resin_recovery_time: - if await Genshin.get_user_resin_recovery_time(u.uid) < datetime.now( - pytz.timezone("Asia/Shanghai") - ): - await Genshin.clear_resin_remind_time(u.uid) - elif ( - await Genshin.get_user_resin_recovery_time(u.uid) - - datetime.now(pytz.timezone("Asia/Shanghai")) - ).seconds > 360: - continue - add_job(u.user_qq, u.uid) - await asyncio.sleep(random.randint(10, 30)) diff --git a/plugins/genshin/query_user/resin_remind/init_task.py b/plugins/genshin/query_user/resin_remind/init_task.py index 844804b2..a13fb834 100644 --- a/plugins/genshin/query_user/resin_remind/init_task.py +++ b/plugins/genshin/query_user/resin_remind/init_task.py @@ -3,11 +3,12 @@ from utils.message_builder import at from models.group_member_info import GroupInfoUser from apscheduler.jobstores.base import ConflictingIdError from nonebot import Driver -from ..models import Genshin +from .._models import Genshin from datetime import datetime, timedelta from services.log import logger from nonebot.plugin import require -import time +from configs.config import Config +import random import nonebot import pytz @@ -15,13 +16,15 @@ import pytz driver: Driver = nonebot.get_driver() -get_memo = require('query_memo').get_memo +get_memo = require("query_memo").get_memo class UserManager: - - def __init__(self): + def __init__(self, max_error_count: int = 3): self._data = [] + self._overflow_data = [] + self._error_count = {} + self.max_error_count = max_error_count def append(self, o: str): if o not in self._data: @@ -34,6 +37,32 @@ class UserManager: def exists(self, o: str): return o in self._data + def add_error_count(self, uid: str): + if uid in self._error_count.keys(): + self._error_count[uid] += 1 + else: + self._error_count[uid] = 1 + + def check(self, uid: str) -> bool: + if uid in self._error_count.keys(): + return self._error_count[uid] == self.max_error_count + return False + + def remove_error_count(self, uid): + if uid in self._error_count.keys(): + del self._error_count[uid] + + def add_overflow(self, uid: str): + if uid not in self._overflow_data: + self._overflow_data.append(uid) + + def remove_overflow(self, uid: str): + if uid in self._overflow_data: + self._overflow_data.remove(uid) + + def is_overflow(self, uid: str) -> bool: + return uid in self._overflow_data + user_manager = UserManager() @@ -44,22 +73,38 @@ async def _(): 启动时分配定时任务 """ g_list = await Genshin.get_all_resin_remind_user() + date = datetime.now(pytz.timezone("Asia/Shanghai")) + timedelta(seconds=30) for u in g_list: - if u.resin_recovery_time and await Genshin.get_user_resin_recovery_time( - u.uid - ) > datetime.now(pytz.timezone("Asia/Shanghai")): - date = await Genshin.get_user_resin_recovery_time(u.uid) - scheduler.add_job( - _remind, - "date", - run_date=date.replace(microsecond=0), - id=f"genshin_resin_remind_{u.uid}_{u.user_qq}", - args=[u.user_qq, u.uid], - ) - logger.info( - f"genshin_resin_remind add_job:USER:{u.user_qq} UID:{u.uid} " - f"{date} 原神树脂提醒" - ) + if u.resin_remind: + if u.resin_recovery_time: + if await Genshin.get_user_resin_recovery_time(u.uid) > datetime.now( + pytz.timezone("Asia/Shanghai") + ): + date = await Genshin.get_user_resin_recovery_time(u.uid) + scheduler.add_job( + _remind, + "date", + run_date=date.replace(microsecond=0), + id=f"genshin_resin_remind_{u.uid}_{u.user_qq}", + args=[u.user_qq, u.uid], + ) + logger.info( + f"genshin_resin_remind add_job:USER:{u.user_qq} UID:{u.uid} " + f"{date} 原神树脂提醒" + ) + else: + await Genshin.clear_resin_remind_time(u.uid) + add_job(u.user_qq, u.uid) + logger.info( + f"genshin_resin_remind add_job CHECK:USER:{u.user_qq} UID:{u.uid} " + f"{date} 原神树脂提醒" + ) + else: + add_job(u.user_qq, u.uid) + logger.info( + f"genshin_resin_remind add_job CHECK:USER:{u.user_qq} UID:{u.uid} " + f"{date} 原神树脂提醒" + ) def add_job(user_id: int, uid: int): @@ -85,39 +130,62 @@ async def _remind(user_id: int, uid: str): else: return data, code = await get_memo(uid, server_id) + now = datetime.now(pytz.timezone("Asia/Shanghai")) + next_time = None if code == 200: current_resin = data["current_resin"] # 当前树脂 max_resin = data["max_resin"] # 最大树脂 - resin_recovery_time = data["resin_recovery_time"] # 树脂全部回复时间 - if max_resin - current_resin > 5: + msg = f"你的已经存了 {current_resin} 个树脂了!不要忘记刷掉!" + # resin_recovery_time = data["resin_recovery_time"] # 树脂全部回复时间 + if current_resin < max_resin: user_manager.remove(uid) - next_time = datetime.strptime(time.strftime( - "%Y-%m-%d %H:%M:%S", time.localtime(time.time() + float(resin_recovery_time)) - ), "%Y-%m-%d %H:%M:%S") - await Genshin.set_user_resin_recovery_time(int(uid), next_time) - scheduler.add_job( - _remind, - "date", - run_date=next_time, - id=f"genshin_resin_remind_{uid}_{user_id}", - args=[user_id, uid], - ) - logger.info(f"genshin_resin_remind add_job:{next_time.replace(microsecond=0)} 原神树脂提醒") - else: - if not user_manager.exists(uid): + user_manager.remove_overflow(uid) + if max_resin - 40 <= current_resin <= max_resin - 20: + next_time = now + timedelta(minutes=(max_resin - 20 - current_resin) * 8, seconds=10) + elif current_resin < max_resin: + next_time = now + timedelta(minutes=(max_resin - current_resin) * 8, seconds=10) + elif current_resin == max_resin: + custom_overflow_resin = Config.get_config("resin_remind", "CUSTOM_RESIN_OVERFLOW_REMIND") + if user_manager.is_overflow(uid) and custom_overflow_resin: + next_time = now + timedelta(minutes=custom_overflow_resin * 8) + user_manager.add_overflow(uid) + user_manager.remove(uid) + msg = f"你的树脂都溢出 {custom_overflow_resin} 个了!浪费可耻!" + else: + next_time = now + timedelta(minutes=40 * 8 + random.randint(5, 50)) + if not user_manager.exists(uid) and current_resin >= max_resin - 40: + if current_resin == max_resin: user_manager.append(uid) - bot = get_bot() - if bot: - if user_id in [x["user_id"] for x in await bot.get_friend_list()]: - await bot.send_private_msg( - user_id=user_id, - message=f"树脂已经 {current_resin} 个啦" f",马上就要溢出了!快快刷掉刷掉!", - ) - else: + bot = get_bot() + if bot: + if user_id in [x["user_id"] for x in await bot.get_friend_list()]: + await bot.send_private_msg( + user_id=user_id, + message=msg, + ) + else: + group_id = await Genshin.get_bind_group(int(uid)) + if not group_id: group_list = await GroupInfoUser.get_user_all_group(user_id) if group_list: - await bot.send_group_msg( - group_id=group_list[0], - message=at(user_id) + f"树脂已经 {current_resin} 个啦" - f",马上就要溢出了!快快刷掉刷掉!", - ) + group_id = group_list[0] + await bot.send_group_msg( + group_id=group_id, + message=at(user_id) + msg + ) + if not next_time: + if user_manager.check(uid) and Config.get_config("resin_remind", "AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND"): + await Genshin.set_resin_remind(int(uid), False) + await Genshin.clear_resin_remind_time(int(uid)) + next_time = now + timedelta(minutes=(20 + random.randint(5, 20)) * 8) + user_manager.add_error_count(uid) + else: + user_manager.remove_error_count(uid) + await Genshin.set_user_resin_recovery_time(int(uid), next_time) + scheduler.add_job( + _remind, + "date", + run_date=next_time, + id=f"genshin_resin_remind_{uid}_{user_id}", + args=[user_id, uid], + ) diff --git a/plugins/gold_redbag/__init__.py b/plugins/gold_redbag/__init__.py index 40211762..49768085 100755 --- a/plugins/gold_redbag/__init__.py +++ b/plugins/gold_redbag/__init__.py @@ -1,11 +1,10 @@ from nonebot import on_command, on_notice -from nonebot.adapters.cqhttp import ( +from nonebot.adapters.onebot.v11 import ( Bot, GroupMessageEvent, PokeNotifyEvent, - MessageEvent, + Message ) -from nonebot.typing import T_State from .data_source import ( check_gold, generate_send_redbag_pic, @@ -13,10 +12,10 @@ from .data_source import ( generate_open_redbag_pic, return_gold, ) -from nonebot.adapters.cqhttp.permission import GROUP +from nonebot.adapters.onebot.v11.permission import GROUP from nonebot.message import run_preprocessor, IgnoredException from nonebot.matcher import Matcher -from utils.utils import get_message_text, is_number, scheduler +from utils.utils import is_number, scheduler from utils.message_builder import image from services.log import logger from configs.path_config import IMAGE_PATH @@ -25,7 +24,8 @@ from nonebot.rule import to_me from datetime import datetime, timedelta from configs.config import NICKNAME from apscheduler.jobstores.base import JobLookupError -from nonebot.adapters.cqhttp.exception import ActionFailed +from nonebot.adapters.onebot.v11.exception import ActionFailed +from nonebot.params import CommandArg import random import time @@ -85,7 +85,7 @@ festive_redbag_data = {} # 阻断其他poke @run_preprocessor -async def _(matcher: Matcher, bot: Bot, event: PokeNotifyEvent, state: T_State): +async def _(matcher: Matcher, event: PokeNotifyEvent): try: if matcher.type == "notice" and event.self_id == event.target_id: flag1 = True @@ -106,17 +106,17 @@ async def _(matcher: Matcher, bot: Bot, event: PokeNotifyEvent, state: T_State): except KeyError: flag2 = False if flag1 or flag2: - if matcher.module == "poke": + if matcher.plugin_name == "poke": raise IgnoredException("目前正在抢红包...") else: - if matcher.module == "gold_redbag": + if matcher.plugin_name == "gold_redbag": raise IgnoredException("目前没有红包...") except AttributeError: pass @gold_redbag.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()): global redbag_data, festive_redbag_data try: if time.time() - redbag_data[event.group_id]["time"] > 60: @@ -137,7 +137,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): ) except KeyError: pass - msg = get_message_text(event.json()) + msg = arg.extract_plain_text().strip() msg = msg.split() if len(msg) == 1: flag, amount = await check_gold(event.user_id, event.group_id, msg[0]) @@ -159,7 +159,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): if num > group_member_num: await gold_redbag.send("你发的红包数量也太多了,已经为你修改成与本群人数相同的红包数量...") num = group_member_num - nickname = event.sender.card if event.sender.card else event.sender.nickname + nickname = event.sender.card or event.sender.nickname flag, result = init_redbag( event.user_id, event.group_id, nickname, amount, num, int(bot.self_id) ) @@ -180,9 +180,9 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @open_.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent, arg: Message = CommandArg()): global redbag_data, festive_redbag_data - msg = get_message_text(event.json()) + msg = arg.extract_plain_text().strip() msg = ( msg.replace("!", "") .replace("!", "") @@ -226,7 +226,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @poke_.handle() -async def _poke_(bot: Bot, event: PokeNotifyEvent, state: T_State): +async def _poke_(event: PokeNotifyEvent): global redbag_data, festive_redbag_data if event.self_id == event.target_id: flag1 = True @@ -250,7 +250,7 @@ async def _poke_(bot: Bot, event: PokeNotifyEvent, state: T_State): @return_.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): global redbag_data try: if redbag_data[event.group_id]["user_id"] != event.user_id: @@ -283,9 +283,9 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @festive_redbag.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(bot: Bot, arg: Message = CommandArg()): global redbag_data - msg = get_message_text(event.json()) + msg = arg.extract_plain_text().strip() if msg: msg = msg.split() amount = 0 @@ -309,7 +309,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): await festive_redbag.finish("指定的群号必须要是数字啊!", at_sender=True) gl.append(int(msg[i])) if not gl: - gl = await bot.get_group_list(self_id=int(bot.self_id)) + gl = await bot.get_group_list() gl = [g["group_id"] for g in gl] for g in gl: try: diff --git a/plugins/group_last_chat/__init__.py b/plugins/group_last_chat/__init__.py index ab7a3e55..e9181cc2 100755 --- a/plugins/group_last_chat/__init__.py +++ b/plugins/group_last_chat/__init__.py @@ -1,7 +1,6 @@ from nonebot import on_message -from nonebot.adapters.cqhttp.permission import GROUP -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent +from nonebot.adapters.onebot.v11.permission import GROUP +from nonebot.adapters.onebot.v11 import GroupMessageEvent from .data_source import cancel_all_notice, save_data, get_data, set_data_value from services.log import logger import time @@ -16,7 +15,7 @@ last_chat = on_message(priority=1, block=False, permission=GROUP) @last_chat.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): time_data = await get_data() set_data_value(event.group_id, time.time()) if event.group_id in time_data["_group"]: diff --git a/plugins/group_last_chat/data_source.py b/plugins/group_last_chat/data_source.py index 9984e20d..0d411dd4 100755 --- a/plugins/group_last_chat/data_source.py +++ b/plugins/group_last_chat/data_source.py @@ -32,14 +32,14 @@ async def init(): def read_data(file_name: str): try: - with open(DATA_PATH + file_name, "r", encoding="utf8") as f: + with open(DATA_PATH / file_name, "r", encoding="utf8") as f: return json.load(f) except (ValueError, FileNotFoundError): return {} def save_data(): - with open(DATA_PATH + "group_last_chat_time.json", "w") as f: + with open(DATA_PATH / "group_last_chat_time.json", "w") as f: json.dump(time_data, f, indent=4) logger.info( f'自动存储 group_last_chat_time.json 时间:{str(datetime.now()).split(".")[0]}' diff --git a/plugins/group_welcome_msg.py b/plugins/group_welcome_msg.py index 8831758a..1b610e51 100755 --- a/plugins/group_welcome_msg.py +++ b/plugins/group_welcome_msg.py @@ -1,11 +1,8 @@ from nonebot import on_command -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from nonebot.adapters.cqhttp.permission import GROUP +from nonebot.adapters.onebot.v11 import GroupMessageEvent +from nonebot.adapters.onebot.v11.permission import GROUP from configs.path_config import DATA_PATH from utils.message_builder import image -import os -from pathlib import Path try: import ujson as json @@ -36,13 +33,13 @@ view_custom_welcome = on_command( @view_custom_welcome.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): img = "" msg = "" - if os.path.exists(DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"): - img = image(abspath=DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg") + if (DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg").exists(): + img = image(abspath=DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg") custom_welcome_msg_json = ( - Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json" + DATA_PATH / "custom_welcome_msg" / "custom_welcome_msg.json" ) if custom_welcome_msg_json.exists(): data = json.load(open(custom_welcome_msg_json, "r")) diff --git a/plugins/image_management/__init__.py b/plugins/image_management/__init__.py index 9a4464db..92d70819 100755 --- a/plugins/image_management/__init__.py +++ b/plugins/image_management/__init__.py @@ -55,7 +55,7 @@ Config.add_plugin_config( ) -(Path(IMAGE_PATH) / "image_management").mkdir(parents=True, exist_ok=True) +(IMAGE_PATH / "image_management").mkdir(parents=True, exist_ok=True) nonebot.load_plugins("plugins/image_management") diff --git a/plugins/image_management/delete_image/__init__.py b/plugins/image_management/delete_image/__init__.py index c4e314fa..fc51fc71 100755 --- a/plugins/image_management/delete_image/__init__.py +++ b/plugins/image_management/delete_image/__init__.py @@ -4,10 +4,10 @@ from services.log import logger from nonebot import on_command from nonebot.rule import to_me from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent -from utils.utils import is_number, cn2py, get_message_text +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message +from utils.utils import is_number, cn2py from configs.config import Config -from pathlib import Path +from nonebot.params import CommandArg, Arg import os __zx_plugin_name__ = "删除图片 [Admin]" @@ -31,60 +31,47 @@ __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" - ): - await delete_img.reject("此目录不正确,请重新输入目录!") - state[state["_current_key"]] = get_message_text(event.json()) - if state["_current_key"] == "id": - if not is_number(get_message_text(event.json())): - await delete_img.reject("id不正确!请重新输入数字...") - state[state["_current_key"]] = get_message_text(event.json()) +_path = IMAGE_PATH / "image_management" @delete_img.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - raw_arg = get_message_text(event.json()).strip() - if raw_arg: - 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]) - ): +async def _(state: T_State, arg: Message = CommandArg()): + args = arg.extract_plain_text().strip().split() + if args: + if args[0] in Config.get_config("image_management", "IMAGE_DIR_LIST"): state["path"] = args[0] + if len(args) > 1 and is_number(args[1]): state["id"] = args[1] @delete_img.got("path", prompt="请输入要删除的目标图库?") @delete_img.got("id", prompt="请输入要删除的图片id?") -async def arg_handle(bot: Bot, event: MessageEvent, state: T_State): - img_id = state["id"] - path = _path / cn2py(state["path"]) +async def arg_handle( + event: MessageEvent, + state: T_State, + path: str = Arg("path"), + img_id: str = Arg("id"), +): + if path in ["取消", "算了"] or img_id in ["取消", "算了"]: + await delete_img.finish("已取消操作...") + if path not in Config.get_config("image_management", "IMAGE_DIR_LIST"): + await delete_img.reject_arg("path", "此目录不正确,请重新输入目录!") + if not is_number(img_id): + await delete_img.reject_arg("id", "id不正确!请重新输入数字...") + path = _path / cn2py(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 (temp / "delete.jpg").exists(): - (temp / "delete.jpg").unlink() + if (TEMP_PATH / "delete.jpg").exists(): + (TEMP_PATH / "delete.jpg").unlink() logger.info(f"删除{cn2py(state['path'])}图片 {img_id}.jpg 成功") except Exception as e: logger.warning(f"删除图片 delete.jpg 失败 e{e}") try: - os.rename(path / f"{img_id}.jpg", temp / "delete.jpg") + os.rename(path / f"{img_id}.jpg", TEMP_PATH / f"{event.user_id}_delete.jpg") logger.info(f"移动 {path}/{img_id}.jpg 移动成功") except Exception as e: logger.warning(f"{path}/{img_id}.jpg --> 移动失败 e:{e}") @@ -100,6 +87,6 @@ async def arg_handle(bot: Bot, event: MessageEvent, state: T_State): f" -> id: {img_id} 删除成功" ) await delete_img.finish( - f"id: {img_id} 删除成功" + image("delete.jpg", TEMP_PATH), at_sender=True + f"id: {img_id} 删除成功" + image(TEMP_PATH / f"{event.user_id}_delete.jpg",), at_sender=True ) await delete_img.finish(f"id: {img_id} 删除失败!") diff --git a/plugins/image_management/move_image/__init__.py b/plugins/image_management/move_image/__init__.py index 1ae25012..1283d157 100755 --- a/plugins/image_management/move_image/__init__.py +++ b/plugins/image_management/move_image/__init__.py @@ -1,14 +1,13 @@ -import os from services.log import logger from nonebot import on_command from nonebot.rule import to_me from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message from configs.config import Config from utils.utils import is_number, cn2py from configs.path_config import IMAGE_PATH -from pathlib import Path - +from nonebot.params import CommandArg, ArgStr +import os __zx_plugin_name__ = "移动图片 [Admin]" __plugin_usage__ = """ @@ -31,71 +30,63 @@ __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 ["取消", "算了"]: - await move_img.finish("已取消操作..", at_sender=True) - if state["_current_key"] in ["source_path", "destination_path"]: - if str(event.get_message()) not in Config.get_config( - "image_management", "IMAGE_DIR_LIST" - ): - await move_img.reject("此目录不正确,请重新输入目录!") - state[state["_current_key"]] = str(event.get_message()) - if state["_current_key"] == "id": - if not is_number(str(event.get_message())): - await move_img.reject("id不正确!请重新输入数字...") - state[state["_current_key"]] = str(event.get_message()) +_path = IMAGE_PATH / "image_management" @move_img.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - raw_arg = str(event.get_message()).strip() - if raw_arg: - args = raw_arg.split(" ") - if args[0] in ["帮助"]: - await move_img.finish(__plugin_usage__) - if ( - len(args) >= 3 - and args[0] in Config.get_config("image_management", "IMAGE_DIR_LIST") - and args[1] in Config.get_config("image_management", "IMAGE_DIR_LIST") - and is_number(args[2]) - ): - state["source_path"] = args[0] - state["destination_path"] = args[1] +async def _(state: T_State, arg: Message = CommandArg()): + args = arg.extract_plain_text().strip().split() + if args: + if n := len(args): + if args[0] in Config.get_config("image_management", "IMAGE_DIR_LIST"): + state["source_path"] = args[0] + if n > 1: + if args[1] in Config.get_config("image_management", "IMAGE_DIR_LIST"): + state["destination_path"] = args[1] + if n > 2 and is_number(args[2]): state["id"] = args[2] - else: - await move_img.finish("参数错误,请重试", at_sender=True) @move_img.got("source_path", prompt="要从哪个图库移出?") @move_img.got("destination_path", prompt="要移动到哪个图库?") @move_img.got("id", prompt="要移动的图片id是?") -async def _(bot: Bot, event: MessageEvent, state: T_State): - img_id = state["id"] - source_path = _path / cn2py(state["source_path"]) - destination_path = _path / cn2py(state["destination_path"]) +async def _( + event: MessageEvent, + source_path: str = ArgStr("source_path"), + destination_path: str = ArgStr("destination_path"), + img_id: str = ArgStr("id"), +): if ( - not source_path.exists() - and (source_path.parent.parent / cn2py(state["source_path"])).exists() + source_path in ["取消", "算了"] + or img_id in ["取消", "算了"] + or destination_path in ["取消", "算了"] ): - 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) + await move_img.finish("已取消操作...") + if source_path not in Config.get_config("image_management", "IMAGE_DIR_LIST"): + await move_img.reject_arg("source_path", "移除目录不正确,请重新输入!") + if destination_path not in Config.get_config("image_management", "IMAGE_DIR_LIST"): + await move_img.reject_arg("destination_path", "移入目录不正确,请重新输入!") + if not is_number(img_id): + await move_img.reject_arg("id", "id不正确!请重新输入数字...") + source_path = _path / cn2py(source_path) + destination_path = _path / cn2py(destination_path) + if not source_path.exists(): + if (source_path.parent.parent / cn2py(source_path.name)).exists(): + source_path = source_path.parent.parent / cn2py(source_path.name) + if not destination_path.exists(): + if (destination_path.parent.parent / cn2py(destination_path.name)).exists(): + source_path = destination_path.parent.parent / cn2py(destination_path.name) + source_path.mkdir(exist_ok=True, parents=True) + destination_path.mkdir(exist_ok=True, parents=True) + if not len(os.listdir(source_path)): + await move_img.finish(f"{source_path}图库中没有任何图片,移动失败。") max_id = len(os.listdir(source_path)) - 1 des_max_id = len(os.listdir(destination_path)) if int(img_id) > max_id or int(img_id) < 0: await move_img.finish(f"Id超过上下限,上限:{max_id}", at_sender=True) try: - os.rename(source_path / f"{img_id}.jpg", destination_path / f"{des_max_id}.jpg") + move_file = source_path / f"{img_id}.jpg" + move_file.rename(destination_path / f"{des_max_id}.jpg") logger.info( f"移动 {source_path}/{img_id}.jpg ---> {destination_path}/{des_max_id} 移动成功" ) @@ -106,7 +97,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): await move_img.finish(f"移动图片id:{img_id} 失败了...", at_sender=True) if max_id > 0: try: - os.rename(source_path / f"{max_id}.jpg", source_path / f"{img_id}.jpg") + rep_file = source_path / f"{max_id}.jpg" + rep_file.rename(source_path / f"{img_id}.jpg") logger.info(f"{source_path}/{max_id}.jpg 替换 {source_path}/{img_id}.jpg 成功") except Exception as e: logger.warning( diff --git a/plugins/image_management/send_image/__init__.py b/plugins/image_management/send_image/__init__.py index 7fb617d7..32673115 100755 --- a/plugins/image_management/send_image/__init__.py +++ b/plugins/image_management/send_image/__init__.py @@ -1,14 +1,13 @@ -from nonebot import on_message, on_keyword, on_regex +from nonebot import on_message, on_regex from configs.path_config import IMAGE_PATH from utils.message_builder import image -from utils.utils import get_message_text, is_number +from utils.utils import is_number from services.log import logger -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message from utils.utils import FreqLimiter, cn2py -from pathlib import Path from configs.config import Config -from utils.manager import group_manager, withdraw_message_manager +from utils.manager import withdraw_message_manager +from nonebot.params import CommandArg from .rule import rule import random import os @@ -38,7 +37,6 @@ __plugin_settings__ = { "limit_superuser": False, "cmd": ["发送图片"] + Config.get_config("image_management", "IMAGE_DIR_LIST"), } -__plugin_task__ = {"pa": "丢人爬"} __plugin_resources__ = {"pa": IMAGE_PATH} Config.add_plugin_config( @@ -53,16 +51,15 @@ _flmt = FreqLimiter(1) send_img = on_message(priority=5, rule=rule, block=True) -pa = on_keyword({"丢人爬", "爪巴"}, priority=5, block=True) -pa_reg = on_regex("^爬$", priority=5, block=True) +pa_reg = on_regex("^(爬|丢人爬|爪巴)$", priority=5, block=True) -_path = Path(IMAGE_PATH) / "image_management" +_path = IMAGE_PATH / "image_management" @send_img.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()).split() +async def _(event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip().split() gallery = msg[0] if gallery not in Config.get_config("image_management", "IMAGE_DIR_LIST"): return @@ -74,7 +71,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): "image_management", "IMAGE_DIR_LIST" ): if not path.exists() and (path.parent.parent / cn2py(gallery)).exists(): - path = Path(IMAGE_PATH) / cn2py(gallery) + path = IMAGE_PATH / cn2py(gallery) else: path.mkdir(parents=True, exist_ok=True) length = len(os.listdir(path)) @@ -113,32 +110,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): await send_img.finish(f"不想给你看Ov|") -@pa.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - if ( - isinstance(event, GroupMessageEvent) - and not await group_manager.check_group_task_status(event.group_id, "pa") - or get_message_text(event.json()).startswith("开启") - or get_message_text(event.json()).startswith("关闭") - ): - return - msg = get_message_text(event.json()) - if not msg or str(event.get_message()[:2]) in ["开启", "关闭"]: - return - if _flmt.check(event.user_id): - _flmt.start_cd(event.user_id) - await pa.finish(image(random.choice(os.listdir(IMAGE_PATH + "pa")), "pa")) - - @pa_reg.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - if ( - isinstance(event, GroupMessageEvent) - and not await group_manager.check_group_task_status(event.group_id, "pa") - or get_message_text(event.json()).startswith("开启") - or get_message_text(event.json()).startswith("关闭") - ): - return +async def _(event: MessageEvent): if _flmt.check(event.user_id): _flmt.start_cd(event.user_id) - await pa_reg.finish(image(random.choice(os.listdir(IMAGE_PATH + "pa")), "pa")) + await pa_reg.finish(image(random.choice(os.listdir(IMAGE_PATH / "pa")), "pa")) diff --git a/plugins/image_management/send_image/rule.py b/plugins/image_management/send_image/rule.py index 981376f1..1ce46829 100644 --- a/plugins/image_management/send_image/rule.py +++ b/plugins/image_management/send_image/rule.py @@ -1,4 +1,4 @@ -from nonebot.adapters.cqhttp import Bot, Event +from nonebot.adapters.onebot.v11 import Bot, Event from nonebot.typing import T_State from utils.utils import get_message_text from configs.config import Config diff --git a/plugins/image_management/upload_image/__init__.py b/plugins/image_management/upload_image/__init__.py index cfc7c119..4dd2059e 100755 --- a/plugins/image_management/upload_image/__init__.py +++ b/plugins/image_management/upload_image/__init__.py @@ -1,10 +1,12 @@ from nonebot import on_command from nonebot.rule import to_me from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message from configs.config import Config -from utils.utils import get_message_img, get_message_text +from utils.utils import get_message_img from .data_source import upload_image_to_local +from nonebot.params import CommandArg, Arg, ArgStr +from typing import List __zx_plugin_name__ = "上传图片 [Admin]" @@ -22,7 +24,9 @@ __plugin_des__ = "指定图库图片上传" __plugin_cmd__ = ["上传图片 [图库] [图片]", "连续上传图片 [图库]", "查看公开图库"] __plugin_version__ = 0.1 __plugin_author__ = "HibiKier" -__plugin_settings__ = {"admin_level": Config.get_config("image_management", "UPLOAD_IMAGE_LEVEL")} +__plugin_settings__ = { + "admin_level": Config.get_config("image_management", "UPLOAD_IMAGE_LEVEL") +} upload_img = on_command("上传图片", rule=to_me(), priority=5, block=True) @@ -32,48 +36,42 @@ show_gallery = on_command("查看公开图库", priority=1, block=True) @show_gallery.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - x = '公开图库列表:\n' +async def _(): + x = "公开图库列表:\n" for i, e in enumerate(Config.get_config("image_management", "IMAGE_DIR_LIST")): - x += f'\t{i+1}.{e}\n' + x += f"\t{i+1}.{e}\n" await show_gallery.send(x[:-1]) -@upload_img.args_parser -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) - if msg in ["取消", "算了"]: - await upload_img.finish("已取消操作..", at_sender=True) - if state["_current_key"] in ["path"]: - if msg not in Config.get_config("image_management", "IMAGE_DIR_LIST"): - await upload_img.reject("此目录不正确,请重新输入目录!") - state["path"] = msg - if state["_current_key"] in ["imgs"]: - if not get_message_img(event.json()): - await upload_img.reject("图呢图呢图呢图呢!GKD!") - state["imgs"] = get_message_img(event.json()) - - @upload_img.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - raw_arg = get_message_text(event.json()) +async def _(event: MessageEvent, state: T_State, arg: Message = CommandArg()): + args = arg.extract_plain_text().strip() img_list = get_message_img(event.json()) - if raw_arg: - if raw_arg in Config.get_config("image_management", "IMAGE_DIR_LIST"): - state["path"] = raw_arg - if img_list: - state["imgs"] = img_list + if args: + if args in Config.get_config("image_management", "IMAGE_DIR_LIST"): + state["path"] = args + if img_list: + state["img_list"] = arg -@upload_img.got("path", prompt="要将图片上传至什么图库呢?") -async def _(bot: Bot, event: MessageEvent, state: T_State): - pass - - -@upload_img.got("imgs", prompt="图呢图呢图呢图呢!GKD!") -async def _(bot: Bot, event: MessageEvent, state: T_State): - path = state["path"] - img_list = state["imgs"] +@upload_img.got( + "path", + prompt=f"请选择要上传的图库\n- " + + "\n- ".join(Config.get_config("image_management", "IMAGE_DIR_LIST")), +) +@upload_img.got("img_list", prompt="图呢图呢图呢图呢!GKD!") +async def _( + bot: Bot, + event: MessageEvent, + state: T_State, + path: str = ArgStr("path"), + img_list: Message = Arg("img_list"), +): + if path not in Config.get_config("image_management", "IMAGE_DIR_LIST"): + await upload_img.reject_arg("path", "此目录不正确,请重新输入目录!") + if not get_message_img(img_list): + await upload_img.reject_arg("img_list", "图呢图呢图呢图呢!GKD!") + img_list = get_message_img(img_list) group_id = 0 if isinstance(event, GroupMessageEvent): group_id = event.group_id @@ -82,42 +80,35 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): ) -@continuous_upload_img.args_parser -async def _(bot: Bot, event: MessageEvent, state: T_State): - if str(event.get_message()) in ["取消", "算了"]: - await continuous_upload_img.finish("已取消操作..", at_sender=True) - if state["_current_key"] in ["path"]: - if str(event.get_message()) not in Config.get_config("image_management", "IMAGE_DIR_LIST"): - await continuous_upload_img.reject("此目录不正确,请重新输入目录!") - state[state["_current_key"]] = str(event.get_message()) - else: - if get_message_text(event.json()) not in ["stop"]: - img = get_message_img(event.json()) - if img: - state["tmp"].extend(img) - await continuous_upload_img.reject("图再来!!") - else: - state["imgs"] = state["tmp"] - - @continuous_upload_img.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent, state: T_State): path = get_message_img(event.json()) if path in Config.get_config("image_management", "IMAGE_DIR_LIST"): state["path"] = path - await continuous_upload_img.send("图来!!【停止请发送 ‘stop’ 开始上传】") - state["tmp"] = [] + state["img_list"] = [] -@continuous_upload_img.got("path", prompt="要将图片上传至什么图库呢?") -async def _(bot: Bot, event: MessageEvent, state: T_State): - pass - - -@continuous_upload_img.got("imgs", prompt="图呢图呢图呢图呢!GKD!") -async def _(bot: Bot, event: MessageEvent, state: T_State): - path = state["path"] - img_list = state["imgs"] +@continuous_upload_img.got( + "path", + prompt=f"请选择要上传的图库\n- " + + "\n- ".join(Config.get_config("image_management", "IMAGE_DIR_LIST")), +) +@continuous_upload_img.got("img", prompt="图呢图呢图呢图呢!GKD!【发送‘stop’为停止】") +async def _( + event: MessageEvent, + state: T_State, + img_list: List[str] = Arg("img_list"), + path: str = ArgStr("path"), + img: Message = Arg("img"), +): + if path not in Config.get_config("image_management", "IMAGE_DIR_LIST"): + await upload_img.reject_arg("path", "此目录不正确,请重新输入目录!") + if not img.extract_plain_text() == "stop": + img = get_message_img(img) + if img: + for i in img: + img_list.append(i) + await upload_img.reject_arg("img", "图再来!!【发送‘stop’为停止】") group_id = 0 if isinstance(event, GroupMessageEvent): group_id = event.group_id diff --git a/plugins/image_management/upload_image/data_source.py b/plugins/image_management/upload_image/data_source.py index 1ac655ab..a9718f32 100755 --- a/plugins/image_management/upload_image/data_source.py +++ b/plugins/image_management/upload_image/data_source.py @@ -3,12 +3,11 @@ from typing import List from configs.path_config import IMAGE_PATH from services.log import logger from utils.utils import cn2py -from pathlib import Path from utils.http_utils import AsyncHttpx import os -_path = Path(IMAGE_PATH) / "image_management" +_path = IMAGE_PATH / "image_management" async def upload_image_to_local( diff --git a/plugins/luxun/__init__.py b/plugins/luxun/__init__.py index f988901b..38c2ee85 100755 --- a/plugins/luxun/__init__.py +++ b/plugins/luxun/__init__.py @@ -1,11 +1,11 @@ from configs.path_config import IMAGE_PATH from nonebot import on_command from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message from utils.message_builder import image from services.log import logger -from utils.utils import get_message_text from utils.image_utils import BuildImage +from nonebot.params import CommandArg __zx_plugin_name__ = "鲁迅说" __plugin_usage__ = """ @@ -35,14 +35,14 @@ luxun_author = BuildImage(0, 0, plain_text="--鲁迅", font_size=30, font='msyh. @luxun.handle() -async def handle(bot: Bot, event: MessageEvent, state: T_State): - args = get_message_text(event.json()) +async def handle(state: T_State, arg: Message = CommandArg()): + args = arg.extract_plain_text().strip() if args: state["content"] = args if args else "烦了,不说了" @luxun.got("content", prompt="你让鲁迅说点啥?") -async def handle_event(bot: Bot, event: MessageEvent, state: T_State): +async def handle_event(event: MessageEvent, state: T_State): content = state["content"].strip() if content.startswith(",") or content.startswith(","): content = content[1:] diff --git a/plugins/mute.py b/plugins/mute.py index b3c91873..6513f33a 100755 --- a/plugins/mute.py +++ b/plugins/mute.py @@ -1,15 +1,16 @@ from nonebot import on_message, on_command -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from nonebot.adapters.cqhttp.permission import GROUP -from utils.utils import get_message_text, is_number, get_message_img +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message +from nonebot.adapters.onebot.v11.permission import GROUP +from utils.utils import is_number, get_message_img from nonebot.typing import T_State -from nonebot.adapters.cqhttp.exception import ActionFailed +from nonebot.adapters.onebot.v11.exception import ActionFailed from configs.path_config import DATA_PATH, TEMP_PATH from utils.image_utils import get_img_hash from services.log import logger from configs.config import NICKNAME, Config from utils.http_utils import AsyncHttpx -from pathlib import Path +from nonebot.params import CommandArg, Command +from typing import Tuple import time try: @@ -58,7 +59,7 @@ mute_setting = on_command( def get_data(): try: - with open(DATA_PATH + "group_mute_data.json", "r", encoding="utf8") as f: + with open(DATA_PATH / "group_mute_data.json", "r", encoding="utf8") as f: data = json.load(f) except (ValueError, FileNotFoundError): data = {} @@ -67,15 +68,15 @@ def get_data(): def save_data(): global mute_data - with open(DATA_PATH + "group_mute_data.json", "w", encoding="utf8") as f: + with open(DATA_PATH / "group_mute_data.json", "w", encoding="utf8") as f: json.dump(mute_data, f, indent=4) async def download_img_and_hash(url, group_id): if await AsyncHttpx.download_file( - url, Path(TEMP_PATH) / f"mute_{group_id}_img.jpg" + url, TEMP_PATH / f"mute_{group_id}_img.jpg" ): - return str(get_img_hash(Path(TEMP_PATH) / f"mute_{group_id}_img.jpg")) + return str(get_img_hash(TEMP_PATH / f"mute_{group_id}_img.jpg")) return "" @@ -84,12 +85,12 @@ mute_data = get_data() @mute.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): group_id = str(event.group_id) - msg = get_message_text(event.json()) - imgs = get_message_img(event.json()) + msg = arg.extract_plain_text().strip() + img_list = get_message_img(event.json()) img_hash = "" - for img in imgs: + for img in img_list: img_hash += await download_img_and_hash(img, event.group_id) msg += img_hash if not mute_data.get(group_id): @@ -101,7 +102,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): if not mute_dict.get(event.user_id): mute_dict[event.user_id] = {"time": time.time(), "count": 1, "msg": msg} else: - if state["_prefix"]["raw_command"] or not msg: + if cmd or not msg: return if msg and msg.find(mute_dict[event.user_id]["msg"]) != -1: mute_dict[event.user_id]["count"] += 1 @@ -135,12 +136,12 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @mute_setting.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): group_id = str(event.group_id) if not mute_data.get(group_id): mute_data[group_id] = {"count": 10, "time": 7, "duration": 0} - msg = get_message_text(event.json()) - if state["_prefix"]["raw_command"] == "刷屏检测设置": + msg = arg.extract_plain_text().strip() + if cmd[0] == "刷屏检测设置": await mute_setting.finish( f'最大次数:{mute_data[group_id]["count"]} 次\n' f'规定时间:{mute_data[group_id]["time"]} 秒\n' @@ -149,17 +150,17 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): ) if not is_number(msg): await mute.finish("设置的参数必须是数字啊!", at_sender=True) - if state["_prefix"]["raw_command"] == "设置检测时间": + if cmd[0] == "设置检测时间": mute_data[group_id]["time"] = int(msg) msg += "秒" - if state["_prefix"]["raw_command"] == "设置检测次数": + if cmd[0] == "设置检测次数": mute_data[group_id]["count"] = int(msg) msg += " 次" - if state["_prefix"]["raw_command"] == "设置禁言时长": + if cmd[0] == "设置禁言时长": mute_data[group_id]["duration"] = int(msg) * 60 msg += " 分钟" - await mute_setting.send(f'刷屏检测:{state["_prefix"]["raw_command"]}为 {msg}') + await mute_setting.send(f'刷屏检测:{cmd[0]}为 {msg}') logger.info( - f'USER {event.user_id} GROUP {group_id} {state["_prefix"]["raw_command"]}:{msg}' + f'USER {event.user_id} GROUP {group_id} {cmd[0]}:{msg}' ) save_data() diff --git a/plugins/my_info/__init__.py b/plugins/my_info/__init__.py index 4939899c..4b5946e3 100644 --- a/plugins/my_info/__init__.py +++ b/plugins/my_info/__init__.py @@ -1,7 +1,6 @@ from nonebot import on_command -from nonebot.adapters.cqhttp.permission import GROUP -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent +from nonebot.adapters.onebot.v11.permission import GROUP +from nonebot.adapters.onebot.v11 import GroupMessageEvent from models.group_member_info import GroupInfoUser from datetime import timedelta from models.level_user import LevelUser @@ -26,7 +25,7 @@ my_level = on_command("我的权限", permission=GROUP, priority=5, block=True) @get_my_group_info.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): result = await get_member_info(event.user_id, event.group_id) await get_my_group_info.finish(result) @@ -42,7 +41,7 @@ async def get_member_info(user_qq: int, group_id: int) -> str: @my_level.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): if (level := await LevelUser.get_user_level(event.user_id, event.group_id)) == -1: await my_level.finish("您目前没有任何权限了,硬要说的话就是0吧~", at_sender=True) await my_level.finish(f"您目前的权限等级:{level}", at_sender=True) diff --git a/plugins/nbnhhsh.py b/plugins/nbnhhsh.py index 469e620a..bbbb3f3b 100755 --- a/plugins/nbnhhsh.py +++ b/plugins/nbnhhsh.py @@ -1,7 +1,6 @@ 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 +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message +from nonebot.params import CommandArg from utils.http_utils import AsyncHttpx from services.log import logger import ujson as json @@ -31,8 +30,8 @@ nbnhhsh = on_command("nbnhhsh", aliases={"能不能好好说话"}, priority=5, b @nbnhhsh.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() if not msg: await nbnhhsh.finish("没话说就别说话!") response = await AsyncHttpx.post( diff --git a/plugins/nonebot_plugin_picsearcher/__init__.py b/plugins/nonebot_plugin_picsearcher/__init__.py deleted file mode 100755 index 6f97e9e7..00000000 --- a/plugins/nonebot_plugin_picsearcher/__init__.py +++ /dev/null @@ -1,180 +0,0 @@ -# -*- coding: utf-8 -*- -from typing import Dict - -from nonebot.plugin import on_command, on_message -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent -from nonebot.typing import T_State -from services.log import logger -from utils.utils import get_message_text, get_message_img -from configs.config import Config -from nonebot.rule import to_me - -from .ex import get_des as get_des_ex -from .iqdb import get_des as get_des_iqdb -from .saucenao import get_des as get_des_sau -from .ascii2d import get_des as get_des_asc -from .trace import get_des as get_des_trace -from .yandex import get_des as get_des_yandex - - -__zx_plugin_name__ = "识图" -__plugin_usage__ = """ -usage: - 识别图片 [二次元图片] - 指令: - 识图 [图片] -""".strip() -__plugin_des__ = "以图搜图,看破本源" -__plugin_cmd__ = ["识图"] -__plugin_type__ = ("一些工具",) -__plugin_version__ = 0.1 -__plugin_author__ = "synodriver" -__plugin_settings__ = { - "level": 5, - "default_status": True, - "limit_superuser": False, - "cmd": ["识图"], -} -__plugin_configs__ = { - "MAX_FIND_IMAGE_COUNT": {"value": 3, "help": "识图返回的最大结果数", "default_value": 3} -} - - -async def get_des(url: str, mode: str, user_id: int): - """ - :param url: 图片链接 - :param mode: 图源 - :param user_id: 用户 id - """ - if mode == "iqdb": - async for msg in get_des_iqdb(url): - yield msg - elif mode == "ex": - async for msg in get_des_ex(url): - yield msg - elif mode == "trace": - async for msg in get_des_trace(url): - yield msg - elif mode == "yandex": - async for msg in get_des_yandex(url): - yield msg - elif mode.startswith("asc"): - async for msg in get_des_asc(url, user_id): - yield msg - else: - async for msg in get_des_sau(url, user_id): - yield msg - - -setu = on_command("识图", aliases={"search"}, block=True, priority=5) - - -@setu.handle() -async def handle_first_receive(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) - imgs = get_message_img(event.json()) - if imgs: - state["setu"] = imgs[0] - if msg: - state["mod"] = msg - - -# ex/nao/trace/iqdb/ascii2d -# @setu.got("mod", prompt="从哪里查找呢? ex/nao/trace/iqdb/ascii2d") -# async def get_func(bot: Bot, event: MessageEvent, state: dict): -# pass - - -@setu.args_parser -async def get_setu(bot: Bot, event: MessageEvent, state: T_State): - imgs = get_message_img(event.json()) - msg = get_message_text(event.json()) - if not imgs: - await setu.reject() - if msg: - state["mod"] = msg - state["setu"] = imgs[0] - - -@setu.got("setu", prompt="图呢?") -async def get_setu(bot: Bot, event: MessageEvent, state: T_State): - """ - 发现没有的时候要发问 - :return: - """ - url: str = state["setu"] - mod: str = state["mod"] if state.get("mod") else "nao" # 模式 - try: - await bot.send(event=event, message="正在处理图片") - idx = 1 - async for msg in get_des(url, mod, event.user_id): - if msg: - await bot.send(event=event, message=msg) - if idx == Config.get_config( - "nonebot_plugin_picsearcher", "MAX_FIND_IMAGE_COUNT" - ): - break - idx += 1 - if id == 1: - await bot.send(event=event, message="没找着.") - logger.info( - f"(USER {event.user_id}, GROUP " - f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 识图:{url}" - ) - # image_data: List[Tuple] = await get_pic_from_url(url) - # await setu.finish("hso") - except IndexError: - # await bot.send(event, traceback.format_exc()) - await setu.finish("参数错误") - # except ClientError: - # await setu.finish("连接失败") - - -pic_map: Dict[str, str] = {} # 保存这个群的其阿金一张色图 {"123456":http://xxx"} - - -async def check_pic(bot: Bot, event: MessageEvent, state: T_State) -> bool: - if isinstance(event, MessageEvent): - for msg in event.message: - if msg.type == "image": - url: str = msg.data["url"] - state["url"] = url - return True - return False - - -notice_pic = on_message(check_pic, block=False, priority=1) - - -@notice_pic.handle() -async def handle_pic(bot: Bot, event: GroupMessageEvent, state: T_State): - try: - group_id: str = str(event.group_id) - pic_map.update({group_id: state["url"]}) - except AttributeError: - pass - - -previous = on_command("上一张图是什么", aliases={"上一张", "这是什么"}, rule=to_me(), block=True) - - -@previous.handle() -async def handle_previous(bot: Bot, event: GroupMessageEvent, state: T_State): - await bot.send(event=event, message="processing...") - try: - url: str = pic_map[str(event.group_id)] - idx = 1 - async for msg in get_des(url, "nao", event.user_id): - await bot.send(event=event, message=msg) - if idx == Config.get_config( - "nonebot_plugin_picsearcher", "MAX_FIND_IMAGE_COUNT" - ): - break - idx += 1 - except IndexError: - await previous.finish("参数错误") - except KeyError: - await previous.finish("没有图啊QAQ") - except Exception as e: - logger.error(f"识图未知错误 {type(e)}:{e}") - await previous.finish("未知错误...") diff --git a/plugins/nonebot_plugin_picsearcher/ascii2d.py b/plugins/nonebot_plugin_picsearcher/ascii2d.py deleted file mode 100755 index b6b56547..00000000 --- a/plugins/nonebot_plugin_picsearcher/ascii2d.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -*- -from typing import List, Tuple -from urllib.parse import urljoin -import aiofiles -from utils.utils import get_local_proxy -from utils.user_agent import get_user_agent -from configs.path_config import IMAGE_PATH -from asyncio.exceptions import TimeoutError -from utils.message_builder import image - -from lxml.html import fromstring -import aiohttp - - -def parse_html(html: str): - selector = fromstring(html) - for tag in selector.xpath('//div[@class="container"]/div[@class="row"]/div/div[@class="row item-box"]')[1:5]: - if pic_url := tag.xpath('./div/img[@loading="lazy"]/@src'): # 缩略图url - pic_url = urljoin("https://ascii2d.net/", pic_url[0]) - if description := tag.xpath('./div/div/h6/a[1]/text()'): # 名字 - description = description[0] - if author := tag.xpath('./div/div/h6/a[2]/text()'): # 作者 - author = author[0] - if origin_url := tag.xpath('./div/div/h6/a[1]/@href'): # 原图地址 - origin_url = origin_url[0] - if author_url := tag.xpath('./div/div/h6/a[2]/@href'): # 作者地址 - author_url = author_url[0] - yield pic_url, description, author, origin_url, author_url - - pass - - -async def get_pic_from_url(url: str): - real_url = "https://ascii2d.net/search/url/" + url - async with aiohttp.ClientSession() as session: - async with session.get(real_url) as resp: - html: str = await resp.text() - return [i for i in parse_html(html)] - - -async def get_des(url: str, user_id): - image_data: List[Tuple] = await get_pic_from_url(url) - if not image_data: - msg: str = "找不到高相似度的" - yield msg - return - for pic in image_data: - msg = await download_img(pic[0], user_id) + "\n" - for i in pic[1:]: - msg = msg + f"{i}\n" - yield msg - - -async def download_img(url, user_id): - try: - async with aiohttp.ClientSession(headers=get_user_agent()) as session: - async with session.get(url, proxy=get_local_proxy(), timeout=7) as response: - async with aiofiles.open(IMAGE_PATH + f'temp/{user_id}_pic_find.png', 'wb') as f: - await f.write(await response.read()) - return image(f'{user_id}_pic_find.png', 'temp') - except TimeoutError: - return image(url) - diff --git a/plugins/nonebot_plugin_picsearcher/ex.py b/plugins/nonebot_plugin_picsearcher/ex.py deleted file mode 100755 index 172ac391..00000000 --- a/plugins/nonebot_plugin_picsearcher/ex.py +++ /dev/null @@ -1,107 +0,0 @@ -# -*- coding: utf-8 -*- -from base64 import b64encode -from typing import List, Tuple -import io - -from lxml.html import fromstring -import aiohttp -import nonebot -from aiohttp.client_exceptions import InvalidURL -from nonebot.adapters.cqhttp import MessageSegment - -from .formdata import FormData - -driver = nonebot.get_driver() -cookie: str = driver.config.ex_cookie -proxy: str = driver.config.proxy -target: str = "https://exhentai.org/upload/image_lookup.php" - -headers = { - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', - 'Accept-Encoding': 'gzip, deflate', - 'Accept-Language': 'zh-CN,zh;q=0.9', - 'Cache-Control': 'max-age=0', - 'Connection': 'keep-alive', - 'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryB0NrMSYMfjY5r0l1', - 'Host': 'exhentai.org', - 'Origin': 'https://exhentai.org', - 'Referer': 'https://exhentai.org/?filesearch=1', - 'Sec-Fetch-Dest': 'document', - 'Sec-Fetch-Mode': 'navigate', - 'Sec-Fetch-Site': 'same-origin', - 'Sec-Fetch-User': '?1', - 'Upgrade-Insecure-Requests': '1', - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36'} - -if cookie: - headers['Cookie'] = cookie -else: - headers['Host'] = 'e-hentai.org' - headers['Origin'] = 'https://e-hentai.org' - headers['Referer'] = 'https://e-hentai.org/?filesearch=1' - target: str = "https://e-hentai.org/upload/image_lookup.php" - - -def parse_html(html: str): - """ - 解析exhentai返回的数据 - :param html: - :return: - """ - selector = fromstring(html) - hrefs = selector.xpath('//td[@class="gl3c glname"]/a/@href') - names = selector.xpath('//td[@class="gl3c glname"]/a/div[1]/text()') - pics = selector.xpath('//tr/td[@class="gl2c"]/div[@class="glthumb"]/div[1]/img/@src') # 缩略图 - for name, href, pic in zip(names, hrefs, pics): - yield name, href, pic - - -async def get_pic_from_url(url: str): - """ - 从接受到的picurl获取图片信息 - :param url: - :return: - """ - async with aiohttp.ClientSession() as session: - async with session.get(url) as resp: - content = io.BytesIO(await resp.read()) - # Content_Length = resp.content_length - data = FormData(boundary="----WebKitFormBoundaryB0NrMSYMfjY5r0l1") - data.add_field(name="sfile", value=content, content_type="image/jpeg", - filename="0.jpg") - data.add_field(name="f_sfile", value="search") - data.add_field(name="fs_similar", value="on") - async with session.post(target, data=data, headers=headers, proxy=proxy) as res: - html = await res.text() - return [i for i in parse_html(html)] - - -async def get_content_from_url(url: str): - """ - 从url 获得b64 encode - :param url: - :return: - """ - try: - async with aiohttp.ClientSession() as session: - async with session.get(url, headers=headers) as resp: - return "base64://" + b64encode(await resp.read()).decode() - except aiohttp.client_exceptions.InvalidURL: - return url - - -async def get_des(url: str): - """ - 迭代要发送的信息 - :param url: - :return: - """ - image_data: List[Tuple] = await get_pic_from_url(url) - if not image_data: - msg: str = "找不到高相似度的" - yield msg - return - for name, href, pic_url in image_data: - content = await get_content_from_url(pic_url) - msg = MessageSegment.image(file=content) + f"\n本子名称:{name}\n" + f"链接{href}\n" - yield msg diff --git a/plugins/nonebot_plugin_picsearcher/formdata.py b/plugins/nonebot_plugin_picsearcher/formdata.py deleted file mode 100755 index f70f040e..00000000 --- a/plugins/nonebot_plugin_picsearcher/formdata.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: utf-8 -*- -from typing import Any, Iterable, List, Optional - -from aiohttp import FormData as _FormData -import aiohttp.multipart as multipart - - -class FormData(_FormData): - def __init__( - self, - fields: Iterable[Any] = (), - quote_fields: bool = True, - charset: Optional[str] = None, - boundary: Optional[str] = None - ) -> None: - self._writer = multipart.MultipartWriter("form-data", boundary=boundary) - self._fields = [] # type: List[Any] - self._is_multipart = False - self._is_processed = False - self._quote_fields = quote_fields - self._charset = charset - - if isinstance(fields, dict): - fields = list(fields.items()) - elif not isinstance(fields, (list, tuple)): - fields = (fields,) - self.add_fields(*fields) diff --git a/plugins/nonebot_plugin_picsearcher/iqdb.py b/plugins/nonebot_plugin_picsearcher/iqdb.py deleted file mode 100755 index 60b9f934..00000000 --- a/plugins/nonebot_plugin_picsearcher/iqdb.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -import asyncio -from typing import List, Tuple -import io - -from urllib.parse import urljoin -from lxml.html import fromstring -import aiohttp -from nonebot.adapters.cqhttp import MessageSegment - -from .formdata import FormData - -headers = { - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', - 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Cache-Control': 'max-age=0', - 'Connection': 'keep-alive', - 'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryuwjSiBcpPag4k159', - 'Cookie': 'Hm_lvt_765ecde8c11b85f1ac5f168fa6e6821f=1602471368; Hm_lpvt_765ecde8c11b85f1ac5f168fa6e6821f=1602472300', - 'Host': 'iqdb.org', 'Origin': 'http://iqdb.org', 'Referer': 'http://iqdb.org/', 'Upgrade-Insecure-Requests': '1', - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36'} - - -def parse_html(html: str): - selector = fromstring(html) - for tag in selector.xpath('//div[@id="pages"]/div[position()>1]/table'): - # 第一个是bestmatch - if pic_url := tag.xpath('./tr[2]/td/a/img/@src'): - pic_url = urljoin("http://iqdb.org/", pic_url[0]) # 缩略图 - else: - pic_url = "没有最相似的" - similarity = tag.xpath('./tr[last()]/td/text()')[0] # 相似度 - href: List[str] = tag.xpath('./tr/td/a/@href') # 第一个href - href.extend(tag.xpath('./tr/td/span/a/@href')) # 第二个 可能是空 - href = list(map(lambda x: "https:" + x if not x.startswith("https") else x, href)) - yield pic_url, similarity, href - - pass - - -async def get_pic_from_url(url: str): - """ - 返回信息元祖 - :param url: - :return: - """ - async with aiohttp.ClientSession() as session: - async with session.get(url) as resp: - content = io.BytesIO(await resp.read()) - data = FormData(boundary="----WebKitFormBoundaryuwjSiBcpPag4k159") - data.add_field(name="MAX_FILE_SIZE", value="") - for i in range(1, 7): - data.add_field(name="service[]", value=str(i)) - data.add_field(name="service[]", value="11") - data.add_field(name="service[]", value="13") - data.add_field(name="file", value=content, content_type="application/octet-stream", filename="0.jpg") - data.add_field(name="url", value="") - async with session.post("http://iqdb.org/", data=data, headers=headers) as res: - html = await res.text() - return [i for i in parse_html(html)] - pass - - -async def get_des(url: str): - """ - 返回详细简介 cq码转义 - :param url: - :return: - """ - image_data: List[Tuple] = await get_pic_from_url(url) - if not image_data: - msg: str = "找不到高相似度的" - yield msg - return - for pic in image_data: - msg = MessageSegment.image(file=pic[0]) + f"\n{pic[1]}\n" - for i in pic[2]: - msg = msg + f"{i}\n" - yield msg - diff --git a/plugins/nonebot_plugin_picsearcher/saucenao.py b/plugins/nonebot_plugin_picsearcher/saucenao.py deleted file mode 100755 index f359b19d..00000000 --- a/plugins/nonebot_plugin_picsearcher/saucenao.py +++ /dev/null @@ -1,117 +0,0 @@ -# -*- coding: utf-8 -*- -import io -from typing import List, Tuple, Union -import aiofiles -from utils.utils import get_local_proxy -from utils.user_agent import get_user_agent -from configs.path_config import IMAGE_PATH -from asyncio.exceptions import TimeoutError -from utils.message_builder import image - -import aiohttp -from lxml.html import fromstring -from nonebot.adapters.cqhttp import Message - -from .formdata import FormData - -header = { - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', - 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-CN,zh;q=0.9', - 'Cache-Control': 'max-age=0', - "Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryPpuR3EZ1Ap2pXv8W", - 'Connection': 'keep-alive', - 'Host': 'saucenao.com', 'Origin': 'https://saucenao.com', 'Referer': 'https://saucenao.com/index.php', - 'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Mode': 'navigate', 'Sec-Fetch-Site': 'same-origin', 'Sec-Fetch-User': '?1', - 'Upgrade-Insecure-Requests': '1', - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36'} - - -def parse_html(html: str): - """ - 解析nao返回的html - :param html: - :return: - """ - selector = fromstring(html) - for tag in selector.xpath('//div[@class="result"]/table'): - pic_url = tag.xpath('./tr/td/div/a/img/@src') - if pic_url: - pic_url = pic_url[0] - else: - pic_url = None # 相似度 - xsd: List[str] = tag.xpath( - './tr/td[@class="resulttablecontent"]/div[@class="resultmatchinfo"]/div[@class="resultsimilarityinfo"]/text()') - if xsd: - xsd = xsd[0] - else: - xsd = "没有写" # 相似度 - title: List[str] = tag.xpath( - './tr/td[@class="resulttablecontent"]/div[@class="resultcontent"]/div[@class="resulttitle"]/strong/text()') - if title: - title = title[0] - else: - title = "没有写" # 标题 - # pixiv id - pixiv_id: List[str] = tag.xpath( - './tr/td[@class="resulttablecontent"]/div[@class="resultcontent"]/div[@class="resultcontentcolumn"]/a[1]/@href') - if pixiv_id: - pixiv_id = pixiv_id[0] - else: - pixiv_id = "没有说" - member: List[str] = tag.xpath( - './tr/td[@class="resulttablecontent"]/div[@class="resultcontent"]/div[@class="resultcontentcolumn"]/a[2]/@href') - if member: - member = member[0] - else: - member = "没有说" - yield pic_url, xsd, title, pixiv_id, member - - -async def get_pic_from_url(url: str): - """ - 从url搜图 - :param url: - :return: - """ - async with aiohttp.ClientSession() as session: - async with session.get(url) as resp: - content = io.BytesIO(await resp.read()) - data = FormData(boundary="----WebKitFormBoundaryPpuR3EZ1Ap2pXv8W") - data.add_field(name="file", value=content, content_type="image/jpeg", - filename="blob") - async with session.post("https://saucenao.com/search.php", proxy=get_local_proxy(), data=data, headers=header) as res: - html = await res.text() - image_data = [each for each in parse_html(html)] - return image_data - - -async def get_des(url: str, user_id: int): - image_data: List[Tuple] = await get_pic_from_url(url) - if not image_data: - msg: Union[str, Message] = "找不到高相似度的" - yield msg - return - for pic in image_data: - # print(pic) - if int(str(pic[1]).split('.')[0]) > 80: - msg = await download_img(pic[0], user_id) \ - + f"\n相似度:{pic[1]}" \ - f"\n标题:{pic[2] if (str(pic[2]).strip() != 'Creator:' and len(str(pic[2]).split('-')) < 3) else '未知'}" \ - f"\nPID:{pic[3]}" \ - f"\nmember:{pic[4]}\n" - yield msg - pass - - -async def download_img(url, user_id): - try: - async with aiohttp.ClientSession(headers=get_user_agent()) as session: - async with session.get(url, proxy=get_local_proxy(), timeout=7) as response: - async with aiofiles.open(IMAGE_PATH + f'temp/{user_id}_pic_find.png', 'wb') as f: - await f.write(await response.read()) - return image(f'{user_id}_pic_find.png', 'temp') - except TimeoutError: - return image(url) - - - diff --git a/plugins/nonebot_plugin_picsearcher/trace.py b/plugins/nonebot_plugin_picsearcher/trace.py deleted file mode 100755 index 0c28d2f2..00000000 --- a/plugins/nonebot_plugin_picsearcher/trace.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- -import io -from copy import deepcopy - -from base64 import b64encode -from typing import List, Tuple - -import aiohttp -from nonebot.adapters.cqhttp import MessageSegment - -header = {':authority': 'api.trace.moe', - 'accept': '*/*', - 'accept-encoding': 'gzip, deflate, br', - 'accept-language': 'zh-CN,zh;q=0.9', - 'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary9cyjY8YBBN8SGdG4', - 'origin': 'https://trace.moe', - 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-site', - 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' - 'Chrome/84.0.4147.105 Safari/537.36'} - - -async def parse_json(session: aiohttp.ClientSession, data: dict): - count = 0 - for i in data["result"]: - title: dict = i["anilist"]["title"] - similarity = i["similarity"] - from_ = i["from"] - to = i["to"] - file = i["filename"] # 名字 - is_adult = i["anilist"]["isAdult"] - episode = i["episode"] # 集 - header_new = deepcopy(header) - del header_new["content-type"] - header_new[":method"] = 'GET' - header_new["accept"] = "image/webp,image/apng,image/*,*/*;q=0.8" - header_new["sec-fetch-dest"] = "image" - header_new["sec-fetch-mode"] = "no-cors" - async with session.get(i["image"], headers=header_new) as resp: - pic = "base64://" + b64encode(await resp.read()).decode() - yield pic, similarity, file, is_adult, from_, to, title, episode - count += 1 - if count > 4: - break - - -# POST https://api.trace.moe/search?cutBorders=1&anilistID= -async def get_pic_from_url(url: str): - """ - 从url搜图 - :param url: - :return: - """ - async with aiohttp.ClientSession() as session: - async with session.get(url) as resp: - content = io.BytesIO(await resp.read()) - # with open("F:\elu.PNG", "rb") as f: - # content = io.BytesIO(f.read()) - data = aiohttp.FormData(boundary="----WebKitFormBoundary9cyjY8YBBN8SGdG4") - data.add_field(name="image", value=content, content_type="image/jpeg", - filename="blob") - # data.add_field(name="filter", value="") - # data.add_field(name="trial", value="0") - async with session.post("https://api.trace.moe/search?cutBorders=1&anilistID=", data=data, - headers=header) as res: - data: dict = await res.json() - image_data = [each async for each in parse_json(session, data)] - return image_data - - -async def get_des(url: str): - image_data: List[Tuple] = await get_pic_from_url(url) - if not image_data: - msg: str = "找不到高相似度的" - yield msg - return - for pic in image_data: - msg = MessageSegment.image( - file=pic[ - 0]) + f"\n相似度:{pic[1]}%\n标题:{pic[6]['native'] + ' ' + pic[6]['chinese']}\n第{pic[7]}集\nR18:{pic[3]}\n开始时间:{pic[4]}s\n结束时间{pic[5]}s" - yield msg - pass - - -if __name__ == "__main__": - import asyncio - - data = asyncio.run(get_pic_from_url( - "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1606681978562&di=6d6c90aef5ff1f9f8915bbc2e18e3c98&imgtype=0&src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202011%2F15%2F20201115190356_c5b95.thumb.1000_0.jpg")) - pass diff --git a/plugins/nonebot_plugin_picsearcher/yandex.py b/plugins/nonebot_plugin_picsearcher/yandex.py deleted file mode 100755 index 0632e442..00000000 --- a/plugins/nonebot_plugin_picsearcher/yandex.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding: utf-8 -*- -from typing import List, Tuple - -import nonebot -from nonebot.adapters.cqhttp import MessageSegment -from lxml.html import fromstring -import aiohttp - -""" -http://yandex.com/clck/jsredir?from=yandex.com%3Bimages%2Fsearch%3Bimages%3B%3B&text=&etext=9185.K4iyzsNBG9xrJrSJCUTF4i-XPMAfmBQYR_Igss1ESRc.65568e796f3375fae39da91273ae8a1a82410929&uuid=&state=iric5OQ0sS2054x1_o8yG9mmGMT8WeQxqpuwa4Ft4KVzd9aE_Y4Dfw,,&data=eEwyM2lDYU9Gd1VROE1ZMXhZYkJTYW5fZC1TWjIzaFh5TmR1Z09fQm5DdDB3bFJSSUpVdUxfZmUzcVhfaXhTN1BCU2dINGxmdkY4NFVNcHYyUmw0emFKT2pnOWJoVmlPVzAzX1FIbWh6aXVFV3F0YWFaMGdxeGFtY2dxTzFZZl9VY1huZmlLaGVGOFZleUthZXBlM1pxUGM2elVDLXdvZEo3OGJwdVFqYmVkTDJxWElHSzFZR2NVQUhVcTdzelJwSXlrTjhlS0txdHpYY1RMMHRLOU5HSTYtT0VDb0hpdll6YjVYRXNVcUhCRFJaeDExNTQwZlhMdjh4M2YtTVFUbVJ5ZzBxMTVJcG9DNW51UWhvRzE0WjlFS19uS0VUZWhNRGxOZWlPUkFlRUUs&sign=7ba9ee25d3716868ec8464fb766c9e25&keyno=IMGS_0&b64e=2&l10n=en -""" - -driver = nonebot.get_driver() -proxy: str = driver.config.proxy - - -def parse_html(html: str): - selector = fromstring(html) - for item in selector.xpath('//li[@class="other-sites__item"]'): - pic_url = item.xpath('./a[@class="other-sites__preview-link"]/img/@src')[0].lstrip("//") # 图床 - des = item.xpath( - './div[@class="other-sites__snippet"]/div[@class="other-sites__snippet-title"]/a/text()')[0] # 简介 - url = item.xpath( - './div[@class="other-sites__snippet"]/div[@class="other-sites__snippet-site"]/a/@href')[0] # 链接 - yield pic_url, des, url - - -async def get_pic_from_url(url: str): - real_url = f"https://yandex.com/images/search?rpt=imageview&url={url}" - async with aiohttp.ClientSession() as session: - async with session.get(real_url, proxy=proxy) as resp: - html: str = await resp.text() - return [i for i in parse_html(html)] - - -async def get_des(url: str): - image_data: List[Tuple] = await get_pic_from_url(url) - if not image_data: - msg: str = "找不到高相似度的" - yield msg - return - for pic in image_data: - msg = MessageSegment.image(file=pic[0]) + "\n" - for i in pic[1:]: - msg = msg + f"{i}\n" - yield msg - - -if __name__ == "__main__": - with open("yandex.html", "r", encoding="utf-8") as f: - data = f.read() - for item in parse_html(data): - print(item) diff --git a/plugins/one_friend/__init__.py b/plugins/one_friend/__init__.py index 67dd0937..93c42660 100755 --- a/plugins/one_friend/__init__.py +++ b/plugins/one_friend/__init__.py @@ -2,11 +2,12 @@ from io import BytesIO from random import choice from nonebot import on_regex from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from utils.utils import get_message_text, get_message_at, get_user_avatar +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent +from utils.utils import get_message_at, get_user_avatar from utils.message_builder import image -import re from utils.image_utils import BuildImage +from nonebot.params import RegexGroup +from typing import Tuple, Any __zx_plugin_name__ = "我有一个朋友" __plugin_usage__ = """ @@ -27,22 +28,21 @@ __plugin_settings__ = { } one_friend = on_regex( - "^我.*?朋友.*?(想问问|说|让我问问|想问|让我问|想知道|让我帮他问问|让我帮他问|让我帮忙问|让我帮忙问问|问).*", + "^我.*?朋友.*?(想问问|说|让我问问|想问|让我问|想知道|让我帮他问问|让我帮他问|让我帮忙问|让我帮忙问问|问)(.*)", priority=4, block=True, ) @one_friend.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(bot: Bot, event: GroupMessageEvent, state: T_State, reg_group: Tuple[Any, ...] = RegexGroup()): qq = get_message_at(event.json()) if not qq: qq = choice( [ x["user_id"] for x in await bot.get_group_member_list( - self_id=event.self_id, group_id=event.group_id + group_id=event.group_id ) ] ) @@ -50,11 +50,8 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): else: qq = qq[0] at_user = await bot.get_group_member_info(group_id=event.group_id, user_id=qq) - user_name = at_user["card"] if at_user["card"] else at_user["nickname"] - msg = re.search( - r"^我.*?朋友.*?(想问问|说|让我问问|想问|让我问|想知道|让我帮他问问|让我帮他问|让我帮忙问|让我帮忙问问|问)(.*)", msg - ) - msg = msg.group(2) + user_name = at_user["card"] or at_user["nickname"] + msg = reg_group[1] if not msg: msg = "都不知道问什么" msg = msg.replace("他", "我").replace("她", "我").replace("它", "我") @@ -64,11 +61,11 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): else: ava = BuildImage(200, 100, color=(0, 0, 0)) ava.circle() - text = BuildImage(300, 30, font_size=30) + text = BuildImage(400, 30, font_size=30) text.text((0, 0), user_name) 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)) + await A.apaste(ava, (30, 25), True) + await A.apaste(text, (150, 38)) + await A.atext((150, 85), msg, (125, 125, 125)) await one_friend.send(image(b64=A.pic2bs4())) diff --git a/plugins/open_cases/__init__.py b/plugins/open_cases/__init__.py index 6639fe6e..39823ac4 100755 --- a/plugins/open_cases/__init__.py +++ b/plugins/open_cases/__init__.py @@ -1,15 +1,15 @@ from typing import Type from nonebot import on_command from nonebot.matcher import Matcher -from utils.utils import scheduler, get_message_text, is_number -from nonebot.adapters.cqhttp.permission import GROUP +from utils.utils import scheduler, is_number +from nonebot.adapters.onebot.v11.permission import GROUP from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent +from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent, Message from nonebot.permission import SUPERUSER import random from nonebot.plugin import MatcherGroup from configs.path_config import IMAGE_PATH -import re +from nonebot.params import CommandArg from .open_cases_c import ( open_case, total_open_statistics, @@ -102,8 +102,8 @@ k_open_case = cases_matcher_group.on_command("开箱") @k_open_case.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - case_name = get_message_text(event.json()) +async def _(event: GroupMessageEvent, arg: Message = CommandArg()): + case_name = arg.extract_plain_text().strip() case_name = case_name.replace("武器箱", "").strip() if case_name: result = await open_case(event.user_id, event.group_id, case_name) @@ -120,7 +120,7 @@ total_case_data = cases_matcher_group.on_command( @total_case_data.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): await total_case_data.finish( await total_open_statistics(event.user_id, event.group_id), at_sender=True, @@ -131,7 +131,7 @@ group_open_case_statistics = cases_matcher_group.on_command("群开箱统计") @group_open_case_statistics.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): await group_open_case_statistics.finish(await group_statistics(event.group_id)) @@ -139,45 +139,39 @@ my_kinfes = on_command("我的金色", priority=1, permission=GROUP, block=True) @my_kinfes.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): await my_kinfes.finish( await my_knifes_name(event.user_id, event.group_id), at_sender=True ) -open_shilian: Type[Matcher] = cases_matcher_group.on_regex(".*连开箱") +open_shilian: Type[Matcher] = cases_matcher_group.on_regex("(.*)连开箱(.*?)") @open_shilian.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - # if not _flmt.check(event.user_id): - # await k_open_case.finish('着什么急啊,慢慢来!', at_sender=True) - # _flmt.start_cd(event.user_id) - msg = get_message_text(event.json()) - rs = re.search(r"(.*)连开箱(.*)", msg) - if rs: - num = rs.group(1).strip() - if is_number(num) or num_dict.get(num): - try: - num = num_dict[num] - except KeyError: - num = int(num) - if num > 30: - await open_shilian.finish("开箱次数不要超过30啊笨蛋!", at_sender=True) - if num < 0: - await open_shilian.finish("再负开箱就扣你明天开箱数了!", at_sender=True) - else: - await open_shilian.finish("必须要是数字切不要超过30啊笨蛋!中文也可!", at_sender=True) - case_name = rs.group(2).strip() - case_name = case_name.replace("武器箱", "").strip() - if not case_name: - case_name = random.choice(cases_name) - elif case_name not in cases_name: - await open_shilian.finish("武器箱未收录!", at_sender=True) - await open_shilian.finish( - await open_shilian_case(event.user_id, event.group_id, case_name, num), - at_sender=True, - ) +async def _(event: GroupMessageEvent, state: T_State): + num = state["_matched_groups"][0].strip() + if is_number(num) or num_dict.get(num): + try: + num = num_dict[num] + except KeyError: + num = int(num) + if num > 30: + await open_shilian.finish("开箱次数不要超过30啊笨蛋!", at_sender=True) + if num < 0: + await open_shilian.finish("再负开箱就扣你明天开箱数了!", at_sender=True) + else: + await open_shilian.finish("必须要是数字切不要超过30啊笨蛋!中文也可!", at_sender=True) + case_name = state["_matched_groups"][1].strip() + case_name = case_name.replace("武器箱", "").strip() + if not case_name: + case_name = random.choice(cases_name) + elif case_name not in cases_name: + await open_shilian.finish("武器箱未收录!", at_sender=True) + await open_shilian.finish( + await open_shilian_case(event.user_id, event.group_id, case_name, num), + at_sender=True, + ) num_dict = { @@ -218,7 +212,7 @@ update_price = on_command("更新开箱价格", priority=1, permission=SUPERUSER @update_price.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _( event: MessageEvent): await update_price.send(await util_get_buff_price(str(event.get_message()))) @@ -226,7 +220,7 @@ update_img = on_command("更新开箱图片", priority=1, permission=SUPERUSER, @update_img.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent): await update_img.send(await util_get_buff_img(str(event.get_message()))) diff --git a/plugins/open_cases/open_cases_c.py b/plugins/open_cases/open_cases_c.py index 0322dc23..a5613f11 100755 --- a/plugins/open_cases/open_cases_c.py +++ b/plugins/open_cases/open_cases_c.py @@ -89,7 +89,7 @@ async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动" dbprice = await BuffPrice.ensure(skin[9 : skin.rfind("(")].strip()) if dbprice.skin_price != 0: price_result = dbprice.skin_price - print("数据库查询到价格: ", dbprice.skin_price) + logger.info("数据库查询到价格: ", dbprice.skin_price) uplist[10] = dbprice.skin_price else: price = -1 @@ -102,7 +102,7 @@ async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动" price = float(pcp[1].strip()) break if price != -1: - print("存储入数据库---->", price) + logger.info("存储入数据库---->", price) uplist[10] = price price_result = str(price) await dbprice.update( @@ -242,7 +242,7 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int = wImg = BuildImage(200, 270, 200, 200) wImg.paste( alpha2white_pil( - Image.open(IMAGE_PATH + f"cases/{case}/{skin_name}.png").resize( + Image.open(IMAGE_PATH / "cases" / case / f"{skin_name}.png").resize( (200, 200), Image.ANTIALIAS ) ), @@ -418,7 +418,7 @@ def _pst_my_knife(w, h, knifes_list): 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( + Image.open(IMAGE_PATH / f"cases" / case / f"{skin_name}.png").resize( (470, 470), Image.ANTIALIAS ) ), diff --git a/plugins/open_cases/utils.py b/plugins/open_cases/utils.py index 77313d51..7c953596 100755 --- a/plugins/open_cases/utils.py +++ b/plugins/open_cases/utils.py @@ -4,14 +4,14 @@ from datetime import datetime, timedelta from configs.path_config import IMAGE_PATH from utils.http_utils import AsyncHttpx from .models.open_cases_user import OpenCasesUser -import os from services.log import logger -from utils.utils import get_bot +from utils.utils import get_bot, cn2py from asyncio.exceptions import TimeoutError -from nonebot.adapters.cqhttp.exception import ActionFailed +from nonebot.adapters.onebot.v11.exception import ActionFailed from configs.config import Config from utils.manager import group_manager from .config import * +import os url = "https://buff.163.com/api/market/goods" # proxies = 'http://49.75.59.242:3128' @@ -20,9 +20,7 @@ url = "https://buff.163.com/api/market/goods" async def util_get_buff_price(case_name: str = "狂牙大行动") -> str: cookie = {"session": Config.get_config("open_cases", "COOKIE")} failed_list = [] - case = "" - for i in pypinyin.pinyin(case_name, style=pypinyin.NORMAL): - case += "".join(i) + case = cn2py(case_name) if case_name == "狂牙大行动": case_id = 1 elif case_name == "突围大行动": @@ -165,12 +163,9 @@ async def util_get_buff_price(case_name: str = "狂牙大行动") -> str: async def util_get_buff_img(case_name: str = "狂牙大行动") -> str: cookie = {"session": Config.get_config("open_cases", "COOKIE")} error_list = [] - case = "" - for i in pypinyin.pinyin(case_name, style=pypinyin.NORMAL): - case += "".join(i) - path = "cases/" + case + "/" - if not os.path.exists(IMAGE_PATH + path): - os.mkdir(IMAGE_PATH + path) + case = cn2py(case_name) + path = IMAGE_PATH / "cases/" / case + path.mkdir(exist_ok=True, parents=True) case = case.upper() CASE_KNIFE = eval(case + "_CASE_KNIFE") CASE_RED = eval(case + "_CASE_RED") @@ -205,11 +200,8 @@ async def util_get_buff_img(case_name: str = "狂牙大行动") -> str: for j in range(len(data)): if data[j]["name"] in [f"{skin}(★)"]: img_url = data[j]["goods_info"]["icon_url"] - for k in pypinyin.pinyin( - skin + "无涂装", style=pypinyin.NORMAL - ): - skin_name += "".join(k) - await AsyncHttpx.download_file(img_url, IMAGE_PATH + path + skin_name + ".png") + skin_name = cn2py(skin + "无涂装") + await AsyncHttpx.download_file(img_url, path / f"{skin_name}.png") flag = True break if flag: @@ -218,11 +210,8 @@ async def util_get_buff_img(case_name: str = "狂牙大行动") -> str: img_url = (await response.json())["data"]["items"][0][ "goods_info" ]["icon_url"] - for i in pypinyin.pinyin( - skin.replace("|", "-").strip(), style=pypinyin.NORMAL - ): - skin_name += "".join(i) - if await AsyncHttpx.download_file(img_url, IMAGE_PATH + path + skin_name + ".png"): + skin_name += cn2py(skin.replace("|", "-").strip()) + if await AsyncHttpx.download_file(img_url, path / f"{skin_name}.png"): logger.info(f"------->写入 {skin} 成功") else: logger.info(f"------->写入 {skin} 失败") @@ -276,11 +265,10 @@ async def update_count_daily(): gl = await bot.get_group_list() gl = [g["group_id"] for g in gl] for g in gl: - if await group_manager.check_group_task_status(g, "open_case_reset_remind"): - try: - await bot.send_group_msg(group_id=g, message="今日开箱次数重置成功") - except ActionFailed: - logger.warning(f"{g} 群被禁言,无法发送 开箱重置提醒") + try: + await bot.send_group_msg(group_id=g, message="[[_task|open_case_reset_remind]]今日开箱次数重置成功") + except ActionFailed: + logger.warning(f"{g} 群被禁言,无法发送 开箱重置提醒") logger.info("今日开箱次数重置成功") except Exception as e: logger.error(f"开箱重置错误 e:{e}") diff --git a/plugins/parse_bilibili_json.py b/plugins/parse_bilibili_json.py index 4811f63a..50a9edb7 100755 --- a/plugins/parse_bilibili_json.py +++ b/plugins/parse_bilibili_json.py @@ -1,18 +1,17 @@ from nonebot import on_message from services.log import logger -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from nonebot.typing import T_State -from utils.utils import get_message_json, get_local_proxy, get_message_text, is_number -from utils.user_agent import get_user_agent -from nonebot.adapters.cqhttp.permission import GROUP +from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message +from utils.utils import get_message_json, get_local_proxy, is_number +from nonebot.adapters.onebot.v11.permission import GROUP from bilibili_api import video from utils.message_builder import image -from nonebot.adapters.cqhttp.exception import ActionFailed +from nonebot.adapters.onebot.v11.exception import ActionFailed 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 +from nonebot.params import CommandArg import asyncio import time from bilibili_api import settings @@ -48,7 +47,7 @@ _tmp = {} @parse_bilibili_json.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent, arg: Message = CommandArg()): if await group_manager.check_group_task_status(event.group_id, "bilibili_parse"): vd_info = None url = None @@ -106,8 +105,8 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): await page.close() return # BV - if get_message_text(event.json()): - msg = get_message_text(event.json()) + if arg.extract_plain_text().strip(): + msg = arg.extract_plain_text().strip() if "BV" in msg: index = msg.find("BV") if len(msg[index + 2 :]) >= 10: @@ -123,15 +122,10 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): vd_info = await video.Video(aid=int(msg)).get_info() elif "https://b23.tv" in msg: url = "https://" + msg[msg.find("b23.tv") : msg.find("b23.tv") + 13] - async with aiohttp.ClientSession(headers=get_user_agent()) as session: - async with session.get( - url, - proxy=get_local_proxy(), - timeout=7, - ) as response: - url = str(response.url).split("?")[0] - bvid = url.split("/")[-1] - vd_info = await video.Video(bvid=bvid).get_info() + res = await AsyncHttpx.get(url, timeout=7) + url = str(res.url).split("?")[0] + bvid = url.split("/")[-1] + vd_info = await video.Video(bvid=bvid).get_info() if vd_info: if ( url in _tmp.keys() and time.time() - _tmp[url] > 30 diff --git a/plugins/pid_search.py b/plugins/pid_search.py index 251a4f53..f0a8d39d 100755 --- a/plugins/pid_search.py +++ b/plugins/pid_search.py @@ -1,14 +1,14 @@ from asyncio.exceptions import TimeoutError from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, Message, GroupMessageEvent from nonebot.typing import T_State from configs.path_config import TEMP_PATH from services.log import logger from utils.message_builder import image -from utils.utils import get_message_text, is_number +from utils.utils import is_number from utils.manager import withdraw_message_manager from utils.http_utils import AsyncHttpx -from pathlib import Path +from nonebot.params import CommandArg, Arg try: import ujson as json @@ -39,32 +39,24 @@ pid_search = on_command("p搜", aliases={"pixiv搜", "P搜"}, priority=5, block= url = "https://api.fantasyzone.cc/tu/search.php" -@pid_search.args_parser -async def _(bot: Bot, event: MessageEvent, state: T_State): - pid = get_message_text(event.json()) - if pid: - if pid in ["取消", "算了"]: - await pid_search.finish("已取消操作...") - if not is_number(pid): - await pid_search.reject("笨蛋,重新输入数!字!", at_sender=True) - state["pid"] = pid - - @pid_search.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - pid = get_message_text(event.json()) +async def _(state: T_State, arg: Message = CommandArg()): + pid = arg.extract_plain_text().strip() if pid: state["pid"] = pid @pid_search.got("pid", prompt="需要查询的图片PID是?") -async def _(bot: Bot, event: MessageEvent, state: T_State): - pid = state["pid"] +async def _(event: MessageEvent, state: T_State, pid: str = Arg("pid")): + if pid in ["取消", "算了"]: + await pid_search.finish("已取消操作...") + if is_number(pid): + await pid_search.reject_arg("pid", "笨蛋,重新输入数!字!") params = { "id": pid, "p": 1, } - for _ in range(10): + for _ in range(3): try: data = (await AsyncHttpx.get(url, params=params, timeout=5)).json() except TimeoutError: @@ -80,7 +72,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): author_id = data["userId"] img_url = data["url"] if not await AsyncHttpx.download_file( - img_url, Path(TEMP_PATH) / f"pid_search_{event.user_id}.png" + img_url, TEMP_PATH / f"pid_search_{event.user_id}.png" ): await pid_search.finish("图片下载失败了....", at_sender=True) tmp = "" diff --git a/plugins/pix_gallery/__init__.py b/plugins/pix_gallery/__init__.py index a846c5f0..6f7b379a 100755 --- a/plugins/pix_gallery/__init__.py +++ b/plugins/pix_gallery/__init__.py @@ -2,11 +2,6 @@ from configs.config import Config import nonebot -__zx_plugin_name__ = "更新扩展图库Omega [Hidden]" -__plugin_version__ = 0.1 -__plugin_author__ = "HibiKier" - - Config.add_plugin_config( "hibiapi", "HIBIAPI", diff --git a/plugins/pix_gallery/data_source.py b/plugins/pix_gallery/_data_source.py old mode 100755 new mode 100644 similarity index 96% rename from plugins/pix_gallery/data_source.py rename to plugins/pix_gallery/_data_source.py index 8cccbf22..05a803f3 --- a/plugins/pix_gallery/data_source.py +++ b/plugins/pix_gallery/_data_source.py @@ -1,396 +1,396 @@ -from asyncpg.exceptions import UniqueViolationError -from .model.omega_pixiv_illusts import OmegaPixivIllusts -from asyncio.locks import Semaphore -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 BuildImage -from utils.http_utils import AsyncHttpx -from services.log import logger -from configs.config import Config -from configs.path_config import TEMP_PATH -import aiofiles -import platform -import asyncio -import math - -try: - import ujson as json -except ModuleNotFoundError: - import json - -if str(platform.system()).lower() == "windows": - policy = asyncio.WindowsSelectorEventLoopPolicy() - asyncio.set_event_loop_policy(policy) - -headers = { - "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;" - " rv:2.0.1) Gecko/20100101 Firefox/4.0.1", - "Referer": "https://www.pixiv.net", -} - -HIBIAPI = Config.get_config("hibiapi", "HIBIAPI") -if not HIBIAPI: - HIBIAPI = "https://api.obfs.dev" -HIBIAPI = HIBIAPI[:-1] if HIBIAPI[-1] == "/" else HIBIAPI - - -async def start_update_image_url( - current_keyword: List[str], black_pid: List[str] -) -> "int, int": - """ - 开始更新图片url - :param current_keyword: 关键词 - :param black_pid: 黑名单pid - :return: pid数量和图片数量 - """ - global HIBIAPI - pid_count = 0 - pic_count = 0 - tasks = [] - semaphore = asyncio.Semaphore(10) - for keyword in current_keyword: - for page in range(1, 110): - if keyword.startswith("uid:"): - url = f"{HIBIAPI}/api/pixiv/member_illust" - params = {"id": keyword[4:], "page": page} - if page == 30: - break - elif keyword.startswith("pid:"): - url = f"{HIBIAPI}/api/pixiv/illust" - params = {"id": keyword[4:]} - else: - url = f"{HIBIAPI}/api/pixiv/search" - params = {"word": keyword, "page": page} - tasks.append( - asyncio.ensure_future( - search_image( - url, keyword, params, semaphore, page, black_pid - ) - ) - ) - if keyword.startswith("pid:"): - break - result = await asyncio.gather(*tasks) - for x in result: - pid_count += x[0] - pic_count += x[1] - return pid_count, pic_count - - -async def search_image( - url: str, - keyword: str, - params: dict, - semaphore: Semaphore, - page: int = 1, - black: List[str] = None, -) -> "int, int": - """ - 搜索图片 - :param url: 搜索url - :param keyword: 关键词 - :param params: params参数 - :param semaphore: semaphore - :param page: 页面 - :param black: pid黑名单 - :return: pid数量和图片数量 - """ - tmp_pid = [] - pic_count = 0 - pid_count = 0 - async with semaphore: - try: - data = (await AsyncHttpx.get(url, params=params)).json() - if ( - not data - or data.get("error") - or (not data.get("illusts") and not data.get("illust")) - ): - return 0, 0 - if url != f"{HIBIAPI}/api/pixiv/illust": - logger.info(f'{keyword}: 获取数据成功...数据总量:{len(data["illusts"])}') - data = data["illusts"] - else: - logger.info(f'获取数据成功...PID:{params.get("id")}') - data = [data["illust"]] - img_data = {} - for x in data: - pid = x["id"] - title = x["title"] - width = x["width"] - height = x["height"] - view = x["total_view"] - bookmarks = x["total_bookmarks"] - uid = x["user"]["id"] - author = x["user"]["name"] - tags = [] - for tag in x["tags"]: - for i in tag: - if tag[i]: - tags.append(tag[i]) - img_urls = [] - if x["page_count"] == 1: - img_urls.append(x["meta_single_page"]["original_image_url"]) - else: - for urls in x["meta_pages"]: - img_urls.append(urls["image_urls"]["original"]) - if ( - ( - bookmarks - >= Config.get_config("pix", "SEARCH_HIBIAPI_BOOKMARKS") - or ( - url == f"{HIBIAPI}/api/pixiv/member_illust" - and bookmarks >= 1500 - ) - or (url == f"{HIBIAPI}/api/pixiv/illust") - ) - and len(img_urls) < 10 - and _check_black(img_urls, black) - ): - img_data[pid] = { - "pid": pid, - "title": title, - "width": width, - "height": height, - "view": view, - "bookmarks": bookmarks, - "img_urls": img_urls, - "uid": uid, - "author": author, - "tags": tags, - } - else: - continue - for x in img_data.keys(): - data = img_data[x] - for img_url in data["img_urls"]: - img_p = img_url[img_url.rfind("_") + 1 : img_url.rfind(".")] - try: - if await Pixiv.add_image_data( - data["pid"], - data["title"], - data["width"], - data["height"], - data["view"], - data["bookmarks"], - img_url, - img_p, - data["uid"], - data["author"], - ",".join(data["tags"]), - ): - if data["pid"] not in tmp_pid: - pid_count += 1 - tmp_pid.append(data["pid"]) - pic_count += 1 - logger.info(f'存储图片PID:{data["pid"]} IMG_P:{img_p}') - except UniqueViolationError: - logger.warning(f'{data["pid"]} | {img_url} 已存在...') - except Exception as e: - logger.warning(f"PIX在线搜索图片错误,已再次调用 {type(e)}:{e}") - await search_image(url, keyword, params, semaphore, page, black) - return pid_count, pic_count - - -async def get_image(img_url: str, user_id: int) -> Optional[str]: - """ - 下载图片 - :param img_url: - :param user_id: - :return: 图片名称 - """ - if "https://www.pixiv.net/artworks" in img_url: - pid = img_url.rsplit("/", maxsplit=1)[-1] - params = {"id": pid} - for _ in range(3): - try: - response = await AsyncHttpx.get(f"{HIBIAPI}/api/pixiv/illust", params=params) - if response.status_code == 200: - data = response.json() - if data.get("illust"): - if data["illust"]["page_count"] == 1: - img_url = data["illust"]["meta_single_page"][ - "original_image_url" - ] - else: - img_url = data["illust"]["meta_pages"][0][ - "image_urls" - ]["original"] - break - except TimeoutError: - pass - old_img_url = img_url - img_url = change_pixiv_image_links( - img_url, Config.get_config("pix", "PIX_IMAGE_SIZE"), Config.get_config("pixiv", "PIXIV_NGINX_URL") - ) - old_img_url = change_pixiv_image_links( - old_img_url, None, Config.get_config("pixiv", "PIXIV_NGINX_URL") - ) - for _ in range(3): - try: - response = await AsyncHttpx.get(img_url, headers=headers, timeout=Config.get_config("pix", "TIMEOUT"),) - if response.status_code == 404: - img_url = old_img_url - continue - async with aiofiles.open( - f"{TEMP_PATH}/pix_{user_id}_{img_url[-10:-4]}.jpg", "wb" - ) as f: - await f.write(response.content) - return f"pix_{user_id}_{img_url[-10:-4]}.jpg" - except TimeoutError: - logger.warning(f"PIX:{img_url} 图片下载超时...") - pass - return None - - -async def uid_pid_exists(id_: str) -> bool: - """ - 检测 pid/uid 是否有效 - :param id_: pid/uid - """ - if id_.startswith("uid:"): - url = f"{HIBIAPI}/api/pixiv/member" - elif id_.startswith("pid:"): - url = f"{HIBIAPI}/api/pixiv/illust" - else: - return False - params = {"id": int(id_[4:])} - data = (await AsyncHttpx.get(url, params=params)).json() - if data.get("error"): - return False - return True - - -async def get_keyword_num(keyword: str) -> "int, int, int, int, int": - """ - 查看图片相关 tag 数量 - :param keyword: 关键词tag - """ - count, r18_count = await Pixiv.get_keyword_num(keyword.split()) - count_, setu_count, r18_count_ = await OmegaPixivIllusts.get_keyword_num( - keyword.split() - ) - return count, r18_count, count_, setu_count, r18_count_ - - -async def remove_image(pid: int, img_p: str) -> bool: - """ - 删除置顶图片 - :param pid: pid - :param img_p: 图片 p 如 p0,p1 等 - """ - if img_p: - if "p" not in img_p: - img_p = f"p{img_p}" - return await Pixiv.remove_image_data(pid, img_p) - - -def gen_keyword_pic( - _pass_keyword: List[str], not_pass_keyword: List[str], is_superuser: bool -): - """ - 已通过或未通过的所有关键词/uid/pid - :param _pass_keyword: 通过列表 - :param not_pass_keyword: 未通过列表 - :param is_superuser: 是否超级用户 - """ - _keyword = [ - x - for x in _pass_keyword - if not x.startswith("uid:") - and not x.startswith("pid:") - and not x.startswith("black:") - ] - _uid = [x for x in _pass_keyword if x.startswith("uid:")] - _pid = [x for x in _pass_keyword if x.startswith("pid:")] - _n_keyword = [ - x - for x in not_pass_keyword - if not x.startswith("uid:") - and not x.startswith("pid:") - and not x.startswith("black:") - ] - _n_uid = [ - x - for x in not_pass_keyword - if x.startswith("uid:") and not x.startswith("black:") - ] - _n_pid = [ - x - for x in not_pass_keyword - if x.startswith("pid:") and not x.startswith("black:") - ] - img_width = 0 - img_data = { - "_keyword": {"width": 0, "data": _keyword}, - "_uid": {"width": 0, "data": _uid}, - "_pid": {"width": 0, "data": _pid}, - "_n_keyword": {"width": 0, "data": _n_keyword}, - "_n_uid": {"width": 0, "data": _n_uid}, - "_n_pid": {"width": 0, "data": _n_pid}, - } - for x in list(img_data.keys()): - img_data[x]["width"] = math.ceil(len(img_data[x]["data"]) / 40) - img_width += img_data[x]["width"] * 200 - if not is_superuser: - img_width = ( - img_width - - ( - img_data["_n_keyword"]["width"] - + img_data["_n_uid"]["width"] - + img_data["_n_pid"]["width"] - ) - * 200 - ) - del img_data["_n_keyword"] - del img_data["_n_pid"] - del img_data["_n_uid"] - current_width = 0 - A = BuildImage(img_width, 1100) - for x in list(img_data.keys()): - if img_data[x]["data"]: - 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 = 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]] - ) - tmp.text((10, 100), key_str) - if x.find("_n") == -1: - text_img.text((24, 24), "已收录") - else: - text_img.text((24, 24), "待收录") - tmp.paste(text_img, (0, 0)) - start_index += 40 - end_index = ( - end_index + 40 if end_index + 40 <= total_index else total_index - ) - background_img = BuildImage(200, 1100, color="#FFE4C4") - background_img.paste(tmp, (1, 1)) - img.paste(background_img) - A.paste(img, (current_width, 0)) - current_width += img_data[x]["width"] * 200 - return A.pic2bs4() - - -def _check_black(img_urls: List[str], black: List[str]) -> bool: - """ - 检测pid是否在黑名单中 - :param img_urls: 图片img列表 - :param black: 黑名单 - :return: - """ - for b in black: - for img_url in img_urls: - if b in img_url: - return False - return True - - - +from asyncpg.exceptions import UniqueViolationError +from ._model.omega_pixiv_illusts import OmegaPixivIllusts +from asyncio.locks import Semaphore +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 BuildImage +from utils.http_utils import AsyncHttpx +from services.log import logger +from configs.config import Config +from configs.path_config import TEMP_PATH +import aiofiles +import platform +import asyncio +import math + +try: + import ujson as json +except ModuleNotFoundError: + import json + +if str(platform.system()).lower() == "windows": + policy = asyncio.WindowsSelectorEventLoopPolicy() + asyncio.set_event_loop_policy(policy) + +headers = { + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;" + " rv:2.0.1) Gecko/20100101 Firefox/4.0.1", + "Referer": "https://www.pixiv.net", +} + +HIBIAPI = Config.get_config("hibiapi", "HIBIAPI") +if not HIBIAPI: + HIBIAPI = "https://api.obfs.dev" +HIBIAPI = HIBIAPI[:-1] if HIBIAPI[-1] == "/" else HIBIAPI + + +async def start_update_image_url( + current_keyword: List[str], black_pid: List[str] +) -> "int, int": + """ + 开始更新图片url + :param current_keyword: 关键词 + :param black_pid: 黑名单pid + :return: pid数量和图片数量 + """ + global HIBIAPI + pid_count = 0 + pic_count = 0 + tasks = [] + semaphore = asyncio.Semaphore(10) + for keyword in current_keyword: + for page in range(1, 110): + if keyword.startswith("uid:"): + url = f"{HIBIAPI}/api/pixiv/member_illust" + params = {"id": keyword[4:], "page": page} + if page == 30: + break + elif keyword.startswith("pid:"): + url = f"{HIBIAPI}/api/pixiv/illust" + params = {"id": keyword[4:]} + else: + url = f"{HIBIAPI}/api/pixiv/search" + params = {"word": keyword, "page": page} + tasks.append( + asyncio.ensure_future( + search_image( + url, keyword, params, semaphore, page, black_pid + ) + ) + ) + if keyword.startswith("pid:"): + break + result = await asyncio.gather(*tasks) + for x in result: + pid_count += x[0] + pic_count += x[1] + return pid_count, pic_count + + +async def search_image( + url: str, + keyword: str, + params: dict, + semaphore: Semaphore, + page: int = 1, + black: List[str] = None, +) -> "int, int": + """ + 搜索图片 + :param url: 搜索url + :param keyword: 关键词 + :param params: params参数 + :param semaphore: semaphore + :param page: 页面 + :param black: pid黑名单 + :return: pid数量和图片数量 + """ + tmp_pid = [] + pic_count = 0 + pid_count = 0 + async with semaphore: + try: + data = (await AsyncHttpx.get(url, params=params)).json() + if ( + not data + or data.get("error") + or (not data.get("illusts") and not data.get("illust")) + ): + return 0, 0 + if url != f"{HIBIAPI}/api/pixiv/illust": + logger.info(f'{keyword}: 获取数据成功...数据总量:{len(data["illusts"])}') + data = data["illusts"] + else: + logger.info(f'获取数据成功...PID:{params.get("id")}') + data = [data["illust"]] + img_data = {} + for x in data: + pid = x["id"] + title = x["title"] + width = x["width"] + height = x["height"] + view = x["total_view"] + bookmarks = x["total_bookmarks"] + uid = x["user"]["id"] + author = x["user"]["name"] + tags = [] + for tag in x["tags"]: + for i in tag: + if tag[i]: + tags.append(tag[i]) + img_urls = [] + if x["page_count"] == 1: + img_urls.append(x["meta_single_page"]["original_image_url"]) + else: + for urls in x["meta_pages"]: + img_urls.append(urls["image_urls"]["original"]) + if ( + ( + bookmarks + >= Config.get_config("pix", "SEARCH_HIBIAPI_BOOKMARKS") + or ( + url == f"{HIBIAPI}/api/pixiv/member_illust" + and bookmarks >= 1500 + ) + or (url == f"{HIBIAPI}/api/pixiv/illust") + ) + and len(img_urls) < 10 + and _check_black(img_urls, black) + ): + img_data[pid] = { + "pid": pid, + "title": title, + "width": width, + "height": height, + "view": view, + "bookmarks": bookmarks, + "img_urls": img_urls, + "uid": uid, + "author": author, + "tags": tags, + } + else: + continue + for x in img_data.keys(): + data = img_data[x] + for img_url in data["img_urls"]: + img_p = img_url[img_url.rfind("_") + 1 : img_url.rfind(".")] + try: + if await Pixiv.add_image_data( + data["pid"], + data["title"], + data["width"], + data["height"], + data["view"], + data["bookmarks"], + img_url, + img_p, + data["uid"], + data["author"], + ",".join(data["tags"]), + ): + if data["pid"] not in tmp_pid: + pid_count += 1 + tmp_pid.append(data["pid"]) + pic_count += 1 + logger.info(f'存储图片PID:{data["pid"]} IMG_P:{img_p}') + except UniqueViolationError: + logger.warning(f'{data["pid"]} | {img_url} 已存在...') + except Exception as e: + logger.warning(f"PIX在线搜索图片错误,已再次调用 {type(e)}:{e}") + await search_image(url, keyword, params, semaphore, page, black) + return pid_count, pic_count + + +async def get_image(img_url: str, user_id: int) -> Optional[str]: + """ + 下载图片 + :param img_url: + :param user_id: + :return: 图片名称 + """ + if "https://www.pixiv.net/artworks" in img_url: + pid = img_url.rsplit("/", maxsplit=1)[-1] + params = {"id": pid} + for _ in range(3): + try: + response = await AsyncHttpx.get(f"{HIBIAPI}/api/pixiv/illust", params=params) + if response.status_code == 200: + data = response.json() + if data.get("illust"): + if data["illust"]["page_count"] == 1: + img_url = data["illust"]["meta_single_page"][ + "original_image_url" + ] + else: + img_url = data["illust"]["meta_pages"][0][ + "image_urls" + ]["original"] + break + except TimeoutError: + pass + old_img_url = img_url + img_url = change_pixiv_image_links( + img_url, Config.get_config("pix", "PIX_IMAGE_SIZE"), Config.get_config("pixiv", "PIXIV_NGINX_URL") + ) + old_img_url = change_pixiv_image_links( + old_img_url, None, Config.get_config("pixiv", "PIXIV_NGINX_URL") + ) + for _ in range(3): + try: + response = await AsyncHttpx.get(img_url, headers=headers, timeout=Config.get_config("pix", "TIMEOUT"),) + if response.status_code == 404: + img_url = old_img_url + continue + async with aiofiles.open( + TEMP_PATH / f"pix_{user_id}_{img_url[-10:-4]}.jpg", "wb" + ) as f: + await f.write(response.content) + return f"pix_{user_id}_{img_url[-10:-4]}.jpg" + except TimeoutError: + logger.warning(f"PIX:{img_url} 图片下载超时...") + pass + return None + + +async def uid_pid_exists(id_: str) -> bool: + """ + 检测 pid/uid 是否有效 + :param id_: pid/uid + """ + if id_.startswith("uid:"): + url = f"{HIBIAPI}/api/pixiv/member" + elif id_.startswith("pid:"): + url = f"{HIBIAPI}/api/pixiv/illust" + else: + return False + params = {"id": int(id_[4:])} + data = (await AsyncHttpx.get(url, params=params)).json() + if data.get("error"): + return False + return True + + +async def get_keyword_num(keyword: str) -> "int, int, int, int, int": + """ + 查看图片相关 tag 数量 + :param keyword: 关键词tag + """ + count, r18_count = await Pixiv.get_keyword_num(keyword.split()) + count_, setu_count, r18_count_ = await OmegaPixivIllusts.get_keyword_num( + keyword.split() + ) + return count, r18_count, count_, setu_count, r18_count_ + + +async def remove_image(pid: int, img_p: str) -> bool: + """ + 删除置顶图片 + :param pid: pid + :param img_p: 图片 p 如 p0,p1 等 + """ + if img_p: + if "p" not in img_p: + img_p = f"p{img_p}" + return await Pixiv.remove_image_data(pid, img_p) + + +def gen_keyword_pic( + _pass_keyword: List[str], not_pass_keyword: List[str], is_superuser: bool +): + """ + 已通过或未通过的所有关键词/uid/pid + :param _pass_keyword: 通过列表 + :param not_pass_keyword: 未通过列表 + :param is_superuser: 是否超级用户 + """ + _keyword = [ + x + for x in _pass_keyword + if not x.startswith("uid:") + and not x.startswith("pid:") + and not x.startswith("black:") + ] + _uid = [x for x in _pass_keyword if x.startswith("uid:")] + _pid = [x for x in _pass_keyword if x.startswith("pid:")] + _n_keyword = [ + x + for x in not_pass_keyword + if not x.startswith("uid:") + and not x.startswith("pid:") + and not x.startswith("black:") + ] + _n_uid = [ + x + for x in not_pass_keyword + if x.startswith("uid:") and not x.startswith("black:") + ] + _n_pid = [ + x + for x in not_pass_keyword + if x.startswith("pid:") and not x.startswith("black:") + ] + img_width = 0 + img_data = { + "_keyword": {"width": 0, "data": _keyword}, + "_uid": {"width": 0, "data": _uid}, + "_pid": {"width": 0, "data": _pid}, + "_n_keyword": {"width": 0, "data": _n_keyword}, + "_n_uid": {"width": 0, "data": _n_uid}, + "_n_pid": {"width": 0, "data": _n_pid}, + } + for x in list(img_data.keys()): + img_data[x]["width"] = math.ceil(len(img_data[x]["data"]) / 40) + img_width += img_data[x]["width"] * 200 + if not is_superuser: + img_width = ( + img_width + - ( + img_data["_n_keyword"]["width"] + + img_data["_n_uid"]["width"] + + img_data["_n_pid"]["width"] + ) + * 200 + ) + del img_data["_n_keyword"] + del img_data["_n_pid"] + del img_data["_n_uid"] + current_width = 0 + A = BuildImage(img_width, 1100) + for x in list(img_data.keys()): + if img_data[x]["data"]: + 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 = 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]] + ) + tmp.text((10, 100), key_str) + if x.find("_n") == -1: + text_img.text((24, 24), "已收录") + else: + text_img.text((24, 24), "待收录") + tmp.paste(text_img, (0, 0)) + start_index += 40 + end_index = ( + end_index + 40 if end_index + 40 <= total_index else total_index + ) + background_img = BuildImage(200, 1100, color="#FFE4C4") + background_img.paste(tmp, (1, 1)) + img.paste(background_img) + A.paste(img, (current_width, 0)) + current_width += img_data[x]["width"] * 200 + return A.pic2bs4() + + +def _check_black(img_urls: List[str], black: List[str]) -> bool: + """ + 检测pid是否在黑名单中 + :param img_urls: 图片img列表 + :param black: 黑名单 + :return: + """ + for b in black: + for img_url in img_urls: + if b in img_url: + return False + return True + + + diff --git a/plugins/pix_gallery/model/__init__.py b/plugins/pix_gallery/_model/__init__.py old mode 100755 new mode 100644 similarity index 50% rename from plugins/pix_gallery/model/__init__.py rename to plugins/pix_gallery/_model/__init__.py index d3f5a12f..8b137891 --- a/plugins/pix_gallery/model/__init__.py +++ b/plugins/pix_gallery/_model/__init__.py @@ -1 +1 @@ - + diff --git a/plugins/pix_gallery/model/omega_pixiv_illusts.py b/plugins/pix_gallery/_model/omega_pixiv_illusts.py old mode 100755 new mode 100644 similarity index 96% rename from plugins/pix_gallery/model/omega_pixiv_illusts.py rename to plugins/pix_gallery/_model/omega_pixiv_illusts.py index b9198e68..43b0687d --- a/plugins/pix_gallery/model/omega_pixiv_illusts.py +++ b/plugins/pix_gallery/_model/omega_pixiv_illusts.py @@ -1,153 +1,153 @@ -from typing import Optional, List -from datetime import datetime -from services.db_context import db - - -class OmegaPixivIllusts(db.Model): - __tablename__ = "omega_pixiv_illusts" - __table_args__ = {'extend_existing': True} - - id = db.Column(db.Integer(), primary_key=True) - pid = db.Column(db.BigInteger(), nullable=False) - uid = db.Column(db.BigInteger(), nullable=False) - title = db.Column(db.String(), nullable=False) - uname = db.Column(db.String(), nullable=False) - nsfw_tag = db.Column(db.Integer(), nullable=False) - width = db.Column(db.Integer(), nullable=False) - height = db.Column(db.Integer(), nullable=False) - tags = db.Column(db.String(), nullable=False) - url = db.Column(db.String(), nullable=False) - created_at = db.Column(db.DateTime(timezone=True)) - updated_at = db.Column(db.DateTime(timezone=True)) - - _idx1 = db.Index("omega_pixiv_illusts_idx1", "pid", "url", unique=True) - - @classmethod - async def add_image_data( - cls, - pid: int, - title: str, - width: int, - height: int, - url: str, - uid: int, - uname: str, - nsfw_tag: int, - tags: str, - created_at: datetime, - updated_at: datetime, - ): - """ - 说明: - 添加图片信息 - 参数: - :param pid: pid - :param title: 标题 - :param width: 宽度 - :param height: 长度 - :param url: url链接 - :param uid: 作者uid - :param uname: 作者名称 - :param nsfw_tag: nsfw标签, 0=safe, 1=setu. 2=r18 - :param tags: 相关tag - :param created_at: 创建日期 - :param updated_at: 更新日期 - """ - if not await cls.check_exists(pid): - await cls.create( - pid=pid, - title=title, - width=width, - height=height, - url=url, - uid=uid, - uname=uname, - nsfw_tag=nsfw_tag, - tags=tags, - ) - return True - return False - - @classmethod - async def query_images( - cls, - keywords: Optional[List[str]] = None, - uid: Optional[int] = None, - pid: Optional[int] = None, - nsfw_tag: Optional[int] = 0, - num: int = 100 - ) -> List[Optional["OmegaPixivIllusts"]]: - """ - 说明: - 查找符合条件的图片 - 参数: - :param keywords: 关键词 - :param uid: 画师uid - :param pid: 图片pid - :param nsfw_tag: nsfw标签, 0=safe, 1=setu. 2=r18 - :param num: 获取图片数量 - """ - if nsfw_tag is not None: - query = cls.query.where(cls.nsfw_tag == nsfw_tag) - else: - query = cls.query - if keywords: - for keyword in keywords: - query = query.where(cls.tags.contains(keyword)) - elif uid: - query = query.where(cls.uid == uid) - elif pid: - query = query.where(cls.uid == pid) - query = query.order_by(db.func.random()).limit(num) - return await query.gino.all() - - @classmethod - async def check_exists(cls, pid: int) -> bool: - """ - 说明: - 检测pid是否已存在 - 参数: - :param pid: 图片PID - """ - query = await cls.query.where(cls.pid == pid).gino.all() - return bool(query) - - @classmethod - async def get_keyword_num(cls, tags: List[str] = None) -> "int, int, int": - """ - 说明: - 获取相关关键词(keyword, tag)在图库中的数量 - 参数: - :param tags: 关键词/Tag - """ - setattr(OmegaPixivIllusts, 'count', db.func.count(cls.pid).label('count')) - query = cls.select('count') - if tags: - for tag in tags: - query = query.where(cls.tags.contains(tag)) - count = await query.where(cls.nsfw_tag == 0).gino.first() - setu_count = await query.where(cls.nsfw_tag == 1).gino.first() - r18_count = await query.where(cls.nsfw_tag == 2).gino.first() - return count[0], setu_count[0], r18_count[0] - - @classmethod - async def get_all_pid(cls) -> List[int]: - """ - 说明: - 获取所有图片PID - """ - data = await cls.select('pid').gino.all() - return [x[0] for x in data] - - @classmethod - async def test(cls, nsfw_tag: int = 1): - if nsfw_tag is not None: - query = cls.query.where(cls.nsfw_tag == nsfw_tag) - else: - query = cls.query - query = query.where((cls.width - cls.height) < 50) - for x in await query.gino.all(): - print(x.pid) - - - +from typing import Optional, List +from datetime import datetime +from services.db_context import db + + +class OmegaPixivIllusts(db.Model): + __tablename__ = "omega_pixiv_illusts" + __table_args__ = {'extend_existing': True} + + id = db.Column(db.Integer(), primary_key=True) + pid = db.Column(db.BigInteger(), nullable=False) + uid = db.Column(db.BigInteger(), nullable=False) + title = db.Column(db.String(), nullable=False) + uname = db.Column(db.String(), nullable=False) + nsfw_tag = db.Column(db.Integer(), nullable=False) + width = db.Column(db.Integer(), nullable=False) + height = db.Column(db.Integer(), nullable=False) + tags = db.Column(db.String(), nullable=False) + url = db.Column(db.String(), nullable=False) + created_at = db.Column(db.DateTime(timezone=True)) + updated_at = db.Column(db.DateTime(timezone=True)) + + _idx1 = db.Index("omega_pixiv_illusts_idx1", "pid", "url", unique=True) + + @classmethod + async def add_image_data( + cls, + pid: int, + title: str, + width: int, + height: int, + url: str, + uid: int, + uname: str, + nsfw_tag: int, + tags: str, + created_at: datetime, + updated_at: datetime, + ): + """ + 说明: + 添加图片信息 + 参数: + :param pid: pid + :param title: 标题 + :param width: 宽度 + :param height: 长度 + :param url: url链接 + :param uid: 作者uid + :param uname: 作者名称 + :param nsfw_tag: nsfw标签, 0=safe, 1=setu. 2=r18 + :param tags: 相关tag + :param created_at: 创建日期 + :param updated_at: 更新日期 + """ + if not await cls.check_exists(pid): + await cls.create( + pid=pid, + title=title, + width=width, + height=height, + url=url, + uid=uid, + uname=uname, + nsfw_tag=nsfw_tag, + tags=tags, + ) + return True + return False + + @classmethod + async def query_images( + cls, + keywords: Optional[List[str]] = None, + uid: Optional[int] = None, + pid: Optional[int] = None, + nsfw_tag: Optional[int] = 0, + num: int = 100 + ) -> List[Optional["OmegaPixivIllusts"]]: + """ + 说明: + 查找符合条件的图片 + 参数: + :param keywords: 关键词 + :param uid: 画师uid + :param pid: 图片pid + :param nsfw_tag: nsfw标签, 0=safe, 1=setu. 2=r18 + :param num: 获取图片数量 + """ + if nsfw_tag is not None: + query = cls.query.where(cls.nsfw_tag == nsfw_tag) + else: + query = cls.query + if keywords: + for keyword in keywords: + query = query.where(cls.tags.contains(keyword)) + elif uid: + query = query.where(cls.uid == uid) + elif pid: + query = query.where(cls.uid == pid) + query = query.order_by(db.func.random()).limit(num) + return await query.gino.all() + + @classmethod + async def check_exists(cls, pid: int) -> bool: + """ + 说明: + 检测pid是否已存在 + 参数: + :param pid: 图片PID + """ + query = await cls.query.where(cls.pid == pid).gino.all() + return bool(query) + + @classmethod + async def get_keyword_num(cls, tags: List[str] = None) -> "int, int, int": + """ + 说明: + 获取相关关键词(keyword, tag)在图库中的数量 + 参数: + :param tags: 关键词/Tag + """ + setattr(OmegaPixivIllusts, 'count', db.func.count(cls.pid).label('count')) + query = cls.select('count') + if tags: + for tag in tags: + query = query.where(cls.tags.contains(tag)) + count = await query.where(cls.nsfw_tag == 0).gino.first() + setu_count = await query.where(cls.nsfw_tag == 1).gino.first() + r18_count = await query.where(cls.nsfw_tag == 2).gino.first() + return count[0], setu_count[0], r18_count[0] + + @classmethod + async def get_all_pid(cls) -> List[int]: + """ + 说明: + 获取所有图片PID + """ + data = await cls.select('pid').gino.all() + return [x[0] for x in data] + + @classmethod + async def test(cls, nsfw_tag: int = 1): + if nsfw_tag is not None: + query = cls.query.where(cls.nsfw_tag == nsfw_tag) + else: + query = cls.query + query = query.where((cls.width - cls.height) < 50) + for x in await query.gino.all(): + print(x.pid) + + + diff --git a/plugins/pix_gallery/model/pixiv.py b/plugins/pix_gallery/_model/pixiv.py old mode 100755 new mode 100644 similarity index 96% rename from plugins/pix_gallery/model/pixiv.py rename to plugins/pix_gallery/_model/pixiv.py index e43b9c35..15275d3e --- a/plugins/pix_gallery/model/pixiv.py +++ b/plugins/pix_gallery/_model/pixiv.py @@ -1,170 +1,170 @@ -from typing import Optional, List -from services.db_context import db - - -class Pixiv(db.Model): - __tablename__ = "pixiv" - __table_args__ = {'extend_existing': True} - - id = db.Column(db.Integer(), primary_key=True) - pid = db.Column(db.BigInteger(), nullable=False) - title = db.Column(db.String(), nullable=False) - width = db.Column(db.Integer(), nullable=False) - height = db.Column(db.Integer(), nullable=False) - view = db.Column(db.Integer(), nullable=False) - bookmarks = db.Column(db.Integer(), nullable=False) - img_url = db.Column(db.String(), nullable=False) - img_p = db.Column(db.String(), nullable=False) - uid = db.Column(db.BigInteger(), nullable=False) - author = db.Column(db.String(), nullable=False) - is_r18 = db.Column(db.Boolean(), nullable=False) - tags = db.Column(db.String(), nullable=False) - - _idx1 = db.Index("pixiv_idx1", "pid", "img_url", unique=True) - - @classmethod - async def add_image_data( - cls, - pid: int, - title: str, - width: int, - height: int, - view: int, - bookmarks: int, - img_url: str, - img_p: str, - uid: int, - author: str, - tags: str, - ): - """ - 说明: - 添加图片信息 - 参数: - :param pid: pid - :param title: 标题 - :param width: 宽度 - :param height: 长度 - :param view: 被查看次数 - :param bookmarks: 收藏数 - :param img_url: url链接 - :param img_p: 张数 - :param uid: 作者uid - :param author: 作者名称 - :param tags: 相关tag - """ - if not await cls.check_exists(pid, img_p): - await cls.create( - pid=pid, - title=title, - width=width, - height=height, - view=view, - bookmarks=bookmarks, - img_url=img_url, - img_p=img_p, - uid=uid, - author=author, - is_r18=True if "R-18" in tags else False, - tags=tags, - ) - return True - return False - - @classmethod - async def remove_image_data(cls, pid: int, img_p: str) -> bool: - """ - 说明: - 删除图片数据 - 参数: - :param pid: 图片pid - :param img_p: 图片pid的张数,如:p0,p1 - """ - try: - if img_p: - await cls.delete.where( - (cls.pid == pid) & (cls.img_p == img_p) - ).gino.status() - else: - await cls.delete.where(cls.pid == pid).gino.status() - return True - except Exception: - return False - - @classmethod - async def get_all_pid(cls) -> List[int]: - """ - 说明: - 获取所有PID - """ - query = await cls.query.select("pid").gino.first() - pid = [x[0] for x in query] - return list(set(pid)) - - # 0:非r18 1:r18 2:混合 - @classmethod - async def query_images( - cls, - keywords: Optional[List[str]] = None, - uid: Optional[int] = None, - pid: Optional[int] = None, - r18: Optional[int] = 0, - num: int = 100 - ) -> List[Optional["Pixiv"]]: - """ - 说明: - 查找符合条件的图片 - 参数: - :param keywords: 关键词 - :param uid: 画师uid - :param pid: 图片pid - :param r18: 是否r18,0:非r18 1:r18 2:混合 - :param num: 查找图片的数量 - """ - if r18 == 0: - query = cls.query.where(cls.is_r18 == False) - elif r18 == 1: - query = cls.query.where(cls.is_r18 == True) - else: - query = cls.query - if keywords: - for keyword in keywords: - query = query.where(cls.tags.contains(keyword)) - elif uid: - query = query.where(cls.uid == uid) - elif pid: - query = query.where(cls.pid == pid) - query = query.order_by(db.func.random()).limit(num) - return await query.gino.all() - - @classmethod - async def check_exists(cls, pid: int, img_p: str) -> bool: - """ - 说明: - 检测pid是否已存在 - 参数: - :param pid: 图片PID - :param img_p: 张数 - """ - query = await cls.query.where( - (cls.pid == pid) & (cls.img_p == img_p) - ).gino.all() - return bool(query) - - @classmethod - async def get_keyword_num(cls, tags: List[str] = None) -> "int, int": - """ - 说明: - 获取相关关键词(keyword, tag)在图库中的数量 - 参数: - :param tags: 关键词/Tag - """ - setattr(Pixiv, 'count', db.func.count(cls.pid).label('count')) - query = cls.select('count') - if tags: - for tag in tags: - query = query.where(cls.tags.contains(tag)) - count = await query.where(cls.is_r18 == False).gino.first() - r18_count = await query.where(cls.is_r18 == True).gino.first() - return count[0], r18_count[0] - +from typing import Optional, List +from services.db_context import db + + +class Pixiv(db.Model): + __tablename__ = "pixiv" + __table_args__ = {'extend_existing': True} + + id = db.Column(db.Integer(), primary_key=True) + pid = db.Column(db.BigInteger(), nullable=False) + title = db.Column(db.String(), nullable=False) + width = db.Column(db.Integer(), nullable=False) + height = db.Column(db.Integer(), nullable=False) + view = db.Column(db.Integer(), nullable=False) + bookmarks = db.Column(db.Integer(), nullable=False) + img_url = db.Column(db.String(), nullable=False) + img_p = db.Column(db.String(), nullable=False) + uid = db.Column(db.BigInteger(), nullable=False) + author = db.Column(db.String(), nullable=False) + is_r18 = db.Column(db.Boolean(), nullable=False) + tags = db.Column(db.String(), nullable=False) + + _idx1 = db.Index("pixiv_idx1", "pid", "img_url", unique=True) + + @classmethod + async def add_image_data( + cls, + pid: int, + title: str, + width: int, + height: int, + view: int, + bookmarks: int, + img_url: str, + img_p: str, + uid: int, + author: str, + tags: str, + ): + """ + 说明: + 添加图片信息 + 参数: + :param pid: pid + :param title: 标题 + :param width: 宽度 + :param height: 长度 + :param view: 被查看次数 + :param bookmarks: 收藏数 + :param img_url: url链接 + :param img_p: 张数 + :param uid: 作者uid + :param author: 作者名称 + :param tags: 相关tag + """ + if not await cls.check_exists(pid, img_p): + await cls.create( + pid=pid, + title=title, + width=width, + height=height, + view=view, + bookmarks=bookmarks, + img_url=img_url, + img_p=img_p, + uid=uid, + author=author, + is_r18=True if "R-18" in tags else False, + tags=tags, + ) + return True + return False + + @classmethod + async def remove_image_data(cls, pid: int, img_p: str) -> bool: + """ + 说明: + 删除图片数据 + 参数: + :param pid: 图片pid + :param img_p: 图片pid的张数,如:p0,p1 + """ + try: + if img_p: + await cls.delete.where( + (cls.pid == pid) & (cls.img_p == img_p) + ).gino.status() + else: + await cls.delete.where(cls.pid == pid).gino.status() + return True + except Exception: + return False + + @classmethod + async def get_all_pid(cls) -> List[int]: + """ + 说明: + 获取所有PID + """ + query = await cls.query.select("pid").gino.first() + pid = [x[0] for x in query] + return list(set(pid)) + + # 0:非r18 1:r18 2:混合 + @classmethod + async def query_images( + cls, + keywords: Optional[List[str]] = None, + uid: Optional[int] = None, + pid: Optional[int] = None, + r18: Optional[int] = 0, + num: int = 100 + ) -> List[Optional["Pixiv"]]: + """ + 说明: + 查找符合条件的图片 + 参数: + :param keywords: 关键词 + :param uid: 画师uid + :param pid: 图片pid + :param r18: 是否r18,0:非r18 1:r18 2:混合 + :param num: 查找图片的数量 + """ + if r18 == 0: + query = cls.query.where(cls.is_r18 == False) + elif r18 == 1: + query = cls.query.where(cls.is_r18 == True) + else: + query = cls.query + if keywords: + for keyword in keywords: + query = query.where(cls.tags.contains(keyword)) + elif uid: + query = query.where(cls.uid == uid) + elif pid: + query = query.where(cls.pid == pid) + query = query.order_by(db.func.random()).limit(num) + return await query.gino.all() + + @classmethod + async def check_exists(cls, pid: int, img_p: str) -> bool: + """ + 说明: + 检测pid是否已存在 + 参数: + :param pid: 图片PID + :param img_p: 张数 + """ + query = await cls.query.where( + (cls.pid == pid) & (cls.img_p == img_p) + ).gino.all() + return bool(query) + + @classmethod + async def get_keyword_num(cls, tags: List[str] = None) -> "int, int": + """ + 说明: + 获取相关关键词(keyword, tag)在图库中的数量 + 参数: + :param tags: 关键词/Tag + """ + setattr(Pixiv, 'count', db.func.count(cls.pid).label('count')) + query = cls.select('count') + if tags: + for tag in tags: + query = query.where(cls.tags.contains(tag)) + count = await query.where(cls.is_r18 == False).gino.first() + r18_count = await query.where(cls.is_r18 == True).gino.first() + return count[0], r18_count[0] + diff --git a/plugins/pix_gallery/model/pixiv_keyword_user.py b/plugins/pix_gallery/_model/pixiv_keyword_user.py old mode 100755 new mode 100644 similarity index 96% rename from plugins/pix_gallery/model/pixiv_keyword_user.py rename to plugins/pix_gallery/_model/pixiv_keyword_user.py index 10d33301..f8774e6d --- a/plugins/pix_gallery/model/pixiv_keyword_user.py +++ b/plugins/pix_gallery/_model/pixiv_keyword_user.py @@ -1,127 +1,127 @@ -from services.db_context import db -from typing import Set, List - - -class PixivKeywordUser(db.Model): - __tablename__ = "pixiv_keyword_users" - __table_args__ = {'extend_existing': True} - - id = db.Column(db.Integer(), primary_key=True) - user_qq = db.Column(db.BigInteger(), nullable=False) - group_id = db.Column(db.BigInteger(), nullable=False) - keyword = db.Column(db.String(), nullable=False) - is_pass = db.Column(db.Boolean(), default=False) - - _idx1 = db.Index("pixiv_keyword_users_idx1", "keyword", unique=True) - - @classmethod - async def add_keyword( - cls, user_qq: int, group_id: int, keyword: str, superusers: Set[str] - ) -> bool: - """ - 说明: - 添加搜图的关键词 - 参数: - :param user_qq: qq号 - :param group_id: 群号 - :param keyword: 关键词 - :param superusers: 是否为超级用户 - """ - is_pass = True if str(user_qq) in superusers else False - if not await cls._check_keyword_exists(keyword): - await cls.create( - user_qq=user_qq, group_id=group_id, keyword=keyword, is_pass=is_pass - ) - return True - return False - - @classmethod - async def delete_keyword(cls, keyword: str) -> bool: - """ - 说明: - 删除关键词 - 参数: - :param keyword: 关键词 - """ - if await cls._check_keyword_exists(keyword): - query = cls.query.where(cls.keyword == keyword).with_for_update() - query = await query.gino.first() - await query.delete() - return True - return False - - @classmethod - async def set_keyword_pass(cls, keyword: str, is_pass: bool) -> "int, int": - """ - 说明: - 通过或禁用关键词 - 参数: - :param keyword: 关键词 - :param is_pass: 通过状态 - """ - if await cls._check_keyword_exists(keyword): - query = cls.query.where(cls.keyword == keyword).with_for_update() - query = await query.gino.first() - await query.update( - is_pass=is_pass, - ).apply() - return query.user_qq, query.group_id - return 0, 0 - - @classmethod - async def get_all_user_dict(cls) -> dict: - """ - 说明: - 获取关键词数据库各个用户贡献的关键词字典 - """ - tmp = {} - query = await cls.query.gino.all() - for user in query: - if not tmp.get(user.user_qq): - tmp[user.user_qq] = {"keyword": []} - tmp[user.user_qq]["keyword"].append(user.keyword) - return tmp - - @classmethod - async def get_current_keyword(cls) -> "List[str], List[str]": - """ - 说明: - 获取当前通过与未通过的关键词 - """ - pass_keyword = [] - not_pass_keyword = [] - query = await cls.query.gino.all() - for user in query: - if user.is_pass: - pass_keyword.append(user.keyword) - else: - not_pass_keyword.append(user.keyword) - return pass_keyword, not_pass_keyword - - @classmethod - async def get_black_pid(cls) -> List[str]: - """ - 说明: - 获取黑名单PID - """ - black_pid = [] - query = await cls.query.where(cls.user_qq == 114514).gino.all() - for image in query: - black_pid.append(image.keyword[6:]) - return black_pid - - @classmethod - async def _check_keyword_exists(cls, keyword: str) -> bool: - """ - 说明: - 检测关键词是否已存在 - 参数: - :param keyword: 关键词 - """ - current_keyword = [] - query = await cls.query.gino.all() - for user in query: - current_keyword.append(user.keyword) - if keyword in current_keyword: - return True - return False +from services.db_context import db +from typing import Set, List + + +class PixivKeywordUser(db.Model): + __tablename__ = "pixiv_keyword_users" + __table_args__ = {'extend_existing': True} + + id = db.Column(db.Integer(), primary_key=True) + user_qq = db.Column(db.BigInteger(), nullable=False) + group_id = db.Column(db.BigInteger(), nullable=False) + keyword = db.Column(db.String(), nullable=False) + is_pass = db.Column(db.Boolean(), default=False) + + _idx1 = db.Index("pixiv_keyword_users_idx1", "keyword", unique=True) + + @classmethod + async def add_keyword( + cls, user_qq: int, group_id: int, keyword: str, superusers: Set[str] + ) -> bool: + """ + 说明: + 添加搜图的关键词 + 参数: + :param user_qq: qq号 + :param group_id: 群号 + :param keyword: 关键词 + :param superusers: 是否为超级用户 + """ + is_pass = True if str(user_qq) in superusers else False + if not await cls._check_keyword_exists(keyword): + await cls.create( + user_qq=user_qq, group_id=group_id, keyword=keyword, is_pass=is_pass + ) + return True + return False + + @classmethod + async def delete_keyword(cls, keyword: str) -> bool: + """ + 说明: + 删除关键词 + 参数: + :param keyword: 关键词 + """ + if await cls._check_keyword_exists(keyword): + query = cls.query.where(cls.keyword == keyword).with_for_update() + query = await query.gino.first() + await query.delete() + return True + return False + + @classmethod + async def set_keyword_pass(cls, keyword: str, is_pass: bool) -> "int, int": + """ + 说明: + 通过或禁用关键词 + 参数: + :param keyword: 关键词 + :param is_pass: 通过状态 + """ + if await cls._check_keyword_exists(keyword): + query = cls.query.where(cls.keyword == keyword).with_for_update() + query = await query.gino.first() + await query.update( + is_pass=is_pass, + ).apply() + return query.user_qq, query.group_id + return 0, 0 + + @classmethod + async def get_all_user_dict(cls) -> dict: + """ + 说明: + 获取关键词数据库各个用户贡献的关键词字典 + """ + tmp = {} + query = await cls.query.gino.all() + for user in query: + if not tmp.get(user.user_qq): + tmp[user.user_qq] = {"keyword": []} + tmp[user.user_qq]["keyword"].append(user.keyword) + return tmp + + @classmethod + async def get_current_keyword(cls) -> "List[str], List[str]": + """ + 说明: + 获取当前通过与未通过的关键词 + """ + pass_keyword = [] + not_pass_keyword = [] + query = await cls.query.gino.all() + for user in query: + if user.is_pass: + pass_keyword.append(user.keyword) + else: + not_pass_keyword.append(user.keyword) + return pass_keyword, not_pass_keyword + + @classmethod + async def get_black_pid(cls) -> List[str]: + """ + 说明: + 获取黑名单PID + """ + black_pid = [] + query = await cls.query.where(cls.user_qq == 114514).gino.all() + for image in query: + black_pid.append(image.keyword[6:]) + return black_pid + + @classmethod + async def _check_keyword_exists(cls, keyword: str) -> bool: + """ + 说明: + 检测关键词是否已存在 + 参数: + :param keyword: 关键词 + """ + current_keyword = [] + query = await cls.query.gino.all() + for user in query: + current_keyword.append(user.keyword) + if keyword in current_keyword: + return True + return False diff --git a/plugins/pix_gallery/pix.py b/plugins/pix_gallery/pix.py index ea283959..1e3a8ebf 100755 --- a/plugins/pix_gallery/pix.py +++ b/plugins/pix_gallery/pix.py @@ -1,18 +1,18 @@ -from nonebot.adapters.cqhttp.message import Message -from utils.utils import get_message_text, is_number +from utils.utils import is_number from configs.config import Config -from .model.omega_pixiv_illusts import OmegaPixivIllusts +from ._model.omega_pixiv_illusts import OmegaPixivIllusts from utils.message_builder import image from utils.manager import withdraw_message_manager from services.log import logger -from nonebot.adapters.cqhttp import ( +from nonebot.adapters.onebot.v11 import ( Bot, MessageEvent, GroupMessageEvent, + Message ) -from nonebot.typing import T_State -from .data_source import get_image -from .model.pixiv import Pixiv +from nonebot.params import CommandArg +from ._data_source import get_image +from ._model.pixiv import Pixiv from nonebot import on_command import random @@ -59,7 +59,7 @@ OMEGA_RATIO = None @pix.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): global PIX_RATIO, OMEGA_RATIO if PIX_RATIO is None: pix_omega_pixiv_ratio = Config.get_config("pix", "PIX_OMEGA_PIXIV_RATIO") @@ -68,7 +68,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): ) OMEGA_RATIO = 1 - PIX_RATIO num = 1 - keyword = get_message_text(event.json()) + keyword = arg.extract_plain_text().strip() x = keyword.split(" ") if "-s" in x: x.remove("-s") diff --git a/plugins/pix_gallery/pix_add_keyword.py b/plugins/pix_gallery/pix_add_keyword.py index 84b8b957..2f3b8c0e 100755 --- a/plugins/pix_gallery/pix_add_keyword.py +++ b/plugins/pix_gallery/pix_add_keyword.py @@ -1,11 +1,12 @@ from nonebot import on_command -from utils.utils import get_message_text, is_number +from utils.utils import is_number from services.log import logger -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent -from nonebot.typing import T_State -from .data_source import uid_pid_exists -from .model.pixiv_keyword_user import PixivKeywordUser -from .model.pixiv import Pixiv +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message +from nonebot.params import CommandArg, Command +from typing import Tuple +from ._data_source import uid_pid_exists +from ._model.pixiv_keyword_user import PixivKeywordUser +from ._model.pixiv import Pixiv from nonebot.permission import SUPERUSER __zx_plugin_name__ = "PIX关键词/UID/PID添加管理 [Superuser]" @@ -39,8 +40,8 @@ add_uid_pid = on_command( @add_keyword.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() group_id = -1 if isinstance(event, GroupMessageEvent): group_id = event.group_id @@ -62,8 +63,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @add_uid_pid.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() exists_flag = True if msg.find("-f") != -1 and str(event.user_id) in bot.config.superusers: exists_flag = False @@ -72,7 +73,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): for msg in msg.split(): if not is_number(msg): await add_uid_pid.finish("UID只能是数字的说...", at_sender=True) - if state["_prefix"]["raw_command"].lower().endswith("uid"): + if cmd[0].lower().endswith("uid"): msg = f"uid:{msg}" else: msg = f"pid:{msg}" @@ -96,8 +97,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @add_black_pid.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - pid = get_message_text(event.json()) +async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): + pid = arg.extract_plain_text().strip() img_p = "" if "p" in pid: img_p = pid.split("p")[-1] diff --git a/plugins/pix_gallery/pix_pass_del_keyword.py b/plugins/pix_gallery/pix_pass_del_keyword.py index 812d21a2..3ce7e83b 100755 --- a/plugins/pix_gallery/pix_pass_del_keyword.py +++ b/plugins/pix_gallery/pix_pass_del_keyword.py @@ -1,14 +1,14 @@ from nonebot import on_command -from nonebot.adapters.cqhttp.message import Message -from utils.utils import get_message_text, is_number +from utils.utils import is_number from utils.message_builder import at from services.log import logger -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message +from nonebot.params import CommandArg, Command from nonebot.permission import SUPERUSER -from nonebot.typing import T_State -from .data_source import remove_image -from .model.pixiv_keyword_user import PixivKeywordUser -from .model.pixiv import Pixiv +from ._data_source import remove_image +from ._model.pixiv_keyword_user import PixivKeywordUser +from ._model.pixiv import Pixiv +from typing import Tuple __zx_plugin_name__ = "PIX关键词/UID/PID删除管理 [Superuser]" @@ -52,8 +52,8 @@ del_pic = on_command("删除pix图片", permission=SUPERUSER, priority=1, block= @del_keyword.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() if not msg: await del_keyword.finish("好好输入要删除什么关键字啊笨蛋!") if is_number(msg): @@ -71,8 +71,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @del_pic.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - pid_arr = get_message_text(event.json()) +async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): + pid_arr = arg.extract_plain_text().strip() if pid_arr: msg = "" black_pid = "" @@ -127,13 +127,13 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @pass_keyword.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): tmp = {"group": {}, "private": {}} - msg = get_message_text(event.json()) + msg = arg.extract_plain_text().strip() if not msg: await pass_keyword.finish("通过虚空的关键词/UID?离谱...") msg = msg.split() - flag = True if state["_prefix"]["raw_command"][:2] == "通过" else False + flag = cmd[0][:2] == "通过" for x in msg: if x.lower().startswith("uid"): x = x.replace("uid", "").replace(":", "") @@ -163,7 +163,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): else: tmp["group"][group_id][user_id]["keyword"].append(x) msg = " ".join(msg) - await pass_keyword.send(f'已成功{state["_prefix"]["raw_command"][:2]}搜图关键词:{msg}....') + await pass_keyword.send(f'已成功{cmd[0][:2]}搜图关键词:{msg}....') for user in tmp["private"]: x = ",".join(tmp["private"][user]["keyword"]) await bot.send_private_msg( diff --git a/plugins/pix_gallery/pix_show_info.py b/plugins/pix_gallery/pix_show_info.py index 798e1ca2..6ea55d03 100755 --- a/plugins/pix_gallery/pix_show_info.py +++ b/plugins/pix_gallery/pix_show_info.py @@ -1,10 +1,9 @@ from nonebot import on_command -from utils.utils import get_message_text from utils.message_builder import image -from nonebot.adapters.cqhttp import Bot, MessageEvent -from nonebot.typing import T_State -from .data_source import gen_keyword_pic, get_keyword_num -from .model.pixiv_keyword_user import PixivKeywordUser +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message +from ._data_source import gen_keyword_pic, get_keyword_num +from ._model.pixiv_keyword_user import PixivKeywordUser +from nonebot.params import CommandArg import asyncio @@ -35,7 +34,7 @@ show_pix = on_command("查看pix图库", priority=1, block=True) @my_keyword.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent): data = await PixivKeywordUser.get_all_user_dict() if data.get(event.user_id) is None or not data[event.user_id]["keyword"]: await my_keyword.finish("您目前没有提供任何Pixiv搜图关键字...", at_sender=True) @@ -45,7 +44,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @show_keyword.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(bot: Bot, event: MessageEvent): _pass_keyword, not_pass_keyword = await PixivKeywordUser.get_current_keyword() if _pass_keyword or not_pass_keyword: await show_keyword.send( @@ -67,8 +66,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @show_pix.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - keyword = get_message_text(event.json()) +async def _(arg: Message = CommandArg()): + keyword = arg.extract_plain_text().strip() count, r18_count, count_, setu_count, r18_count_ = await get_keyword_num(keyword) await show_pix.send( f"PIX图库:{keyword}\n" diff --git a/plugins/pix_gallery/pix_update.py b/plugins/pix_gallery/pix_update.py index f5a64bf6..765b7206 100755 --- a/plugins/pix_gallery/pix_update.py +++ b/plugins/pix_gallery/pix_update.py @@ -1,12 +1,12 @@ from nonebot import on_command -from utils.utils import get_message_text, is_number +from utils.utils import is_number from nonebot.permission import SUPERUSER -from nonebot.typing import T_State -from .data_source import start_update_image_url -from .model.pixiv_keyword_user import PixivKeywordUser -from .model.omega_pixiv_illusts import OmegaPixivIllusts -from .model.pixiv import Pixiv -from nonebot.adapters.cqhttp import Bot, MessageEvent +from ._data_source import start_update_image_url +from ._model.pixiv_keyword_user import PixivKeywordUser +from ._model.omega_pixiv_illusts import OmegaPixivIllusts +from ._model.pixiv import Pixiv +from nonebot.adapters.onebot.v11 import Message +from nonebot.params import CommandArg import time from services.log import logger from pathlib import Path @@ -47,8 +47,8 @@ check_omega = on_command("检测omega图库", permission=SUPERUSER, priority=1, @start_update.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg_sp = get_message_text(event.json()).split() +async def _(arg: Message = CommandArg()): + msg_sp = arg.extract_plain_text().strip().split() _pass_keyword, _ = await PixivKeywordUser.get_current_keyword() _pass_keyword.reverse() black_pid = await PixivKeywordUser.get_black_pid() @@ -105,8 +105,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @check_not_update_uid_pid.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() flag = False if msg == "update": flag = True @@ -142,7 +142,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @check_omega.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(): async def _tasks(line: str, all_pid: List[int], length: int, index: int): data = line.split("VALUES", maxsplit=1)[-1].strip() if data.startswith("("): diff --git a/plugins/pixiv_rank_search/__init__.py b/plugins/pixiv_rank_search/__init__.py index a8e6abcc..d7cf0744 100755 --- a/plugins/pixiv_rank_search/__init__.py +++ b/plugins/pixiv_rank_search/__init__.py @@ -1,11 +1,11 @@ -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message from nonebot.matcher import Matcher +from nonebot.params import CommandArg from nonebot import on_command -from utils.utils import get_message_text, is_number +from utils.utils import is_number from .data_source import get_pixiv_urls, download_pixiv_imgs, search_pixiv_urls from services.log import logger -from nonebot.adapters.cqhttp.exception import NetworkError +from nonebot.adapters.onebot.v11.exception import NetworkError from asyncio.exceptions import TimeoutError from utils.message_builder import custom_forward_msg from configs.config import Config @@ -110,8 +110,8 @@ pixiv_keyword = on_command("搜图", priority=5, block=True, rule=to_me()) @pixiv_rank.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()).strip() +async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip().strip() msg = msg.split(" ") msg = [m for m in msg if m] code = 0 @@ -149,8 +149,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @pixiv_keyword.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() if isinstance(event, GroupMessageEvent): if "r18" in msg.lower(): await pixiv_keyword.finish("(脸红#) 你不会害羞的 八嘎!", at_sender=True) diff --git a/plugins/poke/__init__.py b/plugins/poke/__init__.py index b75606a9..adf3cae0 100755 --- a/plugins/poke/__init__.py +++ b/plugins/poke/__init__.py @@ -1,13 +1,12 @@ from nonebot import on_notice -from nonebot.adapters.cqhttp import Bot, PokeNotifyEvent -from nonebot.typing import T_State -from configs.path_config import VOICE_PATH, IMAGE_PATH -import os +from nonebot.adapters.onebot.v11 import PokeNotifyEvent +from configs.path_config import RECORD_PATH, IMAGE_PATH from utils.message_builder import record, image, poke from services.log import logger import random from utils.utils import CountLimiter from models.ban_user import BanUser +import os __zx_plugin_name__ = "戳一戳" @@ -53,7 +52,7 @@ poke_ = on_notice(priority=5, block=False) @poke_.handle() -async def _poke_(bot: Bot, event: PokeNotifyEvent, state: T_State): +async def _poke_event(event: PokeNotifyEvent): if event.self_id == event.target_id: _clmt.add(event.user_id) if _clmt.check(event.user_id) or random.random() < 0.3: @@ -64,13 +63,13 @@ async def _poke_(bot: Bot, event: PokeNotifyEvent, state: T_State): await poke_.finish(rst + random.choice(poke__reply), at_sender=True) rand = random.random() if rand <= 0.3: - path = random.choice(["luoli/", "meitu/"]) - index = random.randint(0, len(os.listdir(IMAGE_PATH + path))) + path = random.choice(["luoli", "meitu"]) + index = random.randint(0, len(os.listdir(IMAGE_PATH / path))) result = f"id:{index}" + image(f"{index}.jpg", path) await poke_.send(result) logger.info(f"USER {event.user_id} 戳了戳我 回复: {result} \n {result}") elif 0.3 < rand < 0.6: - voice = random.choice(os.listdir(VOICE_PATH + "dinggong/")) + voice = random.choice(os.listdir(RECORD_PATH / "dinggong")) result = record(voice, "dinggong") await poke_.send(result) await poke_.send(voice.split("_")[1]) diff --git a/plugins/quotations.py b/plugins/quotations.py index 3c083c84..d3c5f96e 100755 --- a/plugins/quotations.py +++ b/plugins/quotations.py @@ -1,6 +1,6 @@ from nonebot import on_command from services.log import logger -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent from nonebot.typing import T_State from utils.http_utils import AsyncHttpx diff --git a/plugins/roll.py b/plugins/roll.py index 35fb09f3..6b3be616 100755 --- a/plugins/roll.py +++ b/plugins/roll.py @@ -1,7 +1,6 @@ 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 +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message +from nonebot.params import CommandArg from services.log import logger from configs.config import NICKNAME import random @@ -33,11 +32,11 @@ roll = on_command("roll", priority=5, block=True) @roll.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()).split() +async def _(event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip().split() if not msg: await roll.finish(f"roll: {random.randint(0, 100)}", at_sender=True) - user_name = event.sender.card if event.sender.card else event.sender.nickname + user_name = event.sender.card or event.sender.nickname await roll.send( random.choice( [ diff --git a/plugins/russian/__init__.py b/plugins/russian/__init__.py index afdccbff..c10ea1e6 100755 --- a/plugins/russian/__init__.py +++ b/plugins/russian/__init__.py @@ -1,17 +1,20 @@ from nonebot import on_command -import random -import asyncio -from nonebot.adapters.cqhttp import GROUP, Bot, GroupMessageEvent, Message +from nonebot.adapters.onebot.v11 import GROUP, Bot, GroupMessageEvent, Message from nonebot.typing import T_State -from utils.utils import get_message_text, is_number, get_message_at +from utils.utils import is_number, get_message_at +from nonebot.params import CommandArg, Command, ArgStr from models.group_member_info import GroupInfoUser from utils.message_builder import at, image from .model import RussianUser from models.bag_user import BagUser from services.log import logger -import time from .data_source import rank from configs.config import NICKNAME, Config +from typing import Tuple +import random +import asyncio +import time + __zx_plugin_name__ = "俄罗斯轮盘" __plugin_usage__ = """ @@ -87,7 +90,7 @@ russian_rank = on_command( @accept.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): global rs_player try: if rs_player[event.group_id][1] == 0: @@ -127,7 +130,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): else: await accept.finish("你的金币不足以接受这场对决!", at_sender=True) - player2_name = event.sender.card if event.sender.card else event.sender.nickname + player2_name = event.sender.card or event.sender.nickname rs_player[event.group_id][2] = event.user_id rs_player[event.group_id]["player2"] = player2_name @@ -139,7 +142,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @refuse.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): global rs_player try: if rs_player[event.group_id][1] == 0: @@ -162,7 +165,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @settlement.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(bot: Bot, event: GroupMessageEvent): global rs_player if ( not rs_player.get(event.group_id) @@ -189,29 +192,12 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): await end_game(bot, event) -@russian.args_parser -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - msg = get_message_text(event.json()) - if msg in ["取消", "算了"]: - await russian.finish("已取消操作...") - try: - if rs_player[event.group_id][1] != 0: - await russian.finish("决斗已开始...", at_sender=True) - except KeyError: - pass - if not is_number(msg): - await russian.reject("输入子弹数量必须是数字啊喂!") - if int(msg) < 1 or int(msg) > 6: - await russian.reject("子弹数量必须大于0小于7!") - state["bullet_num"] = int(msg) - - @russian.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _( + bot: Bot, event: GroupMessageEvent, state: T_State, arg: Message = CommandArg() +): global rs_player - msg = get_message_text(event.json()) - if msg == "帮助": - await russian.finish(__plugin_usage__) + msg = arg.extract_plain_text().strip() try: if ( rs_player[event.group_id][1] @@ -270,9 +256,22 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @russian.got("bullet_num", prompt="请输入装填子弹的数量!(最多6颗)") -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _( + event: GroupMessageEvent, state: T_State, bullet_num: str = ArgStr("bullet_num") +): global rs_player - bullet_num = state["bullet_num"] + if bullet_num in ["取消", "算了"]: + await russian.finish("已取消操作...") + try: + if rs_player[event.group_id][1] != 0: + await russian.finish("决斗已开始...", at_sender=True) + except KeyError: + pass + if not is_number(bullet_num): + await russian.reject_arg("bullet_num", "输入子弹数量必须是数字啊喂!") + bullet_num = int(bullet_num) + if bullet_num < 1 or bullet_num > 6: + await russian.reject_arg("bullet_num", "子弹数量必须大于0小于7!") at_ = state["at"] if state.get("at") else [] money = state["money"] if state.get("money") else 200 user_money = await BagUser.get_gold(event.user_id, event.group_id) @@ -286,7 +285,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): if money > user_money: await russian.finish("你没有足够的钱支撑起这场挑战", at_sender=True) - player1_name = event.sender.card if event.sender.card else event.sender.nickname + player1_name = event.sender.card or event.sender.nickname if at_: at_ = at_[0] @@ -326,7 +325,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @shot.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(bot: Bot, event: GroupMessageEvent): global rs_player try: if time.time() - rs_player[event.group_id]["time"] > 30: @@ -467,7 +466,7 @@ async def end_game(bot: Bot, event: GroupMessageEvent): @record.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): user = await RussianUser.ensure(event.user_id, event.group_id) await record.send( f"俄罗斯轮盘\n" @@ -484,24 +483,28 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @russian_rank.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - num = get_message_text(event.json()) +async def _( + event: GroupMessageEvent, + cmd: Tuple[str, ...] = Command(), + arg: Message = CommandArg(), +): + num = arg.extract_plain_text().strip() if is_number(num) and 51 > int(num) > 10: num = int(num) else: num = 10 rank_image = None - if state["_prefix"]["raw_command"] in ["胜场排行", "胜利排行"]: + if cmd[0] in ["胜场排行", "胜利排行"]: rank_image = await rank(event.group_id, "win_rank", num) - if state["_prefix"]["raw_command"] in ["败场排行", "失败排行"]: + if cmd[0] in ["败场排行", "失败排行"]: rank_image = await rank(event.group_id, "lose_rank", num) - if state["_prefix"]["raw_command"] == "欧洲人排行": + if cmd[0] == "欧洲人排行": rank_image = await rank(event.group_id, "make_money", num) - if state["_prefix"]["raw_command"] == "慈善家排行": + if cmd[0] == "慈善家排行": rank_image = await rank(event.group_id, "spend_money", num) - if state["_prefix"]["raw_command"] == "最高连胜排行": + if cmd[0] == "最高连胜排行": rank_image = await rank(event.group_id, "max_winning_streak", num) - if state["_prefix"]["raw_command"] == "最高连败排行": + if cmd[0] == "最高连败排行": rank_image = await rank(event.group_id, "max_losing_streak", num) if rank_image: await russian_rank.send(image(b64=rank_image.pic2bs4())) diff --git a/plugins/search_anime/__init__.py b/plugins/search_anime/__init__.py index 74817b98..89c05350 100755 --- a/plugins/search_anime/__init__.py +++ b/plugins/search_anime/__init__.py @@ -1,11 +1,11 @@ from nonebot import on_command from .data_source import from_anime_get_info from services.log import logger -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent, Message from nonebot.typing import T_State from configs.config import Config -from utils.utils import get_message_text from utils.message_builder import custom_forward_msg +from nonebot.params import CommandArg, ArgStr __zx_plugin_name__ = "搜番" @@ -35,23 +35,14 @@ __plugin_configs__ = { search_anime = on_command("搜番", aliases={"搜动漫"}, priority=5, block=True) -@search_anime.args_parser -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) - if not msg: - await search_anime.reject("番名番名番名呢?", at_sender=True) - state["anime"] = msg - - @search_anime.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - if get_message_text(event.json()): - state["anime"] = get_message_text(event.json()) +async def _(state: T_State, arg: Message = CommandArg()): + if arg.extract_plain_text().strip(): + state["anime"] = arg.extract_plain_text().strip() @search_anime.got("anime", prompt="是不是少了番名?") -async def _(bot: Bot, event: MessageEvent, state: T_State): - key_word = state["anime"] +async def _(bot: Bot, event: MessageEvent, state: T_State, key_word: str = ArgStr("anime")): await search_anime.send(f"开始搜番 {key_word}", at_sender=True) anime_report = await from_anime_get_info( key_word, diff --git a/plugins/search_buff_skin_price/__init__.py b/plugins/search_buff_skin_price/__init__.py index 42d4c9a5..ad903b08 100755 --- a/plugins/search_buff_skin_price/__init__.py +++ b/plugins/search_buff_skin_price/__init__.py @@ -2,10 +2,10 @@ from nonebot import on_command from .data_source import get_price, update_buff_cookie from services.log import logger from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message from nonebot.rule import to_me from nonebot.permission import SUPERUSER -from utils.utils import get_message_text +from nonebot.params import CommandArg, ArgStr from configs.config import NICKNAME @@ -28,38 +28,21 @@ __plugin_settings__ = { "limit_superuser": False, "cmd": ["查询皮肤"], } -__plugin_block_limit__ = { - "rst": "您有皮肤正在搜索,请稍等..." -} +__plugin_block_limit__ = {"rst": "您有皮肤正在搜索,请稍等..."} __plugin_configs__ = { - "BUFF_PROXY": { - "value": None, - "help": "BUFF代理,有些厂ip可能被屏蔽" - }, - "COOKIE": { - "value": None, - "help": "BUFF的账号cookie" - } + "BUFF_PROXY": {"value": None, "help": "BUFF代理,有些厂ip可能被屏蔽"}, + "COOKIE": {"value": None, "help": "BUFF的账号cookie"}, } search_skin = on_command("查询皮肤", aliases={"皮肤查询"}, priority=5, block=True) -@search_skin.args_parser -async def parse(bot: Bot, event: MessageEvent, state: T_State): - if get_message_text(event.json()) in ["取消", "算了"]: - await search_skin.finish("已取消操作..", at_sender=True) - state[state["_current_key"]] = str(event.get_message()) - - @search_skin.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - if str(event.get_message()) in ["帮助"]: - await search_skin.finish(__plugin_usage__) - raw_arg = get_message_text(event.json()) +async def _(event: MessageEvent, state: T_State, arg: Message = CommandArg()): + raw_arg = arg.extract_plain_text().strip() if raw_arg: - args = raw_arg.split(" ") + args = raw_arg.split() if len(args) >= 2: state["name"] = args[0] state["skin"] = args[1] @@ -67,11 +50,18 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @search_skin.got("name", prompt="要查询什么武器呢?") @search_skin.got("skin", prompt="要查询该武器的什么皮肤呢?") -async def arg_handle(bot: Bot, event: MessageEvent, state: T_State): +async def arg_handle( + event: MessageEvent, + state: T_State, + name: str = ArgStr("name"), + skin: str = ArgStr("skin"), +): + if name in ["算了", "取消"] or skin in ["算了", "取消"]: + await search_skin.finish("已取消操作...") result = "" - if state["name"] in ["ak", "ak47"]: - state["name"] = "ak-47" - name = state["name"] + " | " + state["skin"] + if name in ["ak", "ak47"]: + name = "ak-47" + name = name + " | " + skin try: result, status_code = await get_price(name) except FileNotFoundError: @@ -100,7 +90,7 @@ update_buff_session = on_command( @update_buff_session.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent): await update_buff_session.finish( update_buff_cookie(str(event.get_message())), at_sender=True ) diff --git a/plugins/send_dinggong_voice/__init__.py b/plugins/send_dinggong_voice/__init__.py index d0359f53..438634f7 100755 --- a/plugins/send_dinggong_voice/__init__.py +++ b/plugins/send_dinggong_voice/__init__.py @@ -1,9 +1,9 @@ from nonebot import on_keyword from utils.message_builder import record -from configs.path_config import VOICE_PATH +from configs.path_config import RECORD_PATH from services.log import logger from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, GroupMessageEvent from nonebot.rule import to_me import random import os @@ -37,7 +37,7 @@ dg_voice = on_keyword({"骂"}, rule=to_me(), priority=5, block=True) @dg_voice.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): if len(str((event.get_message()))) > 1: - voice = random.choice(os.listdir(VOICE_PATH + "dinggong/")) + voice = random.choice(os.listdir(RECORD_PATH / "dinggong")) result = record(voice, "dinggong") await dg_voice.send(result) await dg_voice.send(voice.split("_")[1]) diff --git a/plugins/send_setu_/model.py b/plugins/send_setu_/_model.py old mode 100755 new mode 100644 similarity index 96% rename from plugins/send_setu_/model.py rename to plugins/send_setu_/_model.py index 4e80d7a3..20286c59 --- a/plugins/send_setu_/model.py +++ b/plugins/send_setu_/_model.py @@ -1,198 +1,198 @@ -from services.db_context import db -from typing import List, Optional - - -class Setu(db.Model): - __tablename__ = "setu" - __table_args__ = {'extend_existing': True} - - id = db.Column(db.Integer(), primary_key=True) - local_id = db.Column(db.Integer(), nullable=False) - title = db.Column(db.String(), nullable=False) - author = db.Column(db.String(), nullable=False) - pid = db.Column(db.BigInteger(), nullable=False) - img_hash = db.Column(db.String(), nullable=False) - img_url = db.Column(db.String(), nullable=False) - is_r18 = db.Column(db.Boolean(), nullable=False) - tags = db.Column(db.String()) - - _idx1 = db.Index("setu_pid_img_url_idx1", "pid", "img_url", unique=True) - - @classmethod - async def add_setu_data( - cls, - local_id: int, - title: str, - author: str, - pid: int, - img_hash: str, - img_url: str, - tags: str, - ): - """ - 说明: - 添加一份色图数据 - 参数: - :param local_id: 本地存储id - :param title: 标题 - :param author: 作者 - :param pid: 图片pid - :param img_hash: 图片hash值 - :param img_url: 图片链接 - :param tags: 图片标签 - """ - if not await cls._check_exists(pid, img_url): - await cls.create( - local_id=local_id, - title=title, - author=author, - pid=pid, - img_hash=img_hash, - img_url=img_url, - is_r18=True if "R-18" in tags else False, - tags=tags, - ) - - @classmethod - async def query_image( - cls, - local_id: Optional[int] = None, - tags: Optional[List[str]] = None, - r18: int = 0, - limit: int = 50, - ): - """ - 说明: - 通过tag查找色图 - 参数: - :param local_id: 本地色图 id - :param tags: tags - :param r18: 是否 r18,0:非r18 1:r18 2:混合 - :param limit: 获取数量 - """ - if local_id: - flag = True if r18 == 1 else False - return await cls.query.where( - (cls.local_id == local_id) & (cls.is_r18 == flag) - ).gino.first() - if r18 == 0: - query = cls.query.where(cls.is_r18 == False) - elif r18 == 1: - query = cls.query.where(cls.is_r18 == True) - else: - query = cls.query - if tags: - for tag in tags: - query = query.where(cls.tags.contains(tag) | cls.title.contains(tag) | cls.author.contains(tag)) - query = query.order_by(db.func.random()).limit(limit) - return await query.gino.all() - - @classmethod - async def get_image_count(cls, r18: int = 0) -> int: - """ - 说明: - 查询图片数量 - """ - flag = False if r18 == 0 else True - setattr(Setu, 'count', db.func.count(cls.local_id).label('count')) - count = await cls.select('count').where(cls.is_r18 == flag).gino.first() - return count[0] - - @classmethod - async def get_image_in_hash(cls, img_hash: str) -> "Setu": - """ - 说明: - 通过图像hash获取图像信息 - 参数: - :param img_hash: = 图像hash值 - """ - query = await cls.query.where(cls.img_hash == img_hash).gino.first() - return query - - @classmethod - async def _check_exists(cls, pid: int, img_url: str) -> bool: - """ - 说明: - 检测图片是否存在 - 参数: - :param pid: 图片pid - :param img_url: 图片链接 - """ - return bool( - await cls.query.where( - (cls.pid == pid) & (cls.img_url == img_url) - ).gino.first() - ) - - @classmethod - async def delete_image(cls, pid: int) -> int: - """ - 说明: - 删除图片并替换 - 参数: - :param pid: 图片pid - """ - query = await cls.query.where(cls.pid == pid).gino.first() - if query: - is_r18 = query.is_r18 - num = await cls.get_image_count(is_r18) - x = await cls.query.where((cls.is_r18 == is_r18) & (cls.local_id == num - 1)).gino.first() - _tmp_local_id = x.local_id - if x: - x.update(local_id=query.local_id).apply() - await cls.delete.where(cls.pid == pid).gino.status() - return _tmp_local_id - return -1 - - - @classmethod - async def update_setu_data( - cls, - pid: int, - *, - local_id: Optional[int] = None, - title: Optional[str] = None, - author: Optional[str] = None, - img_hash: Optional[str] = None, - img_url: Optional[str] = None, - tags: Optional[str] = None, - ) -> bool: - """ - 说明: - 根据PID修改图片数据 - 参数: - :param local_id: 本地id - :param pid: 图片pid - :param title: 标题 - :param author: 作者 - :param img_hash: 图片hash值 - :param img_url: 图片链接 - :param tags: 图片标签 - """ - query = cls.query.where(cls.pid == pid).with_for_update() - image_list = await query.gino.all() - if image_list: - for image in image_list: - if local_id: - await image.update(local_id=local_id).apply() - if title: - await image.update(title=title).apply() - if author: - await image.update(author=author).apply() - if img_hash: - await image.update(img_hash=img_hash).apply() - if img_url: - await image.update(img_url=img_url).apply() - if tags: - await image.update(tags=tags).apply() - return True - return False - - @classmethod - async def get_all_setu(cls) -> List["Setu"]: - """ - 说明: - 获取所有图片对象 - """ - return await cls.query.gino.all() - +from services.db_context import db +from typing import List, Optional + + +class Setu(db.Model): + __tablename__ = "setu" + __table_args__ = {'extend_existing': True} + + id = db.Column(db.Integer(), primary_key=True) + local_id = db.Column(db.Integer(), nullable=False) + title = db.Column(db.String(), nullable=False) + author = db.Column(db.String(), nullable=False) + pid = db.Column(db.BigInteger(), nullable=False) + img_hash = db.Column(db.String(), nullable=False) + img_url = db.Column(db.String(), nullable=False) + is_r18 = db.Column(db.Boolean(), nullable=False) + tags = db.Column(db.String()) + + _idx1 = db.Index("setu_pid_img_url_idx1", "pid", "img_url", unique=True) + + @classmethod + async def add_setu_data( + cls, + local_id: int, + title: str, + author: str, + pid: int, + img_hash: str, + img_url: str, + tags: str, + ): + """ + 说明: + 添加一份色图数据 + 参数: + :param local_id: 本地存储id + :param title: 标题 + :param author: 作者 + :param pid: 图片pid + :param img_hash: 图片hash值 + :param img_url: 图片链接 + :param tags: 图片标签 + """ + if not await cls._check_exists(pid, img_url): + await cls.create( + local_id=local_id, + title=title, + author=author, + pid=pid, + img_hash=img_hash, + img_url=img_url, + is_r18=True if "R-18" in tags else False, + tags=tags, + ) + + @classmethod + async def query_image( + cls, + local_id: Optional[int] = None, + tags: Optional[List[str]] = None, + r18: int = 0, + limit: int = 50, + ): + """ + 说明: + 通过tag查找色图 + 参数: + :param local_id: 本地色图 id + :param tags: tags + :param r18: 是否 r18,0:非r18 1:r18 2:混合 + :param limit: 获取数量 + """ + if local_id: + flag = True if r18 == 1 else False + return await cls.query.where( + (cls.local_id == local_id) & (cls.is_r18 == flag) + ).gino.first() + if r18 == 0: + query = cls.query.where(cls.is_r18 == False) + elif r18 == 1: + query = cls.query.where(cls.is_r18 == True) + else: + query = cls.query + if tags: + for tag in tags: + query = query.where(cls.tags.contains(tag) | cls.title.contains(tag) | cls.author.contains(tag)) + query = query.order_by(db.func.random()).limit(limit) + return await query.gino.all() + + @classmethod + async def get_image_count(cls, r18: int = 0) -> int: + """ + 说明: + 查询图片数量 + """ + flag = False if r18 == 0 else True + setattr(Setu, 'count', db.func.count(cls.local_id).label('count')) + count = await cls.select('count').where(cls.is_r18 == flag).gino.first() + return count[0] + + @classmethod + async def get_image_in_hash(cls, img_hash: str) -> "Setu": + """ + 说明: + 通过图像hash获取图像信息 + 参数: + :param img_hash: = 图像hash值 + """ + query = await cls.query.where(cls.img_hash == img_hash).gino.first() + return query + + @classmethod + async def _check_exists(cls, pid: int, img_url: str) -> bool: + """ + 说明: + 检测图片是否存在 + 参数: + :param pid: 图片pid + :param img_url: 图片链接 + """ + return bool( + await cls.query.where( + (cls.pid == pid) & (cls.img_url == img_url) + ).gino.first() + ) + + @classmethod + async def delete_image(cls, pid: int) -> int: + """ + 说明: + 删除图片并替换 + 参数: + :param pid: 图片pid + """ + query = await cls.query.where(cls.pid == pid).gino.first() + if query: + is_r18 = query.is_r18 + num = await cls.get_image_count(is_r18) + x = await cls.query.where((cls.is_r18 == is_r18) & (cls.local_id == num - 1)).gino.first() + _tmp_local_id = x.local_id + if x: + x.update(local_id=query.local_id).apply() + await cls.delete.where(cls.pid == pid).gino.status() + return _tmp_local_id + return -1 + + + @classmethod + async def update_setu_data( + cls, + pid: int, + *, + local_id: Optional[int] = None, + title: Optional[str] = None, + author: Optional[str] = None, + img_hash: Optional[str] = None, + img_url: Optional[str] = None, + tags: Optional[str] = None, + ) -> bool: + """ + 说明: + 根据PID修改图片数据 + 参数: + :param local_id: 本地id + :param pid: 图片pid + :param title: 标题 + :param author: 作者 + :param img_hash: 图片hash值 + :param img_url: 图片链接 + :param tags: 图片标签 + """ + query = cls.query.where(cls.pid == pid).with_for_update() + image_list = await query.gino.all() + if image_list: + for image in image_list: + if local_id: + await image.update(local_id=local_id).apply() + if title: + await image.update(title=title).apply() + if author: + await image.update(author=author).apply() + if img_hash: + await image.update(img_hash=img_hash).apply() + if img_url: + await image.update(img_url=img_url).apply() + if tags: + await image.update(tags=tags).apply() + return True + return False + + @classmethod + async def get_all_setu(cls) -> List["Setu"]: + """ + 说明: + 获取所有图片对象 + """ + return await cls.query.gino.all() + diff --git a/plugins/send_setu_/send_setu/__init__.py b/plugins/send_setu_/send_setu/__init__.py index e06bde93..0c52de0a 100755 --- a/plugins/send_setu_/send_setu/__init__.py +++ b/plugins/send_setu_/send_setu/__init__.py @@ -8,11 +8,10 @@ from typing import Optional, Type from gino.exceptions import UninitializedError from utils.utils import ( is_number, - get_message_text, get_message_img, ) from nonebot.typing import T_State -from nonebot.adapters.cqhttp import ( +from nonebot.adapters.onebot.v11 import ( Bot, MessageEvent, GroupMessageEvent, @@ -31,9 +30,11 @@ from .data_source import ( add_data_to_database, get_setu_count, ) -from nonebot.adapters.cqhttp.exception import ActionFailed +from nonebot.adapters.onebot.v11.exception import ActionFailed from configs.config import Config, NICKNAME from utils.manager import withdraw_message_manager +from nonebot.params import CommandArg, Command +from typing import Tuple import re try: @@ -87,30 +88,17 @@ __plugin_configs__ = { "INITIAL_SETU_PROBABILITY": { "value": 0.7, "help": "初始色图概率,总概率 = 初始色图概率 + 好感度", - "default_value": 0.7 + "default_value": 0.7, }, "DOWNLOAD_SETU": { "value": True, "help": "是否存储下载的色图,使用本地色图可以加快图片发送速度", - "default_value": True + "default_value": True, }, - "TIMEOUT": { - "value": 10, - "help": "色图下载超时限制(秒)", - "default_value": 10 - }, - "SHOW_INFO": { - "value": True, - "help": "是否显示色图的基本信息,如PID等", - "default_value": True - } + "TIMEOUT": {"value": 10, "help": "色图下载超时限制(秒)", "default_value": 10}, + "SHOW_INFO": {"value": True, "help": "是否显示色图的基本信息,如PID等", "default_value": True}, } -Config.add_plugin_config( - "pixiv", - "PIXIV_NGINX_URL", - "i.pixiv.re", - help_="Pixiv反向代理" -) +Config.add_plugin_config("pixiv", "PIXIV_NGINX_URL", "i.pixiv.re", help_="Pixiv反向代理") setu_data_list = [] @@ -125,7 +113,7 @@ async def do_something( ): global setu_data_list if isinstance(event, MessageEvent): - if matcher.module == "send_setu": + if matcher.plugin_name == "send_setu": # 添加数据至数据库 try: await add_data_to_database(setu_data_list) @@ -141,12 +129,12 @@ setu = on_command( setu_reg = on_regex("(.*)[份|发|张|个|次|点](.*)[瑟|色|涩]图$", priority=5, block=True) -find_setu = on_command("查色图", priority=5, block=True) - @setu.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _( + event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg() +): + msg = arg.extract_plain_text().strip() if isinstance(event, GroupMessageEvent): impression = ( await SignGroupUser.ensure(event.user_id, event.group_id) @@ -157,14 +145,10 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): r18 = 0 num = 1 # 是否看r18 - if state["_prefix"]["raw_command"] == "色图r" and isinstance( - event, PrivateMessageEvent - ): + if cmd[0] == "色图r" and isinstance(event, PrivateMessageEvent): r18 = 1 num = 10 - elif state["_prefix"]["raw_command"] == "色图r" and isinstance( - event, GroupMessageEvent - ): + elif cmd[0] == "色图r" and isinstance(event, GroupMessageEvent): await setu.finish( random.choice(["这种不好意思的东西怎么可能给这么多人看啦", "羞羞脸!给我滚出克私聊!", "变态变态变态变态大变态!"]) ) @@ -187,7 +171,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE"), ) return - await send_setu_handle(setu, event, state["_prefix"]["raw_command"], msg, num, r18) + await send_setu_handle(setu, event, cmd[0], msg, num, r18) num_key = { @@ -206,7 +190,7 @@ num_key = { @setu_reg.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent, arg: Message = CommandArg()): if isinstance(event, GroupMessageEvent): impression = ( await SignGroupUser.ensure(event.user_id, event.group_id) @@ -214,7 +198,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): luox = get_luoxiang(impression) if luox: await setu.finish(luox, at_sender=True) - msg = get_message_text(event.json()) + msg = arg.extract_plain_text().strip() num = 1 msg = re.search(r"(.*)[份发张个次点](.*)[瑟涩色]图", msg) # 解析 tags 以及 num @@ -239,31 +223,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): await send_setu_handle(setu_reg, event, "色图", tags, num, 0) -@find_setu.args_parser -async def _(bot: Bot, event: MessageEvent, state: T_State): - if str(event.message) == "取消": - await find_setu.finish("取消了操作", at_sender=True) - imgs = get_message_img(event.json()) - if not imgs: - await find_setu.reject("不搞错了,俺要图!") - state["img"] = imgs[0] - - -@find_setu.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - if get_message_text(event.json()) in ["帮助"]: - await find_setu.finish("通过图片获取本地色图id\n\t示例:查色图(图片)") - imgs = get_message_img(event.json()) - if imgs: - state["img"] = imgs[0] - - -@find_setu.got("img", prompt="速速来图!") -async def _(bot: Bot, event: MessageEvent, state: T_State): - img = state["img"] - await find_setu.send(await find_img_index(img, event.user_id), at_sender=True) - - async def send_setu_handle( matcher: Type[Matcher], event: MessageEvent, diff --git a/plugins/send_setu_/send_setu/data_source.py b/plugins/send_setu_/send_setu/data_source.py index 418813ed..cc7daee1 100755 --- a/plugins/send_setu_/send_setu/data_source.py +++ b/plugins/send_setu_/send_setu/data_source.py @@ -1,4 +1,4 @@ -from configs.path_config import IMAGE_PATH +from configs.path_config import IMAGE_PATH, TEMP_PATH from utils.message_builder import image from services.log import logger from utils.image_utils import get_img_hash, compressed_image @@ -7,7 +7,7 @@ from asyncio.exceptions import TimeoutError from typing import List, Optional from configs.config import NICKNAME, Config from utils.http_utils import AsyncHttpx -from ..model import Setu +from .._model import Setu import asyncio import os import random @@ -19,8 +19,8 @@ except ModuleNotFoundError: url = "https://api.lolicon.app/setu/v2" -path = "_setu/" -r18_path = "_r18/" +path = "_setu" +r18_path = "_r18" # 获取url @@ -93,13 +93,12 @@ async def search_online_setu( logger.info(f"search_online_setu --> {i}") try: index = random.randint(1, 100000) if id_ is None else id_ - path_ = "temp" if not path_ else path_ - file = f"{index}_temp_setu.jpg" if not path_ else f"{index}.jpg" - if not os.path.exists(f"{IMAGE_PATH}/{path_}"): - os.mkdir(f"{IMAGE_PATH}/{path_}") + path_ = IMAGE_PATH / path_ if path_ else TEMP_PATH + file_name = f"{index}_temp_setu.jpg" if not path_ == TEMP_PATH else f"{index}.jpg" + path_.mkdir(parents=True, exist_ok=True) if not await AsyncHttpx.download_file( url_, - f"{IMAGE_PATH}/{path_}/{file}", + path_ / file_name, timeout=Config.get_config("send_setu", "TIMEOUT"), ): continue @@ -111,8 +110,8 @@ async def search_online_setu( compressed_image( f"{IMAGE_PATH}/{path_}/{index}.jpg", ) - logger.info(f"下载 lolicon图片 {url_} 成功, id:{index}") - return image(file, path_), index + logger.info(f"下载 lolicon 图片 {url_} 成功, id:{index}") + return image(abspath=path_ / file_name), index except TimeoutError: pass except Exception as e: @@ -126,11 +125,9 @@ async def check_local_exists_or_download(setu_image: Setu) -> "MessageSegment, i id_ = None if Config.get_config("send_setu", "DOWNLOAD_SETU"): id_ = setu_image.local_id - if setu_image.is_r18: - path_ = "_r18" - else: - path_ = path - if os.path.exists(f"{IMAGE_PATH}/{path_}/{setu_image.local_id}.jpg"): + path_ = r18_path if setu_image.is_r18 else path + file = IMAGE_PATH / path_ / f"{setu_image.local_id}.jpg" + if file.exists(): return image(f"{setu_image.local_id}.jpg", path_), 200 return await search_online_setu(setu_image.img_url, id_, path_) @@ -202,7 +199,7 @@ def get_luoxiang(impression): if probability < random.randint(1, 101): return ( "我为什么要给你发这个?" - + image(random.choice(os.listdir(IMAGE_PATH + "luoxiang/")), "luoxiang") + + image(random.choice(os.listdir(IMAGE_PATH / "luoxiang")), "luoxiang") + f"\n(快向{NICKNAME}签到提升好感度吧!)" ) return None @@ -219,11 +216,11 @@ async def get_setu_count(r18: int) -> int: async def find_img_index(img_url, user_id): if not await AsyncHttpx.download_file( img_url, - IMAGE_PATH + f"temp/{user_id}_find_setu_index.jpg", + TEMP_PATH / f"{user_id}_find_setu_index.jpg", timeout=Config.get_config("send_setu", "TIMEOUT"), ): return "检索图片下载上失败..." - img_hash = str(get_img_hash(IMAGE_PATH + f"temp/{user_id}_find_setu_index.jpg")) + img_hash = str(get_img_hash(TEMP_PATH / f"{user_id}_find_setu_index.jpg")) setu_img = await Setu.get_image_in_hash(img_hash) if setu_img: return ( diff --git a/plugins/send_setu_/update_setu/__init__.py b/plugins/send_setu_/update_setu/__init__.py index 747185df..5c955a27 100755 --- a/plugins/send_setu_/update_setu/__init__.py +++ b/plugins/send_setu_/update_setu/__init__.py @@ -1,8 +1,6 @@ from utils.utils import scheduler from nonebot import on_command from nonebot.permission import SUPERUSER -from nonebot.typing import T_State -from nonebot.adapters import Bot, Event from nonebot.rule import to_me from .data_source import update_setu_img from configs.config import Config @@ -29,7 +27,7 @@ update_setu = on_command( @update_setu.handle() -async def _(bot: Bot, event: Event, state: T_State): +async def _(): if Config.get_config("send_setu", "DOWNLOAD_SETU"): await update_setu.send("开始更新色图...", at_sender=True) await update_setu_img(True) diff --git a/plugins/send_setu_/update_setu/data_source.py b/plugins/send_setu_/update_setu/data_source.py index c5a7752b..309b426c 100755 --- a/plugins/send_setu_/update_setu/data_source.py +++ b/plugins/send_setu_/update_setu/data_source.py @@ -4,11 +4,10 @@ from datetime import datetime from utils.image_utils import compressed_image, get_img_hash from utils.utils import get_bot from PIL import UnidentifiedImageError -from ..model import Setu +from .._model import Setu from asyncpg.exceptions import UniqueViolationError from configs.config import Config from utils.http_utils import AsyncHttpx -from pathlib import Path from nonebot import Driver import nonebot import os @@ -17,13 +16,13 @@ import shutil driver: Driver = nonebot.get_driver() -_path = Path(IMAGE_PATH) +_path = IMAGE_PATH # 替换旧色图数据,修复local_id一直是50的问题 @driver.on_startup async def update_old_setu_data(): - path = Path(TEXT_PATH) + path = TEXT_PATH setu_data_file = path / "setu_data.json" r18_data_file = path / "r18_setu_data.json" if setu_data_file.exists() or r18_data_file.exists(): @@ -79,9 +78,9 @@ async def update_old_setu_data(): # 删除色图rar文件夹 -shutil.rmtree(Path(IMAGE_PATH) / "setu_rar", ignore_errors=True) -shutil.rmtree(Path(IMAGE_PATH) / "r18_rar", ignore_errors=True) -shutil.rmtree(Path(IMAGE_PATH) / "rar", ignore_errors=True) +shutil.rmtree(IMAGE_PATH / "setu_rar", ignore_errors=True) +shutil.rmtree(IMAGE_PATH / "r18_rar", ignore_errors=True) +shutil.rmtree(IMAGE_PATH / "rar", ignore_errors=True) headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;" @@ -104,12 +103,11 @@ async def update_setu_img(flag: bool = False): for image in image_list: count += 1 path = _path / "_r18" if image.is_r18 else _path / "_setu" - rar_path = Path(TEMP_PATH) local_image = path / f"{image.local_id}.jpg" path.mkdir(exist_ok=True, parents=True) - rar_path.mkdir(exist_ok=True, parents=True) + TEMP_PATH.mkdir(exist_ok=True, parents=True) if not local_image.exists() or not image.img_hash: - temp_file = rar_path / f"{image.local_id}.jpg" + temp_file = TEMP_PATH / f"{image.local_id}.jpg" if temp_file.exists(): temp_file.unlink() url_ = image.img_url @@ -120,29 +118,29 @@ async def update_setu_img(flag: bool = False): ) try: if not await AsyncHttpx.download_file( - url_, rar_path / f"{image.local_id}.jpg" + url_, TEMP_PATH / f"{image.local_id}.jpg" ): continue _success += 1 try: if ( os.path.getsize( - rar_path / f"{image.local_id}.jpg", + TEMP_PATH / f"{image.local_id}.jpg", ) > 1024 * 1024 * 1.5 ): compressed_image( - rar_path / f"{image.local_id}.jpg", + TEMP_PATH / f"{image.local_id}.jpg", path / f"{image.local_id}.jpg", ) else: logger.info( - f"不需要压缩,移动图片{rar_path}/{image.local_id}.jpg " + f"不需要压缩,移动图片{TEMP_PATH}/{image.local_id}.jpg " f"--> /{path}/{image.local_id}.jpg" ) os.rename( - f"{rar_path}/{image.local_id}.jpg", - f"{path}/{image.local_id}.jpg", + TEMP_PATH / f"/{image.local_id}.jpg", + path / f"{image.local_id}.jpg", ) except FileNotFoundError: logger.warning(f"文件 {image.local_id}.jpg 不存在,跳过...") diff --git a/plugins/server_ip.py b/plugins/server_ip.py index adbd041c..8045afff 100644 --- a/plugins/server_ip.py +++ b/plugins/server_ip.py @@ -1,5 +1,5 @@ from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, PrivateMessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import Bot, PrivateMessageEvent, GroupMessageEvent from nonebot.typing import T_State from nonebot.rule import to_me diff --git a/plugins/sign_in/__init__.py b/plugins/sign_in/__init__.py index 37edbefe..d35fd87c 100755 --- a/plugins/sign_in/__init__.py +++ b/plugins/sign_in/__init__.py @@ -5,12 +5,12 @@ from .group_user_checkin import ( impression_rank, check_in_all ) -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from nonebot.adapters.cqhttp.permission import GROUP +from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message +from nonebot.adapters.onebot.v11.permission import GROUP from utils.message_builder import image from nonebot import on_command -from utils.utils import get_message_text, scheduler +from utils.utils import scheduler +from nonebot.params import CommandArg from pathlib import Path from configs.path_config import DATA_PATH from services.log import logger @@ -85,20 +85,19 @@ total_sign_rank = on_command( @sign.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - nickname = event.sender.card if event.sender.card else event.sender.nickname +async def _(event: GroupMessageEvent, arg: Message = CommandArg()): + nickname = event.sender.card or event.sender.nickname await sign.send( await group_user_check_in(nickname, event.user_id, event.group_id), at_sender=True, ) - if get_message_text(event.json()) == "all": + if arg.extract_plain_text().strip() == "all": await check_in_all(nickname, event.user_id) - @my_sign.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - nickname = event.sender.card if event.sender.card else event.sender.nickname +async def _(event: GroupMessageEvent): + nickname = event.sender.card or event.sender.nickname await my_sign.send( await group_user_check(nickname, event.user_id, event.group_id), at_sender=True, @@ -106,8 +105,8 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @sign_rank.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - num = get_message_text(event.json()) +async def _(event: GroupMessageEvent, arg: Message = CommandArg()): + num = arg.extract_plain_text().strip() if is_number(num) and 51 > int(num) > 10: num = int(num) else: @@ -118,8 +117,8 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @total_sign_rank.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(event: GroupMessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() if not msg: await total_sign_rank.send("请稍等..正在整理数据...") await total_sign_rank.send(image(b64=await impression_rank(0, data))) diff --git a/plugins/sign_in/config.py b/plugins/sign_in/config.py index 1bfa7a30..025de8dd 100755 --- a/plugins/sign_in/config.py +++ b/plugins/sign_in/config.py @@ -1,11 +1,10 @@ from configs.path_config import IMAGE_PATH -from pathlib import Path -SIGN_RESOURCE_PATH = Path(IMAGE_PATH) / 'sign' / 'sign_res' -SIGN_TODAY_CARD_PATH = Path(IMAGE_PATH) / 'sign' / 'today_card' -SIGN_BORDER_PATH = Path(SIGN_RESOURCE_PATH) / 'border' -SIGN_BACKGROUND_PATH = Path(SIGN_RESOURCE_PATH) / 'background' +SIGN_RESOURCE_PATH = IMAGE_PATH / 'sign' / 'sign_res' +SIGN_TODAY_CARD_PATH = IMAGE_PATH / 'sign' / 'today_card' +SIGN_BORDER_PATH = SIGN_RESOURCE_PATH / 'border' +SIGN_BACKGROUND_PATH = SIGN_RESOURCE_PATH / 'background' SIGN_BORDER_PATH.mkdir(exist_ok=True, parents=True) SIGN_BACKGROUND_PATH.mkdir(exist_ok=True, parents=True) diff --git a/plugins/sign_in/group_user_checkin.py b/plugins/sign_in/group_user_checkin.py index fb12adbf..52ec4c6f 100755 --- a/plugins/sign_in/group_user_checkin.py +++ b/plugins/sign_in/group_user_checkin.py @@ -3,7 +3,7 @@ from models.sign_group_user import SignGroupUser 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 nonebot.adapters.onebot.v11 import MessageSegment from utils.image_utils import BuildImage, BuildMat from services.db_context import db from .utils import get_card, SIGN_TODAY_CARD_PATH diff --git a/plugins/sign_in/utils.py b/plugins/sign_in/utils.py index 10dff67b..a73f7655 100755 --- a/plugins/sign_in/utils.py +++ b/plugins/sign_in/utils.py @@ -10,7 +10,7 @@ from .config import ( ) from models.sign_group_user import SignGroupUser from models.group_member_info import GroupInfoUser -from nonebot.adapters.cqhttp import MessageSegment +from nonebot.adapters.onebot.v11 import MessageSegment from configs.config import Config from utils.utils import get_user_avatar from utils.image_utils import BuildImage diff --git a/plugins/statistics/__init__.py b/plugins/statistics/__init__.py index 644a544e..4ed43619 100755 --- a/plugins/statistics/__init__.py +++ b/plugins/statistics/__init__.py @@ -1,4 +1,3 @@ -from pathlib import Path from configs.path_config import DATA_PATH import nonebot import os @@ -9,9 +8,9 @@ except ModuleNotFoundError: nonebot.load_plugins("plugins/statistics") -old_file1 = Path(DATA_PATH) / "_prefix_count.json" -old_file2 = Path(DATA_PATH) / "_prefix_user_count.json" -new_path = Path(DATA_PATH) / "statistics" +old_file1 = DATA_PATH / "_prefix_count.json" +old_file2 = DATA_PATH / "_prefix_user_count.json" +new_path = DATA_PATH / "statistics" new_path.mkdir(parents=True, exist_ok=True) if old_file1.exists(): os.rename(old_file1, new_path / "_prefix_count.json") @@ -21,8 +20,8 @@ if old_file2.exists(): # 修改旧数据 -statistics_group_file = Path(DATA_PATH) / "statistics" / "_prefix_count.json" -statistics_user_file = Path(DATA_PATH) / "statistics" / "_prefix_user_count.json" +statistics_group_file = DATA_PATH / "statistics" / "_prefix_count.json" +statistics_user_file = DATA_PATH / "statistics" / "_prefix_user_count.json" for file in [statistics_group_file, statistics_user_file]: if file.exists(): diff --git a/plugins/statistics/statistics_handle.py b/plugins/statistics/statistics_handle.py index e54e8a8f..e83f4e18 100755 --- a/plugins/statistics/statistics_handle.py +++ b/plugins/statistics/statistics_handle.py @@ -1,13 +1,12 @@ from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent, Message from models.group_info import GroupInfo -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 nonebot.params import CommandArg, Command from utils.image_utils import BuildMat from utils.message_builder import image from utils.manager import plugins2settings_manager +from typing import Tuple import asyncio import os @@ -85,27 +84,27 @@ statistics = on_command( ) -statistics_group_file = Path(DATA_PATH) / "statistics" / "_prefix_count.json" -statistics_user_file = Path(DATA_PATH) / "statistics" / "_prefix_user_count.json" +statistics_group_file = DATA_PATH / "statistics" / "_prefix_count.json" +statistics_user_file = DATA_PATH / "statistics" / "_prefix_user_count.json" @statistics.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) - if state["_prefix"]["raw_command"][:2] == "全局": +async def _(bot: Bot, event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() + if cmd[0][:2] == "全局": if str(event.user_id) in bot.config.superusers: data: dict = json.load(open(statistics_group_file, "r", encoding="utf8")) - if state["_prefix"]["raw_command"][2] == '日': - itype = 'day_statistics' - elif state["_prefix"]["raw_command"][2] == '周': - itype = 'week_statistics' - elif state["_prefix"]["raw_command"][2] == '月': - itype = 'month_statistics' + if cmd[0][2] == '日': + _type = 'day_statistics' + elif cmd[0][2] == '周': + _type = 'week_statistics' + elif cmd[0][2] == '月': + _type = 'month_statistics' else: - itype = 'total_statistics' + _type = 'total_statistics' tmp_dict = {} - data = data[itype] - if itype in ["day_statistics", "total_statistics"]: + data = data[_type] + if _type in ["day_statistics", "total_statistics"]: for key in data['total']: tmp_dict[key] = data['total'][key] else: @@ -118,29 +117,30 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): tmp_dict[plugin_name] = 1 else: tmp_dict[plugin_name] += data[group][day][plugin_name] - bar_graph = await init_bar_graph(tmp_dict, state["_prefix"]["raw_command"]) + bar_graph = await init_bar_graph(tmp_dict, cmd[0]) await asyncio.get_event_loop().run_in_executor(None, bar_graph.gen_graph) await statistics.finish(image(b64=bar_graph.pic2bs4())) return - if state["_prefix"]["raw_command"][:2] == "我的": - itype = "user" + if cmd[0][:2] == "我的": + _type = "user" key = str(event.user_id) - state["_prefix"]["raw_command"] = state["_prefix"]["raw_command"][2:] + cmd = list(cmd) + cmd[0] = cmd[0][2:] if not statistics_user_file.exists(): await statistics.finish("统计文件不存在...", at_sender=True) else: if not isinstance(event, GroupMessageEvent): await statistics.finish("请在群内调用此功能...") - itype = "group" + _type = "group" key = str(event.group_id) if not statistics_group_file.exists(): await statistics.finish("统计文件不存在...", at_sender=True) plugin = "" - if state["_prefix"]["raw_command"][0] == "日": + if cmd[0][0] == "日": arg = "day_statistics" - elif state["_prefix"]["raw_command"][0] == "周": + elif cmd[0][0] == "周": arg = "week_statistics" - elif state["_prefix"]["raw_command"][0] == "月": + elif cmd[0][0] == "月": arg = "month_statistics" else: arg = "total_statistics" @@ -149,7 +149,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): if not plugin: if arg not in ["day_statistics", "total_statistics"]: await statistics.finish("未找到此功能的调用...", at_sender=True) - if itype == "group": + if _type == "group": data: dict = json.load(open(statistics_group_file, "r", encoding="utf8")) if not data[arg].get(str(event.group_id)): await statistics.finish("该群统计数据不存在...", at_sender=True) @@ -159,11 +159,11 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): await statistics.finish("该用户统计数据不存在...", at_sender=True) day_index = data["day_index"] data = data[arg][key] - if itype == "group": + if _type == "group": name = await GroupInfo.get_group_info(event.group_id) name = name.group_name if name else str(event.group_id) else: - name = event.sender.card if event.sender.card else event.sender.nickname + name = event.sender.card or event.sender.nickname img = await generate_statistics_img(data, arg, name, plugin, day_index) await statistics.send(image(b64=img)) diff --git a/plugins/statistics/statistics_hook.py b/plugins/statistics/statistics_hook.py index c94622c9..77102a9c 100755 --- a/plugins/statistics/statistics_hook.py +++ b/plugins/statistics/statistics_hook.py @@ -2,7 +2,7 @@ from configs.path_config import DATA_PATH from nonebot.matcher import Matcher from nonebot.message import run_postprocessor from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent from datetime import datetime from utils.manager import plugins2settings_manager from utils.utils import scheduler @@ -19,8 +19,8 @@ __zx_plugin_name__ = "功能调用统计 [Hidden]" __plugin_version__ = 0.1 __plugin_author__ = "HibiKier" -statistics_group_file = Path(DATA_PATH) / "statistics" / "_prefix_count.json" -statistics_user_file = Path(DATA_PATH) / "statistics" / "_prefix_user_count.json" +statistics_group_file = DATA_PATH / "statistics" / "_prefix_count.json" +statistics_user_file = DATA_PATH / "statistics" / "_prefix_user_count.json" try: with open(statistics_group_file, "r", encoding="utf8") as f: @@ -97,9 +97,9 @@ async def _( if ( matcher.type == "message" and matcher.priority not in [1, 9] - and matcher.module not in ["update_info", "statistics_handle"] + and matcher.plugin_name not in ["update_info", "statistics_handle"] ): - module = matcher.module + module = matcher.plugin_name day_index = _prefix_count_dict["day_index"] try: group_id = str(event.group_id) diff --git a/plugins/translate/__init__.py b/plugins/translate/__init__.py index d29189f3..9cf137d5 100755 --- a/plugins/translate/__init__.py +++ b/plugins/translate/__init__.py @@ -1,7 +1,7 @@ from nonebot import on_command -from utils.utils import get_message_text +from nonebot.params import CommandArg from services.log import logger -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message from nonebot.typing import T_State from .data_source import translate_msg @@ -37,14 +37,14 @@ translate = on_command( @translate.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(state: T_State, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() if msg: state["msg"] = msg @translate.got("msg", prompt="你要翻译的消息是啥?") -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent, state: T_State): msg = state["msg"] if len(msg) > 150: await translate.finish("翻译过长!请不要超过150字", at_sender=True) diff --git a/plugins/update_gocqhttp/__init__.py b/plugins/update_gocqhttp/__init__.py index ba6e7ed8..41750f5c 100755 --- a/plugins/update_gocqhttp/__init__.py +++ b/plugins/update_gocqhttp/__init__.py @@ -1,6 +1,6 @@ from nonebot import on_command from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent from .data_source import download_gocq_lasted, upload_gocq_lasted from services.log import logger from utils.utils import scheduler, get_bot diff --git a/plugins/update_picture.py b/plugins/update_picture.py index 56d70e81..8433b7e2 100755 --- a/plugins/update_picture.py +++ b/plugins/update_picture.py @@ -1,17 +1,17 @@ from nonebot import on_command from PIL import Image, ImageFilter from utils.message_builder import image -from configs.path_config import IMAGE_PATH +from configs.path_config import TEMP_PATH, IMAGE_PATH from services.log import logger from nonebot.rule import to_me -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message from nonebot.typing import T_State -from utils.utils import get_message_img -from pathlib import Path -from utils.utils import is_number, get_message_text +from utils.utils import get_message_img, is_number +from nonebot.params import CommandArg, Arg, ArgStr, Depends from utils.image_utils import BuildImage, pic2b64 from configs.config import NICKNAME from utils.http_utils import AsyncHttpx +from typing import Union import cv2 import numpy as np @@ -57,7 +57,6 @@ __plugin_settings__ = { "cmd": ["修改图片", "改图", "操作图片"], } -# IMAGE_LOCAL = IMAGE_PATH + "temp/{}_update.png" method_flag = "" update_img = on_command( @@ -85,85 +84,65 @@ for i in range(len(method_list)): 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") +update_img_help.save(IMAGE_PATH / "update_img_help.png") -@update_img.args_parser -async def _(bot: Bot, event: MessageEvent, state: T_State): - global method_flag - if str(event.get_message()) in ["取消", "算了"]: - await update_img.finish("已取消操作..", at_sender=True) - if state["_current_key"] in ["method"]: - if str(event.get_message()) not in method_oper: - await update_img.reject(f"操作不正确,请重新输入!{method_str}") - state[state["_current_key"]] = str(event.get_message()) - method_flag = str(event.get_message()) - if method_flag in ["1", "修改尺寸"]: - if state["_current_key"] == "x": - if not is_number(str(event.get_message())): - await update_img.reject("宽度不正确!请重新输入数字...") - state[state["_current_key"]] = str(event.get_message()) - if state["_current_key"] == "y": - if not is_number(str(event.get_message())): - await update_img.reject("长度不正确!请重新输入数字...") - state[state["_current_key"]] = str(event.get_message()) - elif method_flag in ["2", "等比压缩", "3", "旋转图片"]: - if state["_current_key"] == "x": - if not is_number(str(event.get_message())): - await update_img.reject("比率不正确!请重新输入数字...") - state[state["_current_key"]] = str(event.get_message()) - state["y"] = "" - elif method_flag in [ - "4", - "水平翻转", - "5", - "铅笔滤镜", - "6", - "模糊效果", - "7", - "锐化效果", - "8", - "高斯模糊", - "9", - "边缘检测", - ]: - state["x"] = "" - state["y"] = "" - elif method_flag in ["10", "底色替换"]: - if state["_current_key"] == "x": - if str(event.get_message()) not in ["红色", "蓝色", "红", "蓝"]: - await update_img.reject("请输入支持的被替换的底色:\n红色 蓝色") - state["x"] = str(event.get_message()) - if state["_current_key"] == "y": - if str(event.get_message()) not in [ - "红色", - "白色", - "蓝色", - "绿色", - "黄色", - "红", - "白", - "蓝", - "绿", - "黄", - ]: - await update_img.reject("请输入支持的替换的底色:\n红色 蓝色 白色 绿色") - state["y"] = str(event.get_message()) - if state["_current_key"] == "imgs": - if not get_message_img(event.json()): - await update_img.reject("没图?没图?没图?来图速来!") - state[state["_current_key"]] = get_message_img(event.json()) +def parse_key(key: str): + async def _key_parser( + state: T_State, inp: Union[Message, str] = Arg(key) + ): + if key != "img_list" and isinstance(inp, Message): + inp = inp.extract_plain_text().strip() + if inp in ["取消", "算了"]: + await update_img.finish("已取消操作..") + if key == "method": + if inp not in method_oper: + await update_img.reject_arg("method", f"操作不正确,请重新输入!{method_str}") + elif key == "x": + method = state["method"] + if method in ["1", "修改尺寸"]: + if not is_number(inp) or int(inp) < 1: + await update_img.reject_arg("x", "宽度不正确!请重新输入数字...") + elif method in ["2", "等比压缩", "3", "旋转图片"]: + if not is_number(inp): + await update_img.reject_arg("x", "比率不正确!请重新输入数字...") + elif method in ["10", "底色替换"]: + if inp not in ["红色", "蓝色", "红", "蓝"]: + await update_img.reject_arg("x", "请输入支持的被替换的底色:\n红色 蓝色") + elif key == "y": + method = state["method"] + if method in ["1", "修改尺寸"]: + if not is_number(inp) or int(inp) < 1: + await update_img.reject_arg("y", "长度不正确!请重新输入数字...") + elif method in ["10", "底色替换"]: + if inp not in [ + "红色", + "白色", + "蓝色", + "绿色", + "黄色", + "红", + "白", + "蓝", + "绿", + "黄", + ]: + await update_img.reject_arg("y", "请输入支持的替换的底色:\n红色 蓝色 白色 绿色") + elif key == "img_list": + if not get_message_img(inp): + await update_img.reject_arg("img_list", "没图?没图?没图?来图速来!") + state[key] = inp + return _key_parser @update_img.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent, state: T_State, arg: Message = CommandArg()): if str(event.get_message()) in ["帮助"]: await update_img.finish(image("update_img_help.png")) - raw_arg = get_message_text(event.json()) + raw_arg = arg.extract_plain_text().strip() img_list = get_message_img(event.json()) if raw_arg: - args = raw_arg.split("[")[0].split(" ") - print(args) + args = raw_arg.split("[")[0].split() state["method"] = args[0] if len(args) == 2: if args[0] in ["等比压缩", "旋转图片"]: @@ -185,18 +164,24 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): state["x"] = "" state["y"] = "" if img_list: - state["imgs"] = img_list + state["img_list"] = event.message -@update_img.got("method", prompt=f"要使用图片的什么操作呢?{method_str}") -@update_img.got("x", prompt="[宽度? 比率? 旋转角度? 底色?]") -@update_img.got("y", prompt="[长度? 0 0 底色?]") -@update_img.got("imgs", prompt="图呢图呢图呢图呢?GKD!") -async def _(bot: Bot, event: MessageEvent, state: T_State): - method = state["method"] - x = state["x"] if state["x"] else "" - y = state["y"] if state["y"] else "" - img_list = state["imgs"] +@update_img.got("method", prompt=f"要使用图片的什么操作呢?{method_str}", parameterless=[Depends(parse_key("method"))]) +@update_img.got("x", prompt="[宽度? 比率? 旋转角度? 底色?]", parameterless=[Depends(parse_key("x"))]) +@update_img.got("y", prompt="[长度? 0 0 底色?]", parameterless=[Depends(parse_key("y"))]) +@update_img.got("img_list", prompt="图呢图呢图呢图呢?GKD!", parameterless=[Depends(parse_key("img_list"))]) +async def _( + event: MessageEvent, + state: T_State, + method: str = ArgStr("method"), + x: str = ArgStr("x"), + y: str = ArgStr("y"), + img_list: Message = Arg("img_list"), +): + x = x or "" + y = y or "" + img_list = get_message_img(img_list) if is_number(x): x = float(x) if is_number(y): @@ -205,7 +190,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): result = "" for img_url in img_list: if await AsyncHttpx.download_file( - img_url, Path(IMAGE_PATH) / "temp" / f"{event.user_id}_{index}_update.png" + img_url, TEMP_PATH / f"{event.user_id}_{index}_update.png" ): index += 1 else: @@ -214,14 +199,14 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): return if method in ["修改尺寸", "1"]: for i in range(index): - img = Image.open(IMAGE_PATH + f"temp/{event.user_id}_{i}_update.png") + img = Image.open(TEMP_PATH / f"{event.user_id}_{i}_update.png") img = img.convert("RGB") img = img.resize((int(x), int(y)), Image.ANTIALIAS) result += image(b64=pic2b64(img)) await update_img.finish(result, at_sender=True) if method in ["等比压缩", "2"]: for i in range(index): - img = Image.open(IMAGE_PATH + f"temp/{event.user_id}_{i}_update.png") + img = Image.open(TEMP_PATH / f"{event.user_id}_{i}_update.png") width, height = img.size img = img.convert("RGB") if width * x < 8000 and height * x < 8000: @@ -231,43 +216,43 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): await update_img.finish(f"{NICKNAME}不支持图片压缩后宽或高大于8000的存在!!") if method in ["旋转图片", "3"]: for i in range(index): - img = Image.open(IMAGE_PATH + f"temp/{event.user_id}_{i}_update.png") + img = Image.open(TEMP_PATH / f"{event.user_id}_{i}_update.png") img = img.rotate(x) result += image(b64=pic2b64(img)) if method in ["水平翻转", "4"]: for i in range(index): - img = Image.open(IMAGE_PATH + f"temp/{event.user_id}_{i}_update.png") + img = Image.open(TEMP_PATH / f"{event.user_id}_{i}_update.png") img = img.transpose(Image.FLIP_LEFT_RIGHT) result += image(b64=pic2b64(img)) if method in ["铅笔滤镜", "5"]: for i in range(index): - img = Image.open( - IMAGE_PATH + f"temp/{event.user_id}_{i}_update.png" - ).filter(ImageFilter.CONTOUR) + img = Image.open(TEMP_PATH / f"{event.user_id}_{i}_update.png").filter( + ImageFilter.CONTOUR + ) result += image(b64=pic2b64(img)) if method in ["模糊效果", "6"]: for i in range(index): - img = Image.open( - IMAGE_PATH + f"temp/{event.user_id}_{i}_update.png" - ).filter(ImageFilter.BLUR) + img = Image.open(TEMP_PATH / f"temp/{event.user_id}_{i}_update.png").filter( + ImageFilter.BLUR + ) result += image(b64=pic2b64(img)) if method in ["锐化效果", "7"]: for i in range(index): - img = Image.open( - IMAGE_PATH + f"temp/{event.user_id}_{i}_update.png" - ).filter(ImageFilter.EDGE_ENHANCE) + img = Image.open(TEMP_PATH / f"{event.user_id}_{i}_update.png").filter( + ImageFilter.EDGE_ENHANCE + ) result += image(b64=pic2b64(img)) if method in ["高斯模糊", "8"]: for i in range(index): - img = Image.open( - IMAGE_PATH + f"temp/{event.user_id}_{i}_update.png" - ).filter(ImageFilter.GaussianBlur) + img = Image.open(TEMP_PATH / f"{event.user_id}_{i}_update.png").filter( + ImageFilter.GaussianBlur + ) result += image(b64=pic2b64(img)) if method in ["边缘检测", "9"]: for i in range(index): - img = Image.open( - IMAGE_PATH + f"temp/{event.user_id}_{i}_update.png" - ).filter(ImageFilter.FIND_EDGES) + img = Image.open(TEMP_PATH / f"{event.user_id}_{i}_update.png").filter( + ImageFilter.FIND_EDGES + ) result += image(b64=pic2b64(img)) if method in ["底色替换", "10"]: if x in ["蓝色", "蓝"]: @@ -287,7 +272,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): if y in ["黄色", "黄"]: color = (0, 255, 255) for k in range(index): - img = cv2.imread(IMAGE_PATH + f"temp/{event.user_id}_{k}_update.png") + img = cv2.imread(TEMP_PATH / f"{event.user_id}_{k}_update.png") img = cv2.resize(img, None, fx=0.3, fy=0.3) rows, cols, channels = img.shape hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) @@ -298,7 +283,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): for j in range(cols): if dilate[i, j] == 255: img[i, j] = color - cv2.imwrite(IMAGE_PATH + f"temp/{event.user_id}_{k}_ok_update.png", img) + cv2.imwrite(TEMP_PATH / f"{event.user_id}_{k}_ok_update.png", img) for i in range(index): result += image(f"{event.user_id}_{i}_ok_update.png", "temp") if is_number(method): diff --git a/plugins/weather/__init__.py b/plugins/weather/__init__.py index e65b1f63..aad24dd3 100755 --- a/plugins/weather/__init__.py +++ b/plugins/weather/__init__.py @@ -1,11 +1,10 @@ from nonebot import on_regex from .data_source import get_weather_of_city, get_city_list -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message from jieba import posseg from services.log import logger -from nonebot.typing import T_State +from nonebot.params import CommandArg import re -from utils.utils import get_message_text __zx_plugin_name__ = "天气查询" @@ -32,8 +31,8 @@ weather = on_regex(r".{0,10}市?的?天气.{0,10}", priority=5, block=True) @weather.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() msg1 = re.search(r".*?(.*)市?的?天气.*?", msg) msg2 = re.search(r".*?天气(.*).*?", msg) msg1 = msg1.group(1) diff --git a/plugins/weather/data_source.py b/plugins/weather/data_source.py index d5c39431..3e542aee 100755 --- a/plugins/weather/data_source.py +++ b/plugins/weather/data_source.py @@ -3,14 +3,13 @@ from configs.path_config import TEXT_PATH from configs.config import NICKNAME from typing import List from nonebot import Driver -from pathlib import Path from utils.http_utils import AsyncHttpx import ujson as json import nonebot driver: Driver = nonebot.get_driver() -china_city = Path(TEXT_PATH) / "china_city.json" +china_city = TEXT_PATH / "china_city.json" data = {} diff --git a/plugins/what_anime/__init__.py b/plugins/what_anime/__init__.py index 823551be..f7ecbc73 100755 --- a/plugins/what_anime/__init__.py +++ b/plugins/what_anime/__init__.py @@ -1,7 +1,8 @@ +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message, Bot from .data_source import get_anime from nonebot import on_command from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.params import Arg from utils.utils import get_message_img from services.log import logger @@ -29,28 +30,19 @@ __plugin_settings__ = { what_anime = on_command("识番", priority=5, block=True) -@what_anime.args_parser -async def _(bot: Bot, event: MessageEvent, state: T_State): - if str(event.get_message()) in ["取消", "算了"]: - await what_anime.finish("已取消操作..", at_sender=True) - img_url = get_message_img(event.json()) - if not img_url: - await what_anime.reject(prompt="图呢图呢图呢图呢GKD", at_sender=True) - state["img_url"] = img_url - - @what_anime.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): - if str(event.get_message()) in ["帮助"]: - await what_anime.finish(__plugin_usage__) img_url = get_message_img(event.json()) if img_url: - state["img_url"] = img_url + state["img_url"] = img_url[0] @what_anime.got("img_url", prompt="虚空识番?来图来图GKD") -async def _(bot: Bot, event: MessageEvent, state: T_State): - img_url = state["img_url"][0] +async def _(bot: Bot, event: MessageEvent, state: T_State, img_url: Message = Arg("img_url")): + img_url = get_message_img(img_url) + if not img_url: + await what_anime.reject_arg("img_url", "发送的必须是图片!") + img_url = img_url[0] await what_anime.send("开始识别.....") anime_data_report = await get_anime(img_url) if anime_data_report: @@ -63,6 +55,6 @@ 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'} 识番 {img_url} 未找到!!" + f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'} 识番 {img_url} 未找到" ) await what_anime.send(f"没有寻找到该番剧,果咩..", at_sender=True) diff --git a/plugins/white2black_image.py b/plugins/white2black_image.py index d453595c..e9643f4c 100755 --- a/plugins/white2black_image.py +++ b/plugins/white2black_image.py @@ -1,13 +1,12 @@ -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message from nonebot import on_command -from utils.utils import get_message_img, get_message_text, is_chinese +from nonebot.params import CommandArg +from utils.utils import get_message_img, is_chinese from utils.message_builder import image from configs.path_config import TEMP_PATH from utils.image_utils import BuildImage from services.log import logger from utils.http_utils import AsyncHttpx -from pathlib import Path # ZH_CN2EN 中文 » 英语 # ZH_CN2JA 中文 » 日语 @@ -45,19 +44,19 @@ w2b_img = on_command("黑白草图", aliases={"黑白图"}, priority=5, block=Tr @w2b_img.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): +async def _(event: MessageEvent, arg: Message = CommandArg()): # try: img = get_message_img(event.json()) - msg = get_message_text(event.json()) + msg = arg.extract_plain_text().strip() if not img or not msg: await w2b_img.finish(f"格式错误:\n" + __plugin_usage__) img = img[0] if not await AsyncHttpx.download_file( - img, Path(TEMP_PATH) / f"{event.user_id}_w2b.png" + img, TEMP_PATH / f"{event.user_id}_w2b.png" ): await w2b_img.finish("下载图片失败...请稍后再试...") msg = await get_translate(msg) - w2b = BuildImage(0, 0, background=Path(TEMP_PATH) / f"{event.user_id}_w2b.png") + w2b = BuildImage(0, 0, background=TEMP_PATH / f"{event.user_id}_w2b.png") w2b.convert("L") msg_sp = msg.split("<|>") w, h = w2b.size diff --git a/plugins/withdraw.py b/plugins/withdraw.py index 42319f59..068cf6ce 100755 --- a/plugins/withdraw.py +++ b/plugins/withdraw.py @@ -1,5 +1,5 @@ from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent from nonebot.typing import T_State import re @@ -27,4 +27,4 @@ withdraw_msg = on_command("撤回", priority=5, block=True) async def _(bot: Bot, event: GroupMessageEvent, state: T_State): r = re.search(r"\[CQ:reply,id=(-?\d*)]", event.raw_message) if r: - await bot.delete_msg(message_id=int(r.group(1)), self_id=int(bot.self_id)) + await bot.delete_msg(message_id=int(r.group(1))) diff --git a/plugins/word_bank/data_source.py b/plugins/word_bank/_data_source.py similarity index 100% rename from plugins/word_bank/data_source.py rename to plugins/word_bank/_data_source.py diff --git a/plugins/word_bank/rule.py b/plugins/word_bank/_rule.py similarity index 83% rename from plugins/word_bank/rule.py rename to plugins/word_bank/_rule.py index 9fa352c4..dcca5afe 100644 --- a/plugins/word_bank/rule.py +++ b/plugins/word_bank/_rule.py @@ -1,4 +1,4 @@ -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, Event +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Event from utils.utils import get_message_text from nonebot.typing import T_State from .model import WordBank diff --git a/plugins/word_bank/message_handle.py b/plugins/word_bank/message_handle.py index dd1ba97a..30000959 100644 --- a/plugins/word_bank/message_handle.py +++ b/plugins/word_bank/message_handle.py @@ -1,21 +1,16 @@ -from utils.utils import get_message_text from utils.message_builder import image, at -from .rule import check +from ._rule import check from .model import WordBank from configs.path_config import DATA_PATH -from pathlib import Path -from nonebot.adapters.cqhttp import ( - Bot, - GroupMessageEvent, -) -from nonebot.typing import T_State +from nonebot.adapters.onebot.v11 import GroupMessageEvent +from utils.utils import get_message_text from nonebot import on_message __zx_plugin_name__ = "词库问答回复操作 [Hidden]" -data_dir = Path(DATA_PATH) / "word_bank" +data_dir = DATA_PATH / "word_bank" data_dir.mkdir(parents=True, exist_ok=True) @@ -23,7 +18,7 @@ message_handle = on_message(priority=5, block=True, rule=check) @message_handle.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): +async def _(event: GroupMessageEvent): path = data_dir / f"{event.group_id}" q = await WordBank.check( event.group_id, get_message_text(event.json()), event.is_tome() diff --git a/plugins/word_bank/model.py b/plugins/word_bank/model.py index 06e8af9a..8b96128e 100644 --- a/plugins/word_bank/model.py +++ b/plugins/word_bank/model.py @@ -181,7 +181,7 @@ class WordBank(db.Model): elif type_ == "delete": q = await q.with_for_update().gino.all() if q: - path = Path(DATA_PATH) / "word_bank" / f"{group_id}" + path = DATA_PATH / "word_bank" / f"{group_id}" if index is not None: _q = [x.problem for x in q] _q.sort() diff --git a/plugins/word_bank/word_hanlde.py b/plugins/word_bank/word_hanlde.py index 268c4044..22d12708 100644 --- a/plugins/word_bank/word_hanlde.py +++ b/plugins/word_bank/word_hanlde.py @@ -1,20 +1,22 @@ -from utils.utils import get_message_at, is_number, get_message_img, get_message_text +from utils.utils import get_message_at, is_number, get_message_img +from nonebot.params import CommandArg from services.log import logger from configs.path_config import DATA_PATH from utils.http_utils import AsyncHttpx -from .data_source import WordBankBuilder +from ._data_source import WordBankBuilder from configs.config import Config from utils.message_builder import image from utils.image_utils import text2image from .model import WordBank -from nonebot.adapters.cqhttp import ( +from nonebot.adapters.onebot.v11 import ( Bot, GroupMessageEvent, + Message ) -from pathlib import Path from nonebot.typing import T_State from nonebot import on_command import random +import os import re __zx_plugin_name__ = "词库问答 [Admin]" @@ -47,7 +49,7 @@ __plugin_settings__ = { "cmd": ["词库问答", "添加词条", "删除词条", "查看词条"], } -data_dir = Path(DATA_PATH) / "word_bank" +data_dir = DATA_PATH / "word_bank" data_dir.mkdir(parents=True, exist_ok=True) @@ -59,8 +61,8 @@ 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() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State, arg: Message = CommandArg()): + msg = str(arg) r = re.search(r"^问(.+)\s?答([\s\S]*)", msg) if not r: await add_word.finish("未检测到词条问题...") @@ -72,11 +74,12 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): await add_word.finish("未检测到词条回答...") idx = 0 for n in bot.config.nickname: - if problem.startswith(n): + if n and problem.startswith(n): _problem = f"[_to_me|{n}]" + problem[len(n) :] break else: _problem = problem + (data_dir / f"{event.group_id}").mkdir(exist_ok=True, parents=True) _builder = WordBankBuilder(event.user_id, event.group_id, _problem) for at_ in get_message_at(event.json()): r = re.search(rf"\[CQ:at,qq={at_}]", answer) @@ -88,7 +91,11 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): _x = img.split("?")[0] r = re.search(rf"\[CQ:image,file=(.*),url={_x}.*?]", answer) if r: - rand = random.randint(1, 10000) + random.randint(1, 14514) + rand = random.randint(1, 10000) + random.randint(1, 114514) + for _ in range(10): + if f"__placeholder_{rand}_{idx}.jpg" not in os.listdir(data_dir / f"{event.group_id}"): + break + rand = random.randint(1, 10000) + random.randint(1, 114514) for i in range(3): answer = answer.replace(f",subType={i}", "") answer = answer.replace( @@ -107,8 +114,8 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @delete_word.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(event: GroupMessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() if not msg: await delete_word.finish("此命令之后需要跟随指定词条,通过“显示词条“查看") index = None @@ -142,8 +149,8 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): @show_word.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(event: GroupMessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() if not msg: _problem_list = await WordBank.get_group_all_problem(event.group_id) if not _problem_list: @@ -151,11 +158,11 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): _problem_list = [f"\t{i}. {x}" for i, x in enumerate(_problem_list)] await show_word.send( image( - b64=await text2image( + b64=(await text2image( "该群已收录的词条:\n\n" + "\n".join(_problem_list), padding=10, color="#f9f6f2", - ) + )).pic2bs4() ) ) else: diff --git a/plugins/yiqing/__init__.py b/plugins/yiqing/__init__.py index 5c0c6834..0b8ffc5e 100755 --- a/plugins/yiqing/__init__.py +++ b/plugins/yiqing/__init__.py @@ -1,9 +1,8 @@ from nonebot import on_command from .data_source import get_yiqing_data, get_city_and_province_list from services.log import logger -from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent -from nonebot.typing import T_State -from utils.utils import get_message_text +from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message +from nonebot.params import CommandArg from configs.config import NICKNAME from .other_than import get_other_data @@ -35,8 +34,8 @@ yiqing = on_command("疫情", aliases={"查询疫情", "疫情查询"}, priority @yiqing.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) +async def _(event: MessageEvent, arg: Message = CommandArg()): + msg = arg.extract_plain_text().strip() city_and_province_list = get_city_and_province_list() if msg: if msg in city_and_province_list or msg[:-1] in city_and_province_list: diff --git a/plugins/yiqing/data_source.py b/plugins/yiqing/data_source.py index 78bde6c5..540c343c 100755 --- a/plugins/yiqing/data_source.py +++ b/plugins/yiqing/data_source.py @@ -1,13 +1,12 @@ from configs.path_config import TEXT_PATH from typing import List, Union -from pathlib import Path from utils.http_utils import AsyncHttpx from utils.image_utils import text2image from utils.message_builder import image -from nonebot.adapters.cqhttp import MessageSegment +from nonebot.adapters.onebot.v11 import MessageSegment import ujson as json -china_city = Path(TEXT_PATH) / "china_city.json" +china_city = TEXT_PATH / "china_city.json" data = {} @@ -71,21 +70,21 @@ async def get_yiqing_data(area: str) -> Union[str, MessageSegment]: heal_rate = f"{heal / confirm * 100:.2f}" # 治愈率 x = f"{city}市" if city else f"{province}{province_type}" - return image(b64=await text2image( - f""" - {x} 疫情数据 {f"({grade})" if grade else ""}: + return image(b64=(await text2image( + f""" + {x} 疫情数据 {f"({grade})" if grade else ""}: 目前确诊: 确诊人数:{now_confirm}(+{add_confirm}) - ----------------- + ----------------- 累计数据: 确诊人数:{confirm} 治愈人数:{heal} 死亡人数:{dead} 治愈率:{heal_rate}% 死亡率:{dead_rate}% - 更新日期:{last_update_time} + 更新日期:{last_update_time} """, font_size=30, color="#f9f6f2" - )) + )).pic2bs4()) def get_city_and_province_list() -> List[str]: diff --git a/plugins/yiqing/other_than.py b/plugins/yiqing/other_than.py index d47a6d5f..28b5fca1 100644 --- a/plugins/yiqing/other_than.py +++ b/plugins/yiqing/other_than.py @@ -6,7 +6,7 @@ # @File : other_than.py # @Software: PyCharm from utils.http_utils import AsyncHttpx -from nonebot.adapters.cqhttp import MessageSegment +from nonebot.adapters.onebot.v11 import MessageSegment from typing import Optional from services.log import logger from utils.image_utils import text2image @@ -54,7 +54,7 @@ async def get_other_data(place: str, count: int = 0) -> Optional[MessageSegment] for country in other_country: if place == country["name2"]: return image( - b64=await text2image( + b64=(await text2image( f" {place} 疫情数据:\n" "——————————————\n" f" 新增病例:{intcomma(country['quezhen_add'])}\n" @@ -69,13 +69,13 @@ async def get_other_data(place: str, count: int = 0) -> Optional[MessageSegment] font_size=30, color="#f9f6f2", padding=15 - ) + )).pic2bs4() ) else: for city in country["child"]: if place == city["name3"]: return image( - b64=await text2image( + b64=(await text2image( f"\n{place} 疫情数据:\n" "——————————————\n" f"\t新增病例:{intcomma(city['quezhen_add'])}\n" @@ -86,7 +86,7 @@ async def get_other_data(place: str, count: int = 0) -> Optional[MessageSegment] font_size=30, color="#f9f6f2", padding=15 - ) + )).pic2bs4() ) except Exception as e: logger.error(f"疫情查询发生错误 {type(e)}:{e}") diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..dfa162c0 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,2202 @@ +[[package]] +name = "aiofiles" +version = "0.8.0" +description = "File support for asyncio." +category = "main" +optional = false +python-versions = ">=3.6,<4.0" + +[[package]] +name = "aiohttp" +version = "3.7.4.post0" +description = "Async http client/server framework (asyncio)" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +async-timeout = ">=3.0,<4.0" +attrs = ">=17.3.0" +chardet = ">=2.0,<5.0" +multidict = ">=4.5,<7.0" +typing-extensions = ">=3.6.5" +yarl = ">=1.0,<2.0" + +[package.extras] +speedups = ["aiodns", "brotlipy", "cchardet"] + +[[package]] +name = "anyio" +version = "3.5.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +category = "main" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +doc = ["packaging", "sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] +test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=6.0)", "pytest-mock (>=3.6.1)", "trustme", "contextlib2", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] +trio = ["trio (>=0.16)"] + +[[package]] +name = "apscheduler" +version = "3.8.1" +description = "In-process task scheduler with Cron-like capabilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.dependencies] +pytz = "*" +six = ">=1.4.0" +tzlocal = ">=2.0,<3.0.0 || >=4.0.0" + +[package.extras] +asyncio = ["trollius"] +doc = ["sphinx", "sphinx-rtd-theme"] +gevent = ["gevent"] +mongodb = ["pymongo (>=3.0)"] +redis = ["redis (>=3.0)"] +rethinkdb = ["rethinkdb (>=2.4.0)"] +sqlalchemy = ["sqlalchemy (>=0.8)"] +testing = ["pytest (<6)", "pytest-cov", "pytest-tornado5", "mock", "pytest-asyncio (<0.6)", "pytest-asyncio"] +tornado = ["tornado (>=4.3)"] +twisted = ["twisted"] +zookeeper = ["kazoo"] + +[[package]] +name = "asgiref" +version = "3.5.0" +description = "ASGI specs, helper code, and adapters" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] + +[[package]] +name = "async-timeout" +version = "3.0.1" +description = "Timeout context manager for asyncio programs" +category = "main" +optional = false +python-versions = ">=3.5.3" + +[[package]] +name = "asyncpg" +version = "0.25.0" +description = "An asyncio PostgreSQL driver" +category = "main" +optional = false +python-versions = ">=3.6.0" + +[package.extras] +dev = ["Cython (>=0.29.24,<0.30.0)", "pytest (>=6.0)", "Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "pycodestyle (>=2.7.0,<2.8.0)", "flake8 (>=3.9.2,<3.10.0)", "uvloop (>=0.15.3)"] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)"] +test = ["pycodestyle (>=2.7.0,<2.8.0)", "flake8 (>=3.9.2,<3.10.0)", "uvloop (>=0.15.3)"] + +[[package]] +name = "attrs" +version = "21.4.0" +description = "Classes Without Boilerplate" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] + +[[package]] +name = "backports.zoneinfo" +version = "0.2.1" +description = "Backport of the standard library zoneinfo module" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +tzdata = ["tzdata"] + +[[package]] +name = "beautifulsoup4" +version = "4.9.3" +description = "Screen-scraping library" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +soupsieve = {version = ">1.2", markers = "python_version >= \"3.0\""} + +[package.extras] +html5lib = ["html5lib"] +lxml = ["lxml"] + +[[package]] +name = "bilibili-api" +version = "9.1.0" +description = "哔哩哔哩的各种 API 调用便捷整合(视频、动态、直播等),另外附加一些常用的功能。" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +aiohttp = ">=3.7.4.post0,<3.8.0" +beautifulsoup4 = ">=4.9.3,<4.10.0" +brotli = ">=1.0.9,<1.1.0" +colorama = ">=0.4.4,<0.5.0" +lxml = ">=4.6.1,<4.7.0" +pyyaml = ">=5.4.1,<5.5.0" +urllib3 = ">=1.26.3,<1.27.0" + +[[package]] +name = "black" +version = "22.1.0" +description = "The uncompromising code formatter." +category = "main" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = ">=1.1.0" +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "brotli" +version = "1.0.9" +description = "Python bindings for the Brotli compression library" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "certifi" +version = "2021.10.8" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "chardet" +version = "4.0.0" +description = "Universal encoding detector for Python 2 and 3" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "charset-normalizer" +version = "2.0.12" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + +[[package]] +name = "click" +version = "8.0.3" +description = "Composable command line interface toolkit" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "cycler" +version = "0.11.0" +description = "Composable style cycles" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "fastapi" +version = "0.73.0" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" +starlette = "0.17.1" + +[package.extras] +all = ["requests (>=2.24.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<3.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "ujson (>=4.0.1,<5.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] +dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] +doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"] +test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==21.9b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "flask (>=1.1.2,<3.0.0)", "anyio[trio] (>=3.2.1,<4.0.0)", "types-ujson (==0.1.1)", "types-orjson (==3.6.0)", "types-dataclasses (==0.1.7)"] + +[[package]] +name = "feedparser" +version = "6.0.8" +description = "Universal feed parser, handles RSS 0.9x, RSS 1.0, RSS 2.0, CDF, Atom 0.3, and Atom 1.0 feeds" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +sgmllib3k = "*" + +[[package]] +name = "fonttools" +version = "4.29.1" +description = "Tools to manipulate font files" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +all = ["fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "zopfli (>=0.1.4)", "lz4 (>=1.7.4.2)", "matplotlib", "sympy", "skia-pathops (>=0.5.0)", "brotlicffi (>=0.8.0)", "scipy", "brotli (>=1.0.1)", "munkres", "unicodedata2 (>=14.0.0)", "xattr"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["scipy", "munkres"] +lxml = ["lxml (>=4.0,<5)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=14.0.0)"] +woff = ["zopfli (>=0.1.4)", "brotlicffi (>=0.8.0)", "brotli (>=1.0.1)"] + +[[package]] +name = "gino" +version = "1.0.1" +description = "GINO Is Not ORM - a Python asyncio ORM on SQLAlchemy core." +category = "main" +optional = false +python-versions = ">=3.5,<4.0" + +[package.dependencies] +asyncpg = ">=0.18,<1.0" +SQLAlchemy = ">=1.2.16,<1.4" + +[package.extras] +starlette = ["gino-starlette (>=0.1.1,<0.2.0)"] +aiohttp = ["gino-aiohttp (>=0.1.0,<0.2.0)"] +tornado = ["gino-tornado (>=0.1.0,<0.2.0)"] +sanic = ["gino-sanic (>=0.1.0,<0.2.0)"] +quart = ["gino-quart (>=0.1.0,<0.2.0)"] + +[[package]] +name = "greenlet" +version = "1.1.2" +description = "Lightweight in-process concurrent programming" +category = "main" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" + +[package.extras] +docs = ["sphinx"] + +[[package]] +name = "h11" +version = "0.12.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "httpcore" +version = "0.14.7" +description = "A minimal low-level HTTP client." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +anyio = ">=3.0.0,<4.0.0" +certifi = "*" +h11 = ">=0.11,<0.13" +sniffio = ">=1.0.0,<2.0.0" + +[package.extras] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] + +[[package]] +name = "httptools" +version = "0.2.0" +description = "A collection of framework independent HTTP protocol utils." +category = "main" +optional = false +python-versions = "*" + +[package.extras] +test = ["Cython (==0.29.22)"] + +[[package]] +name = "httpx" +version = "0.22.0" +description = "The next generation HTTP client." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +certifi = "*" +charset-normalizer = "*" +httpcore = ">=0.14.5,<0.15.0" +rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} +sniffio = "*" + +[package.extras] +brotli = ["brotlicffi", "brotli"] +cli = ["click (>=8.0.0,<9.0.0)", "rich (>=10.0.0,<11.0.0)", "pygments (>=2.0.0,<3.0.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] + +[[package]] +name = "idna" +version = "3.3" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "imagehash" +version = "4.2.1" +description = "Image Hashing library" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +numpy = "*" +pillow = "*" +PyWavelets = "*" +scipy = "*" +six = "*" + +[[package]] +name = "jieba" +version = "0.42.1" +description = "Chinese Words Segmentation Utilities" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "kiwisolver" +version = "1.3.2" +description = "A fast implementation of the Cassowary constraint solver" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "loguru" +version = "0.6.0" +description = "Python logging made (stupidly) simple" +category = "main" +optional = false +python-versions = ">=3.5" + +[package.dependencies] +colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} +win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} + +[package.extras] +dev = ["colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "tox (>=3.9.0)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "black (>=19.10b0)", "isort (>=5.1.1)", "Sphinx (>=4.1.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)"] + +[[package]] +name = "lxml" +version = "4.6.5" +description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" + +[package.extras] +cssselect = ["cssselect (>=0.7)"] +html5 = ["html5lib"] +htmlsoup = ["beautifulsoup4"] +source = ["Cython (>=0.29.7)"] + +[[package]] +name = "matplotlib" +version = "3.5.1" +description = "Python plotting package" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +cycler = ">=0.10" +fonttools = ">=4.22.0" +kiwisolver = ">=1.0.1" +numpy = ">=1.17" +packaging = ">=20.0" +pillow = ">=6.2.0" +pyparsing = ">=2.2.1" +python-dateutil = ">=2.7" +setuptools_scm = ">=4" + +[[package]] +name = "multidict" +version = "6.0.2" +description = "multidict implementation" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "nonebot-adapter-onebot" +version = "2.0.0b1" +description = "OneBot(CQHTTP) adapter for nonebot2" +category = "main" +optional = false +python-versions = ">=3.7.3,<4.0.0" + +[package.dependencies] +nonebot2 = ">=2.0.0-beta.1,<3.0.0" + +[[package]] +name = "nonebot-plugin-apscheduler" +version = "0.1.2" +description = "APScheduler Support for NoneBot2" +category = "main" +optional = false +python-versions = ">=3.7,<4.0" + +[package.dependencies] +apscheduler = ">=3.7.0,<4.0.0" +nonebot2 = ">=2.0.0-alpha.8,<3.0.0" + +[[package]] +name = "nonebot2" +version = "2.0.0b2" +description = "An asynchronous python bot framework." +category = "main" +optional = false +python-versions = ">=3.7.3,<4.0.0" + +[package.dependencies] +fastapi = ">=0.73.0,<0.74.0" +loguru = ">=0.6.0,<0.7.0" +pydantic = {version = ">=1.9.0,<1.10.0", extras = ["dotenv"]} +pygtrie = ">=2.4.1,<3.0.0" +tomlkit = ">=0.9.0,<0.10.0" +typing-extensions = ">=3.10.0,<5.0.0" +uvicorn = {version = ">=0.17.0,<0.18.0", extras = ["standard"]} +yarl = ">=1.7.2,<2.0.0" + +[package.extras] +quart = ["Quart (>=0.16.0,<0.17.0)"] +all = ["Quart (>=0.16.0,<0.17.0)", "websockets (>=10.0,<11.0)", "aiohttp[speedups] (>=3.7.4,<4.0.0)", "httpx[http2] (>=0.20.0,<1.0.0)"] +websockets = ["websockets (>=10.0,<11.0)"] +aiohttp = ["aiohttp[speedups] (>=3.7.4,<4.0.0)"] +httpx = ["httpx[http2] (>=0.20.0,<1.0.0)"] + +[[package]] +name = "numpy" +version = "1.22.2" +description = "NumPy is the fundamental package for array computing with Python." +category = "main" +optional = false +python-versions = ">=3.8" + +[[package]] +name = "opencv-python" +version = "4.5.5.62" +description = "Wrapper package for OpenCV python bindings." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +numpy = [ + {version = ">=1.21.2", markers = "python_version >= \"3.10\" or python_version >= \"3.6\" and platform_system == \"Darwin\" and platform_machine == \"arm64\""}, + {version = ">=1.19.3", markers = "python_version >= \"3.6\" and platform_system == \"Linux\" and platform_machine == \"aarch64\" or python_version >= \"3.9\""}, + {version = ">=1.14.5", markers = "python_version >= \"3.7\""}, + {version = ">=1.17.3", markers = "python_version >= \"3.8\""}, +] + +[[package]] +name = "packaging" +version = "21.3" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" + +[[package]] +name = "pathspec" +version = "0.9.0" +description = "Utility library for gitignore style pattern matching of file paths." +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[[package]] +name = "pillow" +version = "9.0.1" +description = "Python Imaging Library (Fork)" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "platformdirs" +version = "2.5.0" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] +test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] + +[[package]] +name = "playwright" +version = "1.18.2" +description = "A high-level API to automate web browsers" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +greenlet = "1.1.2" +pyee = "8.1.0" +typing-extensions = {version = "*", markers = "python_version <= \"3.8\""} +websockets = "10.1" + +[[package]] +name = "psutil" +version = "5.9.0" +description = "Cross-platform lib for process and system monitoring in Python." +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.extras] +test = ["ipaddress", "mock", "unittest2", "enum34", "pywin32", "wmi"] + +[[package]] +name = "pydantic" +version = "1.9.0" +description = "Data validation and settings management using python 3.6 type hinting" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +python-dotenv = {version = ">=0.10.4", optional = true, markers = "extra == \"dotenv\""} +typing-extensions = ">=3.7.4.3" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] + +[[package]] +name = "pyee" +version = "8.1.0" +description = "A port of node.js's EventEmitter to python." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pygtrie" +version = "2.4.2" +description = "A pure Python trie data structure implementation." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pyparsing" +version = "3.0.7" +description = "Python parsing module" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pypinyin" +version = "0.46.0" +description = "汉字拼音转换模块/工具." +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4" + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-dotenv" +version = "0.19.2" +description = "Read key-value pairs from a .env file and set them as environment variables" +category = "main" +optional = false +python-versions = ">=3.5" + +[package.extras] +cli = ["click (>=5.0)"] + +[[package]] +name = "pytz" +version = "2021.3" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pytz-deprecation-shim" +version = "0.1.0.post0" +description = "Shims to make deprecation of pytz easier" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" + +[package.dependencies] +"backports.zoneinfo" = {version = "*", markers = "python_version >= \"3.6\" and python_version < \"3.9\""} +tzdata = {version = "*", markers = "python_version >= \"3.6\""} + +[[package]] +name = "pywavelets" +version = "1.2.0" +description = "PyWavelets, wavelet transform module" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +numpy = ">=1.17.3" + +[[package]] +name = "pyyaml" +version = "5.4.1" +description = "YAML parser and emitter for Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[[package]] +name = "retrying" +version = "1.3.3" +description = "Retrying" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +six = ">=1.7.0" + +[[package]] +name = "rfc3986" +version = "1.5.0" +description = "Validating URI References per RFC 3986" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} + +[package.extras] +idna2008 = ["idna"] + +[[package]] +name = "ruamel.yaml" +version = "0.17.21" +description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +category = "main" +optional = false +python-versions = ">=3" + +[package.dependencies] +"ruamel.yaml.clib" = {version = ">=0.2.6", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""} + +[package.extras] +docs = ["ryd"] +jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] + +[[package]] +name = "ruamel.yaml.clib" +version = "0.2.6" +description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "scipy" +version = "1.6.1" +description = "SciPy: Scientific Library for Python" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +numpy = ">=1.16.5" + +[[package]] +name = "setuptools-scm" +version = "6.4.2" +description = "the blessed package to manage your versions by scm tags" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +packaging = ">=20.0" +tomli = ">=1.0.0" + +[package.extras] +test = ["pytest (>=6.2)", "virtualenv (>20)"] +toml = ["setuptools (>=42)"] + +[[package]] +name = "sgmllib3k" +version = "1.0.0" +description = "Py3k port of sgmllib." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "sniffio" +version = "1.2.0" +description = "Sniff out which async library your code is running under" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "soupsieve" +version = "2.3.1" +description = "A modern CSS selector implementation for Beautiful Soup." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "sqlalchemy" +version = "1.3.24" +description = "Database Abstraction Library" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.extras] +mssql = ["pyodbc"] +mssql_pymssql = ["pymssql"] +mssql_pyodbc = ["pyodbc"] +mysql = ["mysqlclient"] +oracle = ["cx-oracle"] +postgresql = ["psycopg2"] +postgresql_pg8000 = ["pg8000 (<1.16.6)"] +postgresql_psycopg2binary = ["psycopg2-binary"] +postgresql_psycopg2cffi = ["psycopg2cffi"] +pymysql = ["pymysql (<1)", "pymysql"] + +[[package]] +name = "starlette" +version = "0.17.1" +description = "The little ASGI library that shines." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +anyio = ">=3.0.0,<4" + +[package.extras] +full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "tomlkit" +version = "0.9.2" +description = "Style preserving TOML library" +category = "main" +optional = false +python-versions = ">=3.6,<4.0" + +[[package]] +name = "typing-extensions" +version = "4.1.1" +description = "Backported and Experimental Type Hints for Python 3.6+" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "tzdata" +version = "2021.5" +description = "Provider of IANA time zone data" +category = "main" +optional = false +python-versions = ">=2" + +[[package]] +name = "tzlocal" +version = "4.1" +description = "tzinfo object for the local timezone" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} +pytz-deprecation-shim = "*" +tzdata = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +devenv = ["black", "pyroma", "pytest-cov", "zest.releaser"] +test = ["pytest-mock (>=3.3)", "pytest (>=4.3)"] + +[[package]] +name = "ujson" +version = "5.1.0" +description = "Ultra fast JSON encoder and decoder for Python" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "urllib3" +version = "1.26.8" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "uvicorn" +version = "0.17.5" +description = "The lightning-fast ASGI server." +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +asgiref = ">=3.4.0" +click = ">=7.0" +colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} +h11 = ">=0.8" +httptools = {version = ">=0.2.0,<0.4.0", optional = true, markers = "extra == \"standard\""} +python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +PyYAML = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} +uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +watchgod = {version = ">=0.6", optional = true, markers = "extra == \"standard\""} +websockets = {version = ">=10.0", optional = true, markers = "extra == \"standard\""} + +[package.extras] +standard = ["websockets (>=10.0)", "httptools (>=0.2.0,<0.4.0)", "watchgod (>=0.6)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "colorama (>=0.4)"] + +[[package]] +name = "uvloop" +version = "0.16.0" +description = "Fast implementation of asyncio event loop on top of libuv" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +dev = ["Cython (>=0.29.24,<0.30.0)", "pytest (>=3.6.0)", "Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "psutil", "pycodestyle (>=2.7.0,<2.8.0)", "pyOpenSSL (>=19.0.0,<19.1.0)", "mypy (>=0.800)"] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)"] +test = ["aiohttp", "flake8 (>=3.9.2,<3.10.0)", "psutil", "pycodestyle (>=2.7.0,<2.8.0)", "pyOpenSSL (>=19.0.0,<19.1.0)", "mypy (>=0.800)"] + +[[package]] +name = "watchgod" +version = "0.7" +description = "Simple, modern file watching and code reload in python." +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "websockets" +version = "10.1" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "win32-setctime" +version = "1.1.0" +description = "A small Python utility to set file creation time on Windows" +category = "main" +optional = false +python-versions = ">=3.5" + +[package.extras] +dev = ["pytest (>=4.6.2)", "black (>=19.3b0)"] + +[[package]] +name = "yarl" +version = "1.7.2" +description = "Yet another URL library" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" + +[metadata] +lock-version = "1.1" +python-versions = "^3.8" +content-hash = "ea26d9444670abebc036296cc82714561dd18a6a8a9827a011979a72741d1fdb" + +[metadata.files] +aiofiles = [ + {file = "aiofiles-0.8.0-py3-none-any.whl", hash = "sha256:7a973fc22b29e9962d0897805ace5856e6a566ab1f0c8e5c91ff6c866519c937"}, + {file = "aiofiles-0.8.0.tar.gz", hash = "sha256:8334f23235248a3b2e83b2c3a78a22674f39969b96397126cc93664d9a901e59"}, +] +aiohttp = [ + {file = "aiohttp-3.7.4.post0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:3cf75f7cdc2397ed4442594b935a11ed5569961333d49b7539ea741be2cc79d5"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4b302b45040890cea949ad092479e01ba25911a15e648429c7c5aae9650c67a8"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:393f389841e8f2dfc86f774ad22f00923fdee66d238af89b70ea314c4aefd290"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_ppc64le.whl", hash = "sha256:c6e9dcb4cb338d91a73f178d866d051efe7c62a7166653a91e7d9fb18274058f"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:5df68496d19f849921f05f14f31bd6ef53ad4b00245da3195048c69934521809"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:0563c1b3826945eecd62186f3f5c7d31abb7391fedc893b7e2b26303b5a9f3fe"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-win32.whl", hash = "sha256:3d78619672183be860b96ed96f533046ec97ca067fd46ac1f6a09cd9b7484287"}, + {file = "aiohttp-3.7.4.post0-cp36-cp36m-win_amd64.whl", hash = "sha256:f705e12750171c0ab4ef2a3c76b9a4024a62c4103e3a55dd6f99265b9bc6fcfc"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:230a8f7e24298dea47659251abc0fd8b3c4e38a664c59d4b89cca7f6c09c9e87"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:2e19413bf84934d651344783c9f5e22dee452e251cfd220ebadbed2d9931dbf0"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e4b2b334e68b18ac9817d828ba44d8fcb391f6acb398bcc5062b14b2cbeac970"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:d012ad7911653a906425d8473a1465caa9f8dea7fcf07b6d870397b774ea7c0f"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_ppc64le.whl", hash = "sha256:40eced07f07a9e60e825554a31f923e8d3997cfc7fb31dbc1328c70826e04cde"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:209b4a8ee987eccc91e2bd3ac36adee0e53a5970b8ac52c273f7f8fd4872c94c"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:14762875b22d0055f05d12abc7f7d61d5fd4fe4642ce1a249abdf8c700bf1fd8"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-win32.whl", hash = "sha256:7615dab56bb07bff74bc865307aeb89a8bfd9941d2ef9d817b9436da3a0ea54f"}, + {file = "aiohttp-3.7.4.post0-cp37-cp37m-win_amd64.whl", hash = "sha256:d9e13b33afd39ddeb377eff2c1c4f00544e191e1d1dee5b6c51ddee8ea6f0cf5"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:547da6cacac20666422d4882cfcd51298d45f7ccb60a04ec27424d2f36ba3eaf"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:af9aa9ef5ba1fd5b8c948bb11f44891968ab30356d65fd0cc6707d989cd521df"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:64322071e046020e8797117b3658b9c2f80e3267daec409b350b6a7a05041213"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:bb437315738aa441251214dad17428cafda9cdc9729499f1d6001748e1d432f4"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_ppc64le.whl", hash = "sha256:e54962802d4b8b18b6207d4a927032826af39395a3bd9196a5af43fc4e60b009"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:a00bb73540af068ca7390e636c01cbc4f644961896fa9363154ff43fd37af2f5"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:79ebfc238612123a713a457d92afb4096e2148be17df6c50fb9bf7a81c2f8013"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-win32.whl", hash = "sha256:515dfef7f869a0feb2afee66b957cc7bbe9ad0cdee45aec7fdc623f4ecd4fb16"}, + {file = "aiohttp-3.7.4.post0-cp38-cp38-win_amd64.whl", hash = "sha256:114b281e4d68302a324dd33abb04778e8557d88947875cbf4e842c2c01a030c5"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:7b18b97cf8ee5452fa5f4e3af95d01d84d86d32c5e2bfa260cf041749d66360b"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:15492a6368d985b76a2a5fdd2166cddfea5d24e69eefed4630cbaae5c81d89bd"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bdb230b4943891321e06fc7def63c7aace16095be7d9cf3b1e01be2f10fba439"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:cffe3ab27871bc3ea47df5d8f7013945712c46a3cc5a95b6bee15887f1675c22"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_ppc64le.whl", hash = "sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:a5ca29ee66f8343ed336816c553e82d6cade48a3ad702b9ffa6125d187e2dedb"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:17c073de315745a1510393a96e680d20af8e67e324f70b42accbd4cb3315c9fb"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-win32.whl", hash = "sha256:932bb1ea39a54e9ea27fc9232163059a0b8855256f4052e776357ad9add6f1c9"}, + {file = "aiohttp-3.7.4.post0-cp39-cp39-win_amd64.whl", hash = "sha256:02f46fc0e3c5ac58b80d4d56eb0a7c7d97fcef69ace9326289fb9f1955e65cfe"}, + {file = "aiohttp-3.7.4.post0.tar.gz", hash = "sha256:493d3299ebe5f5a7c66b9819eacdcfbbaaf1a8e84911ddffcdc48888497afecf"}, +] +anyio = [ + {file = "anyio-3.5.0-py3-none-any.whl", hash = "sha256:b5fa16c5ff93fa1046f2eeb5bbff2dad4d3514d6cda61d02816dba34fa8c3c2e"}, + {file = "anyio-3.5.0.tar.gz", hash = "sha256:a0aeffe2fb1fdf374a8e4b471444f0f3ac4fb9f5a5b542b48824475e0042a5a6"}, +] +apscheduler = [ + {file = "APScheduler-3.8.1-py2.py3-none-any.whl", hash = "sha256:c22cb14b411a31435eb2c530dfbbec948ac63015b517087c7978adb61b574865"}, + {file = "APScheduler-3.8.1.tar.gz", hash = "sha256:5cf344ebcfbdaa48ae178c029c055cec7bc7a4a47c21e315e4d1f08bd35f2355"}, +] +asgiref = [ + {file = "asgiref-3.5.0-py3-none-any.whl", hash = "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"}, + {file = "asgiref-3.5.0.tar.gz", hash = "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0"}, +] +async-timeout = [ + {file = "async-timeout-3.0.1.tar.gz", hash = "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f"}, + {file = "async_timeout-3.0.1-py3-none-any.whl", hash = "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"}, +] +asyncpg = [ + {file = "asyncpg-0.25.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bf5e3408a14a17d480f36ebaf0401a12ff6ae5457fdf45e4e2775c51cc9517d3"}, + {file = "asyncpg-0.25.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2bc197fc4aca2fd24f60241057998124012469d2e414aed3f992579db0c88e3a"}, + {file = "asyncpg-0.25.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a70783f6ffa34cc7dd2de20a873181414a34fd35a4a208a1f1a7f9f695e4ec4"}, + {file = "asyncpg-0.25.0-cp310-cp310-win32.whl", hash = "sha256:43cde84e996a3afe75f325a68300093425c2f47d340c0fc8912765cf24a1c095"}, + {file = "asyncpg-0.25.0-cp310-cp310-win_amd64.whl", hash = "sha256:56d88d7ef4341412cd9c68efba323a4519c916979ba91b95d4c08799d2ff0c09"}, + {file = "asyncpg-0.25.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a84d30e6f850bac0876990bcd207362778e2208df0bee8be8da9f1558255e634"}, + {file = "asyncpg-0.25.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:beaecc52ad39614f6ca2e48c3ca15d56e24a2c15cbfdcb764a4320cc45f02fd5"}, + {file = "asyncpg-0.25.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:6f8f5fc975246eda83da8031a14004b9197f510c41511018e7b1bedde6968e92"}, + {file = "asyncpg-0.25.0-cp36-cp36m-win32.whl", hash = "sha256:ddb4c3263a8d63dcde3d2c4ac1c25206bfeb31fa83bd70fd539e10f87739dee4"}, + {file = "asyncpg-0.25.0-cp36-cp36m-win_amd64.whl", hash = "sha256:bf6dc9b55b9113f39eaa2057337ce3f9ef7de99a053b8a16360395ce588925cd"}, + {file = "asyncpg-0.25.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:acb311722352152936e58a8ee3c5b8e791b24e84cd7d777c414ff05b3530ca68"}, + {file = "asyncpg-0.25.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0a61fb196ce4dae2f2fa26eb20a778db21bbee484d2e798cb3cc988de13bdd1b"}, + {file = "asyncpg-0.25.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2633331cbc8429030b4f20f712f8d0fbba57fa8555ee9b2f45f981b81328b256"}, + {file = "asyncpg-0.25.0-cp37-cp37m-win32.whl", hash = "sha256:863d36eba4a7caa853fd7d83fad5fd5306f050cc2fe6e54fbe10cdb30420e5e9"}, + {file = "asyncpg-0.25.0-cp37-cp37m-win_amd64.whl", hash = "sha256:fe471ccd915b739ca65e2e4dbd92a11b44a5b37f2e38f70827a1c147dafe0fa8"}, + {file = "asyncpg-0.25.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:72a1e12ea0cf7c1e02794b697e3ca967b2360eaa2ce5d4bfdd8604ec2d6b774b"}, + {file = "asyncpg-0.25.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4327f691b1bdb222df27841938b3e04c14068166b3a97491bec2cb982f49f03e"}, + {file = "asyncpg-0.25.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:739bbd7f89a2b2f6bc44cb8bf967dab12c5bc714fcbe96e68d512be45ecdf962"}, + {file = "asyncpg-0.25.0-cp38-cp38-win32.whl", hash = "sha256:18d49e2d93a7139a2fdbd113e320cc47075049997268a61bfbe0dde680c55471"}, + {file = "asyncpg-0.25.0-cp38-cp38-win_amd64.whl", hash = "sha256:191fe6341385b7fdea7dbdcf47fd6db3fd198827dcc1f2b228476d13c05a03c6"}, + {file = "asyncpg-0.25.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:52fab7f1b2c29e187dd8781fce896249500cf055b63471ad66332e537e9b5f7e"}, + {file = "asyncpg-0.25.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a738f1b2876f30d710d3dc1e7858160a0afe1603ba16bf5f391f5316eb0ed855"}, + {file = "asyncpg-0.25.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4105f57ad1e8fbc8b1e535d8fcefa6ce6c71081228f08680c6dea24384ff0e"}, + {file = "asyncpg-0.25.0-cp39-cp39-win32.whl", hash = "sha256:f55918ded7b85723a5eaeb34e86e7b9280d4474be67df853ab5a7fa0cc7c6bf2"}, + {file = "asyncpg-0.25.0-cp39-cp39-win_amd64.whl", hash = "sha256:649e2966d98cc48d0646d9a4e29abecd8b59d38d55c256d5c857f6b27b7407ac"}, + {file = "asyncpg-0.25.0.tar.gz", hash = "sha256:63f8e6a69733b285497c2855464a34de657f2cccd25aeaeeb5071872e9382540"}, +] +attrs = [ + {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, + {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, +] +"backports.zoneinfo" = [ + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"}, + {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"}, + {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"}, + {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, + {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, +] +beautifulsoup4 = [ + {file = "beautifulsoup4-4.9.3-py2-none-any.whl", hash = "sha256:4c98143716ef1cb40bf7f39a8e3eec8f8b009509e74904ba3a7b315431577e35"}, + {file = "beautifulsoup4-4.9.3-py3-none-any.whl", hash = "sha256:fff47e031e34ec82bf17e00da8f592fe7de69aeea38be00523c04623c04fb666"}, + {file = "beautifulsoup4-4.9.3.tar.gz", hash = "sha256:84729e322ad1d5b4d25f805bfa05b902dd96450f43842c4e99067d5e1369eb25"}, +] +bilibili-api = [ + {file = "bilibili-api-9.1.0.tar.gz", hash = "sha256:be2e9e142c39a2deb6b74ccf0205ad3eae76c12864ddff7b1693fe52e04efa8c"}, + {file = "bilibili_api-9.1.0-py3-none-any.whl", hash = "sha256:9763e0c7ee05f4ade92855b8942a021e6eeb7ae4a8ba5e32ae377335738f790d"}, +] +black = [ + {file = "black-22.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6"}, + {file = "black-22.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866"}, + {file = "black-22.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71"}, + {file = "black-22.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab"}, + {file = "black-22.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5"}, + {file = "black-22.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a"}, + {file = "black-22.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0"}, + {file = "black-22.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba"}, + {file = "black-22.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1"}, + {file = "black-22.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8"}, + {file = "black-22.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28"}, + {file = "black-22.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912"}, + {file = "black-22.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3"}, + {file = "black-22.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"}, + {file = "black-22.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61"}, + {file = "black-22.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd"}, + {file = "black-22.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f"}, + {file = "black-22.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0"}, + {file = "black-22.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c"}, + {file = "black-22.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2"}, + {file = "black-22.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321"}, + {file = "black-22.1.0-py3-none-any.whl", hash = "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d"}, + {file = "black-22.1.0.tar.gz", hash = "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5"}, +] +brotli = [ + {file = "Brotli-1.0.9-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:268fe94547ba25b58ebc724680609c8ee3e5a843202e9a381f6f9c5e8bdb5c70"}, + {file = "Brotli-1.0.9-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:c2415d9d082152460f2bd4e382a1e85aed233abc92db5a3880da2257dc7daf7b"}, + {file = "Brotli-1.0.9-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5913a1177fc36e30fcf6dc868ce23b0453952c78c04c266d3149b3d39e1410d6"}, + {file = "Brotli-1.0.9-cp27-cp27m-win32.whl", hash = "sha256:afde17ae04d90fbe53afb628f7f2d4ca022797aa093e809de5c3cf276f61bbfa"}, + {file = "Brotli-1.0.9-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7cb81373984cc0e4682f31bc3d6be9026006d96eecd07ea49aafb06897746452"}, + {file = "Brotli-1.0.9-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:db844eb158a87ccab83e868a762ea8024ae27337fc7ddcbfcddd157f841fdfe7"}, + {file = "Brotli-1.0.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9744a863b489c79a73aba014df554b0e7a0fc44ef3f8a0ef2a52919c7d155031"}, + {file = "Brotli-1.0.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a72661af47119a80d82fa583b554095308d6a4c356b2a554fdc2799bc19f2a43"}, + {file = "Brotli-1.0.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ee83d3e3a024a9618e5be64648d6d11c37047ac48adff25f12fa4226cf23d1c"}, + {file = "Brotli-1.0.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:19598ecddd8a212aedb1ffa15763dd52a388518c4550e615aed88dc3753c0f0c"}, + {file = "Brotli-1.0.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:44bb8ff420c1d19d91d79d8c3574b8954288bdff0273bf788954064d260d7ab0"}, + {file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e23281b9a08ec338469268f98f194658abfb13658ee98e2b7f85ee9dd06caa91"}, + {file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3496fc835370da351d37cada4cf744039616a6db7d13c430035e901443a34daa"}, + {file = "Brotli-1.0.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83bb06a0192cccf1eb8d0a28672a1b79c74c3a8a5f2619625aeb6f28b3a82bb"}, + {file = "Brotli-1.0.9-cp310-cp310-win32.whl", hash = "sha256:26d168aac4aaec9a4394221240e8a5436b5634adc3cd1cdf637f6645cecbf181"}, + {file = "Brotli-1.0.9-cp310-cp310-win_amd64.whl", hash = "sha256:622a231b08899c864eb87e85f81c75e7b9ce05b001e59bbfbf43d4a71f5f32b2"}, + {file = "Brotli-1.0.9-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:c83aa123d56f2e060644427a882a36b3c12db93727ad7a7b9efd7d7f3e9cc2c4"}, + {file = "Brotli-1.0.9-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:6b2ae9f5f67f89aade1fab0f7fd8f2832501311c363a21579d02defa844d9296"}, + {file = "Brotli-1.0.9-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:68715970f16b6e92c574c30747c95cf8cf62804569647386ff032195dc89a430"}, + {file = "Brotli-1.0.9-cp35-cp35m-win32.whl", hash = "sha256:defed7ea5f218a9f2336301e6fd379f55c655bea65ba2476346340a0ce6f74a1"}, + {file = "Brotli-1.0.9-cp35-cp35m-win_amd64.whl", hash = "sha256:88c63a1b55f352b02c6ffd24b15ead9fc0e8bf781dbe070213039324922a2eea"}, + {file = "Brotli-1.0.9-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:503fa6af7da9f4b5780bb7e4cbe0c639b010f12be85d02c99452825dd0feef3f"}, + {file = "Brotli-1.0.9-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:40d15c79f42e0a2c72892bf407979febd9cf91f36f495ffb333d1d04cebb34e4"}, + {file = "Brotli-1.0.9-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:93130612b837103e15ac3f9cbacb4613f9e348b58b3aad53721d92e57f96d46a"}, + {file = "Brotli-1.0.9-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87fdccbb6bb589095f413b1e05734ba492c962b4a45a13ff3408fa44ffe6479b"}, + {file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:6d847b14f7ea89f6ad3c9e3901d1bc4835f6b390a9c71df999b0162d9bb1e20f"}, + {file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:495ba7e49c2db22b046a53b469bbecea802efce200dffb69b93dd47397edc9b6"}, + {file = "Brotli-1.0.9-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:4688c1e42968ba52e57d8670ad2306fe92e0169c6f3af0089be75bbac0c64a3b"}, + {file = "Brotli-1.0.9-cp36-cp36m-win32.whl", hash = "sha256:61a7ee1f13ab913897dac7da44a73c6d44d48a4adff42a5701e3239791c96e14"}, + {file = "Brotli-1.0.9-cp36-cp36m-win_amd64.whl", hash = "sha256:1c48472a6ba3b113452355b9af0a60da5c2ae60477f8feda8346f8fd48e3e87c"}, + {file = "Brotli-1.0.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3b78a24b5fd13c03ee2b7b86290ed20efdc95da75a3557cc06811764d5ad1126"}, + {file = "Brotli-1.0.9-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:9d12cf2851759b8de8ca5fde36a59c08210a97ffca0eb94c532ce7b17c6a3d1d"}, + {file = "Brotli-1.0.9-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6c772d6c0a79ac0f414a9f8947cc407e119b8598de7621f39cacadae3cf57d12"}, + {file = "Brotli-1.0.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29d1d350178e5225397e28ea1b7aca3648fcbab546d20e7475805437bfb0a130"}, + {file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7bbff90b63328013e1e8cb50650ae0b9bac54ffb4be6104378490193cd60f85a"}, + {file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ec1947eabbaf8e0531e8e899fc1d9876c179fc518989461f5d24e2223395a9e3"}, + {file = "Brotli-1.0.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12effe280b8ebfd389022aa65114e30407540ccb89b177d3fbc9a4f177c4bd5d"}, + {file = "Brotli-1.0.9-cp37-cp37m-win32.whl", hash = "sha256:f909bbbc433048b499cb9db9e713b5d8d949e8c109a2a548502fb9aa8630f0b1"}, + {file = "Brotli-1.0.9-cp37-cp37m-win_amd64.whl", hash = "sha256:97f715cf371b16ac88b8c19da00029804e20e25f30d80203417255d239f228b5"}, + {file = "Brotli-1.0.9-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e16eb9541f3dd1a3e92b89005e37b1257b157b7256df0e36bd7b33b50be73bcb"}, + {file = "Brotli-1.0.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:160c78292e98d21e73a4cc7f76a234390e516afcd982fa17e1422f7c6a9ce9c8"}, + {file = "Brotli-1.0.9-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b663f1e02de5d0573610756398e44c130add0eb9a3fc912a09665332942a2efb"}, + {file = "Brotli-1.0.9-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5b6ef7d9f9c38292df3690fe3e302b5b530999fa90014853dcd0d6902fb59f26"}, + {file = "Brotli-1.0.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a674ac10e0a87b683f4fa2b6fa41090edfd686a6524bd8dedbd6138b309175c"}, + {file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e2d9e1cbc1b25e22000328702b014227737756f4b5bf5c485ac1d8091ada078b"}, + {file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b336c5e9cf03c7be40c47b5fd694c43c9f1358a80ba384a21969e0b4e66a9b17"}, + {file = "Brotli-1.0.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:85f7912459c67eaab2fb854ed2bc1cc25772b300545fe7ed2dc03954da638649"}, + {file = "Brotli-1.0.9-cp38-cp38-win32.whl", hash = "sha256:35a3edbe18e876e596553c4007a087f8bcfd538f19bc116917b3c7522fca0429"}, + {file = "Brotli-1.0.9-cp38-cp38-win_amd64.whl", hash = "sha256:269a5743a393c65db46a7bb982644c67ecba4b8d91b392403ad8a861ba6f495f"}, + {file = "Brotli-1.0.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2aad0e0baa04517741c9bb5b07586c642302e5fb3e75319cb62087bd0995ab19"}, + {file = "Brotli-1.0.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5cb1e18167792d7d21e21365d7650b72d5081ed476123ff7b8cac7f45189c0c7"}, + {file = "Brotli-1.0.9-cp39-cp39-manylinux1_i686.whl", hash = "sha256:16d528a45c2e1909c2798f27f7bf0a3feec1dc9e50948e738b961618e38b6a7b"}, + {file = "Brotli-1.0.9-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:56d027eace784738457437df7331965473f2c0da2c70e1a1f6fdbae5402e0389"}, + {file = "Brotli-1.0.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bf919756d25e4114ace16a8ce91eb340eb57a08e2c6950c3cebcbe3dff2a5e7"}, + {file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e4c4e92c14a57c9bd4cb4be678c25369bf7a092d55fd0866f759e425b9660806"}, + {file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e48f4234f2469ed012a98f4b7874e7f7e173c167bed4934912a29e03167cf6b1"}, + {file = "Brotli-1.0.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9ed4c92a0665002ff8ea852353aeb60d9141eb04109e88928026d3c8a9e5433c"}, + {file = "Brotli-1.0.9-cp39-cp39-win32.whl", hash = "sha256:cfc391f4429ee0a9370aa93d812a52e1fee0f37a81861f4fdd1f4fb28e8547c3"}, + {file = "Brotli-1.0.9-cp39-cp39-win_amd64.whl", hash = "sha256:854c33dad5ba0fbd6ab69185fec8dab89e13cda6b7d191ba111987df74f38761"}, + {file = "Brotli-1.0.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9749a124280a0ada4187a6cfd1ffd35c350fb3af79c706589d98e088c5044267"}, + {file = "Brotli-1.0.9-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:76ffebb907bec09ff511bb3acc077695e2c32bc2142819491579a695f77ffd4d"}, + {file = "Brotli-1.0.9.zip", hash = "sha256:4d1b810aa0ed773f81dceda2cc7b403d01057458730e309856356d4ef4188438"}, +] +certifi = [ + {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, + {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, +] +chardet = [ + {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, + {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, +] +charset-normalizer = [ + {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, + {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, +] +click = [ + {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, + {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, +] +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] +cycler = [ + {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, + {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, +] +fastapi = [ + {file = "fastapi-0.73.0-py3-none-any.whl", hash = "sha256:f0a618aff5f6942862f2d3f20f39b1c037e33314d1b8207fd1c3a2cca76dfd8c"}, + {file = "fastapi-0.73.0.tar.gz", hash = "sha256:dcfee92a7f9a72b5d4b7ca364bd2b009f8fc10d95ed5769be20e94f39f7e5a15"}, +] +feedparser = [ + {file = "feedparser-6.0.8-py3-none-any.whl", hash = "sha256:1b7f57841d9cf85074deb316ed2c795091a238adb79846bc46dccdaf80f9c59a"}, + {file = "feedparser-6.0.8.tar.gz", hash = "sha256:5ce0410a05ab248c8c7cfca3a0ea2203968ee9ff4486067379af4827a59f9661"}, +] +fonttools = [ + {file = "fonttools-4.29.1-py3-none-any.whl", hash = "sha256:1933415e0fbdf068815cb1baaa1f159e17830215f7e8624e5731122761627557"}, + {file = "fonttools-4.29.1.zip", hash = "sha256:2b18a172120e32128a80efee04cff487d5d140fe7d817deb648b2eee023a40e4"}, +] +gino = [ + {file = "gino-1.0.1-py3-none-any.whl", hash = "sha256:56df57cfdefbaf897a7c4897c265a0e91a8cca80716fb64f7d3cf6d501fdfb3d"}, + {file = "gino-1.0.1.tar.gz", hash = "sha256:fe4189e82fe9d20c4a5f03fc775fb91c168061c5176b4c95623caeef22316150"}, +] +greenlet = [ + {file = "greenlet-1.1.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:58df5c2a0e293bf665a51f8a100d3e9956febfbf1d9aaf8c0677cf70218910c6"}, + {file = "greenlet-1.1.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:aec52725173bd3a7b56fe91bc56eccb26fbdff1386ef123abb63c84c5b43b63a"}, + {file = "greenlet-1.1.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:833e1551925ed51e6b44c800e71e77dacd7e49181fdc9ac9a0bf3714d515785d"}, + {file = "greenlet-1.1.2-cp27-cp27m-win32.whl", hash = "sha256:aa5b467f15e78b82257319aebc78dd2915e4c1436c3c0d1ad6f53e47ba6e2713"}, + {file = "greenlet-1.1.2-cp27-cp27m-win_amd64.whl", hash = "sha256:40b951f601af999a8bf2ce8c71e8aaa4e8c6f78ff8afae7b808aae2dc50d4c40"}, + {file = "greenlet-1.1.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:95e69877983ea39b7303570fa6760f81a3eec23d0e3ab2021b7144b94d06202d"}, + {file = "greenlet-1.1.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:356b3576ad078c89a6107caa9c50cc14e98e3a6c4874a37c3e0273e4baf33de8"}, + {file = "greenlet-1.1.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8639cadfda96737427330a094476d4c7a56ac03de7265622fcf4cfe57c8ae18d"}, + {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e5306482182170ade15c4b0d8386ded995a07d7cc2ca8f27958d34d6736497"}, + {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6a36bb9474218c7a5b27ae476035497a6990e21d04c279884eb10d9b290f1b1"}, + {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb7a75ed8b968f3061327c433a0fbd17b729947b400747c334a9c29a9af6c58"}, + {file = "greenlet-1.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b336501a05e13b616ef81ce329c0e09ac5ed8c732d9ba7e3e983fcc1a9e86965"}, + {file = "greenlet-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:14d4f3cd4e8b524ae9b8aa567858beed70c392fdec26dbdb0a8a418392e71708"}, + {file = "greenlet-1.1.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:17ff94e7a83aa8671a25bf5b59326ec26da379ace2ebc4411d690d80a7fbcf23"}, + {file = "greenlet-1.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9f3cba480d3deb69f6ee2c1825060177a22c7826431458c697df88e6aeb3caee"}, + {file = "greenlet-1.1.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:fa877ca7f6b48054f847b61d6fa7bed5cebb663ebc55e018fda12db09dcc664c"}, + {file = "greenlet-1.1.2-cp35-cp35m-win32.whl", hash = "sha256:7cbd7574ce8e138bda9df4efc6bf2ab8572c9aff640d8ecfece1b006b68da963"}, + {file = "greenlet-1.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:903bbd302a2378f984aef528f76d4c9b1748f318fe1294961c072bdc7f2ffa3e"}, + {file = "greenlet-1.1.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:049fe7579230e44daef03a259faa24511d10ebfa44f69411d99e6a184fe68073"}, + {file = "greenlet-1.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:dd0b1e9e891f69e7675ba5c92e28b90eaa045f6ab134ffe70b52e948aa175b3c"}, + {file = "greenlet-1.1.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7418b6bfc7fe3331541b84bb2141c9baf1ec7132a7ecd9f375912eca810e714e"}, + {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9d29ca8a77117315101425ec7ec2a47a22ccf59f5593378fc4077ac5b754fce"}, + {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21915eb821a6b3d9d8eefdaf57d6c345b970ad722f856cd71739493ce003ad08"}, + {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff9d20417ff9dcb0d25e2defc2574d10b491bf2e693b4e491914738b7908168"}, + {file = "greenlet-1.1.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b8c008de9d0daba7b6666aa5bbfdc23dcd78cafc33997c9b7741ff6353bafb7f"}, + {file = "greenlet-1.1.2-cp36-cp36m-win32.whl", hash = "sha256:32ca72bbc673adbcfecb935bb3fb1b74e663d10a4b241aaa2f5a75fe1d1f90aa"}, + {file = "greenlet-1.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:f0214eb2a23b85528310dad848ad2ac58e735612929c8072f6093f3585fd342d"}, + {file = "greenlet-1.1.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:b92e29e58bef6d9cfd340c72b04d74c4b4e9f70c9fa7c78b674d1fec18896dc4"}, + {file = "greenlet-1.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fdcec0b8399108577ec290f55551d926d9a1fa6cad45882093a7a07ac5ec147b"}, + {file = "greenlet-1.1.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:93f81b134a165cc17123626ab8da2e30c0455441d4ab5576eed73a64c025b25c"}, + {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e12bdc622676ce47ae9abbf455c189e442afdde8818d9da983085df6312e7a1"}, + {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c790abda465726cfb8bb08bd4ca9a5d0a7bd77c7ac1ca1b839ad823b948ea28"}, + {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f276df9830dba7a333544bd41070e8175762a7ac20350786b322b714b0e654f5"}, + {file = "greenlet-1.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c5d5b35f789a030ebb95bff352f1d27a93d81069f2adb3182d99882e095cefe"}, + {file = "greenlet-1.1.2-cp37-cp37m-win32.whl", hash = "sha256:64e6175c2e53195278d7388c454e0b30997573f3f4bd63697f88d855f7a6a1fc"}, + {file = "greenlet-1.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b11548073a2213d950c3f671aa88e6f83cda6e2fb97a8b6317b1b5b33d850e06"}, + {file = "greenlet-1.1.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:9633b3034d3d901f0a46b7939f8c4d64427dfba6bbc5a36b1a67364cf148a1b0"}, + {file = "greenlet-1.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:eb6ea6da4c787111adf40f697b4e58732ee0942b5d3bd8f435277643329ba627"}, + {file = "greenlet-1.1.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:f3acda1924472472ddd60c29e5b9db0cec629fbe3c5c5accb74d6d6d14773478"}, + {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e859fcb4cbe93504ea18008d1df98dee4f7766db66c435e4882ab35cf70cac43"}, + {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e44c8afdbe5467e4f7b5851be223be68adb4272f44696ee71fe46b7036a711"}, + {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec8c433b3ab0419100bd45b47c9c8551248a5aee30ca5e9d399a0b57ac04651b"}, + {file = "greenlet-1.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2bde6792f313f4e918caabc46532aa64aa27a0db05d75b20edfc5c6f46479de2"}, + {file = "greenlet-1.1.2-cp38-cp38-win32.whl", hash = "sha256:288c6a76705dc54fba69fbcb59904ae4ad768b4c768839b8ca5fdadec6dd8cfd"}, + {file = "greenlet-1.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:8d2f1fb53a421b410751887eb4ff21386d119ef9cde3797bf5e7ed49fb51a3b3"}, + {file = "greenlet-1.1.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:166eac03e48784a6a6e0e5f041cfebb1ab400b394db188c48b3a84737f505b67"}, + {file = "greenlet-1.1.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:572e1787d1460da79590bf44304abbc0a2da944ea64ec549188fa84d89bba7ab"}, + {file = "greenlet-1.1.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:be5f425ff1f5f4b3c1e33ad64ab994eed12fc284a6ea71c5243fd564502ecbe5"}, + {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1692f7d6bc45e3200844be0dba153612103db241691088626a33ff1f24a0d88"}, + {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7227b47e73dedaa513cdebb98469705ef0d66eb5a1250144468e9c3097d6b59b"}, + {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff61ff178250f9bb3cd89752df0f1dd0e27316a8bd1465351652b1b4a4cdfd3"}, + {file = "greenlet-1.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0051c6f1f27cb756ffc0ffbac7d2cd48cb0362ac1736871399a739b2885134d3"}, + {file = "greenlet-1.1.2-cp39-cp39-win32.whl", hash = "sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf"}, + {file = "greenlet-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd"}, + {file = "greenlet-1.1.2.tar.gz", hash = "sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a"}, +] +h11 = [ + {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, + {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, +] +httpcore = [ + {file = "httpcore-0.14.7-py3-none-any.whl", hash = "sha256:47d772f754359e56dd9d892d9593b6f9870a37aeb8ba51e9a88b09b3d68cfade"}, + {file = "httpcore-0.14.7.tar.gz", hash = "sha256:7503ec1c0f559066e7e39bc4003fd2ce023d01cf51793e3c173b864eb456ead1"}, +] +httptools = [ + {file = "httptools-0.2.0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:79dbc21f3612a78b28384e989b21872e2e3cf3968532601544696e4ed0007ce5"}, + {file = "httptools-0.2.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:78d03dd39b09c99ec917d50189e6743adbfd18c15d5944392d2eabda688bf149"}, + {file = "httptools-0.2.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:a23166e5ae2775709cf4f7ad4c2048755ebfb272767d244e1a96d55ac775cca7"}, + {file = "httptools-0.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3ab1f390d8867f74b3b5ee2a7ecc9b8d7f53750bd45714bf1cb72a953d7dfa77"}, + {file = "httptools-0.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a7594f9a010cdf1e16a58b3bf26c9da39bbf663e3b8d46d39176999d71816658"}, + {file = "httptools-0.2.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:01b392a166adcc8bc2f526a939a8aabf89fe079243e1543fd0e7dc1b58d737cb"}, + {file = "httptools-0.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:80ffa04fe8c8dfacf6e4cef8277347d35b0442c581f5814f3b0cf41b65c43c6e"}, + {file = "httptools-0.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d5682eeb10cca0606c4a8286a3391d4c3c5a36f0c448e71b8bd05be4e1694bfb"}, + {file = "httptools-0.2.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:a289c27ccae399a70eacf32df9a44059ca2ba4ac444604b00a19a6c1f0809943"}, + {file = "httptools-0.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:813871f961edea6cb2fe312f2d9b27d12a51ba92545380126f80d0de1917ea15"}, + {file = "httptools-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:cc9be041e428c10f8b6ab358c6b393648f9457094e1dcc11b4906026d43cd380"}, + {file = "httptools-0.2.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b08d00d889a118f68f37f3c43e359aab24ee29eb2e3fe96d64c6a2ba8b9d6557"}, + {file = "httptools-0.2.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fd3b8905e21431ad306eeaf56644a68fdd621bf8f3097eff54d0f6bdf7262065"}, + {file = "httptools-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:200fc1cdf733a9ff554c0bb97a4047785cfaad9875307d6087001db3eb2b417f"}, + {file = "httptools-0.2.0.tar.gz", hash = "sha256:94505026be56652d7a530ab03d89474dc6021019d6b8682281977163b3471ea0"}, +] +httpx = [ + {file = "httpx-0.22.0-py3-none-any.whl", hash = "sha256:e35e83d1d2b9b2a609ef367cc4c1e66fd80b750348b20cc9e19d1952fc2ca3f6"}, + {file = "httpx-0.22.0.tar.gz", hash = "sha256:d8e778f76d9bbd46af49e7f062467e3157a5a3d2ae4876a4bbfd8a51ed9c9cb4"}, +] +idna = [ + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, +] +imagehash = [ + {file = "ImageHash-4.2.1.tar.gz", hash = "sha256:a4af957814bc9832d9241247ff03f76e778f890c18147900b4540af124e93011"}, +] +jieba = [ + {file = "jieba-0.42.1.tar.gz", hash = "sha256:055ca12f62674fafed09427f176506079bc135638a14e23e25be909131928db2"}, +] +kiwisolver = [ + {file = "kiwisolver-1.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1d819553730d3c2724582124aee8a03c846ec4362ded1034c16fb3ef309264e6"}, + {file = "kiwisolver-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d93a1095f83e908fc253f2fb569c2711414c0bfd451cab580466465b235b470"}, + {file = "kiwisolver-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4550a359c5157aaf8507e6820d98682872b9100ce7607f8aa070b4b8af6c298"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2210f28778c7d2ee13f3c2a20a3a22db889e75f4ec13a21072eabb5693801e84"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:82f49c5a79d3839bc8f38cb5f4bfc87e15f04cbafa5fbd12fb32c941cb529cfb"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9661a04ca3c950a8ac8c47f53cbc0b530bce1b52f516a1e87b7736fec24bfff0"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ddb500a2808c100e72c075cbb00bf32e62763c82b6a882d403f01a119e3f402"}, + {file = "kiwisolver-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72be6ebb4e92520b9726d7146bc9c9b277513a57a38efcf66db0620aec0097e0"}, + {file = "kiwisolver-1.3.2-cp310-cp310-win32.whl", hash = "sha256:83d2c9db5dfc537d0171e32de160461230eb14663299b7e6d18ca6dca21e4977"}, + {file = "kiwisolver-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:cba430db673c29376135e695c6e2501c44c256a81495da849e85d1793ee975ad"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4116ba9a58109ed5e4cb315bdcbff9838f3159d099ba5259c7c7fb77f8537492"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19554bd8d54cf41139f376753af1a644b63c9ca93f8f72009d50a2080f870f77"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a4cf5bbdc861987a7745aed7a536c6405256853c94abc9f3287c3fa401b174"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0007840186bacfaa0aba4466d5890334ea5938e0bb7e28078a0eb0e63b5b59d5"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec2eba188c1906b05b9b49ae55aae4efd8150c61ba450e6721f64620c50b59eb"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3dbb3cea20b4af4f49f84cffaf45dd5f88e8594d18568e0225e6ad9dec0e7967"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-win32.whl", hash = "sha256:5326ddfacbe51abf9469fe668944bc2e399181a2158cb5d45e1d40856b2a0589"}, + {file = "kiwisolver-1.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c6572c2dab23c86a14e82c245473d45b4c515314f1f859e92608dcafbd2f19b8"}, + {file = "kiwisolver-1.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b5074fb09429f2b7bc82b6fb4be8645dcbac14e592128beeff5461dcde0af09f"}, + {file = "kiwisolver-1.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:22521219ca739654a296eea6d4367703558fba16f98688bd8ce65abff36eaa84"}, + {file = "kiwisolver-1.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c358721aebd40c243894298f685a19eb0491a5c3e0b923b9f887ef1193ddf829"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ba5a1041480c6e0a8b11a9544d53562abc2d19220bfa14133e0cdd9967e97af"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44e6adf67577dbdfa2d9f06db9fbc5639afefdb5bf2b4dfec25c3a7fbc619536"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d45d1c74f88b9f41062716c727f78f2a59a5476ecbe74956fafb423c5c87a76"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70adc3658138bc77a36ce769f5f183169bc0a2906a4f61f09673f7181255ac9b"}, + {file = "kiwisolver-1.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6a5431940f28b6de123de42f0eb47b84a073ee3c3345dc109ad550a3307dd28"}, + {file = "kiwisolver-1.3.2-cp38-cp38-win32.whl", hash = "sha256:ee040a7de8d295dbd261ef2d6d3192f13e2b08ec4a954de34a6fb8ff6422e24c"}, + {file = "kiwisolver-1.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:8dc3d842fa41a33fe83d9f5c66c0cc1f28756530cd89944b63b072281e852031"}, + {file = "kiwisolver-1.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a498bcd005e8a3fedd0022bb30ee0ad92728154a8798b703f394484452550507"}, + {file = "kiwisolver-1.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:80efd202108c3a4150e042b269f7c78643420cc232a0a771743bb96b742f838f"}, + {file = "kiwisolver-1.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f8eb7b6716f5b50e9c06207a14172cf2de201e41912ebe732846c02c830455b9"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f441422bb313ab25de7b3dbfd388e790eceb76ce01a18199ec4944b369017009"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:30fa008c172355c7768159983a7270cb23838c4d7db73d6c0f6b60dde0d432c6"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f8f6c8f4f1cff93ca5058d6ec5f0efda922ecb3f4c5fb76181f327decff98b8"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba677bcaff9429fd1bf01648ad0901cea56c0d068df383d5f5856d88221fe75b"}, + {file = "kiwisolver-1.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7843b1624d6ccca403a610d1277f7c28ad184c5aa88a1750c1a999754e65b439"}, + {file = "kiwisolver-1.3.2-cp39-cp39-win32.whl", hash = "sha256:e6f5eb2f53fac7d408a45fbcdeda7224b1cfff64919d0f95473420a931347ae9"}, + {file = "kiwisolver-1.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:eedd3b59190885d1ebdf6c5e0ca56828beb1949b4dfe6e5d0256a461429ac386"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:dedc71c8eb9c5096037766390172c34fb86ef048b8e8958b4e484b9e505d66bc"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bf7eb45d14fc036514c09554bf983f2a72323254912ed0c3c8e697b62c4c158f"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b65bd35f3e06a47b5c30ea99e0c2b88f72c6476eedaf8cfbc8e66adb5479dcf"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25405f88a37c5f5bcba01c6e350086d65e7465fd1caaf986333d2a045045a223"}, + {file = "kiwisolver-1.3.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:bcadb05c3d4794eb9eee1dddf1c24215c92fb7b55a80beae7a60530a91060560"}, + {file = "kiwisolver-1.3.2.tar.gz", hash = "sha256:fc4453705b81d03568d5b808ad8f09c77c47534f6ac2e72e733f9ca4714aa75c"}, +] +loguru = [ + {file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"}, + {file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"}, +] +lxml = [ + {file = "lxml-4.6.5-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:abcf7daa5ebcc89328326254f6dd6d566adb483d4d00178892afd386ab389de2"}, + {file = "lxml-4.6.5-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3884476a90d415be79adfa4e0e393048630d0d5bcd5757c4c07d8b4b00a1096b"}, + {file = "lxml-4.6.5-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:add017c5bd6b9ec3a5f09248396b6ee2ce61c5621f087eb2269c813cd8813808"}, + {file = "lxml-4.6.5-cp27-cp27m-win32.whl", hash = "sha256:a702005e447d712375433ed0499cb6e1503fadd6c96a47f51d707b4d37b76d3c"}, + {file = "lxml-4.6.5-cp27-cp27m-win_amd64.whl", hash = "sha256:da07c7e7fc9a3f40446b78c54dbba8bfd5c9100dfecb21b65bfe3f57844f5e71"}, + {file = "lxml-4.6.5-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a708c291900c40a7ecf23f1d2384ed0bc0604e24094dd13417c7e7f8f7a50d93"}, + {file = "lxml-4.6.5-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f33d8efb42e4fc2b31b3b4527940b25cdebb3026fb56a80c1c1c11a4271d2352"}, + {file = "lxml-4.6.5-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:f6befb83bca720b71d6bd6326a3b26e9496ae6649e26585de024890fe50f49b8"}, + {file = "lxml-4.6.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:59d77bfa3bea13caee95bc0d3f1c518b15049b97dd61ea8b3d71ce677a67f808"}, + {file = "lxml-4.6.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:68a851176c931e2b3de6214347b767451243eeed3bea34c172127bbb5bf6c210"}, + {file = "lxml-4.6.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a7790a273225b0c46e5f859c1327f0f659896cc72eaa537d23aa3ad9ff2a1cc1"}, + {file = "lxml-4.6.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6548fc551de15f310dd0564751d9dc3d405278d45ea9b2b369ed1eccf142e1f5"}, + {file = "lxml-4.6.5-cp310-cp310-win32.whl", hash = "sha256:dc8a0dbb2a10ae8bb609584f5c504789f0f3d0d81840da4849102ec84289f952"}, + {file = "lxml-4.6.5-cp310-cp310-win_amd64.whl", hash = "sha256:1ccbfe5d17835db906f2bab6f15b34194db1a5b07929cba3cf45a96dbfbfefc0"}, + {file = "lxml-4.6.5-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca9a40497f7e97a2a961c04fa8a6f23d790b0521350a8b455759d786b0bcb203"}, + {file = "lxml-4.6.5-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e5b4b0d9440046ead3bd425eb2b852499241ee0cef1ae151038e4f87ede888c4"}, + {file = "lxml-4.6.5-cp35-cp35m-win32.whl", hash = "sha256:87f8f7df70b90fbe7b49969f07b347e3f978f8bd1046bb8ecae659921869202b"}, + {file = "lxml-4.6.5-cp35-cp35m-win_amd64.whl", hash = "sha256:ce52aad32ec6e46d1a91ff8b8014a91538800dd533914bfc4a82f5018d971408"}, + {file = "lxml-4.6.5-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:8021eeff7fabde21b9858ed058a8250ad230cede91764d598c2466b0ba70db8b"}, + {file = "lxml-4.6.5-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:cab343b265e38d4e00649cbbad9278b734c5715f9bcbb72c85a1f99b1a58e19a"}, + {file = "lxml-4.6.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:3534d7c468c044f6aef3c0aff541db2826986a29ea73f2ca831f5d5284d9b570"}, + {file = "lxml-4.6.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdb98f4c9e8a1735efddfaa995b0c96559792da15d56b76428bdfc29f77c4cdb"}, + {file = "lxml-4.6.5-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:5ea121cb66d7e5cb396b4c3ca90471252b94e01809805cfe3e4e44be2db3a99c"}, + {file = "lxml-4.6.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:121fc6f71c692b49af6c963b84ab7084402624ffbe605287da362f8af0668ea3"}, + {file = "lxml-4.6.5-cp36-cp36m-win32.whl", hash = "sha256:1a2a7659b8eb93c6daee350a0d844994d49245a0f6c05c747f619386fb90ba04"}, + {file = "lxml-4.6.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2f77556266a8fe5428b8759fbfc4bd70be1d1d9c9b25d2a414f6a0c0b0f09120"}, + {file = "lxml-4.6.5-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:558485218ee06458643b929765ac1eb04519ca3d1e2dcc288517de864c747c33"}, + {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:ba0006799f21d83c3717fe20e2707a10bbc296475155aadf4f5850f6659b96b9"}, + {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:916d457ad84e05b7db52700bad0a15c56e0c3000dcaf1263b2fb7a56fe148996"}, + {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c580c2a61d8297a6e47f4d01f066517dbb019be98032880d19ece7f337a9401d"}, + {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a21b78af7e2e13bec6bea12fc33bc05730197674f3e5402ce214d07026ccfebd"}, + {file = "lxml-4.6.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:46515773570a33eae13e451c8fcf440222ef24bd3b26f40774dd0bd8b6db15b2"}, + {file = "lxml-4.6.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:124f09614f999551ac65e5b9875981ce4b66ac4b8e2ba9284572f741935df3d9"}, + {file = "lxml-4.6.5-cp37-cp37m-win32.whl", hash = "sha256:b4015baed99d046c760f09a4c59d234d8f398a454380c3cf0b859aba97136090"}, + {file = "lxml-4.6.5-cp37-cp37m-win_amd64.whl", hash = "sha256:12ae2339d32a2b15010972e1e2467345b7bf962e155671239fba74c229564b7f"}, + {file = "lxml-4.6.5-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:76b6c296e4f7a1a8a128aec42d128646897f9ae9a700ef6839cdc9b3900db9b5"}, + {file = "lxml-4.6.5-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:534032a5ceb34bba1da193b7d386ac575127cc39338379f39a164b10d97ade89"}, + {file = "lxml-4.6.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:60aeb14ff9022d2687ef98ce55f6342944c40d00916452bb90899a191802137a"}, + {file = "lxml-4.6.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9801bcd52ac9c795a7d81ea67471a42cffe532e46cfb750cd5713befc5c019c0"}, + {file = "lxml-4.6.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3b95fb7e6f9c2f53db88f4642231fc2b8907d854e614710996a96f1f32018d5c"}, + {file = "lxml-4.6.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:642eb4cabd997c9b949a994f9643cd8ae00cf4ca8c5cd9c273962296fadf1c44"}, + {file = "lxml-4.6.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:af4139172ff0263d269abdcc641e944c9de4b5d660894a3ec7e9f9db63b56ac9"}, + {file = "lxml-4.6.5-cp38-cp38-win32.whl", hash = "sha256:57cf05466917e08f90e323f025b96f493f92c0344694f5702579ab4b7e2eb10d"}, + {file = "lxml-4.6.5-cp38-cp38-win_amd64.whl", hash = "sha256:4f415624cf8b065796649a5e4621773dc5c9ea574a944c76a7f8a6d3d2906b41"}, + {file = "lxml-4.6.5-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:7679bb6e4d9a3978a46ab19a3560e8d2b7265ef3c88152e7fdc130d649789887"}, + {file = "lxml-4.6.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c34234a1bc9e466c104372af74d11a9f98338a3f72fae22b80485171a64e0144"}, + {file = "lxml-4.6.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4b9390bf973e3907d967b75be199cf1978ca8443183cf1e78ad80ad8be9cf242"}, + {file = "lxml-4.6.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fcc849b28f584ed1dbf277291ded5c32bb3476a37032df4a1d523b55faa5f944"}, + {file = "lxml-4.6.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:46f21f2600d001af10e847df9eb3b832e8a439f696c04891bcb8a8cedd859af9"}, + {file = "lxml-4.6.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:99cf827f5a783038eb313beee6533dddb8bdb086d7269c5c144c1c952d142ace"}, + {file = "lxml-4.6.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:925174cafb0f1179a7fd38da90302555d7445e34c9ece68019e53c946be7f542"}, + {file = "lxml-4.6.5-cp39-cp39-win32.whl", hash = "sha256:12d8d6fe3ddef629ac1349fa89a638b296a34b6529573f5055d1cb4e5245f73b"}, + {file = "lxml-4.6.5-cp39-cp39-win_amd64.whl", hash = "sha256:a52e8f317336a44836475e9c802f51c2dc38d612eaa76532cb1d17690338b63b"}, + {file = "lxml-4.6.5-pp37-pypy37_pp73-macosx_10_14_x86_64.whl", hash = "sha256:11ae552a78612620afd15625be9f1b82e3cc2e634f90d6b11709b10a100cba59"}, + {file = "lxml-4.6.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:473701599665d874919d05bb33b56180447b3a9da8d52d6d9799f381ce23f95c"}, + {file = "lxml-4.6.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:7f00cc64b49d2ef19ddae898a3def9dd8fda9c3d27c8a174c2889ee757918e71"}, + {file = "lxml-4.6.5-pp38-pypy38_pp73-macosx_10_14_x86_64.whl", hash = "sha256:73e8614258404b2689a26cb5d002512b8bc4dfa18aca86382f68f959aee9b0c8"}, + {file = "lxml-4.6.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:ff44de36772b05c2eb74f2b4b6d1ae29b8f41ed5506310ce1258d44826ee38c1"}, + {file = "lxml-4.6.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:5d5254c815c186744c8f922e2ce861a2bdeabc06520b4b30b2f7d9767791ce6e"}, + {file = "lxml-4.6.5.tar.gz", hash = "sha256:6e84edecc3a82f90d44ddee2ee2a2630d4994b8471816e226d2b771cda7ac4ca"}, +] +matplotlib = [ + {file = "matplotlib-3.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:456cc8334f6d1124e8ff856b42d2cc1c84335375a16448189999496549f7182b"}, + {file = "matplotlib-3.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8a77906dc2ef9b67407cec0bdbf08e3971141e535db888974a915be5e1e3efc6"}, + {file = "matplotlib-3.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e70ae6475cfd0fad3816dcbf6cac536dc6f100f7474be58d59fa306e6e768a4"}, + {file = "matplotlib-3.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53273c5487d1c19c3bc03b9eb82adaf8456f243b97ed79d09dded747abaf1235"}, + {file = "matplotlib-3.5.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3b6f3fd0d8ca37861c31e9a7cab71a0ef14c639b4c95654ea1dd153158bf0df"}, + {file = "matplotlib-3.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8c87cdaf06fd7b2477f68909838ff4176f105064a72ca9d24d3f2a29f73d393"}, + {file = "matplotlib-3.5.1-cp310-cp310-win32.whl", hash = "sha256:e2f28a07b4f82abb40267864ad7b3a4ed76f1b1663e81c7efc84a9b9248f672f"}, + {file = "matplotlib-3.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:d70a32ee1f8b55eed3fd4e892f0286df8cccc7e0475c11d33b5d0a148f5c7599"}, + {file = "matplotlib-3.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:68fa30cec89b6139dc559ed6ef226c53fd80396da1919a1b5ef672c911aaa767"}, + {file = "matplotlib-3.5.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e3484d8455af3fdb0424eae1789af61f6a79da0c80079125112fd5c1b604218"}, + {file = "matplotlib-3.5.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e293b16cf303fe82995e41700d172a58a15efc5331125d08246b520843ef21ee"}, + {file = "matplotlib-3.5.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e3520a274a0e054e919f5b3279ee5dbccf5311833819ccf3399dab7c83e90a25"}, + {file = "matplotlib-3.5.1-cp37-cp37m-win32.whl", hash = "sha256:2252bfac85cec7af4a67e494bfccf9080bcba8a0299701eab075f48847cca907"}, + {file = "matplotlib-3.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:abf67e05a1b7f86583f6ebd01f69b693b9c535276f4e943292e444855870a1b8"}, + {file = "matplotlib-3.5.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6c094e4bfecd2fa7f9adffd03d8abceed7157c928c2976899de282f3600f0a3d"}, + {file = "matplotlib-3.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:506b210cc6e66a0d1c2bb765d055f4f6bc2745070fb1129203b67e85bbfa5c18"}, + {file = "matplotlib-3.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b04fc29bcef04d4e2d626af28d9d892be6aba94856cb46ed52bcb219ceac8943"}, + {file = "matplotlib-3.5.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:577ed20ec9a18d6bdedb4616f5e9e957b4c08563a9f985563a31fd5b10564d2a"}, + {file = "matplotlib-3.5.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e486f60db0cd1c8d68464d9484fd2a94011c1ac8593d765d0211f9daba2bd535"}, + {file = "matplotlib-3.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b71f3a7ca935fc759f2aed7cec06cfe10bc3100fadb5dbd9c435b04e557971e1"}, + {file = "matplotlib-3.5.1-cp38-cp38-win32.whl", hash = "sha256:d24e5bb8028541ce25e59390122f5e48c8506b7e35587e5135efcb6471b4ac6c"}, + {file = "matplotlib-3.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:778d398c4866d8e36ee3bf833779c940b5f57192fa0a549b3ad67bc4c822771b"}, + {file = "matplotlib-3.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bb1c613908f11bac270bc7494d68b1ef6e7c224b7a4204d5dacf3522a41e2bc3"}, + {file = "matplotlib-3.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:edf5e4e1d5fb22c18820e8586fb867455de3b109c309cb4fce3aaed85d9468d1"}, + {file = "matplotlib-3.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:40e0d7df05e8efe60397c69b467fc8f87a2affeb4d562fe92b72ff8937a2b511"}, + {file = "matplotlib-3.5.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a350ca685d9f594123f652ba796ee37219bf72c8e0fc4b471473d87121d6d34"}, + {file = "matplotlib-3.5.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3e66497cd990b1a130e21919b004da2f1dc112132c01ac78011a90a0f9229778"}, + {file = "matplotlib-3.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:87900c67c0f1728e6db17c6809ec05c025c6624dcf96a8020326ea15378fe8e7"}, + {file = "matplotlib-3.5.1-cp39-cp39-win32.whl", hash = "sha256:b8a4fb2a0c5afbe9604f8a91d7d0f27b1832c3e0b5e365f95a13015822b4cd65"}, + {file = "matplotlib-3.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:fe8d40c434a8e2c68d64c6d6a04e77f21791a93ff6afe0dce169597c110d3079"}, + {file = "matplotlib-3.5.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:34a1fc29f8f96e78ec57a5eff5e8d8b53d3298c3be6df61e7aa9efba26929522"}, + {file = "matplotlib-3.5.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b19a761b948e939a9e20173aaae76070025f0024fc8f7ba08bef22a5c8573afc"}, + {file = "matplotlib-3.5.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6803299cbf4665eca14428d9e886de62e24f4223ac31ab9c5d6d5339a39782c7"}, + {file = "matplotlib-3.5.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:14334b9902ec776461c4b8c6516e26b450f7ebe0b3ef8703bf5cdfbbaecf774a"}, + {file = "matplotlib-3.5.1.tar.gz", hash = "sha256:b2e9810e09c3a47b73ce9cab5a72243a1258f61e7900969097a817232246ce1c"}, +] +multidict = [ + {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"}, + {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3"}, + {file = "multidict-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:041b81a5f6b38244b34dc18c7b6aba91f9cdaf854d9a39e5ff0b58e2b5773b9c"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fdda29a3c7e76a064f2477c9aab1ba96fd94e02e386f1e665bca1807fc5386f"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3368bf2398b0e0fcbf46d85795adc4c259299fec50c1416d0f77c0a843a3eed9"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4f052ee022928d34fe1f4d2bc743f32609fb79ed9c49a1710a5ad6b2198db20"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:225383a6603c086e6cef0f2f05564acb4f4d5f019a4e3e983f572b8530f70c88"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50bd442726e288e884f7be9071016c15a8742eb689a593a0cac49ea093eef0a7"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:47e6a7e923e9cada7c139531feac59448f1f47727a79076c0b1ee80274cd8eee"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0556a1d4ea2d949efe5fd76a09b4a82e3a4a30700553a6725535098d8d9fb672"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:626fe10ac87851f4cffecee161fc6f8f9853f0f6f1035b59337a51d29ff3b4f9"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8064b7c6f0af936a741ea1efd18690bacfbae4078c0c385d7c3f611d11f0cf87"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2d36e929d7f6a16d4eb11b250719c39560dd70545356365b494249e2186bc389"}, + {file = "multidict-6.0.2-cp310-cp310-win32.whl", hash = "sha256:fcb91630817aa8b9bc4a74023e4198480587269c272c58b3279875ed7235c293"}, + {file = "multidict-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:8cbf0132f3de7cc6c6ce00147cc78e6439ea736cee6bca4f068bcf892b0fd658"}, + {file = "multidict-6.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:05f6949d6169878a03e607a21e3b862eaf8e356590e8bdae4227eedadacf6e51"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2c2e459f7050aeb7c1b1276763364884595d47000c1cddb51764c0d8976e608"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0509e469d48940147e1235d994cd849a8f8195e0bca65f8f5439c56e17872a3"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:514fe2b8d750d6cdb4712346a2c5084a80220821a3e91f3f71eec11cf8d28fd4"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19adcfc2a7197cdc3987044e3f415168fc5dc1f720c932eb1ef4f71a2067e08b"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9d153e7f1f9ba0b23ad1568b3b9e17301e23b042c23870f9ee0522dc5cc79e8"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:aef9cc3d9c7d63d924adac329c33835e0243b5052a6dfcbf7732a921c6e918ba"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4571f1beddff25f3e925eea34268422622963cd8dc395bb8778eb28418248e43"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:d48b8ee1d4068561ce8033d2c344cf5232cb29ee1a0206a7b828c79cbc5982b8"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:45183c96ddf61bf96d2684d9fbaf6f3564d86b34cb125761f9a0ef9e36c1d55b"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:75bdf08716edde767b09e76829db8c1e5ca9d8bb0a8d4bd94ae1eafe3dac5e15"}, + {file = "multidict-6.0.2-cp37-cp37m-win32.whl", hash = "sha256:a45e1135cb07086833ce969555df39149680e5471c04dfd6a915abd2fc3f6dbc"}, + {file = "multidict-6.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f3cdef8a247d1eafa649085812f8a310e728bdf3900ff6c434eafb2d443b23a"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0327292e745a880459ef71be14e709aaea2f783f3537588fb4ed09b6c01bca60"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e875b6086e325bab7e680e4316d667fc0e5e174bb5611eb16b3ea121c8951b86"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feea820722e69451743a3d56ad74948b68bf456984d63c1a92e8347b7b88452d"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc57c68cb9139c7cd6fc39f211b02198e69fb90ce4bc4a094cf5fe0d20fd8b0"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:497988d6b6ec6ed6f87030ec03280b696ca47dbf0648045e4e1d28b80346560d"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:89171b2c769e03a953d5969b2f272efa931426355b6c0cb508022976a17fd376"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684133b1e1fe91eda8fa7447f137c9490a064c6b7f392aa857bba83a28cfb693"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd9fc9c4849a07f3635ccffa895d57abce554b467d611a5009ba4f39b78a8849"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e07c8e79d6e6fd37b42f3250dba122053fddb319e84b55dd3a8d6446e1a7ee49"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4070613ea2227da2bfb2c35a6041e4371b0af6b0be57f424fe2318b42a748516"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:47fbeedbf94bed6547d3aa632075d804867a352d86688c04e606971595460227"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5774d9218d77befa7b70d836004a768fb9aa4fdb53c97498f4d8d3f67bb9cfa9"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2957489cba47c2539a8eb7ab32ff49101439ccf78eab724c828c1a54ff3ff98d"}, + {file = "multidict-6.0.2-cp38-cp38-win32.whl", hash = "sha256:e5b20e9599ba74391ca0cfbd7b328fcc20976823ba19bc573983a25b32e92b57"}, + {file = "multidict-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:8004dca28e15b86d1b1372515f32eb6f814bdf6f00952699bdeb541691091f96"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2e4a0785b84fb59e43c18a015ffc575ba93f7d1dbd272b4cdad9f5134b8a006c"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6701bf8a5d03a43375909ac91b6980aea74b0f5402fbe9428fc3f6edf5d9677e"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a007b1638e148c3cfb6bf0bdc4f82776cef0ac487191d093cdc316905e504071"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07a017cfa00c9890011628eab2503bee5872f27144936a52eaab449be5eaf032"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c207fff63adcdf5a485969131dc70e4b194327666b7e8a87a97fbc4fd80a53b2"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:373ba9d1d061c76462d74e7de1c0c8e267e9791ee8cfefcf6b0b2495762c370c"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfba7c6d5d7c9099ba21f84662b037a0ffd4a5e6b26ac07d19e423e6fdf965a9"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19d9bad105dfb34eb539c97b132057a4e709919ec4dd883ece5838bcbf262b80"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:de989b195c3d636ba000ee4281cd03bb1234635b124bf4cd89eeee9ca8fcb09d"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7c40b7bbece294ae3a87c1bc2abff0ff9beef41d14188cda94ada7bcea99b0fb"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:d16cce709ebfadc91278a1c005e3c17dd5f71f5098bfae1035149785ea6e9c68"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:a2c34a93e1d2aa35fbf1485e5010337c72c6791407d03aa5f4eed920343dd360"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:feba80698173761cddd814fa22e88b0661e98cb810f9f986c54aa34d281e4937"}, + {file = "multidict-6.0.2-cp39-cp39-win32.whl", hash = "sha256:23b616fdc3c74c9fe01d76ce0d1ce872d2d396d8fa8e4899398ad64fb5aa214a"}, + {file = "multidict-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae"}, + {file = "multidict-6.0.2.tar.gz", hash = "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] +nonebot-adapter-onebot = [ + {file = "nonebot-adapter-onebot-2.0.0b1.tar.gz", hash = "sha256:9dad770371e577fead096ceacacc43b3ef304a8e238e8fff1163eefc4e947a75"}, + {file = "nonebot_adapter_onebot-2.0.0b1-py3-none-any.whl", hash = "sha256:ca1375de1dd503a5ab20440445026195b587e05a2b18ae8df9b6ab17c9e857b5"}, +] +nonebot-plugin-apscheduler = [ + {file = "nonebot-plugin-apscheduler-0.1.2.tar.gz", hash = "sha256:1765336cd388dde15f723ed12dbca942b04e4c25d5d7786878e447b09e68b909"}, + {file = "nonebot_plugin_apscheduler-0.1.2-py3-none-any.whl", hash = "sha256:eed7b9e60d08826ae4919f82dc240fc7ec469185271c2271e14438a3e0ca7692"}, +] +nonebot2 = [ + {file = "nonebot2-2.0.0b2-py3-none-any.whl", hash = "sha256:8166490311b607f8fbf5e31934b005e29f6d39ff222a6771ec36c9456ec337ec"}, + {file = "nonebot2-2.0.0b2.tar.gz", hash = "sha256:2950f27a62f2a98b2abf3128c19d898a24c2867e70fb5c6af231eadf558b18a8"}, +] +numpy = [ + {file = "numpy-1.22.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:515a8b6edbb904594685da6e176ac9fbea8f73a5ebae947281de6613e27f1956"}, + {file = "numpy-1.22.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:76a4f9bce0278becc2da7da3b8ef854bed41a991f4226911a24a9711baad672c"}, + {file = "numpy-1.22.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:168259b1b184aa83a514f307352c25c56af111c269ffc109d9704e81f72e764b"}, + {file = "numpy-1.22.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3556c5550de40027d3121ebbb170f61bbe19eb639c7ad0c7b482cd9b560cd23b"}, + {file = "numpy-1.22.2-cp310-cp310-win_amd64.whl", hash = "sha256:aafa46b5a39a27aca566198d3312fb3bde95ce9677085efd02c86f7ef6be4ec7"}, + {file = "numpy-1.22.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:55535c7c2f61e2b2fc817c5cbe1af7cb907c7f011e46ae0a52caa4be1f19afe2"}, + {file = "numpy-1.22.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:60cb8e5933193a3cc2912ee29ca331e9c15b2da034f76159b7abc520b3d1233a"}, + {file = "numpy-1.22.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b536b6840e84c1c6a410f3a5aa727821e6108f3454d81a5cd5900999ef04f89"}, + {file = "numpy-1.22.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2638389562bda1635b564490d76713695ff497242a83d9b684d27bb4a6cc9d7a"}, + {file = "numpy-1.22.2-cp38-cp38-win32.whl", hash = "sha256:6767ad399e9327bfdbaa40871be4254d1995f4a3ca3806127f10cec778bd9896"}, + {file = "numpy-1.22.2-cp38-cp38-win_amd64.whl", hash = "sha256:03ae5850619abb34a879d5f2d4bb4dcd025d6d8fb72f5e461dae84edccfe129f"}, + {file = "numpy-1.22.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:d76a26c5118c4d96e264acc9e3242d72e1a2b92e739807b3b69d8d47684b6677"}, + {file = "numpy-1.22.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:15efb7b93806d438e3bc590ca8ef2f953b0ce4f86f337ef4559d31ec6cf9d7dd"}, + {file = "numpy-1.22.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:badca914580eb46385e7f7e4e426fea6de0a37b9e06bec252e481ae7ec287082"}, + {file = "numpy-1.22.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94dd11d9f13ea1be17bac39c1942f527cbf7065f94953cf62dfe805653da2f8f"}, + {file = "numpy-1.22.2-cp39-cp39-win32.whl", hash = "sha256:8cf33634b60c9cef346663a222d9841d3bbbc0a2f00221d6bcfd0d993d5543f6"}, + {file = "numpy-1.22.2-cp39-cp39-win_amd64.whl", hash = "sha256:59153979d60f5bfe9e4c00e401e24dfe0469ef8da6d68247439d3278f30a180f"}, + {file = "numpy-1.22.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a176959b6e7e00b5a0d6f549a479f869829bfd8150282c590deee6d099bbb6e"}, + {file = "numpy-1.22.2.zip", hash = "sha256:076aee5a3763d41da6bef9565fdf3cb987606f567cd8b104aded2b38b7b47abf"}, +] +opencv-python = [ + {file = "opencv-python-4.5.5.62.tar.gz", hash = "sha256:3efe232b32d5e1327e7c82bc6d61230737821c5190ce5c783e64a1bc8d514e18"}, + {file = "opencv_python-4.5.5.62-cp36-abi3-macosx_10_15_x86_64.whl", hash = "sha256:2601388def0d6b957cc30dd88f8ff74a5651ae6940dd9e488241608cfa2b15c7"}, + {file = "opencv_python-4.5.5.62-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71fdc49df412b102d97f14927321309043c79c4a3582cce1dc803370ff9c39c0"}, + {file = "opencv_python-4.5.5.62-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:130cc75d56b29aa3c5de8b6ac438242dd2574ba6eaa8bccdffdcfd6b78632f7f"}, + {file = "opencv_python-4.5.5.62-cp36-abi3-win32.whl", hash = "sha256:3a75c7ad45b032eea0c72e389aac6dd435f5c87e87f60237095c083400bc23aa"}, + {file = "opencv_python-4.5.5.62-cp36-abi3-win_amd64.whl", hash = "sha256:c463d2276d8662b972d20ca9644702188507de200ca5405b89e1fe71c5c99989"}, + {file = "opencv_python-4.5.5.62-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:ac92e743e22681f30001942d78512c1e39bce53dbffc504e5645fdc45c0f2c47"}, +] +packaging = [ + {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, + {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, +] +pathspec = [ + {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, + {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, +] +pillow = [ + {file = "Pillow-9.0.1-1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a5d24e1d674dd9d72c66ad3ea9131322819ff86250b30dc5821cbafcfa0b96b4"}, + {file = "Pillow-9.0.1-1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2632d0f846b7c7600edf53c48f8f9f1e13e62f66a6dbc15191029d950bfed976"}, + {file = "Pillow-9.0.1-1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9618823bd237c0d2575283f2939655f54d51b4527ec3972907a927acbcc5bfc"}, + {file = "Pillow-9.0.1-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:9bfdb82cdfeccec50aad441afc332faf8606dfa5e8efd18a6692b5d6e79f00fd"}, + {file = "Pillow-9.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5100b45a4638e3c00e4d2320d3193bdabb2d75e79793af7c3eb139e4f569f16f"}, + {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:528a2a692c65dd5cafc130de286030af251d2ee0483a5bf50c9348aefe834e8a"}, + {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f29d831e2151e0b7b39981756d201f7108d3d215896212ffe2e992d06bfe049"}, + {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:855c583f268edde09474b081e3ddcd5cf3b20c12f26e0d434e1386cc5d318e7a"}, + {file = "Pillow-9.0.1-cp310-cp310-win32.whl", hash = "sha256:d9d7942b624b04b895cb95af03a23407f17646815495ce4547f0e60e0b06f58e"}, + {file = "Pillow-9.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:81c4b81611e3a3cb30e59b0cf05b888c675f97e3adb2c8672c3154047980726b"}, + {file = "Pillow-9.0.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:413ce0bbf9fc6278b2d63309dfeefe452835e1c78398efb431bab0672fe9274e"}, + {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80fe64a6deb6fcfdf7b8386f2cf216d329be6f2781f7d90304351811fb591360"}, + {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cef9c85ccbe9bee00909758936ea841ef12035296c748aaceee535969e27d31b"}, + {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d19397351f73a88904ad1aee421e800fe4bbcd1aeee6435fb62d0a05ccd1030"}, + {file = "Pillow-9.0.1-cp37-cp37m-win32.whl", hash = "sha256:d21237d0cd37acded35154e29aec853e945950321dd2ffd1a7d86fe686814669"}, + {file = "Pillow-9.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ede5af4a2702444a832a800b8eb7f0a7a1c0eed55b644642e049c98d589e5092"}, + {file = "Pillow-9.0.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:b5b3f092fe345c03bca1e0b687dfbb39364b21ebb8ba90e3fa707374b7915204"}, + {file = "Pillow-9.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:335ace1a22325395c4ea88e00ba3dc89ca029bd66bd5a3c382d53e44f0ccd77e"}, + {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db6d9fac65bd08cea7f3540b899977c6dee9edad959fa4eaf305940d9cbd861c"}, + {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f154d173286a5d1863637a7dcd8c3437bb557520b01bddb0be0258dcb72696b5"}, + {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d4b1341ac07ae07eb2cc682f459bec932a380c3b122f5540432d8977e64eae"}, + {file = "Pillow-9.0.1-cp38-cp38-win32.whl", hash = "sha256:effb7749713d5317478bb3acb3f81d9d7c7f86726d41c1facca068a04cf5bb4c"}, + {file = "Pillow-9.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:7f7609a718b177bf171ac93cea9fd2ddc0e03e84d8fa4e887bdfc39671d46b00"}, + {file = "Pillow-9.0.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:80ca33961ced9c63358056bd08403ff866512038883e74f3a4bf88ad3eb66838"}, + {file = "Pillow-9.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c3c33ac69cf059bbb9d1a71eeaba76781b450bc307e2291f8a4764d779a6b28"}, + {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12875d118f21cf35604176872447cdb57b07126750a33748bac15e77f90f1f9c"}, + {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:514ceac913076feefbeaf89771fd6febde78b0c4c1b23aaeab082c41c694e81b"}, + {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3c5c79ab7dfce6d88f1ba639b77e77a17ea33a01b07b99840d6ed08031cb2a7"}, + {file = "Pillow-9.0.1-cp39-cp39-win32.whl", hash = "sha256:718856856ba31f14f13ba885ff13874be7fefc53984d2832458f12c38205f7f7"}, + {file = "Pillow-9.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:f25ed6e28ddf50de7e7ea99d7a976d6a9c415f03adcaac9c41ff6ff41b6d86ac"}, + {file = "Pillow-9.0.1-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:011233e0c42a4a7836498e98c1acf5e744c96a67dd5032a6f666cc1fb97eab97"}, + {file = "Pillow-9.0.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:253e8a302a96df6927310a9d44e6103055e8fb96a6822f8b7f514bb7ef77de56"}, + {file = "Pillow-9.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6295f6763749b89c994fcb6d8a7f7ce03c3992e695f89f00b741b4580b199b7e"}, + {file = "Pillow-9.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a9f44cd7e162ac6191491d7249cceb02b8116b0f7e847ee33f739d7cb1ea1f70"}, + {file = "Pillow-9.0.1.tar.gz", hash = "sha256:6c8bc8238a7dfdaf7a75f5ec5a663f4173f8c367e5a39f87e720495e1eed75fa"}, +] +platformdirs = [ + {file = "platformdirs-2.5.0-py3-none-any.whl", hash = "sha256:30671902352e97b1eafd74ade8e4a694782bd3471685e78c32d0fdfd3aa7e7bb"}, + {file = "platformdirs-2.5.0.tar.gz", hash = "sha256:8ec11dfba28ecc0715eb5fb0147a87b1bf325f349f3da9aab2cd6b50b96b692b"}, +] +playwright = [ + {file = "playwright-1.18.2-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:5b512d0d734a2b6bc001461fdf1cc65e5ef1c8489187d03f6a7c0ed3552fe469"}, + {file = "playwright-1.18.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:75aacc73bdfb6c6832e7a09f3e9d356db0e2bd8f18d719b068c17c841c0a5507"}, + {file = "playwright-1.18.2-py3-none-macosx_11_0_universal2.whl", hash = "sha256:0d69764ea9a216ce933eb5679ff6aa6399e7e9e43360809ec261549741e1b8d6"}, + {file = "playwright-1.18.2-py3-none-manylinux1_x86_64.whl", hash = "sha256:425c475b65562a6a2f7d46c5dcaa13d8ff098da101a100600016d320325ec436"}, + {file = "playwright-1.18.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d640e10ce2a41fb474be74526ec1413e71ed242b963a63b4a0ff6f30afabb5d"}, + {file = "playwright-1.18.2-py3-none-win32.whl", hash = "sha256:51f946c98805eedc965673e873c4d828af298cbe171ef26a256d653e3730632a"}, + {file = "playwright-1.18.2-py3-none-win_amd64.whl", hash = "sha256:4b55758555dd3937ed0722446182f0b97e96704895bea47cf58d04fd7a900edb"}, +] +psutil = [ + {file = "psutil-5.9.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:55ce319452e3d139e25d6c3f85a1acf12d1607ddedea5e35fb47a552c051161b"}, + {file = "psutil-5.9.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:7336292a13a80eb93c21f36bde4328aa748a04b68c13d01dfddd67fc13fd0618"}, + {file = "psutil-5.9.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:cb8d10461c1ceee0c25a64f2dd54872b70b89c26419e147a05a10b753ad36ec2"}, + {file = "psutil-5.9.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:7641300de73e4909e5d148e90cc3142fb890079e1525a840cf0dfd39195239fd"}, + {file = "psutil-5.9.0-cp27-none-win32.whl", hash = "sha256:ea42d747c5f71b5ccaa6897b216a7dadb9f52c72a0fe2b872ef7d3e1eacf3ba3"}, + {file = "psutil-5.9.0-cp27-none-win_amd64.whl", hash = "sha256:ef216cc9feb60634bda2f341a9559ac594e2eeaadd0ba187a4c2eb5b5d40b91c"}, + {file = "psutil-5.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90a58b9fcae2dbfe4ba852b57bd4a1dded6b990a33d6428c7614b7d48eccb492"}, + {file = "psutil-5.9.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff0d41f8b3e9ebb6b6110057e40019a432e96aae2008951121ba4e56040b84f3"}, + {file = "psutil-5.9.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:742c34fff804f34f62659279ed5c5b723bb0195e9d7bd9907591de9f8f6558e2"}, + {file = "psutil-5.9.0-cp310-cp310-win32.whl", hash = "sha256:8293942e4ce0c5689821f65ce6522ce4786d02af57f13c0195b40e1edb1db61d"}, + {file = "psutil-5.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:9b51917c1af3fa35a3f2dabd7ba96a2a4f19df3dec911da73875e1edaf22a40b"}, + {file = "psutil-5.9.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e9805fed4f2a81de98ae5fe38b75a74c6e6ad2df8a5c479594c7629a1fe35f56"}, + {file = "psutil-5.9.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c51f1af02334e4b516ec221ee26b8fdf105032418ca5a5ab9737e8c87dafe203"}, + {file = "psutil-5.9.0-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32acf55cb9a8cbfb29167cd005951df81b567099295291bcfd1027365b36591d"}, + {file = "psutil-5.9.0-cp36-cp36m-win32.whl", hash = "sha256:e5c783d0b1ad6ca8a5d3e7b680468c9c926b804be83a3a8e95141b05c39c9f64"}, + {file = "psutil-5.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:d62a2796e08dd024b8179bd441cb714e0f81226c352c802fca0fd3f89eeacd94"}, + {file = "psutil-5.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3d00a664e31921009a84367266b35ba0aac04a2a6cad09c550a89041034d19a0"}, + {file = "psutil-5.9.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7779be4025c540d1d65a2de3f30caeacc49ae7a2152108adeaf42c7534a115ce"}, + {file = "psutil-5.9.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:072664401ae6e7c1bfb878c65d7282d4b4391f1bc9a56d5e03b5a490403271b5"}, + {file = "psutil-5.9.0-cp37-cp37m-win32.whl", hash = "sha256:df2c8bd48fb83a8408c8390b143c6a6fa10cb1a674ca664954de193fdcab36a9"}, + {file = "psutil-5.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1d7b433519b9a38192dfda962dd8f44446668c009833e1429a52424624f408b4"}, + {file = "psutil-5.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c3400cae15bdb449d518545cbd5b649117de54e3596ded84aacabfbb3297ead2"}, + {file = "psutil-5.9.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2237f35c4bbae932ee98902a08050a27821f8f6dfa880a47195e5993af4702d"}, + {file = "psutil-5.9.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1070a9b287846a21a5d572d6dddd369517510b68710fca56b0e9e02fd24bed9a"}, + {file = "psutil-5.9.0-cp38-cp38-win32.whl", hash = "sha256:76cebf84aac1d6da5b63df11fe0d377b46b7b500d892284068bacccf12f20666"}, + {file = "psutil-5.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:3151a58f0fbd8942ba94f7c31c7e6b310d2989f4da74fcbf28b934374e9bf841"}, + {file = "psutil-5.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:539e429da49c5d27d5a58e3563886057f8fc3868a5547b4f1876d9c0f007bccf"}, + {file = "psutil-5.9.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58c7d923dc209225600aec73aa2c4ae8ea33b1ab31bc11ef8a5933b027476f07"}, + {file = "psutil-5.9.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3611e87eea393f779a35b192b46a164b1d01167c9d323dda9b1e527ea69d697d"}, + {file = "psutil-5.9.0-cp39-cp39-win32.whl", hash = "sha256:4e2fb92e3aeae3ec3b7b66c528981fd327fb93fd906a77215200404444ec1845"}, + {file = "psutil-5.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:7d190ee2eaef7831163f254dc58f6d2e2a22e27382b936aab51c835fc080c3d3"}, + {file = "psutil-5.9.0.tar.gz", hash = "sha256:869842dbd66bb80c3217158e629d6fceaecc3a3166d3d1faee515b05dd26ca25"}, +] +pydantic = [ + {file = "pydantic-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cb23bcc093697cdea2708baae4f9ba0e972960a835af22560f6ae4e7e47d33f5"}, + {file = "pydantic-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1d5278bd9f0eee04a44c712982343103bba63507480bfd2fc2790fa70cd64cf4"}, + {file = "pydantic-1.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab624700dc145aa809e6f3ec93fb8e7d0f99d9023b713f6a953637429b437d37"}, + {file = "pydantic-1.9.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c8d7da6f1c1049eefb718d43d99ad73100c958a5367d30b9321b092771e96c25"}, + {file = "pydantic-1.9.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3c3b035103bd4e2e4a28da9da7ef2fa47b00ee4a9cf4f1a735214c1bcd05e0f6"}, + {file = "pydantic-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3011b975c973819883842c5ab925a4e4298dffccf7782c55ec3580ed17dc464c"}, + {file = "pydantic-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:086254884d10d3ba16da0588604ffdc5aab3f7f09557b998373e885c690dd398"}, + {file = "pydantic-1.9.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0fe476769acaa7fcddd17cadd172b156b53546ec3614a4d880e5d29ea5fbce65"}, + {file = "pydantic-1.9.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8e9dcf1ac499679aceedac7e7ca6d8641f0193c591a2d090282aaf8e9445a46"}, + {file = "pydantic-1.9.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1e4c28f30e767fd07f2ddc6f74f41f034d1dd6bc526cd59e63a82fe8bb9ef4c"}, + {file = "pydantic-1.9.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:c86229333cabaaa8c51cf971496f10318c4734cf7b641f08af0a6fbf17ca3054"}, + {file = "pydantic-1.9.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:c0727bda6e38144d464daec31dff936a82917f431d9c39c39c60a26567eae3ed"}, + {file = "pydantic-1.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:dee5ef83a76ac31ab0c78c10bd7d5437bfdb6358c95b91f1ba7ff7b76f9996a1"}, + {file = "pydantic-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9c9bdb3af48e242838f9f6e6127de9be7063aad17b32215ccc36a09c5cf1070"}, + {file = "pydantic-1.9.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ee7e3209db1e468341ef41fe263eb655f67f5c5a76c924044314e139a1103a2"}, + {file = "pydantic-1.9.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b6037175234850ffd094ca77bf60fb54b08b5b22bc85865331dd3bda7a02fa1"}, + {file = "pydantic-1.9.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b2571db88c636d862b35090ccf92bf24004393f85c8870a37f42d9f23d13e032"}, + {file = "pydantic-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8b5ac0f1c83d31b324e57a273da59197c83d1bb18171e512908fe5dc7278a1d6"}, + {file = "pydantic-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:bbbc94d0c94dd80b3340fc4f04fd4d701f4b038ebad72c39693c794fd3bc2d9d"}, + {file = "pydantic-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e0896200b6a40197405af18828da49f067c2fa1f821491bc8f5bde241ef3f7d7"}, + {file = "pydantic-1.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bdfdadb5994b44bd5579cfa7c9b0e1b0e540c952d56f627eb227851cda9db77"}, + {file = "pydantic-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:574936363cd4b9eed8acdd6b80d0143162f2eb654d96cb3a8ee91d3e64bf4cf9"}, + {file = "pydantic-1.9.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c556695b699f648c58373b542534308922c46a1cda06ea47bc9ca45ef5b39ae6"}, + {file = "pydantic-1.9.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f947352c3434e8b937e3aa8f96f47bdfe6d92779e44bb3f41e4c213ba6a32145"}, + {file = "pydantic-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5e48ef4a8b8c066c4a31409d91d7ca372a774d0212da2787c0d32f8045b1e034"}, + {file = "pydantic-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:96f240bce182ca7fe045c76bcebfa0b0534a1bf402ed05914a6f1dadff91877f"}, + {file = "pydantic-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:815ddebb2792efd4bba5488bc8fde09c29e8ca3227d27cf1c6990fc830fd292b"}, + {file = "pydantic-1.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c5b77947b9e85a54848343928b597b4f74fc364b70926b3c4441ff52620640c"}, + {file = "pydantic-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c68c3bc88dbda2a6805e9a142ce84782d3930f8fdd9655430d8576315ad97ce"}, + {file = "pydantic-1.9.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a79330f8571faf71bf93667d3ee054609816f10a259a109a0738dac983b23c3"}, + {file = "pydantic-1.9.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f5a64b64ddf4c99fe201ac2724daada8595ada0d102ab96d019c1555c2d6441d"}, + {file = "pydantic-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a733965f1a2b4090a5238d40d983dcd78f3ecea221c7af1497b845a9709c1721"}, + {file = "pydantic-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cc6a4cb8a118ffec2ca5fcb47afbacb4f16d0ab8b7350ddea5e8ef7bcc53a16"}, + {file = "pydantic-1.9.0-py3-none-any.whl", hash = "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3"}, + {file = "pydantic-1.9.0.tar.gz", hash = "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a"}, +] +pyee = [ + {file = "pyee-8.1.0-py2.py3-none-any.whl", hash = "sha256:383973b63ad7ed5e3c0311f8b179c52981f9e7b3eaea0e9a830d13ec34dde65f"}, + {file = "pyee-8.1.0.tar.gz", hash = "sha256:92dacc5bd2bdb8f95aa8dd2585d47ca1c4840e2adb95ccf90034d64f725bfd31"}, +] +pygtrie = [ + {file = "pygtrie-2.4.2.tar.gz", hash = "sha256:43205559d28863358dbbf25045029f58e2ab357317a59b11f11ade278ac64692"}, +] +pyparsing = [ + {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, + {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, +] +pypinyin = [ + {file = "pypinyin-0.46.0-py2.py3-none-any.whl", hash = "sha256:7251f4fa0b1e43ad91f6121d9a842e8acd72a6a34deea5e87d2a97621eadc11f"}, + {file = "pypinyin-0.46.0.tar.gz", hash = "sha256:0d2e41e95dbc20a232c0f5d3850654eebbfcba303d96358d2c46592725bb989c"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] +python-dotenv = [ + {file = "python-dotenv-0.19.2.tar.gz", hash = "sha256:a5de49a31e953b45ff2d2fd434bbc2670e8db5273606c1e737cc6b93eff3655f"}, + {file = "python_dotenv-0.19.2-py2.py3-none-any.whl", hash = "sha256:32b2bdc1873fd3a3c346da1c6db83d0053c3c62f28f1f38516070c4c8971b1d3"}, +] +pytz = [ + {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, + {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, +] +pytz-deprecation-shim = [ + {file = "pytz_deprecation_shim-0.1.0.post0-py2.py3-none-any.whl", hash = "sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6"}, + {file = "pytz_deprecation_shim-0.1.0.post0.tar.gz", hash = "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d"}, +] +pywavelets = [ + {file = "PyWavelets-1.2.0-cp310-cp310-macosx_10_13_universal2.whl", hash = "sha256:4c29efb581245e4ba3e76b23b1bf254a7c79821d7e63f432e68044cf2d233e9e"}, + {file = "PyWavelets-1.2.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:3089aa6b4962e1f5dbd0434a10f174f7a50f80bf64cb7d33cc725af07bd30ecc"}, + {file = "PyWavelets-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16c30e98f52e1a5d0a06b4b8f294114aaa94a0e95445b4056b6ca0a7a5535a42"}, + {file = "PyWavelets-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79386f4d8518e344487acf22b1c130e5907b3c45852aa50c18df5e19895aa92e"}, + {file = "PyWavelets-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9bf543d552d20cf6ddfd690c5c18afacc8440cfb09b7515b2242bb9abfcc5eb"}, + {file = "PyWavelets-1.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28bb3d7d411ffbcfaa5a81a5a32044805893752c1641b39f6544b7e0a24661c3"}, + {file = "PyWavelets-1.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:333e1370167b0a2b963df82e42968000734bfa23b2ce88191e8ce9d24fc4cc57"}, + {file = "PyWavelets-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2ec1fc92573f56c1b129006d109e7518a098f3c8c6a2183b495619faca931461"}, + {file = "PyWavelets-1.2.0-cp310-cp310-win32.whl", hash = "sha256:d30c09fa805533bf7c8a5d06aa8babda5ae6c1541cd652cb2ebe6ab0b9536c0e"}, + {file = "PyWavelets-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:73805016353a47c5b5f9cea547ea6ae07cd3520abfd7888916ff56b01e71307a"}, + {file = "PyWavelets-1.2.0-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:ec670e78be2c3193e26c4bfa31dff1edd89ee8d7e2f4219782f3ef3f6daf37f0"}, + {file = "PyWavelets-1.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:151a7f3d3db36baffe640d691403b7cd3938a1886c8a387b719e7e8b580dd4b1"}, + {file = "PyWavelets-1.2.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:616fd2967dd153c3f539b1e0979168969f3702125caae4caa769efc5621cc2b7"}, + {file = "PyWavelets-1.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:abedc0b49273a734d4592e325a5fb32f0741e115d6722e0c59964ecf21344640"}, + {file = "PyWavelets-1.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9b05d2f21da666f918692f0313484002307794b5380f7291a395b9271abdda5c"}, + {file = "PyWavelets-1.2.0-cp37-cp37m-win32.whl", hash = "sha256:537b5a8a8a3e9e5b931d34b517aa2312a3d8385937f98c4f8ffa668483329cfb"}, + {file = "PyWavelets-1.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:7a725030682bf891ced9819b4b21d6ef356fa11b70399d2d3adb319aead1efb0"}, + {file = "PyWavelets-1.2.0-cp38-cp38-macosx_10_13_universal2.whl", hash = "sha256:d9831b251f63460302811607f80a20285292ed0a0a046f95b4648edc0ed90f9c"}, + {file = "PyWavelets-1.2.0-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:7e4749ff324e8e01a2fdc859ac9714c4be1cbc6e8a34d5ddedb28fc9513b31a1"}, + {file = "PyWavelets-1.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:333684cc0d0e89cf6cb3a8b3ea68528790e1a3edc565a100cda47e29860f892d"}, + {file = "PyWavelets-1.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71415f2c376ae3e1331249043dddb63370c92fed162ebcb108fd87e12a956d89"}, + {file = "PyWavelets-1.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:44315d197bad9564210ef42f2d5a01c07ee6fd456c679d4a6d0f4e23ec9930cf"}, + {file = "PyWavelets-1.2.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c8b388652b6afb4bf7be313be057240386de93817c6744c2aaf43a22890733c8"}, + {file = "PyWavelets-1.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a1131c27b9f79ca56dd6347d5585a609f51ed3cad0cfb6c17419b1733d3b6acd"}, + {file = "PyWavelets-1.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:df4d950be507a68d107c8f618ef7a9e0d9071789cfc1a840f89d0c985448880f"}, + {file = "PyWavelets-1.2.0-cp38-cp38-win32.whl", hash = "sha256:8a72f11c4d23f8ed8544def0003f500e98598e7a1efce892e6f964c430469c05"}, + {file = "PyWavelets-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:be231e4bc569f2b1177711390d406d08ce388c1e01ab864f89be8928db234856"}, + {file = "PyWavelets-1.2.0-cp39-cp39-macosx_10_13_universal2.whl", hash = "sha256:90d53119f4b518236ad9a8a6be96d86efb1b4eeb73c28e3ed33824ae601ce7b1"}, + {file = "PyWavelets-1.2.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:351937e4fc6f3df3555cd2813e73bfc344885c5d994fd621d13dd004d05a4cb7"}, + {file = "PyWavelets-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:33375e3e6e361659f2519d412de2b50e2527a97c3946ffd66ca20a8ea1346fea"}, + {file = "PyWavelets-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:449d2d5f9c1f28a1bce01f714f9f742d9fdbce90f66de0a92cad39d98d24477b"}, + {file = "PyWavelets-1.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:18d84982417790a645f74cb0f968e89fb8af575dbf17a52c64af5075aa5528b8"}, + {file = "PyWavelets-1.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b3d9dab8223d0ce30e7480751f526ce1e97a1dcf5242875f8206e4449953116c"}, + {file = "PyWavelets-1.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a82e8c307b98d65737b286e0b458343ecee8505dfb519cd314a5f211f4fb92b9"}, + {file = "PyWavelets-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:663d265cb433653ef6335973edd13c66cd86c85fbe9c09e4bd138119bac15974"}, + {file = "PyWavelets-1.2.0-cp39-cp39-win32.whl", hash = "sha256:fd5ca221ac7bedb2a9aebcf3b05020827564db5a979b25005b3a2c7ba84069a2"}, + {file = "PyWavelets-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:69cfc7f2ceb0a1097e7e8d1a026cbb2ff1afecc2d79820856f1abccb6cb59cc4"}, + {file = "PyWavelets-1.2.0.tar.gz", hash = "sha256:6cbd69b047bb4e00873097472133425f5f08a4e6bc8b3f0ae709274d4d5e9a8d"}, +] +pyyaml = [ + {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, + {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, + {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, + {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347"}, + {file = "PyYAML-5.4.1-cp36-cp36m-manylinux2014_s390x.whl", hash = "sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, + {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, + {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa"}, + {file = "PyYAML-5.4.1-cp37-cp37m-manylinux2014_s390x.whl", hash = "sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, + {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, + {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247"}, + {file = "PyYAML-5.4.1-cp38-cp38-manylinux2014_s390x.whl", hash = "sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc"}, + {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, + {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, + {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122"}, + {file = "PyYAML-5.4.1-cp39-cp39-manylinux2014_s390x.whl", hash = "sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6"}, + {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, + {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, + {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, +] +retrying = [ + {file = "retrying-1.3.3.tar.gz", hash = "sha256:08c039560a6da2fe4f2c426d0766e284d3b736e355f8dd24b37367b0bb41973b"}, +] +rfc3986 = [ + {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, + {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, +] +"ruamel.yaml" = [ + {file = "ruamel.yaml-0.17.21-py3-none-any.whl", hash = "sha256:742b35d3d665023981bd6d16b3d24248ce5df75fdb4e2924e93a05c1f8b61ca7"}, + {file = "ruamel.yaml-0.17.21.tar.gz", hash = "sha256:8b7ce697a2f212752a35c1ac414471dc16c424c9573be4926b56ff3f5d23b7af"}, +] +"ruamel.yaml.clib" = [ + {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6e7be2c5bcb297f5b82fee9c665eb2eb7001d1050deaba8471842979293a80b0"}, + {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:221eca6f35076c6ae472a531afa1c223b9c29377e62936f61bc8e6e8bdc5f9e7"}, + {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-win32.whl", hash = "sha256:1070ba9dd7f9370d0513d649420c3b362ac2d687fe78c6e888f5b12bf8bc7bee"}, + {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:77df077d32921ad46f34816a9a16e6356d8100374579bc35e15bab5d4e9377de"}, + {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:cfdb9389d888c5b74af297e51ce357b800dd844898af9d4a547ffc143fa56751"}, + {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7b2927e92feb51d830f531de4ccb11b320255ee95e791022555971c466af4527"}, + {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-win32.whl", hash = "sha256:ada3f400d9923a190ea8b59c8f60680c4ef8a4b0dfae134d2f2ff68429adfab5"}, + {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-win_amd64.whl", hash = "sha256:de9c6b8a1ba52919ae919f3ae96abb72b994dd0350226e28f3686cb4f142165c"}, + {file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d67f273097c368265a7b81e152e07fb90ed395df6e552b9fa858c6d2c9f42502"}, + {file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:72a2b8b2ff0a627496aad76f37a652bcef400fd861721744201ef1b45199ab78"}, + {file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-win32.whl", hash = "sha256:9efef4aab5353387b07f6b22ace0867032b900d8e91674b5d8ea9150db5cae94"}, + {file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-win_amd64.whl", hash = "sha256:846fc8336443106fe23f9b6d6b8c14a53d38cef9a375149d61f99d78782ea468"}, + {file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0847201b767447fc33b9c235780d3aa90357d20dd6108b92be544427bea197dd"}, + {file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:78988ed190206672da0f5d50c61afef8f67daa718d614377dcd5e3ed85ab4a99"}, + {file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-win32.whl", hash = "sha256:a49e0161897901d1ac9c4a79984b8410f450565bbad64dbfcbf76152743a0cdb"}, + {file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-win_amd64.whl", hash = "sha256:bf75d28fa071645c529b5474a550a44686821decebdd00e21127ef1fd566eabe"}, + {file = "ruamel.yaml.clib-0.2.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a32f8d81ea0c6173ab1b3da956869114cae53ba1e9f72374032e33ba3118c233"}, + {file = "ruamel.yaml.clib-0.2.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7f7ecb53ae6848f959db6ae93bdff1740e651809780822270eab111500842a84"}, + {file = "ruamel.yaml.clib-0.2.6-cp38-cp38-win32.whl", hash = "sha256:89221ec6d6026f8ae859c09b9718799fea22c0e8da8b766b0b2c9a9ba2db326b"}, + {file = "ruamel.yaml.clib-0.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:31ea73e564a7b5fbbe8188ab8b334393e06d997914a4e184975348f204790277"}, + {file = "ruamel.yaml.clib-0.2.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dc6a613d6c74eef5a14a214d433d06291526145431c3b964f5e16529b1842bed"}, + {file = "ruamel.yaml.clib-0.2.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1866cf2c284a03b9524a5cc00daca56d80057c5ce3cdc86a52020f4c720856f0"}, + {file = "ruamel.yaml.clib-0.2.6-cp39-cp39-win32.whl", hash = "sha256:3fb9575a5acd13031c57a62cc7823e5d2ff8bc3835ba4d94b921b4e6ee664104"}, + {file = "ruamel.yaml.clib-0.2.6-cp39-cp39-win_amd64.whl", hash = "sha256:825d5fccef6da42f3c8eccd4281af399f21c02b32d98e113dbc631ea6a6ecbc7"}, + {file = "ruamel.yaml.clib-0.2.6.tar.gz", hash = "sha256:4ff604ce439abb20794f05613c374759ce10e3595d1867764dd1ae675b85acbd"}, +] +scipy = [ + {file = "scipy-1.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a15a1f3fc0abff33e792d6049161b7795909b40b97c6cc2934ed54384017ab76"}, + {file = "scipy-1.6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e79570979ccdc3d165456dd62041d9556fb9733b86b4b6d818af7a0afc15f092"}, + {file = "scipy-1.6.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a423533c55fec61456dedee7b6ee7dce0bb6bfa395424ea374d25afa262be261"}, + {file = "scipy-1.6.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:33d6b7df40d197bdd3049d64e8e680227151673465e5d85723b3b8f6b15a6ced"}, + {file = "scipy-1.6.1-cp37-cp37m-win32.whl", hash = "sha256:6725e3fbb47da428794f243864f2297462e9ee448297c93ed1dcbc44335feb78"}, + {file = "scipy-1.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:5fa9c6530b1661f1370bcd332a1e62ca7881785cc0f80c0d559b636567fab63c"}, + {file = "scipy-1.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bd50daf727f7c195e26f27467c85ce653d41df4358a25b32434a50d8870fc519"}, + {file = "scipy-1.6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:f46dd15335e8a320b0fb4685f58b7471702234cba8bb3442b69a3e1dc329c345"}, + {file = "scipy-1.6.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0e5b0ccf63155d90da576edd2768b66fb276446c371b73841e3503be1d63fb5d"}, + {file = "scipy-1.6.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2481efbb3740977e3c831edfd0bd9867be26387cacf24eb5e366a6a374d3d00d"}, + {file = "scipy-1.6.1-cp38-cp38-win32.whl", hash = "sha256:68cb4c424112cd4be886b4d979c5497fba190714085f46b8ae67a5e4416c32b4"}, + {file = "scipy-1.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:5f331eeed0297232d2e6eea51b54e8278ed8bb10b099f69c44e2558c090d06bf"}, + {file = "scipy-1.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0c8a51d33556bf70367452d4d601d1742c0e806cd0194785914daf19775f0e67"}, + {file = "scipy-1.6.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:83bf7c16245c15bc58ee76c5418e46ea1811edcc2e2b03041b804e46084ab627"}, + {file = "scipy-1.6.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:794e768cc5f779736593046c9714e0f3a5940bc6dcc1dba885ad64cbfb28e9f0"}, + {file = "scipy-1.6.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5da5471aed911fe7e52b86bf9ea32fb55ae93e2f0fac66c32e58897cfb02fa07"}, + {file = "scipy-1.6.1-cp39-cp39-win32.whl", hash = "sha256:8e403a337749ed40af60e537cc4d4c03febddcc56cd26e774c9b1b600a70d3e4"}, + {file = "scipy-1.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:a5193a098ae9f29af283dcf0041f762601faf2e595c0db1da929875b7570353f"}, + {file = "scipy-1.6.1.tar.gz", hash = "sha256:c4fceb864890b6168e79b0e714c585dbe2fd4222768ee90bc1aa0f8218691b11"}, +] +setuptools-scm = [ + {file = "setuptools_scm-6.4.2-py3-none-any.whl", hash = "sha256:acea13255093849de7ccb11af9e1fb8bde7067783450cee9ef7a93139bddf6d4"}, + {file = "setuptools_scm-6.4.2.tar.gz", hash = "sha256:6833ac65c6ed9711a4d5d2266f8024cfa07c533a0e55f4c12f6eff280a5a9e30"}, +] +sgmllib3k = [ + {file = "sgmllib3k-1.0.0.tar.gz", hash = "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9"}, +] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] +sniffio = [ + {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, + {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, +] +soupsieve = [ + {file = "soupsieve-2.3.1-py3-none-any.whl", hash = "sha256:1a3cca2617c6b38c0343ed661b1fa5de5637f257d4fe22bd9f1338010a1efefb"}, + {file = "soupsieve-2.3.1.tar.gz", hash = "sha256:b8d49b1cd4f037c7082a9683dfa1801aa2597fb11c3a1155b7a5b94829b4f1f9"}, +] +sqlalchemy = [ + {file = "SQLAlchemy-1.3.24-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:87a2725ad7d41cd7376373c15fd8bf674e9c33ca56d0b8036add2d634dba372e"}, + {file = "SQLAlchemy-1.3.24-cp27-cp27m-win32.whl", hash = "sha256:f597a243b8550a3a0b15122b14e49d8a7e622ba1c9d29776af741f1845478d79"}, + {file = "SQLAlchemy-1.3.24-cp27-cp27m-win_amd64.whl", hash = "sha256:fc4cddb0b474b12ed7bdce6be1b9edc65352e8ce66bc10ff8cbbfb3d4047dbf4"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:f1149d6e5c49d069163e58a3196865e4321bad1803d7886e07d8710de392c548"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:14f0eb5db872c231b20c18b1e5806352723a3a89fb4254af3b3e14f22eaaec75"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:e98d09f487267f1e8d1179bf3b9d7709b30a916491997137dd24d6ae44d18d79"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:fc1f2a5a5963e2e73bac4926bdaf7790c4d7d77e8fc0590817880e22dd9d0b8b"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-win32.whl", hash = "sha256:f3c5c52f7cb8b84bfaaf22d82cb9e6e9a8297f7c2ed14d806a0f5e4d22e83fb7"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-win_amd64.whl", hash = "sha256:0352db1befcbed2f9282e72843f1963860bf0e0472a4fa5cf8ee084318e0e6ab"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:2ed6343b625b16bcb63c5b10523fd15ed8934e1ed0f772c534985e9f5e73d894"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:34fcec18f6e4b24b4a5f6185205a04f1eab1e56f8f1d028a2a03694ebcc2ddd4"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e47e257ba5934550d7235665eee6c911dc7178419b614ba9e1fbb1ce6325b14f"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:816de75418ea0953b5eb7b8a74933ee5a46719491cd2b16f718afc4b291a9658"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-win32.whl", hash = "sha256:26155ea7a243cbf23287f390dba13d7927ffa1586d3208e0e8d615d0c506f996"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-win_amd64.whl", hash = "sha256:f03bd97650d2e42710fbe4cf8a59fae657f191df851fc9fc683ecef10746a375"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:a006d05d9aa052657ee3e4dc92544faae5fcbaafc6128217310945610d862d39"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1e2f89d2e5e3c7a88e25a3b0e43626dba8db2aa700253023b82e630d12b37109"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0d5d862b1cfbec5028ce1ecac06a3b42bc7703eb80e4b53fceb2738724311443"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:0172423a27fbcae3751ef016663b72e1a516777de324a76e30efa170dbd3dd2d"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-win32.whl", hash = "sha256:d37843fb8df90376e9e91336724d78a32b988d3d20ab6656da4eb8ee3a45b63c"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-win_amd64.whl", hash = "sha256:c10ff6112d119f82b1618b6dc28126798481b9355d8748b64b9b55051eb4f01b"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:861e459b0e97673af6cc5e7f597035c2e3acdfb2608132665406cded25ba64c7"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5de2464c254380d8a6c20a2746614d5a436260be1507491442cf1088e59430d2"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d375d8ccd3cebae8d90270f7aa8532fe05908f79e78ae489068f3b4eee5994e8"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:014ea143572fee1c18322b7908140ad23b3994036ef4c0d630110faf942652f8"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-win32.whl", hash = "sha256:6607ae6cd3a07f8a4c3198ffbf256c261661965742e2b5265a77cd5c679c9bba"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-win_amd64.whl", hash = "sha256:fcb251305fa24a490b6a9ee2180e5f8252915fb778d3dafc70f9cc3f863827b9"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:01aa5f803db724447c1d423ed583e42bf5264c597fd55e4add4301f163b0be48"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4d0e3515ef98aa4f0dc289ff2eebb0ece6260bbf37c2ea2022aad63797eacf60"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:bce28277f308db43a6b4965734366f533b3ff009571ec7ffa583cb77539b84d6"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:8110e6c414d3efc574543109ee618fe2c1f96fa31833a1ff36cc34e968c4f233"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-win32.whl", hash = "sha256:ee5f5188edb20a29c1cc4a039b074fdc5575337c9a68f3063449ab47757bb064"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-win_amd64.whl", hash = "sha256:09083c2487ca3c0865dc588e07aeaa25416da3d95f7482c07e92f47e080aa17b"}, + {file = "SQLAlchemy-1.3.24.tar.gz", hash = "sha256:ebbb777cbf9312359b897bf81ba00dae0f5cb69fba2a18265dcc18a6f5ef7519"}, +] +starlette = [ + {file = "starlette-0.17.1-py3-none-any.whl", hash = "sha256:26a18cbda5e6b651c964c12c88b36d9898481cd428ed6e063f5f29c418f73050"}, + {file = "starlette-0.17.1.tar.gz", hash = "sha256:57eab3cc975a28af62f6faec94d355a410634940f10b30d68d31cb5ec1b44ae8"}, +] +tomli = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] +tomlkit = [ + {file = "tomlkit-0.9.2-py3-none-any.whl", hash = "sha256:daf4f9c5f2fbf6b861d6adfc51940b98dee36c13e1d88749a6dc9fb280fff304"}, + {file = "tomlkit-0.9.2.tar.gz", hash = "sha256:ebd982d61446af95a1e082b103e250cb9e6d152eae2581d4a07d31a70b34ab0f"}, +] +typing-extensions = [ + {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, + {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, +] +tzdata = [ + {file = "tzdata-2021.5-py2.py3-none-any.whl", hash = "sha256:3eee491e22ebfe1e5cfcc97a4137cd70f092ce59144d81f8924a844de05ba8f5"}, + {file = "tzdata-2021.5.tar.gz", hash = "sha256:68dbe41afd01b867894bbdfd54fa03f468cfa4f0086bfb4adcd8de8f24f3ee21"}, +] +tzlocal = [ + {file = "tzlocal-4.1-py3-none-any.whl", hash = "sha256:28ba8d9fcb6c9a782d6e0078b4f6627af1ea26aeaa32b4eab5324abc7df4149f"}, + {file = "tzlocal-4.1.tar.gz", hash = "sha256:0f28015ac68a5c067210400a9197fc5d36ba9bc3f8eaf1da3cbd59acdfed9e09"}, +] +ujson = [ + {file = "ujson-5.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:644552d1e89983c08d0c24358fbcb5829ae5b5deee9d876e16d20085cfa7dc81"}, + {file = "ujson-5.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0cae4a9c141856f7ad1a79c17ff1aaebf7fd8faa2f2c2614c37d6f82ed261d96"}, + {file = "ujson-5.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ba63b789d83ca92237dbc72041a268d91559f981c01763a107105878bae442e"}, + {file = "ujson-5.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe4e8f71e2fd42dce245bace7e2aa97dabef13926750a351eadca89a1e0f1abd"}, + {file = "ujson-5.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f73946c047a38640b1f5a2a459237b7bdc417ab028a76c796e4eea984b359b9"}, + {file = "ujson-5.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:afe91153c2046fa8210b92def513124e0ea5b87ad8fa4c14fef8197204b980f1"}, + {file = "ujson-5.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b1ef400fc73ab0cb61b74a662ad4207917223aba6f933a9fea9b0fbe75de2361"}, + {file = "ujson-5.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5c8a884d60dd2eed2fc95a9474d57ead82adf254f54caffb3d9e8ed185c49aba"}, + {file = "ujson-5.1.0-cp310-cp310-win32.whl", hash = "sha256:173b90a2c2836ee42f708df88ecfe3efbc4d868df73c9fcea8cb8f6f3ab93892"}, + {file = "ujson-5.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:6c45ad95e82155372d9908774db46e0ef7880af28a734d0b14eaa4f505e64982"}, + {file = "ujson-5.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4155a7c29bf330329519027c815e15e381c1fff22f50d26f135584d482bbd95d"}, + {file = "ujson-5.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa616d0d3c594785c6e9b7f42686bb1c86f9e64aa0f30a72c86d8eb315f54194"}, + {file = "ujson-5.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a48efcb5d3695b295c26835ed81048da8cd40e76c4fde2940c807aa452b560c9"}, + {file = "ujson-5.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:838d35eb9006d36f9241e95958d9f4819bcf1ea2ec155daf92d5751c31bcc62b"}, + {file = "ujson-5.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:05aa6c7297a22081f65497b6f586de6b7060ea47c3ecda80896f47200e9dbf04"}, + {file = "ujson-5.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ce441ab7ad1db592e2db95b6c2a1eb882123532897340afac1342c28819e9833"}, + {file = "ujson-5.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9937e819196b894ffd00801b24f1042dabda142f355313c3f20410993219bc4f"}, + {file = "ujson-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:06bed66ae62d517f67a61cf53c056800b35ef364270723168a1db62702e2d30c"}, + {file = "ujson-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:74e41a0222e6e8136e38f103d6cc228e4e20f1c35cc80224a42804fd67fb35c8"}, + {file = "ujson-5.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7bbb87f040e618bebe8c6257b3e4e8ae2f708dcbff3270c84718b3360a152799"}, + {file = "ujson-5.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:68e38122115a8097fbe1cfe52979a797eaff91c10c1bf4b27774e5f30e7f723a"}, + {file = "ujson-5.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b09843123425337d2efee5c8ff6519e4dfc7b044db66c8bd560517fc1070a157"}, + {file = "ujson-5.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dca10174a3bd482d969a2d12d0aec2fdd63fb974e255ec0147e36a516a2d68a"}, + {file = "ujson-5.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:202ae52f4a53f03c42ead6d046b1a146517e93bd757f517bdeef0a26228e0260"}, + {file = "ujson-5.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7a4bed7bd7b288cf73ba47bda27fdd1d78ef6906831489e7f296aef9e786eccb"}, + {file = "ujson-5.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d423956f8dfd98a075c9338b886414b6e3c2817dbf67935797466c998af39936"}, + {file = "ujson-5.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:083c1078e4de3a39019e590c43865b17e07a763fee25b012e650bb4f42c89703"}, + {file = "ujson-5.1.0-cp38-cp38-win32.whl", hash = "sha256:31671ad99f0395eb881d698f2871dc64ff00fbd4380c5d9bfd8bff3d4c8f8d88"}, + {file = "ujson-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:994eaf4369e6bc24258f59fe8c6345037abcf24557571814e27879851c4353aa"}, + {file = "ujson-5.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:00d6ea9702c2eaeaf1a826934eaba1b4c609c873379bf54e36ba7b7e128edf94"}, + {file = "ujson-5.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a53c4fe8e1c067e6c98b4526e982ed9486f08578ad8eb5f0e94f8cadf0c1d911"}, + {file = "ujson-5.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:368f855779fded560724a6448838304621f498113a116d66bc5ed5ad5ad3ca92"}, + {file = "ujson-5.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd97e45a0f450ba2c43cda18147e54b8e41e886c22e3506c62f7d61e9e53b0d"}, + {file = "ujson-5.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:caeadbf95ce277f1f8f4f71913bc20c01f49fc9228f238920f9ff6f7645d2a5f"}, + {file = "ujson-5.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:681fed63c948f757466eeb3aea98873e2ab8b2b18e9020c96a97479a513e2018"}, + {file = "ujson-5.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6fc4376266ae67f6d8f9e69386ab950eb84ba345c6fdbeb1884fa5b773c8c76b"}, + {file = "ujson-5.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:585271d6ad545a2ccfc237582f70c160e627735c89d0ca2bde24afa321bc0750"}, + {file = "ujson-5.1.0-cp39-cp39-win32.whl", hash = "sha256:b631af423e6d5d35f9f37fbcc4fbdb6085abc1c441cf864c64b7fbb5b150faf7"}, + {file = "ujson-5.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:08265db5ccff8b521ff68aee13a417d68cca784d7e711d961b92fda6ccffcc4f"}, + {file = "ujson-5.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e2b1c372583eb4363b42e21222d3a18116a41973781d502d61e1b0daf4b8352f"}, + {file = "ujson-5.1.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51142c9d40439f299594e399bef8892a16586ded54c88d3af926865ca221a177"}, + {file = "ujson-5.1.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ba8be1717b1867a85b2413a8585bad0e4507a22d6af2c244e1c74151f6d5cc0"}, + {file = "ujson-5.1.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0b26d9d6eb9a0979d37f28c715e717a409c9e03163e5cd8fa73aab806351ab5"}, + {file = "ujson-5.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:b2c7e4afde0d36926b091fa9613b18b65e911fcaa60024e8721f2dcfedc25329"}, + {file = "ujson-5.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:110633a8dda6c8ca78090292231e15381f8b2423e998399d4bc5f135149c722b"}, + {file = "ujson-5.1.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdac161127ef8e0889180a4c07475457c55fe0bbd644436d8f4c7ef07565d653"}, + {file = "ujson-5.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:452990c2b18445a7379a45873527d2ec47789b9289c13a17a3c1cc76b9641126"}, + {file = "ujson-5.1.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5304ad25d100d50b5bc8513ef110335df678f66c7ccf3d4728c0c3aa69e08e0c"}, + {file = "ujson-5.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ce620a6563b21aa3fbb1658bc1bfddb484a6dad542de1efb5121eb7bb4f2b93a"}, + {file = "ujson-5.1.0.tar.gz", hash = "sha256:a88944d2f99db71a3ca0c63d81f37e55b660edde0b07216fb65a3e46403ef004"}, +] +urllib3 = [ + {file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"}, + {file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"}, +] +uvicorn = [ + {file = "uvicorn-0.17.5-py3-none-any.whl", hash = "sha256:8adddf629b79857b48b999ae1b14d6c92c95d4d7840bd86461f09bee75f1653e"}, + {file = "uvicorn-0.17.5.tar.gz", hash = "sha256:c04a9c069111489c324f427501b3840d306c6b91a77b00affc136a840a3f45f1"}, +] +uvloop = [ + {file = "uvloop-0.16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d"}, + {file = "uvloop-0.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:30ba9dcbd0965f5c812b7c2112a1ddf60cf904c1c160f398e7eed3a6b82dcd9c"}, + {file = "uvloop-0.16.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bd53f7f5db562f37cd64a3af5012df8cac2c464c97e732ed556800129505bd64"}, + {file = "uvloop-0.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:772206116b9b57cd625c8a88f2413df2fcfd0b496eb188b82a43bed7af2c2ec9"}, + {file = "uvloop-0.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b572256409f194521a9895aef274cea88731d14732343da3ecdb175228881638"}, + {file = "uvloop-0.16.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:04ff57aa137230d8cc968f03481176041ae789308b4d5079118331ab01112450"}, + {file = "uvloop-0.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a19828c4f15687675ea912cc28bbcb48e9bb907c801873bd1519b96b04fb805"}, + {file = "uvloop-0.16.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e814ac2c6f9daf4c36eb8e85266859f42174a4ff0d71b99405ed559257750382"}, + {file = "uvloop-0.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bd8f42ea1ea8f4e84d265769089964ddda95eb2bb38b5cbe26712b0616c3edee"}, + {file = "uvloop-0.16.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:647e481940379eebd314c00440314c81ea547aa636056f554d491e40503c8464"}, + {file = "uvloop-0.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e0d26fa5875d43ddbb0d9d79a447d2ace4180d9e3239788208527c4784f7cab"}, + {file = "uvloop-0.16.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6ccd57ae8db17d677e9e06192e9c9ec4bd2066b77790f9aa7dede2cc4008ee8f"}, + {file = "uvloop-0.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:089b4834fd299d82d83a25e3335372f12117a7d38525217c2258e9b9f4578897"}, + {file = "uvloop-0.16.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98d117332cc9e5ea8dfdc2b28b0a23f60370d02e1395f88f40d1effd2cb86c4f"}, + {file = "uvloop-0.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e5f2e2ff51aefe6c19ee98af12b4ae61f5be456cd24396953244a30880ad861"}, + {file = "uvloop-0.16.0.tar.gz", hash = "sha256:f74bc20c7b67d1c27c72601c78cf95be99d5c2cdd4514502b4f3eb0933ff1228"}, +] +watchgod = [ + {file = "watchgod-0.7-py3-none-any.whl", hash = "sha256:d6c1ea21df37847ac0537ca0d6c2f4cdf513562e95f77bb93abbcf05573407b7"}, + {file = "watchgod-0.7.tar.gz", hash = "sha256:48140d62b0ebe9dd9cf8381337f06351e1f2e70b2203fa9c6eff4e572ca84f29"}, +] +websockets = [ + {file = "websockets-10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:38db6e2163b021642d0a43200ee2dec8f4980bdbda96db54fde72b283b54cbfc"}, + {file = "websockets-10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e1b60fd297adb9fc78375778a5220da7f07bf54d2a33ac781319650413fc6a60"}, + {file = "websockets-10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3477146d1f87ead8df0f27e8960249f5248dceb7c2741e8bbec9aa5338d0c053"}, + {file = "websockets-10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb01ea7b5f52e7125bdc3c5807aeaa2d08a0553979cf2d96a8b7803ea33e15e7"}, + {file = "websockets-10.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9fd62c6dc83d5d35fb6a84ff82ec69df8f4657fff05f9cd6c7d9bec0dd57f0f6"}, + {file = "websockets-10.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3bbf080f3892ba1dc8838786ec02899516a9d227abe14a80ef6fd17d4fb57127"}, + {file = "websockets-10.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5560558b0dace8312c46aa8915da977db02738ac8ecffbc61acfbfe103e10155"}, + {file = "websockets-10.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:667c41351a6d8a34b53857ceb8343a45c85d438ee4fd835c279591db8aeb85be"}, + {file = "websockets-10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:468f0031fdbf4d643f89403a66383247eb82803430b14fa27ce2d44d2662ca37"}, + {file = "websockets-10.1-cp310-cp310-win32.whl", hash = "sha256:d0d81b46a5c87d443e40ce2272436da8e6092aa91f5fbeb60d1be9f11eff5b4c"}, + {file = "websockets-10.1-cp310-cp310-win_amd64.whl", hash = "sha256:b68b6caecb9a0c6db537aa79750d1b592a841e4f1a380c6196091e65b2ad35f9"}, + {file = "websockets-10.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a249139abc62ef333e9e85064c27fefb113b16ffc5686cefc315bdaef3eefbc8"}, + {file = "websockets-10.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8877861e3dee38c8d302eee0d5dbefa6663de3b46dc6a888f70cd7e82562d1f7"}, + {file = "websockets-10.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e3872ae57acd4306ecf937d36177854e218e999af410a05c17168cd99676c512"}, + {file = "websockets-10.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b66e6d514f12c28d7a2d80bb2a48ef223342e99c449782d9831b0d29a9e88a17"}, + {file = "websockets-10.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:9f304a22ece735a3da8a51309bc2c010e23961a8f675fae46fdf62541ed62123"}, + {file = "websockets-10.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:189ed478395967d6a98bb293abf04e8815349e17456a0a15511f1088b6cb26e4"}, + {file = "websockets-10.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:08a42856158307e231b199671c4fce52df5786dd3d703f36b5d8ac76b206c485"}, + {file = "websockets-10.1-cp37-cp37m-win32.whl", hash = "sha256:3ef6f73854cded34e78390dbdf40dfdcf0b89b55c0e282468ef92646fce8d13a"}, + {file = "websockets-10.1-cp37-cp37m-win_amd64.whl", hash = "sha256:89e985d40d407545d5f5e2e58e1fdf19a22bd2d8cd54d20a882e29f97e930a0a"}, + {file = "websockets-10.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:002071169d2e44ce8eb9e5ebac9fbce142ba4b5146eef1cfb16b177a27662657"}, + {file = "websockets-10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cfae282c2aa7f0c4be45df65c248481f3509f8c40ca8b15ed96c35668ae0ff69"}, + {file = "websockets-10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:97b4b68a2ddaf5c4707ae79c110bfd874c5be3c6ac49261160fb243fa45d8bbb"}, + {file = "websockets-10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c9407719f42cb77049975410490c58a705da6af541adb64716573e550e5c9db"}, + {file = "websockets-10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1d858fb31e5ac992a2cdf17e874c95f8a5b1e917e1fb6b45ad85da30734b223f"}, + {file = "websockets-10.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7bdd3d26315db0a9cf8a0af30ca95e0aa342eda9c1377b722e71ccd86bc5d1dd"}, + {file = "websockets-10.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e259be0863770cb91b1a6ccf6907f1ac2f07eff0b7f01c249ed751865a70cb0d"}, + {file = "websockets-10.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6b014875fae19577a392372075e937ebfebf53fd57f613df07b35ab210f31534"}, + {file = "websockets-10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:98de71f86bdb29430fd7ba9997f47a6b10866800e3ea577598a786a785701bb0"}, + {file = "websockets-10.1-cp38-cp38-win32.whl", hash = "sha256:3a02ab91d84d9056a9ee833c254895421a6333d7ae7fff94b5c68e4fa8095519"}, + {file = "websockets-10.1-cp38-cp38-win_amd64.whl", hash = "sha256:7d6673b2753f9c5377868a53445d0c321ef41ff3c8e3b6d57868e72054bfce5f"}, + {file = "websockets-10.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ddab2dc69ee5ae27c74dbfe9d7bb6fee260826c136dca257faa1a41d1db61a89"}, + {file = "websockets-10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:14e9cf68a08d1a5d42109549201aefba473b1d925d233ae19035c876dd845da9"}, + {file = "websockets-10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e4819c6fb4f336fd5388372cb556b1f3a165f3f68e66913d1a2fc1de55dc6f58"}, + {file = "websockets-10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05e7f098c76b0a4743716590bb8f9706de19f1ef5148d61d0cf76495ec3edb9c"}, + {file = "websockets-10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5bb6256de5a4fb1d42b3747b4e2268706c92965d75d0425be97186615bf2f24f"}, + {file = "websockets-10.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:888a5fa2a677e0c2b944f9826c756475980f1b276b6302e606f5c4ff5635be9e"}, + {file = "websockets-10.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6fdec1a0b3e5630c58e3d8704d2011c678929fce90b40908c97dfc47de8dca72"}, + {file = "websockets-10.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:531d8eb013a9bc6b3ad101588182aa9b6dd994b190c56df07f0d84a02b85d530"}, + {file = "websockets-10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0d93b7cadc761347d98da12ec1930b5c71b2096f1ceed213973e3cda23fead9c"}, + {file = "websockets-10.1-cp39-cp39-win32.whl", hash = "sha256:d9b245db5a7e64c95816e27d72830e51411c4609c05673d1ae81eb5d23b0be54"}, + {file = "websockets-10.1-cp39-cp39-win_amd64.whl", hash = "sha256:882c0b8bdff3bf1bd7f024ce17c6b8006042ec4cceba95cf15df57e57efa471c"}, + {file = "websockets-10.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:10edd9d7d3581cfb9ff544ac09fc98cab7ee8f26778a5a8b2d5fd4b0684c5ba5"}, + {file = "websockets-10.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa83174390c0ff4fc1304fbe24393843ac7a08fdd59295759c4b439e06b1536"}, + {file = "websockets-10.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:483edee5abed738a0b6a908025be47f33634c2ad8e737edd03ffa895bd600909"}, + {file = "websockets-10.1-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:816ae7dac2c6522cfa620947ead0ca95ac654916eebf515c94d7c28de5601a6e"}, + {file = "websockets-10.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:1dafe98698ece09b8ccba81b910643ff37198e43521d977be76caf37709cf62b"}, + {file = "websockets-10.1.tar.gz", hash = "sha256:181d2b25de5a437b36aefedaf006ecb6fa3aa1328ec0236cdde15f32f9d3ff6d"}, +] +win32-setctime = [ + {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, + {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, +] +yarl = [ + {file = "yarl-1.7.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f2a8508f7350512434e41065684076f640ecce176d262a7d54f0da41d99c5a95"}, + {file = "yarl-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da6df107b9ccfe52d3a48165e48d72db0eca3e3029b5b8cb4fe6ee3cb870ba8b"}, + {file = "yarl-1.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a1d0894f238763717bdcfea74558c94e3bc34aeacd3351d769460c1a586a8b05"}, + {file = "yarl-1.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe4b95b7e00c6635a72e2d00b478e8a28bfb122dc76349a06e20792eb53a523"}, + {file = "yarl-1.7.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c145ab54702334c42237a6c6c4cc08703b6aa9b94e2f227ceb3d477d20c36c63"}, + {file = "yarl-1.7.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ca56f002eaf7998b5fcf73b2421790da9d2586331805f38acd9997743114e98"}, + {file = "yarl-1.7.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1d3d5ad8ea96bd6d643d80c7b8d5977b4e2fb1bab6c9da7322616fd26203d125"}, + {file = "yarl-1.7.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:167ab7f64e409e9bdd99333fe8c67b5574a1f0495dcfd905bc7454e766729b9e"}, + {file = "yarl-1.7.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:95a1873b6c0dd1c437fb3bb4a4aaa699a48c218ac7ca1e74b0bee0ab16c7d60d"}, + {file = "yarl-1.7.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6152224d0a1eb254f97df3997d79dadd8bb2c1a02ef283dbb34b97d4f8492d23"}, + {file = "yarl-1.7.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:5bb7d54b8f61ba6eee541fba4b83d22b8a046b4ef4d8eb7f15a7e35db2e1e245"}, + {file = "yarl-1.7.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:9c1f083e7e71b2dd01f7cd7434a5f88c15213194df38bc29b388ccdf1492b739"}, + {file = "yarl-1.7.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f44477ae29025d8ea87ec308539f95963ffdc31a82f42ca9deecf2d505242e72"}, + {file = "yarl-1.7.2-cp310-cp310-win32.whl", hash = "sha256:cff3ba513db55cc6a35076f32c4cdc27032bd075c9faef31fec749e64b45d26c"}, + {file = "yarl-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:c9c6d927e098c2d360695f2e9d38870b2e92e0919be07dbe339aefa32a090265"}, + {file = "yarl-1.7.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9b4c77d92d56a4c5027572752aa35082e40c561eec776048330d2907aead891d"}, + {file = "yarl-1.7.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c01a89a44bb672c38f42b49cdb0ad667b116d731b3f4c896f72302ff77d71656"}, + {file = "yarl-1.7.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c19324a1c5399b602f3b6e7db9478e5b1adf5cf58901996fc973fe4fccd73eed"}, + {file = "yarl-1.7.2-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3abddf0b8e41445426d29f955b24aeecc83fa1072be1be4e0d194134a7d9baee"}, + {file = "yarl-1.7.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6a1a9fe17621af43e9b9fcea8bd088ba682c8192d744b386ee3c47b56eaabb2c"}, + {file = "yarl-1.7.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8b0915ee85150963a9504c10de4e4729ae700af11df0dc5550e6587ed7891e92"}, + {file = "yarl-1.7.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:29e0656d5497733dcddc21797da5a2ab990c0cb9719f1f969e58a4abac66234d"}, + {file = "yarl-1.7.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:bf19725fec28452474d9887a128e98dd67eee7b7d52e932e6949c532d820dc3b"}, + {file = "yarl-1.7.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:d6f3d62e16c10e88d2168ba2d065aa374e3c538998ed04996cd373ff2036d64c"}, + {file = "yarl-1.7.2-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:ac10bbac36cd89eac19f4e51c032ba6b412b3892b685076f4acd2de18ca990aa"}, + {file = "yarl-1.7.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:aa32aaa97d8b2ed4e54dc65d241a0da1c627454950f7d7b1f95b13985afd6c5d"}, + {file = "yarl-1.7.2-cp36-cp36m-win32.whl", hash = "sha256:87f6e082bce21464857ba58b569370e7b547d239ca22248be68ea5d6b51464a1"}, + {file = "yarl-1.7.2-cp36-cp36m-win_amd64.whl", hash = "sha256:ac35ccde589ab6a1870a484ed136d49a26bcd06b6a1c6397b1967ca13ceb3913"}, + {file = "yarl-1.7.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a467a431a0817a292121c13cbe637348b546e6ef47ca14a790aa2fa8cc93df63"}, + {file = "yarl-1.7.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ab0c3274d0a846840bf6c27d2c60ba771a12e4d7586bf550eefc2df0b56b3b4"}, + {file = "yarl-1.7.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d260d4dc495c05d6600264a197d9d6f7fc9347f21d2594926202fd08cf89a8ba"}, + {file = "yarl-1.7.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fc4dd8b01a8112809e6b636b00f487846956402834a7fd59d46d4f4267181c41"}, + {file = "yarl-1.7.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c1164a2eac148d85bbdd23e07dfcc930f2e633220f3eb3c3e2a25f6148c2819e"}, + {file = "yarl-1.7.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:67e94028817defe5e705079b10a8438b8cb56e7115fa01640e9c0bb3edf67332"}, + {file = "yarl-1.7.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:89ccbf58e6a0ab89d487c92a490cb5660d06c3a47ca08872859672f9c511fc52"}, + {file = "yarl-1.7.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8cce6f9fa3df25f55521fbb5c7e4a736683148bcc0c75b21863789e5185f9185"}, + {file = "yarl-1.7.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:211fcd65c58bf250fb994b53bc45a442ddc9f441f6fec53e65de8cba48ded986"}, + {file = "yarl-1.7.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c10ea1e80a697cf7d80d1ed414b5cb8f1eec07d618f54637067ae3c0334133c4"}, + {file = "yarl-1.7.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:52690eb521d690ab041c3919666bea13ab9fbff80d615ec16fa81a297131276b"}, + {file = "yarl-1.7.2-cp37-cp37m-win32.whl", hash = "sha256:695ba021a9e04418507fa930d5f0704edbce47076bdcfeeaba1c83683e5649d1"}, + {file = "yarl-1.7.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c17965ff3706beedafd458c452bf15bac693ecd146a60a06a214614dc097a271"}, + {file = "yarl-1.7.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fce78593346c014d0d986b7ebc80d782b7f5e19843ca798ed62f8e3ba8728576"}, + {file = "yarl-1.7.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c2a1ac41a6aa980db03d098a5531f13985edcb451bcd9d00670b03129922cd0d"}, + {file = "yarl-1.7.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:39d5493c5ecd75c8093fa7700a2fb5c94fe28c839c8e40144b7ab7ccba6938c8"}, + {file = "yarl-1.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1eb6480ef366d75b54c68164094a6a560c247370a68c02dddb11f20c4c6d3c9d"}, + {file = "yarl-1.7.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ba63585a89c9885f18331a55d25fe81dc2d82b71311ff8bd378fc8004202ff6"}, + {file = "yarl-1.7.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e39378894ee6ae9f555ae2de332d513a5763276a9265f8e7cbaeb1b1ee74623a"}, + {file = "yarl-1.7.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c0910c6b6c31359d2f6184828888c983d54d09d581a4a23547a35f1d0b9484b1"}, + {file = "yarl-1.7.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6feca8b6bfb9eef6ee057628e71e1734caf520a907b6ec0d62839e8293e945c0"}, + {file = "yarl-1.7.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8300401dc88cad23f5b4e4c1226f44a5aa696436a4026e456fe0e5d2f7f486e6"}, + {file = "yarl-1.7.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:788713c2896f426a4e166b11f4ec538b5736294ebf7d5f654ae445fd44270832"}, + {file = "yarl-1.7.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:fd547ec596d90c8676e369dd8a581a21227fe9b4ad37d0dc7feb4ccf544c2d59"}, + {file = "yarl-1.7.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:737e401cd0c493f7e3dd4db72aca11cfe069531c9761b8ea474926936b3c57c8"}, + {file = "yarl-1.7.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baf81561f2972fb895e7844882898bda1eef4b07b5b385bcd308d2098f1a767b"}, + {file = "yarl-1.7.2-cp38-cp38-win32.whl", hash = "sha256:ede3b46cdb719c794427dcce9d8beb4abe8b9aa1e97526cc20de9bd6583ad1ef"}, + {file = "yarl-1.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:cc8b7a7254c0fc3187d43d6cb54b5032d2365efd1df0cd1749c0c4df5f0ad45f"}, + {file = "yarl-1.7.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:580c1f15500e137a8c37053e4cbf6058944d4c114701fa59944607505c2fe3a0"}, + {file = "yarl-1.7.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3ec1d9a0d7780416e657f1e405ba35ec1ba453a4f1511eb8b9fbab81cb8b3ce1"}, + {file = "yarl-1.7.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3bf8cfe8856708ede6a73907bf0501f2dc4e104085e070a41f5d88e7faf237f3"}, + {file = "yarl-1.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1be4bbb3d27a4e9aa5f3df2ab61e3701ce8fcbd3e9846dbce7c033a7e8136746"}, + {file = "yarl-1.7.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:534b047277a9a19d858cde163aba93f3e1677d5acd92f7d10ace419d478540de"}, + {file = "yarl-1.7.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6ddcd80d79c96eb19c354d9dca95291589c5954099836b7c8d29278a7ec0bda"}, + {file = "yarl-1.7.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9bfcd43c65fbb339dc7086b5315750efa42a34eefad0256ba114cd8ad3896f4b"}, + {file = "yarl-1.7.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f64394bd7ceef1237cc604b5a89bf748c95982a84bcd3c4bbeb40f685c810794"}, + {file = "yarl-1.7.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044daf3012e43d4b3538562da94a88fb12a6490652dbc29fb19adfa02cf72eac"}, + {file = "yarl-1.7.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:368bcf400247318382cc150aaa632582d0780b28ee6053cd80268c7e72796dec"}, + {file = "yarl-1.7.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:bab827163113177aee910adb1f48ff7af31ee0289f434f7e22d10baf624a6dfe"}, + {file = "yarl-1.7.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0cba38120db72123db7c58322fa69e3c0efa933040ffb586c3a87c063ec7cae8"}, + {file = "yarl-1.7.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:59218fef177296451b23214c91ea3aba7858b4ae3306dde120224cfe0f7a6ee8"}, + {file = "yarl-1.7.2-cp39-cp39-win32.whl", hash = "sha256:1edc172dcca3f11b38a9d5c7505c83c1913c0addc99cd28e993efeaafdfaa18d"}, + {file = "yarl-1.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:797c2c412b04403d2da075fb93c123df35239cd7b4cc4e0cd9e5839b73f52c58"}, + {file = "yarl-1.7.2.tar.gz", hash = "sha256:45399b46d60c253327a460e99856752009fcee5f5d3c80b2f7c0cae1c38d56dd"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..fc8a2b4b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,44 @@ +[tool.poetry] +name = "zhenxun_bot" +version = "0.1.1" +description = "基于 Nonebot2 和 go-cqhttp 开发,以 postgresql 作为数据库,非常可爱的绪山真寻bot" +authors = ["HibiKier <775757368@qq.com>"] +license = "AGPL" + +[[tool.poetry.source]] +name = "tsinghua" +default = true +url = "https://pypi.tuna.tsinghua.edu.cn/simple" + +[tool.poetry.dependencies] +python = "^3.8" +nonebot2 = "^2.0.0-beta.2" +nonebot-adapter-onebot = "^2.0.0-beta.1" +bilibili-api = "^9.1.0" +aiofiles = "^0.8.0" +aiohttp = "3.7.4.post0" +beautifulsoup4 = "4.9.3" +feedparser = "^6.0.8" +gino = "^1.0.1" +httpx = "^0.22.0" +ImageHash = "^4.2.1" +jieba = "^0.42.1" +lxml = "4.6.5" +nonebot-plugin-apscheduler = "^0.1.2" +opencv-python = "^4.5.5" +Pillow = "^9.0.1" +playwright = "^1.18.2" +psutil = "^5.9.0" +PyYAML = "5.4.1" +retrying = "^1.3.3" +ujson = "^5.1.0" +"ruamel.yaml" = "^0.17.21" +matplotlib = "^3.5.1" +black = "^22.1.0" +pypinyin = "^0.46.0" + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 2e9bb3f0..00000000 --- a/requirements.txt +++ /dev/null @@ -1,75 +0,0 @@ -aiofiles==0.8.0 -aiohttp==3.7.4.post0 -APScheduler==3.8.1 -async-timeout==3.0.1 -asyncpg==0.25.0 -attrs==21.2.0 -backports.zoneinfo==0.2.1 -beautifulsoup4==4.9.3 -bilibili-api==5.1.1 -certifi==2021.10.8 -chardet==4.0.0 -click==7.1.2 -colorama==0.4.4 -cycler==0.11.0 -fastapi==0.63.0 -feedparser==6.0.8 -fonttools==4.28.2 -gino==1.0.1 -greenlet==1.0.0 -h11==0.12.0 -httpcore==0.12.3 -httptools==0.1.2 -httpx==0.17.1 -idna==3.3 -ImageHash==4.2.1 -jieba==0.42.1 -kiwisolver==1.3.2 -loguru==0.5.3 -lxml==4.6.4 -matplotlib==3.5.0 -multidict==5.2.0 -nonebot-adapter-cqhttp==2.0.0a12 -nonebot-plugin-apscheduler==0.1.2 -nonebot2==2.0.0a13.post1 -numpy==1.21.4 -opencv-python==4.5.1.48 -packaging==21.3 -Pillow==8.2.0 -playwright==1.10.0 -psutil==5.8.0 -pydantic==1.8.2 -pyee==8.2.2 -pygtrie==2.4.2 -pyparsing==3.0.6 -pypinyin==0.41.0 -python-dateutil==2.8.2 -python-dotenv==0.19.2 -pytz==2021.3 -pytz-deprecation-shim==0.1.0.post0 -PyWavelets==1.2.0 -PyYAML==5.4.1 -retrying==1.3.3 -rfc3986==1.5.0 -ruamel.yaml==0.17.17 -ruamel.yaml.clib==0.2.6 -scipy==1.7.3 -setuptools-scm==6.3.2 -sgmllib3k==1.0.0 -six==1.16.0 -sniffio==1.2.0 -soupsieve==2.3.1 -SQLAlchemy==1.3.24 -starlette==0.13.6 -tomli==1.2.2 -tomlkit==0.7.2 -typing_extensions==4.0.1 -tzdata==2021.5 -tzlocal==4.1 -ujson==4.3.0 -urllib3==1.26.7 -uvicorn==0.13.4 -uvloop==0.16.0 -watchgod==0.7 -websockets==8.1 -yarl==1.7.2 diff --git a/services/log.py b/services/log.py index d870e320..ee757aec 100755 --- a/services/log.py +++ b/services/log.py @@ -8,7 +8,7 @@ logger = logger_ logger.add( - f'{LOG_PATH}/{datetime.now().date()}.log', + LOG_PATH / f'{datetime.now().date()}.log', level='INFO', rotation='00:00', format=default_format, @@ -16,7 +16,7 @@ logger.add( retention=timedelta(days=30)) logger.add( - f'{LOG_PATH}/error_{datetime.now().date()}.log', + LOG_PATH / f'error_{datetime.now().date()}.log', level='ERROR', rotation='00:00', format=default_format, diff --git a/update_info.json b/update_info.json index 38b4c20a..7fd1954b 100644 --- a/update_info.json +++ b/update_info.json @@ -4,7 +4,10 @@ "models", "services", "utils", - "basic_plugins" + "basic_plugins", + "configs/path_config.py", + "configs/utils", + "bot.py" ], "add_file": [], "delete_file": [] diff --git a/utils/browser.py b/utils/browser.py index 944ba379..28888df1 100755 --- a/utils/browser.py +++ b/utils/browser.py @@ -30,7 +30,7 @@ async def get_browser(**kwargs) -> Browser: return _browser or await init(**kwargs) -@driver.on_startup +# @driver.on_startup def install(): """自动安装、更新 Chromium""" logger.info("正在检查 Chromium 更新") @@ -38,4 +38,7 @@ def install(): from playwright.__main__ import main sys.argv = ["", "install", "chromium"] - main() + try: + main() + except SystemExit: + pass diff --git a/utils/http_utils.py b/utils/http_utils.py index 460b4832..42be9515 100644 --- a/utils/http_utils.py +++ b/utils/http_utils.py @@ -5,7 +5,7 @@ from services.log import logger from pathlib import Path from httpx import Response from asyncio.exceptions import TimeoutError -from nonebot.adapters.cqhttp import MessageSegment +from nonebot.adapters.onebot.v11 import MessageSegment from playwright.async_api import Page from .message_builder import image from httpx import ConnectTimeout @@ -31,7 +31,6 @@ class AsyncHttpx: cookies: Optional[Dict[str, str]] = None, use_proxy: bool = True, proxy: Dict[str, str] = None, - allow_redirects: bool = True, timeout: Optional[int] = 30, **kwargs, ) -> Response: @@ -45,7 +44,6 @@ class AsyncHttpx: :param cookies: cookies :param use_proxy: 使用默认代理 :param proxy: 指定代理 - :param allow_redirects: allow_redirects :param timeout: 超时时间 """ if not headers: @@ -57,7 +55,6 @@ class AsyncHttpx: params=params, headers=headers, cookies=cookies, - allow_redirects=allow_redirects, timeout=timeout, **kwargs ) @@ -76,7 +73,6 @@ class AsyncHttpx: params: Optional[Dict[str, str]] = None, headers: Optional[Dict[str, str]] = None, cookies: Optional[Dict[str, str]] = None, - allow_redirects: bool = True, timeout: Optional[int] = 30, **kwargs, ) -> Response: @@ -94,7 +90,6 @@ class AsyncHttpx: :param params: params :param headers: 请求头 :param cookies: cookies - :param allow_redirects: allow_redirects :param timeout: 超时时间 """ if not headers: @@ -110,7 +105,6 @@ class AsyncHttpx: params=params, headers=headers, cookies=cookies, - allow_redirects=allow_redirects, timeout=timeout, **kwargs, ) @@ -299,7 +293,7 @@ class AsyncPlaywright: cls, url: str, path: Union[Path, str], - element: str, + element: Union[str, List[str]], *, sleep: Optional[int] = None, viewport_size: Dict[str, int] = None, @@ -333,7 +327,12 @@ class AsyncPlaywright: await page.set_viewport_size(viewport_size) if sleep: await asyncio.sleep(sleep) - card = await page.query_selector(element) + if isinstance(element, str): + card = await page.query_selector(element) + else: + card = page + for e in element: + card = await card.query_selector(e) await card.screenshot(path=path, timeout=timeout, type=type_) return image(path) except Exception as e: diff --git a/utils/image_utils.py b/utils/image_utils.py index 17581bc8..74fe0a17 100755 --- a/utils/image_utils.py +++ b/utils/image_utils.py @@ -63,10 +63,10 @@ def compressed_image( :param out_file: 压缩后输出的文件路径 :param ratio: 压缩率,宽高 * 压缩率 """ - in_file = Path(IMAGE_PATH) / in_file if isinstance(in_file, str) else in_file + in_file = IMAGE_PATH / in_file if isinstance(in_file, str) else in_file if out_file: out_file = ( - Path(IMAGE_PATH) / out_file if isinstance(out_file, str) else out_file + IMAGE_PATH / out_file if isinstance(out_file, str) else out_file ) else: out_file = in_file @@ -137,186 +137,6 @@ def is_valid(file: str) -> bool: return valid -async def text2image( - text: str, - auto_parse: bool = True, - font_size: int = 20, - color: Union[str, Tuple[int, int, int], Tuple[int, int, int, int]] = "white", - font: str = "CJGaoDeGuo.otf", - font_color: Union[str, Tuple[int, int, int]] = "black", - padding: Union[int, Tuple[int, int, int, int]] = 0, -) -> str: - """ - 说明: - 解析文本并转为图片 - 使用标签 - - 可选配置项 - font: str -> 特殊文本字体 - font_size: int -> 特殊文本大小 - font_color: str -> 特殊文本颜色 - 示例 - 在不在,HibiKi小姐, - 你最近还好吗,我非常想你,这段时间我非常不好过, - 抽卡抽不到金色,这让我很痛苦 - 参数: - :param text: 文本 - :param auto_parse: 是否自动解析,否则原样发送 - :param font_size: 普通字体大小 - :param color: 背景颜色 - :param font: 普通字体 - :param font_color: 普通字体颜色 - :param padding: 文本外边距,元组类型时为 (上,左,下,右) - """ - pw = ph = top_padding = left_padding = 0 - if padding: - if isinstance(padding, int): - pw = padding * 2 - ph = padding * 2 - top_padding = left_padding = padding - elif isinstance(padding, tuple): - pw = padding[0] + padding[2] - ph = padding[1] + padding[3] - top_padding = padding[0] - left_padding = padding[1] - if auto_parse and re.search(r"(.*)", text): - _data = [] - new_text = "" - placeholder_index = 0 - for s in text.split(""): - r = re.search(r"(.*)", s) - if r: - start, end = r.span() - if start != 0 and (t := s[:start]): - new_text += t - _data.append( - [ - (start, end), - f"[placeholder_{placeholder_index}]", - r.group(1).strip(), - r.group(2), - ] - ) - new_text += f"[placeholder_{placeholder_index}]" - placeholder_index += 1 - new_text += text.split("")[-1] - image_list = [] - current_placeholder_index = 0 - # 切分换行,每行为单张图片 - for s in new_text.split("\n"): - _tmp_text = s - img_height = BuildImage(0, 0, font_size=font_size).getsize("正")[1] - img_width = 0 - _tmp_index = current_placeholder_index - for _ in range(s.count("[placeholder_")): - placeholder = _data[_tmp_index] - if "font_size" in placeholder[2]: - r = re.search(r"font_size=['\"]?(\d+)", placeholder[2]) - if r: - w, h = BuildImage(0, 0, font_size=int(r.group(1))).getsize( - placeholder[3] - ) - img_height = img_height if img_height > h else h - img_width += w - else: - img_width += BuildImage(0, 0, font_size=font_size).getsize( - placeholder[3] - )[0] - _tmp_text = _tmp_text.replace(f"[placeholder_{_tmp_index}]", "") - _tmp_index += 1 - img_width += BuildImage(0, 0, font_size=font_size).getsize(_tmp_text)[0] - # img_width += len(_tmp_text) * font_size - # 开始画图 - A = BuildImage( - img_width, img_height, color=color, font=font, font_size=font_size - ) - basic_font_h = A.getsize("正")[1] - current_width = 0 - # 遍历占位符 - for _ in range(s.count("[placeholder_")): - if not s.startswith(f"[placeholder_{current_placeholder_index}]"): - slice_ = s.split(f"[placeholder_{current_placeholder_index}]") - await A.atext( - (current_width, A.h - basic_font_h - 1), slice_[0], font_color - ) - current_width += A.getsize(slice_[0])[0] - placeholder = _data[current_placeholder_index] - # 解析配置 - _font = font - _font_size = font_size - _font_color = font_color - for e in placeholder[2].split(): - if e.startswith("font="): - _font = e.split("=")[-1] - if e.startswith("font_size=") or e.startswith("fs="): - _font_size = int(e.split("=")[-1]) - if _font_size > 1000: - _font_size = 1000 - if _font_size < 1: - _font_size = 1 - if e.startswith("font_color") or e.startswith("fc="): - _font_color = e.split("=")[-1] - text_img = BuildImage( - 0, - 0, - plain_text=placeholder[3], - font_size=_font_size, - font_color=_font_color, - font=_font, - ) - _img_h = ( - int(A.h / 2 - text_img.h / 2) - if new_text == "[placeholder_0]" - else A.h - text_img.h - ) - await A.apaste(text_img, (current_width, _img_h - 1), True) - current_width += text_img.w - s = s[ - s.index(f"[placeholder_{current_placeholder_index}]") - + len(f"[placeholder_{current_placeholder_index}]") : - ] - current_placeholder_index += 1 - if s: - slice_ = s.split(f"[placeholder_{current_placeholder_index}]") - await A.atext((current_width, A.h - basic_font_h), slice_[0]) - current_width += A.getsize(slice_[0])[0] - A.crop((0, 0, current_width, A.h)) - # A.show() - image_list.append(A) - height = 0 - width = 0 - for img in image_list: - height += img.h - width = width if width > img.w else img.w - width += pw - height += ph - A = BuildImage(width + left_padding, height + top_padding, color=color) - current_height = top_padding - for img in image_list: - await A.apaste(img, (left_padding, current_height), True) - current_height += img.h - else: - width = 0 - height = 0 - _tmp = BuildImage(0, 0, font_size=font_size) - for x in text.split("\n"): - w, h = _tmp.getsize(x) - height += h - width = width if width > w else w - width += pw - height += ph - A = BuildImage( - width + left_padding, - height + top_padding, - font_size=font_size, - color=color, - font=font, - ) - await A.atext((left_padding, top_padding), text, font_color) - # A.show() - return A.pic2bs4() - - class BuildImage: """ 快捷生成图片与操作图片的工具类 @@ -359,7 +179,7 @@ class BuildImage: self.paste_image_height = int(paste_image_height) self.current_w = 0 self.current_h = 0 - self.font = ImageFont.truetype(FONT_PATH + font, int(font_size)) + self.font = ImageFont.truetype(str(FONT_PATH / font), int(font_size)) if not plain_text and not color: color = (255, 255, 255) self.background = background @@ -838,41 +658,29 @@ class BuildImage: """ await self.loop.run_in_executor(None, self.circle) - def draw_ellipse(self, image, bounds, width=1, outline='white', antialias=4): - """ - Improved ellipse drawing function, based on PIL.ImageDraw. - """ - - # Use a single channel image (mode='L') as mask. - # The size of the mask can be increased relative to the imput image - # to get smoother looking results. - mask = Image.new( - size=[int(dim * antialias) for dim in image.size], - mode='L', color='black') - draw = ImageDraw.Draw(mask) - - # draw outer shape in white (color) and inner shape in black (transparent) - for offset, fill in (width / -2.0, 'black'), (width / 2.0, 'white'): - left, top = [(value + offset) * antialias for value in bounds[:2]] - right, bottom = [(value - offset) * antialias for value in bounds[2:]] - draw.ellipse([left, top, right, bottom], fill=fill) - - # downsample the mask using PIL.Image.LANCZOS - # (a high-quality downsampling filter). - mask = mask.resize(image.size, Image.LANCZOS) - - # paste outline color to input image through the mask - image.putalpha(mask) - - # def circle(self): + """ + 说明: + 使图像变圆 + """ self.markImg.convert("RGBA") size = self.markImg.size r2 = min(size[0], size[1]) if size[0] != size[1]: self.markImg = self.markImg.resize((r2, r2), Image.ANTIALIAS) + width = 1 + antialias = 4 ellipse_box = [0, 0, r2 - 2, r2 - 2] - self.draw_ellipse(self.markImg, ellipse_box, width=1) + mask = Image.new( + size=[int(dim * antialias) for dim in self.markImg.size], + mode='L', color='black') + draw = ImageDraw.Draw(mask) + for offset, fill in (width / -2.0, 'black'), (width / 2.0, 'white'): + left, top = [(value + offset) * antialias for value in ellipse_box[:2]] + right, bottom = [(value - offset) * antialias for value in ellipse_box[2:]] + draw.ellipse([left, top, right, bottom], fill=fill) + mask = mask.resize(self.markImg.size, Image.LANCZOS) + self.markImg.putalpha(mask) async def acircle_corner(self, radii: int = 30): """ @@ -1519,5 +1327,185 @@ class BuildMat: return A +async def text2image( + text: str, + auto_parse: bool = True, + font_size: int = 20, + color: Union[str, Tuple[int, int, int], Tuple[int, int, int, int]] = "white", + font: str = "CJGaoDeGuo.otf", + font_color: Union[str, Tuple[int, int, int]] = "black", + padding: Union[int, Tuple[int, int, int, int]] = 0, +) -> BuildImage: + """ + 说明: + 解析文本并转为图片 + 使用标签 + + 可选配置项 + font: str -> 特殊文本字体 + fs / font_size: int -> 特殊文本大小 + fc / font_color: Union[str, Tuple[int, int, int]] -> 特殊文本颜色 + 示例 + 在不在,HibiKi小姐, + 你最近还好吗,我非常想你,这段时间我非常不好过, + 抽卡抽不到金色,这让我很痛苦 + 参数: + :param text: 文本 + :param auto_parse: 是否自动解析,否则原样发送 + :param font_size: 普通字体大小 + :param color: 背景颜色 + :param font: 普通字体 + :param font_color: 普通字体颜色 + :param padding: 文本外边距,元组类型时为 (上,左,下,右) + """ + pw = ph = top_padding = left_padding = 0 + if padding: + if isinstance(padding, int): + pw = padding * 2 + ph = padding * 2 + top_padding = left_padding = padding + elif isinstance(padding, tuple): + pw = padding[0] + padding[2] + ph = padding[1] + padding[3] + top_padding = padding[0] + left_padding = padding[1] + if auto_parse and re.search(r"(.*)", text): + _data = [] + new_text = "" + placeholder_index = 0 + for s in text.split(""): + r = re.search(r"(.*)", s) + if r: + start, end = r.span() + if start != 0 and (t := s[:start]): + new_text += t + _data.append( + [ + (start, end), + f"[placeholder_{placeholder_index}]", + r.group(1).strip(), + r.group(2), + ] + ) + new_text += f"[placeholder_{placeholder_index}]" + placeholder_index += 1 + new_text += text.split("")[-1] + image_list = [] + current_placeholder_index = 0 + # 切分换行,每行为单张图片 + for s in new_text.split("\n"): + _tmp_text = s + img_height = BuildImage(0, 0, font_size=font_size).getsize("正")[1] + img_width = 0 + _tmp_index = current_placeholder_index + for _ in range(s.count("[placeholder_")): + placeholder = _data[_tmp_index] + if "font_size" in placeholder[2]: + r = re.search(r"font_size=['\"]?(\d+)", placeholder[2]) + if r: + w, h = BuildImage(0, 0, font_size=int(r.group(1))).getsize( + placeholder[3] + ) + img_height = img_height if img_height > h else h + img_width += w + else: + img_width += BuildImage(0, 0, font_size=font_size).getsize( + placeholder[3] + )[0] + _tmp_text = _tmp_text.replace(f"[placeholder_{_tmp_index}]", "") + _tmp_index += 1 + img_width += BuildImage(0, 0, font_size=font_size).getsize(_tmp_text)[0] + # img_width += len(_tmp_text) * font_size + # 开始画图 + A = BuildImage( + img_width, img_height, color=color, font=font, font_size=font_size + ) + basic_font_h = A.getsize("正")[1] + current_width = 0 + # 遍历占位符 + for _ in range(s.count("[placeholder_")): + if not s.startswith(f"[placeholder_{current_placeholder_index}]"): + slice_ = s.split(f"[placeholder_{current_placeholder_index}]") + await A.atext( + (current_width, A.h - basic_font_h - 1), slice_[0], font_color + ) + current_width += A.getsize(slice_[0])[0] + placeholder = _data[current_placeholder_index] + # 解析配置 + _font = font + _font_size = font_size + _font_color = font_color + for e in placeholder[2].split(): + if e.startswith("font="): + _font = e.split("=")[-1] + if e.startswith("font_size=") or e.startswith("fs="): + _font_size = int(e.split("=")[-1]) + if _font_size > 1000: + _font_size = 1000 + if _font_size < 1: + _font_size = 1 + if e.startswith("font_color") or e.startswith("fc="): + _font_color = e.split("=")[-1] + text_img = BuildImage( + 0, + 0, + plain_text=placeholder[3], + font_size=_font_size, + font_color=_font_color, + font=_font, + ) + _img_h = ( + int(A.h / 2 - text_img.h / 2) + if new_text == "[placeholder_0]" + else A.h - text_img.h + ) + await A.apaste(text_img, (current_width, _img_h - 1), True) + current_width += text_img.w + s = s[ + s.index(f"[placeholder_{current_placeholder_index}]") + + len(f"[placeholder_{current_placeholder_index}]") : + ] + current_placeholder_index += 1 + if s: + slice_ = s.split(f"[placeholder_{current_placeholder_index}]") + await A.atext((current_width, A.h - basic_font_h), slice_[0]) + current_width += A.getsize(slice_[0])[0] + A.crop((0, 0, current_width, A.h)) + # A.show() + image_list.append(A) + height = 0 + width = 0 + for img in image_list: + height += img.h + width = width if width > img.w else img.w + width += pw + height += ph + A = BuildImage(width + left_padding, height + top_padding, color=color) + current_height = top_padding + for img in image_list: + await A.apaste(img, (left_padding, current_height), True) + current_height += img.h + else: + width = 0 + height = 0 + _tmp = BuildImage(0, 0, font_size=font_size) + for x in text.split("\n"): + w, h = _tmp.getsize(x) + height += h + width = width if width > w else w + width += pw + height += ph + A = BuildImage( + width + left_padding, + height + top_padding, + font_size=font_size, + color=color, + font=font, + ) + await A.atext((left_padding, top_padding), text, font_color) + # A.show() + return A + + if __name__ == "__main__": pass diff --git a/utils/manager/__init__.py b/utils/manager/__init__.py index 02b8ba5d..01fc1266 100755 --- a/utils/manager/__init__.py +++ b/utils/manager/__init__.py @@ -1,6 +1,5 @@ from typing import Optional from .group_manager import GroupManager -from pathlib import Path from .data_class import StaticData from .withdraw_message_manager import WithdrawMessageManager from .plugins2cd_manager import Plugins2cdManager @@ -17,7 +16,7 @@ from configs.path_config import DATA_PATH # 群功能开关 | 群被动技能 | 群权限 管理 group_manager: Optional[GroupManager] = GroupManager( - Path(DATA_PATH) / "manager" / "group_manager.json" + DATA_PATH / "manager" / "group_manager.json" ) # 撤回消息管理 @@ -25,42 +24,42 @@ withdraw_message_manager: Optional[WithdrawMessageManager] = WithdrawMessageMana # 插件管理 plugins_manager: Optional[PluginsManager] = PluginsManager( - Path(DATA_PATH) / "manager" / "plugins_manager.json" + DATA_PATH / "manager" / "plugins_manager.json" ) # 插件基本设置管理 plugins2settings_manager: Optional[Plugins2settingsManager] = Plugins2settingsManager( - Path(DATA_PATH) / "configs" / "plugins2settings.yaml" + DATA_PATH / "configs" / "plugins2settings.yaml" ) # 插件命令 cd 管理 plugins2cd_manager: Optional[Plugins2cdManager] = Plugins2cdManager( - Path(DATA_PATH) / "configs" / "plugins2cd.yaml" + DATA_PATH / "configs" / "plugins2cd.yaml" ) # 插件命令 阻塞 管理 plugins2block_manager: Optional[Plugins2blockManager] = Plugins2blockManager( - Path(DATA_PATH) / "configs" / "plugins2block.yaml" + DATA_PATH / "configs" / "plugins2block.yaml" ) # 插件命令 每次次数限制 管理 plugins2count_manager: Optional[Plugins2countManager] = Plugins2countManager( - Path(DATA_PATH) / "configs" / "plugins2count.yaml" + DATA_PATH / "configs" / "plugins2count.yaml" ) # 资源管理 resources_manager: Optional[ResourcesManager] = ResourcesManager( - Path(DATA_PATH) / "manager" / "resources_manager.json" + DATA_PATH / "manager" / "resources_manager.json" ) # 插件加载容忍管理 none_plugin_count_manager: Optional[NonePluginCountManager] = NonePluginCountManager( - Path(DATA_PATH) / "manager" / "none_plugin_count_manager.json" + DATA_PATH / "manager" / "none_plugin_count_manager.json" ) # 好友请求/群聊邀请 管理 requests_manager: Optional[RequestManager] = RequestManager( - Path(DATA_PATH) / "manager" / "requests_manager.json" + DATA_PATH / "manager" / "requests_manager.json" ) diff --git a/utils/manager/group_manager.py b/utils/manager/group_manager.py index b450c403..123f4beb 100755 --- a/utils/manager/group_manager.py +++ b/utils/manager/group_manager.py @@ -262,7 +262,7 @@ class GroupManager(StaticData): """ if not self._task: for matcher in get_matchers(): - _plugin = nonebot.plugin.get_plugin(matcher.module) + _plugin = nonebot.plugin.get_plugin(matcher.plugin_name) try: _module = _plugin.module plugin_task = _module.__getattribute__("__plugin_task__") @@ -292,7 +292,6 @@ class GroupManager(StaticData): self._data["group_manager"][group_id]["group_task_status"][ task ] = Config.get_config('_task', f'DEFAULT_{task}', default=True) - print(task, Config.get_config('_task', f'DEFAULT_{task}')) for task in list( self._data["group_manager"][group_id]["group_task_status"] ): diff --git a/utils/manager/requests_manager.py b/utils/manager/requests_manager.py index 9085520c..ac790c88 100755 --- a/utils/manager/requests_manager.py +++ b/utils/manager/requests_manager.py @@ -1,6 +1,6 @@ from utils.manager.data_class import StaticData -from nonebot.adapters.cqhttp import Bot -from nonebot.adapters.cqhttp.exception import ActionFailed +from nonebot.adapters.onebot.v11 import Bot +from nonebot.adapters.onebot.v11.exception import ActionFailed from services.log import logger from typing import Optional from utils.image_utils import BuildImage diff --git a/utils/manager/resources_manager.py b/utils/manager/resources_manager.py index 07c02e13..c93b04ee 100755 --- a/utils/manager/resources_manager.py +++ b/utils/manager/resources_manager.py @@ -31,7 +31,7 @@ class ResourcesManager(StaticData): if isinstance(source_file, Path): source_file = str(source_file.absolute()) if isinstance(move_file, Path): - move_file = move_file.absolute() + move_file = str(move_file.absolute()) if module not in self._data.keys(): self._data[module] = {source_file: move_file} else: @@ -97,6 +97,7 @@ class ResourcesManager(StaticData): """ 添加临时清理文件夹 :param path: 路径 + :param recursive: 是否将该目录下的所有目录也添加为临时文件夹 """ if isinstance(path, str): path = Path(path) diff --git a/utils/manager/withdraw_message_manager.py b/utils/manager/withdraw_message_manager.py index 57eb3445..924486f5 100755 --- a/utils/manager/withdraw_message_manager.py +++ b/utils/manager/withdraw_message_manager.py @@ -1,5 +1,5 @@ from typing import Tuple, Union, Dict -from nonebot.adapters.cqhttp import MessageEvent, PrivateMessageEvent, GroupMessageEvent +from nonebot.adapters.onebot.v11 import MessageEvent, PrivateMessageEvent, GroupMessageEvent class WithdrawMessageManager: diff --git a/utils/message_builder.py b/utils/message_builder.py index cb7779a0..0e01e627 100755 --- a/utils/message_builder.py +++ b/utils/message_builder.py @@ -1,5 +1,5 @@ -from configs.path_config import IMAGE_PATH, VOICE_PATH -from nonebot.adapters.cqhttp.message import MessageSegment +from configs.path_config import IMAGE_PATH, RECORD_PATH +from nonebot.adapters.onebot.v11.message import MessageSegment from configs.config import NICKNAME from services.log import logger from typing import Union, List @@ -8,9 +8,9 @@ import os def image( - img_name: Union[str, Path] = None, + file: Union[str, Path, bytes] = None, path: str = None, - abspath: str = None, + abspath: Union[str, Path] = None, b64: str = None, ) -> Union[MessageSegment, str]: """ @@ -18,36 +18,40 @@ def image( 生成一个 MessageSegment.image 消息 生成顺序:绝对路径(abspath) > base64(b64) > img_name 参数: - :param img_name: 图片文件名称,默认在 resource/img 目录下 + :param file: 图片文件名称,默认在 resource/img 目录下 :param path: 图片所在路径,默认在 resource/img 目录下 :param abspath: 图片绝对路径 :param b64: 图片base64 """ if abspath: + if isinstance(abspath, Path): + return MessageSegment.image(file) return ( MessageSegment.image("file:///" + abspath) if os.path.exists(abspath) else "" ) - elif isinstance(img_name, Path): - if img_name.exists(): - return MessageSegment.image(f"file:///{img_name.absolute()}") - logger.warning(f"图片 {img_name.absolute()}缺失...") + elif isinstance(file, Path): + if file.exists(): + return MessageSegment.image(file) + logger.warning(f"图片 {file.absolute()}缺失...") return "" + elif isinstance(file, bytes): + return MessageSegment.image(file) elif b64: return MessageSegment.image(b64 if "base64://" in b64 else "base64://" + b64) else: - if "http" in img_name: - return MessageSegment.image(img_name) - if len(img_name.split(".")) == 1: - img_name += ".jpg" + if "http" in file: + return MessageSegment.image(file) + if len(file.split(".")) == 1: + file += ".jpg" file = ( - Path(IMAGE_PATH) / path / img_name if path else Path(IMAGE_PATH) / img_name + IMAGE_PATH / path / file if path else IMAGE_PATH / file ) if file.exists(): - return MessageSegment.image(f"file:///{file.absolute()}") + return MessageSegment.image(file) else: - logger.warning(f"图片 {file.absolute()}缺失...") + logger.warning(f"图片 {file} 缺失...") return "" @@ -72,7 +76,7 @@ def record(voice_name: str, path: str = None) -> MessageSegment or str: if len(voice_name.split(".")) == 1: voice_name += ".mp3" file = ( - Path(VOICE_PATH) / path / voice_name if path else Path(VOICE_PATH) / voice_name + Path(RECORD_PATH) / path / voice_name if path else Path(RECORD_PATH) / voice_name ) if "http" in voice_name: return MessageSegment.record(voice_name) diff --git a/utils/utils.py b/utils/utils.py index f4eabf85..6dd7f41b 100755 --- a/utils/utils.py +++ b/utils/utils.py @@ -3,7 +3,7 @@ from collections import defaultdict from nonebot import require from configs.config import SYSTEM_PROXY from typing import List, Union, Optional, Type, Any -from nonebot.adapters.cqhttp import Bot +from nonebot.adapters.onebot.v11 import Bot, Message from nonebot.matcher import matchers, Matcher import httpx import nonebot @@ -190,76 +190,82 @@ def get_matchers() -> List[Type[Matcher]]: return _matchers -def get_message_at(data: str) -> List[int]: +def get_message_at(data: Union[str, Message]) -> List[int]: """ 说明: 获取消息中所有的 at 对象的 qq 参数: :param data: event.json() """ - try: - qq_list = [] + qq_list = [] + if isinstance(data, str): data = json.loads(data) for msg in data["message"]: if msg["type"] == "at": qq_list.append(int(msg["data"]["qq"])) - return qq_list - except KeyError: - return [] + else: + for seg in data: + if seg.type == "image": + qq_list.append(seg.data["url"]) + return qq_list -def get_message_img(data: str) -> List[str]: +def get_message_img(data: Union[str, Message]) -> List[str]: """ 说明: 获取消息中所有的 图片 的链接 参数: :param data: event.json() """ - try: - img_list = [] + img_list = [] + if isinstance(data, str): data = json.loads(data) for msg in data["message"]: if msg["type"] == "image": img_list.append(msg["data"]["url"]) - return img_list - except KeyError: - return [] + else: + for seg in data["image"]: + img_list.append(seg.data["url"]) + return img_list -def get_message_text(data: str) -> str: +def get_message_text(data: Union[str, Message]) -> str: """ 说明: 获取消息中 纯文本 的信息 参数: :param data: event.json() """ - try: + result = "" + if isinstance(data, str): data = json.loads(data) - result = "" for msg in data["message"]: if msg["type"] == "text": result += msg["data"]["text"].strip() + " " return result.strip() - except KeyError: - return "" + else: + for seg in data["text"]: + result += seg.data["text"] + " " + return result -def get_message_record(data: str) -> List[str]: +def get_message_record(data: Union[str, Message]) -> List[str]: """ 说明: 获取消息中所有 语音 的链接 参数: :param data: event.json() """ - try: - record_list = [] + record_list = [] + if isinstance(data, str): data = json.loads(data) for msg in data["message"]: if msg["type"] == "record": record_list.append(msg["data"]["url"]) - return record_list - except KeyError: - return [] + else: + for seg in data["record"]: + record_list.append(seg.data["url"]) + return record_list def get_message_json(data: str) -> List[dict]: