diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..4f753bbb --- /dev/null +++ b/.gitignore @@ -0,0 +1,145 @@ +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +test.py +server.py +member_activity_handle.py +Yu-Gi-Oh/ + diff --git a/README.md b/README.md index 3d23c013..1aee848f 100644 --- a/README.md +++ b/README.md @@ -321,6 +321,15 @@ python bot.py ## 更新 +### 2021/12/1 \[v0.0.6.5] + +* 群权限-1时超级用户命令依旧生效 +* 修复以真寻为开头的词条不会被回复 +* 修复购买道具可以为负数 +* P站排行/搜图提供配置项,将略过大于指定张数的作品 +* 昵称提供关键词屏蔽配置项,会将指定关键词替换为“*” +* 取消了自动更新,改为自动检测版本 + ### 2021/11/29 \[v0.0.6.4] * 新增cos图撤回配置项 diff --git a/__version__ b/__version__ index 533ba4fb..ecae71be 100644 --- a/__version__ +++ b/__version__ @@ -1 +1 @@ -__version__: v0.0.6.4 +__version__: v0.0.6.5 diff --git a/basic_plugins/hooks/auth_hook.py b/basic_plugins/hooks/auth_hook.py index aaf782bf..aaa173da 100755 --- a/basic_plugins/hooks/auth_hook.py +++ b/basic_plugins/hooks/auth_hook.py @@ -20,6 +20,7 @@ from models.ban_user import BanUser from utils.utils import FreqLimiter from utils.message_builder import at from models.level_user import LevelUser +import nonebot _flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD")) @@ -46,6 +47,18 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): and not plugins2info_dict[module]["limit_superuser"] ): return + # 超级用户命令 + try: + _plugin = nonebot.plugin.get_plugin(module) + _module = _plugin.module + plugin_name = _module.__getattribute__("__zx_plugin_name__") + if ( + "[superuser]" in plugin_name.lower() + and str(event.user_id) in bot.config.superusers + ): + return + except AttributeError: + pass # 群黑名单检测 if isinstance(event, GroupMessageEvent): if group_manager.get_group_level(event.group_id) < 0: diff --git a/basic_plugins/init_plugin_config/__init__.py b/basic_plugins/init_plugin_config/__init__.py index 65156ada..f2b6f963 100755 --- a/basic_plugins/init_plugin_config/__init__.py +++ b/basic_plugins/init_plugin_config/__init__.py @@ -11,6 +11,7 @@ from .init_plugins_limit import ( ) from .init import init from .check_plugin_status import check_plugin_status +from utils.manager import admin_manager from nonebot.adapters.cqhttp import Bot from configs.path_config import DATA_PATH from services.log import logger diff --git a/basic_plugins/init_plugin_config/init_plugins_config.py b/basic_plugins/init_plugin_config/init_plugins_config.py index 5fb57ffa..c1fc94c9 100755 --- a/basic_plugins/init_plugin_config/init_plugins_config.py +++ b/basic_plugins/init_plugin_config/init_plugins_config.py @@ -148,4 +148,3 @@ def init_plugins_config(data_path): logger.error(f"生成简易配置注释错误 {type(e)}:{e}") if temp_file.exists(): temp_file.unlink() - diff --git a/basic_plugins/init_plugin_config/init_plugins_settings.py b/basic_plugins/init_plugin_config/init_plugins_settings.py index fff027d9..82f0dced 100755 --- a/basic_plugins/init_plugin_config/init_plugins_settings.py +++ b/basic_plugins/init_plugin_config/init_plugins_settings.py @@ -26,7 +26,7 @@ def init_plugins_settings(data_path: str): plugin_name = _module.__getattribute__("__zx_plugin_name__") _tmp_module[x] = plugin_name except (KeyError, AttributeError) as e: - logger.error(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}") + logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}") _tmp_module[x] = "" for matcher in _matchers: if matcher.module not in plugins2settings_manager.keys(): diff --git a/basic_plugins/nickname.py b/basic_plugins/nickname.py index f06018b8..c4ff30db 100755 --- a/basic_plugins/nickname.py +++ b/basic_plugins/nickname.py @@ -8,7 +8,7 @@ from models.friend_user import FriendUser import random from models.ban_user import BanUser from services.log import logger -from configs.config import NICKNAME +from configs.config import NICKNAME, Config __zx_plugin_name__ = "昵称系统" @@ -23,6 +23,13 @@ __plugin_des__ = "区区昵称,才不想叫呢!" __plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁"] __plugin_version__ = 0.1 __plugin_author__ = "HibiKier" +__plugin_configs__ = { + "BLACK_WORD": { + "value": ["爸", "妈", "爹", "爷"], + "help": "昵称所屏蔽的关键词,会被替换为 *", + "default_value": None + } +} nickname = on_command( "nickname", @@ -47,52 +54,52 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True) if len(msg) > 10: await nickname.finish("昵称可不能超过10个字!", at_sender=True) - if await GroupInfoUser.set_group_member_nickname( - event.user_id, event.group_id, msg - ): - if len(msg) < 5: - if random.random() < 0.5: - msg = "~".join(msg) - await nickname.send( - random.choice( - [ - f"好啦好啦,我知道啦,{msg},以后就这么叫你吧", - f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}", - f"好突然,突然要叫你昵称什么的...{msg}..", - f"{NICKNAME}会好好记住的{msg}的,放心吧", - f"好..好.,那窝以后就叫你{msg}了.", - ] + if msg in bot.config.superusers: + await nickname.finish("笨蛋!休想占用我的名字!#", at_sender=True) + _tmp = "" + black_word = Config.get_config("nickname", "BLACK_WORD") + for x in msg: + _tmp += "*" if x in black_word else x + msg = _tmp + if isinstance(event, GroupMessageEvent): + if await GroupInfoUser.set_group_member_nickname( + event.user_id, event.group_id, msg + ): + if len(msg) < 5: + if random.random() < 0.3: + msg = "~".join(msg) + await nickname.send( + random.choice( + [ + f"好啦好啦,我知道啦,{msg},以后就这么叫你吧", + f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}", + f"好突然,突然要叫你昵称什么的...{msg}..", + f"{NICKNAME}会好好记住的{msg}的,放心吧", + f"好..好.,那窝以后就叫你{msg}了.", + ] + ) ) - ) - logger.info(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg}") + logger.info(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg}") + else: + await nickname.send("设置昵称失败,请更新群组成员信息!", at_sender=True) + logger.warning(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg} 失败") else: - await nickname.send("设置昵称失败,请更新群组成员信息!", at_sender=True) - logger.warning(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg} 失败") - - -@nickname.handle() -async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): - msg = get_message_text(event.json()) - if not msg: - await nickname.finish("叫你空白?叫你虚空?叫你无名??", at_sender=True) - if len(msg) > 10: - await nickname.finish("不要超过10个字!", at_sender=True) - if await FriendUser.set_friend_nickname(event.user_id, msg): - await nickname.send( - random.choice( - [ - f"好啦好啦,我知道啦,{msg},以后就这么叫你吧", - f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}", - f"好突然,突然要叫你昵称什么的...{msg}..", - f"{NICKNAME}会好好记住的{msg}的,放心吧", - f"好..好.,那窝以后就叫你{msg}了.", - ] + if await FriendUser.set_friend_nickname(event.user_id, msg): + await nickname.send( + random.choice( + [ + f"好啦好啦,我知道啦,{msg},以后就这么叫你吧", + f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}", + f"好突然,突然要叫你昵称什么的...{msg}..", + f"{NICKNAME}会好好记住的{msg}的,放心吧", + f"好..好.,那窝以后就叫你{msg}了.", + ] + ) ) - ) - logger.info(f"USER {event.user_id} 设置昵称 {msg}") - else: - await nickname.send("设置昵称失败了,明天再来试一试!或联系管理员更新好友!", at_sender=True) - logger.warning(f"USER {event.user_id} 设置昵称 {msg} 失败") + logger.info(f"USER {event.user_id} 设置昵称 {msg}") + else: + await nickname.send("设置昵称失败了,明天再来试一试!或联系管理员更新好友!", at_sender=True) + logger.warning(f"USER {event.user_id} 设置昵称 {msg} 失败") @my_nickname.handle() diff --git a/basic_plugins/super_cmd/reload_setting.py b/basic_plugins/super_cmd/reload_setting.py index 494ee819..fd92db2d 100755 --- a/basic_plugins/super_cmd/reload_setting.py +++ b/basic_plugins/super_cmd/reload_setting.py @@ -15,6 +15,10 @@ __zx_plugin_name__ = "重载插件配置 [Superuser]" __plugin_usage__ = """ usage: 重载插件配置 + plugins2settings, + plugins2cd + plugins2block + group_manager 指令: 重载插件配置 """.strip() @@ -27,7 +31,7 @@ __plugin_author__ = "HibiKier" reload_plugins_manager = on_command( - "重载插件限制", rule=to_me(), permission=SUPERUSER, priority=1, block=True + "重载配置", rule=to_me(), permission=SUPERUSER, priority=1, block=True ) diff --git a/models/friend_user.py b/models/friend_user.py index c6b731ef..69d31ef5 100755 --- a/models/friend_user.py +++ b/models/friend_user.py @@ -1,4 +1,5 @@ from services.db_context import db +from configs.config import Config class FriendUser(db.Model): @@ -80,7 +81,11 @@ class FriendUser(db.Model): user = await query.gino.first() if user: if user.nickname: - return user.nickname + _tmp = "" + black_word = Config.get_config("nickname", "BLACK_WORD") + for x in user.nickname: + _tmp += "*" if x in black_word else x + return _tmp return "" @classmethod diff --git a/models/group_member_info.py b/models/group_member_info.py index 0e2be8f6..df032d8b 100755 --- a/models/group_member_info.py +++ b/models/group_member_info.py @@ -1,5 +1,5 @@ from datetime import datetime - +from configs.config import Config from services.db_context import db from typing import List, Optional @@ -128,6 +128,17 @@ class GroupInfoUser(db.Model): return True return False + @classmethod + async def get_user_all_group(cls, user_qq: int) -> List[int]: + """ + 获取该用户所在的所有群聊 + :param user_qq: 用户qq + """ + query = await cls.query.where(cls.user_qq == user_qq).gino.all() + if query: + query = [x.belonging_group for x in query] + return query + @classmethod async def get_group_member_nickname(cls, user_qq: int, belonging_group: int) -> str: """ @@ -143,7 +154,11 @@ class GroupInfoUser(db.Model): user = await query.gino.first() if user: if user.nickname: - return user.nickname + _tmp = "" + black_word = Config.get_config("nickname", "BLACK_WORD") + for x in user.nickname: + _tmp += "*" if x in black_word else x + return _tmp return "" @classmethod diff --git a/plugins/ai/data_source.py b/plugins/ai/data_source.py index 13c8d630..893f316a 100755 --- a/plugins/ai/data_source.py +++ b/plugins/ai/data_source.py @@ -59,7 +59,6 @@ async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str) nickname += "大~人~" rst = rst.replace("小主人", nickname).replace("小朋友", nickname) ai_message_manager.add_result(user_id, rst) - print(ai_message_manager) return rst diff --git a/plugins/alapi/__init__.py b/plugins/alapi/__init__.py index ddabb5d5..2135b636 100755 --- a/plugins/alapi/__init__.py +++ b/plugins/alapi/__init__.py @@ -1,7 +1,6 @@ from configs.config import Config import nonebot -nonebot.load_plugins("plugins/alapi") Config.add_plugin_config( "alapi", @@ -9,3 +8,7 @@ Config.add_plugin_config( None, help_="在https://admin.alapi.cn/user/login登录后获取token" ) + + +nonebot.load_plugins("plugins/alapi") + diff --git a/plugins/check_zhenxun_update/__init__.py b/plugins/check_zhenxun_update/__init__.py index ff590e40..19633fd6 100755 --- a/plugins/check_zhenxun_update/__init__.py +++ b/plugins/check_zhenxun_update/__init__.py @@ -110,17 +110,17 @@ async def _(): f"当前版本:{_version},最新版本:{latest_version}\n" f"尝试自动更新...", ) - try: - code = await check_update(bot) - except Exception as e: - logger.error(f"更新真寻未知错误 {type(e)}:{e}") - await bot.send_private_msg( - user_id=int(list(bot.config.superusers)[0]), - message=f"更新真寻未知错误 {type(e)}:{e}\n", - ) - else: - if code == 200: - await bot.send_private_msg( - user_id=int(list(bot.config.superusers)[0]), - message=f"更新完毕,请重启真寻....", - ) + # try: + # code = await check_update(bot) + # except Exception as e: + # logger.error(f"更新真寻未知错误 {type(e)}:{e}") + # await bot.send_private_msg( + # user_id=int(list(bot.config.superusers)[0]), + # message=f"更新真寻未知错误 {type(e)}:{e}\n", + # ) + # else: + # if code == 200: + # await bot.send_private_msg( + # user_id=int(list(bot.config.superusers)[0]), + # message=f"更新完毕,请重启真寻....", + # ) diff --git a/plugins/coser/__init__.py b/plugins/coser/__init__.py index 3694f18c..5c37c2d7 100755 --- a/plugins/coser/__init__.py +++ b/plugins/coser/__init__.py @@ -51,4 +51,3 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): except Exception as e: await coser.send("你cos给我看!") logger.error(f"coser 发送了未知错误 {type(e)}:{e}") - diff --git a/plugins/draw_card/genshin_handle.py b/plugins/draw_card/genshin_handle.py index 4941c778..c05aab91 100755 --- a/plugins/draw_card/genshin_handle.py +++ b/plugins/draw_card/genshin_handle.py @@ -1,6 +1,5 @@ import os from nonebot.adapters.cqhttp import MessageSegment, Message -import nonebot import random from .update_game_info import update_info from .util import generate_img, init_star_rst, BaseData, set_list, get_star, init_up_char @@ -15,7 +14,6 @@ try: except ModuleNotFoundError: import json -driver: nonebot.Driver = nonebot.get_driver() announcement = GenshinAnnouncement() diff --git a/plugins/draw_card/guardian_handle.py b/plugins/draw_card/guardian_handle.py index cedc86e7..dfc2f501 100755 --- a/plugins/draw_card/guardian_handle.py +++ b/plugins/draw_card/guardian_handle.py @@ -1,6 +1,5 @@ import os -import nonebot from nonebot.adapters.cqhttp import MessageSegment, Message from .update_game_info import update_info from .announcement import GuardianAnnouncement @@ -18,7 +17,6 @@ try: except ModuleNotFoundError: import json -driver: nonebot.Driver = nonebot.get_driver() announcement = GuardianAnnouncement() diff --git a/plugins/draw_card/pretty_handle.py b/plugins/draw_card/pretty_handle.py index 91e81a1b..5e74f4c5 100755 --- a/plugins/draw_card/pretty_handle.py +++ b/plugins/draw_card/pretty_handle.py @@ -1,5 +1,4 @@ -import nonebot from .update_game_info import update_info from .announcement import PrettyAnnouncement from .util import init_star_rst, generate_img, max_card, BaseData, \ @@ -15,7 +14,6 @@ try: except ModuleNotFoundError: import json -driver: nonebot.Driver = nonebot.get_driver() announcement = PrettyAnnouncement() diff --git a/plugins/draw_card/prts_handle.py b/plugins/draw_card/prts_handle.py index df8c6ab6..3278ffef 100755 --- a/plugins/draw_card/prts_handle.py +++ b/plugins/draw_card/prts_handle.py @@ -1,6 +1,5 @@ from nonebot.adapters.cqhttp import MessageSegment, Message -import nonebot import random from .config import PRTS_FIVE_P, PRTS_FOUR_P, PRTS_SIX_P, PRTS_THREE_P, DRAW_PATH, PRTS_FLAG from .update_game_info import update_info @@ -15,7 +14,6 @@ try: except ModuleNotFoundError: import json -driver: nonebot.Driver = nonebot.get_driver() announcement = PrtsAnnouncement() diff --git a/plugins/genshin/almanac/__init__.py b/plugins/genshin/almanac/__init__.py index a8c49454..894f28e3 100755 --- a/plugins/genshin/almanac/__init__.py +++ b/plugins/genshin/almanac/__init__.py @@ -65,4 +65,4 @@ async def _(): mes = 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) + await bot.send_group_msg(group_id=int(gid), message="" + mes) diff --git a/plugins/genshin/query_resource_points/query_resource.py b/plugins/genshin/query_resource_points/query_resource.py index 958546a0..8c131832 100755 --- a/plugins/genshin/query_resource_points/query_resource.py +++ b/plugins/genshin/query_resource_points/query_resource.py @@ -8,6 +8,7 @@ from asyncio.exceptions import TimeoutError 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 @@ -150,9 +151,11 @@ async def download_resource_data(semaphore: Semaphore): logger.warning(f'获取原神资源失败 msg: {data["message"]}') else: logger.warning(f"获取原神资源失败 code:{response.status_code}") - except TimeoutError: + except (TimeoutError, ConnectTimeout): logger.warning("获取原神资源数据超时...已再次尝试...") await download_resource_data(semaphore) + except Exception as e: + logger.error(f"获取原神资源数据未知错误 {type(e)}:{e}") # 下载原神地图并拼图 @@ -164,55 +167,65 @@ async def download_map_init( _map = map_path / "map.png" if _map.exists() and os.path.getsize(_map) > 1024 * 1024 * 30: _map.unlink() - response = await AsyncHttpx.get(MAP_URL) - if response.status_code == 200: - data = response.json() - if data["message"] == "OK": - data = json.loads(data["data"]["info"]["detail"]) - CENTER_POINT = (data["origin"][0], data["origin"][1]) - if not _map.exists(): - data = data["slices"] - idx = 0 - for _map_data in data[0]: - map_url = _map_data['url'] - await download_image( - map_url, - f"{map_path}/{idx}.png", - semaphore, - force_flag=flag, - ) - idx += 1 - _w, h = CreateImg(0, 0, background=f"{map_path}/0.png", ratio=MAP_RATIO).size - w = _w * len(os.listdir(map_path)) - map_file = CreateImg(w, h, _w, h, ratio=MAP_RATIO) - for i in range(idx): - map_file.paste(CreateImg(0, 0, background=f"{map_path}/{i}.png", ratio=MAP_RATIO)) - map_file.save(f"{map_path}/map.png") + try: + response = await AsyncHttpx.get(MAP_URL) + if response.status_code == 200: + data = response.json() + if data["message"] == "OK": + data = json.loads(data["data"]["info"]["detail"]) + CENTER_POINT = (data["origin"][0], data["origin"][1]) + if not _map.exists(): + data = data["slices"] + idx = 0 + for _map_data in data[0]: + map_url = _map_data['url'] + await download_image( + map_url, + f"{map_path}/{idx}.png", + semaphore, + force_flag=flag, + ) + idx += 1 + _w, h = CreateImg(0, 0, background=f"{map_path}/0.png", ratio=MAP_RATIO).size + w = _w * len(os.listdir(map_path)) + map_file = CreateImg(w, h, _w, h, ratio=MAP_RATIO) + for i in range(idx): + map_file.paste(CreateImg(0, 0, background=f"{map_path}/{i}.png", ratio=MAP_RATIO)) + map_file.save(f"{map_path}/map.png") + else: + logger.warning(f'获取原神地图失败 msg: {data["message"]}') else: - logger.warning(f'获取原神地图失败 msg: {data["message"]}') - else: - logger.warning(f"获取原神地图失败 code:{response.status}") + logger.warning(f"获取原神地图失败 code:{response.status_code}") + except (TimeoutError, ConnectTimeout): + logger.warning("下载原神地图数据超时....") + except Exception as e: + logger.error(f"下载原神地图数据超时 {type(e)}:{e}") # 下载资源类型数据 async def download_resource_type(): resource_type_file.parent.mkdir(parents=True, exist_ok=True) - response = await AsyncHttpx.get(LABEL_URL) - if response.status_code == 200: - data = response.json() - if data["message"] == "OK": - data = data["data"]["tree"] - resource_data = {} - for x in data: - id_ = x["id"] - resource_data[id_] = x - with open(resource_type_file, "w", encoding="utf8") as f: - json.dump(resource_data, f, ensure_ascii=False, indent=4) - logger.info(f"更新原神资源类型成功...") + try: + response = await AsyncHttpx.get(LABEL_URL) + if response.status_code == 200: + data = response.json() + if data["message"] == "OK": + data = data["data"]["tree"] + resource_data = {} + for x in data: + id_ = x["id"] + resource_data[id_] = x + with open(resource_type_file, "w", encoding="utf8") as f: + json.dump(resource_data, f, ensure_ascii=False, indent=4) + logger.info(f"更新原神资源类型成功...") + else: + logger.warning(f'获取原神资源类型失败 msg: {data["message"]}') else: - logger.warning(f'获取原神资源类型失败 msg: {data["message"]}') - else: - logger.warning(f"获取原神资源类型失败 code:{response.status_code}") + logger.warning(f"获取原神资源类型失败 code:{response.status_code}") + except (TimeoutError, ConnectTimeout): + logger.warning("下载原神资源类型数据超时....") + except Exception as e: + logger.error(f"载原神资源类型数据超时 {type(e)}:{e}") # 初始化资源图标 diff --git a/plugins/gold_redbag/data_source.py b/plugins/gold_redbag/data_source.py index 44dd159f..419cfe3b 100755 --- a/plugins/gold_redbag/data_source.py +++ b/plugins/gold_redbag/data_source.py @@ -1,7 +1,6 @@ from models.bag_user import BagUser -from utils.utils import is_number, get_local_proxy, get_user_avatar +from utils.utils import is_number, get_user_avatar from utils.image_utils import CreateImg -from utils.user_agent import get_user_agent from configs.path_config import IMAGE_PATH from .model import RedbagUser import random diff --git a/plugins/image_management/upload_image/__init__.py b/plugins/image_management/upload_image/__init__.py index dbe3ce82..b75ce1ae 100755 --- a/plugins/image_management/upload_image/__init__.py +++ b/plugins/image_management/upload_image/__init__.py @@ -22,7 +22,7 @@ __plugin_des__ = "指定图库图片上传" __plugin_cmd__ = ["上传图片 [图库] [图片]", "连续上传图片 [图库]", "查看公开图库"] __plugin_version__ = 0.1 __plugin_author__ = "HibiKier" -__plugin_settings__ = {"admin_level": Config.get_config("image_management", "DELETE_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) diff --git a/plugins/my_info.py b/plugins/my_info/__init__.py old mode 100755 new mode 100644 similarity index 97% rename from plugins/my_info.py rename to plugins/my_info/__init__.py index e9b2c510..4939899c --- a/plugins/my_info.py +++ b/plugins/my_info/__init__.py @@ -1,48 +1,48 @@ -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 models.group_member_info import GroupInfoUser -from datetime import timedelta -from models.level_user import LevelUser - - -__zx_plugin_name__ = "个人信息权限查看" -__plugin_usage__ = """ -usage: - 个人信息权限查看 - 指令: - 我的信息 - 我的权限 -""".strip() -__plugin_des__ = "我们还记得你和你的权利" -__plugin_cmd__ = ["我的信息", "我的权限"] -__plugin_version__ = 0.1 -__plugin_author__ = "HibiKier" - - -get_my_group_info = on_command("我的信息", permission=GROUP, priority=1, block=True) -my_level = on_command("我的权限", permission=GROUP, priority=5, block=True) - - -@get_my_group_info.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - result = await get_member_info(event.user_id, event.group_id) - await get_my_group_info.finish(result) - - -async def get_member_info(user_qq: int, group_id: int) -> str: - user = await GroupInfoUser.get_member_info(user_qq, group_id) - if user is None: - return "该群员不在列表中,请更新群成员信息" - result = "" - result += "昵称:" + user.user_name + "\n" - result += "加群时间:" + str(user.user_join_time.date() + timedelta(hours=8)) - return result - - -@my_level.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - 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) +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 models.group_member_info import GroupInfoUser +from datetime import timedelta +from models.level_user import LevelUser + + +__zx_plugin_name__ = "个人信息权限查看" +__plugin_usage__ = """ +usage: + 个人信息权限查看 + 指令: + 我的信息 + 我的权限 +""".strip() +__plugin_des__ = "我们还记得你和你的权利" +__plugin_cmd__ = ["我的信息", "我的权限"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" + + +get_my_group_info = on_command("我的信息", permission=GROUP, priority=1, block=True) +my_level = on_command("我的权限", permission=GROUP, priority=5, block=True) + + +@get_my_group_info.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + result = await get_member_info(event.user_id, event.group_id) + await get_my_group_info.finish(result) + + +async def get_member_info(user_qq: int, group_id: int) -> str: + user = await GroupInfoUser.get_member_info(user_qq, group_id) + if user is None: + return "该群员不在列表中,请更新群成员信息" + result = "" + result += "昵称:" + user.user_name + "\n" + result += "加群时间:" + str(user.user_join_time.date() + timedelta(hours=8)) + return result + + +@my_level.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + 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/my_info/data_source.py b/plugins/my_info/data_source.py new file mode 100644 index 00000000..6fb66a5e --- /dev/null +++ b/plugins/my_info/data_source.py @@ -0,0 +1,6 @@ + + + + + + diff --git a/plugins/pix_gallery/model/__init__.py b/plugins/pix_gallery/model/__init__.py index f16c3e52..d3f5a12f 100755 --- a/plugins/pix_gallery/model/__init__.py +++ b/plugins/pix_gallery/model/__init__.py @@ -1,3 +1 @@ -from .pixiv_keyword_user import * -from .omega_pixiv_illusts import * -from .pixiv import * + diff --git a/plugins/pix_gallery/model/omega_pixiv_illusts.py b/plugins/pix_gallery/model/omega_pixiv_illusts.py index b9df7fce..b9198e68 100755 --- a/plugins/pix_gallery/model/omega_pixiv_illusts.py +++ b/plugins/pix_gallery/model/omega_pixiv_illusts.py @@ -139,3 +139,15 @@ class OmegaPixivIllusts(db.Model): 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/pixiv_rank_search/__init__.py b/plugins/pixiv_rank_search/__init__.py index c09b4795..a8e6abcc 100755 --- a/plugins/pixiv_rank_search/__init__.py +++ b/plugins/pixiv_rank_search/__init__.py @@ -64,6 +64,11 @@ __plugin_configs__ = { "value": 10, "help": "图片下载超时限制", "default_value": 10 + }, + "MAX_PAGE_LIMIT": { + "value": 20, + "help": "作品最大页数限制,超过的作品会被略过", + "default_value": 20 } } Config.add_plugin_config( diff --git a/plugins/pixiv_rank_search/data_source.py b/plugins/pixiv_rank_search/data_source.py index 898c97d0..82d3b068 100755 --- a/plugins/pixiv_rank_search/data_source.py +++ b/plugins/pixiv_rank_search/data_source.py @@ -89,8 +89,13 @@ async def parser_data( else: return ["网络不太好?没有该页数?也许过一会就好了..."], 998 num = num if num < 30 else 30 - data = data[:num] + _data = [] for x in data: + if x["page_count"] < Config.get_config("pixiv_rank_search", "MAX_PAGE_LIMIT"): + _data.append(x) + if len(_data) == num: + break + for x in _data: if type_ == "search" and r18 == 1: if "R-18" in str(x["tags"]): continue diff --git a/plugins/send_setu_/update_setu/data_source.py b/plugins/send_setu_/update_setu/data_source.py index 67d83c43..5c9bd3fe 100755 --- a/plugins/send_setu_/update_setu/data_source.py +++ b/plugins/send_setu_/update_setu/data_source.py @@ -37,8 +37,8 @@ async def update_old_setu_data(): for x in data: if file == setu_data_file: idx = index - if 'R-18' in data[x]["tags"]: - data[x]["tags"].remove('R-18') + if "R-18" in data[x]["tags"]: + data[x]["tags"].remove("R-18") else: idx = r18_index img_url = ( @@ -58,14 +58,16 @@ async def update_old_setu_data(): ",".join(data[x]["tags"]), ) count += 1 - if 'R-18' in data[x]["tags"]: + if "R-18" in data[x]["tags"]: r18_index += 1 else: index += 1 logger.info(f'添加旧色图数据成功 PID:{data[x]["pid"]} index:{idx}....') except UniqueViolationError: fail_count += 1 - logger.info(f'添加旧色图数据失败,色图重复 PID:{data[x]["pid"]} index:{idx}....') + logger.info( + f'添加旧色图数据失败,色图重复 PID:{data[x]["pid"]} index:{idx}....' + ) file.unlink() setu_url_path = path / "setu_url.json" setu_r18_url_path = path / "setu_r18_url.json" @@ -106,21 +108,25 @@ async def update_setu_img(): url_ = image.img_url ws_url = Config.get_config("pixiv", "PIXIV_NGINX_URL") if ws_url: - url_ = url_.replace("i.pximg.net", ws_url).replace("i.pixiv.cat", ws_url) + url_ = url_.replace("i.pximg.net", ws_url).replace( + "i.pixiv.cat", ws_url + ) try: - if not await AsyncHttpx.download_file(url_, rar_path / f'{image.local_id}.jpg'): + if not await AsyncHttpx.download_file( + url_, rar_path / f"{image.local_id}.jpg" + ): continue _success += 1 try: if ( os.path.getsize( - rar_path / f'{image.local_id}.jpg', + rar_path / f"{image.local_id}.jpg", ) > 1024 * 1024 * 1.5 ): compressed_image( rar_path / f"{image.local_id}.jpg", - path / f"{image.local_id}.jpg" + path / f"{image.local_id}.jpg", ) else: logger.info( @@ -134,30 +140,20 @@ async def update_setu_img(): except FileNotFoundError: logger.warning(f"文件 {image.local_id}.jpg 不存在,跳过...") continue - img_hash = str( - get_img_hash( - f"{path}/{image.local_id}.jpg" - ) - ) - await Setu.update_setu_data( - image.pid, img_hash=img_hash - ) + img_hash = str(get_img_hash(f"{path}/{image.local_id}.jpg")) + await Setu.update_setu_data(image.pid, img_hash=img_hash) except Exception as e: _success -= 1 logger.error(f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}") if type(e) not in error_type: error_type.append(type(e)) - error_info.append( - f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}" - ) + error_info.append(f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}") else: - logger.info(f'更新色图 {image.local_id}.jpg 已存在') - error_info = ['无报错..'] if not error_info else error_info - if count or _success or (error_info and "无报错.." not in error_info): + logger.info(f"更新色图 {image.local_id}.jpg 已存在") + error_info = ["无报错.."] if not error_info else error_info + if count or _success or error_info: await get_bot().send_private_msg( user_id=int(list(get_bot().config.superusers)[0]), - message=f'{str(datetime.now()).split(".")[0]} 更新 色图 完成,本地存在 {count} 张,实际更新 {_success} 张,以下为更新时未知错误:\n' - + "\n".join(error_info), + message=f'{str(datetime.now()).split(".")[0]} 更新 色图 完成,本地存在 {count} 张,实际更新 {_success} 张,' + f"以下为更新时未知错误:\n" + "\n".join(error_info), ) - - diff --git a/plugins/shop/buy.py b/plugins/shop/buy.py index 7518ccc6..cce978f6 100755 --- a/plugins/shop/buy.py +++ b/plugins/shop/buy.py @@ -43,10 +43,10 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): msg = get_message_text(event.json()).strip().split(" ") num = 1 if len(msg) > 1: - if is_number(msg[1]): + if is_number(msg[1]) and int(msg[1]) > 0: num = int(msg[1]) else: - await buy.finish("购买的数量要是数字!", at_sender=True) + await buy.finish("购买的数量要是数字且大于0!", at_sender=True) # print(msg, num) if is_number(msg[0]): msg = int(msg[0]) diff --git a/plugins/word_bank/message_handle.py b/plugins/word_bank/message_handle.py index 117e461e..dd1ba97a 100644 --- a/plugins/word_bank/message_handle.py +++ b/plugins/word_bank/message_handle.py @@ -19,17 +19,23 @@ data_dir = Path(DATA_PATH) / "word_bank" data_dir.mkdir(parents=True, exist_ok=True) -message_handle = on_message(priority=7, block=True, rule=check) +message_handle = on_message(priority=5, block=True, rule=check) @message_handle.handle() async def _(bot: Bot, event: GroupMessageEvent, state: T_State): path = data_dir / f"{event.group_id}" - q = await WordBank.check(event.group_id, get_message_text(event.json())) - placeholder_list = [ - (x.split("<_s>")[0], x.split("<_s>")[1]) - for x in q.format.split("")[:-1] - ] if q.format else [] + q = await WordBank.check( + event.group_id, get_message_text(event.json()), event.is_tome() + ) + placeholder_list = ( + [ + (x.split("<_s>")[0], x.split("<_s>")[1]) + for x in q.format.split("")[:-1] + ] + if q.format + else [] + ) answer = "" _a = q.answer if not placeholder_list: @@ -37,8 +43,10 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): else: for idx, placeholder in placeholder_list: if placeholder.endswith("jpg"): - answer += _a[:_a.find(f"[__placeholder_{idx}]")] + image(path / placeholder) + answer += _a[: _a.find(f"[__placeholder_{idx}]")] + image( + path / placeholder + ) else: - answer += _a[:_a.find(f"[__placeholder_{idx}]")] + at(placeholder) - _a = _a[_a.find(f"[__placeholder_{idx}]") + len(f"[__placeholder_{idx}]"):] + answer += _a[: _a.find(f"[__placeholder_{idx}]")] + at(placeholder) + _a = _a[_a.find(f"[__placeholder_{idx}]") + len(f"[__placeholder_{idx}]") :] await message_handle.send(answer) diff --git a/plugins/word_bank/model.py b/plugins/word_bank/model.py index b4d2e265..34bc0e40 100644 --- a/plugins/word_bank/model.py +++ b/plugins/word_bank/model.py @@ -3,6 +3,7 @@ from typing import Optional, List, Union, Tuple from datetime import datetime from pathlib import Path from configs.path_config import DATA_PATH +import re import random @@ -97,18 +98,39 @@ class WordBank(db.Model): q = await cls.query.where(cls.group_id == group_id).gino.all() q = [x.problem for x in q] q.sort() - return list(set(q)) + _tmp = [] + for problem in q: + if "[_to_me" in problem: + r = re.search(r"\[_to_me\|(.*?)](.*)", problem) + if r: + bot_name = r.group(1) + problem = problem.replace(f"[_to_me|{bot_name}]", bot_name) + _tmp.append(problem) + return list(set(_tmp)) @classmethod - async def check(cls, group_id: int, problem: str) -> Optional["WordBank"]: + async def check(cls, group_id: int, problem: str, is_tome: bool = False) -> Optional["WordBank"]: """ 检测词条并随机返回 :param group_id: 群号 :param problem: 问题 + :param is_tome:是否at真寻 """ - q = await cls.query.where( - (cls.group_id == group_id) & (cls.problem == problem) - ).gino.all() + if is_tome: + q = await cls.query.where( + (cls.group_id == group_id) + ).gino.all() + q = [x for x in q if "[_to_me" in x.problem] + if q: + for x in q: + r = re.search(r"\[_to_me\|(.*?)](.*)", x.problem) + if r and r.group(2) == problem: + return x + return None + else: + q = await cls.query.where( + (cls.group_id == group_id) & (cls.problem == problem) + ).gino.all() return random.choice(q) if q else None @classmethod diff --git a/plugins/word_bank/rule.py b/plugins/word_bank/rule.py index b93a9e89..9fa352c4 100644 --- a/plugins/word_bank/rule.py +++ b/plugins/word_bank/rule.py @@ -7,6 +7,6 @@ from .model import WordBank async def check(bot: Bot, event: Event, state: T_State) -> bool: if isinstance(event, GroupMessageEvent): return bool( - await WordBank.check(event.group_id, get_message_text(event.json())) + await WordBank.check(event.group_id, get_message_text(event.json()), event.is_tome()) ) return False diff --git a/plugins/word_bank/word_hanlde.py b/plugins/word_bank/word_hanlde.py index 2ef837b2..881209fa 100644 --- a/plugins/word_bank/word_hanlde.py +++ b/plugins/word_bank/word_hanlde.py @@ -67,7 +67,13 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): if not answer: await add_word.finish("未检测到词条回答...") idx = 0 - _builder = WordBankBuilder(event.user_id, event.group_id, problem) + for n in bot.config.nickname: + if problem.startswith(n): + _problem = f"[_to_me|{n}]" + problem[len(n):] + break + else: + _problem = problem + _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) if r: diff --git a/services/__init__.py b/services/__init__.py old mode 100644 new mode 100755 index aae2c093..8bbd77c0 --- a/services/__init__.py +++ b/services/__init__.py @@ -1,2 +1,2 @@ -from .db_context import * -from .log import * +from .db_context import * +from .log import * diff --git a/services/db_context.py b/services/db_context.py old mode 100644 new mode 100755 index 0911a4bb..40891e18 --- a/services/db_context.py +++ b/services/db_context.py @@ -1,25 +1,25 @@ - -from gino import Gino -from .log import logger -from configs.config import bind, sql_name, user, password, address, port, database - - -# 全局数据库连接对象 -db = Gino() - - -async def init(): - i_bind = bind - if not i_bind: - i_bind = f"{sql_name}://{user}:{password}@{address}:{port}/{database}" - try: - await db.set_bind(i_bind) - await db.gino.create_all() - logger.info(f'Database loaded successfully!') - except Exception as e: - raise Exception(f'数据库连接错误.... e: {e}') - - -async def disconnect(): - await db.pop_bind().close() - + +from gino import Gino +from .log import logger +from configs.config import bind, sql_name, user, password, address, port, database + + +# 全局数据库连接对象 +db = Gino() + + +async def init(): + i_bind = bind + if not i_bind: + i_bind = f"{sql_name}://{user}:{password}@{address}:{port}/{database}" + try: + await db.set_bind(i_bind) + await db.gino.create_all() + logger.info(f'Database loaded successfully!') + except Exception as e: + raise Exception(f'数据库连接错误.... e: {e}') + + +async def disconnect(): + await db.pop_bind().close() + diff --git a/services/log.py b/services/log.py old mode 100644 new mode 100755 diff --git a/update_info.json b/update_info.json index 826a619d..3b5a617c 100644 --- a/update_info.json +++ b/update_info.json @@ -4,8 +4,9 @@ "models", "basic_plugins", "utils", - "services" + "services", + "configs" ], "add_file": [], "delete_file": [] -} +} \ No newline at end of file diff --git a/utils/http_utils.py b/utils/http_utils.py index 9140d743..738ca2c6 100644 --- a/utils/http_utils.py +++ b/utils/http_utils.py @@ -8,7 +8,9 @@ from asyncio.exceptions import TimeoutError from nonebot.adapters.cqhttp import MessageSegment from playwright.async_api import Page from .message_builder import image +from httpx import ConnectTimeout from .browser import get_browser +from retrying import retry import asyncio import aiofiles import httpx @@ -19,6 +21,7 @@ class AsyncHttpx: proxy = {"http://": get_local_proxy()} @classmethod + @retry(stop_max_attempt_number=3) async def get( cls, url: str, @@ -149,7 +152,7 @@ class AsyncHttpx: await wf.write(content) logger.info(f"下载图片 {url} 成功.. Path:{path.absolute()}") return True - except TimeoutError: + except (TimeoutError, ConnectTimeout): pass else: logger.error(f"下载图片 {url} 下载超时.. Path:{path.absolute()}") @@ -312,6 +315,7 @@ class AsyncPlaywright: return image(path) except Exception as e: logger.warning(f"Playwright 截图 url:{url} element:{element} 发生错误 {type(e)}:{e}") + finally: if page: await page.close() return None diff --git a/utils/manager/__init__.py b/utils/manager/__init__.py index 15ab6c27..02b8ba5d 100755 --- a/utils/manager/__init__.py +++ b/utils/manager/__init__.py @@ -13,10 +13,7 @@ from .admin_manager import AdminManager from .none_plugin_count_manager import NonePluginCountManager from .requests_manager import RequestManager from configs.path_config import DATA_PATH -from nonebot import Driver -import nonebot -driver: Driver = nonebot.get_driver() # 群功能开关 | 群被动技能 | 群权限 管理 group_manager: Optional[GroupManager] = GroupManager( @@ -69,4 +66,3 @@ requests_manager: Optional[RequestManager] = RequestManager( # 管理员命令管理器 admin_manager = AdminManager() - diff --git a/utils/manager/group_manager.py b/utils/manager/group_manager.py index 53c6f579..332be9fb 100755 --- a/utils/manager/group_manager.py +++ b/utils/manager/group_manager.py @@ -299,4 +299,3 @@ class GroupManager(StaticData): del self._data["super"]["close_plugins"] return _x return None -