diff --git a/LICENSE b/LICENSE
index f288702d..0ad25db4 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
@@ -7,17 +7,15 @@
Preamble
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
+our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
+software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
@@ -26,44 +24,34 @@ them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
The precise terms and conditions for copying, distribution and
modification follow.
@@ -72,7 +60,7 @@ modification follow.
0. Definitions.
- "This License" refers to version 3 of the GNU General Public License.
+ "This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
@@ -549,35 +537,45 @@ to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
- 13. Use with the GNU Affero General Public License.
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
+under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
+Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
+GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
+versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
@@ -635,40 +633,29 @@ the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ GNU Affero General Public License for more details.
- You should have received a copy of the GNU General Public License
+ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- Copyright (C)
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
+For more information on this, and how to apply and follow the GNU AGPL, see
.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-.
diff --git a/README.md b/README.md
index 5fe1b495..9cf49d43 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,10 @@
## 声明
此项目仅用于学习交流,请勿用于非法用途
+## 未完成的文档
+
+[传送门](https://hibikier.github.io/zhenxun_bot/)
+
## 真寻的帮助
请对真寻说: '真寻帮助' or '管理员帮助' or '超级用户帮助' or '真寻帮助 指令'
@@ -313,6 +317,58 @@ python bot.py
## 更新
+### 2021/11/10
+
+* 修复PIX表重复创建导致首次无法运行
+* 检测Omage图库改为命令方式:检测omega图库
+
+### 2021/11/9
+
+* 修复管理员帮助无法正常响应
+* 修复被ban时会一直回复被ban提醒
+
+### 2021/11/5
+
+* 修复ai没有图灵key时报错
+* 提供图片路径resource/img/background/check
+
+### 2021/11/4
+
+* 通用排行榜改用图片消息,且可以自定义排行榜人数
+* 优化CreateMat排行榜数据显示
+* 修复了pix更新多余参数导致失败的问题
+* 修复滴滴滴-注入风险
+* 修复无法正常关闭滴滴滴,戳一戳
+* 添加了发送图片撤回配置项WITHDRAW_IMAGE_TIME
+* 修复了天气regex文本过长时会正则匹配过久导致nb卡顿
+* message_build新增custom_forward_msg用于快捷生成转发消息
+* 插件配置改为yaml存储,新增Config,用于获取和新增插件配置
+* 新增 当插件加载失败时,会发送消息提醒超级用户,且在功能状态中对应失败插件写上[ERROR]
+* 修复当查看-spuer插件帮助时无法正确回复
+* 群内帮助图片会随群内功能开关和插件总开关变化
+* 自检改为图像形式
+* 更新色图删除了rar_setu,r18_rar和rar文件夹,压缩将统一在temp文件夹
+* 更新色图只有在有更新数量或报错时才会提醒超级用户
+* 群欢迎消息加入cd
+* 加入资源管理resources_manager
+* 新增 好友请求/群聊邀请 控制命令
+
+### 2021/10/15
+
+* 适配了原神资源查询米游社地图返回的新格式
+
+### 2021/10/8
+
+* 修复疫情省份查询失效
+* 修复功能调用统计全局下统计可能发生错误
+
+### 2021/10/4
+
+* 修复了功能调用统计失效问题
+* 当色图库中没有色图时,会在线搜索色图而不是‘没找到符合条件的色图...’
+* 快速更新权限再给超级用户发送错误日志
+* 修复疫情未加载省份城市无法正常使用
+
### 2021/10/3
* 对插件进行分离
@@ -333,8 +389,9 @@ python bot.py
* 当群权限为-1时,不会对群发送修改权限通知,并屏蔽此群一切命令(包括提醒)
* 修复了红包数量可以过大或为负数,红包数量大于群员数量时会修改为群员数量
* 修复了负数开箱
-* 签到最低好感度设置为0.01 [pull/53](https://github.com/HibiKier/zhenxun_bot/pull/53)
+* 签到最低好感度设置为0.01 [@pull/53](https://github.com/HibiKier/zhenxun_bot/pull/53)
* pip安装新依赖 ruamel.yaml
+* 修复功能 EPIC [@pull/58](https://github.com/HibiKier/zhenxun_bot/pull/58)
### 2021/9/10
@@ -358,7 +415,7 @@ python bot.py
* 修改 更新信息 图片大小
* 修复 查看订阅 命令 UP和番剧无法正常显示
* 修复订阅推送无法正确推送
-* 修复搜图返回列表为空时无法正确回复 @[pull/40](https://github.com/HibiKier/zhenxun_bot/pull/40)
+* 修复搜图返回列表为空时无法正确回复 [@pull/40](https://github.com/HibiKier/zhenxun_bot/pull/40)
### 2021/9/5
* 添加配置PIX_IMAGE_SIZE,调整PIX下载图片大小,当设置的图片404时,改为原图
diff --git a/__version__ b/__version__
index a244d235..4ac81ba1 100644
--- a/__version__
+++ b/__version__
@@ -1 +1 @@
-__version__: v0.0.5.0
+__version__: v0.0.6.1
diff --git a/admin_manager.py b/admin_manager.py
deleted file mode 100644
index c050ad16..00000000
--- a/admin_manager.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from typing import Optional, Dict
-from .data_class import StaticData
-from utils.utils import FreqLimiter
-from services.log import logger
-from pathlib import Path
-
-
-class AdminManager(StaticData):
- """
- 管理员命令 管理器
- """
-
- def __init__(self):
- super().__init__(None)
-
- def add_admin_command(self, plugin: str, level: int):
- """
- 添加一个管理员命令
- :param plugin: 模块名
- :param level: 权限等级
- """
- self._data[plugin] = level
-
- def remove_admin_command(self, plugin: str):
- """
- 删除一个管理员命令
- :param plugin: 模块名
- """
- if plugin in self._data.keys():
- del self._data[plugin]
-
- def check(self, plugin: str, level: int) -> bool:
- """
- 检查是否满足权限
- :param plugin: 模块名
- :param level: 权限等级
- """
- if plugin in self._data.keys():
- return level >= self._data[plugin]
- return True
-
- def get_plugin_level(self, plugin: str) -> int:
- """
- 获取插件等级
- :param plugin: 模块名
- """
- if plugin in self._data.keys():
- return self._data[plugin]
- return 0
-
-
diff --git a/basic_plugins/__init__.py b/basic_plugins/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/basic_plugins/admin_bot_manage/__init__.py b/basic_plugins/admin_bot_manage/__init__.py
new file mode 100644
index 00000000..0449b3f4
--- /dev/null
+++ b/basic_plugins/admin_bot_manage/__init__.py
@@ -0,0 +1,30 @@
+from configs.config import Config
+import nonebot
+
+
+Config.add_plugin_config(
+ "admin_bot_manage:custom_welcome_message",
+ "SET_GROUP_WELCOME_MESSAGE_LEVEL",
+ 2,
+ name="群管理员操作",
+ help_="设置群欢迎消息权限",
+ default_value=2,
+)
+
+Config.add_plugin_config(
+ "admin_bot_manage:switch_rule",
+ "CHANGE_GROUP_SWITCH_LEVEL [LEVEL]",
+ 2,
+ help_="开关群功能权限",
+ default_value=2,
+)
+
+Config.add_plugin_config(
+ "admin_bot_manage",
+ "ADMIN_DEFAULT_AUTH",
+ 5,
+ help_="默认群管理员权限",
+ default_value=5
+)
+
+nonebot.load_plugins("basic_plugins/admin_bot_manage")
diff --git a/plugins/admin_config.py b/basic_plugins/admin_bot_manage/admin_config.py
similarity index 69%
rename from plugins/admin_config.py
rename to basic_plugins/admin_bot_manage/admin_config.py
index 82a750e6..bd34b3d5 100644
--- a/plugins/admin_config.py
+++ b/basic_plugins/admin_bot_manage/admin_config.py
@@ -1,31 +1,38 @@
-from nonebot import on_notice
-from services.log import logger
-from nonebot.adapters.cqhttp import Bot, GroupAdminNoticeEvent
-from nonebot.typing import T_State
-from models.level_user import LevelUser
-from models.group_member_info import GroupInfoUser
-from configs.config import ADMIN_DEFAULT_AUTH
-
-
-__zx_plugin_name__ = "群管理员变动监测 [Hidden]"
-__plugin_version__ = 0.1
-__plugin_author__ = "HibiKier"
-
-
-admin_notice = on_notice(priority=5)
-
-
-@admin_notice.handle()
-async def _(bot: Bot, event: GroupAdminNoticeEvent, state: T_State):
- try:
- nickname = (
- await GroupInfoUser.get_member_info(event.user_id, event.group_id)
- ).user_name
- except AttributeError:
- nickname = event.user_id
- if event.sub_type == "set":
- await LevelUser.set_level(event.user_id, event.group_id, ADMIN_DEFAULT_AUTH)
- logger.info(f"为新晋管理员 {nickname}({event.user_id}) 添加权限等级:{ADMIN_DEFAULT_AUTH}")
- elif event.sub_type == "unset":
- await LevelUser.delete_level(event.user_id, event.group_id)
- logger.info(f"将非管理员 {nickname}({event.user_id}) 取消权限等级")
+from nonebot import on_notice
+from services.log import logger
+from nonebot.adapters.cqhttp import Bot, GroupAdminNoticeEvent
+from nonebot.typing import T_State
+from models.level_user import LevelUser
+from models.group_member_info import GroupInfoUser
+from configs.config import Config
+
+
+__zx_plugin_name__ = "群管理员变动监测 [Hidden]"
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+
+
+admin_notice = on_notice(priority=5)
+
+
+@admin_notice.handle()
+async def _(bot: Bot, event: GroupAdminNoticeEvent, state: T_State):
+ try:
+ nickname = (
+ await GroupInfoUser.get_member_info(event.user_id, event.group_id)
+ ).user_name
+ except AttributeError:
+ nickname = event.user_id
+ if event.sub_type == "set":
+ await LevelUser.set_level(
+ event.user_id,
+ event.group_id,
+ Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"),
+ )
+ logger.info(
+ f"为新晋管理员 {nickname}({event.user_id}) "
+ f"添加权限等级:{Config.get_config('admin_bot_manage', 'ADMIN_DEFAULT_AUTH')}"
+ )
+ elif event.sub_type == "unset":
+ await LevelUser.delete_level(event.user_id, event.group_id)
+ logger.info(f"将非管理员 {nickname}({event.user_id}) 取消权限等级")
diff --git a/plugins/admin_bot_manage/custom_welcome_message.py b/basic_plugins/admin_bot_manage/custom_welcome_message.py
similarity index 93%
rename from plugins/admin_bot_manage/custom_welcome_message.py
rename to basic_plugins/admin_bot_manage/custom_welcome_message.py
index 1a570c2e..6eca8539 100644
--- a/plugins/admin_bot_manage/custom_welcome_message.py
+++ b/basic_plugins/admin_bot_manage/custom_welcome_message.py
@@ -4,7 +4,7 @@ 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 configs.config import OC_LEVEL
+from configs.config import Config
from services.log import logger
@@ -22,7 +22,7 @@ __plugin_cmd__ = ['自定义群欢迎消息 ?[文本] ?[图片]']
__plugin_version__ = 0.1
__plugin_author__ = 'HibiKier'
__plugin_settings__ = {
- "admin_level": OC_LEVEL,
+ "admin_level": Config.get_config("admin_bot_manage", "SET_GROUP_WELCOME_MESSAGE_LEVEL"),
}
custom_welcome = on_command(
diff --git a/plugins/admin_bot_manage/data_source.py b/basic_plugins/admin_bot_manage/data_source.py
similarity index 84%
rename from plugins/admin_bot_manage/data_source.py
rename to basic_plugins/admin_bot_manage/data_source.py
index a6edb684..e0954eaa 100644
--- a/plugins/admin_bot_manage/data_source.py
+++ b/basic_plugins/admin_bot_manage/data_source.py
@@ -1,272 +1,296 @@
-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 ADMIN_DEFAULT_AUTH
-from utils.manager import group_manager, plugins2settings_manager
-from utils.image_utils import CreateImg
-import aiofiles
-import aiohttp
-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:
- async with aiohttp.ClientSession() as session:
- async with session.get(img, proxy=get_local_proxy()) as response:
- async with aiofiles.open(
- DATA_PATH + f"custom_welcome_msg/{group_id}.jpg", "wb"
- ) as f:
- await f.write(await response.read())
- 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)
- 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()
- 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 == "开启":
- group_manager.unblock_plugin(module)
- else:
- group_manager.block_plugin(module, block_type=block_type)
-
-
-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 plugins2settings_manager.get_data():
- flag = group_manager.get_plugin_block_type(module)
- flag = flag.upper() + " CLOSE" if flag else "OPEN"
- try:
- rst += f'{plugins2settings_manager.get(module)["cmd"][0]}\n'
- except IndexError:
- rst += f"{module}\n"
- flag_str += f"{flag}\n"
- height = len(rst.split("\n")) * 24
- a = CreateImg(150, height, font_size=20)
- a.text((10, 10), rst)
- b = CreateImg(200, height, font_size=20)
- b.text((10, 10), flag_str)
- A = CreateImg(380, height)
- A.paste(a)
- A.paste(b, (150, 0))
- return image(b64=A.pic2bs4())
-
-
-async def update_member_info(group_id: int) -> bool:
- """
- 更新群成员信息
- :param group_id: 群号
- """
- 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"], 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:
- 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
+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 CreateImg
+import aiofiles
+import aiohttp
+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:
+ async with aiohttp.ClientSession() as session:
+ async with session.get(img, proxy=get_local_proxy()) as response:
+ async with aiofiles.open(
+ DATA_PATH + f"custom_welcome_msg/{group_id}.jpg", "wb"
+ ) as f:
+ await f.write(await response.read())
+ 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)
+ 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 = CreateImg(250, height, font_size=20)
+ a.text((10, 10), rst)
+ b = CreateImg(200, height, font_size=20)
+ b.text((10, 10), flag_str)
+ A = CreateImg(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
diff --git a/plugins/admin_bot_manage/rule.py b/basic_plugins/admin_bot_manage/rule.py
similarity index 100%
rename from plugins/admin_bot_manage/rule.py
rename to basic_plugins/admin_bot_manage/rule.py
diff --git a/plugins/admin_bot_manage/switch_rule.py b/basic_plugins/admin_bot_manage/switch_rule.py
similarity index 95%
rename from plugins/admin_bot_manage/switch_rule.py
rename to basic_plugins/admin_bot_manage/switch_rule.py
index 2f2a5b84..fee7660b 100644
--- a/plugins/admin_bot_manage/switch_rule.py
+++ b/basic_plugins/admin_bot_manage/switch_rule.py
@@ -8,7 +8,7 @@ from .data_source import (
group_current_status,
)
from services.log import logger
-from configs.config import NICKNAME, OC_LEVEL
+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
@@ -47,7 +47,8 @@ __plugin_cmd__ = [
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
- "admin_level": OC_LEVEL,
+ "admin_level": Config.get_config("admin_bot_manage", "CHANGE_GROUP_SWITCH_LEVEL"),
+ "cmd": ["开启功能", "关闭功能", "开关"]
}
switch_rule_matcher = on_message(rule=switch_rule, priority=4, block=True)
diff --git a/plugins/admin_bot_manage/timing_task.py b/basic_plugins/admin_bot_manage/timing_task.py
similarity index 86%
rename from plugins/admin_bot_manage/timing_task.py
rename to basic_plugins/admin_bot_manage/timing_task.py
index 598ab7ea..5bb1aadd 100644
--- a/plugins/admin_bot_manage/timing_task.py
+++ b/basic_plugins/admin_bot_manage/timing_task.py
@@ -2,7 +2,7 @@ from utils.utils import scheduler, get_bot
from .data_source import update_member_info
from services.log import logger
from models.group_info import GroupInfo
-from asyncpg.exceptions import ConnectionDoesNotExistError
+from asyncpg.exceptions import ConnectionDoesNotExistError, UndefinedColumnError
__zx_plugin_name__ = '管理方面定时任务 [Hidden]'
@@ -45,7 +45,7 @@ async def _():
all_group = [x.group_id for x in await GroupInfo.get_all_group()]
for g in gl:
if g not in all_group:
- await update_member_info(g)
+ await update_member_info(g, False)
logger.info(f"快速更新群信息以及权限:{g}")
- except (IndexError, ConnectionDoesNotExistError):
+ except (IndexError, ConnectionDoesNotExistError, UndefinedColumnError):
pass
diff --git a/plugins/admin_bot_manage/update_group_member_info.py b/basic_plugins/admin_bot_manage/update_group_member_info.py
similarity index 100%
rename from plugins/admin_bot_manage/update_group_member_info.py
rename to basic_plugins/admin_bot_manage/update_group_member_info.py
diff --git a/plugins/admin_help/__init__.py b/basic_plugins/admin_help/__init__.py
similarity index 96%
rename from plugins/admin_help/__init__.py
rename to basic_plugins/admin_help/__init__.py
index 0b110162..1262eb22 100644
--- a/plugins/admin_help/__init__.py
+++ b/basic_plugins/admin_help/__init__.py
@@ -1,27 +1,27 @@
-from nonebot import on_command
-from nonebot.typing import T_State
-from nonebot.adapters import Bot
-from nonebot.adapters.cqhttp import GroupMessageEvent
-from utils.message_builder import image
-from .data_source import create_help_image, admin_help_image
-
-
-__zx_plugin_name__ = '管理帮助 [Admin]'
-__plugin_usage__ = '管理员帮助,在群内回复“管理员帮助”'
-__plugin_version__ = 0.1
-__plugin_author__ = 'HibiKier'
-__plugin_settings__ = {
- "admin_level": 1,
-}
-
-admin_help = on_command("管理员帮助", aliases={"管理帮助"}, priority=5, block=True)
-
-if admin_help_image.exists():
- admin_help_image.unlink()
-
-
-@admin_help.handle()
-async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
- if not admin_help_image.exists():
- await create_help_image()
- await admin_help.send(image('admin_help_img.png'))
+from nonebot import on_command
+from nonebot.typing import T_State
+from nonebot.adapters import Bot
+from nonebot.adapters.cqhttp import GroupMessageEvent
+from utils.message_builder import image
+from .data_source import create_help_image, admin_help_image
+
+
+__zx_plugin_name__ = '管理帮助 [Admin]'
+__plugin_usage__ = '管理员帮助,在群内回复“管理员帮助”'
+__plugin_version__ = 0.1
+__plugin_author__ = 'HibiKier'
+__plugin_settings__ = {
+ "admin_level": 1,
+}
+
+admin_help = on_command("管理员帮助", aliases={"管理帮助"}, priority=5, block=True)
+
+if admin_help_image.exists():
+ admin_help_image.unlink()
+
+
+@admin_help.handle()
+async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
+ if not admin_help_image.exists():
+ await create_help_image()
+ await admin_help.send(image('admin_help_img.png'))
diff --git a/plugins/admin_help/data_source.py b/basic_plugins/admin_help/data_source.py
similarity index 97%
rename from plugins/admin_help/data_source.py
rename to basic_plugins/admin_help/data_source.py
index 48d87832..9d8959dc 100644
--- a/plugins/admin_help/data_source.py
+++ b/basic_plugins/admin_help/data_source.py
@@ -18,13 +18,16 @@ admin_help_image = Path(IMAGE_PATH) / 'admin_help_img.png'
@driver.on_bot_connect
-async def create_help_image(bot: Bot = None):
- """
- 创建管理员帮助图片
- """
+async def init_task(bot: Bot = None):
if not group_manager.get_task_data():
await group_manager.init_group_task()
logger.info(f'已成功加载 {len(group_manager.get_task_data())} 个被动技能.')
+
+
+async def create_help_image():
+ """
+ 创建管理员帮助图片
+ """
await asyncio.get_event_loop().run_in_executor(
None, _create_help_image
)
diff --git a/plugins/group_apscheduler/__init__.py b/basic_plugins/apscheduler/__init__.py
similarity index 98%
rename from plugins/group_apscheduler/__init__.py
rename to basic_plugins/apscheduler/__init__.py
index 3f0b6168..5eb8463b 100644
--- a/plugins/group_apscheduler/__init__.py
+++ b/basic_plugins/apscheduler/__init__.py
@@ -8,7 +8,7 @@ from nonebot.adapters.cqhttp.exception import ActionFailed
from configs.config import NICKNAME
from utils.manager import group_manager
-__zx_plugin_name__ = "群定时任务相关 [Hidden]"
+__zx_plugin_name__ = "定时任务相关 [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {'zwa': '早晚安'}
@@ -106,7 +106,7 @@ async def _():
logger.error(f"自动更新群组信息错误 e:{e}")
-# 一次性任务
+ # 一次性任务
# 固定时间触发,仅触发一次:
#
# from datetime import datetime
diff --git a/plugins/auto_invite/__init__.py b/basic_plugins/auto_invite/__init__.py
similarity index 53%
rename from plugins/auto_invite/__init__.py
rename to basic_plugins/auto_invite/__init__.py
index 74009e7d..6133f283 100644
--- a/plugins/auto_invite/__init__.py
+++ b/basic_plugins/auto_invite/__init__.py
@@ -1,87 +1,150 @@
-from nonebot import on_request
-from nonebot.adapters.cqhttp import Bot, FriendRequestEvent, GroupRequestEvent
-from models.friend_user import FriendUser
-from datetime import datetime
-from configs.config import AUTO_ADD_FRIEND, NICKNAME
-from nonebot.adapters.cqhttp.exception import ActionFailed
-from utils.utils import scheduler
-import time
-
-__zx_plugin_name__ = "好友群聊处理请求 [Hidden]"
-__plugin_version__ = 0.1
-__plugin_author__ = 'HibiKier'
-
-friend_req = on_request(priority=5)
-
-
-exists_data = {"private": {}, "group": {}}
-
-
-@friend_req.handle()
-async def _(bot: Bot, event: FriendRequestEvent, state: dict):
- global exists_data
- if exists_data["private"].get(event.user_id):
- if time.time() - exists_data["private"][event.user_id] < 60 * 5:
- return
- exists_data["private"][event.user_id] = time.time()
- user = await bot.get_stranger_info(user_id=event.user_id)
- nickname = user["nickname"]
- await bot.send_private_msg(
- user_id=int(list(bot.config.superusers)[0]),
- message=f"*****一份好友申请*****\n"
- f"昵称:{nickname}({event.user_id})\n"
- f"自动同意:{'√' if AUTO_ADD_FRIEND else '×'}\n"
- f"日期:{str(datetime.now()).split('.')[0]}\n"
- f"备注:{event.comment}",
- )
- if AUTO_ADD_FRIEND:
- await bot.set_friend_add_request(flag=event.flag, approve=True)
- await FriendUser.add_friend_info(user["user_id"], user["nickname"])
-
-
-group_req = on_request(priority=5, block=True)
-
-
-@group_req.handle()
-async def _(bot: Bot, event: GroupRequestEvent, state: dict):
- global exists_data
- if event.sub_type == "invite":
- if str(event.user_id) in bot.config.superusers:
- try:
- await bot.set_group_add_request(
- flag=event.flag, sub_type="invite", approve=True
- )
- except ActionFailed:
- pass
- else:
- if exists_data["group"].get(f"{event.user_id}:{event.group_id}"):
- if (
- time.time()
- - exists_data["group"][f"{event.user_id}:{event.group_id}"]
- < 60 * 5
- ):
- return
- exists_data["group"][f"{event.user_id}:{event.group_id}"] = time.time()
- nickname = await FriendUser.get_user_name(event.user_id)
- await bot.send_private_msg(
- user_id=int(list(bot.config.superusers)[0]),
- message=f"*****一份入群申请*****\n"
- f"申请人:{nickname}({event.user_id})\n"
- f"群聊:{event.group_id}\n"
- f"邀请日期:{str(datetime.now()).split('.')[0]}",
- )
- await bot.send_private_msg(
- user_id=event.user_id,
- message=f"想要邀请我偷偷入群嘛~已经提醒{NICKNAME}的管理员大人了\n"
- "请确保已经群主或群管理沟通过!\n"
- "等待管理员处理吧!",
- )
-
-
-@scheduler.scheduled_job(
- "interval",
- minutes=5,
-)
-async def _():
- global exists_data
- exists_data = {"private": {}, "group": {}}
+from nonebot import on_request, on_message
+from nonebot.adapters.cqhttp import (
+ Bot,
+ FriendRequestEvent,
+ GroupRequestEvent,
+ MessageEvent,
+)
+from models.friend_user import FriendUser
+from datetime import datetime
+from configs.config import NICKNAME, Config
+from nonebot.adapters.cqhttp.exception import ActionFailed
+from utils.manager import requests_manager
+from models.group_info import GroupInfo
+from utils.utils import scheduler
+import asyncio
+import time
+import re
+
+__zx_plugin_name__ = "好友群聊处理请求 [Hidden]"
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+__plugin_configs__ = {
+ "AUTO_ADD_FRIEND": {"value": False, "help": "是否自动同意好友添加", "default_value": False}
+}
+
+friend_req = on_request(priority=5, block=True)
+group_req = on_request(priority=5, block=True)
+x = on_message(priority=9, block=False)
+
+exists_data = {"private": {}, "group": {}}
+
+
+@friend_req.handle()
+async def _(bot: Bot, event: FriendRequestEvent, state: dict):
+ print(event)
+ global exists_data
+ if exists_data["private"].get(event.user_id):
+ if time.time() - exists_data["private"][event.user_id] < 60 * 5:
+ return
+ exists_data["private"][event.user_id] = time.time()
+ user = await bot.get_stranger_info(user_id=event.user_id)
+ nickname = user["nickname"]
+ sex = user["sex"]
+ age = str(user["age"])
+ comment = event.comment
+ await bot.send_private_msg(
+ user_id=int(list(bot.config.superusers)[0]),
+ message=f"*****一份好友申请*****\n"
+ f"昵称:{nickname}({event.user_id})\n"
+ f"自动同意:{'√' if Config.get_config('auto_invite', 'AUTO_ADD_FRIEND') else '×'}\n"
+ f"日期:{str(datetime.now()).split('.')[0]}\n"
+ f"备注:{event.comment}",
+ )
+ if Config.get_config("auto_invite", "AUTO_ADD_FRIEND"):
+ await bot.set_friend_add_request(flag=event.flag, approve=True)
+ await FriendUser.add_friend_info(user["user_id"], user["nickname"])
+ else:
+ requests_manager.add_request(
+ event.user_id,
+ "private",
+ event.flag,
+ nickname=nickname,
+ sex=sex,
+ age=age,
+ comment=comment,
+ )
+
+
+@group_req.handle()
+async def _(bot: Bot, event: GroupRequestEvent, state: dict):
+ global exists_data
+ if event.sub_type == "invite":
+ if str(event.user_id) in bot.config.superusers:
+ try:
+ await bot.set_group_add_request(
+ flag=event.flag, sub_type="invite", approve=True
+ )
+ if await GroupInfo.get_group_info(event.group_id):
+ await GroupInfo.set_group_flag(event.group_id, 1)
+ else:
+ group_info = await bot.get_group_info(group_id=event.group_id)
+ await GroupInfo.add_group_info(
+ group_info["group_id"],
+ group_info["group_name"],
+ group_info["max_member_count"],
+ group_info["member_count"],
+ 1,
+ )
+ except ActionFailed:
+ pass
+ else:
+ user = await bot.get_stranger_info(user_id=event.user_id)
+ sex = user["sex"]
+ age = str(user["age"])
+ if exists_data["group"].get(f"{event.user_id}:{event.group_id}"):
+ if (
+ time.time()
+ - exists_data["group"][f"{event.user_id}:{event.group_id}"]
+ < 60 * 5
+ ):
+ return
+ exists_data["group"][f"{event.user_id}:{event.group_id}"] = time.time()
+ nickname = await FriendUser.get_user_name(event.user_id)
+ await bot.send_private_msg(
+ user_id=int(list(bot.config.superusers)[0]),
+ message=f"*****一份入群申请*****\n"
+ f"申请人:{nickname}({event.user_id})\n"
+ f"群聊:{event.group_id}\n"
+ f"邀请日期:{str(datetime.now()).split('.')[0]}",
+ )
+ await bot.send_private_msg(
+ user_id=event.user_id,
+ message=f"想要邀请我偷偷入群嘛~已经提醒{NICKNAME}的管理员大人了\n"
+ "请确保已经群主或群管理沟通过!\n"
+ "等待管理员处理吧!",
+ )
+ requests_manager.add_request(
+ event.user_id,
+ "group",
+ event.flag,
+ invite_group=event.group_id,
+ nickname=nickname,
+ sex=sex,
+ age=age,
+ )
+
+
+@x.handle()
+async def _(bot: Bot, event: MessageEvent, state: dict):
+ await asyncio.sleep(0.1)
+ r = re.search(r'groupcode="(.*?)"', str(event.get_message()))
+ if r:
+ group_id = int(r.group(1))
+ else:
+ return
+ r = re.search(r'groupname="(.*?)"', str(event.get_message()))
+ if r:
+ group_name = r.group(1)
+ else:
+ group_name = "None"
+ requests_manager.set_group_name(group_name, group_id)
+
+
+@scheduler.scheduled_job(
+ "interval",
+ minutes=5,
+)
+async def _():
+ global exists_data
+ exists_data = {"private": {}, "group": {}}
diff --git a/plugins/ban/__init__.py b/basic_plugins/ban/__init__.py
similarity index 95%
rename from plugins/ban/__init__.py
rename to basic_plugins/ban/__init__.py
index f05900b9..7592c44a 100644
--- a/plugins/ban/__init__.py
+++ b/basic_plugins/ban/__init__.py
@@ -1,189 +1,197 @@
-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
-from utils.utils import get_message_at, get_message_text, is_number
-from configs.config import NICKNAME, BAN_LEVEL
-from nonebot.permission import SUPERUSER
-from services.log import logger
-
-
-__zx_plugin_name__ = "封禁Ban用户 [Admin]"
-__plugin_usage__ = """
-usage:
- 将用户拉入或拉出黑名单
- 指令:
- .ban [at] ?[小时] ?[分钟]
- .unban
- 示例:.ban @user
- 示例:.ban @user 6
- 示例:.ban @user 3 10
- 示例:.unban @user
-""".strip()
-__plugin_superuser_usage__ = """
-usage:
- 屏蔽用户消息,相当于最上级.ban
- 指令:
- b了 [at]
- 示例:b了 @user
-""".strip()
-__plugin_des__ = '你被逮捕了!丢进小黑屋!'
-__plugin_cmd__ = ['.ban [at] ?[小时] ?[分钟]', '.unban [at]', 'b了 [at] [_superuser]']
-__plugin_version__ = 0.1
-__plugin_author__ = 'HibiKier'
-__plugin_settings__ = {
- "admin_level": BAN_LEVEL,
-}
-
-
-ban = on_command(
- ".ban",
- aliases={".unban", "/ban", "/unban"},
- priority=5,
- block=True,
-)
-
-super_ban = on_command('b了', permission=SUPERUSER, priority=5, block=True)
-
-
-@ban.handle()
-async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
- 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"]:
- 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 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}后解封"
- 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 ban.finish(
- f"ban掉 {user_name} 的管理员权限比您高,无法进行unban", at_sender=True
- )
- if await BanUser.unban(qq):
- logger.info(
- f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 解禁"
- )
- result = f"已经把 {user_name} 从黑名单中删除了!"
- else:
- result = f"{user_name} 不在黑名单!"
- else:
- await ban.finish("艾特人了吗??", at_sender=True)
- await ban.finish(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)
- 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 += " 分钟"
- 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} 不在黑名单!"
- await ban.send(result)
- else:
- await ban.finish('qq号必须是数字!\n格式:.ban [qq] [hour]? [minute]?', at_sender=True)
-
-
-@super_ban.handle()
-async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
- qq = get_message_at(event.json())
- 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']
- 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的对象..')
-
+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
+from utils.utils import get_message_at, get_message_text, is_number
+from configs.config import NICKNAME, Config
+from nonebot.permission import SUPERUSER
+from services.log import logger
+
+
+__zx_plugin_name__ = "封禁Ban用户 [Admin]"
+__plugin_usage__ = """
+usage:
+ 将用户拉入或拉出黑名单
+ 指令:
+ .ban [at] ?[小时] ?[分钟]
+ .unban
+ 示例:.ban @user
+ 示例:.ban @user 6
+ 示例:.ban @user 3 10
+ 示例:.unban @user
+""".strip()
+__plugin_superuser_usage__ = """
+usage:
+ 屏蔽用户消息,相当于最上级.ban
+ 指令:
+ b了 [at]
+ 示例:b了 @user
+""".strip()
+__plugin_des__ = '你被逮捕了!丢进小黑屋!'
+__plugin_cmd__ = ['.ban [at] ?[小时] ?[分钟]', '.unban [at]', 'b了 [at] [_superuser]']
+__plugin_version__ = 0.1
+__plugin_author__ = 'HibiKier'
+__plugin_settings__ = {
+ "admin_level": Config.get_config("ban", "BAN_LEVEL"),
+ "cmd": ['.ban', '.unban', 'ban', 'unban']
+}
+__plugin_configs__ = {
+ "BAN_LEVEL [LEVEL]": {
+ "value": 5,
+ "help": "ban/unban所需要的管理员权限等级",
+ "default_value": 5
+ }
+}
+
+
+ban = on_command(
+ ".ban",
+ aliases={".unban", "/ban", "/unban"},
+ priority=5,
+ block=True,
+)
+
+super_ban = on_command('b了', permission=SUPERUSER, priority=5, block=True)
+
+
+@ban.handle()
+async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
+ 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"]:
+ 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 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}后解封"
+ 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 ban.finish(
+ f"ban掉 {user_name} 的管理员权限比您高,无法进行unban", at_sender=True
+ )
+ if await BanUser.unban(qq):
+ logger.info(
+ f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 解禁"
+ )
+ result = f"已经把 {user_name} 从黑名单中删除了!"
+ else:
+ result = f"{user_name} 不在黑名单!"
+ else:
+ await ban.finish("艾特人了吗??", at_sender=True)
+ await ban.finish(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)
+ 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 += " 分钟"
+ 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} 不在黑名单!"
+ await ban.send(result)
+ else:
+ await ban.finish('qq号必须是数字!\n格式:.ban [qq] [hour]? [minute]?', at_sender=True)
+
+
+@super_ban.handle()
+async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
+ qq = get_message_at(event.json())
+ 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']
+ 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的对象..')
+
diff --git a/plugins/broadcast/__init__.py b/basic_plugins/broadcast/__init__.py
similarity index 96%
rename from plugins/broadcast/__init__.py
rename to basic_plugins/broadcast/__init__.py
index 328d73c7..b97d2a6c 100644
--- a/plugins/broadcast/__init__.py
+++ b/basic_plugins/broadcast/__init__.py
@@ -1,59 +1,59 @@
-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_imgs
-from services.log import logger
-from utils.message_builder import image
-from utils.manager import group_manager
-
-__zx_plugin_name__ = "广播 [Superuser]"
-__plugin_usage__ = """
-usage:
- 指令:
- 广播- ?[消息] ?[图片]
- 示例:广播- 你们好!
-""".strip()
-__plugin_des__ = "昭告天下!"
-__plugin_cmd__ = ["广播-"]
-__plugin_version__ = 0.1
-__plugin_author__ = "HibiKier"
-__plugin_task__ = {"broadcast": "广播"}
-
-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_imgs(event.json())
- rst = ""
- for img in imgs:
- rst += image(img)
- sid = bot.self_id
- gl = await bot.get_group_list(self_id=sid)
- gl = [
- g["group_id"]
- for g in gl
- if await group_manager.check_group_task_status(g["group_id"], "broadcast")
- ]
- g_cnt = len(gl)
- cnt = 0
- error = ""
- x = 0.25
- for g in gl:
- cnt += 1
- if cnt / g_cnt > x:
- 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)
- logger.info(f"GROUP {g} 投递广播成功")
- except Exception as e:
- logger.error(f"GROUP {g} 投递广播失败:{type(e)}")
- error += f"GROUP {g} 投递广播失败:{type(e)}\n"
- await asyncio.sleep(0.5)
- await broadcast.send(f"已播报至 100% 的群聊")
- if error:
- await broadcast.send(f"播报时错误:{error}")
+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_imgs
+from services.log import logger
+from utils.message_builder import image
+from utils.manager import group_manager
+
+__zx_plugin_name__ = "广播 [Superuser]"
+__plugin_usage__ = """
+usage:
+ 指令:
+ 广播- ?[消息] ?[图片]
+ 示例:广播- 你们好!
+""".strip()
+__plugin_des__ = "昭告天下!"
+__plugin_cmd__ = ["广播-"]
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+__plugin_task__ = {"broadcast": "广播"}
+
+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_imgs(event.json())
+ rst = ""
+ for img in imgs:
+ rst += image(img)
+ sid = bot.self_id
+ gl = await bot.get_group_list(self_id=sid)
+ gl = [
+ g["group_id"]
+ for g in gl
+ if await group_manager.check_group_task_status(g["group_id"], "broadcast")
+ ]
+ g_cnt = len(gl)
+ cnt = 0
+ error = ""
+ x = 0.25
+ for g in gl:
+ cnt += 1
+ if cnt / g_cnt > x:
+ 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)
+ logger.info(f"GROUP {g} 投递广播成功")
+ except Exception as e:
+ logger.error(f"GROUP {g} 投递广播失败:{type(e)}")
+ error += f"GROUP {g} 投递广播失败:{type(e)}\n"
+ await asyncio.sleep(0.5)
+ await broadcast.send(f"已播报至 100% 的群聊")
+ if error:
+ await broadcast.send(f"播报时错误:{error}")
diff --git a/plugins/group_handle/__init__.py b/basic_plugins/group_handle/__init__.py
similarity index 66%
rename from plugins/group_handle/__init__.py
rename to basic_plugins/group_handle/__init__.py
index ec6c348c..d83ae817 100644
--- a/plugins/group_handle/__init__.py
+++ b/basic_plugins/group_handle/__init__.py
@@ -1,141 +1,184 @@
-from nonebot import on_notice, on_request
-from configs.path_config import IMAGE_PATH, DATA_PATH
-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 (
- Bot,
- GroupIncreaseNoticeEvent,
- GroupDecreaseNoticeEvent,
-)
-from nonebot.adapters.cqhttp.exception import ActionFailed
-from utils.manager import group_manager, plugins2settings_manager
-from models.group_info import GroupInfo
-from pathlib import Path
-import random
-import os
-
-try:
- import ujson as json
-except ModuleNotFoundError:
- import json
-
-
-__zx_plugin_name__ = "群事件处理 [Hidden]"
-__plugin_version__ = 0.1
-__plugin_author__ = "HibiKier"
-__plugin_task__ = {
- 'group_welcome': '进群欢迎',
- 'refund_group_remind': '退群提醒'
-}
-
-
-# 群员增加处理
-group_increase_handle = on_notice(priority=1, block=False)
-# 群员减少处理
-group_decrease_handle = on_notice(priority=1, block=False)
-# (群管理)加群同意请求
-add_group = on_request(priority=1, block=False)
-
-
-@group_increase_handle.handle()
-async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
- if event.user_id == int(bot.self_id):
- if event.group_id not in group_manager["group_manager"].keys():
- data = plugins2settings_manager.get_data()
- for plugin in data.keys():
- if not data[plugin]["default_status"]:
- group_manager.block_plugin(plugin, event.group_id)
- else:
- join_time = datetime.now()
- user_info = await bot.get_group_member_info(
- group_id=event.group_id, user_id=event.user_id
- )
- if await GroupInfoUser.add_member_info(
- user_info["user_id"],
- user_info["group_id"],
- user_info["nickname"],
- join_time,
- ):
- logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
- else:
- logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败")
-
- # 群欢迎消息
- if await group_manager.check_group_task_status(event.group_id, 'group_welcome'):
- msg = ""
- img = ""
- at_flag = False
- custom_welcome_msg_json = (
- Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
- )
- if custom_welcome_msg_json.exists():
- data = json.load(open(custom_welcome_msg_json, "r"))
- if data.get(str(event.group_id)):
- msg = data[str(event.group_id)]
- 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"):
- img = image(
- abspath=DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"
- )
- if msg or img:
- await group_increase_handle.send(
- "\n" + msg.strip() + img, at_sender=at_flag
- )
- else:
- await group_increase_handle.send(
- "新人快跑啊!!本群现状↓(快使用自定义!)"
- + image(random.choice(os.listdir(IMAGE_PATH + "qxz/")), "qxz")
- )
-
-
-@group_decrease_handle.handle()
-async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict):
- # 被踢出群
- if event.sub_type == "kick_me":
- group_id = event.group_id
- operator_id = event.operator_id
- try:
- operator_name = (
- await GroupInfoUser.get_member_info(event.operator_id, event.group_id)
- ).user_name
- except AttributeError:
- operator_name = "None"
- group = await GroupInfo.get_group_info(group_id)
- group_name = group.group_name if group else ""
- coffee = int(list(bot.config.superusers)[0])
- await bot.send_private_msg(
- user_id=coffee,
- message=f"****呜..一份踢出报告****\n"
- f"我被 {operator_name}({operator_id})\n"
- f"踢出了 {group_name}({group_id})\n"
- f"日期:{str(datetime.now()).split('.')[0]}",
- )
- return
- try:
- user_name = (
- await GroupInfoUser.get_member_info(event.user_id, event.group_id)
- ).user_name
- except AttributeError:
- user_name = str(event.user_id)
- if await GroupInfoUser.delete_member_info(event.user_id, event.group_id):
- 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
+from nonebot import on_notice, on_request
+from configs.path_config import IMAGE_PATH, DATA_PATH
+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 (
+ Bot,
+ GroupIncreaseNoticeEvent,
+ GroupDecreaseNoticeEvent,
+)
+from nonebot.adapters.cqhttp.exception import ActionFailed
+from utils.manager import group_manager, plugins2settings_manager, requests_manager
+from configs.config import NICKNAME
+from models.group_info import GroupInfo
+from utils.utils import FreqLimiter
+from configs.config import Config
+from pathlib import Path
+import random
+import os
+
+try:
+ import ujson as json
+except ModuleNotFoundError:
+ import json
+
+
+__zx_plugin_name__ = "群事件处理 [Hidden]"
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+__plugin_task__ = {"group_welcome": "进群欢迎", "refund_group_remind": "退群提醒"}
+Config.add_plugin_config(
+ "auto_invite", "message", f"请不要未经同意就拉{NICKNAME}入群!告辞!", help_="强制拉群后进群回复的内容.."
+)
+Config.add_plugin_config(
+ "auto_invite", "flag", True, help_="被强制拉群后是否直接退出", default_value=True
+)
+Config.add_plugin_config(
+ "auto_invite", "welcome_msg_cd", 5, help_="群欢迎消息cd", default_value=5
+)
+_flmt = FreqLimiter(Config.get_config("auto_invite", "welcome_msg_cd"))
+
+
+# 群员增加处理
+group_increase_handle = on_notice(priority=1, block=False)
+# 群员减少处理
+group_decrease_handle = on_notice(priority=1, block=False)
+# (群管理)加群同意请求
+add_group = on_request(priority=1, block=False)
+
+
+@group_increase_handle.handle()
+async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict):
+ if event.user_id == int(bot.self_id):
+ group = await GroupInfo.get_group_info(event.group_id)
+ # 群聊不存在或被强制拉群,退出该群
+ if (not group or group.group_flag == 0) and Config.get_config(
+ "auto_invite", "flag"
+ ):
+ try:
+ msg = Config.get_config("auto_invite", "message")
+ if msg:
+ await bot.send_group_msg(group_id=event.group_id, message=msg)
+ await bot.set_group_leave(group_id=event.group_id)
+ await bot.send_private_msg(
+ user_id=int(list(bot.config.superusers)[0]),
+ message=f"触发强制入群保护,已成功退出群聊 {event.group_id}..",
+ )
+ logger.info(f"强制拉群或未有群信息,退出群聊 {group} 成功")
+ requests_manager.remove_request("group", event.group_id)
+ except Exception as e:
+ logger.info(f"强制拉群或未有群信息,退出群聊 {group} 失败 e:{e}")
+ await bot.send_private_msg(
+ user_id=int(list(bot.config.superusers)[0]),
+ message=f"触发强制入群保护,退出群聊 {event.group_id} 失败..",
+ )
+ # 默认群功能开关
+ elif event.group_id not in group_manager["group_manager"].keys():
+ data = plugins2settings_manager.get_data()
+ for plugin in data.keys():
+ if not data[plugin]["default_status"]:
+ group_manager.block_plugin(plugin, event.group_id)
+ else:
+ join_time = datetime.now()
+ user_info = await bot.get_group_member_info(
+ group_id=event.group_id, user_id=event.user_id
+ )
+ if await GroupInfoUser.add_member_info(
+ user_info["user_id"],
+ user_info["group_id"],
+ user_info["nickname"],
+ join_time,
+ ):
+ logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
+ else:
+ 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):
+ _flmt.start_cd(event.group_id)
+ msg = ""
+ img = ""
+ at_flag = False
+ custom_welcome_msg_json = (
+ Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
+ )
+ if custom_welcome_msg_json.exists():
+ data = json.load(open(custom_welcome_msg_json, "r"))
+ if data.get(str(event.group_id)):
+ msg = data[str(event.group_id)]
+ 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"):
+ img = image(
+ abspath=DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"
+ )
+ if msg or img:
+ await group_increase_handle.send(
+ "\n" + msg.strip() + img, at_sender=at_flag
+ )
+ else:
+ await group_increase_handle.send(
+ "新人快跑啊!!本群现状↓(快使用自定义!)"
+ + image(random.choice(os.listdir(IMAGE_PATH + "qxz/")), "qxz")
+ )
+
+
+@group_decrease_handle.handle()
+async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict):
+ # 被踢出群
+ if event.sub_type == "kick_me":
+ group_id = event.group_id
+ operator_id = event.operator_id
+ try:
+ operator_name = (
+ await GroupInfoUser.get_member_info(event.operator_id, event.group_id)
+ ).user_name
+ except AttributeError:
+ operator_name = "None"
+ group = await GroupInfo.get_group_info(group_id)
+ group_name = group.group_name if group else ""
+ coffee = int(list(bot.config.superusers)[0])
+ await bot.send_private_msg(
+ user_id=coffee,
+ message=f"****呜..一份踢出报告****\n"
+ f"我被 {operator_name}({operator_id})\n"
+ f"踢出了 {group_name}({group_id})\n"
+ f"日期:{str(datetime.now()).split('.')[0]}",
+ )
+ return
+ if event.user_id == int(bot.self_id):
+ group_manager.delete_group(event.group_id)
+ return
+ try:
+ user_name = (
+ await GroupInfoUser.get_member_info(event.user_id, event.group_id)
+ ).user_name
+ except AttributeError:
+ user_name = str(event.user_id)
+ if await GroupInfoUser.delete_member_info(event.user_id, event.group_id):
+ 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
diff --git a/plugins/help/__init__.py b/basic_plugins/help/__init__.py
similarity index 58%
rename from plugins/help/__init__.py
rename to basic_plugins/help/__init__.py
index 6fc4deb4..da1ffd3c 100644
--- a/plugins/help/__init__.py
+++ b/basic_plugins/help/__init__.py
@@ -1,61 +1,73 @@
-from nonebot import on_command
-from nonebot.adapters.cqhttp import (
- Bot,
- MessageEvent,
-)
-from nonebot.typing import T_State
-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_img, get_plugin_help
-from utils.utils import get_message_text
-from pathlib import Path
-
-
-__zx_plugin_name__ = "帮助"
-
-
-help_image = Path(IMAGE_PATH) / "help.png"
-simple_help_image = Path(IMAGE_PATH) / "simple_help.png"
-if help_image.exists():
- help_image.unlink()
-if simple_help_image.exists():
- simple_help_image.unlink()
-
-_help = on_command("详细功能", rule=to_me(), aliases={"详细帮助"}, priority=1, block=True)
-simple_help = on_command("功能", rule=to_me(), aliases={"help", "帮助"}, priority=1, block=True)
-
-
-@_help.handle()
-async def _(bot: Bot, event: MessageEvent, state: T_State):
- if not help_image.exists():
- if help_image.exists():
- help_image.unlink()
- if simple_help_image.exists():
- simple_help_image.unlink()
- await create_help_img(help_image, simple_help_image)
- await _help.finish(image("help.png"))
-
-
-@simple_help.handle()
-async def _(bot: Bot, event: MessageEvent, state: T_State):
- msg = get_message_text(event.json())
- is_super = False
- if msg:
- if '-super' in msg:
- if str(event.user_id) in bot.config.superusers:
- is_super = True
- msg = msg.replace('-super', '')
- msg = get_plugin_help(msg, is_super)
- if msg:
- await _help.send(image(b64=msg))
- else:
- await _help.send("没有此功能的帮助信息...")
- else:
- if not simple_help_image.exists():
- if help_image.exists():
- help_image.unlink()
- if simple_help_image.exists():
- simple_help_image.unlink()
- await create_help_img(help_image, simple_help_image)
- await _help.finish(image("simple_help.png"))
+from nonebot import on_command
+from nonebot.adapters.cqhttp import (
+ Bot,
+ MessageEvent,
+ GroupMessageEvent
+)
+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"
+if help_image.exists():
+ help_image.unlink()
+if simple_help_image.exists():
+ simple_help_image.unlink()
+group_help_path.mkdir(exist_ok=True, parents=True)
+for x in os.listdir(group_help_path):
+ group_help_image = group_help_path / x
+ group_help_image.unlink()
+
+_help = on_command("详细功能", rule=to_me(), aliases={"详细帮助"}, priority=1, block=True)
+simple_help = on_command("功能", rule=to_me(), aliases={"help", "帮助"}, priority=1, block=True)
+
+
+@_help.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ if not help_image.exists():
+ if help_image.exists():
+ help_image.unlink()
+ if simple_help_image.exists():
+ simple_help_image.unlink()
+ await create_help_img(None, help_image, simple_help_image)
+ await _help.finish(image("help.png"))
+
+
+@simple_help.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ msg = get_message_text(event.json())
+ is_super = False
+ if msg:
+ if '-super' in msg:
+ if str(event.user_id) in bot.config.superusers:
+ is_super = True
+ msg = msg.replace('-super', '').strip()
+ msg = get_plugin_help(msg, is_super)
+ if msg:
+ await _help.send(image(b64=msg))
+ else:
+ await _help.send("没有此功能的帮助信息...")
+ else:
+ if isinstance(event, GroupMessageEvent):
+ _image_path = group_help_path / f"{event.group_id}.png"
+ if not _image_path.exists():
+ await create_help_img(event.group_id, help_image, _image_path)
+ await simple_help.send(image(_image_path))
+ else:
+ if not simple_help_image.exists():
+ if help_image.exists():
+ help_image.unlink()
+ if simple_help_image.exists():
+ simple_help_image.unlink()
+ await create_help_img(None, help_image, simple_help_image)
+ await _help.finish(image("simple_help.png"))
diff --git a/plugins/help/data_source.py b/basic_plugins/help/data_source.py
similarity index 67%
rename from plugins/help/data_source.py
rename to basic_plugins/help/data_source.py
index 2512f321..64d0276d 100644
--- a/plugins/help/data_source.py
+++ b/basic_plugins/help/data_source.py
@@ -1,289 +1,367 @@
-from utils.image_utils import CreateImg
-from configs.path_config import IMAGE_PATH
-from utils.manager import plugins2settings_manager
-from typing import Optional
-from services.log import logger
-from pathlib import Path
-from utils.utils import get_matchers
-import random
-import asyncio
-import nonebot
-import os
-
-
-random_bk_path = Path(IMAGE_PATH) / "background" / "help" / "simple_help"
-
-background = Path(IMAGE_PATH) / "background" / "0.png"
-
-
-async def create_help_img(help_image: Path, simple_help_image: Path):
- """
- 生成帮助图片
- :param help_image: 图片路径
- :param simple_help_image: 简易帮助图片路径
- """
- return await asyncio.get_event_loop().run_in_executor(
- None, _create_help_img, help_image, simple_help_image
- )
-
-
-def _create_help_img(help_image: Path, simple_help_image: Path):
- """
- 生成帮助图片
- :param help_image: 图片路径
- :param simple_help_image: 简易帮助图片路径
- """
- _matchers = get_matchers()
- width = 0
- matchers_data = {}
- _des_tmp = {}
- _plugin_name_tmp = []
- _tmp = []
- tmp_img = CreateImg(0, 0, plain_text="1", font_size=24)
- font_height = tmp_img.h
- for matcher in _matchers:
- plugin_name = None
- _plugin = nonebot.plugin.get_plugin(matcher.module)
- _module = _plugin.module
- try:
- plugin_name = _module.__getattribute__("__zx_plugin_name__")
- try:
- plugin_des = _module.__getattribute__("__plugin_des__")
- except AttributeError:
- plugin_des = "_"
- if (
- "[hidden]" in plugin_name.lower()
- or "[admin]" in plugin_name.lower()
- or "[superuser]" in plugin_name.lower()
- or plugin_name in _plugin_name_tmp
- or plugin_name == "帮助"
- ):
- continue
- plugin_type = ("normal",)
- text_type = 0
- if plugins2settings_manager.get(
- matcher.module
- ) and plugins2settings_manager[matcher.module].get("plugin_type"):
- plugin_type = tuple(
- plugins2settings_manager.get_plugin_data(matcher.module)[
- "plugin_type"
- ]
- )
- else:
- try:
- plugin_type = _module.__getattribute__("__plugin_type__")
- except AttributeError:
- pass
- if len(plugin_type) > 1:
- try:
- text_type = int(plugin_type[1])
- except ValueError as e:
- logger.warning(f"生成列向帮助排列失败 {plugin_name}: {type(e)}: {e}")
- plugin_type = plugin_type[0]
- else:
- plugin_type = plugin_type[0]
- try:
- plugin_cmd = _module.__getattribute__("__plugin_cmd__")
- plugin_cmd = [x for x in plugin_cmd if "[_superuser]" not in x]
- except AttributeError:
- plugin_cmd = []
- if plugin_type not in matchers_data.keys():
- matchers_data[plugin_type] = {}
- if plugin_des in _des_tmp.keys():
- try:
- matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"] = (
- matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"]
- + plugin_cmd
- )
- except KeyError as e:
- logger.warning(f"{type(e)}: {e}")
- else:
- matchers_data[plugin_type][plugin_name] = {
- "des": plugin_des,
- "cmd": plugin_cmd,
- "text_type": text_type,
- }
- try:
- if text_type == 0:
- x = tmp_img.getsize(
- f'{plugin_name}: {matchers_data[plugin_type][plugin_name]["des"]} ->'
- + " / ".join(matchers_data[plugin_type][plugin_name]["cmd"])
- )[0]
- width = width if width > x else x
- except KeyError:
- pass
- if plugin_des not in _des_tmp:
- _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}")
- if plugin_name not in _plugin_name_tmp:
- _plugin_name_tmp.append(plugin_name)
- help_img_list = []
- simple_help_img_list = []
- types = list(matchers_data.keys())
- types.sort()
- ix = 0
- for type_ in types:
- keys = list(matchers_data[type_].keys())
- keys.sort()
- help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n"
- simple_help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n"
- for i, k in enumerate(keys):
- simple_help_str += f"{i+1}.{k}\n"
- if matchers_data[type_][k]["text_type"] == 1:
- _x = tmp_img.getsize(
- f"{i+1}".rjust(5)
- + f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
- )[0]
- _str = (
- f"{i+1}".rjust(5)
- + f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
- )
- _str += matchers_data[type_][k]["cmd"][0] + "\n"
- for c in matchers_data[type_][k]["cmd"][1:]:
- _str += "".rjust(int(_x * 0.125) + 1) + f"{c}\n"
- help_str += _str
- else:
- help_str += (
- f"{i+1}".rjust(5)
- + f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
- + " / ".join(matchers_data[type_][k]["cmd"])
- + "\n"
- )
- height = len(help_str.split("\n")) * (font_height + 5)
- simple_height = len(simple_help_str.split("\n")) * (font_height + 5)
- A = CreateImg(
- width + 150, height, font_size=24, color="white" if not ix % 2 else "black"
- )
- A.text((10, 10), help_str, (255, 255, 255) if ix % 2 else (0, 0, 0))
- simple_width = 0
- for x in [tmp_img.getsize(x)[0] for x in simple_help_str.split("\n")]:
- simple_width = simple_width if simple_width > x else x
- bk = CreateImg(
- simple_width + 20, simple_height, font_size=24, color="#6495ED"
- )
- B = CreateImg(
- simple_width + 20,
- simple_height,
- font_size=24,
- color="white" if not ix % 2 else "black",
- )
- B.text((10, 10), simple_help_str, (255, 255, 255) if ix % 2 else (0, 0, 0))
- bk.paste(B, center_type="center")
- bk.transparent(2)
- ix += 1
- help_img_list.append(A)
- simple_help_img_list.append(bk)
- height = 0
- for img in help_img_list:
- height += img.h
- A = CreateImg(width + 150, height + 50, font_size=24)
- A.text((10, 10), '* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" "功能名: 功能简介 -> 指令\n\n')
- current_height = 50
- for img in help_img_list:
- A.paste(img, (0, current_height))
- current_height += img.h
- A.save(help_image)
- height = 0
- width = 0
- for img in simple_help_img_list:
- if img.h > height:
- height = img.h
- width += img.w + 10
- B = CreateImg(width + 100, height + 250, font_size=24)
- width, _ = get_max_width_or_paste(simple_help_img_list, B)
- bk = None
- random_bk = os.listdir(random_bk_path)
- if random_bk:
- bk = random.choice(random_bk)
- x = max(width + 50, height + 250)
- B = CreateImg(
- x,
- x,
- font_size=24,
- color="#FFEFD5",
- background=random_bk_path / bk,
- )
- B.filter("GaussianBlur", 10)
- _, B = get_max_width_or_paste(simple_help_img_list, B, True)
- w = 10
- h = 10
- for msg in ['目前支持的功能列表:', '可以通过 ‘帮助[功能名称]’ 来获取对应功能的使用方法', '或者使用 ‘详细帮助’ 来获取所有功能方法']:
- text = CreateImg(
- 0,
- 0,
- plain_text=msg,
- font_size=24,
- color=(255, 255, 255, 0),
- font='yuanshen.ttf'
- )
- B.paste(text, (w, h), True)
- h += 50
- if msg == '目前支持的功能列表:':
- w += 50
- B.save(simple_help_image)
-
-
-def get_max_width_or_paste(
- simple_help_img_list: list, B: CreateImg = None, is_paste: bool = False
-) -> "int, CreateImg":
- """
- 获取最大宽度,或直接贴图
- :param simple_help_img_list: 简单帮助图片列表
- :param B: 背景图
- :param is_paste: 是否直接贴图
- """
- current_width = 50
- current_height = 180
- max_width = simple_help_img_list[0].w
- for i in range(len(simple_help_img_list)):
- try:
- if is_paste and B:
- B.paste(simple_help_img_list[i], (current_width, current_height), True)
- current_height += simple_help_img_list[i].h + 40
- if current_height + simple_help_img_list[i + 1].h > B.h - 10:
- current_height = 180
- current_width += max_width + 30
- max_width = 0
- elif simple_help_img_list[i].w > max_width:
- max_width = simple_help_img_list[i].w
- except IndexError:
- pass
- if current_width > simple_help_img_list[0].w + 50:
- current_width += simple_help_img_list[-1].w
- return current_width, B
-
-
-def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]:
- """
- 获取功能的帮助信息
- :param msg: 功能cmd
- :param is_super: 是否为超级用户
- """
- module = plugins2settings_manager.get_plugin_module(msg)
- if module:
- try:
- plugin = nonebot.plugin.get_plugin(module)
- if plugin:
- if is_super:
- result = plugin.module.__getattribute__(
- "__plugin_superuser_usage__"
- )
- else:
- result = plugin.module.__getattribute__("__plugin_usage__")
- width = 0
- for x in result.split("\n"):
- _width = len(x) * 24
- width = width if width > _width else _width
- height = len(result.split("\n")) * 45
- A = CreateImg(width, height, font_size=24)
- bk = CreateImg(
- width, height, background=Path(IMAGE_PATH) / "background" / "1.png"
- )
- A.paste(bk, alpha=True)
- A.text((int(width * 0.048), int(height * 0.21)), result)
- return A.pic2bs4()
- except AttributeError:
- pass
- return None
+from utils.image_utils import CreateImg
+from configs.path_config import IMAGE_PATH
+from utils.manager import (
+ plugins2settings_manager,
+ admin_manager,
+ plugins_manager,
+ group_manager,
+)
+from typing import Optional
+from services.log import logger
+from pathlib import Path
+from utils.utils import get_matchers
+import random
+import asyncio
+import nonebot
+import os
+
+
+random_bk_path = Path(IMAGE_PATH) / "background" / "help" / "simple_help"
+
+background = Path(IMAGE_PATH) / "background" / "0.png"
+
+
+async def create_help_img(
+ group_id: Optional[int], help_image: Path, simple_help_image: Path
+):
+ """
+ 生成帮助图片
+ :param group_id: 群号
+ :param help_image: 图片路径
+ :param simple_help_image: 简易帮助图片路径
+ """
+ return await asyncio.get_event_loop().run_in_executor(
+ None, _create_help_img, group_id, help_image, simple_help_image
+ )
+
+
+def _create_help_img(
+ group_id: Optional[int], help_image: Path, simple_help_image: Path
+):
+ """
+ 生成帮助图片
+ :param group_id: 群号
+ :param help_image: 图片路径
+ :param simple_help_image: 简易帮助图片路径
+ """
+ _matchers = get_matchers()
+ width = 0
+ matchers_data = {}
+ _des_tmp = {}
+ _plugin_name_tmp = []
+ _tmp = []
+ tmp_img = CreateImg(0, 0, plain_text="1", font_size=24)
+ font_height = tmp_img.h
+ # 插件分类
+ for matcher in _matchers:
+ plugin_name = None
+ _plugin = nonebot.plugin.get_plugin(matcher.module)
+ _module = _plugin.module
+ try:
+ plugin_name = _module.__getattribute__("__zx_plugin_name__")
+ try:
+ plugin_des = _module.__getattribute__("__plugin_des__")
+ except AttributeError:
+ plugin_des = "_"
+ if (
+ "[hidden]" in plugin_name.lower()
+ or "[admin]" in plugin_name.lower()
+ or "[superuser]" in plugin_name.lower()
+ or plugin_name in _plugin_name_tmp
+ or plugin_name == "帮助"
+ ):
+ continue
+ plugin_type = ("normal",)
+ text_type = 0
+ if plugins2settings_manager.get(
+ matcher.module
+ ) and plugins2settings_manager[matcher.module].get("plugin_type"):
+ plugin_type = tuple(
+ plugins2settings_manager.get_plugin_data(matcher.module)[
+ "plugin_type"
+ ]
+ )
+ else:
+ try:
+ plugin_type = _module.__getattribute__("__plugin_type__")
+ except AttributeError:
+ pass
+ if len(plugin_type) > 1:
+ try:
+ text_type = int(plugin_type[1])
+ except ValueError as e:
+ logger.warning(f"生成列向帮助排列失败 {plugin_name}: {type(e)}: {e}")
+ plugin_type = plugin_type[0]
+ else:
+ plugin_type = plugin_type[0]
+ try:
+ plugin_cmd = _module.__getattribute__("__plugin_cmd__")
+ plugin_cmd = [x for x in plugin_cmd if "[_superuser]" not in x]
+ except AttributeError:
+ plugin_cmd = []
+ if plugin_type not in matchers_data.keys():
+ matchers_data[plugin_type] = {}
+ if plugin_des in _des_tmp.keys():
+ try:
+ matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"] = (
+ matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"]
+ + plugin_cmd
+ )
+ except KeyError as e:
+ logger.warning(f"{type(e)}: {e}")
+ else:
+ matchers_data[plugin_type][plugin_name] = {
+ "module": matcher.module,
+ "des": plugin_des,
+ "cmd": plugin_cmd,
+ "text_type": text_type,
+ }
+ try:
+ if text_type == 0:
+ x = tmp_img.getsize(
+ f'{plugin_name}: {matchers_data[plugin_type][plugin_name]["des"]} ->'
+ + " / ".join(matchers_data[plugin_type][plugin_name]["cmd"])
+ )[0]
+ width = width if width > x else x
+ except KeyError:
+ pass
+ if plugin_des not in _des_tmp:
+ _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}")
+ if plugin_name not in _plugin_name_tmp:
+ _plugin_name_tmp.append(plugin_name)
+ help_img_list = []
+ simple_help_img_list = []
+ types = list(matchers_data.keys())
+ types.sort()
+ ix = 0
+ # 详细帮助
+ for type_ in types:
+ keys = list(matchers_data[type_].keys())
+ keys.sort()
+ help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n"
+ simple_help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n"
+ for i, k in enumerate(keys):
+ # 禁用flag
+ flag = True
+ if plugins_manager.get_plugin_status(
+ matchers_data[type_][k]["module"], "all"
+ ):
+ flag = False
+ if group_id:
+ flag = flag and plugins_manager.get_plugin_status(
+ matchers_data[type_][k]["module"], "group"
+ )
+ simple_help_str += (
+ f"{i+1}.{k}<|_|~|>"
+ f"{group_manager.get_plugin_status(matchers_data[type_][k]['module'], group_id) if group_id else '_'}|"
+ f"{flag}\n"
+ )
+ if matchers_data[type_][k]["text_type"] == 1:
+ _x = tmp_img.getsize(
+ f"{i+1}".rjust(5)
+ + f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
+ )[0]
+ _str = (
+ f"{i+1}".rjust(5)
+ + f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
+ )
+ _str += matchers_data[type_][k]["cmd"][0] + "\n"
+ for c in matchers_data[type_][k]["cmd"][1:]:
+ _str += "".rjust(int(_x * 0.125) + 1) + f"{c}\n"
+ help_str += _str
+ else:
+ help_str += (
+ f"{i+1}".rjust(5)
+ + f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} '
+ + " / ".join(matchers_data[type_][k]["cmd"])
+ + "\n"
+ )
+ height = len(help_str.split("\n")) * (font_height + 5)
+ simple_height = len(simple_help_str.split("\n")) * (font_height + 5)
+ A = CreateImg(
+ width + 150, height, font_size=24, color="white" if not ix % 2 else "black"
+ )
+ A.text((10, 10), help_str, (255, 255, 255) if ix % 2 else (0, 0, 0))
+ # 生成各个分类的插件简易帮助图片
+ simple_width = 0
+ for x in [
+ tmp_img.getsize(x.split("<|_|~|>")[0])[0]
+ for x in simple_help_str.split("\n")
+ ]:
+ simple_width = simple_width if simple_width > x else x
+ bk = CreateImg(simple_width + 20, simple_height, font_size=24, color="#6495ED")
+ B = CreateImg(
+ simple_width + 20,
+ simple_height,
+ font_size=24,
+ color="white" if not ix % 2 else "black",
+ )
+ # 切分,判断插件开关状态
+ _s_height = 10
+ for _s in simple_help_str.split("\n"):
+ text_color = (255, 255, 255) if ix % 2 else (0, 0, 0)
+ _line_flag = False
+ if "<|_|~|>" in _s:
+ _x = _s.split("<|_|~|>")
+ _flag_sp = _x[-1].split("|")
+ if group_id:
+ if _flag_sp[0].lower() != "true":
+ text_color = (252, 75, 13)
+ if _flag_sp[1].lower() == "true":
+ _line_flag = True
+ _s = _x[0]
+ B.text((10, _s_height), _s, text_color)
+ if _line_flag:
+ B.line(
+ (
+ 7,
+ _s_height + int(B.getsize(_s)[1] / 2) + 2,
+ B.getsize(_s)[0] + 11,
+ _s_height + int(B.getsize(_s)[1] / 2) + 2,
+ ),
+ (236, 66, 7),
+ 3,
+ )
+ _s_height += B.getsize("1")[1] + 5
+ # B.text((10, 10), simple_help_str, (255, 255, 255) if ix % 2 else (0, 0, 0))
+ bk.paste(B, center_type="center")
+ bk.transparent(2)
+ ix += 1
+ help_img_list.append(A)
+ simple_help_img_list.append(bk)
+ height = 0
+ for img in help_img_list:
+ height += img.h
+ if not group_id:
+ A = CreateImg(width + 150, height + 50, font_size=24)
+ A.text(
+ (10, 10), '* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" "功能名: 功能简介 -> 指令\n\n'
+ )
+ current_height = 50
+ for img in help_img_list:
+ A.paste(img, (0, current_height))
+ current_height += img.h
+ A.save(help_image)
+ # 详细帮助生成完毕
+ # 简易帮助图片合成
+ height = 0
+ width = 0
+ for img in simple_help_img_list:
+ if img.h > height:
+ height = img.h
+ width += img.w + 10
+ B = CreateImg(width + 100, height + 250, font_size=24)
+ width, _ = get_max_width_or_paste(simple_help_img_list, B)
+ bk = None
+ random_bk = os.listdir(random_bk_path)
+ if random_bk:
+ bk = random.choice(random_bk)
+ x = max(width + 50, height + 250)
+ B = CreateImg(
+ x,
+ x,
+ font_size=24,
+ color="#FFEFD5",
+ background=random_bk_path / bk,
+ )
+ B.filter("GaussianBlur", 10)
+ _, B = get_max_width_or_paste(simple_help_img_list, B, True)
+ w = 10
+ h = 10
+ for msg in ["目前支持的功能列表:", "可以通过 ‘帮助[功能名称]’ 来获取对应功能的使用方法", "或者使用 ‘详细帮助’ 来获取所有功能方法"]:
+ text = CreateImg(
+ 0,
+ 0,
+ plain_text=msg,
+ font_size=24,
+ font="yuanshen.ttf",
+ )
+ B.paste(text, (w, h), True)
+ h += 50
+ if msg == "目前支持的功能列表:":
+ w += 50
+ B.paste(
+ CreateImg(
+ 0,
+ 0,
+ plain_text="注: 红字代表功能被群管理员禁用,红线代表功能正在维护",
+ font_size=24,
+ font="yuanshen.ttf",
+ font_color=(231, 74, 57)
+ ),
+ (300, 10),
+ True,
+ )
+ B.save(simple_help_image)
+
+
+def get_max_width_or_paste(
+ simple_help_img_list: list, B: CreateImg = None, is_paste: bool = False
+) -> "int, CreateImg":
+ """
+ 获取最大宽度,或直接贴图
+ :param simple_help_img_list: 简单帮助图片列表
+ :param B: 背景图
+ :param is_paste: 是否直接贴图
+ """
+ current_width = 50
+ current_height = 180
+ max_width = simple_help_img_list[0].w
+ for i in range(len(simple_help_img_list)):
+ try:
+ if is_paste and B:
+ B.paste(simple_help_img_list[i], (current_width, current_height), True)
+ current_height += simple_help_img_list[i].h + 40
+ if current_height + simple_help_img_list[i + 1].h > B.h - 10:
+ current_height = 180
+ current_width += max_width + 30
+ max_width = 0
+ elif simple_help_img_list[i].w > max_width:
+ max_width = simple_help_img_list[i].w
+ except IndexError:
+ pass
+ if current_width > simple_help_img_list[0].w + 50:
+ current_width += simple_help_img_list[-1].w
+ return current_width, B
+
+
+def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]:
+ """
+ 获取功能的帮助信息
+ :param msg: 功能cmd
+ :param is_super: 是否为超级用户
+ """
+ module = plugins2settings_manager.get_plugin_module(msg)
+ if not module:
+ module = admin_manager.get_plugin_module(msg)
+ if module:
+ try:
+ plugin = nonebot.plugin.get_plugin(module)
+ if plugin:
+ if is_super:
+ result = plugin.module.__getattribute__(
+ "__plugin_superuser_usage__"
+ )
+ else:
+ result = plugin.module.__getattribute__("__plugin_usage__")
+ if result:
+ width = 0
+ for x in result.split("\n"):
+ _width = len(x) * 24
+ width = width if width > _width else _width
+ height = len(result.split("\n")) * 45
+ A = CreateImg(width, height, font_size=24)
+ bk = CreateImg(
+ width,
+ height,
+ background=Path(IMAGE_PATH) / "background" / "1.png",
+ )
+ A.paste(bk, alpha=True)
+ A.text((int(width * 0.048), int(height * 0.21)), result)
+ return A.pic2bs4()
+ except AttributeError:
+ pass
+ return None
diff --git a/basic_plugins/hooks/__init__.py b/basic_plugins/hooks/__init__.py
new file mode 100644
index 00000000..d1c21d41
--- /dev/null
+++ b/basic_plugins/hooks/__init__.py
@@ -0,0 +1,38 @@
+from configs.config import Config
+import nonebot
+
+
+Config.add_plugin_config(
+ "hook",
+ "CHECK_NOTICE_INFO_CD",
+ 300,
+ name="基础hook配置",
+ help_="群检测,个人权限检测等各种检测提示信息cd",
+ default_value=300
+)
+
+Config.add_plugin_config(
+ "hook",
+ "MALICIOUS_BAN_TIME",
+ 30,
+ help_="恶意命令触发检测触发后ban的时长(分钟)",
+ default_value=30
+)
+
+Config.add_plugin_config(
+ "hook",
+ "MALICIOUS_CHECK_TIME",
+ 5,
+ help_="恶意命令触发检测规定时间内(秒)",
+ default_value=5
+)
+
+Config.add_plugin_config(
+ "hook",
+ "MALICIOUS_BAN_COUNT",
+ 6,
+ help_="恶意命令触发检测最大触发次数",
+ default_value=6
+)
+
+nonebot.load_plugins("basic_plugins/hooks")
diff --git a/basic_plugins/hooks/auth_hook.py b/basic_plugins/hooks/auth_hook.py
new file mode 100644
index 00000000..1dadbaa2
--- /dev/null
+++ b/basic_plugins/hooks/auth_hook.py
@@ -0,0 +1,210 @@
+from nonebot.matcher import Matcher
+from nonebot.message import run_preprocessor, IgnoredException
+from nonebot.adapters.cqhttp.exception import ActionFailed
+from utils.manager import (
+ plugins2settings_manager,
+ admin_manager,
+ group_manager,
+ plugins_manager,
+)
+from .utils import set_block_limit_false, status_message_manager
+from nonebot.typing import T_State
+from nonebot.adapters.cqhttp import (
+ Bot,
+ MessageEvent,
+ GroupMessageEvent,
+ PokeNotifyEvent,
+)
+from configs.config import Config
+from models.ban_user import BanUser
+from utils.utils import FreqLimiter
+from utils.message_builder import at
+from models.level_user import LevelUser
+
+
+_flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
+_flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
+_flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
+_flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
+
+
+ignore_rst_module = ["ai", "poke", "dialogue"]
+
+
+# 权限检测
+@run_preprocessor
+async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
+ module = matcher.module
+ plugins2info_dict = plugins2settings_manager.get_data()
+ if (
+ (not isinstance(event, MessageEvent) and module != "poke")
+ or await BanUser.is_ban(event.user_id)
+ and str(event.user_id) not in bot.config.superusers
+ ) or (
+ str(event.user_id) in bot.config.superusers
+ and plugins2info_dict.get(module)
+ and not plugins2info_dict[module]["limit_superuser"]
+ ):
+ return
+ # 群黑名单检测
+ if isinstance(event, GroupMessageEvent):
+ if group_manager.get_group_level(event.group_id) < 0:
+ raise IgnoredException("群黑名单")
+ if module in admin_manager.keys() and matcher.priority not in [1, 9]:
+ if isinstance(event, GroupMessageEvent):
+ # 个人权限
+ if (
+ not await LevelUser.check_level(
+ event.user_id,
+ event.group_id,
+ admin_manager.get_plugin_level(module),
+ )
+ and admin_manager.get_plugin_level(module) > 0
+ ):
+ try:
+ if _flmt.check(event.user_id):
+ _flmt.start_cd(event.user_id)
+ await bot.send_group_msg(
+ group_id=event.group_id,
+ message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
+ f"{admin_manager.get_plugin_level(module)}",
+ )
+ except ActionFailed:
+ pass
+ set_block_limit_false(event, module)
+ if event.is_tome():
+ status_message_manager.add(event.group_id)
+ raise IgnoredException("权限不足")
+ else:
+ if not await LevelUser.check_level(
+ event.user_id, 0, admin_manager.get_plugin_level(module)
+ ):
+ try:
+ await bot.send_private_msg(
+ user_id=event.user_id,
+ message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(module)}",
+ )
+ except ActionFailed:
+ pass
+ set_block_limit_false(event, module)
+ if event.is_tome():
+ status_message_manager.add(event.user_id)
+ raise IgnoredException("权限不足")
+ if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]:
+ # 戳一戳单独判断
+ if isinstance(event, GroupMessageEvent) or (
+ isinstance(event, PokeNotifyEvent) and event.group_id
+ ):
+ if status_message_manager.get(event.group_id) is None:
+ status_message_manager.delete(event.group_id)
+ if plugins2info_dict[module]["level"] > group_manager.get_group_level(
+ event.group_id
+ ):
+ try:
+ if _flmt_g.check(event.user_id) and module not in ignore_rst_module:
+ _flmt_g.start_cd(event.user_id)
+ await bot.send_group_msg(
+ group_id=event.group_id, message="群权限不足..."
+ )
+ except ActionFailed:
+ pass
+ if event.is_tome():
+ status_message_manager.add(event.group_id)
+ set_block_limit_false(event, module)
+ raise IgnoredException("群权限不足")
+ # 插件状态
+ if not group_manager.get_plugin_status(module, event.group_id):
+ try:
+ if module not in ignore_rst_module and _flmt_s.check(
+ event.group_id
+ ):
+ _flmt_s.start_cd(event.group_id)
+ await bot.send_group_msg(
+ group_id=event.group_id, message="该群未开启此功能.."
+ )
+ except ActionFailed:
+ pass
+ if event.is_tome():
+ status_message_manager.add(event.group_id)
+ set_block_limit_false(event, module)
+ raise IgnoredException("未开启此功能...")
+ # 管理员禁用
+ if not group_manager.get_plugin_status(f"{module}:super", event.group_id):
+ try:
+ if (
+ _flmt_s.check(event.group_id)
+ and module not in ignore_rst_module
+ ):
+ _flmt_s.start_cd(event.group_id)
+ await bot.send_group_msg(
+ group_id=event.group_id, message="管理员禁用了此群该功能..."
+ )
+ except ActionFailed:
+ pass
+ if event.is_tome():
+ status_message_manager.add(event.group_id)
+ set_block_limit_false(event, module)
+ raise IgnoredException("管理员禁用了此群该功能...")
+ # 群聊禁用
+ if not plugins_manager.get_plugin_status(module, block_type="group"):
+ try:
+ if (
+ _flmt_c.check(event.group_id)
+ and module not in ignore_rst_module
+ ):
+ _flmt_c.start_cd(event.group_id)
+ await bot.send_group_msg(
+ group_id=event.group_id, message="该功能在群聊中已被禁用..."
+ )
+ except ActionFailed:
+ pass
+ if event.is_tome():
+ status_message_manager.add(event.group_id)
+ set_block_limit_false(event, module)
+ raise IgnoredException("该插件在群聊中已被禁用...")
+ else:
+ # 私聊禁用
+ if not plugins_manager.get_plugin_status(module, block_type="private"):
+ try:
+ if _flmt_c.check(event.user_id):
+ _flmt_c.start_cd(event.user_id)
+ await bot.send_private_msg(
+ user_id=event.user_id, message="该功能在私聊中已被禁用..."
+ )
+ except ActionFailed:
+ pass
+ if event.is_tome():
+ status_message_manager.add(event.user_id)
+ set_block_limit_false(event, module)
+ raise IgnoredException("该插件在私聊中已被禁用...")
+ # 维护
+ if not plugins_manager.get_plugin_status(module, block_type="all"):
+ if isinstance(
+ event, GroupMessageEvent
+ ) and group_manager.check_group_is_white(event.group_id):
+ return
+ try:
+ if isinstance(event, GroupMessageEvent):
+ if (
+ _flmt_c.check(event.group_id)
+ and module not in ignore_rst_module
+ ):
+ _flmt_c.start_cd(event.group_id)
+ await bot.send_group_msg(
+ group_id=event.group_id, message="此功能正在维护..."
+ )
+ else:
+ await bot.send_private_msg(
+ user_id=event.user_id, message="此功能正在维护..."
+ )
+ except ActionFailed:
+ pass
+ if event.is_tome():
+ id_ = (
+ event.group_id
+ if isinstance(event, GroupMessageEvent)
+ else event.user_id
+ )
+ status_message_manager.add(id_)
+ set_block_limit_false(event, module)
+ raise IgnoredException("此功能正在维护...")
diff --git a/basic_plugins/hooks/ban_hook.py b/basic_plugins/hooks/ban_hook.py
new file mode 100644
index 00000000..e7d131b0
--- /dev/null
+++ b/basic_plugins/hooks/ban_hook.py
@@ -0,0 +1,83 @@
+from nonebot.matcher import Matcher
+from nonebot.message import run_preprocessor, IgnoredException
+from nonebot.adapters.cqhttp.exception import ActionFailed
+from nonebot.typing import T_State
+from nonebot.adapters.cqhttp import (
+ Bot,
+ MessageEvent,
+ GroupMessageEvent,
+)
+from configs.config import Config
+from models.ban_user import BanUser
+from utils.utils import is_number, static_flmt
+from utils.message_builder import at
+
+
+Config.add_plugin_config(
+ "hook",
+ "BAN_RESULT",
+ "才不会给你发消息.",
+ help_="对被ban用户发送的消息",
+)
+
+
+# 检查是否被ban
+@run_preprocessor
+async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
+ try:
+ if (
+ await BanUser.is_super_ban(event.user_id)
+ and str(event.user_id) not in bot.config.superusers
+ ):
+ raise IgnoredException("用户处于超级黑名单中")
+ except AttributeError:
+ pass
+ if not isinstance(event, MessageEvent):
+ return
+ if matcher.type == "message" and matcher.priority not in [1, 9]:
+ if (
+ await BanUser.is_ban(event.user_id)
+ and str(event.user_id) not in bot.config.superusers
+ ):
+ time = await BanUser.check_ban_time(event.user_id)
+ if is_number(time):
+ time = abs(int(time))
+ if time < 60:
+ time = str(time) + " 秒"
+ else:
+ time = str(int(time / 60)) + " 分钟"
+ else:
+ time = str(time) + " 分钟"
+ if isinstance(event, GroupMessageEvent):
+ if not static_flmt.check(event.user_id):
+ raise IgnoredException("用户处于黑名单中")
+ static_flmt.start_cd(event.user_id)
+ if matcher.priority != 9:
+ try:
+ ban_result = Config.get_config("hook", "BAN_RESULT")
+ if ban_result:
+ await bot.send_group_msg(
+ group_id=event.group_id,
+ message=at(event.user_id)
+ + ban_result
+ + f" 在..在 {time} 后才会理你喔",
+ )
+ except ActionFailed:
+ pass
+ else:
+ if not static_flmt.check(event.user_id):
+ raise IgnoredException("用户处于黑名单中")
+ static_flmt.start_cd(event.user_id)
+ if matcher.priority != 9:
+ try:
+ ban_result = Config.get_config("hook", "BAN_RESULT")
+ if ban_result:
+ await bot.send_private_msg(
+ user_id=event.user_id,
+ message=at(event.user_id)
+ + ban_result
+ + f" 在..在 {time}后才会理你喔",
+ )
+ except ActionFailed:
+ pass
+ raise IgnoredException("用户处于黑名单中")
\ No newline at end of file
diff --git a/basic_plugins/hooks/chkdsk_hook.py b/basic_plugins/hooks/chkdsk_hook.py
new file mode 100644
index 00000000..3fa53285
--- /dev/null
+++ b/basic_plugins/hooks/chkdsk_hook.py
@@ -0,0 +1,54 @@
+from nonebot.matcher import Matcher
+from nonebot.message import run_preprocessor, IgnoredException
+from nonebot.adapters.cqhttp.exception import ActionFailed
+from nonebot.typing import T_State
+from nonebot.adapters.cqhttp import (
+ Bot,
+ MessageEvent,
+ GroupMessageEvent,
+)
+from configs.config import Config
+from models.ban_user import BanUser
+from utils.utils import BanCheckLimiter
+from utils.message_builder import at
+from services.log import logger
+
+
+_blmt = BanCheckLimiter(
+ Config.get_config("hook", "MALICIOUS_CHECK_TIME"),
+ Config.get_config("hook", "MALICIOUS_BAN_COUNT"),
+)
+
+
+# 恶意触发命令检测
+@run_preprocessor
+async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State):
+ if not isinstance(event, MessageEvent):
+ return
+ if matcher.type == "message" and matcher.priority not in [1, 9]:
+ if state["_prefix"]["raw_command"]:
+ if _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'):
+ if await BanUser.ban(
+ event.user_id,
+ 9,
+ Config.get_config("hook", "MALICIOUS_BAN_TIME") * 60,
+ ):
+ logger.info(f"USER {event.user_id} 触发了恶意触发检测")
+ if isinstance(event, GroupMessageEvent):
+ try:
+ await bot.send_group_msg(
+ group_id=event.group_id,
+ message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟",
+ )
+ except ActionFailed:
+ pass
+ else:
+ try:
+ await bot.send_private_msg(
+ user_id=event.user_id,
+ message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟",
+ )
+ except ActionFailed:
+ pass
+ raise IgnoredException("检测到恶意触发命令")
+ _blmt.add(f'{event.user_id}{state["_prefix"]["raw_command"]}')
diff --git a/basic_plugins/hooks/limit_hook.py b/basic_plugins/hooks/limit_hook.py
new file mode 100644
index 00000000..eff6760c
--- /dev/null
+++ b/basic_plugins/hooks/limit_hook.py
@@ -0,0 +1,146 @@
+from nonebot.matcher import Matcher
+from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
+from nonebot.adapters.cqhttp.exception import ActionFailed
+from models.friend_user import FriendUser
+from models.group_member_info import GroupInfoUser
+from utils.message_builder import at
+from .utils import status_message_manager, set_block_limit_false
+from utils.manager import (
+ plugins2cd_manager,
+ plugins2block_manager,
+ plugins2count_manager,
+)
+from typing import Optional
+from nonebot.typing import T_State
+from nonebot.adapters.cqhttp import (
+ Bot,
+ Event,
+ MessageEvent,
+ PrivateMessageEvent,
+ GroupMessageEvent,
+ Message,
+)
+
+
+# 命令cd | 命令阻塞 | 命令次数
+@run_preprocessor
+async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
+ if not isinstance(event, MessageEvent) and matcher.module != "poke":
+ return
+ module = matcher.module
+ if (
+ isinstance(event, GroupMessageEvent)
+ and status_message_manager.get(event.group_id) is None
+ ):
+ status_message_manager.delete(event.group_id)
+ # Count
+ if (
+ plugins2count_manager.check_plugin_count_status(module)
+ and event.user_id not in bot.config.superusers
+ ):
+ plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
+ limit_type = plugin_count_data["limit_type"]
+ rst = plugin_count_data["rst"]
+ count_type_ = event.user_id
+ if limit_type == "group" and isinstance(event, GroupMessageEvent):
+ count_type_ = event.group_id
+ if not plugins2count_manager.check(module, count_type_):
+ if rst:
+ rst = await init_rst(rst, event)
+ await send_msg(rst, bot, event)
+ raise IgnoredException(f"{module} count次数限制...")
+ else:
+ plugins2count_manager.increase(module, count_type_)
+ # Cd
+ if plugins2cd_manager.check_plugin_cd_status(module):
+ plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
+ check_type = plugin_cd_data["check_type"]
+ limit_type = plugin_cd_data["limit_type"]
+ rst = plugin_cd_data["rst"]
+ if (
+ (isinstance(event, PrivateMessageEvent) and check_type == "private")
+ or (isinstance(event, GroupMessageEvent) and check_type == "group")
+ or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
+ ):
+ cd_type_ = event.user_id
+ if limit_type == "group" and isinstance(event, GroupMessageEvent):
+ cd_type_ = event.group_id
+ if not plugins2cd_manager.check(module, cd_type_):
+ if rst:
+ rst = await init_rst(rst, event)
+ await send_msg(rst, bot, event)
+ raise IgnoredException(f"{module} 正在cd中...")
+ else:
+ plugins2cd_manager.start_cd(module, cd_type_)
+ # Block
+ 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"]
+ rst = plugin_block_data["rst"]
+ if (
+ (isinstance(event, PrivateMessageEvent) and check_type == "private")
+ or (isinstance(event, GroupMessageEvent) and check_type == "group")
+ or check_type == "all"
+ ):
+ block_type_ = event.user_id
+ if limit_type == "group" and isinstance(event, GroupMessageEvent):
+ block_type_ = event.group_id
+ if plugins2block_manager.check(block_type_, module):
+ if rst:
+ rst = await init_rst(rst, event)
+ await send_msg(rst, bot, event)
+ raise IgnoredException(f"{event.user_id}正在调用{module}....")
+ else:
+ plugins2block_manager.set_true(block_type_, module)
+
+
+async def send_msg(rst: str, bot: Bot, event: MessageEvent):
+ """
+ 发送信息
+ :param rst: pass
+ :param bot: pass
+ :param event: pass
+ """
+ rst = await init_rst(rst, event)
+ try:
+ if isinstance(event, GroupMessageEvent):
+ status_message_manager.add(event.group_id)
+ await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
+ else:
+ status_message_manager.add(event.user_id)
+ await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
+ except ActionFailed:
+ pass
+
+
+# 解除命令block阻塞
+@run_postprocessor
+async def _(
+ matcher: Matcher,
+ exception: Optional[Exception],
+ bot: Bot,
+ event: Event,
+ state: T_State,
+):
+ if not isinstance(event, MessageEvent) and matcher.module != "poke":
+ return
+ module = matcher.module
+ 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
+ rst = rst.replace("[uname]", uname)
+ if "[nickname]" in rst:
+ if isinstance(event, GroupMessageEvent):
+ nickname = await GroupInfoUser.get_group_member_nickname(
+ event.user_id, event.group_id
+ )
+ else:
+ nickname = await FriendUser.get_friend_nickname(event.user_id)
+ rst = rst.replace("[nickname]", nickname)
+ if "[at]" in rst and isinstance(event, GroupMessageEvent):
+ rst = rst.replace("[at]", str(at(event.user_id)))
+ return rst
diff --git a/basic_plugins/hooks/other_hook.py b/basic_plugins/hooks/other_hook.py
new file mode 100644
index 00000000..b2a85919
--- /dev/null
+++ b/basic_plugins/hooks/other_hook.py
@@ -0,0 +1,41 @@
+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 (
+ Bot,
+ MessageEvent,
+ PrivateMessageEvent,
+ GroupMessageEvent,
+)
+
+
+# 为什么AI会自己和自己聊天
+@run_preprocessor
+async def _(matcher: Matcher, bot: Bot, event: PrivateMessageEvent, state: T_State):
+ if not isinstance(event, MessageEvent):
+ return
+ if event.user_id == int(bot.self_id):
+ raise IgnoredException("为什么AI会自己和自己聊天")
+
+
+# 有命令就别说话了
+@run_preprocessor
+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 (
+ isinstance(event, GroupMessageEvent)
+ and not status_message_manager.check(event.group_id)
+ ):
+ status_message_manager.delete(event.group_id)
+ raise IgnoredException("有命令就别说话了")
+ elif (
+ 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/utils.py b/basic_plugins/hooks/utils.py
new file mode 100644
index 00000000..5231b8f9
--- /dev/null
+++ b/basic_plugins/hooks/utils.py
@@ -0,0 +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)
+
diff --git a/basic_plugins/hooks/withdraw_message_hook.py b/basic_plugins/hooks/withdraw_message_hook.py
new file mode 100644
index 00000000..76356542
--- /dev/null
+++ b/basic_plugins/hooks/withdraw_message_hook.py
@@ -0,0 +1,28 @@
+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 utils.manager import withdraw_message_manager
+import asyncio
+
+
+# 消息撤回
+@run_postprocessor
+async def _(
+ matcher: Matcher,
+ exception: Optional[Exception],
+ bot: Bot,
+ event: Event,
+ state: T_State,
+):
+ tasks = []
+ for id_, time in withdraw_message_manager.data:
+ tasks.append(asyncio.ensure_future(_withdraw_message(bot, id_, time)))
+ withdraw_message_manager.remove((id_, time))
+ await asyncio.gather(*tasks)
+
+
+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))
diff --git a/basic_plugins/init_plugin_config/__init__.py b/basic_plugins/init_plugin_config/__init__.py
new file mode 100644
index 00000000..0b4efb6c
--- /dev/null
+++ b/basic_plugins/init_plugin_config/__init__.py
@@ -0,0 +1,51 @@
+from .init_group_manager import init_group_manager, group_manager
+from .init_plugins_config import init_plugins_config
+from .init_plugins_data import init_plugins_data, plugins_manager
+from .init_none_plugin_count_manager import init_none_plugin_count_manager
+from .init_plugins_resources import init_plugins_resources
+from .init_plugins_settings import init_plugins_settings
+from .init_plugins_limit import (
+ init_plugins_block_limit,
+ init_plugins_count_limit,
+ init_plugins_cd_limit,
+)
+from .check_plugin_status import check_plugin_status
+from nonebot.adapters.cqhttp import Bot
+from configs.path_config import DATA_PATH
+from services.log import logger
+from nonebot import Driver
+import nonebot
+
+
+__zx_plugin_name__ = "初始化插件数据 [Hidden]"
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+
+
+driver: Driver = nonebot.get_driver()
+
+
+@driver.on_startup
+def _():
+ """
+ 初始化数据
+ """
+ init_plugins_settings(DATA_PATH)
+ init_plugins_cd_limit(DATA_PATH)
+ init_plugins_block_limit(DATA_PATH)
+ init_plugins_count_limit(DATA_PATH)
+ init_plugins_data(DATA_PATH)
+ init_plugins_config(DATA_PATH)
+ init_plugins_resources()
+ init_none_plugin_count_manager()
+ x = group_manager.get_super_old_data()
+ if x:
+ for key in x.keys():
+ plugins_manager.block_plugin(key, block_type=x[key])
+ logger.info("初始化数据完成...")
+
+
+@driver.on_bot_connect
+async def _(bot: Bot):
+ await init_group_manager()
+ await check_plugin_status(bot)
diff --git a/basic_plugins/init_plugin_config/check_plugin_status.py b/basic_plugins/init_plugin_config/check_plugin_status.py
new file mode 100644
index 00000000..ad2bd049
--- /dev/null
+++ b/basic_plugins/init_plugin_config/check_plugin_status.py
@@ -0,0 +1,18 @@
+from utils.manager import plugins_manager
+from nonebot.adapters.cqhttp import Bot
+
+
+async def check_plugin_status(bot: Bot):
+ """
+ 遍历查看插件加载情况
+ """
+ rst = ""
+ for plugin in plugins_manager.keys():
+ data = plugins_manager.get(plugin)
+ if data.get("error") or data.get("error") is None:
+ rst += f'{plugin}:{data["plugin_name"]}\n'
+ if rst:
+ rst = "以下插件加载失败..\n" + rst
+ await bot.send_private_msg(
+ user_id=int(list(bot.config.superusers)[0]), message=rst[:-1]
+ )
diff --git a/basic_plugins/init_plugin_config/init_group_manager.py b/basic_plugins/init_plugin_config/init_group_manager.py
new file mode 100644
index 00000000..3b91ae03
--- /dev/null
+++ b/basic_plugins/init_plugin_config/init_group_manager.py
@@ -0,0 +1,73 @@
+from pathlib import Path
+from utils.manager import group_manager
+from services.db_context import db
+from asyncpg.exceptions import DuplicateColumnError
+from services.log import logger
+
+try:
+ import ujson as json
+except ModuleNotFoundError:
+ import json
+try:
+ from models.group_remind import GroupRemind
+except ModuleNotFoundError:
+ pass
+
+
+async def init_group_manager():
+ """
+ 旧数据格式替换为新格式
+ 初始化数据
+ """
+ old_group_level_file = Path() / "data" / "manager" / "group_level.json"
+ old_plugin_list_file = Path() / "data" / "manager" / "plugin_list.json"
+ if old_group_level_file.exists():
+ data = json.load(open(old_group_level_file, "r", encoding="utf8"))
+ for key in data.keys():
+ group = key
+ level = data[key]
+ group_manager.set_group_level(group, level)
+ old_group_level_file.unlink()
+ group_manager.save()
+
+ if old_plugin_list_file.exists():
+ data = json.load(open(old_plugin_list_file, "r", encoding="utf8"))
+ for plugin in data.keys():
+ for group in data[plugin].keys():
+ if group == "default" and not data[plugin]["default"]:
+ group_manager.block_plugin(plugin)
+ elif not data[plugin][group]:
+ group_manager.block_plugin(plugin, group)
+ old_plugin_list_file.unlink()
+ old_data_table = Path() / "models" / "group_remind.py"
+ try:
+ if old_data_table.exists():
+ b = {
+ "hy": "group_welcome",
+ "kxcz": "open_case_reset_remind",
+ "zwa": "zwa",
+ "blpar": "bilibili_parse",
+ "epic": "epic_free_game",
+ "pa": "pa",
+ "almanac": "genshin_alc",
+ }
+ for group in group_manager.get_data()["group_manager"]:
+ for remind in b:
+ try:
+ status = await GroupRemind.get_status(int(group), remind)
+ if status is not None:
+ if status:
+ await group_manager.open_group_task(group, b[remind])
+ logger.info(f"读取旧数据-->{group} 开启 {b[remind]}")
+ else:
+ await group_manager.close_group_task(group, b[remind])
+ logger.info(f"读取旧数据-->{group} 关闭 {b[remind]}")
+ except Exception as e:
+ pass
+ query = db.text("DROP TABLE group_reminds;")
+ await db.first(query)
+ old_data_table.unlink()
+ logger.info("旧数据读取完毕,删除了舍弃表 group_reminds...")
+ except (ModuleNotFoundError, DuplicateColumnError):
+ pass
+ group_manager.save()
diff --git a/basic_plugins/init_plugin_config/init_none_plugin_count_manager.py b/basic_plugins/init_plugin_config/init_none_plugin_count_manager.py
new file mode 100644
index 00000000..b89dd422
--- /dev/null
+++ b/basic_plugins/init_plugin_config/init_none_plugin_count_manager.py
@@ -0,0 +1,45 @@
+from utils.manager import (
+ none_plugin_count_manager,
+ plugins2count_manager,
+ plugins2cd_manager,
+ plugins2settings_manager,
+ plugins2block_manager,
+ plugins_manager,
+ resources_manager
+)
+from services.log import logger
+from utils.utils import get_matchers
+
+try:
+ import ujson as json
+except ModuleNotFoundError:
+ import json
+
+
+def init_none_plugin_count_manager():
+ """
+ 清除已删除插件数据
+ """
+ modules = [x.module for x in get_matchers()]
+ for module in none_plugin_count_manager.keys():
+ if module not in modules:
+ none_plugin_count_manager.add_count(module)
+ else:
+ none_plugin_count_manager.reset(module)
+ if none_plugin_count_manager.check(module):
+ try:
+ plugin_name = plugins_manager.get(module)["plugin_name"]
+ except (AttributeError, KeyError):
+ plugin_name = ""
+ try:
+ plugins2settings_manager.delete(module)
+ plugins2count_manager.delete(module)
+ plugins2cd_manager.delete(module)
+ plugins2block_manager.delete(module)
+ plugins_manager.delete(module)
+ resources_manager.remove_resource(module)
+ logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...")
+ except Exception as e:
+ logger.error(
+ f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}:{e}"
+ )
diff --git a/basic_plugins/init_plugin_config/init_plugins_config.py b/basic_plugins/init_plugin_config/init_plugins_config.py
new file mode 100644
index 00000000..addd8602
--- /dev/null
+++ b/basic_plugins/init_plugin_config/init_plugins_config.py
@@ -0,0 +1,147 @@
+from pathlib import Path
+from ruamel.yaml import round_trip_load, round_trip_dump, YAML
+from utils.manager import admin_manager, plugins_manager
+from configs.config import Config
+from services.log import logger
+from utils.utils import get_matchers
+from ruamel import yaml
+import nonebot
+
+
+_yaml = YAML(typ="safe")
+
+
+def init_plugins_config(data_path):
+ """
+ 初始化插件数据配置
+ """
+ plugins2config_file = Path(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)
+ try:
+ _module = _plugin.module
+ except AttributeError:
+ continue
+ try:
+ plugin_version = _module.__getattribute__("__plugin_version__")
+ except AttributeError:
+ plugin_version = None
+ try:
+ plugin_configs = _module.__getattribute__("__plugin_configs__")
+ except AttributeError:
+ continue
+ # 插件配置版本更新或为Version为None或不在存储配置内
+ if (
+ plugin_version is None
+ or (
+ _data.get(matcher.module)
+ and _data[matcher.module].keys() != plugin_configs.keys()
+ )
+ or plugin_version > plugins_manager.get(matcher.module)["version"]
+ or matcher.module not in _data.keys()
+ ):
+ for key in plugin_configs:
+ if isinstance(plugin_configs[key], dict):
+ Config.add_plugin_config(
+ matcher.module,
+ key,
+ plugin_configs[key].get("value"),
+ help_=plugin_configs[key].get("help"),
+ default_value=plugin_configs[key].get("default_value"),
+ _override=True,
+ )
+ else:
+ Config.add_plugin_config(matcher.module, key, plugin_configs[key])
+ else:
+ plugin_configs = _data[matcher.module]
+ for key in plugin_configs:
+ Config.add_plugin_config(
+ matcher.module,
+ key,
+ plugin_configs[key]["value"],
+ help_=plugin_configs[key]["help"],
+ default_value=plugin_configs[key]["default_value"],
+ _override=True,
+ )
+ if not Config.is_empty():
+ Config.save()
+ _data = round_trip_load(open(plugins2config_file, encoding="utf8"))
+ for plugin in _data.keys():
+ try:
+ plugin_name = plugins_manager.get(plugin)["plugin_name"]
+ except (AttributeError, TypeError):
+ plugin_name = plugin
+ _data[plugin].yaml_set_start_comment(plugin_name, indent=2)
+ # 初始化未设置的管理员权限等级
+ for k, v in Config.get_admin_level_data():
+ admin_manager.set_admin_level(k, v)
+ # 存完插件基本设置
+ with open(plugins2config_file, "w", encoding="utf8") as wf:
+ round_trip_dump(
+ _data, wf, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
+ )
+ # 再开始读取用户配置
+ user_config_file = Path() / "configs" / "config.yaml"
+ _data = {}
+ _tmp_data = {}
+ if user_config_file.exists():
+ with open(user_config_file, "r", encoding="utf8") as f:
+ _data = _yaml.load(f)
+ for plugin in Config.keys():
+ _tmp_data[plugin] = {}
+ for k in Config[plugin].keys():
+ if _data.get(plugin) and k in _data[plugin].keys():
+ Config.set_config(plugin, k, _data[plugin][k])
+ _tmp_data[plugin][k] = Config.get_config(plugin, k)
+ Config.save()
+ temp_file = Path() / "configs" / "temp_config.yaml"
+ try:
+ with open(temp_file, "w", encoding="utf8") as wf:
+ yaml.dump(
+ _tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
+ )
+ with open(temp_file, "r", encoding="utf8") as rf:
+ _data = round_trip_load(rf)
+ # 添加注释
+ for plugin in _data.keys():
+ rst = ""
+ plugin_name = None
+ try:
+ plugin_data = Config.get(plugin)
+ for x in list(Config.get(plugin).keys()):
+ try:
+ _x = plugin_data[x].get("name")
+ if _x:
+ plugin_name = _x
+ except AttributeError:
+ pass
+ except (KeyError, AttributeError):
+ plugin_name = None
+ if not plugin_name:
+ try:
+ plugin_name = plugins_manager.get(plugin)["plugin_name"]
+ except (AttributeError, TypeError):
+ plugin_name = plugin
+ plugin_name = (
+ plugin_name.replace("[Hidden]", "")
+ .replace("[Superuser]", "")
+ .replace("[Admin]", "")
+ .strip()
+ )
+ rst += plugin_name + "\n"
+ for k in _data[plugin].keys():
+ rst += f'{k}: {Config[plugin][k]["help"]}' + "\n"
+ _data[plugin].yaml_set_start_comment(rst[:-1], indent=2)
+ with open(Path() / "configs" / "config.yaml", "w", encoding="utf8") as wf:
+ round_trip_dump(
+ _data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
+ )
+ except Exception as e:
+ logger.error(f"生成简易配置注释错误 {type(e)}:{e}")
+ if temp_file.exists():
+ temp_file.unlink()
diff --git a/basic_plugins/init_plugin_config/init_plugins_data.py b/basic_plugins/init_plugin_config/init_plugins_data.py
new file mode 100644
index 00000000..e90d5238
--- /dev/null
+++ b/basic_plugins/init_plugin_config/init_plugins_data.py
@@ -0,0 +1,82 @@
+from pathlib import Path
+from ruamel.yaml import YAML
+from utils.manager import plugins_manager
+from utils.utils import get_matchers
+import nonebot
+
+try:
+ import ujson as json
+except ModuleNotFoundError:
+ import json
+
+
+_yaml = YAML(typ="safe")
+
+
+def init_plugins_data(data_path):
+ """
+ 初始化插件数据信息
+ """
+ plugin2data_file = Path(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)
+ try:
+ _module = _plugin.module
+ except AttributeError:
+ if matcher.module not in _data.keys():
+ plugins_manager.add_plugin_data(
+ matcher.module, matcher.module, error=True
+ )
+ else:
+ plugins_manager.set_module_data(matcher.module, "error", True)
+ plugin_data = plugins_manager.get(matcher.module)
+ if plugin_data:
+ plugins_manager.set_module_data(
+ matcher.module, "version", plugin_data.get("version")
+ )
+ else:
+ try:
+ plugin_version = _module.__getattribute__("__plugin_version__")
+ except AttributeError:
+ plugin_version = None
+ try:
+ plugin_name = _module.__getattribute__("__zx_plugin_name__")
+ except AttributeError:
+ plugin_name = matcher.module
+ 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():
+ plugins_manager.add_plugin_data(
+ matcher.module,
+ plugin_name=plugin_name,
+ author=plugin_author,
+ version=plugin_version,
+ )
+ elif plugins_manager[matcher.module]["version"] is None or (
+ plugin_version is not None
+ and plugin_version > plugins_manager[matcher.module]["version"]
+ ):
+ plugins_manager.set_module_data(
+ matcher.module, "plugin_name", plugin_name
+ )
+ plugins_manager.set_module_data(matcher.module, "author", plugin_author)
+ plugins_manager.set_module_data(
+ matcher.module, "version", plugin_version
+ )
+ if matcher.module in _data.keys():
+ plugins_manager.set_module_data(
+ matcher.module, "error", _data[matcher.module]["error"]
+ )
+ plugins_manager.set_module_data(
+ matcher.module, "plugin_name", _data[matcher.module]["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
new file mode 100644
index 00000000..459f747c
--- /dev/null
+++ b/basic_plugins/init_plugin_config/init_plugins_limit.py
@@ -0,0 +1,157 @@
+from pathlib import Path
+from ruamel.yaml import round_trip_load, round_trip_dump, YAML
+from utils.manager import (
+ plugins2cd_manager,
+ plugins2block_manager,
+ plugins2count_manager,
+)
+from utils.utils import get_matchers
+from ruamel import yaml
+import nonebot
+
+
+_yaml = YAML(typ="safe")
+
+
+def init_plugins_cd_limit(data_path):
+ """
+ 加载 cd 限制
+ """
+ plugins2cd_file = Path(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)
+ try:
+ _module = _plugin.module
+ plugin_cd_limit = _module.__getattribute__("__plugin_cd_limit__")
+ plugins2cd_manager.add_cd_limit(
+ matcher.module, data_dict=plugin_cd_limit
+ )
+ except AttributeError:
+ pass
+ if not plugins2cd_manager.keys():
+ plugins2cd_manager.add_cd_limit(
+ "这是一个示例"
+ )
+ _tmp_data = {"PluginCdLimit": plugins2cd_manager.get_data()}
+ with open(plugins2cd_file, "w", encoding="utf8") as wf:
+ yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
+ _data = round_trip_load(open(plugins2cd_file, encoding="utf8"))
+ _data["PluginCdLimit"].yaml_set_start_comment(
+ """# 需要cd的功能
+# 自定义的功能需要cd也可以在此配置
+# key:模块名称
+# cd:cd 时长(秒)
+# status:此限制的开关状态
+# check_type:'private'/'group'/'all',限制私聊/群聊/全部
+# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
+# 示例:'user':用户N秒内触发1次,'group':群N秒内触发1次
+# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
+# rst 为 "" 或 None 时则不回复
+# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
+# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
+# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
+ indent=2,
+ )
+ with open(plugins2cd_file, "w", encoding="utf8") as wf:
+ round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
+ plugins2cd_manager.reload_cd_limit()
+
+
+def init_plugins_block_limit(data_path):
+ """
+ 加载阻塞限制
+ """
+ plugins2block_file = Path(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)
+ try:
+ _module = _plugin.module
+ plugin_block_limit = _module.__getattribute__("__plugin_block_limit__")
+ plugins2block_manager.add_block_limit(
+ matcher.module, data_dict=plugin_block_limit
+ )
+ except AttributeError:
+ pass
+ if not plugins2block_manager.keys():
+ plugins2block_manager.add_block_limit(
+ "这是一个示例"
+ )
+ _tmp_data = {"PluginBlockLimit": plugins2block_manager.get_data()}
+ with open(plugins2block_file, "w", encoding="utf8") as wf:
+ yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
+ _data = round_trip_load(open(plugins2block_file, encoding="utf8"))
+ _data["PluginBlockLimit"].yaml_set_start_comment(
+ """# 用户调用阻塞
+# 即 当用户调用此功能还未结束时
+# 用发送消息阻止用户重复调用此命令直到该命令结束
+# key:模块名称
+# status:此限制的开关状态
+# check_type:'private'/'group'/'all',限制私聊/群聊/全部
+# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
+# 示例:'user':阻塞用户,'group':阻塞群聊
+# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
+# rst 为 "" 或 None 时则不回复
+# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
+# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
+# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
+ indent=2,
+ )
+ with open(plugins2block_file, "w", encoding="utf8") as wf:
+ round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
+ plugins2block_manager.reload_block_limit()
+
+
+def init_plugins_count_limit(data_path):
+ """
+ 加载次数限制
+ """
+ plugins2count_file = Path(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)
+ try:
+ _module = _plugin.module
+ plugin_count_limit = _module.__getattribute__("__plugin_count_limit__")
+ plugins2count_manager.add_count_limit(
+ matcher.module, data_dict=plugin_count_limit
+ )
+ except AttributeError:
+ pass
+ if not plugins2count_manager.keys():
+ plugins2count_manager.add_count_limit(
+ "这是一个示例"
+ )
+ _tmp_data = {"PluginCountLimit": plugins2count_manager.get_data()}
+ with open(plugins2count_file, "w", encoding="utf8") as wf:
+ yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
+ _data = round_trip_load(open(plugins2count_file, encoding="utf8"))
+ _data["PluginCountLimit"].yaml_set_start_comment(
+ """# 命令每日次数限制
+# 即 用户/群聊 每日可调用命令的次数 [数据内存存储,重启将会重置]
+# 每日调用直到 00:00 刷新
+# key:模块名称
+# max_count: 每日调用上限
+# status:此限制的开关状态
+# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
+# 示例:'user':用户上限,'group':群聊上限
+# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
+# rst 为 "" 或 None 时则不回复
+# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
+# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
+# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
+ indent=2,
+ )
+ with open(plugins2count_file, "w", encoding="utf8") as wf:
+ round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
+ plugins2count_manager.reload_count_limit()
diff --git a/basic_plugins/init_plugin_config/init_plugins_resources.py b/basic_plugins/init_plugin_config/init_plugins_resources.py
new file mode 100644
index 00000000..36e2f47b
--- /dev/null
+++ b/basic_plugins/init_plugin_config/init_plugins_resources.py
@@ -0,0 +1,43 @@
+from utils.manager import resources_manager
+from utils.utils import get_matchers
+from services.log import logger
+from pathlib import Path
+import nonebot
+
+
+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)
+ try:
+ _module = _plugin.module
+ except AttributeError:
+ logger.warning(f"插件 {matcher.module} 加载失败...,资源控制未加载...")
+ else:
+ try:
+ resources = _module.__getattribute__("__plugin_resources__")
+ except AttributeError:
+ pass
+ 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.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
new file mode 100644
index 00000000..c1ec6c11
--- /dev/null
+++ b/basic_plugins/init_plugin_config/init_plugins_settings.py
@@ -0,0 +1,130 @@
+from pathlib import Path
+from ruamel.yaml import round_trip_load, round_trip_dump, YAML
+from utils.manager import plugins2settings_manager, admin_manager
+from services.log import logger
+from utils.utils import get_matchers
+from ruamel import yaml
+import nonebot
+
+
+_yaml = YAML(typ="safe")
+
+
+def init_plugins_settings(data_path: str):
+ """
+ 初始化插件设置,从插件中获取 __zx_plugin_name__,__plugin_cmd__,__plugin_settings__
+ """
+ plugins2settings_file = Path(data_path) / "configs" / "plugins2settings.yaml"
+ plugins2settings_file.parent.mkdir(exist_ok=True, parents=True)
+ _matchers = get_matchers()
+ _data = {}
+ if plugins2settings_file.exists():
+ with open(plugins2settings_file, "r", encoding="utf8") as f:
+ _data = _yaml.load(f)
+ _data = _data["PluginSettings"] if _data else {}
+ _tmp_module = {}
+ _tmp = []
+ for matcher in _matchers:
+ if matcher.module in _data.keys():
+ plugins2settings_manager.add_plugin_settings(
+ matcher.module,
+ plugin_type=_data[matcher.module]["plugin_type"],
+ data_dict=_data[matcher.module],
+ )
+ if _data[matcher.module]["cmd"]:
+ _tmp_module[matcher.module] = _data[matcher.module]["cmd"][0]
+ else:
+ _plugin = nonebot.plugin.get_plugin(matcher.module)
+ try:
+ _module = _plugin.module
+ except AttributeError:
+ logger.warning(f"插件 {matcher.module} 加载失败...,插件控制未加载.")
+ else:
+ try:
+ plugin_name = _module.__getattribute__("__zx_plugin_name__")
+ if "[admin]" in plugin_name.lower():
+ try:
+ admin_settings = _module.__getattribute__(
+ "__plugin_settings__"
+ )
+ level = admin_settings["admin_level"]
+ cmd = admin_settings.get("cmd")
+ except (AttributeError, KeyError):
+ level = 5
+ cmd = None
+ if not level:
+ level = 5
+ admin_manager.add_admin_plugin_settings(
+ matcher.module, 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()
+ ):
+ continue
+ except AttributeError:
+ if matcher.module not in _tmp:
+ logger.warning(
+ f"获取插件 {matcher.module} __zx_plugin_name__ 失败...,插件控制未加载."
+ )
+ else:
+ try:
+ _tmp_module[matcher.module] = plugin_name
+ plugin_settings = _module.__getattribute__(
+ "__plugin_settings__"
+ )
+ if (
+ plugin_settings["cmd"]
+ and plugin_name not in plugin_settings["cmd"]
+ ):
+ plugin_settings["cmd"].append(plugin_name)
+ if plugins2settings_manager.get(
+ matcher.module
+ ) and plugins2settings_manager[matcher.module].get(
+ "plugin_type"
+ ):
+ plugin_type = tuple(
+ plugins2settings_manager.get_plugin_data(
+ matcher.module
+ )["plugin_type"]
+ )
+ else:
+ try:
+ plugin_type = _module.__getattribute__(
+ "__plugin_type__"
+ )
+ except AttributeError:
+ plugin_type = ("normal",)
+ if plugin_settings and matcher.module:
+ plugins2settings_manager.add_plugin_settings(
+ matcher.module,
+ plugin_type=plugin_type,
+ data_dict=plugin_settings,
+ )
+ except AttributeError:
+ pass
+ _tmp.append(matcher.module)
+ _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)
+ _data = round_trip_load(open(plugins2settings_file, encoding="utf8"))
+ _data["PluginSettings"].yaml_set_start_comment(
+ """# 模块与对应命令和对应群权限
+# 用于生成帮助图片 和 开关功能
+# key:模块名称
+# level:需要的群等级
+# default_status:加入群时功能的默认开关状态
+# limit_superuser: 功能状态是否限制超级用户
+# cmd: 关闭[cmd] 都会触发命令 关闭对应功能,cmd列表第一个词为统计的功能名称
+# plugin_type: 帮助类别 示例:('原神相关',) 或 ('原神相关', 1),1代表帮助命令列向排列,否则为横向排列""",
+ indent=2,
+ )
+ for plugin in _data["PluginSettings"].keys():
+ _data["PluginSettings"][plugin].yaml_set_start_comment(
+ f"{plugin}:{_tmp_module[plugin]}", indent=2
+ )
+ with open(plugins2settings_file, "w", encoding="utf8") as wf:
+ round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
+ logger.info(f"已成功加载 {len(plugins2settings_manager.get_data())} 个非限制插件.")
diff --git a/plugins/nickname.py b/basic_plugins/nickname.py
similarity index 97%
rename from plugins/nickname.py
rename to basic_plugins/nickname.py
index f06018b8..75e497d4 100644
--- a/plugins/nickname.py
+++ b/basic_plugins/nickname.py
@@ -1,194 +1,194 @@
-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
-
-
-__zx_plugin_name__ = "昵称系统"
-__plugin_usage__ = f"""
-usage:
- 个人昵称系统,群聊 与 私聊 昵称相互独立
- 指令:
- 以后叫我 [昵称]
- {NICKNAME}我是谁
-""".strip()
-__plugin_des__ = "区区昵称,才不想叫呢!"
-__plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁"]
-__plugin_version__ = 0.1
-__plugin_author__ = "HibiKier"
-
-nickname = on_command(
- "nickname",
- aliases={"以后叫我", "以后请叫我", "称呼我", "以后请称呼我", "以后称呼我", "叫我", "请叫我"},
- rule=to_me(),
- priority=5,
- block=True,
-)
-
-my_nickname = on_command(
- "my_name", aliases={"我叫什么", "我是谁", "我的名字"}, rule=to_me(), priority=5, block=True
-)
-
-
-cancel_nickname = on_command("取消昵称", rule=to_me(), priority=5, block=True)
-
-
-@nickname.handle()
-async def _(bot: Bot, event: GroupMessageEvent, 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 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}了.",
- ]
- )
- )
- 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} 失败")
-
-
-@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}了.",
- ]
- )
- )
- 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()
-async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
- try:
- nickname_ = await GroupInfoUser.get_group_member_nickname(
- event.user_id, event.group_id
- )
- except AttributeError:
- nickname_ = ""
- if nickname_:
- await my_nickname.send(
- random.choice(
- [
- f"我肯定记得你啊,你是{nickname_}啊",
- f"我不会忘记你的,你也不要忘记我!{nickname_}",
- f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
- f"嗯?你是失忆了嘛...{nickname_}..",
- f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ",
- f"哎?{nickname_}..怎么了吗..突然这样问..",
- ]
- )
- )
- else:
- nickname_ = event.sender.card if event.sender.card else event.sender.nickname
- await my_nickname.send(
- random.choice(
- ["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"]
- ).format(nickname_)
- )
-
-
-@my_nickname.handle()
-async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
- nickname_ = await FriendUser.get_friend_nickname(event.user_id)
- if nickname_:
- await my_nickname.send(
- random.choice(
- [
- f"我肯定记得你啊,你是{nickname_}啊",
- f"我不会忘记你的,你也不要忘记我!{nickname_}",
- f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
- f"嗯?你是失忆了嘛...{nickname_}..",
- f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ",
- f"哎?{nickname_}..怎么了吗..突然这样问..",
- ]
- )
- )
- else:
- nickname_ = (await bot.get_stranger_info(user_id=event.user_id))["nickname"]
- await my_nickname.send(
- random.choice(
- ["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"]
- ).format(nickname_)
- )
-
-
-@cancel_nickname.handle()
-async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
- nickname_ = await GroupInfoUser.get_group_member_nickname(
- event.user_id, event.group_id
- )
- if nickname_:
- await cancel_nickname.send(
- random.choice(
- [
- f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
- f"窝知道了..{nickname_}..",
- f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
- f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
- f"可..可恶!{nickname_}!太可恶了!呜",
- ]
- )
- )
- await GroupInfoUser.set_group_member_nickname(event.user_id, event.group_id, "")
- await BanUser.ban(event.user_id, 9, 60)
- else:
- await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)
-
-
-@cancel_nickname.handle()
-async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
- nickname_ = await FriendUser.get_friend_nickname(event.user_id)
- if nickname_:
- await cancel_nickname.send(
- random.choice(
- [
- f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
- f"窝知道了..{nickname_}..",
- f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
- f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
- f"可..可恶!{nickname_}!太可恶了!呜",
- ]
- )
- )
- await FriendUser.get_user_name(event.user_id)
- await BanUser.ban(event.user_id, 9, 60)
- else:
- await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)
+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
+
+
+__zx_plugin_name__ = "昵称系统"
+__plugin_usage__ = f"""
+usage:
+ 个人昵称系统,群聊 与 私聊 昵称相互独立
+ 指令:
+ 以后叫我 [昵称]
+ {NICKNAME}我是谁
+""".strip()
+__plugin_des__ = "区区昵称,才不想叫呢!"
+__plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁"]
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+
+nickname = on_command(
+ "nickname",
+ aliases={"以后叫我", "以后请叫我", "称呼我", "以后请称呼我", "以后称呼我", "叫我", "请叫我"},
+ rule=to_me(),
+ priority=5,
+ block=True,
+)
+
+my_nickname = on_command(
+ "my_name", aliases={"我叫什么", "我是谁", "我的名字"}, rule=to_me(), priority=5, block=True
+)
+
+
+cancel_nickname = on_command("取消昵称", rule=to_me(), priority=5, block=True)
+
+
+@nickname.handle()
+async def _(bot: Bot, event: GroupMessageEvent, 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 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}了.",
+ ]
+ )
+ )
+ 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} 失败")
+
+
+@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}了.",
+ ]
+ )
+ )
+ 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()
+async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
+ try:
+ nickname_ = await GroupInfoUser.get_group_member_nickname(
+ event.user_id, event.group_id
+ )
+ except AttributeError:
+ nickname_ = ""
+ if nickname_:
+ await my_nickname.send(
+ random.choice(
+ [
+ f"我肯定记得你啊,你是{nickname_}啊",
+ f"我不会忘记你的,你也不要忘记我!{nickname_}",
+ f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
+ f"嗯?你是失忆了嘛...{nickname_}..",
+ f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ",
+ f"哎?{nickname_}..怎么了吗..突然这样问..",
+ ]
+ )
+ )
+ else:
+ nickname_ = event.sender.card if event.sender.card else event.sender.nickname
+ await my_nickname.send(
+ random.choice(
+ ["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"]
+ ).format(nickname_)
+ )
+
+
+@my_nickname.handle()
+async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
+ nickname_ = await FriendUser.get_friend_nickname(event.user_id)
+ if nickname_:
+ await my_nickname.send(
+ random.choice(
+ [
+ f"我肯定记得你啊,你是{nickname_}啊",
+ f"我不会忘记你的,你也不要忘记我!{nickname_}",
+ f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}",
+ f"嗯?你是失忆了嘛...{nickname_}..",
+ f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ",
+ f"哎?{nickname_}..怎么了吗..突然这样问..",
+ ]
+ )
+ )
+ else:
+ nickname_ = (await bot.get_stranger_info(user_id=event.user_id))["nickname"]
+ await my_nickname.send(
+ random.choice(
+ ["没..没有昵称嘛,{}", "啊,你是{}啊,我想叫你的昵称!", "是{}啊,有什么事吗?", "你是{}?"]
+ ).format(nickname_)
+ )
+
+
+@cancel_nickname.handle()
+async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
+ nickname_ = await GroupInfoUser.get_group_member_nickname(
+ event.user_id, event.group_id
+ )
+ if nickname_:
+ await cancel_nickname.send(
+ random.choice(
+ [
+ f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
+ f"窝知道了..{nickname_}..",
+ f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
+ f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
+ f"可..可恶!{nickname_}!太可恶了!呜",
+ ]
+ )
+ )
+ await GroupInfoUser.set_group_member_nickname(event.user_id, event.group_id, "")
+ await BanUser.ban(event.user_id, 9, 60)
+ else:
+ await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)
+
+
+@cancel_nickname.handle()
+async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
+ nickname_ = await FriendUser.get_friend_nickname(event.user_id)
+ if nickname_:
+ await cancel_nickname.send(
+ random.choice(
+ [
+ f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}",
+ f"窝知道了..{nickname_}..",
+ f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}",
+ f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!",
+ f"可..可恶!{nickname_}!太可恶了!呜",
+ ]
+ )
+ )
+ await FriendUser.get_user_name(event.user_id)
+ await BanUser.ban(event.user_id, 9, 60)
+ else:
+ await cancel_nickname.send("你在做梦吗?你没有昵称啊", at_sender=True)
diff --git a/basic_plugins/scripts.py b/basic_plugins/scripts.py
new file mode 100644
index 00000000..2a8879e6
--- /dev/null
+++ b/basic_plugins/scripts.py
@@ -0,0 +1,111 @@
+from nonebot import Driver
+from services.db_context import db
+from asyncpg.exceptions import DuplicateColumnError
+from models.group_info import GroupInfo
+from nonebot.adapters.cqhttp import Bot
+from utils.user_agent import get_user_agent
+from services.log import logger
+from configs.path_config import TEXT_PATH
+from asyncio.exceptions import TimeoutError
+from pathlib import Path
+import aiohttp
+import nonebot
+
+try:
+ import ujson as json
+except ModuleNotFoundError:
+ import json
+
+
+driver: Driver = nonebot.get_driver()
+
+
+@driver.on_startup
+async def update_city():
+ """
+ 部分插件需要中国省份城市
+ 这里直接更新,避免插件内代码重复
+ :return:
+ """
+ china_city = Path(TEXT_PATH) / "china_city.json"
+ data = {}
+ try:
+ async with aiohttp.ClientSession(headers=get_user_agent()) as session:
+ async with session.get(
+ "http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
+ ) as res:
+ provinces_data = json.loads(await res.text(encoding="utf8"))
+ for province in provinces_data.keys():
+ data[provinces_data[province]] = []
+ async with session.get(
+ f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
+ timeout=5,
+ ) as res:
+ city_data = json.loads(await res.text(encoding="utf8"))
+ for city in city_data.keys():
+ data[provinces_data[province]].append(city_data[city])
+ with open(china_city, "w", encoding="utf8") as f:
+ json.dump(data, f, indent=4, ensure_ascii=False)
+ logger.info("自动更新城市列表完成.....")
+ except TimeoutError:
+ logger.info("自动更新城市列表超时.....")
+
+
+@driver.on_startup
+async def _():
+ """
+ 数据库表结构变换
+ """
+ sql_str = [
+ "ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;" # group_info表添加一个group_flag
+ ]
+ for sql in sql_str:
+ try:
+ query = db.text(sql)
+ await db.first(query)
+ except DuplicateColumnError:
+ pass
+
+
+@driver.on_bot_connect
+async def _(bot: Bot):
+ """
+ 版本某些需要的变换
+ """
+ # 清空不存在的群聊信息,并将已所有已存在的群聊group_flag设置为1(认证所有已存在的群)
+ if not await GroupInfo.get_group_info(114514):
+ # 标识符,该功能只需执行一次
+ await GroupInfo.add_group_info(
+ 114514,
+ "114514",
+ 114514,
+ 114514,
+ 1
+ )
+ group_list = await bot.get_group_list()
+ group_list = [g["group_id"] for g in group_list]
+ _gl = [x.group_id for x in await GroupInfo.get_all_group()]
+ if 114514 in _gl:
+ _gl.remove(114514)
+ for group_id in _gl:
+ if group_id in group_list:
+ if await GroupInfo.get_group_info(group_id):
+ await GroupInfo.set_group_flag(group_id, 1)
+ else:
+ group_info = await bot.get_group_info(group_id=group_id)
+ await GroupInfo.add_group_info(
+ group_info["group_id"],
+ group_info["group_name"],
+ group_info["max_member_count"],
+ group_info["member_count"],
+ 1
+ )
+ logger.info(f"已将群聊 {group_id} 添加认证...")
+ else:
+ await GroupInfo.delete_group_info(group_id)
+ logger.info(f"移除不存在的群聊信息:{group_id}")
+
+
+
+
+
diff --git a/basic_plugins/super_cmd/__init__.py b/basic_plugins/super_cmd/__init__.py
new file mode 100644
index 00000000..b4997936
--- /dev/null
+++ b/basic_plugins/super_cmd/__init__.py
@@ -0,0 +1,10 @@
+import nonebot
+
+
+nonebot.load_plugins('basic_plugins/super_cmd')
+
+
+
+
+
+
diff --git a/basic_plugins/super_cmd/bot_friend_group.py b/basic_plugins/super_cmd/bot_friend_group.py
new file mode 100644
index 00000000..def933c8
--- /dev/null
+++ b/basic_plugins/super_cmd/bot_friend_group.py
@@ -0,0 +1,152 @@
+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.rule import to_me
+from utils.utils import get_message_text, is_number
+from utils.manager import requests_manager
+from utils.message_builder import image
+from models.group_info import GroupInfo
+
+
+__zx_plugin_name__ = "显示所有好友群组 [Superuser]"
+__plugin_usage__ = """
+usage:
+ 显示所有好友群组
+ 指令:
+ 查看所有好友/查看所有群组
+ 同意好友请求 [id]
+ 拒绝好友请求 [id]
+ 同意群聊请求 [id]
+ 拒绝群聊请求 [id]
+ 查看所有请求
+ 清空所有请求
+""".strip()
+__plugin_des__ = "显示所有好友群组"
+__plugin_cmd__ = [
+ "查看所有好友/查看所有群组",
+ "同意好友请求 [id]",
+ "拒绝好友请求 [id]",
+ "同意群聊请求 [id]",
+ "拒绝群聊请求 [id]",
+ "查看所有请求",
+ "清空所有请求",
+]
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+
+
+cls_group = on_command(
+ "查看所有群组", rule=to_me(), permission=SUPERUSER, priority=1, block=True
+)
+cls_friend = on_command(
+ "查看所有好友", rule=to_me(), permission=SUPERUSER, priority=1, block=True
+)
+
+friend_handle = on_command(
+ "同意好友请求", aliases={"拒绝好友请求"}, permission=SUPERUSER, priority=1, block=True
+)
+
+group_handle = on_command(
+ "同意群聊请求", aliases={"拒绝群聊请求"}, permission=SUPERUSER, priority=1, block=True
+)
+
+clear_request = on_command("清空所有请求", permission=SUPERUSER, priority=1, block=True)
+
+cls_request = on_command("查看所有请求", permission=SUPERUSER, priority=1, block=True)
+
+
+@cls_group.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ gl = await bot.get_group_list(self_id=int(bot.self_id))
+ 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,
+ )
+
+
+@cls_friend.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ gl = await bot.get_friend_list(self_id=int(bot.self_id))
+ 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,
+ )
+
+
+@friend_handle.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ id_ = get_message_text(event.json())
+ if is_number(id_):
+ id_ = int(id_)
+ if state["_prefix"]["raw_command"][:2] == "同意":
+ if await requests_manager.approve(bot, id_, "private"):
+ await friend_handle.send("同意好友请求成功..")
+ else:
+ await friend_handle.send("同意好友请求失败,可能是未找到此id的请求..")
+ else:
+ if await requests_manager.refused(bot, id_, "private"):
+ await friend_handle.send("拒绝好友请求成功..")
+ else:
+ await friend_handle.send("拒绝好友请求失败,可能是未找到此id的请求..")
+ else:
+ await friend_handle.send("id必须为纯数字!")
+
+
+@group_handle.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ id_ = get_message_text(event.json())
+ if is_number(id_):
+ id_ = int(id_)
+ if state["_prefix"]["raw_command"][:2] == "同意":
+ rid = await requests_manager.approve(bot, id_, "group")
+ if rid:
+ await friend_handle.send("同意群聊请求成功..")
+ if await GroupInfo.get_group_info(rid):
+ await GroupInfo.set_group_flag(rid, 1)
+ else:
+ group_info = await bot.get_group_info(group_id=rid)
+ await GroupInfo.add_group_info(
+ rid,
+ group_info["group_name"],
+ group_info["max_member_count"],
+ group_info["member_count"],
+ 1
+ )
+ else:
+ await friend_handle.send("同意群聊请求失败,可能是未找到此id的请求..")
+ else:
+ if await requests_manager.refused(bot, id_, "group"):
+ await friend_handle.send("拒绝群聊请求成功..")
+ else:
+ await friend_handle.send("拒绝群聊请求失败,可能是未找到此id的请求..")
+ else:
+ await friend_handle.send("id必须为纯数字!")
+
+
+@cls_request.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ _str = ""
+ for type_ in ["private", "group"]:
+ msg = await requests_manager.show(type_)
+ if msg:
+ _str += image(b64=msg)
+ else:
+ _str += "没有任何好友请求.." if type_ == "private" else "没有任何群聊请求.."
+ if type_ == "private":
+ _str += '\n--------------------\n'
+ await cls_request.send(Message(_str))
+
+
+@clear_request.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ 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
new file mode 100644
index 00000000..b77237ad
--- /dev/null
+++ b/basic_plugins/super_cmd/clear_data.py
@@ -0,0 +1,67 @@
+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
+from services.log import logger
+from utils.manager import resources_manager
+import asyncio
+import time
+import os
+
+__zx_plugin_name__ = "清理临时数据 [Superuser]"
+__plugin_usage__ = """
+usage:
+ 清理临时数据
+ 指令:
+ 清理临时数据
+""".strip()
+__plugin_des__ = "清理临时数据"
+__plugin_cmd__ = [
+ "清理临时数据",
+]
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+
+
+clear_data = on_command(
+ "清理临时数据", rule=to_me(), permission=SUPERUSER, priority=1, block=True
+)
+
+
+resources_manager.add_temp_dir(TEMP_PATH)
+
+
+@clear_data.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ 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))
+
+
+def _clear_data() -> float:
+ size = 0
+ for dir_ in resources_manager.get_temp_data_dir():
+ 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}")
+ return float(size)
+
+
+@scheduler.scheduled_job(
+ "cron",
+ hour=1,
+ minute=1,
+)
+async def _():
+ size = await asyncio.get_event_loop().run_in_executor(None, _clear_data)
+ logger.info("自动清理临时数据完成," + "共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
diff --git a/plugins/super_cmd/data_source.py b/basic_plugins/super_cmd/data_source.py
similarity index 97%
rename from plugins/super_cmd/data_source.py
rename to basic_plugins/super_cmd/data_source.py
index 53244823..86c06db0 100644
--- a/plugins/super_cmd/data_source.py
+++ b/basic_plugins/super_cmd/data_source.py
@@ -1,74 +1,74 @@
-
-
-# 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
+
+
+# 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/plugins/group_manager/__init__.py b/basic_plugins/super_cmd/manager_group.py
similarity index 57%
rename from plugins/group_manager/__init__.py
rename to basic_plugins/super_cmd/manager_group.py
index b7d73855..36d4fb56 100644
--- a/plugins/group_manager/__init__.py
+++ b/basic_plugins/super_cmd/manager_group.py
@@ -1,34 +1,45 @@
from nonebot import on_command, on_regex
-from utils.utils import get_message_text, is_number
-from nonebot.rule import to_me
-from services.log import logger
-from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent, GROUP
-from nonebot.typing import T_State
from nonebot.permission import SUPERUSER
-from configs.config import NICKNAME
+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.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
-try:
- import ujson as json
-except ModuleNotFoundError:
- import json
-__zx_plugin_name__ = "群权限操作 [Superuser]"
+__zx_plugin_name__ = "管理群操作 [Superuser]"
__plugin_usage__ = """
usage:
- 对群权限 | 群白名单 的操作
+ 群权限 | 群白名单 | 退出群 操作
指令:
- 修改群权限 [group] [等级]
- 添加群白名单 *[group]
- 删除群白名单 *[group]
+ 退群 [group_id]
+ 修改群权限 [group_id] [等级]
+ 添加群白名单 *[group_id]
+ 删除群白名单 *[group_id]
+ 添加群认证 *[group_id]
+ 删除群认证 *[group_id]
查看群白名单
""".strip()
-__plugin_des__ = "对群权限 | 群白名单 的操作"
-__plugin_cmd__ = ["修改群权限 [group] [等级]", "添加群白名单 *[group]", "删除群白名单 *[group]", "查看群白名单"]
+__plugin_des__ = "管理群操作"
+__plugin_cmd__ = [
+ "退群 [group_id]",
+ "修改群权限 [group_id] [等级]",
+ "添加群白名单 *[group_id]",
+ "删除群白名单 *[group_id]",
+ "添加群认证 *[group_id]",
+ "删除群认证 *[group_id]",
+ "查看群白名单",
+]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
+del_group = on_command("退群", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
+
add_group_level = on_command("修改群权限", priority=1, permission=SUPERUSER, block=True)
my_group_level = on_command(
"查看群权限", aliases={"群权限"}, priority=5, permission=GROUP, block=True
@@ -40,7 +51,6 @@ what_up_group_level = on_regex(
permission=GROUP,
block=True,
)
-
manager_group_whitelist = on_command(
"添加群白名单", aliases={"删除群白名单"}, priority=1, permission=SUPERUSER, block=True
)
@@ -49,6 +59,29 @@ show_group_whitelist = on_command(
"查看群白名单", priority=1, permission=SUPERUSER, block=True
)
+group_auth = on_command(
+ "添加群认证", aliases={"删除群认证"}, priority=1, permission=SUPERUSER, block=True
+)
+
+
+@del_group.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ group_id = get_message_text(event.json())
+ if group_id:
+ if is_number(group_id):
+ try:
+ await bot.set_group_leave(group_id=int(group_id))
+ logger.info(f"退出群聊 {group_id} 成功")
+ await del_group.send(f"退出群聊 {group_id} 成功", at_sender=True)
+ group_manager.delete_group(int(group_id))
+ await GroupInfo.delete_group_info(int(group_id))
+ except Exception as e:
+ logger.info(f"退出群聊 {group_id} 失败 e:{e}")
+ else:
+ await del_group.finish(f"请输入正确的群号", at_sender=True)
+ else:
+ await del_group.finish(f"请输入群号", at_sender=True)
+
@add_group_level.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
@@ -130,3 +163,38 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
await show_group_whitelist.send("目前的群白名单:\n" + "\n".join(x))
else:
await show_group_whitelist.send("没有任何群在群白名单...")
+
+
+@group_auth.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ msg = get_message_text(event.json()).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 await GroupInfo.get_group_info(group_id):
+ await GroupInfo.set_group_flag(group_id, 1)
+ else:
+ try:
+ group_info = await bot.get_group_info(group_id=group_id)
+ except ActionFailed:
+ group_info = {
+ "group_id": group_id,
+ "group_name": "_",
+ "max_member_count": -1,
+ "member_count": -1,
+ }
+ await GroupInfo.add_group_info(
+ group_info["group_id"],
+ group_info["group_name"],
+ group_info["max_member_count"],
+ group_info["member_count"],
+ 1,
+ )
+ else:
+ 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]}群认证..'
+ )
diff --git a/basic_plugins/super_cmd/reload_setting.py b/basic_plugins/super_cmd/reload_setting.py
new file mode 100644
index 00000000..b392f913
--- /dev/null
+++ b/basic_plugins/super_cmd/reload_setting.py
@@ -0,0 +1,40 @@
+from nonebot import on_command
+from nonebot.permission import SUPERUSER
+from nonebot.rule import to_me
+from utils.manager import (
+ plugins2cd_manager,
+ plugins2settings_manager,
+ plugins2block_manager,
+ group_manager,
+)
+from nonebot.typing import T_State
+from nonebot.adapters.cqhttp import Bot, MessageEvent
+
+
+__zx_plugin_name__ = "重载插件配置 [Superuser]"
+__plugin_usage__ = """
+usage:
+ 重载插件配置
+ 指令:
+ 重载插件配置
+""".strip()
+__plugin_des__ = "重载插件配置"
+__plugin_cmd__ = [
+ "重载插件配置",
+]
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+
+
+reload_plugins_manager = on_command(
+ "重载插件限制", rule=to_me(), permission=SUPERUSER, priority=1, block=True
+)
+
+
+@reload_plugins_manager.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ plugins2settings_manager.reload()
+ plugins2cd_manager.reload()
+ plugins2block_manager.reload()
+ group_manager.reload()
+ await reload_plugins_manager.send("重载完成...")
diff --git a/basic_plugins/super_cmd/set_admin_permissions.py b/basic_plugins/super_cmd/set_admin_permissions.py
new file mode 100644
index 00000000..f075dd94
--- /dev/null
+++ b/basic_plugins/super_cmd/set_admin_permissions.py
@@ -0,0 +1,89 @@
+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 services.log import logger
+from utils.message_builder import at
+
+__zx_plugin_name__ = "用户权限管理 [Superuser]"
+__plugin_usage__ = """
+usage:
+ 增删改用户的权限
+ 指令:
+ 添加权限 [at] [权限]
+ 添加权限 [qq] [group_id] [权限]
+ 删除权限 [at]
+""".strip()
+__plugin_des__ = "增删改用户的权限"
+__plugin_cmd__ = [
+ "添加权限 [at] [权限]",
+ "添加权限 [qq] [group_id] [权限]",
+ "删除权限 [at]",
+]
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+
+
+super_cmd = on_command(
+ "添加管理",
+ aliases={"删除管理", "添加权限", "删除权限"},
+ priority=1,
+ permission=SUPERUSER,
+ block=True,
+)
+
+
+@super_cmd.handle()
+async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
+ group_id = -1
+ level = 0
+ try:
+ args = get_message_text(event.json()).strip().split()
+ qq = get_message_at(event.json())
+ flag = -1
+ if not qq:
+ if len(args) > 2:
+ if is_number(args[0]) and is_number(args[1]) and is_number(args[2]):
+ qq = int(args[0])
+ group_id = int(args[1])
+ level = int(args[2])
+ flag = 1
+ else:
+ await super_cmd.finish("所有参数必须是数字!", at_sender=True)
+ else:
+ await super_cmd.finish(
+ "权限参数不完全\n\t格式:添加/删除权限 [at] [level]"
+ "\n\t格式:添加/删除权限 [qq] [group] [level]",
+ at_sender=True,
+ )
+ else:
+ qq = qq[0]
+ group_id = event.group_id
+ flag = 2
+ if state["_prefix"]["raw_command"][:2] == "添加":
+ if is_number(args[0]):
+ level = int(args[0])
+ else:
+ await super_cmd.finish("权限等级必须是数字!", at_sender=True)
+ if await LevelUser.set_level(qq, group_id, level, 1):
+ result = "添加管理成功, 权限: " + str(level)
+ else:
+ result = "管理已存在, 更新权限: " + str(level)
+ else:
+ if await LevelUser.delete_level(qq, event.group_id):
+ result = "删除管理成功!"
+ else:
+ result = "该账号无管理权限!"
+ if flag == 2:
+ await super_cmd.send(result)
+ elif flag == 1:
+ await bot.send_group_msg(
+ group_id=group_id,
+ message=Message(f"{at(qq)}管理员修改了你的权限" f"\n--------\n你当前的权限等级:{level}"),
+ )
+ await super_cmd.send("修改成功")
+ except Exception as e:
+ await super_cmd.send("执行指令失败!")
+ logger.error(f"执行指令失败 e:{e}")
diff --git a/basic_plugins/super_cmd/super_task_switch.py b/basic_plugins/super_cmd/super_task_switch.py
new file mode 100644
index 00000000..391d5778
--- /dev/null
+++ b/basic_plugins/super_cmd/super_task_switch.py
@@ -0,0 +1,56 @@
+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_message_text, is_number
+from services.log import logger
+from utils.manager import group_manager
+
+
+__zx_plugin_name__ = "超级用户被动开关 [Superuser]"
+__plugin_usage__ = """
+usage:
+ 超级用户被动开关
+ 指令:
+ 开启/关闭广播通知
+""".strip()
+__plugin_des__ = "超级用户被动开关"
+__plugin_cmd__ = [
+ "开启/关闭广播通知",
+]
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+
+
+oc_gb = on_command(
+ "开启广播通知",
+ aliases={"关闭广播通知"},
+ rule=to_me(),
+ permission=SUPERUSER,
+ priority=1,
+ block=True,
+)
+
+
+@oc_gb.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ group = get_message_text(event.json())
+ if group:
+ if is_number(group):
+ group = int(group)
+ for g in await bot.get_group_list():
+ if g["group_id"] == group:
+ break
+ else:
+ await oc_gb.finish("没有加入这个群...", at_sender=True)
+ if state["_prefix"]["raw_command"] == "开启广播通知":
+ 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:
+ logger.info(f"USER {event.user_id} 关闭了 GROUP {group} 的广播")
+ await oc_gb.finish(await group_manager.close_group_task(group, "broadcast"), at_sender=True)
+ else:
+ await oc_gb.finish("请输入正确的群号", at_sender=True)
+ else:
+ await oc_gb.finish("请输入要关闭广播的群号", at_sender=True)
\ No newline at end of file
diff --git a/basic_plugins/super_cmd/update_friend_group_info.py b/basic_plugins/super_cmd/update_friend_group_info.py
new file mode 100644
index 00000000..091e89f8
--- /dev/null
+++ b/basic_plugins/super_cmd/update_friend_group_info.py
@@ -0,0 +1,71 @@
+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
+from models.group_info import GroupInfo
+from models.friend_user import FriendUser
+
+
+__zx_plugin_name__ = "更新群/好友信息 [Superuser]"
+__plugin_usage__ = """
+usage:
+ 更新群/好友信息
+ 指令:
+ 更新群信息
+ 更新好友信息
+""".strip()
+__plugin_des__ = "更新群/好友信息"
+__plugin_cmd__ = [
+ "更新群信息",
+ "更新好友信息",
+]
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+
+update_group_info = on_command(
+ "更新群信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True
+)
+update_friend_info = on_command(
+ "更新好友信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True
+)
+
+
+@update_group_info.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ bot = get_bot()
+ gl = await bot.get_group_list()
+ gl = [g["group_id"] for g in gl]
+ num = 0
+ rst = ""
+ for g in gl:
+ group_info = await bot.get_group_info(group_id=g)
+ if await GroupInfo.add_group_info(
+ group_info["group_id"],
+ group_info["group_name"],
+ group_info["max_member_count"],
+ group_info["member_count"],
+ ):
+ num += 1
+ logger.info(f"自动更新群组 {g} 信息成功")
+ else:
+ logger.info(f"自动更新群组 {g} 信息失败")
+ rst += f"{g} 更新失败\n"
+ await update_group_info.send(f"成功更新了 {num} 个群的信息\n{rst[:-1]}")
+
+
+@update_friend_info.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ num = 0
+ rst = ""
+ fl = await get_bot().get_friend_list()
+ for f in fl:
+ if await FriendUser.add_friend_info(f["user_id"], f["nickname"]):
+ logger.info(f'自动更新好友 {f["user_id"]} 信息成功')
+ num += 1
+ else:
+ logger.warning(f'自动更新好友 {f["user_id"]} 信息失败')
+ rst += f'{f["user_id"]} 更新失败\n'
+ await update_friend_info.send(f"成功更新了 {num} 个好友的信息\n{rst[:-1]}")
diff --git a/plugins/super_help/__init__.py b/basic_plugins/super_help/__init__.py
similarity index 96%
rename from plugins/super_help/__init__.py
rename to basic_plugins/super_help/__init__.py
index 1bdbaf69..49aa7058 100644
--- a/plugins/super_help/__init__.py
+++ b/basic_plugins/super_help/__init__.py
@@ -1,30 +1,30 @@
-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'
-
-if superuser_help_image.exists():
- superuser_help_image.unlink()
-
-super_help = on_command(
- "超级用户帮助", rule=to_me(), priority=1, permission=SUPERUSER, block=True
-)
-
-
-@super_help.handle()
-async def _(bot: Bot, event: Event, state: T_State):
- if not superuser_help_image.exists():
- await create_help_image()
- x = image(superuser_help_image)
- await super_help.finish(x)
+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'
+
+if superuser_help_image.exists():
+ superuser_help_image.unlink()
+
+super_help = on_command(
+ "超级用户帮助", rule=to_me(), priority=1, permission=SUPERUSER, block=True
+)
+
+
+@super_help.handle()
+async def _(bot: Bot, event: Event, state: T_State):
+ if not superuser_help_image.exists():
+ await create_help_image()
+ x = image(superuser_help_image)
+ await super_help.finish(x)
diff --git a/plugins/super_help/data_source.py b/basic_plugins/super_help/data_source.py
similarity index 99%
rename from plugins/super_help/data_source.py
rename to basic_plugins/super_help/data_source.py
index c0c98448..730ff152 100644
--- a/plugins/super_help/data_source.py
+++ b/basic_plugins/super_help/data_source.py
@@ -33,8 +33,8 @@ def _create_help_image():
width = 0
help_str = "超级用户帮助\n\n* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n"
tmp_img = CreateImg(0, 0, plain_text='1', font_size=24)
- plugin_name = ""
for matcher in _matchers:
+ plugin_name = ""
try:
_plugin = nonebot.plugin.get_plugin(matcher.module)
_module = _plugin.module
diff --git a/plugins/update_info.py b/basic_plugins/update_info.py
similarity index 96%
rename from plugins/update_info.py
rename to basic_plugins/update_info.py
index 8d11d144..e86e82af 100644
--- a/plugins/update_info.py
+++ b/basic_plugins/update_info.py
@@ -1,35 +1,35 @@
-from nonebot import on_command
-from nonebot.adapters.cqhttp import Bot, Event
-from nonebot.typing import T_State
-from utils.message_builder import image
-
-
-__zx_plugin_name__ = "更新信息"
-__plugin_usage__ = """
-usage:
- 更新信息
- 指令:
- 更新信息
-""".strip()
-__plugin_des__ = "当前版本的更新信息"
-__plugin_cmd__ = ["更新信息"]
-__plugin_version__ = 0.1
-__plugin_author__ = "HibiKier"
-__plugin_settings__ = {
- "level": 5,
- "default_status": True,
- "limit_superuser": False,
- "cmd": ["更新信息"],
-}
-
-
-update_info = on_command("更新信息", aliases={"更新日志"}, priority=5, block=True)
-
-
-@update_info.handle()
-async def _(bot: Bot, event: Event, state: T_State):
- img = image("update_info.png")
- if img:
- await update_info.finish(image("update_info.png"))
- else:
- await update_info.finish("目前没有更新信息哦")
+from nonebot import on_command
+from nonebot.adapters.cqhttp import Bot, Event
+from nonebot.typing import T_State
+from utils.message_builder import image
+
+
+__zx_plugin_name__ = "更新信息"
+__plugin_usage__ = """
+usage:
+ 更新信息
+ 指令:
+ 更新信息
+""".strip()
+__plugin_des__ = "当前版本的更新信息"
+__plugin_cmd__ = ["更新信息"]
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+__plugin_settings__ = {
+ "level": 5,
+ "default_status": True,
+ "limit_superuser": False,
+ "cmd": ["更新信息"],
+}
+
+
+update_info = on_command("更新信息", aliases={"更新日志"}, priority=5, block=True)
+
+
+@update_info.handle()
+async def _(bot: Bot, event: Event, state: T_State):
+ img = image("update_info.png")
+ if img:
+ await update_info.finish(image("update_info.png"))
+ else:
+ await update_info.finish("目前没有更新信息哦")
diff --git a/bot.py b/bot.py
index d384928d..c8f1a34b 100644
--- a/bot.py
+++ b/bot.py
@@ -9,6 +9,9 @@ driver.register_adapter("cqhttp", CQHTTPBot)
config = driver.config
driver.on_startup(init)
driver.on_shutdown(disconnect)
+# 优先加载定时任务插件
+nonebot.load_plugin("nonebot_plugin_apscheduler")
+nonebot.load_plugins("basic_plugins")
nonebot.load_plugins("plugins")
diff --git a/configs/config.py b/configs/config.py
index a727a572..ead748f6 100644
--- a/configs/config.py
+++ b/configs/config.py
@@ -1,21 +1,11 @@
-from typing import List, Optional, Tuple
-from services.service_config import TL_M_KEY, SYSTEM_M_PROXY, ALAPI_M_TOKEN
-try:
- import ujson as json
-except ModuleNotFoundError:
- import json
+from typing import Optional
+from pathlib import Path
+from .utils import ConfigsManager
# 回复消息名称
NICKNAME: str = "小真寻"
-# API KEY(必要)
-RSSHUBAPP: str = "https://rsshub.app" # rsshub
-ALAPI_TOKEN: str = "" # ALAPI https://admin.alapi.cn/user/login
-HIBIAPI: str = "https://api.obfs.dev"
-# 图灵
-TL_KEY: List[str] = []
-
# 数据库(必要)
# 如果填写了bind就不需要再填写后面的字段了#)
# 示例:"bind": "postgresql://user:password@127.0.0.1:5432/database"
@@ -27,113 +17,8 @@ address: str = "" # 数据库地址
port: str = "" # 数据库端口
database: str = "" # 数据库名称
-# 代理
-SYSTEM_PROXY: Optional[str] = None # 全局代理
-BUFF_PROXY: Optional[str] = None # Buff代理
-
-# 公开图库列表
-IMAGE_DIR_LIST: List[str] = ["美图", "萝莉", "壁纸"]
-
-# 对被ban用户发送的消息
-BAN_RESULT: str = "才不会给你发消息."
-
-# PIX图库下载的画质 可能的值:original:原图,master:缩略图(加快发送速度)
-PIX_IMAGE_SIZE: str = "master"
-
-
-# 插件配置
-MAXINFO_REIMU: int = 7 # 上车(reimu)功能查找目的地的最大数
-COUNT_PER_DAY_REIMU: int = 5 # 每日上车(reimu)次数限制
-MAXINFO_BT: int = 10 # bt功能单次查找最大数
-MAXINFO_PRIVATE_ANIME: int = 20 # 私聊搜索动漫返回的最大数量
-MAXINFO_GROUP_ANIME: int = 5 # 群搜索动漫返回的最大数量
-MAX_FIND_IMG_COUNT: int = 3 # 识图最大返回数
-# 参1:延迟撤回色图时间(秒),0 为关闭 | 参2:监控聊天类型,0(私聊) 1(群聊) 2(群聊+私聊)
-WITHDRAW_SETU_TIME: Tuple[int, int] = (0, 1)
-# 参1:延迟撤回PIX图片时间(秒),0 为关闭 | 参2:监控聊天类型,0(私聊) 1(群聊) 2(群聊+私聊)
-WITHDRAW_PIX_TIME: Tuple[int, int] = (0, 1)
-
-# PIX图库 与 额外图库OmegaPixivIllusts 混合搜索的比例 参1:PIX图库 参2:OmegaPixivIllusts扩展图库(没有此图库请设置为0)
-PIX_OMEGA_PIXIV_RATIO: Tuple[int, int] = (10, 0)
-
-# 各种卡池的开关
-PRTS_FLAG = True # 明日方舟
-GENSHIN_FLAG = True # 原神
-PRETTY_FLAG = True # 赛马娘
-GUARDIAN_FLAG = True # 坎公骑冠剑
-PCR_FLAG = True # 公主连结
-AZUR_FLAG = True # 碧蓝航线
-FGO_FLAG = True # 命运-冠位指定(FGO)
-ONMYOJI_FLAG = True # 阴阳师
-
-PCR_TAI = True # pcr是否开启台服卡池
-SEMAPHORE = 5 # 限制碧蓝航线和FGO并发数
-
-ADMIN_DEFAULT_AUTH: int = 5 # 默认群管理员权限
-
-MAX_SIGN_GOLD: int = 200 # 签到好感度加成额外获得的最大金币数
-MAX_RUSSIAN_BET_GOLD: int = 1000 # 俄罗斯轮盘最大赌注金额
-
-INITIAL_SETU_PROBABILITY: float = 0.7 # 色图概率
-FUDU_PROBABILITY: float = 0.7 # 复读概率
-
-INITIAL_OPEN_CASE_COUNT: int = 20 # 初始开箱次数
-MUTE_DEFAULT_COUNT: int = 10 # 刷屏禁言默认检测次数
-MUTE_DEFAULT_TIME: int = 7 # 刷屏检测默认规定时间
-MUTE_DEFAULT_DURATION: int = 10 # 刷屏检测默禁言时长(分钟)
-
-CHECK_NOTICE_INFO_CD = 300 # 群检测,个人权限检测等各种检测提示信息cd
-
-# 注:即在 MALICIOUS_CHECK_TIME 时间内触发相同命令 MALICIOUS_BAN_COUNT 将被ban MALICIOUS_BAN_TIME 分钟
-MALICIOUS_BAN_TIME: int = 30 # 恶意命令触发检测触发后ban的时长(分钟)
-MALICIOUS_BAN_COUNT: int = 6 # 恶意命令触发检测最大触发次数
-MALICIOUS_CHECK_TIME: int = 5 # 恶意命令触发检测规定时间内(秒)
-
-# LEVEL
-DELETE_IMG_LEVEL: int = 7 # 删除图片权限
-MOVE_IMG_LEVEL: int = 7 # 移动图片权限
-UPLOAD_IMG_LEVEL: int = 6 # 上传图片权限
-BAN_LEVEL: int = 5 # BAN权限
-OC_LEVEL: int = 2 # 开关群功能权限
-MUTE_LEVEL: int = 5 # 更改禁言设置权限
-MEMBER_ACTIVITY_LEVEL = 5 # 群员活跃检测设置权限
-GROUP_BILIBILI_SUB_LEVEL = 5 # 群内bilibili订阅需要的权限
-
-DEFAULT_GROUP_LEVEL = 5 # 默认群等级
-
-# 是否开启HIBIAPI搜图功能(该功能会搜索群友提交的xp)
-HIBIAPI_FLAG: bool = True
-# HIBIAPI搜图图片的最低收藏
-HIBIAPI_BOOKMARKS: int = 5000
-
-# 需要为哪些群更新最新版gocq吗?(上传最新版gocq)
-# 示例:[434995955, 239483248]
-UPDATE_GOCQ_GROUP: List[int] = []
-
-# 是否存储色图
-DOWNLOAD_SETU: bool = True
-# 仅仅使用本地色图
-ONLY_USE_LOCAL_SETU: bool = False
-# 是否自动同意好友添加
-AUTO_ADD_FRIEND: bool = True
-# 当含有ALAPI_TOKEN时是否检测文本合规,开启检测会减慢回复速度
-ALAPI_AI_CHECK: bool = True
-# 导入商店自带的三个商品
-IMPORT_DEFAULT_SHOP_GOODS: bool = True
-# 真寻是否自动更新
-AUTO_UPDATE_ZHENXUN: bool = True
-
-
-if TL_M_KEY:
- TL_KEY = TL_M_KEY
-if SYSTEM_M_PROXY:
- SYSTEM_PROXY = SYSTEM_M_PROXY
-if ALAPI_M_TOKEN:
- ALAPI_TOKEN = ALAPI_M_TOKEN
-
-
-HIBIAPI = HIBIAPI[:-1] if HIBIAPI[-1] == "/" else HIBIAPI
-RSSHUBAPP = RSSHUBAPP[:-1] if RSSHUBAPP[-1] == "/" else RSSHUBAPP
-
+# 全局代理,例如 "http://127.0.0.1:7890"
+SYSTEM_PROXY: Optional[str] = None
+Config = ConfigsManager(Path() / "data" / "configs" / "plugins2config.yaml")
diff --git a/configs/utils/__init__.py b/configs/utils/__init__.py
new file mode 100644
index 00000000..2bbba45f
--- /dev/null
+++ b/configs/utils/__init__.py
@@ -0,0 +1,160 @@
+from typing import Optional, Any, Union
+from pathlib import Path
+from ruamel.yaml import YAML
+from ruamel import yaml
+
+
+class ConfigsManager:
+ """
+ 插件配置 与 资源 管理器
+ """
+
+ def __init__(self, file: Path):
+ self._data: dict = {}
+ self._admin_level_data = []
+ if file:
+ file.parent.mkdir(exist_ok=True, parents=True)
+ self.file = file
+ if file.exists():
+ _yaml = YAML()
+ with open(file, "r", encoding="utf8") as f:
+ self._data = _yaml.load(f)
+
+ def add_plugin_config(
+ self,
+ module: str,
+ key: str,
+ value: Optional[Any],
+ *,
+ name: Optional[str] = None,
+ help_: Optional[str] = None,
+ default_value: Optional[str] = None,
+ _override: bool = False
+ ):
+ """
+ 为插件添加一个配置,不会被覆盖,只有第一个生效
+ :param module: 模块
+ :param key: 键
+ :param value: 值
+ :param name: 插件名称
+ :param help_: 配置注解
+ :param default_value: 默认值
+ :param _override: 覆盖前值
+ """
+ if (
+ not (module in self._data.keys() and self._data[module].get(key))
+ or _override
+ ):
+ _module = None
+ if ":" in module:
+ module = module.split(":")
+ _module = module[-1]
+ module = module[0]
+ if "[LEVEL]" in key and _module:
+ key = key.replace("[LEVEL]", "").strip()
+ self._admin_level_data.append((_module, value))
+ if self._data.get(module) is None:
+ self._data[module] = {}
+ key = key.upper()
+ self._data[module][key] = {
+ "value": value,
+ "name": name.strip() if isinstance(name, str) else name,
+ "help": help_.strip() if isinstance(help_, str) else help_,
+ "default_value": default_value,
+ }
+
+ def remove_plugin_config(self, module: str):
+ """
+ 为插件删除一个配置
+ :param module: 模块名
+ """
+ if module in self._data.keys():
+ del self._data[module]
+
+ def set_config(self, module: str, key: str, value: str):
+ """
+ 设置配置值
+ :param module: 模块名
+ :param key: 配置名称
+ :param value: 值
+ """
+ if module in self._data.keys():
+ if self._data[module].get(key) is not None:
+ self._data[module][key]["value"] = value
+
+ def set_help(self, module: str, key: str, help_: str):
+ """
+ 设置配置注释
+ :param module: 模块名
+ :param key: 配置名称
+ :param help_: 注释文本
+ """
+ if module in self._data.keys():
+ if self._data[module].get(key) is not None:
+ self._data[module][key]["help"] = help_
+
+ def set_default_value(self, module: str, key: str, value: str):
+ """
+ 设置配置默认值
+ :param module: 模块名
+ :param key: 配置名称
+ :param value: 值
+ """
+ if module in self._data.keys():
+ if self._data[module].get(key) is not None:
+ self._data[module][key]["default_value"] = value
+
+ def get_config(self, module: str, key: str) -> Optional[Any]:
+ """
+ 获取指定配置值
+ :param module: 模块名
+ :param key: 配置名称
+ """
+ key = key.upper()
+ if module in self._data.keys():
+ for key in [key, f"{key} [LEVEL]"]:
+ if self._data[module].get(key) is not None:
+ if self._data[module][key]["value"] is None:
+ return self._data[module][key]["default_value"]
+ return self._data[module][key]["value"]
+ return None
+
+ def get(self, key: str):
+ """
+ 获取插件配置数据
+ :param key: 名称
+ """
+ if key in self._data.keys():
+ return self._data[key]
+
+ def save(self, path: Union[str, Path] = None):
+ """
+ 保存数据
+ :param path: 路径
+ """
+ path = path if path else self.file
+ with open(path, "w", encoding="utf8") as f:
+ yaml.dump(
+ self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
+ )
+
+ def get_admin_level_data(self):
+ """
+ 获取管理插件等级
+ """
+ return self._admin_level_data
+
+ def is_empty(self) -> bool:
+ return not bool(self._data)
+
+ def keys(self):
+ return self._data.keys()
+
+ def __str__(self):
+ return str(self._data)
+
+ def __setitem__(self, key, value):
+ self._data[key] = value
+
+ def __getitem__(self, key):
+ return self._data[key]
diff --git a/docs/ban.png b/docs/ban.png
deleted file mode 100644
index 087ac9ba..00000000
Binary files a/docs/ban.png and /dev/null differ
diff --git a/docs/beidong.png b/docs/beidong.png
deleted file mode 100644
index f269e60b..00000000
Binary files a/docs/beidong.png and /dev/null differ
diff --git a/docs/buff.png b/docs/buff.png
deleted file mode 100644
index aa7948f7..00000000
Binary files a/docs/buff.png and /dev/null differ
diff --git a/docs/check.png b/docs/check.png
deleted file mode 100644
index 4d3c614b..00000000
Binary files a/docs/check.png and /dev/null differ
diff --git a/docs/coser.png b/docs/coser.png
deleted file mode 100644
index c546a530..00000000
Binary files a/docs/coser.png and /dev/null differ
diff --git a/docs/daoju.png b/docs/daoju.png
deleted file mode 100644
index e41403f8..00000000
Binary files a/docs/daoju.png and /dev/null differ
diff --git a/docs/epic.png b/docs/epic.png
deleted file mode 100644
index 96ae4510..00000000
Binary files a/docs/epic.png and /dev/null differ
diff --git a/docs/fanyi.png b/docs/fanyi.png
deleted file mode 100644
index 8919e0d5..00000000
Binary files a/docs/fanyi.png and /dev/null differ
diff --git a/docs/guanli.png b/docs/guanli.png
deleted file mode 100644
index 9cab7478..00000000
Binary files a/docs/guanli.png and /dev/null differ
diff --git a/docs/help.PNG b/docs/help.PNG
deleted file mode 100644
index 157a16b3..00000000
Binary files a/docs/help.PNG and /dev/null differ
diff --git a/docs/huifu.png b/docs/huifu.png
deleted file mode 100644
index 93760157..00000000
Binary files a/docs/huifu.png and /dev/null differ
diff --git a/docs/info.png b/docs/info.png
deleted file mode 100644
index 172a6f02..00000000
Binary files a/docs/info.png and /dev/null differ
diff --git a/docs/jiaxiaoxi.png b/docs/jiaxiaoxi.png
deleted file mode 100644
index 7a9a598e..00000000
Binary files a/docs/jiaxiaoxi.png and /dev/null differ
diff --git a/docs/jieshao.png b/docs/jieshao.png
deleted file mode 100644
index 423ef585..00000000
Binary files a/docs/jieshao.png and /dev/null differ
diff --git a/docs/jitang.png b/docs/jitang.png
deleted file mode 100644
index a6d98fa5..00000000
Binary files a/docs/jitang.png and /dev/null differ
diff --git a/docs/kaixiang.png b/docs/kaixiang.png
deleted file mode 100644
index 8ddcf023..00000000
Binary files a/docs/kaixiang.png and /dev/null differ
diff --git a/docs/kg1.png b/docs/kg1.png
deleted file mode 100644
index c7a0dd0f..00000000
Binary files a/docs/kg1.png and /dev/null differ
diff --git a/docs/kg2.png b/docs/kg2.png
deleted file mode 100644
index caec2c2a..00000000
Binary files a/docs/kg2.png and /dev/null differ
diff --git a/docs/kg3.png b/docs/kg3.png
deleted file mode 100644
index 962692d2..00000000
Binary files a/docs/kg3.png and /dev/null differ
diff --git a/docs/luxun.png b/docs/luxun.png
deleted file mode 100644
index 2d72cd50..00000000
Binary files a/docs/luxun.png and /dev/null differ
diff --git a/docs/mawo.png b/docs/mawo.png
deleted file mode 100644
index 979b9fac..00000000
Binary files a/docs/mawo.png and /dev/null differ
diff --git a/docs/nicheng1.png b/docs/nicheng1.png
deleted file mode 100644
index 971f8001..00000000
Binary files a/docs/nicheng1.png and /dev/null differ
diff --git a/docs/nicheng2.png b/docs/nicheng2.png
deleted file mode 100644
index d3fdc0a3..00000000
Binary files a/docs/nicheng2.png and /dev/null differ
diff --git a/docs/ocgn.png b/docs/ocgn.png
deleted file mode 100644
index 8f882b06..00000000
Binary files a/docs/ocgn.png and /dev/null differ
diff --git a/docs/ocgn2.png b/docs/ocgn2.png
deleted file mode 100644
index dbb2ee9b..00000000
Binary files a/docs/ocgn2.png and /dev/null differ
diff --git a/docs/one_firend.png b/docs/one_firend.png
deleted file mode 100644
index 48aa0427..00000000
Binary files a/docs/one_firend.png and /dev/null differ
diff --git a/docs/p_rank.png b/docs/p_rank.png
deleted file mode 100644
index 989a59f4..00000000
Binary files a/docs/p_rank.png and /dev/null differ
diff --git a/docs/p_sou.png b/docs/p_sou.png
deleted file mode 100644
index 27d41952..00000000
Binary files a/docs/p_sou.png and /dev/null differ
diff --git a/docs/qhyxx.png b/docs/qhyxx.png
deleted file mode 100644
index 85922e42..00000000
Binary files a/docs/qhyxx.png and /dev/null differ
diff --git a/docs/qunhuanying.png b/docs/qunhuanying.png
deleted file mode 100644
index 09050fbd..00000000
Binary files a/docs/qunhuanying.png and /dev/null differ
diff --git a/docs/redbag0.png b/docs/redbag0.png
deleted file mode 100644
index 11a19ca7..00000000
Binary files a/docs/redbag0.png and /dev/null differ
diff --git a/docs/redbag1.png b/docs/redbag1.png
deleted file mode 100644
index 9883f068..00000000
Binary files a/docs/redbag1.png and /dev/null differ
diff --git a/docs/redbag2.png b/docs/redbag2.png
deleted file mode 100644
index e6ecbd3b..00000000
Binary files a/docs/redbag2.png and /dev/null differ
diff --git a/docs/russian0.png b/docs/russian0.png
deleted file mode 100644
index c9ae5d0e..00000000
Binary files a/docs/russian0.png and /dev/null differ
diff --git a/docs/russian1.png b/docs/russian1.png
deleted file mode 100644
index 01598a98..00000000
Binary files a/docs/russian1.png and /dev/null differ
diff --git a/docs/russian2.png b/docs/russian2.png
deleted file mode 100644
index 9fe9a055..00000000
Binary files a/docs/russian2.png and /dev/null differ
diff --git a/docs/send_img.png b/docs/send_img.png
deleted file mode 100644
index 93293905..00000000
Binary files a/docs/send_img.png and /dev/null differ
diff --git a/docs/shifan.png b/docs/shifan.png
deleted file mode 100644
index 071b515e..00000000
Binary files a/docs/shifan.png and /dev/null differ
diff --git a/docs/shitu.png b/docs/shitu.png
deleted file mode 100644
index 452b3eff..00000000
Binary files a/docs/shitu.png and /dev/null differ
diff --git a/docs/shop.png b/docs/shop.png
deleted file mode 100644
index 4b2480b6..00000000
Binary files a/docs/shop.png and /dev/null differ
diff --git a/docs/sign.png b/docs/sign.png
deleted file mode 100644
index b136c413..00000000
Binary files a/docs/sign.png and /dev/null differ
diff --git a/docs/tupian.png b/docs/tupian.png
deleted file mode 100644
index 04bef568..00000000
Binary files a/docs/tupian.png and /dev/null differ
diff --git a/docs/w2b.png b/docs/w2b.png
deleted file mode 100644
index dc1719aa..00000000
Binary files a/docs/w2b.png and /dev/null differ
diff --git a/docs/zhenxun.jpg b/docs/zhenxun.jpg
deleted file mode 100644
index 61171ed8..00000000
Binary files a/docs/zhenxun.jpg and /dev/null differ
diff --git a/models/count_user.py b/models/count_user.py
deleted file mode 100644
index 39d59771..00000000
--- a/models/count_user.py
+++ /dev/null
@@ -1,63 +0,0 @@
-from services.db_context import db
-
-
-class UserCount(db.Model):
- __tablename__ = "count_users"
-
- user_qq = db.Column(db.BigInteger(), nullable=False, primary_key=True)
- reimu_count = db.Column(db.Integer(), nullable=False, default=0)
- setu_r18_count = db.Column(db.Integer(), nullable=False, default=0)
-
- _idx1 = db.Index("sign_reimu_users_idx1", "user_qq", unique=True)
-
- @classmethod
- async def add_count(cls, user_qq: int, name: str, count: int = 1):
- """
- 说明:
- 用户添加次数
- 参数:
- :param user_qq: qq号
- :param name: 目标名称
- :param count: 增加次数
- """
- query = cls.query.where((cls.user_qq == user_qq))
- query = query.with_for_update()
- user = await query.gino.first()
- user = user if user else await cls.create(user_qq=user_qq)
- if name == "reimu":
- await user.update(reimu_count=cls.reimu_count + count).apply()
- if name == "setu_r18":
- await user.update(setu_r18_count=cls.setu_r18_count + count).apply()
-
- @classmethod
- async def check_count(cls, user_qq: int, name: str, max_count: int) -> bool:
- """
- 说明:
- 检测次数是否到达最大值
- 参数:
- :param user_qq: qq号
- :param name: 目标名称
- :param max_count: 最大值
- """
- query = cls.query.where((cls.user_qq == user_qq))
- user = await query.gino.first()
- user = user if user else await cls.create(user_qq=user_qq)
- if name == "reimu":
- if user.reimu_count == max_count:
- return True
- else:
- return False
- if name == "setu_r18":
- if user.setu_r18_count == max_count:
- return True
- else:
- return False
-
- @classmethod
- async def reset_count(cls):
- """
- 说明:
- 重置每日次数
- """
- for user in await cls.query.gino.all():
- await user.update(reimu_count=0, setu_r18_count=0).apply()
diff --git a/models/group_info.py b/models/group_info.py
index c8999474..960c695a 100644
--- a/models/group_info.py
+++ b/models/group_info.py
@@ -1,5 +1,6 @@
from services.db_context import db
-from typing import List
+from services.log import logger
+from typing import List, Optional
class GroupInfo(db.Model):
@@ -9,6 +10,7 @@ class GroupInfo(db.Model):
group_name = db.Column(db.Unicode(), nullable=False, default="")
max_member_count = db.Column(db.Integer(), nullable=False, default=0)
member_count = db.Column(db.Integer(), nullable=False, default=0)
+ group_flag = db.Column(db.Integer(), nullable=False, default=0)
_idx1 = db.Index("group_info_idx1", "group_id", unique=True)
@@ -25,7 +27,12 @@ class GroupInfo(db.Model):
@classmethod
async def add_group_info(
- cls, group_id: int, group_name: str, max_member_count: int, member_count: int
+ cls,
+ group_id: int,
+ group_name: str,
+ max_member_count: int,
+ member_count: int,
+ group_flag: Optional[int] = None,
) -> bool:
"""
说明:
@@ -35,6 +42,7 @@ class GroupInfo(db.Model):
:param group_name: 群名称
:param max_member_count: 群员最大数量
:param member_count: 群员数量
+ :param group_flag: 群认证,0为未认证,1为认证
"""
try:
group = (
@@ -43,36 +51,35 @@ class GroupInfo(db.Model):
.gino.first()
)
if group:
- await cls.update(
- group_id=group_id,
+ await group.update(
group_name=group_name,
max_member_count=max_member_count,
member_count=member_count,
).apply()
+ if group_flag is not None:
+ await group.update(group_flag=group_flag).apply()
else:
await cls.create(
group_id=group_id,
group_name=group_name,
max_member_count=max_member_count,
member_count=member_count,
+ group_flag=group_flag,
)
return True
- except Exception:
+ except Exception as e:
+ logger.info(f"GroupInfo 调用 add_group_info 发生错误 {type(e)}:{e}")
return False
@classmethod
- async def delete_group_info(cls, group_id: int) -> bool:
+ async def delete_group_info(cls, group_id: int):
"""
说明:
删除群信息
参数:
:param group_id: 群号
"""
- try:
- await cls.delete.where(cls.group_id == group_id).gino.status()
- return True
- except Exception:
- return False
+ await cls.delete.where(cls.group_id == group_id).gino.status()
@classmethod
async def get_all_group(cls) -> List["GroupInfo"]:
@@ -82,3 +89,23 @@ class GroupInfo(db.Model):
"""
query = await cls.query.gino.all()
return query
+
+ @classmethod
+ async def set_group_flag(cls, group_id: int, group_flag: int) -> bool:
+ """
+ 设置群认证
+ :param group_id: 群号
+ :param group_flag: 群认证,0为未认证,1为认证
+ """
+ group = (
+ await cls.query.where(cls.group_id == group_id)
+ .with_for_update()
+ .gino.first()
+ )
+ if group:
+ if group.group_flag != group_flag:
+ await group.update(
+ group_flag=group_flag,
+ ).apply()
+ return True
+ return False
diff --git a/models/group_remind.py b/models/group_remind.py
deleted file mode 100644
index 0dab8985..00000000
--- a/models/group_remind.py
+++ /dev/null
@@ -1,105 +0,0 @@
-from services.db_context import db
-
-
-class GroupRemind(db.Model):
- __tablename__ = "group_reminds"
-
- id = db.Column(db.Integer(), primary_key=True)
- group_id = db.Column(db.BigInteger(), nullable=False)
- hy = db.Column(db.Boolean(), default=False) # 进群欢迎
- kxcz = db.Column(db.Boolean(), default=False) # 开箱重置
- zwa = db.Column(db.Boolean(), default=False) # 早晚安
- gb = db.Column(db.Boolean(), default=True) # 广播
- blpar = db.Column(db.Boolean(), default=True) # bilibili转发解析
- pa = db.Column(db.Boolean(), default=True) # 爬
- epic = db.Column(db.Boolean(), default=False) # epic
- almanac = db.Column(db.Boolean(), default=False) # 原神黄历
-
- _idx1 = db.Index("info_group_reminds_idx1", "group_id", unique=True)
-
- @classmethod
- async def get_status(cls, group_id: int, name: str) -> bool:
- """
- 说明:
- 获取群通知状态
- 参数:
- :param group_id: 群号
- :param name: 目标名称
- """
- group = await cls.query.where((cls.group_id == group_id)).gino.first()
- if not group:
- group = await cls.create(
- group_id=group_id,
- )
- if name == "hy":
- return group.hy
- if name == "kxcz":
- return group.kxcz
- if name == "zwa":
- return group.zwa
- if name == "gb":
- return group.gb
- if name == "blpar":
- return group.blpar
- if name == "epic":
- return group.epic
- if name == "pa":
- return group.pa
- if name == "almanac":
- return group.almanac
-
- @classmethod
- async def set_status(cls, group_id: int, name: str, status: bool) -> bool:
- """
- 说明:
- 设置群通知状态
- 参数:
- :param group_id: 群号
- :param name: 目标名称
- :param status: 通知状态
- """
- try:
- group = (
- await cls.query.where((cls.group_id == group_id))
- .with_for_update()
- .gino.first()
- )
- if not group:
- group = await cls.create(
- group_id=group_id,
- )
- if name == "hy":
- await group.update(
- hy=status,
- ).apply()
- if name == "kxcz":
- await group.update(
- kxcz=status,
- ).apply()
- if name == "zwa":
- await group.update(
- zwa=status,
- ).apply()
- if name == "gb":
- await group.update(
- gb=status,
- ).apply()
- if name == "blpar":
- await group.update(
- blpar=status,
- ).apply()
- if name == "epic":
- await group.update(
- epic=status,
- ).apply()
- if name == "pa":
- await group.update(
- pa=status,
- ).apply()
- if name == "almanac":
- await group.update(
- almanac=status,
- ).apply()
- return True
- except Exception as e:
- return False
\ No newline at end of file
diff --git a/plugins/admin_bot_manage/__init__.py b/plugins/admin_bot_manage/__init__.py
deleted file mode 100644
index 4985070c..00000000
--- a/plugins/admin_bot_manage/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-import nonebot
-
-nonebot.load_plugins("plugins/admin_bot_manage")
diff --git a/plugins/ai/__init__.py b/plugins/ai/__init__.py
index 96af27e7..fc55b73e 100644
--- a/plugins/ai/__init__.py
+++ b/plugins/ai/__init__.py
@@ -13,7 +13,7 @@ from models.group_member_info import GroupInfoUser
from services.log import logger
from utils.utils import get_message_text, get_message_imgs
from .data_source import get_chat_result, hello, no_result
-from configs.config import NICKNAME
+from configs.config import NICKNAME, Config
__zx_plugin_name__ = "AI"
__plugin_usage__ = f"""
@@ -28,6 +28,23 @@ __plugin_settings__ = {
"limit_superuser": False,
"cmd": ["Ai", "ai", "AI", "aI"],
}
+__plugin_configs__ = {
+ "TL_KEY": {
+ "value": [],
+ "help": "图灵Key"
+ },
+ "ALAPI_AI_CHECK": {
+ "value": False,
+ "help": "是否检测青云客骂娘回复",
+ "default_value": False
+ }
+}
+Config.add_plugin_config(
+ "alapi",
+ "ALAPI_TOKEN",
+ None,
+ help_="在https://admin.alapi.cn/user/login登录后获取token"
+)
ai = on_message(rule=to_me(), priority=8)
@@ -36,7 +53,7 @@ ai = on_message(rule=to_me(), priority=8)
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
imgs = get_message_imgs(event.json())
- if "CQ:xml" in msg:
+ if "CQ:xml" in str(event.get_message()):
return
# 打招呼
if (not msg and not imgs) or msg in [
diff --git a/plugins/ai/data_source.py b/plugins/ai/data_source.py
index d197b83f..1cbbb2dc 100644
--- a/plugins/ai/data_source.py
+++ b/plugins/ai/data_source.py
@@ -4,11 +4,10 @@ import re
import aiohttp
from aiohttp.client import ClientSession
-
-from configs.config import TL_KEY, ALAPI_TOKEN, ALAPI_AI_CHECK, NICKNAME
from configs.path_config import IMAGE_PATH, DATA_PATH
from services.log import logger
from utils.message_builder import image, face
+from configs.config import Config, NICKNAME
try:
import ujson as json
@@ -70,6 +69,9 @@ async def tu_ling(text: str, img_url: str, user_id: int, sess: ClientSession) ->
:return: 图灵回复
"""
global index
+ TL_KEY = Config.get_config("ai", "TL_KEY")
+ if not TL_KEY:
+ return ''
try:
if text:
req = {
@@ -149,7 +151,7 @@ async def xie_ai(text: str, sess: ClientSession) -> str:
break
return (
content
- if not content and not ALAPI_AI_CHECK
+ if not content and not Config.get_config("ai", "ALAPI_AI_CHECK")
else await check_text(content, sess)
)
@@ -200,9 +202,9 @@ async def check_text(text: str, sess: ClientSession) -> str:
:param text: 回复
:param sess: AIOHTTP SESSION
"""
- if not ALAPI_TOKEN:
+ if not Config.get_config("alapi", "ALAPI_TOKEN"):
return text
- params = {"token": ALAPI_TOKEN, "text": text}
+ params = {"token": Config.get_config("alapi", "ALAPI_TOKEN"), "text": text}
try:
async with sess.get(check_url, timeout=2, params=params) as response:
data = await response.json()
diff --git a/plugins/alapi/__init__.py b/plugins/alapi/__init__.py
index f4c7b35f..ddabb5d5 100644
--- a/plugins/alapi/__init__.py
+++ b/plugins/alapi/__init__.py
@@ -1,3 +1,11 @@
+from configs.config import Config
import nonebot
nonebot.load_plugins("plugins/alapi")
+
+Config.add_plugin_config(
+ "alapi",
+ "ALAPI_TOKEN",
+ None,
+ help_="在https://admin.alapi.cn/user/login登录后获取token"
+)
diff --git a/plugins/alapi/comments_163.py b/plugins/alapi/comments_163.py
index 12d10ba8..b88cc643 100644
--- 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 configs.config import ALAPI_TOKEN
from .data_source import get_data
from services.log import logger
@@ -34,8 +33,7 @@ comments_163_url = "https://v2.alapi.cn/api/comment"
@comments_163.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
- params = {"token": ALAPI_TOKEN}
- data, code = await get_data(comments_163_url, params)
+ data, code = await get_data(comments_163_url)
if code != 200:
await comments_163.finish(data, at_sender=True)
data = data["data"]
diff --git a/plugins/alapi/cover.py b/plugins/alapi/cover.py
index 48efbbcc..8d0ce8c9 100644
--- a/plugins/alapi/cover.py
+++ b/plugins/alapi/cover.py
@@ -1,53 +1,48 @@
from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent
from nonebot.typing import T_State
-from configs.config import ALAPI_TOKEN
from utils.message_builder import image
from utils.utils import get_message_text
from .data_source import get_data
from services.log import logger
-__zx_plugin_name__ = 'b封面'
-__plugin_usage__ = """usage:
+__zx_plugin_name__ = "b封面"
+__plugin_usage__ = """
+usage:
b封面 [链接/av/bv/cv/直播id]
示例:b封面 av86863038
-"""
-__plugin_des__ = '快捷的b站视频封面获取方式'
-__plugin_cmd__ = ['b封面/B封面']
-__plugin_type__ = ('一些工具',)
+""".strip()
+__plugin_des__ = "快捷的b站视频封面获取方式"
+__plugin_cmd__ = ["b封面/B封面"]
+__plugin_type__ = ("一些工具",)
__plugin_version__ = 0.1
-__plugin_author__ = 'HibiKier'
+__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
- "cmd": ["b封面", 'B封面'],
+ "cmd": ["b封面", "B封面"],
}
-cover = on_command('b封面', aliases={'B封面'}, priority=5, block=True)
+cover = on_command("b封面", aliases={"B封面"}, priority=5, block=True)
-cover_url = 'https://v2.alapi.cn/api/bilibili/cover'
+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())
- params = {
- 'token': ALAPI_TOKEN,
- 'c': msg
- }
+ params = {"c": msg}
data, code = await get_data(cover_url, params)
if code != 200:
await cover.finish(data, at_sender=True)
- data = data['data']
- title = data['title']
- img = data['cover']
- await cover.send(Message(f'title:{title}\n{image(img)}'))
+ data = data["data"]
+ title = data["title"]
+ img = data["cover"]
+ await cover.send(Message(f"title:{title}\n{image(img)}"))
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
- f" 获取b站封面: {title} url:{img}")
-
-
-
+ f" 获取b站封面: {title} url:{img}"
+ )
diff --git a/plugins/alapi/data_source.py b/plugins/alapi/data_source.py
index 7c13ab5c..0571e802 100644
--- a/plugins/alapi/data_source.py
+++ b/plugins/alapi/data_source.py
@@ -2,21 +2,23 @@ from nonebot.adapters.cqhttp import MessageSegment
from utils.image_utils import CreateImg
from utils.message_builder import image
from configs.path_config import IMAGE_PATH
-from typing import Union
+from typing import Optional
+from configs.config import Config
import aiohttp
-async def get_data(url: str, params: dict) -> 'Union[dict, str], int':
+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")
async with aiohttp.ClientSession() as session:
try:
- async with session.get(
- url, timeout=2, params=params
- ) as response:
+ async with session.get(url, timeout=2, params=params) as response:
data = await response.json()
if data["code"] == 200:
if not data["data"]:
@@ -33,13 +35,13 @@ def gen_wbtop_pic(data: dict) -> MessageSegment:
生成微博热搜图片
:param data: 微博热搜数据
"""
- bk = CreateImg(700, 32 * 50 + 280, 700, 32, color='#797979')
- wbtop_bk = CreateImg(700, 280, background=f'{IMAGE_PATH}/other/webtop.png')
+ bk = CreateImg(700, 32 * 50 + 280, 700, 32, color="#797979")
+ wbtop_bk = CreateImg(700, 280, background=f"{IMAGE_PATH}/other/webtop.png")
bk.paste(wbtop_bk)
- text_bk = CreateImg(700, 32 * 50, 700, 32, color='#797979')
+ text_bk = CreateImg(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']
+ hot = data["hot_word_num"]
img = CreateImg(700, 30, font_size=20)
w, h = img.getsize(title)
img.text((10, int((30 - h) / 2)), title)
diff --git a/plugins/alapi/poetry.py b/plugins/alapi/poetry.py
index 009ef226..05395c2c 100644
--- a/plugins/alapi/poetry.py
+++ b/plugins/alapi/poetry.py
@@ -1,48 +1,42 @@
from nonebot import on_command
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from nonebot.typing import T_State
-from configs.config import ALAPI_TOKEN
from services.log import logger
from .data_source import get_data
-__zx_plugin_name__ = '古诗'
+__zx_plugin_name__ = "古诗"
__plugin_usage__ = """usage:
平白无故念首诗
示例:念诗/来首诗/念首诗
"""
-__plugin_des__ = '为什么突然文艺起来了!'
-__plugin_cmd__ = ['念诗/来首诗/念首诗']
+__plugin_des__ = "为什么突然文艺起来了!"
+__plugin_cmd__ = ["念诗/来首诗/念首诗"]
__plugin_version__ = 0.1
-__plugin_author__ = 'HibiKier'
+__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
- "cmd": ['念诗', '来首诗', '念首诗'],
+ "cmd": ["念诗", "来首诗", "念首诗"],
}
-poetry = on_command("念诗", aliases={'来首诗', '念首诗'}, priority=5, block=True)
+poetry = on_command("念诗", aliases={"来首诗", "念首诗"}, priority=5, block=True)
-poetry_url = 'https://v2.alapi.cn/api/shici'
+poetry_url = "https://v2.alapi.cn/api/shici"
@poetry.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
- params = {
- 'token': ALAPI_TOKEN
- }
- data, code = await get_data(poetry_url, params)
+ data, code = await get_data(poetry_url)
if code != 200:
await poetry.finish(data, at_sender=True)
- data = data['data']
- content = data['content']
- title = data['origin']
- author = data['author']
- await poetry.send(f'{content}\n\t——{author}《{title}》')
+ data = data["data"]
+ content = data["content"]
+ title = data["origin"]
+ author = data["author"]
+ await poetry.send(f"{content}\n\t——{author}《{title}》")
logger.info(
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
- f" 发送古诗: f'{content}\n\t--{author}《{title}》'")
-
-
-
+ f" 发送古诗: f'{content}\n\t--{author}《{title}》'"
+ )
diff --git a/plugins/alapi/wbtop.py b/plugins/alapi/wbtop.py
index deca4604..e367e533 100644
--- a/plugins/alapi/wbtop.py
+++ b/plugins/alapi/wbtop.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 configs.config import ALAPI_TOKEN
from services.log import logger
from .data_source import get_data, gen_wbtop_pic
from utils.browser import get_browser
@@ -43,10 +42,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
global wbtop_data
msg = get_message_text(event.json())
if not wbtop_data or not msg:
- params = {
- 'token': ALAPI_TOKEN
- }
- data, code = await get_data(wbtop_url, params)
+ data, code = await get_data(wbtop_url)
if code != 200:
await wbtop.finish(data, at_sender=True)
wbtop_data = data['data']
@@ -67,6 +63,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
page = await browser.new_page()
await page.goto(url, wait_until='networkidle', timeout=10000)
await page.set_viewport_size({"width": 2560, "height": 1080})
+ await asyncio.sleep(5)
div = await page.query_selector("#pl_feedlist_index")
await div.screenshot(path=f'{IMAGE_PATH}/temp/wbtop_{event.user_id}.png', timeout=100000)
await page.close()
diff --git a/plugins/bilibili_sub/__init__.py b/plugins/bilibili_sub/__init__.py
index e13d0859..6ee0138c 100644
--- a/plugins/bilibili_sub/__init__.py
+++ b/plugins/bilibili_sub/__init__.py
@@ -9,11 +9,11 @@ from .data_source import (
get_media_id,
get_sub_status,
SubManager,
+ BilibiliSub
)
from models.level_user import LevelUser
-from configs.config import GROUP_BILIBILI_SUB_LEVEL
+from configs.config import Config
from utils.utils import get_message_text, is_number, scheduler, get_bot
-from models.bilibili_sub import BilibiliSub
from typing import Optional
from services.log import logger
from nonebot import Driver
@@ -34,20 +34,27 @@ usage:
示例:添加订阅番剧 125344 <-(番剧id)
示例:删除订阅 2324344 <-(任意id,通过查看订阅获取)
""".strip()
-__plugin_des__ = '非常便利的B站订阅通知'
-__plugin_cmd__ = ['添加订阅 [主播/UP/番剧] [id/链接/番名]', '删除订阅 [id]', '查看订阅']
+__plugin_des__ = "非常便利的B站订阅通知"
+__plugin_cmd__ = ["添加订阅 [主播/UP/番剧] [id/链接/番名]", "删除订阅 [id]", "查看订阅"]
__plugin_version__ = 0.1
-__plugin_author__ = 'HibiKier'
+__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
- "cmd": ["B站订阅", 'b站订阅', '添加订阅', '删除订阅', '查看订阅'],
+ "cmd": ["B站订阅", "b站订阅", "添加订阅", "删除订阅", "查看订阅"],
+}
+__plugin_configs__ = {
+ "GROUP_BILIBILI_SUB_LEVEL": {
+ "value": 5,
+ "help": "群内bilibili订阅需要管理的权限",
+ "default_value": 5,
+ }
}
add_sub = on_command("添加订阅", priority=5, block=True)
del_sub = on_command("删除订阅", priority=5, block=True)
-show_sub_info = on_command('查看订阅', priority=5, block=True)
+show_sub_info = on_command("查看订阅", priority=5, block=True)
driver: Driver = nonebot.get_driver()
@@ -79,10 +86,13 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
id_ = ""
if isinstance(event, GroupMessageEvent):
if not await LevelUser.check_level(
- event.user_id, event.group_id, GROUP_BILIBILI_SUB_LEVEL
+ event.user_id,
+ event.group_id,
+ Config.get_config("bilibili_sub", "GROUP_BILIBILI_SUB_LEVEL"),
):
await add_sub.finish(
- f"您的权限不足,群内订阅的需要 {GROUP_BILIBILI_SUB_LEVEL} 级权限..", at_sender=True
+ f"您的权限不足,群内订阅的需要 {Config.get_config('bilibili_sub', 'GROUP_BILIBILI_SUB_LEVEL')} 级权限..",
+ at_sender=True,
)
sub_user = f"{event.user_id}:{event.group_id}"
else:
@@ -134,44 +144,52 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
if not is_number(msg):
- await del_sub.finish('Id必须为数字!', at_sender=True)
- id_ = f'{event.user_id}:{event.group_id}' if isinstance(event, GroupMessageEvent) else f'{event.user_id}'
+ await del_sub.finish("Id必须为数字!", at_sender=True)
+ id_ = (
+ f"{event.user_id}:{event.group_id}"
+ if isinstance(event, GroupMessageEvent)
+ else f"{event.user_id}"
+ )
if await BilibiliSub.delete_bilibili_sub(int(msg), id_):
- await del_sub.send(f'删除订阅id:{msg} 成功...')
+ await del_sub.send(f"删除订阅id:{msg} 成功...")
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 删除订阅 {id_}"
)
else:
- await del_sub.send(f'删除订阅id:{msg} 失败...')
+ await del_sub.send(f"删除订阅id:{msg} 失败...")
@show_sub_info.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
- id_ = f'{event.user_id}:{event.group_id}' if isinstance(event, GroupMessageEvent) else f'{event.user_id}'
+ id_ = (
+ f"{event.user_id}:{event.group_id}"
+ if isinstance(event, GroupMessageEvent)
+ else f"{event.user_id}"
+ )
data = await BilibiliSub.get_sub_data(id_)
- live_rst = ''
- up_rst = ''
- season_rst = ''
+ live_rst = ""
+ up_rst = ""
+ season_rst = ""
for x in data:
- if x.sub_type == 'live':
- live_rst += f'\t直播间id:{x.sub_id}\n' \
- f'\t名称:{x.uname}\n' \
- f'------------------\n'
- if x.sub_type == 'up':
- up_rst += f'\tUP:{x.uname}\n' \
- f'\tuid:{x.uid}\n' \
- f'------------------\n'
- if x.sub_type == 'season':
- season_rst += f'\t番名:{x.season_name}\n' \
- f'\t当前集数:{x.season_current_episode}\n' \
- f'------------------\n'
- live_rst = '当前订阅的直播:\n' + live_rst if live_rst else live_rst
- up_rst = '当前订阅的UP:\n' + up_rst if up_rst else up_rst
- season_rst = '当前订阅的番剧:\n' + season_rst if season_rst else season_rst
+ if x.sub_type == "live":
+ live_rst += (
+ f"\t直播间id:{x.sub_id}\n" f"\t名称:{x.uname}\n" f"------------------\n"
+ )
+ if x.sub_type == "up":
+ up_rst += f"\tUP:{x.uname}\n" f"\tuid:{x.uid}\n" f"------------------\n"
+ if x.sub_type == "season":
+ season_rst += (
+ f"\t番名:{x.season_name}\n"
+ f"\t当前集数:{x.season_current_episode}\n"
+ f"------------------\n"
+ )
+ live_rst = "当前订阅的直播:\n" + live_rst if live_rst else live_rst
+ up_rst = "当前订阅的UP:\n" + up_rst if up_rst else up_rst
+ season_rst = "当前订阅的番剧:\n" + season_rst if season_rst else season_rst
if not live_rst and not up_rst and not season_rst:
- live_rst = '您目前没有任何订阅...'
+ live_rst = "您目前没有任何订阅..."
await show_sub_info.send(live_rst + up_rst + season_rst)
diff --git a/plugins/bilibili_sub/data_source.py b/plugins/bilibili_sub/data_source.py
index a99251e2..3261df3e 100644
--- a/plugins/bilibili_sub/data_source.py
+++ b/plugins/bilibili_sub/data_source.py
@@ -1,6 +1,7 @@
from bilibili_api.exceptions.ResponseCodeException import ResponseCodeException
+from utils.manager import resources_manager
from asyncio.exceptions import TimeoutError
-from models.bilibili_sub import BilibiliSub
+from .model import BilibiliSub
from bilibili_api.live import LiveRoom
from bilibili_api import bangumi
from utils.message_builder import image
@@ -23,6 +24,9 @@ dynamic_path = Path(IMAGE_PATH) / "bilibili_sub" / "dynamic"
dynamic_path.mkdir(exist_ok=True, parents=True)
+resources_manager.add_temp_dir(dynamic_path)
+
+
async def add_live_sub(live_id: int, sub_user: str) -> str:
"""
添加直播订阅
diff --git a/models/bilibili_sub.py b/plugins/bilibili_sub/model.py
similarity index 100%
rename from models/bilibili_sub.py
rename to plugins/bilibili_sub/model.py
diff --git a/plugins/bt/__init__.py b/plugins/bt/__init__.py
index f99020e6..d155550e 100644
--- a/plugins/bt/__init__.py
+++ b/plugins/bt/__init__.py
@@ -32,6 +32,13 @@ __plugin_settings__ = {
__plugin_block_limit__ = {
"rst": "您有bt任务正在进行,请等待结束."
}
+__plugin_configs__ = {
+ "BT_MAX_NUM": {
+ "value": 10,
+ "help": "单次BT搜索返回最大消息数量",
+ "default_value": 10,
+ }
+}
bt = on_command("bt", permission=PRIVATE, priority=5, block=True)
diff --git a/plugins/bt/data_source.py b/plugins/bt/data_source.py
index 80a5433b..3ea7270e 100644
--- a/plugins/bt/data_source.py
+++ b/plugins/bt/data_source.py
@@ -1,6 +1,6 @@
from utils.user_agent import get_user_agent
import aiohttp
-from configs.config import MAXINFO_BT
+from configs.config import Config
from bs4 import BeautifulSoup
from utils.utils import get_local_proxy
import platform
@@ -24,7 +24,9 @@ async def get_bt_info(keyword: str, page: str):
return
soup = BeautifulSoup(text, "lxml")
item_lst = soup.find_all("div", {"class": "search-item"})
- for item in item_lst[:MAXINFO_BT]:
+ bt_max_num = Config.get_config("bt", "BT_MAX_NUM")
+ bt_max_num = bt_max_num if bt_max_num < len(item_lst) else len(item_lst)
+ for item in item_lst[:bt_max_num]:
divs = item.find_all("div")
title = (
str(divs[0].find("a").text)
diff --git a/plugins/check/__init__.py b/plugins/check/__init__.py
index 0861ffb2..dd008217 100644
--- a/plugins/check/__init__.py
+++ b/plugins/check/__init__.py
@@ -4,6 +4,7 @@ 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
__zx_plugin_name__ = "服务器自我检查 [Superuser]"
@@ -29,4 +30,4 @@ check_ = on_command(
@check_.handle()
async def _(bot: Bot, event: Event, state: T_State):
- await check_.send(await check.show())
+ await check_.send(image(b64=await check.show()))
diff --git a/plugins/check/data_source.py b/plugins/check/data_source.py
index baa0af81..81b156ee 100644
--- a/plugins/check/data_source.py
+++ b/plugins/check/data_source.py
@@ -6,6 +6,9 @@ from utils.user_agent import get_user_agent
from asyncio.exceptions import TimeoutError
from aiohttp.client_exceptions import ClientConnectorError
from utils.utils import get_local_proxy
+from utils.image_utils import CreateImg
+from configs.path_config import IMAGE_PATH
+from pathlib import Path
import asyncio
from services.log import logger
@@ -57,6 +60,7 @@ class Check:
async def show(self):
await self.check_all()
+ A = CreateImg(0, 0, font_size=24)
rst = (
f'[Time] {str(datetime.now()).split(".")[0]}\n'
f"-----System-----\n"
@@ -69,4 +73,17 @@ class Check:
)
if self.user:
rst += "-----User-----\n" + self.user
- return rst
+ width = 0
+ height = 0
+ for x in rst.split('\n'):
+ w, h = A.getsize(x)
+ if w > width:
+ width = w
+ height += 30
+ A = CreateImg(width + 50, height + 10, font_size=24, font="HWZhongSong.ttf")
+ A.transparent(1)
+ A.text((10, 10), rst)
+ _x = max(width, height)
+ bk = CreateImg(_x + 100, _x + 100, background=Path(IMAGE_PATH) / "background" / "check" / "0.jpg")
+ bk.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 525fbf4b..1014025b 100644
--- a/plugins/check_zhenxun_update/__init__.py
+++ b/plugins/check_zhenxun_update/__init__.py
@@ -6,7 +6,7 @@ from .data_source import check_update, get_latest_version_data
from services.log import logger
from utils.utils import scheduler, get_bot
from pathlib import Path
-from configs.config import AUTO_UPDATE_ZHENXUN
+from configs.config import Config
from nonebot.rule import to_me
import platform
import os
@@ -24,6 +24,13 @@ __plugin_des__ = "就算是真寻也会成长的"
__plugin_cmd__ = ["检查更新真寻", "重启"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
+__plugin_configs__ = {
+ "AUTO_UPDATE_ZHENXUN": {
+ "value": False,
+ "help": "真寻是否自动检查更新",
+ "default": False,
+ }
+}
update_zhenxun = on_command("检查更新真寻", permission=SUPERUSER, priority=1, block=True)
@@ -82,7 +89,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
minute=0,
)
async def _():
- if AUTO_UPDATE_ZHENXUN:
+ if Config.get_config("check_zhenxun_update", "AUTO_UPDATE_ZHENXUN"):
_version = "v0.0.0"
_version_file = Path() / "__version__"
if _version_file.exists():
diff --git a/plugins/coser/__init__.py b/plugins/coser/__init__.py
index 9e5d78cc..1d67c019 100644
--- a/plugins/coser/__init__.py
+++ b/plugins/coser/__init__.py
@@ -41,7 +41,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
try:
for _ in range(3):
try:
- async with session.get(url, proxy=get_local_proxy(), timeout=2) as response:
+ async with session.get(url, proxy=get_local_proxy(), timeout=2, verify_ssl=False) as response:
_url = (await response.json())['text']
async with session.get(
_url, timeout=5, proxy=get_local_proxy(), verify_ssl=False
diff --git a/plugins/csgo/__init__.py b/plugins/csgo/__init__.py
new file mode 100644
index 00000000..e955a89f
--- /dev/null
+++ b/plugins/csgo/__init__.py
@@ -0,0 +1,69 @@
+from nonebot import on_command
+from nonebot.typing import T_State
+from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
+from utils.utils import get_message_text, is_number
+from .data_source import get_csgola_data, get_5e_data
+from services.log import logger
+
+
+__zx_plugin_name__ = "cs国服/平台信息查找"
+__plugin_usage__ = """
+usage:
+ 快速查询csgo战绩和数据
+ 指令:
+ cs国服查询 [steam主页个人id]
+ 5e查询 [5e战绩个人名称]
+ 示例:cs国服查询 23848238483
+ 示例:5e查询 poster
+"""
+__plugin_des__ = "什么?你也是rush B玩家?"
+__plugin_cmd__ = ["cs国服查询 [steam主页个人id]", "5e查询 [5e战绩个人名称]"]
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+__plugin_settings__ = {
+ "level": 5,
+ "default_status": True,
+ "limit_superuser": False,
+ "cmd": ["csgo战绩查询", "cs国服查询", "5e查询"],
+}
+
+csgola = on_command("cs国服查询", priority=5, block=True)
+
+csgo5e = on_command("5e查询", priority=5, block=True)
+
+
+@csgola.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ msg = get_message_text(event.json())
+ if "http" in msg:
+ msg = msg[:-1] if msg[-1] == "/" else msg
+ msg = msg.split("/")[-1]
+ if not is_number(msg):
+ await csgola.finish("Id必须为数字!", at_sender=True)
+ await csgola.send("开始查找...")
+ img, code = await get_csgola_data(int(msg))
+ if code == 200:
+ await csgola.send(img, at_sender=True)
+ logger.info(
+ f"(USER {event.user_id}, GROUP "
+ f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
+ f" 查询csgo国服战绩:{msg}"
+ )
+ else:
+ await csgola.send(img, at_sender=True)
+
+
+@csgo5e.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ msg = get_message_text(event.json())
+ await csgola.send("开始查找...")
+ img, code = await get_5e_data(msg)
+ if code == 200:
+ await csgo5e.send(img, at_sender=True)
+ logger.info(
+ f"(USER {event.user_id}, GROUP "
+ f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
+ f" 查询csgo国服战绩:{msg}"
+ )
+ else:
+ await csgo5e.send(img, at_sender=True)
diff --git a/plugins/csgo/data_source.py b/plugins/csgo/data_source.py
new file mode 100644
index 00000000..b6c6969e
--- /dev/null
+++ b/plugins/csgo/data_source.py
@@ -0,0 +1,130 @@
+from configs.path_config import IMAGE_PATH
+from utils.image_utils import CreateImg
+from utils.message_builder import image
+from services.log import logger
+from utils.browser import get_browser
+from playwright._impl._api_types import TimeoutError
+
+csgola_url = "https://www.csgola.com/player/"
+_5e_url = "https://arena.5eplay.com/data/player/"
+
+
+async def get_csgola_data(uid: int) -> "str, int":
+ page = None
+ try:
+ browser = await get_browser()
+ if not browser:
+ return "", 997
+ page = await browser.new_page()
+ for _ in range(3):
+ try:
+ await page.goto(f"{csgola_url}{uid}", wait_until="networkidle", timeout=10000)
+ break
+ except TimeoutError:
+ pass
+ else:
+ return '连接超时...', 995
+ await page.set_viewport_size({"width": 2560, "height": 1080})
+
+ data = await page.query_selector_all(".panel-body")
+ if not data:
+ return "未查询到该Id....", 999
+ await data[0].screenshot(path=f"{IMAGE_PATH}/temp/{uid}_1.png", timeout=100000)
+ await data[3].screenshot(path=f"{IMAGE_PATH}/temp/{uid}_2.png", timeout=100000)
+ await data[5].screenshot(path=f"{IMAGE_PATH}/temp/{uid}_3.png", timeout=100000)
+ await data[7].screenshot(path=f"{IMAGE_PATH}/temp/{uid}_5.png", timeout=100000)
+
+ ava = await page.query_selector("div.container:nth-child(4) > div:nth-child(1)")
+ await ava.screenshot(path=f"{IMAGE_PATH}/temp/{uid}_0.png", timeout=100000)
+
+ weapon_data = await page.query_selector(".gun-stats-sec")
+ await weapon_data.screenshot(
+ path=f"{IMAGE_PATH}/temp/{uid}_4.png", timeout=100000
+ )
+
+ ava = CreateImg(0, 0, background=f"{IMAGE_PATH}/temp/{uid}_0.png")
+ statistical_data = CreateImg(0, 0, background=f"{IMAGE_PATH}/temp/{uid}_1.png")
+ combined_data = CreateImg(0, 0, background=f"{IMAGE_PATH}/temp/{uid}_2.png")
+ detailed_data = CreateImg(0, 0, background=f"{IMAGE_PATH}/temp/{uid}_3.png")
+ weapon_data = CreateImg(0, 0, background=f"{IMAGE_PATH}/temp/{uid}_4.png")
+ map_data = CreateImg(0, 0, background=f"{IMAGE_PATH}/temp/{uid}_5.png")
+ if statistical_data.h > 300:
+ statistical_data.crop((0, 0, statistical_data.w, 300))
+ if combined_data.h > 260:
+ combined_data.crop((0, 0, combined_data.w, 260))
+ if detailed_data.h > 400:
+ detailed_data.crop((0, 0, detailed_data.w, 400))
+ weapon_data.crop((0, 100, weapon_data.w, weapon_data.h))
+ map_data.crop((0, 310, map_data.w, map_data.h))
+ height = (
+ ava.h
+ + statistical_data.h
+ + combined_data.h
+ + detailed_data.h
+ + weapon_data.h
+ + map_data.h
+ )
+ bk = CreateImg(1168, height)
+ current_h = 0
+ for img in [
+ ava,
+ statistical_data,
+ combined_data,
+ detailed_data,
+ weapon_data,
+ map_data,
+ ]:
+ bk.paste(img, (0, current_h))
+ current_h += img.h
+ bk.save(f"{IMAGE_PATH}/temp/csgo_{uid}.png")
+ except Exception as e:
+ logger.error(f"生成csgola图片错误 {type(e)}:{e}")
+ if page:
+ await page.close()
+ return "发生了错误....", 998
+ if page:
+ await page.close()
+ return image(f"csgo_{uid}.png", "temp"), 200
+
+
+async def get_5e_data(uname: str) -> "str, int":
+ page = None
+ try:
+ browser = await get_browser()
+ if not browser:
+ return "", 997
+ page = await browser.new_page()
+ await page.goto(f"{_5e_url}{uname}", wait_until="networkidle", timeout=10000)
+ if "HTTP ERROR 404" in await page.content():
+ return "未查询到该玩家...", 999
+ await page.set_viewport_size({"width": 2560, "height": 1080})
+ body = await page.query_selector("body")
+ await body.screenshot(
+ path=f"{IMAGE_PATH}/temp/csgo_{uname}_0.png", timeout=100000
+ )
+ await page.click("a.match-tab-item:nth-child(2)")
+ body = await page.query_selector("body")
+ await body.screenshot(
+ path=f"{IMAGE_PATH}/temp/csgo_{uname}_1.png", timeout=100000
+ )
+ await page.click("a.match-tab-item:nth-child(1)")
+ body = await page.query_selector("body")
+ await body.screenshot(
+ path=f"{IMAGE_PATH}/temp/csgo_{uname}_2.png", timeout=100000
+ )
+ bk = CreateImg(1344 * 3, 2307)
+ current_w = 0
+ for i in range(3):
+ body = CreateImg(0, 0, background=f"{IMAGE_PATH}/temp/csgo_{uname}_{i}.png")
+ body.crop((600, 90, body.w - 600, body.h - 410))
+ bk.paste(body, (current_w, 0))
+ current_w += 1344
+ bk.save(f"{IMAGE_PATH}/temp/csgo_{uname}.png")
+ except Exception as e:
+ logger.error(f"生成5e图片错误 {type(e)}:{e}")
+ if page:
+ await page.close()
+ return "发生了错误...", 998
+ if page:
+ await page.close()
+ return image(f"csgo_{uname}.png", "temp"), 200
diff --git a/plugins/dialogue/__init__.py b/plugins/dialogue/__init__.py
index cfb0a818..e8ad4c1e 100644
--- a/plugins/dialogue/__init__.py
+++ b/plugins/dialogue/__init__.py
@@ -4,6 +4,7 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEven
from nonebot.permission import SUPERUSER
from utils.utils import get_message_text, is_number, get_message_imgs
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
@@ -52,7 +53,7 @@ __plugin_settings__ = {
dialogue_data = {}
-dialogue = on_command("[滴滴滴]", aliases={"滴滴滴-"}, priority=1, block=True)
+dialogue = on_command("[滴滴滴]", aliases={"滴滴滴-"}, priority=5, block=True)
reply = on_command("/t", priority=1, permission=SUPERUSER, block=True)
@@ -61,7 +62,7 @@ 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())
- img_msg = ""
+ img_msg = _text("")
for img in get_message_imgs(event.json()):
img_msg += image(img)
if not text or text in ["帮助"]:
@@ -78,15 +79,16 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
nickname = event.sender.card if event.sender.card else event.sender.nickname
await bot.send_private_msg(
user_id=coffee,
- message=Message(
+ message=_text(
f"*****一份交流报告*****\n"
f"昵称:{nickname}({uid})\n"
f"群聊:{group_name}({group_id})\n"
- f"消息:{text} {img_msg}"
- ),
+ f"消息:{text}"
+ )
+ + img_msg,
)
await dialogue.send(
- Message(f"您的话已发送至管理员!\n======\n{text}{img_msg}"), at_sender=True
+ _text(f"您的话已发送至管理员!\n======\n{text}") + img_msg, at_sender=True
)
nickname = event.sender.nickname if event.sender.nickname else event.sender.card
dialogue_data[len(dialogue_data)] = {
@@ -94,7 +96,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
"user_id": event.user_id,
"group_id": group_id,
"group_name": group_name,
- "msg": f"{text} {img_msg}",
+ "msg": _text(text) + img_msg,
}
# print(dialogue_data)
logger.info(f"Q{uid}@群{group_id} 联系管理员:{coffee} text:{text}")
diff --git a/plugins/draw_card/config.py b/plugins/draw_card/config.py
index 2340d01e..e3a91db0 100644
--- a/plugins/draw_card/config.py
+++ b/plugins/draw_card/config.py
@@ -1,31 +1,56 @@
import nonebot
from pathlib import Path
from configs.path_config import DATA_PATH
-from configs.config import FGO_FLAG, PCR_FLAG, AZUR_FLAG, PRTS_FLAG,\
- PRETTY_FLAG, GUARDIAN_FLAG, GENSHIN_FLAG, ONMYOJI_FLAG, PCR_TAI, SEMAPHORE
+from configs.config import Config
+
try:
import ujson as json
except ModuleNotFoundError:
import json
-DRAW_PATH = DATA_PATH + '/draw_card/'
+DRAW_PATH = DATA_PATH + "/draw_card/"
_draw_config = Path(rf"{DRAW_PATH}/draw_card_config/draw_card_config.json")
-# 开关
-PRTS_FLAG = PRTS_FLAG
-GENSHIN_FLAG = GENSHIN_FLAG
-PRETTY_FLAG = PRETTY_FLAG
-GUARDIAN_FLAG = GUARDIAN_FLAG
-PCR_FLAG = PCR_FLAG
-AZUR_FLAG = AZUR_FLAG
-FGO_FLAG = FGO_FLAG
-ONMYOJI_FLAG = ONMYOJI_FLAG
+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")
-PCR_TAI = PCR_TAI
-SEMAPHORE = SEMAPHORE
# 方舟概率
PRTS_SIX_P = 0.02
@@ -97,244 +122,290 @@ ONMYOJI_R = 0.7875
path_dict = {
- 'genshin': '原神',
- 'prts': '明日方舟',
- 'pretty': '赛马娘',
- 'guardian': '坎公骑冠剑',
- 'pcr': '公主连结',
- 'azur': '碧蓝航线',
- 'fgo': '命运-冠位指定',
- 'onmyoji': '阴阳师',
+ "genshin": "原神",
+ "prts": "明日方舟",
+ "pretty": "赛马娘",
+ "guardian": "坎公骑冠剑",
+ "pcr": "公主连结",
+ "azur": "碧蓝航线",
+ "fgo": "命运-冠位指定",
+ "onmyoji": "阴阳师",
}
driver: nonebot.Driver = nonebot.get_driver()
config_default_data = {
-
- 'path_dict': {
- 'genshin': '原神',
- 'prts': '明日方舟',
- 'pretty': '赛马娘',
- 'guardian': '坎公骑冠剑',
- 'pcr': '公主连结',
- 'azur': '碧蓝航线',
- 'fgo': '命运-冠位指定',
- 'onmyoji': '阴阳师',
+ "path_dict": {
+ "genshin": "原神",
+ "prts": "明日方舟",
+ "pretty": "赛马娘",
+ "guardian": "坎公骑冠剑",
+ "pcr": "公主连结",
+ "azur": "碧蓝航线",
+ "fgo": "命运-冠位指定",
+ "onmyoji": "阴阳师",
},
-
- 'prts': {
- 'PRTS_SIX_P': 0.02,
- 'PRTS_FIVE_P': 0.08,
- 'PRTS_FOUR_P': 0.48,
- 'PRTS_THREE_P': 0.42,
+ "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,
+ "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,
+ "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,
+ "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,
+ "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,
+ "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,
+ "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,
},
-
- 'onmyoji': {
- 'ONMYOJI_SP': 0.0025,
- 'ONMYOJI_SSR': 0.01,
- 'ONMYOJI_SR': 0.2,
- 'ONMYOJI_R': 0.7875,
- }
}
@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
+ 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'))
+ 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:配置文件不存在或格式错误,已重新生成配置文件.....')
+ json.dump(
+ config_default_data,
+ open(_draw_config, "w", encoding="utf8"),
+ indent=4,
+ ensure_ascii=False,
+ )
+ print("draw_card:配置文件不存在或格式错误,已重新生成配置文件.....")
else:
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'])
+ 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']
+ 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"]
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'])
+ 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']
+ 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'])
+ 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']
+ 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'])
+ 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']
+ 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'])
+ 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']
+ 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'])
+ 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']
+ 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'])
+ 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']
+ 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'])
+ 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)
-
-
-
-
+ 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
+ )
diff --git a/plugins/epic/data_source.py b/plugins/epic/data_source.py
index 32d14b03..ed78181a 100644
--- a/plugins/epic/data_source.py
+++ b/plugins/epic/data_source.py
@@ -1,7 +1,11 @@
from httpx import AsyncClient
from datetime import datetime
from nonebot.log import logger
-from nonebot.adapters.cqhttp import Bot, Event, GroupMessageEvent
+from nonebot.adapters.cqhttp import (
+ Bot,
+ Event,
+ GroupMessageEvent,
+)
from configs.config import NICKNAME
@@ -109,6 +113,16 @@ async def get_epic_free(bot: Bot, event: Event):
}
msg_list.append(data)
else:
+ msg = "[CQ:image,file={}]\n\nFREE now :: {} ({})\n{}\n此游戏由 {} 开发、{} 发行,将在 UTC 时间 {} 结束免费游玩,戳链接速度加入你的游戏库吧~\n{}\n".format(
+ game_thumbnail,
+ game_name,
+ game_price,
+ game_desp,
+ game_dev,
+ game_pub,
+ end_date,
+ game_url,
+ )
msg_list.append(msg)
except TypeError as e:
# logger.info(str(e))
diff --git a/plugins/fudu.py b/plugins/fudu.py
index 1c36f524..56423c4c 100644
--- a/plugins/fudu.py
+++ b/plugins/fudu.py
@@ -9,9 +9,9 @@ from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
import aiohttp
import aiofiles
-from asyncio.exceptions import TimeoutError
-from configs.config import FUDU_PROBABILITY
+from configs.config import Config
from utils.manager import group_manager
+from services.log import logger
__zx_plugin_name__ = "复读"
@@ -24,6 +24,9 @@ __plugin_type__ = ("被动相关",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {"fudu": "复读"}
+__plugin_configs__ = {
+ "FUDU_PROBABILITY": {"value": 0.7, "help": "复读概率", "default_value": 0.7}
+}
class Fudu:
@@ -98,9 +101,9 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
_fudu_list.clear(event.group_id)
_fudu_list.append(event.group_id, add_msg)
if _fudu_list.size(event.group_id) > 2:
- if random.random() < FUDU_PROBABILITY and not _fudu_list.is_repeater(
- event.group_id
- ):
+ if random.random() < Config.get_config(
+ "fudu", "FUDU_PROBABILITY"
+ ) and not _fudu_list.is_repeater(event.group_id):
if random.random() < 0.2:
await fudu.finish("打断施法!")
_fudu_list.set_repeater(event.group_id)
@@ -126,5 +129,6 @@ async def get_fudu_img_hash(url, group_id):
await f.write(await response.read())
img_hash = get_img_hash(IMAGE_PATH + f"temp/compare_{group_id}_img.jpg")
return str(img_hash)
- except TimeoutError:
+ except Exception as e:
+ logger.warning(f"复读读取图片Hash出错 {type(e)}:{e}")
return ""
diff --git a/plugins/genshin/query_resource_points/query_resource.py b/plugins/genshin/query_resource_points/query_resource.py
index d763ec5a..e7fc3ed2 100644
--- a/plugins/genshin/query_resource_points/query_resource.py
+++ b/plugins/genshin/query_resource_points/query_resource.py
@@ -178,17 +178,22 @@ async def download_map_init(
if not _map.exists():
# padding_w, padding_h = data['padding']
data = data["slices"]
- map_url = data[0][0]['url']
- await download_image(
- map_url,
- f"{map_path}/map.png",
- session,
- semaphore,
- force_flag=flag,
- )
- map_file = CreateImg(
- 0, 0, background=f"{map_path}/map.png", ratio=MAP_RATIO
- )
+ idx = 0
+ for _map_data in data[0]:
+ map_url = _map_data['url']
+ await download_image(
+ map_url,
+ f"{map_path}/{idx}.png",
+ session,
+ 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"]}')
diff --git a/plugins/hook.py b/plugins/hook.py
deleted file mode 100644
index ac244d6e..00000000
--- a/plugins/hook.py
+++ /dev/null
@@ -1,467 +0,0 @@
-from nonebot.matcher import Matcher
-from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
-from nonebot.adapters.cqhttp.exception import ActionFailed
-from models.group_member_info import GroupInfoUser
-from utils.manager import (
- plugins2cd_manager,
- plugins2block_manager,
- plugins2settings_manager,
- admin_manager
-)
-from models.friend_user import FriendUser
-from typing import Optional
-from nonebot.typing import T_State
-from nonebot.adapters.cqhttp import (
- Bot,
- Event,
- MessageEvent,
- PrivateMessageEvent,
- GroupMessageEvent,
- PokeNotifyEvent,
- Message,
-)
-from configs.config import (
- BAN_RESULT,
- MALICIOUS_BAN_TIME,
- MALICIOUS_CHECK_TIME,
- MALICIOUS_BAN_COUNT,
- CHECK_NOTICE_INFO_CD,
-)
-from models.ban_user import BanUser
-from utils.utils import (
- is_number,
- static_flmt,
- BanCheckLimiter,
- FreqLimiter,
-)
-from utils.manager import withdraw_message_manager
-from utils.message_builder import at
-from services.log import logger
-from models.level_user import LevelUser
-from utils.manager import group_manager
-import asyncio
-
-try:
- import ujson as json
-except ModuleNotFoundError:
- import json
-
-
-# 检查是否被ban
-@run_preprocessor
-async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
- try:
- if (
- await BanUser.is_super_ban(event.user_id)
- and str(event.user_id) not in bot.config.superusers
- ):
- raise IgnoredException("用户处于超级黑名单中")
- except AttributeError:
- pass
- if not isinstance(event, MessageEvent):
- return
- if matcher.type == "message" and matcher.priority not in [1, 9]:
- if (
- await BanUser.is_ban(event.user_id)
- and str(event.user_id) not in bot.config.superusers
- ):
- time = await BanUser.check_ban_time(event.user_id)
- if is_number(time):
- time = abs(int(time))
- if time < 60:
- time = str(time) + " 秒"
- else:
- time = str(int(time / 60)) + " 分钟"
- else:
- time = str(time) + " 分钟"
- if isinstance(event, GroupMessageEvent):
- if not static_flmt.check(event.user_id):
- raise IgnoredException("用户处于黑名单中")
- static_flmt.start_cd(event.user_id)
- if matcher.priority != 9:
- try:
- await bot.send_group_msg(
- group_id=event.group_id,
- message=at(event.user_id)
- + BAN_RESULT
- + f" 在..在 {time} 后才会理你喔",
- )
- except ActionFailed:
- pass
- else:
- if not static_flmt.check(event.user_id):
- raise IgnoredException("用户处于黑名单中")
- static_flmt.start_cd(event.user_id)
- if matcher.priority != 9:
- try:
- await bot.send_private_msg(
- user_id=event.user_id,
- message=at(event.user_id)
- + BAN_RESULT
- + f" 在..在 {time}后才会理你喔",
- )
- except ActionFailed:
- pass
- raise IgnoredException("用户处于黑名单中")
-
-
-_blmt = BanCheckLimiter(MALICIOUS_CHECK_TIME, MALICIOUS_BAN_COUNT)
-
-
-# 恶意触发命令检测
-@run_preprocessor
-async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State):
- if not isinstance(event, MessageEvent):
- return
- if matcher.type == "message" and matcher.priority not in [1, 9]:
- if state["_prefix"]["raw_command"]:
- if _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'):
- if await BanUser.ban(event.user_id, 9, MALICIOUS_BAN_TIME * 60):
- logger.info(f"USER {event.user_id} 触发了恶意触发检测")
- if isinstance(event, GroupMessageEvent):
- try:
- await bot.send_group_msg(
- group_id=event.group_id,
- message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟",
- )
- except ActionFailed:
- pass
- else:
- try:
- await bot.send_private_msg(
- user_id=event.user_id,
- message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟",
- )
- except ActionFailed:
- pass
- raise IgnoredException("检测到恶意触发命令")
- _blmt.add(f'{event.user_id}{state["_prefix"]["raw_command"]}')
-
-
-_flmt = FreqLimiter(CHECK_NOTICE_INFO_CD)
-_flmt_g = FreqLimiter(CHECK_NOTICE_INFO_CD)
-_flmt_s = FreqLimiter(CHECK_NOTICE_INFO_CD)
-_flmt_c = FreqLimiter(CHECK_NOTICE_INFO_CD)
-_exists_msg = {}
-
-
-ignore_rst_module = ["ai", "poke"]
-
-
-# 权限检测
-@run_preprocessor
-async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
- global _exists_msg
- module = matcher.module
- plugins2info_dict = plugins2settings_manager.get_data()
- if (
- (not isinstance(event, MessageEvent) and module != "poke")
- or await BanUser.is_ban(event.user_id)
- and str(event.user_id) not in bot.config.superusers
- ) or (
- str(event.user_id) in bot.config.superusers
- and plugins2info_dict.get(module)
- and not plugins2info_dict[module]["limit_superuser"]
- ):
- return
- # 黑名单检测
- if isinstance(event, GroupMessageEvent):
- if group_manager.get_group_level(event.group_id) < 0:
- raise IgnoredException("群黑名单")
- if module in admin_manager.keys() and matcher.priority not in [1, 9]:
- if isinstance(event, GroupMessageEvent):
- # 个人权限
- if not await LevelUser.check_level(
- event.user_id, event.group_id, admin_manager.get_plugin_level(module)
- ):
- try:
- if _flmt.check(event.user_id):
- _flmt.start_cd(event.user_id)
- await bot.send_group_msg(
- group_id=event.group_id,
- message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
- f"{admin_manager.get_plugin_level(module)}",
- )
- except ActionFailed:
- pass
- raise IgnoredException("权限不足")
- else:
- if not await LevelUser.check_level(
- event.user_id, 0, admin_manager.get_plugin_level(module)
- ):
- try:
- await bot.send_private_msg(
- user_id=event.user_id,
- message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(module)}",
- )
- except ActionFailed:
- pass
- raise IgnoredException("权限不足")
- if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]:
- # 戳一戳单独判断
- if isinstance(event, GroupMessageEvent) or (
- isinstance(event, PokeNotifyEvent) and event.group_id
- ):
- if _exists_msg.get(event.group_id) is None:
- _exists_msg[event.group_id] = False
- # 群权限
- if plugins2info_dict[module]["level"] > group_manager.get_group_level(
- event.group_id
- ):
- try:
- if _flmt_g.check(event.user_id) and module not in ignore_rst_module:
- _flmt_g.start_cd(event.user_id)
- await bot.send_group_msg(
- group_id=event.group_id, message="群权限不足..."
- )
- except ActionFailed:
- pass
- _exists_msg[event.group_id] = True
- raise IgnoredException("群权限不足")
- # 插件状态
- if not group_manager.get_plugin_status(module, event.group_id):
- try:
- if module not in ignore_rst_module and _flmt_s.check(
- event.group_id
- ):
- _flmt_s.start_cd(event.group_id)
- await bot.send_group_msg(
- group_id=event.group_id, message="该群未开启此功能.."
- )
- except ActionFailed:
- pass
- _exists_msg[event.group_id] = True
- print(123123)
- raise IgnoredException("未开启此功能...")
- # 管理员禁用
- if not group_manager.get_plugin_status(f"{module}:super", event.group_id):
- try:
- if (
- _flmt_s.check(event.group_id)
- and module not in ignore_rst_module
- ):
- _flmt_s.start_cd(event.group_id)
- await bot.send_group_msg(
- group_id=event.group_id, message="管理员禁用了此群该功能..."
- )
- except ActionFailed:
- pass
- _exists_msg[event.group_id] = True
- raise IgnoredException("管理员禁用了此群该功能...")
- # 群聊禁用
- if not group_manager.get_plugin_status(module, block_type="group"):
- try:
- if (
- _flmt_c.check(event.group_id)
- and module not in ignore_rst_module
- ):
- _flmt_c.start_cd(event.group_id)
- await bot.send_group_msg(
- group_id=event.group_id, message="该功能在群聊中已被禁用..."
- )
- except ActionFailed:
- pass
- _exists_msg[event.group_id] = True
- raise IgnoredException("该插件在群聊中已被禁用...")
- else:
- # 私聊禁用
- if not group_manager.get_plugin_status(module, block_type="private"):
- try:
- if _flmt_c.check(event.user_id):
- _flmt_c.start_cd(event.user_id)
- await bot.send_private_msg(
- user_id=event.user_id, message="该功能在私聊中已被禁用..."
- )
- except ActionFailed:
- pass
- raise IgnoredException("该插件在私聊中已被禁用...")
- # 维护
- if not group_manager.get_plugin_status(module, block_type="all"):
- if isinstance(
- event, GroupMessageEvent
- ) and group_manager.check_group_is_white(event.group_id):
- return
- try:
- if isinstance(event, GroupMessageEvent):
- if (
- _flmt_c.check(event.group_id)
- and module not in ignore_rst_module
- ):
- _flmt_c.start_cd(event.group_id)
- await bot.send_group_msg(
- group_id=event.group_id, message="此功能正在维护..."
- )
- else:
- await bot.send_private_msg(
- user_id=event.user_id, message="此功能正在维护..."
- )
- except ActionFailed:
- pass
- if isinstance(event, GroupMessageEvent):
- _exists_msg[event.group_id] = True
- raise IgnoredException("此功能正在维护...")
-
-
-# 命令cd 和 命令阻塞
-@run_preprocessor
-async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
- global _exists_msg
- if not isinstance(event, MessageEvent) and matcher.module != "poke":
- return
- module = matcher.module
- if isinstance(event, GroupMessageEvent) and _exists_msg.get(event.group_id) is None:
- _exists_msg[event.group_id] = False
- if plugins2cd_manager.check_plugin_cd_status(module):
- plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
- check_type = plugin_cd_data["check_type"]
- limit_type = plugin_cd_data["limit_type"]
- rst = plugin_cd_data["rst"]
- if (
- (isinstance(event, PrivateMessageEvent) and check_type == "private")
- or (isinstance(event, GroupMessageEvent) and check_type == "group")
- or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
- ):
- cd_type_ = event.user_id
- if limit_type == "group" and isinstance(event, GroupMessageEvent):
- cd_type_ = event.group_id
- if not plugins2cd_manager.check(module, cd_type_):
- if rst:
- rst = await init_rst(rst, event)
- await send_msg(rst, bot, event)
- raise IgnoredException(f"{module} 正在cd中...")
- else:
- plugins2cd_manager.start_cd(module, cd_type_)
- 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"]
- rst = plugin_block_data["rst"]
- if (
- (isinstance(event, PrivateMessageEvent) and check_type == "private")
- or (isinstance(event, GroupMessageEvent) and check_type == "group")
- or check_type == "all"
- ):
- block_type_ = event.user_id
- if limit_type == "group" and isinstance(event, GroupMessageEvent):
- block_type_ = event.group_id
- if plugins2block_manager.check(block_type_, module):
- if rst:
- rst = await init_rst(rst, event)
- await send_msg(rst, bot, event)
- raise IgnoredException(f"{event.user_id}正在调用{module}....")
- else:
- plugins2block_manager.set_true(block_type_, module)
-
-
-async def send_msg(rst: str, bot: Bot, event: MessageEvent):
- """
- 发送信息
- :param rst: pass
- :param bot: pass
- :param event: pass
- """
- global _exists_msg
- rst = await init_rst(rst, event)
- try:
- if isinstance(event, GroupMessageEvent):
- _exists_msg[event.group_id] = True
- await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
- else:
- _exists_msg[event.user_id] = True
- await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
- except ActionFailed:
- pass
-
-
-@run_postprocessor
-async def _(
- matcher: Matcher,
- exception: Optional[Exception],
- bot: Bot,
- event: Event,
- state: T_State,
-):
- if not isinstance(event, MessageEvent) and matcher.module != "poke":
- return
- module = matcher.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)
-
-
-async def init_rst(rst: str, event: MessageEvent):
- if "[uname]" in rst:
- uname = event.sender.card if event.sender.card else event.sender.nickname
- rst = rst.replace("[uname]", uname)
- if "[nickname]" in rst:
- if isinstance(event, GroupMessageEvent):
- nickname = await GroupInfoUser.get_group_member_nickname(
- event.user_id, event.group_id
- )
- else:
- nickname = await FriendUser.get_friend_nickname(event.user_id)
- rst = rst.replace("[nickname]", nickname)
- if "[at]" in rst and isinstance(event, GroupMessageEvent):
- rst = rst.replace("[at]", str(at(event.user_id)))
- return rst
-
-
-# 消息撤回
-@run_postprocessor
-async def _(
- matcher: Matcher,
- exception: Optional[Exception],
- bot: Bot,
- event: Event,
- state: T_State,
-):
- tasks = []
- for id_, time in withdraw_message_manager.data:
- tasks.append(asyncio.ensure_future(_withdraw_message(bot, id_, time)))
- withdraw_message_manager.remove((id_, time))
- await asyncio.gather(*tasks)
-
-
-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))
-
-
-# 为什么AI会自己和自己聊天
-@run_preprocessor
-async def _(matcher: Matcher, bot: Bot, event: PrivateMessageEvent, state: T_State):
- if not isinstance(event, MessageEvent):
- return
- if event.user_id == int(bot.self_id):
- raise IgnoredException("为什么AI会自己和自己聊天")
-
-
-# 有命令就别说话了
-@run_preprocessor
-async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
- global _exists_msg
- if not isinstance(event, MessageEvent):
- return
- if matcher.type == "message":
- if matcher.module == "ai":
- if (
- isinstance(event, GroupMessageEvent)
- and _exists_msg.get(event.group_id) is True
- ):
- _exists_msg[event.group_id] = False
- raise IgnoredException("有命令就别说话了")
- elif (
- isinstance(event, PrivateMessageEvent)
- and _exists_msg.get(event.user_id) is True
- ):
- _exists_msg[event.user_id] = False
- raise IgnoredException("有命令就别说话了")
diff --git a/plugins/image_management/__init__.py b/plugins/image_management/__init__.py
index 60531929..1e5ef28d 100644
--- a/plugins/image_management/__init__.py
+++ b/plugins/image_management/__init__.py
@@ -1,3 +1,48 @@
+from configs.config import Config
import nonebot
+
+Config.add_plugin_config(
+ "image_management",
+ "IMAGE_DIR_LIST",
+ ["美图", "萝莉", "壁纸"],
+ name="图库操作",
+ help_="公开图库列表,可自定义添加 [如果含有send_setu插件,请不要添加色图库]",
+ default_value=[],
+)
+
+Config.add_plugin_config(
+ "image_management",
+ "WITHDRAW_IMAGE_MESSAGE",
+ (0, 1),
+ name="图库操作",
+ help_="自动撤回,参1:延迟撤回发送图库图片的时间(秒),0 为关闭 | 参2:监控聊天类型,0(私聊) 1(群聊) 2(群聊+私聊)",
+ default_value=(0, 1),
+)
+
+Config.add_plugin_config(
+ "image_management:delete_img",
+ "DELETE_IMAGE_LEVEL [LEVEL]",
+ 7,
+ help_="删除图库图片需要的管理员等级",
+ default_value=7,
+)
+
+Config.add_plugin_config(
+ "image_management:move_img",
+ "MOVE_IMAGE_LEVEL [LEVEL]",
+ 7,
+ help_="移动图库图片需要的管理员等级",
+ default_value=7,
+)
+
+Config.add_plugin_config(
+ "image_management:upload_img",
+ "UPLOAD_IMAGE_LEVEL [LEVEL]",
+ 6,
+ help_="上传图库图片需要的管理员等级",
+ default_value=6,
+)
+
+
nonebot.load_plugins("plugins/image_management")
diff --git a/plugins/image_management/delete_img/__init__.py b/plugins/image_management/delete_img/__init__.py
index e3e85ff9..e7d9b70c 100644
--- a/plugins/image_management/delete_img/__init__.py
+++ b/plugins/image_management/delete_img/__init__.py
@@ -5,9 +5,8 @@ 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 configs.config import DELETE_IMG_LEVEL
-from configs.config import IMAGE_DIR_LIST
from utils.utils import is_number, cn2py, get_message_text
+from configs.config import Config
from pathlib import Path
import os
@@ -25,7 +24,7 @@ __plugin_cmd__ = ["删除图片 [图库] [id]", "查看公开图库"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
- "admin_level": DELETE_IMG_LEVEL
+ "admin_level": Config.get_config("image_management", "DELETE_IMAGE_LEVEL")
}
@@ -37,7 +36,7 @@ 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 IMAGE_DIR_LIST:
+ if get_message_text(event.json()) not in Config.get_config("image_management", "IMAGE_DIR_LIST"):
await delete_img.reject("此目录不正确,请重新输入目录!")
state[state["_current_key"]] = get_message_text(event.json())
if state["_current_key"] == "id":
@@ -53,7 +52,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
args = raw_arg.split(" ")
if args[0] in ["帮助"]:
await delete_img.finish(__plugin_usage__)
- if len(args) >= 2 and args[0] in IMAGE_DIR_LIST and is_number(args[1]):
+ if len(args) >= 2 and args[0] in Config.get_config("image_management", "IMAGE_DIR_LIST") and is_number(args[1]):
state["path"] = args[0]
state["id"] = args[1]
diff --git a/plugins/image_management/move_img/__init__.py b/plugins/image_management/move_img/__init__.py
index f541e883..90a177f2 100644
--- a/plugins/image_management/move_img/__init__.py
+++ b/plugins/image_management/move_img/__init__.py
@@ -4,7 +4,7 @@ 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 configs.config import IMAGE_DIR_LIST, MOVE_IMG_LEVEL
+from configs.config import Config
from utils.utils import is_number, cn2py
from configs.path_config import IMAGE_PATH
from pathlib import Path
@@ -24,7 +24,7 @@ __plugin_cmd__ = ["移动图片 [源图库] [目标图库] [id]", "查看公开
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
- "admin_level": MOVE_IMG_LEVEL
+ "admin_level": Config.get_config("image_management", "MOVE_IMAGE_LEVEL")
}
@@ -36,7 +36,9 @@ 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 IMAGE_DIR_LIST:
+ 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":
@@ -54,8 +56,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
await move_img.finish(__plugin_usage__)
if (
len(args) >= 3
- and args[0] in IMAGE_DIR_LIST
- and args[1] in IMAGE_DIR_LIST
+ 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]
@@ -78,9 +80,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
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"
- )
+ os.rename(source_path / f"{img_id}.jpg", destination_path / f"{des_max_id}.jpg")
logger.info(
f"移动 {source_path}/{img_id}.jpg ---> {destination_path}/{des_max_id} 移动成功"
)
diff --git a/plugins/send_img/__init__.py b/plugins/image_management/send_img/__init__.py
similarity index 73%
rename from plugins/send_img/__init__.py
rename to plugins/image_management/send_img/__init__.py
index 548b2984..57f9e1f9 100644
--- a/plugins/send_img/__init__.py
+++ b/plugins/image_management/send_img/__init__.py
@@ -1,135 +1,124 @@
-from nonebot import on_command, on_keyword, on_regex
-from configs.path_config import IMAGE_PATH
-from utils.message_builder import image
-from utils.utils import get_message_text, is_number
-import os
-import random
-from services.log import logger
-from nonebot.typing import T_State
-from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
-from utils.utils import FreqLimiter, cn2py
-from configs.config import IMAGE_DIR_LIST
-from utils.manager import group_manager
-
-try:
- import ujson as json
-except ModuleNotFoundError:
- import json
-
-if "色图" in IMAGE_DIR_LIST:
- IMAGE_DIR_LIST.remove("色图")
-
-__zx_plugin_name__ = "发送本地图库图片"
-__plugin_usage__ = f"""
-usage:
- 发送指定图库下的随机或指定id图片
- 指令:
- {IMAGE_DIR_LIST} ?[id]
- 示例:美图
- 示例: 萝莉 2
-""".strip()
-__plugin_des__ = "让看看我的私藏,指[图片]"
-__plugin_cmd__ = IMAGE_DIR_LIST
-__plugin_type__ = ("来点好康的",)
-__plugin_version__ = 0.1
-__plugin_author__ = "HibiKier"
-__plugin_settings__ = {
- "level": 5,
- "default_status": True,
- "limit_superuser": False,
- "cmd": ["发送图片"] + IMAGE_DIR_LIST,
-}
-__plugin_task__ = {"pa": "丢人爬"}
-
-_flmt = FreqLimiter(1)
-
-cmd = set(IMAGE_DIR_LIST)
-
-# print(cmd)
-
-send_img = on_command("img", aliases=cmd, priority=5, block=True)
-pa = on_keyword({"丢人爬", "爪巴"}, priority=5, block=True)
-pa_reg = on_regex("^爬$", priority=5, block=True)
-
-search_url = "https://api.fantasyzone.cc/tu/search.php"
-
-
-@send_img.handle()
-async def _(bot: Bot, event: MessageEvent, state: T_State):
- img_id = get_message_text(event.json())
- path = cn2py(state["_prefix"]["raw_command"]) + "/"
- if state["_prefix"]["raw_command"] in IMAGE_DIR_LIST:
- if not os.path.exists(f"{IMAGE_PATH}/{path}/"):
- os.mkdir(f"{IMAGE_PATH}/{path}/")
- length = len(os.listdir(IMAGE_PATH + path)) - 1
- if length < 1:
- await send_img.finish("该图库中没有图片噢")
- logger.warning(f"图库 {path} 为空,调用取消!")
- return
- index = img_id if img_id else str(random.randint(0, length))
- if not is_number(index):
- await send_img.finish("id错误!")
- if int(index) > length or int(index) < 0:
- await send_img.finish(f"超过当前上下限!({length - 1})")
- result = image(f"{index}.jpg", path)
- if result:
- logger.info(
- f"(USER {event.user_id}, GROUP "
- f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送{path}:"
- + result
- )
- await send_img.finish(f"id:{index}" + result)
- else:
- logger.info(
- f"(USER {event.user_id}, GROUP "
- f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送 {path} 失败"
- )
- 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
- if _flmt.check(event.user_id):
- _flmt.start_cd(event.user_id)
- await pa.finish(image(random.choice(os.listdir(IMAGE_PATH + "pa")), "pa"))
-
-
-num_key = {
- "一": 1,
- "二": 2,
- "两": 2,
- "双": 2,
- "三": 3,
- "四": 4,
- "五": 5,
- "六": 6,
- "七": 7,
- "八": 8,
- "九": 9,
-}
+from nonebot import on_command, on_keyword, 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 services.log import logger
+from nonebot.typing import T_State
+from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
+from utils.utils import FreqLimiter, cn2py
+from configs.config import Config
+from utils.manager import group_manager, withdraw_message_manager
+import random
+import os
+
+try:
+ import ujson as json
+except ModuleNotFoundError:
+ import json
+
+__zx_plugin_name__ = "发送本地图库图片"
+__plugin_usage__ = f"""
+usage:
+ 发送指定图库下的随机或指定id图片
+ 指令:
+ {Config.get_config("image_management", "IMAGE_DIR_LIST")} ?[id]
+ 示例:美图
+ 示例: 萝莉 2
+""".strip()
+__plugin_des__ = "让看看我的私藏,指[图片]"
+__plugin_cmd__ = Config.get_config("image_management", "IMAGE_DIR_LIST")
+__plugin_type__ = ("来点好康的",)
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+__plugin_settings__ = {
+ "level": 5,
+ "default_status": True,
+ "limit_superuser": False,
+ "cmd": ["发送图片"] + Config.get_config("image_management", "IMAGE_DIR_LIST"),
+}
+__plugin_task__ = {"pa": "丢人爬"}
+__plugin_resources__ = {
+ "pa": IMAGE_PATH
+}
+
+_flmt = FreqLimiter(1)
+
+cmd = set(Config.get_config("image_management", "IMAGE_DIR_LIST"))
+
+# print(cmd)
+
+send_img = on_command("img", aliases=cmd, priority=5, block=True)
+pa = on_keyword({"丢人爬", "爪巴"}, priority=5, block=True)
+pa_reg = on_regex("^爬$", priority=5, block=True)
+
+search_url = "https://api.fantasyzone.cc/tu/search.php"
+
+
+@send_img.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ img_id = get_message_text(event.json())
+ path = cn2py(state["_prefix"]["raw_command"]) + "/"
+ if state["_prefix"]["raw_command"] in Config.get_config(
+ "image_management", "IMAGE_DIR_LIST"
+ ):
+ if not os.path.exists(f"{IMAGE_PATH}/{path}/"):
+ os.mkdir(f"{IMAGE_PATH}/{path}/")
+ length = len(os.listdir(IMAGE_PATH + path))
+ if length == 0:
+ logger.warning(f"图库 {path} 为空,调用取消!")
+ await send_img.finish("该图库中没有图片噢")
+ index = img_id if img_id else str(random.randint(0, length))
+ if not is_number(index):
+ return
+ if int(index) > length - 1 or int(index) < 0:
+ await send_img.finish(f"超过当前上下限!({length - 1})")
+ result = image(f"{index}.jpg", path)
+ if result:
+ logger.info(
+ f"(USER {event.user_id}, GROUP "
+ f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送{path}:"
+ + result
+ )
+ msg_id = await send_img.send(f"id:{index}" + result)
+ withdraw_message_manager.withdraw_message(
+ event,
+ msg_id,
+ Config.get_config("image_management", "WITHDRAW_IMAGE_MESSAGE"),
+ )
+ else:
+ logger.info(
+ f"(USER {event.user_id}, GROUP "
+ f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送 {path} 失败"
+ )
+ 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
+ if _flmt.check(event.user_id):
+ _flmt.start_cd(event.user_id)
+ await pa.finish(image(random.choice(os.listdir(IMAGE_PATH + "pa")), "pa"))
diff --git a/plugins/image_management/upload_img/__init__.py b/plugins/image_management/upload_img/__init__.py
index 082b0184..cc2f5908 100644
--- a/plugins/image_management/upload_img/__init__.py
+++ b/plugins/image_management/upload_img/__init__.py
@@ -3,7 +3,7 @@ from nonebot.rule import to_me
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
-from configs.config import IMAGE_DIR_LIST, UPLOAD_IMG_LEVEL
+from configs.config import Config
from utils.utils import get_message_imgs, get_message_text
from .data_source import upload_image_to_local
@@ -23,7 +23,7 @@ __plugin_des__ = "指定图库图片上传"
__plugin_cmd__ = ["上传图片 [图库] [图片]", "连续上传图片 [图库]", "查看公开图库"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
-__plugin_settings__ = {"admin_level": UPLOAD_IMG_LEVEL}
+__plugin_settings__ = {"admin_level": Config.get_config("image_management", "DELETE_IMAGE_LEVEL")}
upload_img = on_command("上传图片", rule=to_me(), priority=5, block=True)
@@ -35,7 +35,7 @@ show_gallery = on_command("查看公开图库", priority=1, block=True)
@show_gallery.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
x = '公开图库列表:\n'
- for i, e in enumerate(IMAGE_DIR_LIST):
+ for i, e in enumerate(Config.get_config("image_management", "IMAGE_DIR_LIST")):
x += f'\t{i+1}.{e}\n'
await show_gallery.send(x[:-1])
@@ -46,7 +46,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
if msg in ["取消", "算了"]:
await upload_img.finish("已取消操作..", at_sender=True)
if state["_current_key"] in ["path"]:
- if msg not in IMAGE_DIR_LIST:
+ 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"]:
@@ -60,7 +60,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
raw_arg = get_message_text(event.json())
img_list = get_message_imgs(event.json())
if raw_arg:
- if raw_arg in IMAGE_DIR_LIST:
+ if raw_arg in Config.get_config("image_management", "IMAGE_DIR_LIST"):
state["path"] = raw_arg
if img_list:
state["imgs"] = img_list
@@ -88,7 +88,7 @@ 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 IMAGE_DIR_LIST:
+ 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:
@@ -104,7 +104,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
@continuous_upload_img.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
path = get_message_imgs(event.json())
- if path in IMAGE_DIR_LIST:
+ if path in Config.get_config("image_management", "IMAGE_DIR_LIST"):
state["path"] = path
await continuous_upload_img.send("图来!!")
state["tmp"] = []
diff --git a/plugins/init_config/__init__.py b/plugins/init_config/__init__.py
deleted file mode 100644
index 926c6f5c..00000000
--- a/plugins/init_config/__init__.py
+++ /dev/null
@@ -1,36 +0,0 @@
-from .data_source import (
- init_plugins_settings,
- init_plugins_cd_limit,
- init_plugins_block_limit,
- init_group_manager,
-)
-from nonebot.adapters.cqhttp import Bot
-from configs.path_config import DATA_PATH
-from services.log import logger
-from nonebot import Driver
-import nonebot
-
-
-__zx_plugin_name__ = "初始化插件数据 [Hidden]"
-__plugin_version__ = 0.1
-__plugin_author__ = "HibiKier"
-
-
-driver: Driver = nonebot.get_driver()
-
-
-@driver.on_startup
-def _():
- """
- 初始化数据
- """
- init_plugins_settings(DATA_PATH)
- init_plugins_cd_limit(DATA_PATH)
- init_plugins_block_limit(DATA_PATH)
- logger.info("初始化数据完成...")
-
-
-@driver.on_bot_connect
-async def _(bot: Bot):
- await init_group_manager()
-
diff --git a/plugins/init_config/data_source.py b/plugins/init_config/data_source.py
deleted file mode 100644
index ae90a75d..00000000
--- a/plugins/init_config/data_source.py
+++ /dev/null
@@ -1,290 +0,0 @@
-from pathlib import Path
-from ruamel.yaml import YAML, round_trip_load, round_trip_dump
-from utils.manager import (
- plugins2settings_manager,
- plugins2cd_manager,
- plugins2block_manager,
- group_manager,
- admin_manager
-)
-from services.db_context import db
-from asyncpg.exceptions import DuplicateColumnError
-from services.log import logger
-from utils.utils import get_matchers
-import nonebot
-
-try:
- import ujson as json
-except ModuleNotFoundError:
- import json
-try:
- from models.group_remind import GroupRemind
-except ModuleNotFoundError:
- pass
-
-yaml = YAML(typ="safe")
-
-
-def init_plugins_settings(data_path: str):
- """
- 初始化插件设置,从插件中获取 __zx_plugin_name__,__plugin_cmd__,__plugin_settings__
- """
- plugins2config_file = Path(data_path) / "configs" / "plugins2settings.yaml"
- plugins2config_file.parent.mkdir(exist_ok=True, parents=True)
- _matchers = get_matchers()
- _data = {}
- if plugins2config_file.exists():
- with open(plugins2config_file, "r", encoding="utf8") as f:
- _data = yaml.load(f)
- _data = _data["PluginSettings"] if _data else {}
- _tmp_module = {}
- _tmp = []
- for matcher in _matchers:
- if matcher.module in _data.keys():
- plugins2settings_manager.add_plugin_settings(
- matcher.module,
- plugin_type=_data[matcher.module]["plugin_type"],
- data_dict=_data[matcher.module],
- )
- if _data[matcher.module]['cmd']:
- _tmp_module[matcher.module] = _data[matcher.module]['cmd'][0]
- else:
- _plugin = nonebot.plugin.get_plugin(matcher.module)
- _module = _plugin.module
- try:
- plugin_name = _module.__getattribute__("__zx_plugin_name__")
- if "[admin]" in plugin_name.lower():
- try:
- level = (_module.__getattribute__("__plugin_settings__"))['admin_level']
- except (AttributeError, KeyError):
- level = 5
- admin_manager.add_admin_command(matcher.module, 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()
- ):
- continue
- except AttributeError:
- if matcher.module not in _tmp:
- logger.warning(
- f"获取插件 {matcher.module} __zx_plugin_name__ 失败...,插件控制未加载."
- )
- else:
- try:
- _tmp_module[matcher.module] = plugin_name
- plugin_settings = _module.__getattribute__("__plugin_settings__")
- if plugin_settings['cmd'] and plugin_name not in plugin_settings['cmd']:
- plugin_settings['cmd'].append(plugin_name)
- if plugins2settings_manager.get(
- matcher.module
- ) and plugins2settings_manager[matcher.module].get("plugin_type"):
- plugin_type = tuple(
- plugins2settings_manager.get_plugin_data(matcher.module)[
- "plugin_type"
- ]
- )
- else:
- try:
- plugin_type = _module.__getattribute__("__plugin_type__")
- except AttributeError:
- plugin_type = ("normal",)
- if plugin_settings and matcher.module:
- plugins2settings_manager.add_plugin_settings(
- matcher.module,
- plugin_type=plugin_type,
- data_dict=plugin_settings,
- )
- except AttributeError:
- pass
- _tmp.append(matcher.module)
- _tmp_data = {"PluginSettings": plugins2settings_manager.get_data()}
- with open(plugins2config_file, "w", encoding="utf8") as wf:
- yaml.dump(_tmp_data, wf)
- _data = round_trip_load(open(plugins2config_file, encoding="utf8"))
- _data["PluginSettings"].yaml_set_start_comment(
- """# 模块与对应命令和对应群权限
-# 用于生成帮助图片 和 开关功能
-# key:模块名称
-# level:需要的群等级
-# default_status:加入群时功能的默认开关状态
-# limit_superuser: 功能状态是否限制超级用户
-# cmd: 关闭[cmd] 都会触发命令 关闭对应功能,cmd列表第一个词为统计的功能名称
-# plugin_type: 帮助类别 示例:('原神相关',) 或 ('原神相关', 1),1代表帮助命令列向排列,否则为横向排列""",
- indent=2,
- )
- for plugin in _data["PluginSettings"].keys():
- _data["PluginSettings"][plugin].yaml_set_start_comment(
- f"{plugin}:{_tmp_module[plugin]}", indent=2
- )
- with open(plugins2config_file, "w", encoding="utf8") as wf:
- round_trip_dump(_data, wf)
- logger.info(f"已成功加载 {len(plugins2settings_manager.get_data())} 个非限制插件.")
- print(admin_manager)
-
-
-def init_plugins_cd_limit(data_path):
- """
- 加载 cd 限制
- """
- plugins2cd_file = Path(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)
- _module = _plugin.module
- try:
- plugin_cd_limit = _module.__getattribute__("__plugin_cd_limit__")
- plugins2cd_manager.add_cd_limit(
- matcher.module, data_dict=plugin_cd_limit
- )
- except AttributeError:
- pass
- if plugins2cd_file.exists():
- with open(plugins2cd_file, "r", encoding="utf8") as f:
- _data = yaml.load(f)
- _data = _data if _data else {}
- if _data.get("PluginCdLimit"):
- for plugin in _data["PluginCdLimit"].keys():
- plugins2cd_manager.add_cd_limit(
- plugin, data_dict=_data["PluginCdLimit"][plugin]
- )
- _tmp_data = {"PluginCdLimit": plugins2cd_manager.get_data()}
- with open(plugins2cd_file, "w", encoding="utf8") as wf:
- yaml.dump(_tmp_data, wf)
- _data = round_trip_load(open(plugins2cd_file, encoding="utf8"))
- _data["PluginCdLimit"].yaml_set_start_comment(
- """# 需要cd的功能
-# 自定义的功能需要cd也可以在此配置
-# key:模块名称
-# cd:cd 时长(秒)
-# status:此限制的开关状态
-# check_type:'private'/'group'/'all',限制私聊/群聊/全部
-# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
-# 示例:'user':用户N秒内触发1次,'group':群N秒内触发1次
-# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
-# rst 为 "" 或 None 时则不回复
-# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
-# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
-# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
- indent=2,
- )
- with open(plugins2cd_file, "w", encoding="utf8") as wf:
- round_trip_dump(_data, wf)
- plugins2cd_manager.reload_cd_limit()
-
-
-def init_plugins_block_limit(data_path):
- """
- 加载阻塞限制
- """
- plugins2block_file = Path(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)
- _module = _plugin.module
- try:
- plugin_block_limit = _module.__getattribute__("__plugin_block_limit__")
- plugins2block_manager.add_block_limit(
- matcher.module, data_dict=plugin_block_limit
- )
- except AttributeError:
- pass
- if plugins2block_file.exists():
- with open(plugins2block_file, "r", encoding="utf8") as f:
- _data = yaml.load(f)
- _data = _data if _data else {}
- if _data.get("PluginBlockLimit"):
- for plugin in _data["PluginBlockLimit"].keys():
- plugins2block_manager.add_block_limit(
- plugin, data_dict=_data["PluginBlockLimit"][plugin]
- )
- _tmp_data = {"PluginBlockLimit": plugins2block_manager.get_data()}
- with open(plugins2block_file, "w", encoding="utf8") as wf:
- yaml.dump(_tmp_data, wf)
- _data = round_trip_load(open(plugins2block_file, encoding="utf8"))
- _data["PluginBlockLimit"].yaml_set_start_comment(
- """# 用户调用阻塞
-# 即 当用户调用此功能还未结束时
-# 用发送消息阻止用户重复调用此命令直到该命令结束
-# key:模块名称
-# cd:cd 时长(秒)
-# status:此限制的开关状态
-# check_type:'private'/'group'/'all',限制私聊/群聊/全部
-# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
-# 示例:'user':用户N秒内触发1次,'group':群N秒内触发1次
-# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
-# rst 为 "" 或 None 时则不回复
-# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
-# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
-# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
- indent=2,
- )
- with open(plugins2block_file, "w", encoding="utf8") as wf:
- round_trip_dump(_data, wf)
- plugins2block_manager.reload_block_limit()
-
-
-async def init_group_manager():
- """
- 旧数据格式替换为新格式
- 初始化数据
- """
- old_group_level_file = Path() / "data" / "manager" / "group_level.json"
- old_plugin_list_file = Path() / "data" / "manager" / "plugin_list.json"
- if old_group_level_file.exists():
- data = json.load(open(old_group_level_file, "r", encoding="utf8"))
- for key in data.keys():
- group = key
- level = data[key]
- group_manager.set_group_level(group, level)
- old_group_level_file.unlink()
- group_manager.save()
-
- if old_plugin_list_file.exists():
- data = json.load(open(old_plugin_list_file, "r", encoding="utf8"))
- for plugin in data.keys():
- for group in data[plugin].keys():
- if group == "default" and not data[plugin]["default"]:
- group_manager.block_plugin(plugin)
- elif not data[plugin][group]:
- group_manager.block_plugin(plugin, group)
- old_plugin_list_file.unlink()
- old_data_table = Path() / "models" / "group_remind.py"
- try:
- if old_data_table.exists():
- b = {
- "hy": "group_welcome",
- "kxcz": "open_case_reset_remind",
- "zwa": "zwa",
- "blpar": "bilibili_parse",
- "epic": "epic_free_game",
- "pa": "pa",
- "almanac": "genshin_alc",
- }
- for group in group_manager.get_data()["group_manager"]:
- for remind in b:
- try:
- status = await GroupRemind.get_status(int(group), remind)
- if status is not None:
- if status:
- await group_manager.open_group_task(group, b[remind])
- logger.info(f"读取旧数据-->{group} 开启 {b[remind]}")
- else:
- await group_manager.close_group_task(group, b[remind])
- logger.info(f"读取旧数据-->{group} 关闭 {b[remind]}")
- except Exception as e:
- pass
- query = db.text("DROP TABLE group_reminds;")
- await db.first(query)
- old_data_table.unlink()
- logger.info("旧数据读取完毕,删除了舍弃表 group_reminds...")
- except (ModuleNotFoundError, DuplicateColumnError):
- pass
- group_manager.save()
diff --git a/plugins/jitang.py b/plugins/jitang.py
index e631126b..a3663741 100644
--- a/plugins/jitang.py
+++ b/plugins/jitang.py
@@ -5,6 +5,7 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from nonebot.typing import T_State
import aiohttp
from asyncio.exceptions import TimeoutError
+from configs.config import Config
__zx_plugin_name__ = "鸡汤"
@@ -33,7 +34,7 @@ jitang = on_command("鸡汤", aliases={"毒鸡汤"}, priority=5, block=True)
@jitang.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
- params = {"format": "json", "token": "h0KuF6qNniMHGUtA"}
+ params = {"format": "json", "token": f"{Config.get_config('alapi', 'ALAPI_TOKEN')}"}
try:
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(url, timeout=7, params=params) as response:
diff --git a/plugins/mute.py b/plugins/mute.py
index 9035386d..0cd87fc7 100644
--- a/plugins/mute.py
+++ b/plugins/mute.py
@@ -9,15 +9,9 @@ from nonebot.adapters.cqhttp.exception import ActionFailed
from configs.path_config import DATA_PATH, IMAGE_PATH
from utils.image_utils import get_img_hash
from services.log import logger
-from configs.config import MUTE_LEVEL
+from configs.config import NICKNAME, Config
import aiohttp
import aiofiles
-from configs.config import (
- MUTE_DEFAULT_COUNT,
- MUTE_DEFAULT_TIME,
- MUTE_DEFAULT_DURATION,
- NICKNAME,
-)
try:
import ujson as json
@@ -40,7 +34,29 @@ __plugin_des__ = "刷屏禁言相关操作"
__plugin_cmd__ = ["设置刷屏检测时间 [秒]", "设置刷屏检测次数 [次数]", "设置刷屏禁言时长 [分钟]", "刷屏检测设置"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
-__plugin_settings__ = {"admin_level": MUTE_LEVEL}
+__plugin_settings__ = {"admin_level": Config.get_config("mute", "MUTE_LEVEL")}
+__plugin_configs__ = {
+ "MUTE_LEVEL [LEVEL]": {
+ "value": 5,
+ "help": "更改禁言设置的管理权限",
+ "default_value": 5
+ },
+ "MUTE_DEFAULT_COUNT": {
+ "value": 10,
+ "help": "刷屏禁言默认检测次数",
+ "default_value": 10
+ },
+ "MUTE_DEFAULT_TIME": {
+ "value": 7,
+ "help": "刷屏检测默认规定时间",
+ "default_value": 7
+ },
+ "MUTE_DEFAULT_DURATION": {
+ "value": 10,
+ "help": "刷屏检测默禁言时长(分钟)",
+ "default_value": 10
+ },
+}
mute = on_message(priority=1, block=False)
@@ -98,9 +114,9 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
msg += img_hash
if not mute_data.get(group_id):
mute_data[group_id] = {
- "count": MUTE_DEFAULT_COUNT,
- "time": MUTE_DEFAULT_TIME,
- "duration": MUTE_DEFAULT_DURATION,
+ "count": Config.get_config("mute", "MUTE_DEFAULT_COUNT"),
+ "time": Config.get_config("mute", "MUTE_DEFAULT_TIME"),
+ "duration": Config.get_config("mute", "MUTE_DEFAULT_DURATION"),
}
if not mute_dict.get(event.user_id):
mute_dict[event.user_id] = {"time": time.time(), "count": 1, "msg": msg}
diff --git a/plugins/nonebot_plugin_picsearcher/__init__.py b/plugins/nonebot_plugin_picsearcher/__init__.py
index 48659189..9810adac 100644
--- a/plugins/nonebot_plugin_picsearcher/__init__.py
+++ b/plugins/nonebot_plugin_picsearcher/__init__.py
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
-import traceback
from typing import Dict
from aiohttp.client_exceptions import ClientError
@@ -8,7 +7,7 @@ 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_imgs
-from configs.config import MAX_FIND_IMG_COUNT
+from configs.config import Config
from nonebot.rule import to_me
from .ex import get_des as get_des_ex
@@ -37,6 +36,9 @@ __plugin_settings__ = {
"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):
@@ -109,11 +111,13 @@ async def get_setu(bot: Bot, event: MessageEvent, state: T_State):
async for msg in get_des(url, mod, event.user_id):
if msg:
await bot.send(event=event, message=msg)
- if idx == MAX_FIND_IMG_COUNT:
+ if idx == Config.get_config(
+ "nonebot_plugin_picsearcher", "MAX_FIND_IMAGE_COUNT"
+ ):
break
idx += 1
if id == 1:
- await bot.send(event=event, message='没找着.')
+ 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}"
@@ -163,7 +167,9 @@ async def handle_previous(bot: Bot, event: GroupMessageEvent, state: T_State):
idx = 1
async for msg in get_des(url, "nao", event.user_id):
await bot.send(event=event, message=msg)
- if idx == MAX_FIND_IMG_COUNT:
+ if idx == Config.get_config(
+ "nonebot_plugin_picsearcher", "MAX_FIND_IMAGE_COUNT"
+ ):
break
idx += 1
except IndexError:
diff --git a/plugins/one_friend/__init__.py b/plugins/one_friend/__init__.py
index 6e175b87..f1526bef 100644
--- a/plugins/one_friend/__init__.py
+++ b/plugins/one_friend/__init__.py
@@ -1,14 +1,12 @@
-import aiohttp
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
+from utils.utils import get_message_text, get_message_at, get_user_avatar
from utils.message_builder import image
import re
from utils.image_utils import CreateImg
-from asyncio.exceptions import TimeoutError
__zx_plugin_name__ = "我有一个朋友"
__plugin_usage__ = """
@@ -35,18 +33,6 @@ one_friend = on_regex(
)
-async def get_pic(qq):
- url = f"http://q1.qlogo.cn/g?b=qq&nk={qq}&s=100"
- async with aiohttp.ClientSession() as session:
- for _ in range(3):
- try:
- async with session.get(url, timeout=5) as response:
- return await response.read()
- except TimeoutError:
- pass
- return None
-
-
@one_friend.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
msg = get_message_text(event.json())
@@ -72,11 +58,11 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
if not msg:
msg = "都不知道问什么"
msg = msg.replace("他", "我").replace("她", "我").replace("它", "我")
- x = await get_pic(qq)
+ x = await get_user_avatar(qq)
if x:
- ava = CreateImg(100, 100, background=BytesIO(await get_pic(qq)))
+ ava = CreateImg(200, 100, background=BytesIO(x))
else:
- ava = CreateImg(100, 100, color=(0, 0, 0))
+ ava = CreateImg(200, 100, color=(0, 0, 0))
ava.circle()
text = CreateImg(300, 30, font_size=30)
text.text((0, 0), user_name)
diff --git a/plugins/open_cases/__init__.py b/plugins/open_cases/__init__.py
index b8ca3407..155881d4 100644
--- a/plugins/open_cases/__init__.py
+++ b/plugins/open_cases/__init__.py
@@ -8,6 +8,7 @@ from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent
from nonebot.permission import SUPERUSER
import random
from nonebot.plugin import MatcherGroup
+from configs.path_config import IMAGE_PATH
import re
from .open_cases_c import (
open_case,
@@ -68,6 +69,20 @@ __plugin_settings__ = {
}
__plugin_task__ = {"open_case_reset_remind": "每日开箱重置提醒"}
__plugin_cd_limit__ = {"rst": "着什么急啊,慢慢来!"}
+__plugin_resources__ = {f"cases": IMAGE_PATH}
+__plugin_configs__ = {
+ "INITIAL_OPEN_CASE_COUNT": {"value": 20, "help": "初始每日开箱次数", "default_value": 20},
+ "EACH_IMPRESSION_ADD_COUNT": {
+ "value": 3,
+ "help": "每 * 点好感度额外增加开箱次数",
+ "default_value": 3,
+ },
+ "COOKIE": {
+ "value": None,
+ "help": "BUFF的cookie",
+ },
+ "BUFF_PROXY": {"value": None, "help": "使用代理访问BUFF"},
+}
cases_name = ["狂牙大行动", "突围大行动", "命悬一线", "裂空", "光谱"]
diff --git a/plugins/open_cases/models/__init__.py b/plugins/open_cases/models/__init__.py
new file mode 100644
index 00000000..a944b2fd
--- /dev/null
+++ b/plugins/open_cases/models/__init__.py
@@ -0,0 +1,2 @@
+from .open_cases_user import *
+from .buff_prices import *
diff --git a/models/buff_price.py b/plugins/open_cases/models/buff_prices.py
similarity index 95%
rename from models/buff_price.py
rename to plugins/open_cases/models/buff_prices.py
index 852f30e7..1c988ee1 100644
--- a/models/buff_price.py
+++ b/plugins/open_cases/models/buff_prices.py
@@ -8,6 +8,7 @@ from services.db_context import db
class BuffPrice(db.Model):
__tablename__ = 'buff_prices'
+ __table_args__ = {'extend_existing': True}
id = db.Column(db.Integer(), primary_key=True)
case_id = db.Column(db.Integer(), nullable=False)
diff --git a/models/open_cases_user.py b/plugins/open_cases/models/open_cases_user.py
similarity index 98%
rename from models/open_cases_user.py
rename to plugins/open_cases/models/open_cases_user.py
index 85c8c60e..99662bb2 100644
--- a/models/open_cases_user.py
+++ b/plugins/open_cases/models/open_cases_user.py
@@ -5,6 +5,7 @@ from services.db_context import db
class OpenCasesUser(db.Model):
__tablename__ = 'open_cases_users'
+ __table_args__ = {'extend_existing': True}
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
diff --git a/plugins/open_cases/open_cases_c.py b/plugins/open_cases/open_cases_c.py
index 20de162f..b8ff2fe6 100644
--- a/plugins/open_cases/open_cases_c.py
+++ b/plugins/open_cases/open_cases_c.py
@@ -2,39 +2,40 @@ from datetime import datetime, timedelta
from .config import *
from services.log import logger
from services.db_context import db
-from models.open_cases_user import OpenCasesUser
+from .models.open_cases_user import OpenCasesUser
from models.sign_group_user import SignGroupUser
from utils.message_builder import image
import pypinyin
import random
from .utils import get_price
-from models.buff_price import BuffPrice
+from .models.buff_prices import BuffPrice
from PIL import Image
from utils.image_utils import alpha2white_pil, CreateImg
from configs.path_config import IMAGE_PATH
import asyncio
from utils.utils import cn2py
-from configs.config import INITIAL_OPEN_CASE_COUNT
-
-
-MAX_COUNT = INITIAL_OPEN_CASE_COUNT
+from configs.config import Config
async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动") -> str:
- if case_name not in ["狂牙大行动", "突围大行动", "命悬一线", '裂空', '光谱']:
+ if case_name not in ["狂牙大行动", "突围大行动", "命悬一线", "裂空", "光谱"]:
return "武器箱未收录"
knifes_flag = False
# lan zi fen hong jin price
uplist = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0]
case = ""
for i in pypinyin.pinyin(case_name, style=pypinyin.NORMAL):
- case += ''.join(i)
+ case += "".join(i)
impression = (await SignGroupUser.ensure(user_qq, group)).impression
rand = random.random()
async with db.transaction():
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
# 一天次数上限
- if user.today_open_total == int(MAX_COUNT + int(impression) / 3):
+ if user.today_open_total == int(
+ Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
+ + int(impression)
+ / Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
+ ):
return _handle_is_MAX_COUNT()
skin, mosun = get_color_quality(rand, case_name)
# 调侃
@@ -43,51 +44,49 @@ async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动"
uplist[0] = 1
else:
uplist[1] = 1
- ridicule_result = random.choice(['这样看着才舒服',
- '是自己人,大伙把刀收好',
- '非常舒适~'])
+ ridicule_result = random.choice(["这样看着才舒服", "是自己人,大伙把刀收好", "非常舒适~"])
if skin[:2] == "受限":
if skin.find("StatTrak") == -1:
uplist[2] = 1
else:
uplist[3] = 1
- ridicule_result = random.choice(['还行吧,勉强接受一下下',
- '居然不是蓝色,太假了',
- '运气-1-1-1-1-1...'])
+ ridicule_result = random.choice(
+ ["还行吧,勉强接受一下下", "居然不是蓝色,太假了", "运气-1-1-1-1-1..."]
+ )
if skin[:2] == "保密":
if skin.find("StatTrak") == -1:
uplist[4] = 1
else:
uplist[5] = 1
- ridicule_result = random.choice(['开始不适....',
- '你妈妈买菜必涨价!涨三倍!',
- '你最近不适合出门,真的'])
+ ridicule_result = random.choice(
+ ["开始不适....", "你妈妈买菜必涨价!涨三倍!", "你最近不适合出门,真的"]
+ )
if skin[:2] == "隐秘":
if skin.find("StatTrak") == -1:
uplist[6] = 1
else:
uplist[7] = 1
- ridicule_result = random.choice(['已经非常不适',
- '好兄弟你开的什么箱子啊,一般箱子不是只有蓝色的吗',
- '开始拿阳寿开箱子了?'])
+ ridicule_result = random.choice(
+ ["已经非常不适", "好兄弟你开的什么箱子啊,一般箱子不是只有蓝色的吗", "开始拿阳寿开箱子了?"]
+ )
if skin[:2] == "罕见":
knifes_flag = True
if skin.find("StatTrak") == -1:
uplist[8] = 1
else:
uplist[9] = 1
- ridicule_result = random.choice(['你的好运我收到了,你可以去喂鲨鱼了',
- '最近该吃啥就迟点啥吧,哎,好好的一个人怎么就....哎',
- '众所周知,欧皇寿命极短.'])
+ ridicule_result = random.choice(
+ ["你的好运我收到了,你可以去喂鲨鱼了", "最近该吃啥就迟点啥吧,哎,好好的一个人怎么就....哎", "众所周知,欧皇寿命极短."]
+ )
if skin.find("(") != -1:
cskin = skin.split("(")
skin = cskin[0].strip() + "(" + cskin[1].strip()
skin = skin.split("|")[0].strip() + " | " + skin.split("|")[1].strip()
# 价格
- if skin.find('无涂装') == -1:
+ if skin.find("无涂装") == -1:
dbprice = await BuffPrice.ensure(skin[9:])
else:
- dbprice = await BuffPrice.ensure(skin[9: skin.rfind('(')].strip())
+ dbprice = await BuffPrice.ensure(skin[9 : skin.rfind("(")].strip())
if dbprice.skin_price != 0:
price_result = dbprice.skin_price
print("数据库查询到价格: ", dbprice.skin_price)
@@ -114,38 +113,55 @@ async def open_case(user_qq: int, group: int, case_name: str = "狂牙大行动"
# cskin_word = sp[1][:sp[1].find("(") - 1].strip()
if knifes_flag:
await user.update(
- knifes_name=user.knifes_name + f"{case}||{skin.split(':')[1].strip()} 磨损:{str(mosun)[:11]}, 价格:{uplist[10]},"
+ knifes_name=user.knifes_name
+ + f"{case}||{skin.split(':')[1].strip()} 磨损:{str(mosun)[:11]}, 价格:{uplist[10]},"
).apply()
- cskin_word = skin.split(':')[1].replace('|', '-').replace('(StatTrak™)', '')
- cskin_word = cskin_word[: cskin_word.rfind('(')].strip()
- skin_name = cn2py(cskin_word.replace('|', '-').replace('(StatTrak™)', '').strip())
- img = image(f'{skin_name}.png', "cases/" + case)
+ cskin_word = skin.split(":")[1].replace("|", "-").replace("(StatTrak™)", "")
+ cskin_word = cskin_word[: cskin_word.rfind("(")].strip()
+ skin_name = cn2py(
+ cskin_word.replace("|", "-").replace("(StatTrak™)", "").strip()
+ )
+ img = image(f"{skin_name}.png", "cases/" + case)
# if knifes_flag:
# await user.update(
# knifes_name=user.knifes_name + f"{skin} 磨损:{mosun}, 价格:{uplist[10]}"
# ).apply()
if await update_user_total(user, uplist):
- logger.info(f"qq:{user_qq} 群:{group} 开启{case_name}武器箱 获得 {skin} 磨损:{mosun}, 价格:{uplist[10]}, 数据更新成功")
+ logger.info(
+ f"qq:{user_qq} 群:{group} 开启{case_name}武器箱 获得 {skin} 磨损:{mosun}, 价格:{uplist[10]}, 数据更新成功"
+ )
else:
- logger.warning(f"qq:{user_qq} 群:{group} 开启{case_name}武器箱 获得 {skin} 磨损:{mosun}, 价格:{uplist[10]}, 数据更新失败")
+ logger.warning(
+ f"qq:{user_qq} 群:{group} 开启{case_name}武器箱 获得 {skin} 磨损:{mosun}, 价格:{uplist[10]}, 数据更新失败"
+ )
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
- over_count = int(MAX_COUNT + int(impression) / 3) - user.today_open_total
- return f"开启{case_name}武器箱.\n剩余开箱次数:{over_count}.\n" \
- + img + "\n" + \
- f"皮肤:{skin}\n" \
- f"磨损:{mosun:.9f}\n" \
- f"价格:{price_result}\n" \
- f"{ridicule_result}"
+ over_count = int(
+ Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
+ + int(impression)
+ / Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
+ ) - user.today_open_total
+ return (
+ f"开启{case_name}武器箱.\n剩余开箱次数:{over_count}.\n" + img + "\n" + f"皮肤:{skin}\n"
+ f"磨损:{mosun:.9f}\n"
+ f"价格:{price_result}\n"
+ f"{ridicule_result}"
+ )
async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int = 10):
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
impression = (await SignGroupUser.ensure(user_qq, group)).impression
- if user.today_open_total == int(MAX_COUNT + int(impression) / 3):
+ max_count = int(
+ Config.get_config("open_cases", "INITIAL_OPEN_CASE_COUNT")
+ + int(impression) / Config.get_config("open_cases", "EACH_IMPRESSION_ADD_COUNT")
+ )
+ if user.today_open_total == max_count:
return _handle_is_MAX_COUNT()
- if int(MAX_COUNT + int(impression) / 3) - user.today_open_total < num:
- return f"今天开箱次数不足{num}次噢,请单抽试试看(也许单抽运气更好?)" \
- f"\n剩余开箱次数:{int(MAX_COUNT + int(impression) / 3) - user.today_open_total}"
+ if max_count - user.today_open_total < num:
+ return (
+ f"今天开箱次数不足{num}次噢,请单抽试试看(也许单抽运气更好?)"
+ f"\n剩余开箱次数:{max_count - user.today_open_total}"
+ )
await user.update(
total_count=user.total_count + num,
spend_money=user.spend_money + 17 * num,
@@ -163,7 +179,7 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
# lan zi fen hong jin price
uplist = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0]
img_list = []
- name_list = ['蓝', '蓝(暗金)', '紫', '紫(暗金)', '粉', '粉(暗金)', '红', '红(暗金)', '金', '金(暗金)']
+ name_list = ["蓝", "蓝(暗金)", "紫", "紫(暗金)", "粉", "粉(暗金)", "红", "红(暗金)", "金", "金(暗金)"]
async with db.transaction():
for _ in range(num):
knifes_flag = False
@@ -200,49 +216,71 @@ async def open_shilian_case(user_qq: int, group: int, case_name: str, num: int =
skin = cskin[0].strip() + "(" + cskin[1].strip()
skin = skin.split("|")[0].strip() + " | " + skin.split("|")[1].strip()
# 价格
- if skin.find('无涂装') == -1:
+ if skin.find("无涂装") == -1:
dbprice = await BuffPrice.ensure(skin[9:])
else:
- dbprice = await BuffPrice.ensure(skin[9: skin.rfind('(')].strip())
+ dbprice = await BuffPrice.ensure(skin[9 : skin.rfind("(")].strip())
if dbprice.skin_price != 0:
price_result = dbprice.skin_price
uplist[10] += price_result
else:
- price_result = '未查询到'
+ price_result = "未查询到"
if knifes_flag:
await user.update(
- knifes_name=user.knifes_name + f"{case}||{skin.split(':')[1].strip()} 磨损:{str(mosun)[:11]}, 价格:{dbprice.skin_price},"
+ knifes_name=user.knifes_name
+ + f"{case}||{skin.split(':')[1].strip()} 磨损:{str(mosun)[:11]}, 价格:{dbprice.skin_price},"
).apply()
- cskin_word = skin.split(':')[1].replace('|', '-').replace('(StatTrak™)', '')
- cskin_word = cskin_word[: cskin_word.rfind('(')].strip()
+ cskin_word = skin.split(":")[1].replace("|", "-").replace("(StatTrak™)", "")
+ cskin_word = cskin_word[: cskin_word.rfind("(")].strip()
skin_name = ""
- for i in pypinyin.pinyin(cskin_word.replace('|', '-').replace('(StatTrak™)', '').strip(),
- style=pypinyin.NORMAL):
- skin_name += ''.join(i)
+ for i in pypinyin.pinyin(
+ cskin_word.replace("|", "-").replace("(StatTrak™)", "").strip(),
+ style=pypinyin.NORMAL,
+ ):
+ skin_name += "".join(i)
# img = image(skin_name, "cases/" + case, "png")
wImg = CreateImg(200, 270, 200, 200)
- wImg.paste(alpha2white_pil(Image.open(IMAGE_PATH + f'cases/{case}/{skin_name}.png').resize((200, 200), Image.ANTIALIAS)), (0, 0))
+ wImg.paste(
+ alpha2white_pil(
+ Image.open(IMAGE_PATH + f"cases/{case}/{skin_name}.png").resize(
+ (200, 200), Image.ANTIALIAS
+ )
+ ),
+ (0, 0),
+ )
wImg.text((5, 200), skin)
- wImg.text((5, 220), f'磨损:{str(mosun)[:9]}')
- wImg.text((5, 240), f'价格:{price_result}')
+ wImg.text((5, 220), f"磨损:{str(mosun)[:9]}")
+ wImg.text((5, 240), f"价格:{price_result}")
img_list.append(wImg)
- logger.info(f"USER {user_qq} GROUP {group} 开启{case_name}武器箱 获得 {skin} 磨损:{mosun}, 价格:{uplist[10]}")
+ logger.info(
+ f"USER {user_qq} GROUP {group} 开启{case_name}武器箱 获得 {skin} 磨损:{mosun}, 价格:{uplist[10]}"
+ )
if await update_user_total(user, uplist, 0):
- logger.info(f"USER {user_qq} GROUP {group} 开启{case_name}武器箱 {num} 次, 数据更新成功")
+ logger.info(
+ f"USER {user_qq} GROUP {group} 开启{case_name}武器箱 {num} 次, 数据更新成功"
+ )
else:
- logger.warning(f"USER {user_qq} GROUP {group} 开启{case_name}武器箱 {num} 次, 价格:{uplist[10]}, 数据更新失败")
+ logger.warning(
+ f"USER {user_qq} GROUP {group} 开启{case_name}武器箱 {num} 次, 价格:{uplist[10]}, 数据更新失败"
+ )
# markImg = CreateImg(1000, h, 200, 270)
# for img in img_list:
# markImg.paste(img)
- markImg = await asyncio.get_event_loop().run_in_executor(None, paste_markImg, h, img_list)
- over_count = int(MAX_COUNT + int(impression) / 3) - user.today_open_total
- result = ''
+ markImg = await asyncio.get_event_loop().run_in_executor(
+ None, paste_markImg, h, img_list
+ )
+ over_count = max_count - user.today_open_total
+ result = ""
for i in range(len(name_list)):
if uplist[i]:
- result += f'[{name_list[i]}:{uplist[i]}] '
- return f"开启{case_name}武器箱\n剩余开箱次数:{over_count}\n" \
- + image(b64=markImg.pic2bs4()) + \
- '\n' + result[:-1] + f'\n总获取金额:{uplist[-1]:.2f}\n总花费:{17 * num}'
+ result += f"[{name_list[i]}:{uplist[i]}] "
+ return (
+ f"开启{case_name}武器箱\n剩余开箱次数:{over_count}\n"
+ + image(b64=markImg.pic2bs4())
+ + "\n"
+ + result[:-1]
+ + f"\n总获取金额:{uplist[-1]:.2f}\n总花费:{17 * num}"
+ )
def paste_markImg(h: int, img_list: list):
@@ -273,7 +311,7 @@ async def update_user_total(user: OpenCasesUser, up_list: list, num: int = 1) ->
spend_money=user.spend_money + 17 * num,
make_money=user.make_money + up_list[10],
today_open_total=user.today_open_total + num,
- open_cases_time_last=datetime.now()
+ open_cases_time_last=datetime.now(),
).apply()
return True
except:
@@ -283,21 +321,23 @@ async def update_user_total(user: OpenCasesUser, up_list: list, num: int = 1) ->
async def total_open_statistics(user_qq: int, group: int) -> str:
async with db.transaction():
user = await OpenCasesUser.ensure(user_qq, group, for_update=True)
- return f"开箱总数:{user.total_count}\n" \
- f"今日开箱:{user.today_open_total}\n" \
- f"蓝色军规:{user.blue_count}\n" \
- f"蓝色暗金:{user.blue_st_count}\n" \
- f"紫色受限:{user.purple_count}\n" \
- f"紫色暗金:{user.purple_st_count}\n" \
- f"粉色保密:{user.pink_count}\n" \
- f"粉色暗金:{user.pink_st_count}\n" \
- f"红色隐秘:{user.red_count}\n" \
- f"红色暗金:{user.red_st_count}\n" \
- f"金色罕见:{user.knife_count}\n" \
- f"金色暗金:{user.knife_st_count}\n" \
- f"花费金额:{user.spend_money}\n" \
- f"获取金额:{user.make_money:.2f}\n" \
- f"最后开箱日期:{(user.open_cases_time_last + timedelta(hours=8)).date()}"
+ return (
+ f"开箱总数:{user.total_count}\n"
+ f"今日开箱:{user.today_open_total}\n"
+ f"蓝色军规:{user.blue_count}\n"
+ f"蓝色暗金:{user.blue_st_count}\n"
+ f"紫色受限:{user.purple_count}\n"
+ f"紫色暗金:{user.purple_st_count}\n"
+ f"粉色保密:{user.pink_count}\n"
+ f"粉色暗金:{user.pink_st_count}\n"
+ f"红色隐秘:{user.red_count}\n"
+ f"红色暗金:{user.red_st_count}\n"
+ f"金色罕见:{user.knife_count}\n"
+ f"金色暗金:{user.knife_st_count}\n"
+ f"花费金额:{user.spend_money}\n"
+ f"获取金额:{user.make_money:.2f}\n"
+ f"最后开箱日期:{(user.open_cases_time_last + timedelta(hours=8)).date()}"
+ )
async def group_statistics(group: int):
@@ -318,20 +358,22 @@ async def group_statistics(group: int):
uplist[10] += user.make_money
uplist[11] += user.total_count
uplist[12] += user.today_open_total
- return f"群开箱总数:{uplist[11]}\n" \
- f"群今日开箱:{uplist[12]}\n" \
- f"蓝色军规:{uplist[0]}\n" \
- f"蓝色暗金:{uplist[1]}\n" \
- f"紫色受限:{uplist[2]}\n" \
- f"紫色暗金:{uplist[3]}\n" \
- f"粉色保密:{uplist[4]}\n" \
- f"粉色暗金:{uplist[5]}\n" \
- f"红色隐秘:{uplist[6]}\n" \
- f"红色暗金:{uplist[7]}\n" \
- f"金色罕见:{uplist[8]}\n" \
- f"金色暗金:{uplist[9]}\n" \
- f"花费金额:{uplist[11] * 17}\n" \
- f"获取金额:{uplist[10]:.2f}"
+ return (
+ f"群开箱总数:{uplist[11]}\n"
+ f"群今日开箱:{uplist[12]}\n"
+ f"蓝色军规:{uplist[0]}\n"
+ f"蓝色暗金:{uplist[1]}\n"
+ f"紫色受限:{uplist[2]}\n"
+ f"紫色暗金:{uplist[3]}\n"
+ f"粉色保密:{uplist[4]}\n"
+ f"粉色暗金:{uplist[5]}\n"
+ f"红色隐秘:{uplist[6]}\n"
+ f"红色暗金:{uplist[7]}\n"
+ f"金色罕见:{uplist[8]}\n"
+ f"金色暗金:{uplist[9]}\n"
+ f"花费金额:{uplist[11] * 17}\n"
+ f"获取金额:{uplist[10]:.2f}"
+ )
async def my_knifes_name(user_id: int, group: int):
@@ -348,7 +390,9 @@ async def my_knifes_name(user_id: int, group: int):
else:
h = 600 * int(length / 5) + 600
w = 540 * 5
- A = await asyncio.get_event_loop().run_in_executor(None, _pst_my_knife, w, h, knifes_list)
+ A = await asyncio.get_event_loop().run_in_executor(
+ None, _pst_my_knife, w, h, knifes_list
+ )
return image(b64=A.pic2bs4())
else:
return "您木有开出金色级别的皮肤喔"
@@ -357,30 +401,36 @@ async def my_knifes_name(user_id: int, group: int):
def _pst_my_knife(w, h, knifes_list):
A = CreateImg(w, h, 540, 600)
for knife in knifes_list:
- case = knife.split('||')[0]
- knife = knife.split('||')[1]
- name = knife[:knife.find('(')].strip()
- itype = knife[knife.find('(')+1: knife.find(')')].strip()
- mosun = knife[knife.find('磨损:')+3: knife.rfind('价格:')].strip()
- if mosun[-1] == ',' or mosun[-1] == ',':
+ case = knife.split("||")[0]
+ knife = knife.split("||")[1]
+ name = knife[: knife.find("(")].strip()
+ itype = knife[knife.find("(") + 1 : knife.find(")")].strip()
+ mosun = knife[knife.find("磨损:") + 3 : knife.rfind("价格:")].strip()
+ if mosun[-1] == "," or mosun[-1] == ",":
mosun = mosun[:-1]
- price = knife[knife.find('价格:')+3:]
+ price = knife[knife.find("价格:") + 3 :]
skin_name = ""
- for i in pypinyin.pinyin(name.replace('|', '-').replace('(StatTrak™)', '').strip(),
- style=pypinyin.NORMAL):
- skin_name += ''.join(i)
+ for i in pypinyin.pinyin(
+ name.replace("|", "-").replace("(StatTrak™)", "").strip(),
+ style=pypinyin.NORMAL,
+ ):
+ skin_name += "".join(i)
knife_img = CreateImg(470, 600, 470, 470, font_size=20)
- knife_img.paste(alpha2white_pil(
- Image.open(IMAGE_PATH + f'cases/{case}/{skin_name}.png').resize((470, 470), Image.ANTIALIAS)), (0, 0))
- knife_img.text((5, 500), f'\t{name}({itype})')
- knife_img.text((5, 530), f'\t磨损:{mosun}')
- knife_img.text((5, 560), f'\t价格:{price}')
+ knife_img.paste(
+ alpha2white_pil(
+ Image.open(IMAGE_PATH + f"cases/{case}/{skin_name}.png").resize(
+ (470, 470), Image.ANTIALIAS
+ )
+ ),
+ (0, 0),
+ )
+ knife_img.text((5, 500), f"\t{name}({itype})")
+ knife_img.text((5, 530), f"\t磨损:{mosun}")
+ knife_img.text((5, 560), f"\t价格:{price}")
A.paste(knife_img)
return A
-
-
# G3SG1(StatTrak™) | 血腥迷彩 (战痕累累)
# G3SG1(StatTrak™) | 血腥迷彩 (战痕累累)
# G3SG1(StatTrak™) | 血腥迷彩 (战痕累累)
diff --git a/plugins/open_cases/utils.py b/plugins/open_cases/utils.py
index be7db1d6..5c534a62 100644
--- a/plugins/open_cases/utils.py
+++ b/plugins/open_cases/utils.py
@@ -1,19 +1,18 @@
-from models.buff_price import BuffPrice
+from .models.buff_prices import BuffPrice
from services.db_context import db
from datetime import datetime, timedelta
from utils.user_agent import get_user_agent
from configs.path_config import IMAGE_PATH
import aiohttp
import aiofiles
-from models.open_cases_user import OpenCasesUser
+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_cookie_text
from asyncio.exceptions import TimeoutError
import pypinyin
from nonebot.adapters.cqhttp.exception import ActionFailed
-from configs.config import BUFF_PROXY
+from configs.config import Config
from utils.manager import group_manager
url = "https://buff.163.com/api/market/goods"
@@ -21,20 +20,20 @@ url = "https://buff.163.com/api/market/goods"
async def util_get_buff_price(case_name: str = "狂牙大行动") -> str:
- cookie = {'session': get_cookie_text('buff')}
+ 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 += "".join(i)
if case_name == "狂牙大行动":
case_id = 1
elif case_name == "突围大行动":
case_id = 2
elif case_name == "命悬一线":
case_id = 3
- elif case_name == '裂空':
+ elif case_name == "裂空":
case_id = 4
- elif case_name == '光谱':
+ elif case_name == "光谱":
case_id = 5
else:
return "未查询到武器箱"
@@ -44,47 +43,63 @@ async def util_get_buff_price(case_name: str = "狂牙大行动") -> str:
CASE_PINK = eval(case + "_CASE_PINK")
CASE_PURPLE = eval(case + "_CASE_PURPLE")
CASE_BLUE = eval(case + "_CASE_BLUE")
- async with aiohttp.ClientSession(cookies=cookie, headers=get_user_agent()) as session:
+ async with aiohttp.ClientSession(
+ cookies=cookie, headers=get_user_agent()
+ ) as session:
for total_list in [CASE_KNIFE, CASE_RED, CASE_PINK, CASE_PURPLE, CASE_BLUE]:
- print("----------------------------------")
for skin in total_list:
- print(skin)
- if skin in ["蝴蝶刀 | 无涂装", '求生匕首 | 无涂装', '流浪者匕首 | 无涂装', '系绳匕首 | 无涂装', '骷髅匕首 | 无涂装']:
- skin = skin.split('|')[0].strip()
+ if skin in [
+ "蝴蝶刀 | 无涂装",
+ "求生匕首 | 无涂装",
+ "流浪者匕首 | 无涂装",
+ "系绳匕首 | 无涂装",
+ "骷髅匕首 | 无涂装",
+ ]:
+ skin = skin.split("|")[0].strip()
async with db.transaction():
name_list = []
price_list = []
- parameter = {
- "game": "csgo",
- "page_num": "1",
- "search": skin
- }
+ parameter = {"game": "csgo", "page_num": "1", "search": skin}
try:
- async with session.get(url, proxy=BUFF_PROXY, params=parameter, timeout=20) as response:
+ async with session.get(
+ url,
+ proxy=Config.get_config("open_cases", "BUFF_PROXY"),
+ params=parameter,
+ timeout=20,
+ ) as response:
if response.status == 200:
data = (await response.json())["data"]
total_page = data["total_page"]
data = data["items"]
flag = False
- if skin.find('|') == -1: # in ['蝴蝶刀', '求生匕首', '流浪者匕首', '系绳匕首', '骷髅匕首']:
+ if (
+ skin.find("|") == -1
+ ): # in ['蝴蝶刀', '求生匕首', '流浪者匕首', '系绳匕首', '骷髅匕首']:
for i in range(1, total_page + 1):
name_list = []
price_list = []
parameter = {
"game": "csgo",
"page_num": f"{i}",
- "search": skin
+ "search": skin,
}
- async with session.get(url, params=parameter, timeout=20) as res:
- data = (await response.json())["data"]["items"]
+ async with session.get(
+ url, params=parameter, timeout=20
+ ) as res:
+ data = (await response.json())["data"][
+ "items"
+ ]
for j in range(len(data)):
- if data[j]['name'] in [f'{skin}(★)']:
+ if data[j]["name"] in [f"{skin}(★)"]:
name = data[j]["name"]
- price = data[j]["sell_reference_price"]
- name_list.append(name.split('(')[0].strip() + ' | 无涂装')
+ price = data[j][
+ "sell_reference_price"
+ ]
+ name_list.append(
+ name.split("(")[0].strip()
+ + " | 无涂装"
+ )
price_list.append(price)
- print(name_list[-1])
- print(price_list[-1])
flag = True
break
if flag:
@@ -99,38 +114,56 @@ async def util_get_buff_price(case_name: str = "狂牙大行动") -> str:
price_list.append(price)
except Exception as e:
failed_list.append(skin)
- print(f"{skin}更新失败")
+ logger.warning(f"{skin}更新失败")
else:
failed_list.append(skin)
- print(f"{skin}更新失败")
+ logger.warning(f"{skin}更新失败")
except Exception:
failed_list.append(skin)
- print(f"{skin}更新失败")
+ logger.warning(f"{skin}更新失败")
continue
for i in range(len(name_list)):
name = name_list[i].strip()
price = float(price_list[i])
if name.find("(★)") != -1:
- name = name[: name.find("(")] + name[name.find(")") + 1:]
+ name = name[: name.find("(")] + name[name.find(")") + 1 :]
if name.find("消音") != -1 and name.find("(S") != -1:
name = name.split("(")[0][:-4] + "(" + name.split("(")[1]
- name = name.split("|")[0].strip() + " | " + name.split("|")[1].strip()
+ name = (
+ name.split("|")[0].strip()
+ + " | "
+ + name.split("|")[1].strip()
+ )
elif name.find("消音") != -1:
- name = name.split("|")[0][:-5].strip() + " | " + name.split("|")[1].strip()
+ name = (
+ name.split("|")[0][:-5].strip()
+ + " | "
+ + name.split("|")[1].strip()
+ )
if name.find(" 18 ") != -1 and name.find("(S") != -1:
name = name.split("(")[0][:-5] + "(" + name.split("(")[1]
- name = name.split("|")[0].strip() + " | " + name.split("|")[1].strip()
+ name = (
+ name.split("|")[0].strip()
+ + " | "
+ + name.split("|")[1].strip()
+ )
elif name.find(" 18 ") != -1:
- name = name.split("|")[0][:-6].strip() + " | " + name.split("|")[1].strip()
+ name = (
+ name.split("|")[0][:-6].strip()
+ + " | "
+ + name.split("|")[1].strip()
+ )
dbskin = await BuffPrice.ensure(name, True)
- if (dbskin.update_date + timedelta(8)).date() == datetime.now().date():
+ if (
+ dbskin.update_date + timedelta(8)
+ ).date() == datetime.now().date():
continue
await dbskin.update(
case_id=case_id,
skin_price=price,
update_date=datetime.now(),
).apply()
- print(f"{name_list[i]}---------->成功更新")
+ logger.info(f"{name_list[i]}---------->成功更新")
result = None
if failed_list:
result = ""
@@ -140,11 +173,11 @@ async def util_get_buff_price(case_name: str = "狂牙大行动") -> str:
async def util_get_buff_img(case_name: str = "狂牙大行动") -> str:
- cookie = {'session': get_cookie_text('buff')}
+ cookie = {"session": Config.get_config("open_cases", "COOKIE")}
error_list = []
case = ""
for i in pypinyin.pinyin(case_name, style=pypinyin.NORMAL):
- case += ''.join(i)
+ case += "".join(i)
path = "cases/" + case + "/"
if not os.path.exists(IMAGE_PATH + path):
os.mkdir(IMAGE_PATH + path)
@@ -154,63 +187,75 @@ async def util_get_buff_img(case_name: str = "狂牙大行动") -> str:
CASE_PINK = eval(case + "_CASE_PINK")
CASE_PURPLE = eval(case + "_CASE_PURPLE")
CASE_BLUE = eval(case + "_CASE_BLUE")
- async with aiohttp.ClientSession(cookies=cookie, headers=get_user_agent()) as session:
+ async with aiohttp.ClientSession(
+ cookies=cookie, headers=get_user_agent()
+ ) as session:
for total_list in [CASE_KNIFE, CASE_RED, CASE_PINK, CASE_PURPLE, CASE_BLUE]:
for skin in total_list:
- parameter = {
- "game": "csgo",
- "page_num": "1",
- "search": skin
- }
- if skin in ["蝴蝶刀 | 无涂装", '求生匕首 | 无涂装', '流浪者匕首 | 无涂装', '系绳匕首 | 无涂装', '骷髅匕首 | 无涂装']:
- skin = skin.split('|')[0].strip()
- print("开始更新----->", skin)
- print(skin)
- skin_name = ''
+ parameter = {"game": "csgo", "page_num": "1", "search": skin}
+ if skin in [
+ "蝴蝶刀 | 无涂装",
+ "求生匕首 | 无涂装",
+ "流浪者匕首 | 无涂装",
+ "系绳匕首 | 无涂装",
+ "骷髅匕首 | 无涂装",
+ ]:
+ skin = skin.split("|")[0].strip()
+ logger.info(f"开始更新----->{skin}")
+ skin_name = ""
# try:
- async with session.get(url, proxy=BUFF_PROXY, params=parameter, timeout=20) as response:
+ async with session.get(
+ url,
+ proxy=Config.get_config("open_cases", "BUFF_PROXY"),
+ params=parameter,
+ timeout=20,
+ ) as response:
if response.status == 200:
data = (await response.json())["data"]
total_page = data["total_page"]
flag = False
- if skin.find('|') == -1: # in ['蝴蝶刀', '求生匕首', '流浪者匕首', '系绳匕首', '骷髅匕首']:
+ if (
+ skin.find("|") == -1
+ ): # in ['蝴蝶刀', '求生匕首', '流浪者匕首', '系绳匕首', '骷髅匕首']:
for i in range(1, total_page + 1):
- async with session.get(url, params=parameter, timeout=20) as res:
+ async with session.get(
+ url, params=parameter, timeout=20
+ ) as res:
data = (await response.json())["data"]["items"]
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)
- async with aiofiles.open(IMAGE_PATH + path + skin_name + ".png", 'wb') as f:
- print("------->开始写入 ", skin)
- async with session.get(img_url, timeout=7) as res:
+ 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)
+ async with aiofiles.open(
+ IMAGE_PATH + path + skin_name + ".png",
+ "wb",
+ ) as f:
+ logger.info(f"------->开始写入{skin}")
+ async with session.get(
+ img_url, timeout=7
+ ) as res:
await f.write(await res.read())
flag = True
break
if flag:
break
else:
- 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)
- async with aiofiles.open(IMAGE_PATH + path + skin_name + ".png", 'wb') as f:
- print("------->开始写入 ", skin)
+ 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)
+ async with aiofiles.open(
+ IMAGE_PATH + path + skin_name + ".png", "wb"
+ ) as f:
+ logger.info(f"------->开始写入 {skin}")
async with session.get(img_url, timeout=7) as res:
await f.write(await res.read())
- # async with session.get(url, params=parameter, timeout=7) as response:
- # if response.status == 200:
- # img_url = (await response.json())["data"]['items'][0]['goods_info']['icon_url']
- # skin_name = ''
- # for i in pypinyin.pinyin(skin.split("|")[1].strip(), style=pypinyin.NORMAL):
- # skin_name += ''.join(i)
- # async with aiofiles.open(IMAGE_PATH + path + skin_name + ".png", 'wb') as f:
- # print("------->开始写入 ", skin)
- # async with session.get(img_url, timeout=7) as res:
- # await f.write(await res.read())
- # except Exception:
- # print("图片更新失败 ---->", skin)
- # error_list.append(skin)
result = None
if error_list:
result = ""
@@ -220,16 +265,14 @@ async def util_get_buff_img(case_name: str = "狂牙大行动") -> str:
async def get_price(dname):
- cookie = {'session': get_cookie_text('buff')}
+ cookie = {"session": Config.get_config("open_cases", "COOKIE")}
name_list = []
price_list = []
- parameter = {
- "game": "csgo",
- "page_num": "1",
- "search": dname
- }
+ parameter = {"game": "csgo", "page_num": "1", "search": dname}
try:
- async with aiohttp.ClientSession(cookies=cookie, headers=get_user_agent()) as session:
+ async with aiohttp.ClientSession(
+ cookies=cookie, headers=get_user_agent()
+ ) as session:
async with session.get(url, params=parameter, timeout=7) as response:
if response.status == 200:
try:
@@ -262,22 +305,21 @@ async def update_count_daily():
for user in users:
await user.update(
today_open_total=0,
- ).apply()
+ ).apply()
bot = get_bot()
gl = await bot.get_group_list()
- gl = [g['group_id'] for g in gl]
+ 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'):
+ 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} 群被禁言,无法发送 开箱重置提醒')
+ logger.warning(f"{g} 群被禁言,无法发送 开箱重置提醒")
logger.info("今日开箱次数重置成功")
except Exception as e:
- logger.error(f'开箱重置错误 e:{e}')
-
+ logger.error(f"开箱重置错误 e:{e}")
# 蝴蝶刀(★) | 噩梦之夜 (久经沙场)
-if __name__ == '__main__':
+if __name__ == "__main__":
print(util_get_buff_img("xxxx/"))
diff --git a/plugins/pid_search.py b/plugins/pid_search.py
index 85e694fb..80e6701f 100644
--- a/plugins/pid_search.py
+++ b/plugins/pid_search.py
@@ -104,7 +104,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
)
)
logger.info(
- f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
+ f"(USER {event.user_id}, "
+ f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查询图片 PID:{pid}"
)
if isinstance(event, GroupMessageEvent):
diff --git a/plugins/pix_gallery/__init__.py b/plugins/pix_gallery/__init__.py
index 7d7f556c..15e42178 100644
--- a/plugins/pix_gallery/__init__.py
+++ b/plugins/pix_gallery/__init__.py
@@ -1,85 +1,62 @@
-from configs.config import HIBIAPI
-from services.log import logger
-from models.omega_pixiv_illusts import OmegaPixivIllusts
-from pathlib import Path
-from nonebot import Driver
-from typing import List
-from datetime import datetime
+from configs.config import Config
import nonebot
-import asyncio
-import os
__zx_plugin_name__ = "更新扩展图库Omega [Hidden]"
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
+
+Config.add_plugin_config(
+ "hibiapi",
+ "HIBIAPI",
+ "https://api.obfs.dev",
+ help_="如果没有自建或其他hibiapi请不要修改",
+ default_value="https://api.obfs.dev",
+)
+Config.add_plugin_config(
+ "pixiv",
+ "PIXIV_NGINX_URL",
+ "i.pixiv.re",
+ help_="Pixiv反向代理"
+)
+Config.add_plugin_config(
+ "pix",
+ "PIX_IMAGE_SIZE",
+ "master",
+ name="PIX图库",
+ help_="PIX图库下载的画质 可能的值:original:原图,master:缩略图(加快发送速度)",
+ default_value="master"
+)
+Config.add_plugin_config(
+ "pix",
+ "SEARCH_HIBIAPI_BOOKMARKS",
+ 5000,
+ help_="最低收藏,PIX使用HIBIAPI搜索图片时达到最低收藏才会添加至图库",
+ default_value=5000
+)
+Config.add_plugin_config(
+ "pix",
+ "WITHDRAW_PIX_MESSAGE",
+ (0, 1),
+ help_="自动撤回,参1:延迟撤回色图时间(秒),0 为关闭 | 参2:监控聊天类型,0(私聊) 1(群聊) 2(群聊+私聊)",
+ default_value=(0, 1)
+)
+Config.add_plugin_config(
+ "pix",
+ "PIX_OMEGA_PIXIV_RATIO",
+ (10, 0),
+ help_="PIX图库 与 额外图库OmegaPixivIllusts 混合搜索的比例 参1:PIX图库 参2:OmegaPixivIllusts扩展图库(没有此图库请设置为0)",
+ default_value=(10, 0)
+)
+Config.add_plugin_config(
+ "pix",
+ "TIMEOUT",
+ 10,
+ help_="下载图片超时限制(秒)",
+ default_value=10
+)
+
nonebot.load_plugins("plugins/pix_gallery")
-driver: Driver = nonebot.get_driver()
-illust_url = f"{HIBIAPI}/api/pixiv/illust"
-
-@driver.on_startup
-async def _init_omega_pixiv_illusts():
- omega_pixiv_illusts = None
- for file in os.listdir("."):
- if "omega_pixiv_illusts" in file and ".sql" in file:
- omega_pixiv_illusts = Path() / file
- if omega_pixiv_illusts:
- with open(omega_pixiv_illusts, "r", encoding="utf8") as f:
- lines = f.readlines()
- tasks = []
- length = len([x for x in lines if "INSERT INTO" in x.upper()])
- all_pid = await OmegaPixivIllusts.get_all_pid()
- index = 0
- logger.info("检测到OmegaPixivIllusts数据库,准备开始更新....")
- for line in lines:
- if "INSERT INTO" in line.upper():
- index += 1
- tasks.append(
- asyncio.ensure_future(_tasks(line, all_pid, length, index))
- )
- await asyncio.gather(*tasks)
- omega_pixiv_illusts.unlink()
-
-
-async def _tasks(line: str, all_pid: List[int], length: int, index: int):
- data = line.split("VALUES", maxsplit=1)[-1].strip()
- if data.startswith("("):
- data = data[1:]
- if data.endswith(");"):
- data = data[:-2]
- x = data.split(maxsplit=3)
- pid = int(x[1][:-1].strip())
- if pid in all_pid:
- logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}")
- return
- uid = int(x[2][:-1].strip())
- x = x[3].split(", '")
- title = x[0].strip()[1:-1]
- tmp = x[1].split(", ")
- author = tmp[0].strip()[:-1]
- nsfw_tag = int(tmp[1])
- width = int(tmp[2])
- height = int(tmp[3])
- tags = x[2][:-1]
- url = x[3][:-1]
- if await OmegaPixivIllusts.add_image_data(
- pid,
- title,
- width,
- height,
- url,
- uid,
- author,
- nsfw_tag,
- tags,
- datetime.min,
- datetime.min,
- ):
- logger.info(
- f"成功添加OmegaPixivIllusts图库数据 pid:{pid} 本次预计存储 {length} 张,已更新第 {index} 张"
- )
- else:
- logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}")
diff --git a/plugins/pix_gallery/data_source.py b/plugins/pix_gallery/data_source.py
index 17941f45..a85e8bde 100644
--- a/plugins/pix_gallery/data_source.py
+++ b/plugins/pix_gallery/data_source.py
@@ -4,17 +4,17 @@ from aiohttp.client_exceptions import (
ClientConnectorError,
)
from asyncpg.exceptions import UniqueViolationError
-from models.omega_pixiv_illusts import OmegaPixivIllusts
+from .model.omega_pixiv_illusts import OmegaPixivIllusts
from asyncio.locks import Semaphore
from aiohttp import ClientPayloadError
from aiohttp.client import ClientSession
from asyncio.exceptions import TimeoutError
-from models.pixiv import Pixiv
+from .model.pixiv import Pixiv
from typing import List
from utils.utils import get_local_proxy, change_picture_links
from utils.image_utils import CreateImg
from services.log import logger
-from configs.config import HIBIAPI_BOOKMARKS, HIBIAPI, PIX_IMAGE_SIZE
+from configs.config import Config
from configs.path_config import TEMP_PATH
import platform
import aiohttp
@@ -31,36 +31,45 @@ if str(platform.system()).lower() == "windows":
policy = asyncio.WindowsSelectorEventLoopPolicy()
asyncio.set_event_loop_policy(policy)
-search_url = f"{HIBIAPI}/api/pixiv/search"
-member_illust_url = f"{HIBIAPI}/api/pixiv/member_illust"
-illust_url = f"{HIBIAPI}/api/pixiv/illust"
-
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 = None
-# 开始更新
-async def start_update_image_url(current_keyword: List[str], black_pid: List[str]):
+
+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)
+ if not HIBIAPI:
+ HIBIAPI = Config.get_config("hibiapi", "HIBIAPI")
+ HIBIAPI = HIBIAPI[:-1] if HIBIAPI[-1] == "/" else HIBIAPI
async with aiohttp.ClientSession(headers=headers) as session:
for keyword in current_keyword:
for page in range(1, 110):
if keyword.startswith("uid:"):
- url = member_illust_url
+ url = f"{HIBIAPI}/api/pixiv/member_illust"
params = {"id": keyword[4:], "page": page}
if page == 30:
break
elif keyword.startswith("pid:"):
- url = illust_url
+ url = f"{HIBIAPI}/api/pixiv/illust"
params = {"id": keyword[4:]}
else:
- url = search_url
+ url = f"{HIBIAPI}/api/pixiv/search"
params = {"word": keyword, "page": page}
tasks.append(
asyncio.ensure_future(
@@ -86,7 +95,18 @@ async def search_image(
session: ClientSession,
page: int = 1,
black: List[str] = None,
-):
+) -> "int, int":
+ """
+ 搜索图片
+ :param url: 搜索url
+ :param keyword: 关键词
+ :param params: params参数
+ :param semaphore: semaphore
+ :param session: session
+ :param page: 页面
+ :param black: pid黑名单
+ :return: pid数量和图片数量
+ """
tmp_pid = []
pic_count = 0
pid_count = 0
@@ -104,7 +124,7 @@ async def search_image(
or (not data.get("illusts") and not data.get("illust"))
):
return 0, 0
- if url != illust_url:
+ if url != f"{HIBIAPI}/api/pixiv/illust":
logger.info(f'{keyword}: 获取数据成功...数据总量:{len(data["illusts"])}')
data = data["illusts"]
else:
@@ -133,9 +153,13 @@ async def search_image(
img_urls.append(urls["image_urls"]["original"])
if (
(
- bookmarks >= HIBIAPI_BOOKMARKS
- or (url == member_illust_url and bookmarks >= 1500)
- or (url == illust_url)
+ 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)
@@ -177,13 +201,8 @@ async def search_image(
tmp_pid.append(data["pid"])
pic_count += 1
logger.info(f'存储图片PID:{data["pid"]} IMG_P:{img_p}')
- # await download_image(img_url, session)
except UniqueViolationError:
logger.warning(f'{data["pid"]} | {img_url} 已存在...')
- # 下载图片
- # if not os.path.exists(f'{image_path}/
- # {img_url[img_url.rfind("/") + 1:]}'):
- # await download_image(img_url, session)
except (ServerDisconnectedError, ClientConnectorError, ClientOSError):
logger.warning("搜索图片服务被关闭,再次调用....")
await search_image(url, keyword, params, semaphore, session, page, black)
@@ -192,22 +211,26 @@ async def search_image(
# 下载图片
async def download_image(img_url: str, session: ClientSession, _count: int = 1):
+ """
+ 下载图片
+ :param img_url: 图片url
+ :param session: session
+ :param _count: 次数
+ """
try:
async with session.get(img_url, proxy=get_local_proxy()) as response:
logger.info(f"下载图片 --> {img_url}")
async with aiofiles.open(f'tmp/{img_url.split("/")[-1]}', "wb") as f:
await f.write(await response.read())
- # async with semaphore:
- # await asyncio.get_event_loop().run_in_executor(None,
- # upload_image, img_url[img_url.rfind("/")+1:])
except ServerDisconnectedError:
logger.warning(f"下载图片服务被关闭,第 {_count} 次调用....")
await download_image(img_url, session, _count + 1)
except ClientOSError:
logger.warning(f"远程连接被关闭,第 {_count} 次调用....")
- await download_image(
- img_url.replace("i.pximg.net", "i.pixiv.cat"), session, _count + 1
- )
+ ws_url = Config.get_config("pixiv", "PIXIV_NGINX_URL")
+ if ws_url:
+ img_url = img_url.replace("i.pximg.net", ws_url)
+ await download_image(img_url, session, _count + 1)
except TimeoutError:
logger.warning(f"下载或写入超时,第 {_count} 次调用....")
await download_image(img_url, session, _count + 1)
@@ -216,34 +239,56 @@ async def download_image(img_url: str, session: ClientSession, _count: int = 1):
async def get_image(img_url: str, user_id: int) -> str:
+ """
+ 下载图片
+ :param img_url:
+ :param user_id:
+ :return: 图片名称
+ """
+ global HIBIAPI
+ if not HIBIAPI:
+ HIBIAPI = Config.get_config("hibiapi", "HIBIAPI")
+ HIBIAPI = HIBIAPI[:-1] if HIBIAPI[-1] == "/" else HIBIAPI
async with aiohttp.ClientSession(headers=headers) as session:
- if 'https://www.pixiv.net/artworks' in img_url:
- pid = img_url.rsplit('/', maxsplit=1)[-1]
+ if "https://www.pixiv.net/artworks" in img_url:
+ pid = img_url.rsplit("/", maxsplit=1)[-1]
params = {"id": pid}
for _ in range(3):
try:
async with session.get(
- illust_url,
+ f"{HIBIAPI}/api/pixiv/illust",
params=params,
proxy=get_local_proxy(),
) as response:
if response.status == 200:
data = await response.json()
- if data.get('illust'):
- if data['illust']['page_count'] == 1:
- img_url = data['illust']['meta_single_page']['original_image_url']
+ 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"]
+ img_url = data["illust"]["meta_pages"][0][
+ "image_urls"
+ ]["original"]
break
except (ClientConnectorError, TimeoutError):
pass
old_img_url = img_url
- img_url = change_picture_links(img_url, PIX_IMAGE_SIZE)
+ img_url = change_picture_links(
+ img_url, Config.get_config("pix", "PIX_IMAGE_SIZE")
+ )
+ ws_url = Config.get_config("pixiv", "PIXIV_NGINX_URL")
+ if ws_url:
+ if ws_url.startswith("http"):
+ ws_url = ws_url.split("//")[-1]
+ img_url = img_url.replace("i.pximg.net", ws_url).replace("i.pixiv.cat", ws_url)
for _ in range(3):
try:
async with session.get(
img_url,
proxy=get_local_proxy(),
+ timeout=Config.get_config("pix", "TIMEOUT"),
) as response:
if response.status == 404:
img_url = old_img_url
@@ -257,12 +302,15 @@ async def get_image(img_url: str, user_id: int) -> str:
pass
-# 检测UID或PID是否有效
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 = illust_url
+ url = f"{HIBIAPI}/api/pixiv/illust"
else:
return False
params = {"id": int(id_[4:])}
@@ -274,13 +322,24 @@ async def uid_pid_exists(id_: str) -> bool:
return True
-async def get_keyword_num(keyword: str) -> "int , int":
+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())
+ 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}"
@@ -290,6 +349,12 @@ async def remove_image(pid: int, img_p: str) -> bool:
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
@@ -373,10 +438,15 @@ def gen_keyword_pic(
return A.pic2bs4()
-def _check_black(img_urls: List[str], black: List[str]):
+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:
- # img_url = img_url[img_url.rfind('/')+1: img_url.rfind('.')]
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
new file mode 100644
index 00000000..e3ad2b4b
--- /dev/null
+++ b/plugins/pix_gallery/model/__init__.py
@@ -0,0 +1,3 @@
+from .pixiv_keyword_user import *
+from .omega_pixiv_illusts import *
+from .pixiv import *
diff --git a/models/omega_pixiv_illusts.py b/plugins/pix_gallery/model/omega_pixiv_illusts.py
similarity index 98%
rename from models/omega_pixiv_illusts.py
rename to plugins/pix_gallery/model/omega_pixiv_illusts.py
index 52a086f2..cd213853 100644
--- a/models/omega_pixiv_illusts.py
+++ b/plugins/pix_gallery/model/omega_pixiv_illusts.py
@@ -5,6 +5,8 @@ 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)
diff --git a/models/pixiv.py b/plugins/pix_gallery/model/pixiv.py
similarity index 98%
rename from models/pixiv.py
rename to plugins/pix_gallery/model/pixiv.py
index 6210f2a2..15275d3e 100644
--- a/models/pixiv.py
+++ b/plugins/pix_gallery/model/pixiv.py
@@ -4,6 +4,7 @@ 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)
@@ -35,7 +36,6 @@ class Pixiv(db.Model):
uid: int,
author: str,
tags: str,
- nws
):
"""
说明:
@@ -133,7 +133,7 @@ class Pixiv(db.Model):
elif uid:
query = query.where(cls.uid == uid)
elif pid:
- query = query.where(cls.uid == pid)
+ query = query.where(cls.pid == pid)
query = query.order_by(db.func.random()).limit(num)
return await query.gino.all()
diff --git a/models/pixiv_keyword_user.py b/plugins/pix_gallery/model/pixiv_keyword_user.py
similarity index 98%
rename from models/pixiv_keyword_user.py
rename to plugins/pix_gallery/model/pixiv_keyword_user.py
index 7c5b864c..f8774e6d 100644
--- a/models/pixiv_keyword_user.py
+++ b/plugins/pix_gallery/model/pixiv_keyword_user.py
@@ -4,6 +4,7 @@ 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)
diff --git a/plugins/pix_gallery/pix.py b/plugins/pix_gallery/pix.py
index 755ecdb8..10c352c1 100644
--- a/plugins/pix_gallery/pix.py
+++ b/plugins/pix_gallery/pix.py
@@ -1,19 +1,18 @@
from nonebot.adapters.cqhttp.message import Message
from utils.utils import get_message_text, is_number
-from configs.config import PIX_OMEGA_PIXIV_RATIO, WITHDRAW_PIX_TIME
-from models.omega_pixiv_illusts import OmegaPixivIllusts
+from configs.config import Config
+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 (
Bot,
MessageEvent,
GroupMessageEvent,
- PrivateMessageEvent,
)
-from utils.manager import withdraw_message_manager
from nonebot.typing import T_State
from .data_source import get_image
-from models.pixiv import Pixiv
+from .model.pixiv import Pixiv
from nonebot import on_command
import random
@@ -55,54 +54,66 @@ __plugin_block_limit__ = {"rst": "您有PIX图片正在处理,请稍等..."}
pix = on_command("pix", aliases={"PIX", "Pix"}, priority=5, block=True)
-PIX_RATIO = PIX_OMEGA_PIXIV_RATIO[0] / (
- PIX_OMEGA_PIXIV_RATIO[0] + PIX_OMEGA_PIXIV_RATIO[1]
-)
-OMEGA_RATIO = 1 - PIX_RATIO
+PIX_RATIO = None
+OMEGA_RATIO = None
@pix.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
+ global PIX_RATIO, OMEGA_RATIO
+ if PIX_RATIO is None:
+ pix_omega_pixiv_ratio = Config.get_config("pix", "PIX_OMEGA_PIXIV_RATIO")
+ PIX_RATIO = pix_omega_pixiv_ratio[0] / (
+ pix_omega_pixiv_ratio[0] + pix_omega_pixiv_ratio[1]
+ )
+ OMEGA_RATIO = 1 - PIX_RATIO
num = 1
keyword = get_message_text(event.json())
+ x = keyword.split(" ")
+ if "-s" in x:
+ x.remove("-s")
+ nsfw_tag = 1
+ elif "-r" in x:
+ x.remove("-r")
+ nsfw_tag = 2
+ else:
+ nsfw_tag = 0
+ if nsfw_tag != 0 and str(event.user_id) not in bot.config.superusers:
+ await pix.finish("你不能看这些噢,这些都是是留给管理员看的...")
+ if len(x) > 1:
+ if is_number(x[-1]):
+ num = int(x[-1])
+ if num > 10:
+ if str(event.user_id) not in bot.config.superusers or (
+ str(event.user_id) in bot.config.superusers and num > 30
+ ):
+ num = random.randint(1, 10)
+ await pix.send(f"太贪心了,就给你发 {num}张 好了")
+ x = x[:-1]
+ keyword = " ".join(x)
+ pix_num = int(num * PIX_RATIO) + 15 if PIX_RATIO != 0 else 0
+ omega_num = num - pix_num + 15
if is_number(keyword):
- all_image = await Pixiv.query_images(uid=int(keyword))
+ if num == 1:
+ pix_num = 15
+ omega_num = 15
+ all_image = await Pixiv.query_images(
+ uid=int(keyword), num=pix_num, r18=1 if nsfw_tag == 2 else 0
+ ) + await OmegaPixivIllusts.query_images(
+ uid=int(keyword), num=omega_num, nsfw_tag=nsfw_tag
+ )
elif keyword.lower().startswith("pid"):
- pid = keyword.replace("pid", "").replace(":", "")
+ pid = keyword.replace("pid", "").replace(":", "").replace(":", "")
if not is_number(pid):
await pix.finish("PID必须是数字...", at_sender=True)
- isr18 = 0 if isinstance(event, GroupMessageEvent) else 2
- nsfw_tag = 0 if isinstance(event, GroupMessageEvent) else None
- all_image = await Pixiv.query_images(pid=int(pid), r18=isr18)
+ all_image = await Pixiv.query_images(
+ pid=int(pid), r18=1 if nsfw_tag == 2 else 0
+ )
if not all_image:
all_image = await OmegaPixivIllusts.query_images(
pid=int(pid), nsfw_tag=nsfw_tag
)
else:
- x = keyword.split()
- if "-s" in x:
- x.remove("-s")
- nsfw_tag = 1
- elif "-r" in x:
- x.remove("-r")
- nsfw_tag = 2
- else:
- nsfw_tag = 0
- if nsfw_tag != 0 and str(event.user_id) not in bot.config.superusers:
- await pix.finish("你不能看这些噢,这些都是是留给管理员看的...")
- if len(x) > 1:
- if is_number(x[-1]):
- num = int(x[-1])
- if num > 10:
- if str(event.user_id) not in bot.config.superusers or (
- str(event.user_id) in bot.config.superusers and num > 30
- ):
- num = random.randint(1, 10)
- await pix.send(f"太贪心了,就给你发 {num}张 好了")
- x = x[:-1]
- keyword = " ".join(x)
- pix_num = int(num * PIX_RATIO) + 15 if PIX_RATIO != 0 else 0
- omega_num = num - pix_num + 15
tmp = await Pixiv.query_images(
x, r18=1 if nsfw_tag == 2 else 0, num=pix_num
) + await OmegaPixivIllusts.query_images(x, nsfw_tag=nsfw_tag, num=omega_num)
@@ -124,14 +135,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
if isinstance(img, OmegaPixivIllusts):
img_url = img.url
author = img.uname
- print(img.nsfw_tag)
elif isinstance(img, Pixiv):
img_url = img.img_url
author = img.author
pid = img.pid
title = img.title
uid = img.uid
- # tags = img.tags
_img = await get_image(img_url, event.user_id)
if _img:
msg_id = await pix.send(
@@ -152,14 +161,5 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查看PIX图库PID: {pid},下载图片出错"
)
- withdraw_message(event, msg_id["message_id"])
+ withdraw_message_manager.withdraw_message(event, msg_id, Config.get_config("pix", "WITHDRAW_PIX_MESSAGE"))
-
-def withdraw_message(event: MessageEvent, id_: int):
- if WITHDRAW_PIX_TIME[0]:
- if (
- (WITHDRAW_PIX_TIME[1] == 0 and isinstance(event, PrivateMessageEvent))
- or (WITHDRAW_PIX_TIME[1] == 1 and isinstance(event, GroupMessageEvent))
- or WITHDRAW_PIX_TIME[1] == 2
- ):
- withdraw_message_manager.append((id_, WITHDRAW_PIX_TIME[0]))
diff --git a/plugins/pix_gallery/pix_add_keyword.py b/plugins/pix_gallery/pix_add_keyword.py
index fd8c16fc..6160be15 100644
--- a/plugins/pix_gallery/pix_add_keyword.py
+++ b/plugins/pix_gallery/pix_add_keyword.py
@@ -4,8 +4,8 @@ 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 models.pixiv_keyword_user import PixivKeywordUser
-from models.pixiv import Pixiv
+from .model.pixiv_keyword_user import PixivKeywordUser
+from .model.pixiv import Pixiv
from nonebot.permission import SUPERUSER
__zx_plugin_name__ = "PIX关键词/UID/PID添加管理 [Superuser]"
diff --git a/plugins/pix_gallery/pix_pass_del_keyword.py b/plugins/pix_gallery/pix_pass_del_keyword.py
index eed460aa..9bbbba1d 100644
--- a/plugins/pix_gallery/pix_pass_del_keyword.py
+++ b/plugins/pix_gallery/pix_pass_del_keyword.py
@@ -7,8 +7,8 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from nonebot.permission import SUPERUSER
from nonebot.typing import T_State
from .data_source import remove_image
-from models.pixiv_keyword_user import PixivKeywordUser
-from models.pixiv import Pixiv
+from .model.pixiv_keyword_user import PixivKeywordUser
+from .model.pixiv import Pixiv
__zx_plugin_name__ = "PIX关键词/UID/PID删除管理 [Superuser]"
diff --git a/plugins/pix_gallery/pix_show_info.py b/plugins/pix_gallery/pix_show_info.py
index 9463fd2b..5ed7eb9f 100644
--- a/plugins/pix_gallery/pix_show_info.py
+++ b/plugins/pix_gallery/pix_show_info.py
@@ -4,7 +4,7 @@ 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 models.pixiv_keyword_user import PixivKeywordUser
+from .model.pixiv_keyword_user import PixivKeywordUser
import asyncio
diff --git a/plugins/pix_gallery/pix_update.py b/plugins/pix_gallery/pix_update.py
index 1dcc5006..162e03db 100644
--- a/plugins/pix_gallery/pix_update.py
+++ b/plugins/pix_gallery/pix_update.py
@@ -3,10 +3,15 @@ from utils.utils import get_message_text, is_number
from nonebot.permission import SUPERUSER
from nonebot.typing import T_State
from .data_source import start_update_image_url
-from models.pixiv_keyword_user import PixivKeywordUser
-from models.pixiv import Pixiv
+from .model import PixivKeywordUser, Pixiv, OmegaPixivIllusts
from nonebot.adapters.cqhttp import Bot, MessageEvent
+from services.log import logger
+from typing import List
+from datetime import datetime
+from pathlib import Path
+import asyncio
import time
+import os
__zx_plugin_name__ = "pix检查更新 [Superuser]"
@@ -28,6 +33,10 @@ start_update = on_command(
"更新pix关键词", aliases={"更新pix关键字"}, permission=SUPERUSER, priority=1, block=True
)
+check_omega = on_command(
+ "检测omega图库", permission=SUPERUSER, priority=1, block=True
+)
+
check_not_update_uid_pid = on_command(
"pix检测更新",
aliases={"pix检查更新"},
@@ -130,3 +139,70 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
f"累计更新PID {pid_count} 个\n"
f"累计更新图片 {pic_count} 张" + "\n耗时:{:.2f}秒".format((time.time() - start_time))
)
+
+
+@check_omega.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ async def _tasks(line: str, all_pid: List[int], length: int, index: int):
+ data = line.split("VALUES", maxsplit=1)[-1].strip()
+ if data.startswith("("):
+ data = data[1:]
+ if data.endswith(");"):
+ data = data[:-2]
+ x = data.split(maxsplit=3)
+ pid = int(x[1][:-1].strip())
+ if pid in all_pid:
+ logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}")
+ return
+ uid = int(x[2][:-1].strip())
+ x = x[3].split(", '")
+ title = x[0].strip()[1:-1]
+ tmp = x[1].split(", ")
+ author = tmp[0].strip()[:-1]
+ nsfw_tag = int(tmp[1])
+ width = int(tmp[2])
+ height = int(tmp[3])
+ tags = x[2][:-1]
+ url = x[3][:-1]
+ if await OmegaPixivIllusts.add_image_data(
+ pid,
+ title,
+ width,
+ height,
+ url,
+ uid,
+ author,
+ nsfw_tag,
+ tags,
+ datetime.min,
+ datetime.min,
+ ):
+ logger.info(
+ f"成功添加OmegaPixivIllusts图库数据 pid:{pid} 本次预计存储 {length} 张,已更新第 {index} 张"
+ )
+ else:
+ logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}")
+ omega_pixiv_illusts = None
+ for file in os.listdir("."):
+ if "omega_pixiv_illusts" in file and ".sql" in file:
+ omega_pixiv_illusts = Path() / file
+ if omega_pixiv_illusts:
+ with open(omega_pixiv_illusts, "r", encoding="utf8") as f:
+ lines = f.readlines()
+ tasks = []
+ length = len([x for x in lines if "INSERT INTO" in x.upper()])
+ all_pid = await OmegaPixivIllusts.get_all_pid()
+ index = 0
+ logger.info("检测到OmegaPixivIllusts数据库,准备开始更新....")
+ for line in lines:
+ if "INSERT INTO" in line.upper():
+ index += 1
+ tasks.append(
+ asyncio.ensure_future(_tasks(line, all_pid, length, index))
+ )
+ await asyncio.gather(*tasks)
+ omega_pixiv_illusts.unlink()
+
+
+
+
diff --git a/plugins/pixiv/__init__.py b/plugins/pixiv_rank_search/__init__.py
similarity index 87%
rename from plugins/pixiv/__init__.py
rename to plugins/pixiv_rank_search/__init__.py
index af901a2d..172cbc89 100644
--- a/plugins/pixiv/__init__.py
+++ b/plugins/pixiv_rank_search/__init__.py
@@ -1,204 +1,213 @@
-from nonebot.typing import T_State
-from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
-from nonebot.matcher import Matcher
-from nonebot import on_command
-from utils.utils import get_message_text, 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 asyncio.exceptions import TimeoutError
-from aiohttp.client_exceptions import ClientConnectorError
-from configs.config import NICKNAME
-from typing import Type
-from nonebot.rule import to_me
-import time
-
-__zx_plugin_name__ = "P站排行/搜图"
-
-__plugin_usage__ = """
-usage:
- P站排行:
- 可选参数:
- 类型:
- 1. 日排行
- 2. 周排行
- 3. 月排行
- 4. 原创排行
- 5. 新人排行
- 6. R18日排行
- 7. R18周排行
- 8. R18受男性欢迎排行
- 9. R18重口排行【慎重!】
- 【使用时选择参数序号即可,R18仅可私聊】
- p站排行 ?[参数] ?[数量] ?[日期]
- 示例:
- p站排行榜 [无参数默认为日榜]
- p站排行榜 1
- p站排行榜 1 5
- p站排行榜 1 5 2018-4-25
- 【注意空格!!】【在线搜索会较慢】
- ---------------------------------
- P站搜图:
- 搜图 [关键词] ?[数量] ?[页数=1] ?[r18](不屏蔽R-18)
- 示例:
- 搜图 樱岛麻衣
- 搜图 樱岛麻衣 5
- 搜图 樱岛麻衣 5 r18
- 【默认为 热度排序】
- 【注意空格!!】【在线搜索会较慢】【数量可能不符?可能该页数量不够,也可能被R-18屏蔽】
-""".strip()
-__plugin_des__ = "P站排行榜直接冲,P站搜图跟着冲"
-__plugin_cmd__ = ["p站排行 ?[参数] ?[数量] ?[日期]", "搜图 [关键词] ?[数量] ?[页数=1] ?[r18](不屏蔽R-18)"]
-__plugin_type__ = ("来点好康的",)
-__plugin_version__ = 0.1
-__plugin_author__ = "HibiKier"
-__plugin_settings__ = {
- "level": 9,
- "default_status": True,
- "limit_superuser": False,
- "cmd": ["pixiv", "p站排行", "搜图", "p站搜图", "P站搜图"],
-}
-__plugin_block_limit__ = {
- "rst": "P站排行榜或搜图正在搜索,请不要重复触发命令..."
-}
-
-
-rank_dict = {
- "1": "day",
- "2": "week",
- "3": "month",
- "4": "week_original",
- "5": "week_rookie",
- "6": "day_r18",
- "7": "week_r18",
- "8": "day_male_r18",
- "9": "week_r18g",
-}
-
-
-pixiv_rank = on_command(
- "p站排行",
- aliases={"P站排行榜", "p站排行榜", "P站排行榜", "P站排行"},
- priority=5,
- block=True,
- rule=to_me(),
-)
-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()
- msg = msg.split(" ")
- msg = [m for m in msg if m]
- code = 0
- info_list = []
- if not msg:
- msg = ["1"]
- if msg[0] in ["6", "7", "8", "9"]:
- if event.message_type == "group":
- await pixiv_rank.finish("羞羞脸!私聊里自己看!", at_sender=True)
- if (n := len(msg)) == 0 or msg[0] == "":
- info_list, code = await get_pixiv_urls(rank_dict.get("1"))
- elif n == 1:
- if msg[0] not in ["1", "2", "3", "4", "5", "6", "7", "8", "9"]:
- await pixiv_rank.finish("要好好输入要看什么类型的排行榜呀!", at_sender=True)
- info_list, code = await get_pixiv_urls(rank_dict.get(msg[0]))
- elif n == 2:
- info_list, code = await get_pixiv_urls(rank_dict.get(msg[0]), int(msg[1]))
- elif n == 3:
- if not check_date(msg[2]):
- await pixiv_rank.finish("日期格式错误了", at_sender=True)
- info_list, code = await get_pixiv_urls(
- rank_dict.get(msg[0]), int(msg[1]), date=msg[2]
- )
- else:
- await pixiv_rank.finish("格式错了噢,参数不够?看看帮助?", at_sender=True)
- if code != 200 and info_list:
- await pixiv_rank.finish(info_list[0])
- if not info_list:
- await pixiv_rank.finish("没有找到啊,等等再试试吧~V", at_sender=True)
- await send_image(info_list, pixiv_rank, bot, event)
- logger.info(
- f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
- f" 查看了P站排行榜 code:{msg[0]}"
- )
-
-
-@pixiv_keyword.handle()
-async def _(bot: Bot, event: MessageEvent, state: T_State):
- msg = get_message_text(event.json())
- if isinstance(event, GroupMessageEvent):
- if "r18" in msg.lower():
- await pixiv_keyword.finish("(脸红#) 你不会害羞的 八嘎!", at_sender=True)
- r18 = 0 if "r18" in msg else 1
- msg = msg.replace("r18", "").strip().split()
- msg = [m.strip() for m in msg if m]
- keyword = None
- info_list = None
- num = 10
- page = 1
- if (n := len(msg)) == 1:
- keyword = msg[0]
- if n > 1:
- if not is_number(msg[1]):
- await pixiv_keyword.finish("图片数量必须是数字!", at_sender=True)
- num = int(msg[1])
- if n > 2:
- if not is_number(msg[2]):
- await pixiv_keyword.finish("页数数量必须是数字!", at_sender=True)
- page = int(msg[2])
- if keyword:
- info_list, code = await search_pixiv_urls(keyword, num, page, r18)
- if code != 200:
- await pixiv_keyword.finish(info_list[0])
- if not info_list:
- await pixiv_keyword.finish("没有找到啊,等等再试试吧~V", at_sender=True)
- await send_image(info_list, pixiv_keyword, bot, event)
- logger.info(
- f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
- f" 查看了搜索 {keyword} R18:{r18}"
- )
-
-
-def check_date(date):
- try:
- time.strptime(date, "%Y-%m-%d")
- return True
- except:
- return False
-
-
-async def send_image(
- info_list: list, matcher: Type[Matcher], bot: Bot, event: MessageEvent
-):
- if isinstance(event, GroupMessageEvent):
- await pixiv_rank.send("开始下载整理数据...")
- idx = 0
- mes_list = []
- for title, author, urls in info_list:
- _message = (
- f"title: {title}\nauthor: {author}\n"
- + await download_pixiv_imgs(urls, event.user_id, idx)
- )
- data = {
- "type": "node",
- "data": {
- "name": f"这里是{NICKNAME}酱",
- "uin": f"{bot.self_id}",
- "content": _message,
- },
- }
- mes_list.append(data)
- idx += 1
- await bot.send_group_forward_msg(group_id=event.group_id, messages=mes_list)
- else:
- for title, author, urls in info_list:
- try:
- await matcher.send(
- f"title: {title}\n"
- f"author: {author}\n"
- + await download_pixiv_imgs(urls, event.user_id)
- )
- except (NetworkError, TimeoutError, ClientConnectorError):
- await matcher.send("这张图网络直接炸掉了!", at_sender=True)
+from nonebot.typing import T_State
+from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
+from nonebot.matcher import Matcher
+from nonebot import on_command
+from utils.utils import get_message_text, 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 asyncio.exceptions import TimeoutError
+from aiohttp.client_exceptions import ClientConnectorError
+from utils.message_builder import custom_forward_msg
+from configs.config import Config
+from typing import Type
+from nonebot.rule import to_me
+import time
+
+__zx_plugin_name__ = "P站排行/搜图"
+
+__plugin_usage__ = """
+usage:
+ P站排行:
+ 可选参数:
+ 类型:
+ 1. 日排行
+ 2. 周排行
+ 3. 月排行
+ 4. 原创排行
+ 5. 新人排行
+ 6. R18日排行
+ 7. R18周排行
+ 8. R18受男性欢迎排行
+ 9. R18重口排行【慎重!】
+ 【使用时选择参数序号即可,R18仅可私聊】
+ p站排行 ?[参数] ?[数量] ?[日期]
+ 示例:
+ p站排行榜 [无参数默认为日榜]
+ p站排行榜 1
+ p站排行榜 1 5
+ p站排行榜 1 5 2018-4-25
+ 【注意空格!!】【在线搜索会较慢】
+ ---------------------------------
+ P站搜图:
+ 搜图 [关键词] ?[数量] ?[页数=1] ?[r18](不屏蔽R-18)
+ 示例:
+ 搜图 樱岛麻衣
+ 搜图 樱岛麻衣 5
+ 搜图 樱岛麻衣 5 r18
+ 【默认为 热度排序】
+ 【注意空格!!】【在线搜索会较慢】【数量可能不符?可能该页数量不够,也可能被R-18屏蔽】
+""".strip()
+__plugin_des__ = "P站排行榜直接冲,P站搜图跟着冲"
+__plugin_cmd__ = ["p站排行 ?[参数] ?[数量] ?[日期]", "搜图 [关键词] ?[数量] ?[页数=1] ?[r18](不屏蔽R-18)"]
+__plugin_type__ = ("来点好康的",)
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+__plugin_settings__ = {
+ "level": 9,
+ "default_status": True,
+ "limit_superuser": False,
+ "cmd": ["p站排行", "搜图", "p站搜图", "P站搜图"],
+}
+__plugin_block_limit__ = {"rst": "P站排行榜或搜图正在搜索,请不要重复触发命令..."}
+__plugin_configs__ = {
+ "TIMEOUT": {
+ "value": 10,
+ "help": "图片下载超时限制",
+ "default_value": 10
+ }
+}
+Config.add_plugin_config(
+ "hibiapi",
+ "HIBIAPI",
+ "https://api.obfs.dev",
+ help_="如果没有自建或其他hibiapi请不要修改",
+ default_value="https://api.obfs.dev",
+)
+Config.add_plugin_config(
+ "pixiv",
+ "PIXIV_NGINX_URL",
+ "i.pixiv.re",
+ help_="Pixiv反向代理"
+)
+
+
+rank_dict = {
+ "1": "day",
+ "2": "week",
+ "3": "month",
+ "4": "week_original",
+ "5": "week_rookie",
+ "6": "day_r18",
+ "7": "week_r18",
+ "8": "day_male_r18",
+ "9": "week_r18g",
+}
+
+
+pixiv_rank = on_command(
+ "p站排行",
+ aliases={"P站排行榜", "p站排行榜", "P站排行榜", "P站排行"},
+ priority=5,
+ block=True,
+ rule=to_me(),
+)
+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()
+ msg = msg.split(" ")
+ msg = [m for m in msg if m]
+ code = 0
+ info_list = []
+ if not msg:
+ msg = ["1"]
+ if msg[0] in ["6", "7", "8", "9"]:
+ if event.message_type == "group":
+ await pixiv_rank.finish("羞羞脸!私聊里自己看!", at_sender=True)
+ if (n := len(msg)) == 0 or msg[0] == "":
+ info_list, code = await get_pixiv_urls(rank_dict.get("1"))
+ elif n == 1:
+ if msg[0] not in ["1", "2", "3", "4", "5", "6", "7", "8", "9"]:
+ await pixiv_rank.finish("要好好输入要看什么类型的排行榜呀!", at_sender=True)
+ info_list, code = await get_pixiv_urls(rank_dict.get(msg[0]))
+ elif n == 2:
+ info_list, code = await get_pixiv_urls(rank_dict.get(msg[0]), int(msg[1]))
+ elif n == 3:
+ if not check_date(msg[2]):
+ await pixiv_rank.finish("日期格式错误了", at_sender=True)
+ info_list, code = await get_pixiv_urls(
+ rank_dict.get(msg[0]), int(msg[1]), date=msg[2]
+ )
+ else:
+ await pixiv_rank.finish("格式错了噢,参数不够?看看帮助?", at_sender=True)
+ if code != 200 and info_list:
+ await pixiv_rank.finish(info_list[0])
+ if not info_list:
+ await pixiv_rank.finish("没有找到啊,等等再试试吧~V", at_sender=True)
+ await send_image(info_list, pixiv_rank, bot, event)
+ logger.info(
+ f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
+ f" 查看了P站排行榜 code:{msg[0]}"
+ )
+
+
+@pixiv_keyword.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ msg = get_message_text(event.json())
+ if isinstance(event, GroupMessageEvent):
+ if "r18" in msg.lower():
+ await pixiv_keyword.finish("(脸红#) 你不会害羞的 八嘎!", at_sender=True)
+ r18 = 0 if "r18" in msg else 1
+ msg = msg.replace("r18", "").strip().split()
+ msg = [m.strip() for m in msg if m]
+ keyword = None
+ info_list = None
+ num = 10
+ page = 1
+ if (n := len(msg)) == 1:
+ keyword = msg[0]
+ if n > 1:
+ if not is_number(msg[1]):
+ await pixiv_keyword.finish("图片数量必须是数字!", at_sender=True)
+ num = int(msg[1])
+ if n > 2:
+ if not is_number(msg[2]):
+ await pixiv_keyword.finish("页数数量必须是数字!", at_sender=True)
+ page = int(msg[2])
+ if keyword:
+ info_list, code = await search_pixiv_urls(keyword, num, page, r18)
+ if code != 200:
+ await pixiv_keyword.finish(info_list[0])
+ if not info_list:
+ await pixiv_keyword.finish("没有找到啊,等等再试试吧~V", at_sender=True)
+ await send_image(info_list, pixiv_keyword, bot, event)
+ logger.info(
+ f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
+ f" 查看了搜索 {keyword} R18:{r18}"
+ )
+
+
+def check_date(date):
+ try:
+ time.strptime(date, "%Y-%m-%d")
+ return True
+ except:
+ return False
+
+
+async def send_image(
+ info_list: list, matcher: Type[Matcher], bot: Bot, event: MessageEvent
+):
+ if isinstance(event, GroupMessageEvent):
+ await pixiv_rank.send("开始下载整理数据...")
+ idx = 0
+ mes_list = []
+ for title, author, urls in info_list:
+ _message = f"title: {title}\nauthor: {author}\n" + await download_pixiv_imgs(urls, event.user_id, idx)
+ mes_list.append(_message)
+ idx += 1
+ mes_list = custom_forward_msg(mes_list, bot.self_id)
+ await bot.send_group_forward_msg(group_id=event.group_id, messages=mes_list)
+ else:
+ for title, author, urls in info_list:
+ try:
+ await matcher.send(
+ f"title: {title}\n"
+ f"author: {author}\n"
+ + await download_pixiv_imgs(urls, event.user_id)
+ )
+ except (NetworkError, TimeoutError, ClientConnectorError):
+ await matcher.send("这张图网络直接炸掉了!", at_sender=True)
diff --git a/plugins/pixiv/data_source.py b/plugins/pixiv_rank_search/data_source.py
similarity index 68%
rename from plugins/pixiv/data_source.py
rename to plugins/pixiv_rank_search/data_source.py
index 3909e544..6547747e 100644
--- a/plugins/pixiv/data_source.py
+++ b/plugins/pixiv_rank_search/data_source.py
@@ -1,131 +1,174 @@
-from configs.path_config import IMAGE_PATH
-from utils.utils import get_local_proxy
-from utils.message_builder import image
-from asyncio.exceptions import TimeoutError
-from configs.config import HIBIAPI
-from aiohttp.client_exceptions import ClientConnectorError
-from typing import Optional
-from pathlib import Path
-import aiohttp
-import aiofiles
-import platform
-
-if platform.system() == "Windows":
- import asyncio
-
- asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
-
-
-rank_url = f"{HIBIAPI}/api/pixiv/rank"
-search_url = f"{HIBIAPI}/api/pixiv/search"
-
-
-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",
-}
-
-
-async def get_pixiv_urls(
- mode: str, num: int = 10, page: int = 1, date: Optional[str] = None
-) -> "list, int":
- params = {"mode": mode, "page": page}
- if date:
- params["date"] = date
- return await parser_data(rank_url, num, params, 'rank')
-
-
-async def search_pixiv_urls(
- keyword: str, num: int, page: int, r18: int
-) -> "list, list":
- params = {"word": keyword, 'page': page}
- return await parser_data(search_url, num, params, 'search', r18)
-
-
-async def parser_data(url: str, num: int, params: dict, type_: str, r18: int = 0) -> "list, int":
- info_list = []
- async with aiohttp.ClientSession() as session:
- for _ in range(3):
- try:
- async with session.get(
- url, params=params, proxy=get_local_proxy(), timeout=5
- ) as response:
- if response.status == 200:
- data = await response.json()
- if data.get("illusts"):
- data = data["illusts"]
- break
- except (TimeoutError, ClientConnectorError):
- pass
- else:
- return ["网络不太好?没有该页数?也许过一会就好了..."], 998
- num = num if num < 30 else 30
- data = data[:num]
- for x in data:
- if type_ == 'search' and r18 == 1:
- if 'R-18' in str(x['tags']):
- continue
- title = x["title"]
- author = x["user"]["name"]
- urls = []
- if x["page_count"] == 1:
- urls.append(x["image_urls"]["large"])
- else:
- for j in x["meta_pages"]:
- urls.append(j["image_urls"]["large"])
- info_list.append((title, author, urls))
- return info_list, 200
-
-
-async def download_pixiv_imgs(
- urls: list, user_id: int, forward_msg_index: int = None
-) -> str:
- result = ""
- index = 0
- for url in urls:
- url = url.replace('_webp', '')
- async with aiohttp.ClientSession(headers=headers) as session:
- for _ in range(3):
- try:
- async with session.get(
- url, proxy=get_local_proxy(), timeout=3
- ) as response:
- if response.status == 200:
- try:
- file = (
- f"{IMAGE_PATH}/temp/{user_id}_{forward_msg_index}_{index}_pixiv.jpg"
- if forward_msg_index is not None
- else f"{IMAGE_PATH}/temp/{user_id}_{index}_pixiv.jpg"
- )
- file = Path(file)
- if forward_msg_index is not None:
- async with aiofiles.open(
- file,
- "wb",
- ) as f:
- await f.write(await response.read())
- result += image(
- f"{user_id}_{forward_msg_index}_{index}_pixiv.jpg",
- "temp",
- )
- else:
- async with aiofiles.open(
- file,
- "wb",
- ) as f:
- await f.write(await response.read())
- result += image(
- f"{user_id}_{index}_pixiv.jpg", "temp"
- )
- index += 1
- break
- except OSError:
- file.unlink()
- except (TimeoutError, ClientConnectorError):
- # result += '\n这张图下载失败了..\n'
- pass
- else:
- result += "\n这张图下载失败了..\n"
- return result
-
+from configs.path_config import IMAGE_PATH
+from utils.utils import get_local_proxy
+from utils.message_builder import image
+from asyncio.exceptions import TimeoutError
+from configs.config import Config
+from aiohttp.client_exceptions import ClientConnectorError
+from typing import Optional
+from pathlib import Path
+import aiohttp
+import aiofiles
+import platform
+
+if platform.system() == "Windows":
+ import asyncio
+
+ asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
+
+
+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",
+}
+
+
+async def get_pixiv_urls(
+ mode: str, num: int = 10, page: int = 1, date: Optional[str] = None
+) -> "list, int":
+ """
+ 拿到pixiv rank图片url
+ :param mode: 模式
+ :param num: 数量
+ :param page: 页数
+ :param date: 日期
+ """
+ params = {"mode": mode, "page": page}
+ if date:
+ params["date"] = date
+ hibiapi = Config.get_config("hibiapi", "HIBIAPI")
+ hibiapi = hibiapi[:-1] if hibiapi[-1] == "/" else hibiapi
+ rank_url = f"{hibiapi}/api/pixiv/rank"
+ return await parser_data(rank_url, num, params, "rank")
+
+
+async def search_pixiv_urls(
+ keyword: str, num: int, page: int, r18: int
+) -> "list, list":
+ """
+ 搜图图片的url
+ :param keyword: 关键词
+ :param num: 数量
+ :param page: 页数
+ :param r18: 是否r18
+ """
+ params = {"word": keyword, "page": page}
+ hibiapi = Config.get_config("hibiapi", "HIBIAPI")
+ hibiapi = hibiapi[:-1] if hibiapi[-1] == "/" else hibiapi
+ search_url = f"{hibiapi}/api/pixiv/search"
+ return await parser_data(search_url, num, params, "search", r18)
+
+
+async def parser_data(
+ url: str, num: int, params: dict, type_: str, r18: int = 0
+) -> "list, int":
+ """
+ 解析数据
+ :param url: hibiapi搜索url
+ :param num: 数量
+ :param params: 参数
+ :param type_: 类型,rank或search
+ :param r18: 是否r18
+ """
+ info_list = []
+ async with aiohttp.ClientSession() as session:
+ for _ in range(3):
+ try:
+ async with session.get(
+ url,
+ params=params,
+ proxy=get_local_proxy(),
+ timeout=Config.get_config("pixiv_rank_search", "TIMEOUT"),
+ ) as response:
+ if response.status == 200:
+ data = await response.json()
+ if data.get("illusts"):
+ data = data["illusts"]
+ break
+ except (TimeoutError, ClientConnectorError):
+ pass
+ else:
+ return ["网络不太好?没有该页数?也许过一会就好了..."], 998
+ num = num if num < 30 else 30
+ data = data[:num]
+ for x in data:
+ if type_ == "search" and r18 == 1:
+ if "R-18" in str(x["tags"]):
+ continue
+ title = x["title"]
+ author = x["user"]["name"]
+ urls = []
+ if x["page_count"] == 1:
+ urls.append(x["image_urls"]["large"])
+ else:
+ for j in x["meta_pages"]:
+ urls.append(j["image_urls"]["large"])
+ info_list.append((title, author, urls))
+ return info_list, 200
+
+
+async def download_pixiv_imgs(
+ urls: list, user_id: int, forward_msg_index: int = None
+) -> str:
+ """
+ 下载图片
+ :param urls: 图片链接
+ :param user_id: 用户id
+ :param forward_msg_index: 转发消息中的图片排序
+ """
+ result = ""
+ index = 0
+ for url in urls:
+ ws_url = Config.get_config("pixiv", "PIXIV_NGINX_URL")
+ if ws_url.startswith("http"):
+ ws_url = ws_url.split("//")[-1]
+ url = (
+ url.replace("i.pximg.net", ws_url)
+ .replace("i.pixiv.cat", ws_url)
+ .replace("_webp", "")
+ )
+ async with aiohttp.ClientSession(headers=headers) as session:
+ for _ in range(3):
+ try:
+ async with session.get(
+ url,
+ proxy=get_local_proxy(),
+ timeout=Config.get_config("pixiv_rank_search", "TIMEOUT"),
+ ) as response:
+ if response.status == 200:
+ try:
+ file = (
+ f"{IMAGE_PATH}/temp/{user_id}_{forward_msg_index}_{index}_pixiv.jpg"
+ if forward_msg_index is not None
+ else f"{IMAGE_PATH}/temp/{user_id}_{index}_pixiv.jpg"
+ )
+ file = Path(file)
+ if forward_msg_index is not None:
+ async with aiofiles.open(
+ file,
+ "wb",
+ ) as f:
+ await f.write(await response.read())
+ result += image(
+ f"{user_id}_{forward_msg_index}_{index}_pixiv.jpg",
+ "temp",
+ )
+ else:
+ async with aiofiles.open(
+ file,
+ "wb",
+ ) as f:
+ await f.write(await response.read())
+ result += image(
+ f"{user_id}_{index}_pixiv.jpg", "temp"
+ )
+ index += 1
+ break
+ except OSError:
+ file.unlink()
+ except (TimeoutError, ClientConnectorError):
+ # result += '\n这张图下载失败了..\n'
+ pass
+ else:
+ result += "\n这张图下载失败了..\n"
+ return result
diff --git a/plugins/reimu/__init__.py b/plugins/reimu/__init__.py
deleted file mode 100644
index 73b24a49..00000000
--- a/plugins/reimu/__init__.py
+++ /dev/null
@@ -1,98 +0,0 @@
-from nonebot import on_command
-from nonebot.adapters.cqhttp.permission import PRIVATE
-from .data_source import from_reimu_get_info
-from services.log import logger
-from nonebot.adapters.cqhttp import Bot, PrivateMessageEvent
-from nonebot.typing import T_State
-from utils.utils import is_number, get_message_text, UserBlockLimiter, scheduler
-from models.count_user import UserCount
-from configs.config import COUNT_PER_DAY_REIMU, NICKNAME
-
-__zx_plugin_name__ = "上车"
-__plugin_usage__ = """
-usage:
- * 请各位使用后不要转发 *
- * 大部分解压密码是⑨ *
- / 并不推荐小色批使用此功能[主要是不够色,目的不够明确] /
- 指令:
- 上车 ?[page] [目的地]
- 示例:上车 萝莉
- 示例:上车 5 萝莉: 该目的地第5页停车场
- ps: 请尽量提供具体的目的地名称
-""".strip()
-__plugin_des__ = "都坐稳了,老司机焊死了车门![仅限私聊]"
-__plugin_cmd__ = ["上车 ?[page] [目的地]"]
-__plugin_version__ = 0.1
-__plugin_author__ = "HibiKier"
-__plugin_settings__ = {
- "level": 5,
- "default_status": True,
- "limit_superuser": False,
- "cmd": ["上车"],
-}
-
-
-_ulmt = UserBlockLimiter()
-
-reimu = on_command("上车", permission=PRIVATE, block=True, priority=1)
-
-
-@reimu.args_parser
-async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
- if get_message_text(event.json()) in ["取消", "算了"]:
- await reimu.finish("已取消操作..", at_sender=True)
- if not get_message_text(event.json()):
- await reimu.reject("没时间等了!快说你要去哪里?", at_sender=True)
- state["keyword"] = get_message_text(event.json())
- state["page"] = 1
-
-
-@reimu.handle()
-async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
- if str(event.get_message()) in ["帮助"]:
- await reimu.finish(__plugin_usage__)
- if await UserCount.check_count(event.user_id, "reimu", COUNT_PER_DAY_REIMU):
- await reimu.finish("今天已经没车了,请明天再来...", at_sender=True)
- if _ulmt.check(event.user_id):
- await reimu.finish("您还没下车呢,请稍等...", at_sender=True)
- _ulmt.set_true(event.user_id)
- msg = get_message_text(event.json())
- args = msg.split(" ")
- if msg in ["!", "!", "?", "?", ",", ",", ".", "。"]:
- await reimu.finish(__plugin_usage__)
- if msg:
- if len(args) > 1 and is_number(args[0]):
- state["keyword"] = args[1]
- state["page"] = args[0]
- else:
- state["keyword"] = msg
- state["page"] = 1
-
-
-@reimu.got("keyword", "你的目的地是哪?")
-async def _(bot: Bot, event: PrivateMessageEvent, state: T_State):
- try:
- keyword = state["keyword"]
- page = state["page"]
- await UserCount.add_count(event.user_id, "reimu")
- await reimu.send(
- f"已经帮你关好车门了,请等待发车(不加{NICKNAME}好友的话是欣赏不到旅途的风景的)", at_sender=True
- )
- reimu_report = await from_reimu_get_info(keyword, page)
- if reimu_report:
- await reimu.send(reimu_report)
- else:
- logger.error("Not found reimuInfo")
- await reimu.send("没找着")
- _ulmt.set_false(event.user_id)
- except:
- _ulmt.set_false(event.user_id)
-
-
-@scheduler.scheduled_job(
- "cron",
- hour=0,
- minute=1,
-)
-async def _():
- await UserCount.reset_count()
diff --git a/plugins/reimu/data_source.py b/plugins/reimu/data_source.py
deleted file mode 100644
index 926eb967..00000000
--- a/plugins/reimu/data_source.py
+++ /dev/null
@@ -1,112 +0,0 @@
-from lxml import etree
-import time
-import aiohttp
-from services.log import logger
-from configs.config import MAXINFO_REIMU
-from utils.user_agent import get_user_agent
-from utils.utils import get_local_proxy
-from asyncio.exceptions import TimeoutError
-
-
-async def from_reimu_get_info(key_word: str, page: int) -> str:
- if "miku" in key_word.lower():
- logger.warning("Taboo words are being triggered")
- return ''
- repass = ""
- url = f"https://blog.reimu.net/search/{key_word}/page/{page}"
- url_s = "https://blog.reimu.net/"
- # try:
- # if key_word == "最近的存档":
- # logger.debug("Now starting get the {}".format(url_s))
- # repass = await get_repass(url_s)
- # else:
- # logger.debug("Now starting get the {}".format(url))
- # repass = await get_repass(url)
- # except TimeoutError as e:
- # logger.error("Timeout! {}".format(e))
- #
- # return repass
-
-
-# async def get_repass(url: str) -> str:
-# repass = ""
-# info = "[Note]注意大部分资源解压密码为⑨\n"
-# fund = None
-# print(url)
-# async with aiohttp.ClientSession(headers=get_user_agent()) as session:
-# async with session.get(url, proxy=get_local_proxy(), timeout=15) as response:
-# html = etree.HTML(await response.text())
-#
-# fund_l = html.xpath('//h1[@class="page-title"]/text()')
-# if fund_l:
-# fund = fund_l[0]
-# if fund == "未找到":
-# return "老司机也找不到路了……"
-# else:
-# pass
-#
-# headers = html.xpath("//article/header/h2/a/text()")
-# urls = html.xpath("//article/header/h2/a/@href")
-# logger.debug("Now get {} post from search page".format(len(headers)))
-#
-# headers_d = []
-# urls_d = []
-# for i, header in enumerate(headers):
-# if check_need_list(header):
-# headers_d.append(headers[i])
-# urls_d.append(urls[i])
-# else:
-# logger.debug(
-# "This title {} does not meet the requirements".format(header)
-# )
-#
-# header_len = len(headers_d)
-# logger.debug("Get {} post after processing".format(header_len))
-# if header_len > MAXINFO_REIMU:
-# headers_d = headers_d[:MAXINFO_REIMU]
-# urls_d = urls_d[:MAXINFO_REIMU]
-#
-# for h_s, url_s in zip(headers_d, urls_d):
-# if h_s != "审核结果存档":
-# time.sleep(1.5)
-# putline = await get_son_html_info(h_s, url_s)
-# if putline:
-# if repass:
-# repass = "\n\n- - - - - - - - \n".join([repass, putline])
-# else:
-# repass = putline
-# else:
-# logger.info("审核归档页面已跳过")
-#
-# if repass:
-# repass = info + repass
-# return repass
-#
-#
-# async def get_son_html_info(h_s, url_s) -> str:
-# repass = ""
-# logger.debug("Now starting get the {}".format(url_s))
-# async with aiohttp.ClientSession(headers=get_user_agent()) as session:
-# async with session.get(url_s, proxy=get_local_proxy(), timeout=15) as response:
-# html = etree.HTML(await response.text())
-# pres = html.xpath('//div[@class="entry-content"]/pre/text()')
-# a_texts = html.xpath('//div[@class="entry-content"]/pre//a/text()')
-# a_hrefs = html.xpath('//div[@class="entry-content"]/pre//a/@href')
-#
-# if pres and a_texts and a_hrefs:
-# while "" in pres:
-# pres.remove("")
-#
-# repass = "【资源名称】 {}\n\n{}".format(h_s, pres[0].strip())
-# for i, (a_t_s, a_h_s) in enumerate(zip(a_texts, a_hrefs)):
-# a = "\n {} {} {} ".format(a_t_s, a_h_s, pres[i + 1].strip())
-# repass += a
-# else:
-# logger.warning("Not get putline from {}".format(url_s))
-#
-# return repass
-
-
-
-
-
diff --git a/plugins/russian/__init__.py b/plugins/russian/__init__.py
index 791a7372..afdccbff 100644
--- a/plugins/russian/__init__.py
+++ b/plugins/russian/__init__.py
@@ -5,13 +5,13 @@ from nonebot.adapters.cqhttp import GROUP, Bot, GroupMessageEvent, Message
from nonebot.typing import T_State
from utils.utils import get_message_text, is_number, get_message_at
from models.group_member_info import GroupInfoUser
-from utils.message_builder import at
-from models.russian_user import RussianUser
+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 MAX_RUSSIAN_BET_GOLD, NICKNAME
+from configs.config import NICKNAME, Config
__zx_plugin_name__ = "俄罗斯轮盘"
__plugin_usage__ = """
@@ -47,6 +47,13 @@ __plugin_settings__ = {
"limit_superuser": False,
"cmd": ["俄罗斯轮盘", "装弹"],
}
+__plugin_configs__ = {
+ "MAX_RUSSIAN_BET_GOLD": {
+ "value": 1000,
+ "help": "俄罗斯轮盘最大赌注金额",
+ "default_value": 1000,
+ }
+}
rs_player = {}
@@ -228,7 +235,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
and rs_player[event.group_id][2]
and time.time() - rs_player[event.group_id]["time"] > 30
):
- await shot.send("决斗已过时,强行结算...")
+ await russian.send("决斗已过时,强行结算...")
await end_game(bot, event)
if (
not rs_player[event.group_id][2]
@@ -250,11 +257,15 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
msg = msg[0].strip()
if is_number(msg) and not (int(msg) < 1 or int(msg) > 6):
state["bullet_num"] = int(msg)
- if is_number(money) and 0 < int(money) <= MAX_RUSSIAN_BET_GOLD:
+ if is_number(money) and 0 < int(money) <= Config.get_config(
+ "russian", "MAX_RUSSIAN_BET_GOLD"
+ ):
state["money"] = int(money)
else:
state["money"] = 200
- await russian.send(f"赌注金额超过限制({MAX_RUSSIAN_BET_GOLD}),已改为200(默认)")
+ await russian.send(
+ f"赌注金额超过限制({Config.get_config('russian', 'MAX_RUSSIAN_BET_GOLD')}),已改为200(默认)"
+ )
state["at"] = get_message_at(event.json())
@@ -267,8 +278,11 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
user_money = await BagUser.get_gold(event.user_id, event.group_id)
if bullet_num < 0 or bullet_num > 6:
await russian.reject("子弹数量必须大于0小于7!速速重新装弹!")
- if money > MAX_RUSSIAN_BET_GOLD:
- await russian.finish(f"太多了!单次金额不能超过{MAX_RUSSIAN_BET_GOLD}!", at_sender=True)
+ if money > Config.get_config("russian", "MAX_RUSSIAN_BET_GOLD"):
+ await russian.finish(
+ f"太多了!单次金额不能超过{Config.get_config('russian', 'MAX_RUSSIAN_BET_GOLD')}!",
+ at_sender=True,
+ )
if money > user_money:
await russian.finish("你没有足够的钱支撑起这场挑战", at_sender=True)
@@ -433,6 +447,7 @@ async def end_game(bot: Bot, event: GroupMessageEvent):
for x in rs_player[event.group_id]["bullet"]:
bullet_str += "__ " if x == 0 else "| "
logger.info(f"俄罗斯轮盘:胜者:{win_name} - 败者:{lose_name} - 金币:{money}")
+ rs_player[event.group_id] = {}
await bot.send(
event,
message=f"结算:\n"
@@ -449,7 +464,6 @@ async def end_game(bot: Bot, event: GroupMessageEvent):
f"哼哼,{NICKNAME}从中收取了 {float(rand)}%({fee}金币) 作为手续费!\n"
f"子弹排列:{bullet_str[:-1]}",
)
- rs_player[event.group_id] = {}
@record.handle()
@@ -471,18 +485,26 @@ 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())
+ if is_number(num) and 51 > int(num) > 10:
+ num = int(num)
+ else:
+ num = 10
+ rank_image = None
if state["_prefix"]["raw_command"] in ["胜场排行", "胜利排行"]:
- await russian_rank.finish(await rank(event.group_id, "win_rank"))
+ rank_image = await rank(event.group_id, "win_rank", num)
if state["_prefix"]["raw_command"] in ["败场排行", "失败排行"]:
- await russian_rank.finish(await rank(event.group_id, "lose_rank"))
+ rank_image = await rank(event.group_id, "lose_rank", num)
if state["_prefix"]["raw_command"] == "欧洲人排行":
- await russian_rank.finish(await rank(event.group_id, "make_money"))
+ rank_image = await rank(event.group_id, "make_money", num)
if state["_prefix"]["raw_command"] == "慈善家排行":
- await russian_rank.finish(await rank(event.group_id, "spend_money"))
+ rank_image = await rank(event.group_id, "spend_money", num)
if state["_prefix"]["raw_command"] == "最高连胜排行":
- await russian_rank.finish(await rank(event.group_id, "max_winning_streak"))
+ rank_image = await rank(event.group_id, "max_winning_streak", num)
if state["_prefix"]["raw_command"] == "最高连败排行":
- await russian_rank.finish(await rank(event.group_id, "max_losing_streak"))
+ 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/russian/data_source.py b/plugins/russian/data_source.py
index 9c793e6d..35d12623 100644
--- a/plugins/russian/data_source.py
+++ b/plugins/russian/data_source.py
@@ -1,32 +1,34 @@
-from models.russian_user import RussianUser
+from .model import RussianUser
+from typing import Optional
from utils.data_utils import init_rank
+from utils.image_utils import CreateMat
-async def rank(group_id: int, itype) -> str:
+async def rank(group_id: int, itype: str, num: int) -> Optional[CreateMat]:
all_users = await RussianUser.get_all_user(group_id)
all_user_id = [user.user_qq for user in all_users]
if itype == 'win_rank':
- rank_name = '\t胜场排行榜\n'
+ rank_name = '胜场排行榜'
all_user_data = [user.win_count for user in all_users]
elif itype == 'lose_rank':
- rank_name = '\t败场排行榜\n'
+ rank_name = '败场排行榜'
all_user_data = [user.fail_count for user in all_users]
elif itype == 'make_money':
- rank_name = '\t赢取金币排行榜\n'
+ rank_name = '赢取金币排行榜'
all_user_data = [user.make_money for user in all_users]
elif itype == 'spend_money':
- rank_name = '\t输掉金币排行榜\n'
+ rank_name = '输掉金币排行榜'
all_user_data = [user.lose_money for user in all_users]
elif itype == 'max_winning_streak':
- rank_name = '\t最高连胜排行榜\n'
+ rank_name = '最高连胜排行榜'
all_user_data = [user.max_winning_streak for user in all_users]
else:
- rank_name = '\t最高连败排行榜\n'
+ rank_name = '最高连败排行榜'
all_user_data = [user.max_losing_streak for user in all_users]
- rst = ''
+ rst = None
if all_users:
- rst = await init_rank(all_user_id, all_user_data, group_id)
- return rank_name + rst
+ rst = await init_rank(rank_name, all_user_id, all_user_data, group_id, num)
+ return rst
diff --git a/models/russian_user.py b/plugins/russian/model.py
similarity index 98%
rename from models/russian_user.py
rename to plugins/russian/model.py
index 26e5a207..e7fec04a 100644
--- a/models/russian_user.py
+++ b/plugins/russian/model.py
@@ -4,6 +4,7 @@ from typing import List
class RussianUser(db.Model):
__tablename__ = "russian_users"
+ __table_args__ = {'extend_existing': True}
id = db.Column(db.Integer(), primary_key=True)
user_qq = db.Column(db.BigInteger(), nullable=False)
diff --git a/plugins/search_anime/__init__.py b/plugins/search_anime/__init__.py
index 3bc06b46..74817b98 100644
--- a/plugins/search_anime/__init__.py
+++ b/plugins/search_anime/__init__.py
@@ -3,15 +3,15 @@ from .data_source import from_anime_get_info
from services.log import logger
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from nonebot.typing import T_State
-from configs.config import MAXINFO_GROUP_ANIME, MAXINFO_PRIVATE_ANIME
+from configs.config import Config
from utils.utils import get_message_text
+from utils.message_builder import custom_forward_msg
__zx_plugin_name__ = "搜番"
__plugin_usage__ = f"""
usage:
搜索动漫资源
- 普通的搜番群内使用此功能只返还 {MAXINFO_GROUP_ANIME} 个结果,私聊返还 {MAXINFO_PRIVATE_ANIME} 个结果(绝不能打扰老色批们看色图!)
指令:
搜番 [番剧名称或者关键词]
示例:搜番 刀剑神域
@@ -27,8 +27,9 @@ __plugin_settings__ = {
"limit_superuser": False,
"cmd": ["搜番"],
}
-__plugin_block_limit__ = {
- "rst": "搜索还未完成,不要重复触发!"
+__plugin_block_limit__ = {"rst": "搜索还未完成,不要重复触发!"}
+__plugin_configs__ = {
+ "SEARCH_ANIME_MAX_INFO": {"value": 20, "help": "搜索动漫返回的最大数量", "default_value": 20}
}
search_anime = on_command("搜番", aliases={"搜动漫"}, priority=5, block=True)
@@ -54,12 +55,14 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
await search_anime.send(f"开始搜番 {key_word}", at_sender=True)
anime_report = await from_anime_get_info(
key_word,
- MAXINFO_GROUP_ANIME
- if isinstance(event, GroupMessageEvent)
- else MAXINFO_PRIVATE_ANIME,
+ Config.get_config("search_anime", "SEARCH_ANIME_MAX_INFO"),
)
if anime_report:
- await search_anime.send(anime_report)
+ if isinstance(event, GroupMessageEvent):
+ mes_list = custom_forward_msg(anime_report, bot.self_id)
+ await bot.send_group_forward_msg(group_id=event.group_id, messages=mes_list)
+ else:
+ await search_anime.send("\n\n".join(anime_report))
logger.info(
f"USER {event.user_id} GROUP"
f" {event.group_id if isinstance(event, GroupMessageEvent) else 'private'} 搜索番剧 {key_word} 成功"
diff --git a/plugins/search_anime/data_source.py b/plugins/search_anime/data_source.py
index 182e4f44..577ccf3d 100644
--- a/plugins/search_anime/data_source.py
+++ b/plugins/search_anime/data_source.py
@@ -2,12 +2,13 @@ from lxml import etree
import feedparser
from urllib import parse
from services.log import logger
+from typing import List
import aiohttp
import time
from utils.utils import get_local_proxy
-async def from_anime_get_info(key_word: str, max_: int) -> str:
+async def from_anime_get_info(key_word: str, max_: int) -> List[str]:
s_time = time.time()
repass = ""
url = "https://share.dmhy.org/topics/rss/rss.xml?keyword=" + parse.quote(key_word)
@@ -15,15 +16,16 @@ async def from_anime_get_info(key_word: str, max_: int) -> str:
repass = await get_repass(url, max_)
except Exception as e:
logger.error("Timeout! {}".format(e))
-
- return f"搜索 {key_word} 结果(耗时 {int(time.time() - s_time)} 秒):\n" + repass
+ repass.insert(0, f"搜索 {key_word} 结果(耗时 {int(time.time() - s_time)} 秒):\n")
+ return repass
-async def get_repass(url: str, max_: int) -> str:
- putline = []
+async def get_repass(url: str, max_: int) -> List[str]:
+ put_line = []
async with aiohttp.ClientSession() as session:
async with session.get(url, proxy=get_local_proxy(), timeout=20) as response:
d = feedparser.parse(await response.text())
+ max_ = max_ if max_ < len([e.link for e in d.entries]) else len([e.link for e in d.entries])
url_list = [e.link for e in d.entries][:max_]
for u in url_list:
try:
@@ -44,15 +46,11 @@ async def get_repass(url: str, max_: int) -> str:
.replace("\t", "")
)
size = item[3].xpath("string(.)")[5:].strip()
- putline.append(
+ put_line.append(
"【{}】| {}\n【{}】| {}".format(class_a, title, size, magent)
)
except Exception as e:
logger.warning(f"搜番超时 e:{e}")
-
- repass = "\n\n".join(putline)
-
- return repass
+ return put_line
-# print(asyncio.get_event_loop().run_until_complete(from_anime_get_info('进击的巨人', 1234556)))
diff --git a/plugins/search_buff_skin_price/__init__.py b/plugins/search_buff_skin_price/__init__.py
index 318a824c..42d4c9a5 100644
--- a/plugins/search_buff_skin_price/__init__.py
+++ b/plugins/search_buff_skin_price/__init__.py
@@ -28,6 +28,19 @@ __plugin_settings__ = {
"limit_superuser": False,
"cmd": ["查询皮肤"],
}
+__plugin_block_limit__ = {
+ "rst": "您有皮肤正在搜索,请稍等..."
+}
+__plugin_configs__ = {
+ "BUFF_PROXY": {
+ "value": None,
+ "help": "BUFF代理,有些厂ip可能被屏蔽"
+ },
+ "COOKIE": {
+ "value": None,
+ "help": "BUFF的账号cookie"
+ }
+}
search_skin = on_command("查询皮肤", aliases={"皮肤查询"}, priority=5, block=True)
@@ -45,8 +58,6 @@ 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())
- if _ulmt.check(event.user_id):
- await search_skin.finish("您有皮肤正在搜索,请稍等...", at_sender=True)
if raw_arg:
args = raw_arg.split(" ")
if len(args) >= 2:
@@ -58,7 +69,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
@search_skin.got("skin", prompt="要查询该武器的什么皮肤呢?")
async def arg_handle(bot: Bot, event: MessageEvent, state: T_State):
result = ""
- _ulmt.set_true(event.user_id)
if state["name"] in ["ak", "ak47"]:
state["name"] = "ak-47"
name = state["name"] + " | " + state["skin"]
@@ -67,7 +77,6 @@ async def arg_handle(bot: Bot, event: MessageEvent, state: T_State):
except FileNotFoundError:
await search_skin.finish(f'请先对{NICKNAME}说"设置cookie"来设置cookie!')
if status_code in [996, 997, 998]:
- _ulmt.set_false(event.user_id)
await search_skin.finish(result)
if result:
logger.info(
@@ -75,7 +84,6 @@ async def arg_handle(bot: Bot, event: MessageEvent, state: T_State):
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询皮肤:"
+ name
)
- _ulmt.set_false(event.user_id)
await search_skin.finish(result)
else:
logger.info(
@@ -83,7 +91,6 @@ async def arg_handle(bot: Bot, event: MessageEvent, state: T_State):
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}"
f" 查询皮肤:{name} 没有查询到"
)
- _ulmt.set_false(event.user_id)
await search_skin.finish("没有查询到哦,请检查格式吧")
diff --git a/plugins/search_buff_skin_price/data_source.py b/plugins/search_buff_skin_price/data_source.py
index 6d5032c7..3785484a 100644
--- a/plugins/search_buff_skin_price/data_source.py
+++ b/plugins/search_buff_skin_price/data_source.py
@@ -1,18 +1,14 @@
from utils.user_agent import get_user_agent
import aiohttp
-from utils.utils import get_cookie_text
-from configs.path_config import TEXT_PATH
from asyncio.exceptions import TimeoutError
-from configs.config import BUFF_PROXY
-from pathlib import Path
-from services.log import logger
+from configs.config import Config
url = "https://buff.163.com/api/market/goods"
async def get_price(dname):
- cookie = {"session": get_cookie_text("buff")}
+ cookie = {"session": Config.get_config("search_buff_skin_price", "COOKIE")}
name_list = []
price_list = []
parameter = {"game": "csgo", "page_num": "1", "search": dname}
@@ -21,7 +17,7 @@ async def get_price(dname):
cookies=cookie, headers=get_user_agent()
) as session:
async with session.get(
- url, proxy=BUFF_PROXY, params=parameter, timeout=5
+ url, proxy=Config.get_config("search_buff_skin_price", "BUFF_PROXY"), params=parameter, timeout=5
) as response:
if response.status == 200:
try:
@@ -36,29 +32,21 @@ async def get_price(dname):
price = data[i]["sell_reference_price"]
name_list.append(name)
price_list.append(price)
- except Exception as e:
+ except Exception:
return "没有查询到...", 998
else:
return "访问失败!", response.status
- except TimeoutError as e:
+ except TimeoutError:
return "访问超时! 请重试或稍后再试!", 997
result = f"皮肤: {dname}({len(name_list)})\n"
- # result = "皮肤: " + dname + "\n"
for i in range(len(name_list)):
result += name_list[i] + ": " + price_list[i] + "\n"
return result[:-1], 999
-def update_buff_cookie(cookie: str):
- _cookie = Path(TEXT_PATH + "cookie/buff.txt")
- try:
- _cookie.parent.mkdir(parents=True, exist_ok=True)
- with open(_cookie, "w") as f:
- f.write(cookie)
- return "更新cookie成功"
- except Exception as e:
- logger.error(f"更新cookie失败 e:{e}")
- return "更新cookie失败"
+def update_buff_cookie(cookie: str) -> str:
+ Config.set_config("search_buff_skin_price", "COOKIE", cookie)
+ return "更新cookie成功"
if __name__ == "__main__":
diff --git a/plugins/send_dinggong_voice/__init__.py b/plugins/send_dinggong_voice/__init__.py
index f547ff5f..2b584168 100644
--- a/plugins/send_dinggong_voice/__init__.py
+++ b/plugins/send_dinggong_voice/__init__.py
@@ -3,7 +3,6 @@ from utils.message_builder import record
from configs.path_config import VOICE_PATH
import random
from services.log import logger
-from utils.utils import FreqLimiter
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from nonebot.rule import to_me
@@ -26,8 +25,10 @@ __plugin_settings__ = {
"limit_superuser": False,
"cmd": ["骂老子", "骂我"],
}
-
-_flmt = FreqLimiter(3)
+__plugin_cd_limit__ = {
+ "cd": 3,
+ "rst": "就...就算求我骂你也得慢慢来..."
+}
dg_voice = on_keyword({"骂"}, rule=to_me(), priority=5, block=True)
@@ -35,16 +36,13 @@ 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:
- return
- if not _flmt.check(event.user_id):
- await dg_voice.finish("就...就算求我骂你也得慢慢来...", at_sender=True)
- _flmt.start_cd(event.user_id)
- voice = random.choice(os.listdir(VOICE_PATH + "dinggong/"))
- result = record(voice, "dinggong")
- await dg_voice.send(result)
- await dg_voice.send(voice.split("_")[1])
- logger.info(
- f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送钉宫骂人:"
- + result
- )
+ if len(str((event.get_message()))) > 1:
+ voice = random.choice(os.listdir(VOICE_PATH + "dinggong/"))
+ result = record(voice, "dinggong")
+ await dg_voice.send(result)
+ await dg_voice.send(voice.split("_")[1])
+ logger.info(
+ f"(USER {event.user_id}, GROUP "
+ f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送钉宫骂人:"
+ + result
+ )
diff --git a/plugins/send_setu_/__init__.py b/plugins/send_setu_/__init__.py
new file mode 100644
index 00000000..9418a25b
--- /dev/null
+++ b/plugins/send_setu_/__init__.py
@@ -0,0 +1,4 @@
+import nonebot
+
+
+nonebot.load_plugins("plugins/send_setu_")
diff --git a/models/setu.py b/plugins/send_setu_/model.py
similarity index 99%
rename from models/setu.py
rename to plugins/send_setu_/model.py
index 4cd05883..affe617d 100644
--- a/models/setu.py
+++ b/plugins/send_setu_/model.py
@@ -4,6 +4,8 @@ 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)
diff --git a/plugins/send_setu/__init__.py b/plugins/send_setu_/send_setu/__init__.py
similarity index 82%
rename from plugins/send_setu/__init__.py
rename to plugins/send_setu_/send_setu/__init__.py
index 05bed0c4..2d4ce1fc 100644
--- a/plugins/send_setu/__init__.py
+++ b/plugins/send_setu_/send_setu/__init__.py
@@ -1,329 +1,368 @@
-import random
-from nonebot import on_command, on_regex
-from services.log import logger
-from models.sign_group_user import SignGroupUser
-from nonebot.message import run_postprocessor
-from nonebot.matcher import Matcher
-from typing import Optional, Type
-from gino.exceptions import UninitializedError
-from utils.utils import (
- is_number,
- get_message_text,
- get_message_imgs,
-)
-from nonebot.typing import T_State
-from nonebot.adapters.cqhttp import (
- Bot,
- MessageEvent,
- GroupMessageEvent,
- PrivateMessageEvent,
- Message,
- Event,
-)
-from .data_source import (
- get_setu_list,
- get_luoxiang,
- search_online_setu,
- get_setu_urls,
- find_img_index,
- gen_message,
- check_local_exists_or_download,
- add_data_to_database,
-)
-from nonebot.adapters.cqhttp.exception import ActionFailed
-from configs.config import ONLY_USE_LOCAL_SETU, WITHDRAW_SETU_TIME, NICKNAME
-from utils.manager import withdraw_message_manager
-import re
-
-try:
- import ujson as json
-except ModuleNotFoundError:
- import json
-
-__zx_plugin_name__ = "色图"
-__plugin_usage__ = f"""
-usage:
- 搜索 lolicon 图库,每日色图time...
- 指令:
- 色图: 随机本地色图
- 色图r: 随机在线十张r18涩图
- 色图 [id]: 本地指定id色图
- 色图 *[tags]: 在线搜索指定tag色图
- 色图r *[tags]: 同上
- [1-9]张涩图: 本地随机色图连发
- [1-9]张[tags]的涩图: 指定tag色图连发
- 示例:色图 萝莉|少女 白丝|黑丝
- 示例:色图 萝莉 猫娘
- 注:
- tag至多取前20项,| 为或,萝莉|少女=萝莉或者少女
-""".strip()
-__plugin_des__ = "不要小看涩图啊混蛋!"
-__plugin_cmd__ = ["色图 ?[id]", "色图 ?[tags]", "色图r ?[tags]", "[1-9]张?[tags]色图"]
-__plugin_type__ = ("来点好康的",)
-__plugin_version__ = 0.1
-__plugin_author__ = "HibiKier"
-__plugin_settings__ = {
- "level": 9,
- "default_status": True,
- "limit_superuser": False,
- "cmd": ["色图", "涩图", "瑟图"],
-}
-__plugin_block_limit__ = {}
-__plugin_cd_limit__ = {
- 'rst': '您冲的太快了,请稍后再冲.',
-}
-
-setu_data_list = []
-
-
-@run_postprocessor
-async def do_something(
- matcher: Matcher,
- exception: Optional[Exception],
- bot: Bot,
- event: Event,
- state: T_State,
-):
- global setu_data_list
- if isinstance(event, MessageEvent):
- if matcher.module == "send_setu":
- # 添加数据至数据库
- try:
- await add_data_to_database(setu_data_list)
- logger.info("色图数据自动存储数据库成功...")
- setu_data_list = []
- except UninitializedError:
- pass
-
-
-setu = on_command(
- "色图", aliases={"涩图", "不够色", "来一发", "再来点", "色图r"}, priority=5, block=True
-)
-
-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())
- if isinstance(event, GroupMessageEvent):
- impression = (
- await SignGroupUser.ensure(event.user_id, event.group_id)
- ).impression
- luox = get_luoxiang(impression)
- if luox:
- await setu.finish(luox)
- r18 = 0
- num = 1
- # 是否看r18
- if state["_prefix"]["raw_command"] == "色图r" and isinstance(
- event, PrivateMessageEvent
- ):
- r18 = 1
- num = 10
- elif state["_prefix"]["raw_command"] == "色图r" and isinstance(
- event, GroupMessageEvent
- ):
- await setu.finish(
- random.choice(["这种不好意思的东西怎么可能给这么多人看啦", "羞羞脸!给我滚出克私聊!", "变态变态变态变态大变态!"])
- )
- # 有 数字 的话先尝试本地色图id
- if msg and is_number(msg):
- setu_list, code = await get_setu_list(int(msg), r18=r18)
- if code != 200:
- await setu.finish(setu_list[0], at_sender=True)
- setu_img, code = await check_local_exists_or_download(setu_list[0])
- msg_id = await setu.send(gen_message(setu_list[0]) + setu_img, at_sender=True)
- logger.info(
- f"(USER {event.user_id}, GROUP "
- f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
- f" 发送色图 {setu_list[0].local_id}.png"
- )
- if msg_id:
- withdraw_message(event, msg_id["message_id"])
- return
- await send_setu_handle(setu, event, state["_prefix"]["raw_command"], msg, num, r18)
-
-
-num_key = {
- "一": 1,
- "二": 2,
- "两": 2,
- "双": 2,
- "三": 3,
- "四": 4,
- "五": 5,
- "六": 6,
- "七": 7,
- "八": 8,
- "九": 9,
-}
-
-
-@setu_reg.handle()
-async def _(bot: Bot, event: MessageEvent, state: T_State):
- if isinstance(event, GroupMessageEvent):
- impression = (
- await SignGroupUser.ensure(event.user_id, event.group_id)
- ).impression
- luox = get_luoxiang(impression)
- if luox:
- await setu.finish(luox, at_sender=True)
- msg = get_message_text(event.json())
- num = 1
- msg = re.search(r"(.*)[份发张个次点](.*)[瑟涩色]图", msg)
- # 解析 tags 以及 num
- if msg:
- num = msg.group(1)
- tags = msg.group(2)
- if tags:
- tags = tags[:-1] if tags[-1] == "的" else tags
- if num:
- num = num[-1]
- if num_key.get(num):
- num = num_key[num]
- elif is_number(num):
- try:
- num = int(num)
- except ValueError:
- num = 1
- else:
- num = 1
- else:
- return
- 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_imgs(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_imgs(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,
- command: str,
- msg: str,
- num: int,
- r18: int,
-):
- global setu_data_list
- # 非 id,在线搜索
- tags = msg.split()
- # 真寻的色图?怎么可能
- if f"{NICKNAME}" in tags:
- await matcher.finish("咳咳咳,虽然我很可爱,但是我木有自己的色图~~~有的话记得发我一份呀")
- # 本地先拿图,下载失败补上去
- setu_list, code = None, 200
- msg_id = None
- if not ONLY_USE_LOCAL_SETU and tags:
- # 先尝试获取在线图片
- urls, text_list, add_databases_list, code = await get_setu_urls(
- tags, num, r18, command
- )
- for x in add_databases_list:
- setu_data_list.append(x)
- # 未找到符合的色图,想来本地应该也没有
- if code == 401:
- await setu.finish(urls[0], at_sender=True)
- if code == 200:
- for i in range(len(urls)):
- try:
- setu_img, index = await search_online_setu(urls[i])
- # 下载成功的话
- if index != -1:
- logger.info(
- f"(USER {event.user_id}, GROUP "
- f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
- f" 发送色图 {index}.png"
- )
- msg_id = await matcher.send(
- Message(f"{text_list[i]}\n{setu_img}")
- )
- else:
- if setu_list is None:
- setu_list, _ = await get_setu_list(tags=tags, r18=r18)
- if setu_list:
- setu_image = random.choice(setu_list)
- setu_list.remove(setu_image)
- msg_id = await matcher.send(
- Message(
- gen_message(setu_image)
- + (
- await check_local_exists_or_download(setu_image)
- )[0]
- )
- )
- logger.info(
- f"(USER {event.user_id}, GROUP "
- f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
- f" 发送本地色图 {setu_image.local_id}.png"
- )
- else:
- msg_id = await matcher.send(text_list[i] + "\n" + setu_img)
- if msg_id:
- withdraw_message(event, msg_id["message_id"])
- except ActionFailed:
- await matcher.finish("坏了,这张图色过头了,我自己看看就行了!", at_sender=True)
- return
- # 本地无图 或 超过上下限
- if code != 200:
- await matcher.finish("网络连接失败...", at_sender=True)
- if setu_list is None:
- setu_list, code = await get_setu_list(tags=tags, r18=r18)
- if code != 200:
- await matcher.finish(setu_list[0], at_sender=True)
- # 开始发图
- for _ in range(num):
- if not setu_list:
- await setu.finish("坏了,已经没图了,被榨干了!")
- setu_image = random.choice(setu_list)
- setu_list.remove(setu_image)
- try:
- msg_id = await matcher.send(
- Message(
- gen_message(setu_image)
- + (await check_local_exists_or_download(setu_image))[0]
- )
- )
- withdraw_message(event, msg_id["message_id"])
- logger.info(
- f"(USER {event.user_id}, GROUP "
- f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
- f" 发送本地色图 {setu_image.local_id}.png"
- )
- except ActionFailed:
- await matcher.finish("坏了,这张图色过头了,我自己看看就行了!", at_sender=True)
-
-
-# 撤回图片
-def withdraw_message(event: MessageEvent, id_: int):
- if WITHDRAW_SETU_TIME[0]:
- if (
- (WITHDRAW_SETU_TIME[1] == 0 and isinstance(event, PrivateMessageEvent))
- or (WITHDRAW_SETU_TIME[1] == 1 and isinstance(event, GroupMessageEvent))
- or WITHDRAW_SETU_TIME[1] == 2
- ):
- withdraw_message_manager.append((id_, WITHDRAW_SETU_TIME[0]))
+import random
+from nonebot import on_command, on_regex
+from services.log import logger
+from models.sign_group_user import SignGroupUser
+from nonebot.message import run_postprocessor
+from nonebot.matcher import Matcher
+from typing import Optional, Type
+from gino.exceptions import UninitializedError
+from utils.utils import (
+ is_number,
+ get_message_text,
+ get_message_imgs,
+)
+from nonebot.typing import T_State
+from nonebot.adapters.cqhttp import (
+ Bot,
+ MessageEvent,
+ GroupMessageEvent,
+ PrivateMessageEvent,
+ Message,
+ Event,
+)
+from .data_source import (
+ get_setu_list,
+ get_luoxiang,
+ search_online_setu,
+ get_setu_urls,
+ find_img_index,
+ gen_message,
+ check_local_exists_or_download,
+ add_data_to_database,
+ get_setu_count,
+)
+from nonebot.adapters.cqhttp.exception import ActionFailed
+from configs.config import Config, NICKNAME
+from utils.manager import withdraw_message_manager
+import re
+
+try:
+ import ujson as json
+except ModuleNotFoundError:
+ import json
+
+__zx_plugin_name__ = "色图"
+__plugin_usage__ = f"""
+usage:
+ 搜索 lolicon 图库,每日色图time...
+ 指令:
+ 色图: 随机本地色图
+ 色图r: 随机在线十张r18涩图
+ 色图 [id]: 本地指定id色图
+ 色图 *[tags]: 在线搜索指定tag色图
+ 色图r *[tags]: 同上
+ [1-9]张涩图: 本地随机色图连发
+ [1-9]张[tags]的涩图: 指定tag色图连发
+ 示例:色图 萝莉|少女 白丝|黑丝
+ 示例:色图 萝莉 猫娘
+ 注:
+ tag至多取前20项,| 为或,萝莉|少女=萝莉或者少女
+""".strip()
+__plugin_des__ = "不要小看涩图啊混蛋!"
+__plugin_cmd__ = ["色图 ?[id]", "色图 ?[tags]", "色图r ?[tags]", "[1-9]张?[tags]色图"]
+__plugin_type__ = ("来点好康的",)
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+__plugin_settings__ = {
+ "level": 9,
+ "default_status": True,
+ "limit_superuser": False,
+ "cmd": ["色图", "涩图", "瑟图"],
+}
+__plugin_block_limit__ = {}
+__plugin_cd_limit__ = {
+ "rst": "您冲的太快了,请稍后再冲.",
+}
+__plugin_configs__ = {
+ "WITHDRAW_SETU_MESSAGE": {
+ "value": (0, 1),
+ "help": "自动撤回,参1:延迟撤回色图时间(秒),0 为关闭 | 参2:监控聊天类型,0(私聊) 1(群聊) 2(群聊+私聊)",
+ "default_value": (0, 1),
+ },
+ "ONLY_USE_LOCAL_SETU": {
+ "value": False,
+ "help": "仅仅使用本地色图,不在线搜索",
+ "default_value": False,
+ },
+ "INITIAL_SETU_PROBABILITY": {
+ "value": 0.7,
+ "help": "初始色图概率,总概率 = 初始色图概率 + 好感度",
+ "default_value": 0.7
+ },
+ "DOWNLOAD_SETU": {
+ "value": True,
+ "help": "是否存储下载的色图,使用本地色图可以加快图片发送速度",
+ "default_value": True
+ },
+ "TIMEOUT": {
+ "value": 10,
+ "help": "色图下载超时限制(秒)",
+ "default_value": 10
+ }
+}
+Config.add_plugin_config(
+ "pixiv",
+ "PIXIV_NGINX_URL",
+ "i.pixiv.re",
+ help_="Pixiv反向代理"
+)
+
+setu_data_list = []
+
+
+@run_postprocessor
+async def do_something(
+ matcher: Matcher,
+ exception: Optional[Exception],
+ bot: Bot,
+ event: Event,
+ state: T_State,
+):
+ global setu_data_list
+ if isinstance(event, MessageEvent):
+ if matcher.module == "send_setu":
+ # 添加数据至数据库
+ try:
+ await add_data_to_database(setu_data_list)
+ logger.info("色图数据自动存储数据库成功...")
+ setu_data_list = []
+ except UninitializedError:
+ pass
+
+
+setu = on_command(
+ "色图", aliases={"涩图", "不够色", "来一发", "再来点", "色图r"}, priority=5, block=True
+)
+
+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())
+ if isinstance(event, GroupMessageEvent):
+ impression = (
+ await SignGroupUser.ensure(event.user_id, event.group_id)
+ ).impression
+ luox = get_luoxiang(impression)
+ if luox:
+ await setu.finish(luox)
+ r18 = 0
+ num = 1
+ # 是否看r18
+ if state["_prefix"]["raw_command"] == "色图r" and isinstance(
+ event, PrivateMessageEvent
+ ):
+ r18 = 1
+ num = 10
+ elif state["_prefix"]["raw_command"] == "色图r" and isinstance(
+ event, GroupMessageEvent
+ ):
+ await setu.finish(
+ random.choice(["这种不好意思的东西怎么可能给这么多人看啦", "羞羞脸!给我滚出克私聊!", "变态变态变态变态大变态!"])
+ )
+ # 有 数字 的话先尝试本地色图id
+ if msg and is_number(msg):
+ setu_list, code = await get_setu_list(int(msg), r18=r18)
+ if code != 200:
+ await setu.finish(setu_list[0], at_sender=True)
+ setu_img, code = await check_local_exists_or_download(setu_list[0])
+ msg_id = await setu.send(gen_message(setu_list[0]) + setu_img, at_sender=True)
+ logger.info(
+ f"(USER {event.user_id}, GROUP "
+ f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
+ f" 发送色图 {setu_list[0].local_id}.png"
+ )
+ if msg_id:
+ withdraw_message_manager.withdraw_message(
+ event,
+ msg_id["message_id"],
+ Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE"),
+ )
+ return
+ await send_setu_handle(setu, event, state["_prefix"]["raw_command"], msg, num, r18)
+
+
+num_key = {
+ "一": 1,
+ "二": 2,
+ "两": 2,
+ "双": 2,
+ "三": 3,
+ "四": 4,
+ "五": 5,
+ "六": 6,
+ "七": 7,
+ "八": 8,
+ "九": 9,
+}
+
+
+@setu_reg.handle()
+async def _(bot: Bot, event: MessageEvent, state: T_State):
+ if isinstance(event, GroupMessageEvent):
+ impression = (
+ await SignGroupUser.ensure(event.user_id, event.group_id)
+ ).impression
+ luox = get_luoxiang(impression)
+ if luox:
+ await setu.finish(luox, at_sender=True)
+ msg = get_message_text(event.json())
+ num = 1
+ msg = re.search(r"(.*)[份发张个次点](.*)[瑟涩色]图", msg)
+ # 解析 tags 以及 num
+ if msg:
+ num = msg.group(1)
+ tags = msg.group(2)
+ if tags:
+ tags = tags[:-1] if tags[-1] == "的" else tags
+ if num:
+ num = num[-1]
+ if num_key.get(num):
+ num = num_key[num]
+ elif is_number(num):
+ try:
+ num = int(num)
+ except ValueError:
+ num = 1
+ else:
+ num = 1
+ else:
+ return
+ 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_imgs(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_imgs(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,
+ command: str,
+ msg: str,
+ num: int,
+ r18: int,
+):
+ global setu_data_list
+ # 非 id,在线搜索
+ tags = msg.split()
+ # 真寻的色图?怎么可能
+ if f"{NICKNAME}" in tags:
+ await matcher.finish("咳咳咳,虽然我很可爱,但是我木有自己的色图~~~有的话记得发我一份呀")
+ # 本地先拿图,下载失败补上去
+ setu_list, code = None, 200
+ setu_count = await get_setu_count(r18)
+ if (
+ not Config.get_config("send_setu", "ONLY_USE_LOCAL_SETU") and tags
+ ) or setu_count <= 0:
+ # 先尝试获取在线图片
+ urls, text_list, add_databases_list, code = await get_setu_urls(
+ tags, num, r18, command
+ )
+ for x in add_databases_list:
+ setu_data_list.append(x)
+ # 未找到符合的色图,想来本地应该也没有
+ if code == 401:
+ await setu.finish(urls[0], at_sender=True)
+ if code == 200:
+ for i in range(len(urls)):
+ try:
+ setu_img, index = await search_online_setu(urls[i])
+ # 下载成功的话
+ if index != -1:
+ logger.info(
+ f"(USER {event.user_id}, GROUP "
+ f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
+ f" 发送色图 {index}.png"
+ )
+ msg_id = await matcher.send(
+ Message(f"{text_list[i]}\n{setu_img}")
+ )
+ else:
+ if setu_list is None:
+ setu_list, code = await get_setu_list(tags=tags, r18=r18)
+ if code != 200:
+ await setu.finish(setu_list[0], at_sender=True)
+ if setu_list:
+ setu_image = random.choice(setu_list)
+ setu_list.remove(setu_image)
+ msg_id = await matcher.send(
+ Message(
+ gen_message(setu_image)
+ + (
+ await check_local_exists_or_download(setu_image)
+ )[0]
+ )
+ )
+ logger.info(
+ f"(USER {event.user_id}, GROUP "
+ f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
+ f" 发送本地色图 {setu_image.local_id}.png"
+ )
+ else:
+ msg_id = await matcher.send(text_list[i] + "\n" + setu_img)
+ if msg_id:
+ withdraw_message_manager.withdraw_message(
+ event,
+ msg_id["message_id"],
+ Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE"),
+ )
+ except ActionFailed:
+ await matcher.finish("坏了,这张图色过头了,我自己看看就行了!", at_sender=True)
+ return
+ if code != 200:
+ await matcher.finish("网络连接失败...", at_sender=True)
+ # 本地无图
+ if setu_list is None:
+ setu_list, code = await get_setu_list(tags=tags, r18=r18)
+ if code != 200:
+ await matcher.finish(setu_list[0], at_sender=True)
+ # 开始发图
+ for _ in range(num):
+ if not setu_list:
+ await setu.finish("坏了,已经没图了,被榨干了!")
+ setu_image = random.choice(setu_list)
+ setu_list.remove(setu_image)
+ try:
+ msg_id = await matcher.send(
+ Message(
+ gen_message(setu_image)
+ + (await check_local_exists_or_download(setu_image))[0]
+ )
+ )
+ withdraw_message_manager.withdraw_message(
+ event,
+ msg_id["message_id"],
+ Config.get_config("send_setu", "WITHDRAW_SETU_MESSAGE"),
+ )
+ logger.info(
+ f"(USER {event.user_id}, GROUP "
+ f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
+ f" 发送本地色图 {setu_image.local_id}.png"
+ )
+ except ActionFailed:
+ await matcher.finish("坏了,这张图色过头了,我自己看看就行了!", at_sender=True)
diff --git a/plugins/send_setu/data_source.py b/plugins/send_setu_/send_setu/data_source.py
similarity index 89%
rename from plugins/send_setu/data_source.py
rename to plugins/send_setu_/send_setu/data_source.py
index 2df67611..acb9590f 100644
--- a/plugins/send_setu/data_source.py
+++ b/plugins/send_setu_/send_setu/data_source.py
@@ -1,265 +1,278 @@
-from configs.path_config import IMAGE_PATH
-from utils.message_builder import image
-from services.log import logger
-from aiohttp.client_exceptions import ClientConnectorError
-from utils.image_utils import get_img_hash, compressed_image
-from asyncpg.exceptions import UniqueViolationError
-from utils.utils import get_local_proxy
-from asyncio.exceptions import TimeoutError
-from typing import List, Optional
-from configs.config import INITIAL_SETU_PROBABILITY, NICKNAME, DOWNLOAD_SETU
-from models.setu import Setu
-import aiohttp
-import aiofiles
-import asyncio
-import os
-import random
-
-try:
- import ujson as json
-except ModuleNotFoundError:
- import json
-
-
-url = "https://api.lolicon.app/setu/v2"
-path = "_setu/"
-r18_path = "_r18/"
-
-
-# 获取url
-async def get_setu_urls(
- tags: List[str], num: int = 1, r18: int = 0, command: str = ""
-) -> "List[str], List[str], List[tuple], int":
- tags = tags[:3] if len(tags) > 3 else tags
- params = {
- "r18": r18, # 添加r18参数 0为否,1为是,2为混合
- "tag": tags, # 若指定tag
- "num": 100, # 一次返回的结果数量
- "size": ["original"],
- }
- async with aiohttp.ClientSession() as session:
- for count in range(3):
- logger.info(f"get_setu_url: count --> {count}")
- try:
- async with session.get(
- url, proxy=get_local_proxy(), timeout=2, params=params
- ) as response:
- if response.status == 200:
- data = await response.json()
- if not data["error"]:
- data = data["data"]
- (
- urls,
- text_list,
- add_databases_list,
- ) = await asyncio.get_event_loop().run_in_executor(
- None, _setu_data_process, data, command
- )
- num = num if num < len(data) else len(data)
- random_idx = random.sample(range(len(data)), num)
- x_urls = []
- x_text_lst = []
- for x in random_idx:
- x_urls.append(urls[x])
- x_text_lst.append(text_list[x])
- if not x_urls:
- return ["没找到符合条件的色图..."], [], [], 401
- return x_urls, x_text_lst, add_databases_list, 200
- else:
- return ["没找到符合条件的色图..."], [], [], 401
- except (TimeoutError, ClientConnectorError):
- pass
- return ["我网线被人拔了..QAQ"], [], [], 999
-
-
-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",
-}
-
-
-async def search_online_setu(
- url_: str, id_: Optional[int] = None, path_: Optional[str] = None
-) -> "MessageSegment, int":
- """
- 下载色图
- :param url_: 色图url
- :param id_: 本地id
- :param path_: 存储路径
- """
- if "i.pixiv.cat" in url_:
- url_ = url_.replace("i.pixiv.cat", "i.pximg.net")
- async with aiohttp.ClientSession(headers=headers) as session:
- for i in range(3):
- logger.info(f"search_online_setu --> {i}")
- try:
- async with session.get(url_, proxy=get_local_proxy(), timeout=3) as res:
- if res.status == 200:
- 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_}')
- async with aiofiles.open(
- f"{IMAGE_PATH}/{path_}/{file}", "wb"
- ) as f:
- try:
- await f.write(await res.read())
- except TimeoutError:
- continue
- if id_ is not None:
- if (
- os.path.getsize(f"{IMAGE_PATH}/{path_}/{index}.jpg")
- > 1024 * 1024 * 1.5
- ):
- compressed_image(
- f"{IMAGE_PATH}/{path_}/{index}.jpg",
- )
- logger.info(f"下载 lolicon图片 {url_} 成功, id:{index}")
- return image(file, path_), index
- else:
- logger.warning(f"访问 lolicon图片 {url_} 失败 status:{res.status}")
- # return '\n这图好难下载啊!QAQ', -1, False
- except (TimeoutError, ClientConnectorError):
- pass
- return "图片被小怪兽恰掉啦..!QAQ", -1
-
-
-# 检测本地是否有id涩图,无的话则下载
-async def check_local_exists_or_download(setu_image: Setu) -> "MessageSegment, int":
- path_ = None
- id_ = None
- if 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"):
- return image(f"{setu_image.local_id}.jpg", path_), 200
- return await search_online_setu(setu_image.img_url, id_, path_)
-
-
-# 添加涩图数据到数据库
-async def add_data_to_database(lst: List[tuple]):
- tmp = []
- for x in lst:
- if x not in tmp:
- tmp.append(x)
- if tmp:
- for x in tmp:
- try:
- r18 = 1 if "R-18" in x[5] else 0
- idx = await Setu.get_image_count(r18)
- await Setu.add_setu_data(
- idx,
- x[0],
- x[1],
- x[2],
- x[3],
- x[4],
- x[5],
- )
- except UniqueViolationError:
- pass
-
-
-# 拿到本地色图列表
-async def get_setu_list(
- index: Optional[int] = None, tags: Optional[List[str]] = None, r18: int = 0
-) -> "list, int":
- if index:
- image_count = await Setu.get_image_count(r18) - 1
- if index < 0 or index > image_count:
- return [f"超过当前上下限!({image_count})"], 999
- image_list = [await Setu.query_image(index, r18=r18)]
- elif tags:
- image_list = await Setu.query_image(tags=tags, r18=r18)
- else:
- image_list = await Setu.query_image(r18=r18)
- if not image_list:
- return ["没找到符合条件的色图..."], 998
- return image_list, 200
-
-
-# 初始化消息
-def gen_message(setu_image: Setu, img_msg: bool = False):
- local_id = setu_image.local_id
- title = setu_image.title
- author = setu_image.author
- pid = setu_image.pid
- return (
- f"id:{local_id}\n"
- f"title:{title}\n"
- f"author:{author}\n"
- f"PID:{pid}\n"
- f"{image(f'{local_id}', f'{r18_path if setu_image.is_r18 else path}') if img_msg else ''}"
- )
-
-
-# 罗翔老师!
-def get_luoxiang(impression):
- probability = impression + INITIAL_SETU_PROBABILITY * 100
- if probability < random.randint(1, 101):
- return (
- "我为什么要给你发这个?"
- + image(random.choice(os.listdir(IMAGE_PATH + "luoxiang/")), "luoxiang")
- + f"\n(快向{NICKNAME}签到提升好感度吧!)"
- )
- return None
-
-
-async def find_img_index(img_url, user_id):
- async with aiohttp.ClientSession() as session:
- async with session.get(img_url, proxy=get_local_proxy(), timeout=5) as res:
- async with aiofiles.open(
- IMAGE_PATH + f"temp/{user_id}_find_setu_index.jpg", "wb"
- ) as f:
- await f.write(await res.read())
- img_hash = str(get_img_hash(IMAGE_PATH + f"temp/{user_id}_find_setu_index.jpg"))
- setu_img = await Setu.get_image_in_hash(img_hash)
- if setu_img:
- return (
- f"id:{setu_img.local_id}\n"
- f"title:{setu_img.title}\n"
- f"author:{setu_img.author}\n"
- f"PID:{setu_img.pid}"
- )
- return "该图不在色图库中或色图库未更新!"
-
-
-# 处理色图数据
-def _setu_data_process(data: dict, command: str) -> "list, list, list":
- urls = []
- text_list = []
- add_databases_list = []
- for i in range(len(data)):
- img_url = data[i]["urls"]["original"]
- img_url = (
- img_url.replace("i.pixiv.cat", "i.pximg.net")
- if "i.pixiv.cat" in img_url
- else img_url
- )
- title = data[i]["title"]
- author = data[i]["author"]
- pid = data[i]["pid"]
- urls.append(img_url)
- text_list.append(f"title:{title}\nauthor:{author}\nPID:{pid}")
- tags = []
- for j in range(len(data[i]["tags"])):
- tags.append(data[i]["tags"][j])
- if command != "色图r":
- if "R-18" in tags:
- tags.remove("R-18")
- add_databases_list.append(
- (
- title,
- author,
- pid,
- "",
- img_url,
- ",".join(tags),
- )
- )
- return urls, text_list, add_databases_list
+from configs.path_config import IMAGE_PATH
+from utils.message_builder import image
+from services.log import logger
+from aiohttp.client_exceptions import ClientConnectorError
+from utils.image_utils import get_img_hash, compressed_image
+from asyncpg.exceptions import UniqueViolationError
+from utils.utils import get_local_proxy
+from asyncio.exceptions import TimeoutError
+from typing import List, Optional
+from configs.config import NICKNAME, Config
+from ..model import Setu
+import aiohttp
+import aiofiles
+import asyncio
+import os
+import random
+
+try:
+ import ujson as json
+except ModuleNotFoundError:
+ import json
+
+
+url = "https://api.lolicon.app/setu/v2"
+path = "_setu/"
+r18_path = "_r18/"
+
+
+# 获取url
+async def get_setu_urls(
+ tags: List[str], num: int = 1, r18: int = 0, command: str = ""
+) -> "List[str], List[str], List[tuple], int":
+ tags = tags[:3] if len(tags) > 3 else tags
+ params = {
+ "r18": r18, # 添加r18参数 0为否,1为是,2为混合
+ "tag": tags, # 若指定tag
+ "num": 100, # 一次返回的结果数量
+ "size": ["original"],
+ }
+ async with aiohttp.ClientSession() as session:
+ for count in range(3):
+ logger.info(f"get_setu_url: count --> {count}")
+ try:
+ async with session.get(
+ url, proxy=get_local_proxy(), timeout=Config.get_config("send_setu", "TIMEOUT"), params=params
+ ) as response:
+ if response.status == 200:
+ data = await response.json()
+ if not data["error"]:
+ data = data["data"]
+ (
+ urls,
+ text_list,
+ add_databases_list,
+ ) = await asyncio.get_event_loop().run_in_executor(
+ None, _setu_data_process, data, command
+ )
+ num = num if num < len(data) else len(data)
+ random_idx = random.sample(range(len(data)), num)
+ x_urls = []
+ x_text_lst = []
+ for x in random_idx:
+ x_urls.append(urls[x])
+ x_text_lst.append(text_list[x])
+ if not x_urls:
+ return ["没找到符合条件的色图..."], [], [], 401
+ return x_urls, x_text_lst, add_databases_list, 200
+ else:
+ return ["没找到符合条件的色图..."], [], [], 401
+ except (TimeoutError, ClientConnectorError):
+ pass
+ return ["我网线被人拔了..QAQ"], [], [], 999
+
+
+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",
+}
+
+
+async def search_online_setu(
+ url_: str, id_: Optional[int] = None, path_: Optional[str] = None
+) -> "MessageSegment, int":
+ """
+ 下载色图
+ :param url_: 色图url
+ :param id_: 本地id
+ :param path_: 存储路径
+ """
+ ws_url = Config.get_config("pixiv", "PIXIV_NGINX_URL")
+ if ws_url:
+ if ws_url.startswith("http"):
+ ws_url = ws_url.split("//")[-1]
+ url_ = url_.replace("i.pximg.net", ws_url).replace("i.pixiv.cat", ws_url)
+ async with aiohttp.ClientSession(headers=headers) as session:
+ for i in range(3):
+ logger.info(f"search_online_setu --> {i}")
+ try:
+ async with session.get(url_, proxy=get_local_proxy(), timeout=Config.get_config("send_setu", "TIMEOUT")) as res:
+ if res.status == 200:
+ 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_}")
+ async with aiofiles.open(
+ f"{IMAGE_PATH}/{path_}/{file}", "wb"
+ ) as f:
+ try:
+ await f.write(await res.read())
+ except TimeoutError:
+ continue
+ if id_ is not None:
+ if (
+ os.path.getsize(f"{IMAGE_PATH}/{path_}/{index}.jpg")
+ > 1024 * 1024 * 1.5
+ ):
+ compressed_image(
+ f"{IMAGE_PATH}/{path_}/{index}.jpg",
+ )
+ logger.info(f"下载 lolicon图片 {url_} 成功, id:{index}")
+ return image(file, path_), index
+ else:
+ logger.warning(f"访问 lolicon图片 {url_} 失败 status:{res.status}")
+ # return '\n这图好难下载啊!QAQ', -1, False
+ except (TimeoutError, ClientConnectorError):
+ pass
+ return "图片被小怪兽恰掉啦..!QAQ", -1
+
+
+# 检测本地是否有id涩图,无的话则下载
+async def check_local_exists_or_download(setu_image: Setu) -> "MessageSegment, int":
+ path_ = None
+ 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"):
+ return image(f"{setu_image.local_id}.jpg", path_), 200
+ return await search_online_setu(setu_image.img_url, id_, path_)
+
+
+# 添加涩图数据到数据库
+async def add_data_to_database(lst: List[tuple]):
+ tmp = []
+ for x in lst:
+ if x not in tmp:
+ tmp.append(x)
+ if tmp:
+ for x in tmp:
+ try:
+ r18 = 1 if "R-18" in x[5] else 0
+ idx = await Setu.get_image_count(r18)
+ await Setu.add_setu_data(
+ idx,
+ x[0],
+ x[1],
+ x[2],
+ x[3],
+ x[4],
+ x[5],
+ )
+ except UniqueViolationError:
+ pass
+
+
+# 拿到本地色图列表
+async def get_setu_list(
+ index: Optional[int] = None, tags: Optional[List[str]] = None, r18: int = 0
+) -> "list, int":
+ if index:
+ image_count = await Setu.get_image_count(r18) - 1
+ if index < 0 or index > image_count:
+ return [f"超过当前上下限!({image_count})"], 999
+ image_list = [await Setu.query_image(index, r18=r18)]
+ elif tags:
+ image_list = await Setu.query_image(tags=tags, r18=r18)
+ else:
+ image_list = await Setu.query_image(r18=r18)
+ if not image_list:
+ return ["没找到符合条件的色图..."], 998
+ return image_list, 200
+
+
+# 初始化消息
+def gen_message(setu_image: Setu, img_msg: bool = False) -> str:
+ local_id = setu_image.local_id
+ title = setu_image.title
+ author = setu_image.author
+ pid = setu_image.pid
+ return (
+ f"id:{local_id}\n"
+ f"title:{title}\n"
+ f"author:{author}\n"
+ f"PID:{pid}\n"
+ f"{image(f'{local_id}', f'{r18_path if setu_image.is_r18 else path}') if img_msg else ''}"
+ )
+
+
+# 罗翔老师!
+def get_luoxiang(impression):
+ probability = (
+ impression + Config.get_config("send_setu", "INITIAL_SETU_PROBABILITY") * 100
+ )
+ if probability < random.randint(1, 101):
+ return (
+ "我为什么要给你发这个?"
+ + image(random.choice(os.listdir(IMAGE_PATH + "luoxiang/")), "luoxiang")
+ + f"\n(快向{NICKNAME}签到提升好感度吧!)"
+ )
+ return None
+
+
+async def get_setu_count(r18: int) -> int:
+ """
+ 获取色图数量
+ :param r18: r18类型
+ """
+ return await Setu.get_image_count(r18)
+
+
+async def find_img_index(img_url, user_id):
+ async with aiohttp.ClientSession() as session:
+ async with session.get(img_url, proxy=get_local_proxy(), timeout=Config.get_config("send_setu", "TIMEOUT")) as res:
+ async with aiofiles.open(
+ IMAGE_PATH + f"temp/{user_id}_find_setu_index.jpg", "wb"
+ ) as f:
+ await f.write(await res.read())
+ img_hash = str(get_img_hash(IMAGE_PATH + f"temp/{user_id}_find_setu_index.jpg"))
+ setu_img = await Setu.get_image_in_hash(img_hash)
+ if setu_img:
+ return (
+ f"id:{setu_img.local_id}\n"
+ f"title:{setu_img.title}\n"
+ f"author:{setu_img.author}\n"
+ f"PID:{setu_img.pid}"
+ )
+ return "该图不在色图库中或色图库未更新!"
+
+
+# 处理色图数据
+def _setu_data_process(data: dict, command: str) -> "list, list, list":
+ urls = []
+ text_list = []
+ add_databases_list = []
+ for i in range(len(data)):
+ img_url = data[i]["urls"]["original"]
+ img_url = (
+ img_url.replace("i.pixiv.cat", "i.pximg.net")
+ if "i.pixiv.cat" in img_url
+ else img_url
+ )
+ title = data[i]["title"]
+ author = data[i]["author"]
+ pid = data[i]["pid"]
+ urls.append(img_url)
+ text_list.append(f"title:{title}\nauthor:{author}\nPID:{pid}")
+ tags = []
+ for j in range(len(data[i]["tags"])):
+ tags.append(data[i]["tags"][j])
+ if command != "色图r":
+ if "R-18" in tags:
+ tags.remove("R-18")
+ add_databases_list.append(
+ (
+ title,
+ author,
+ pid,
+ "",
+ img_url,
+ ",".join(tags),
+ )
+ )
+ return urls, text_list, add_databases_list
diff --git a/plugins/update_setu/__init__.py b/plugins/send_setu_/update_setu/__init__.py
similarity index 88%
rename from plugins/update_setu/__init__.py
rename to plugins/send_setu_/update_setu/__init__.py
index 48d86b75..aa048f9b 100644
--- a/plugins/update_setu/__init__.py
+++ b/plugins/send_setu_/update_setu/__init__.py
@@ -1,48 +1,48 @@
-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 DOWNLOAD_SETU
-
-
-__zx_plugin_name__ = "更新色图 [Superuser]"
-__plugin_usage__ = """
-usage:
- 更新数据库内存在的色图
- 指令:
- 更新色图
-""".strip()
-__plugin_cmd__ = ["更新色图"]
-__plugin_version__ = 0.1
-__plugin_author__ = "HibiKier"
-__plugin_block_limit__ = {
- "rst": "色图正在更新..."
-}
-
-
-update_setu = on_command(
- "更新色图", rule=to_me(), permission=SUPERUSER, priority=1, block=True
-)
-
-
-@update_setu.handle()
-async def _(bot: Bot, event: Event, state: T_State):
- if DOWNLOAD_SETU:
- await update_setu.send("开始更新色图...", at_sender=True)
- await update_setu.send(await update_setu_img(), at_sender=True)
- else:
- await update_setu.finish("更新色图配置未开启")
-
-
-# 更新色图
-@scheduler.scheduled_job(
- "cron",
- hour=4,
- minute=30,
-)
-async def _():
- if DOWNLOAD_SETU:
- await update_setu_img()
+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
+
+
+__zx_plugin_name__ = "更新色图 [Superuser]"
+__plugin_usage__ = """
+usage:
+ 更新数据库内存在的色图
+ 指令:
+ 更新色图
+""".strip()
+__plugin_cmd__ = ["更新色图"]
+__plugin_version__ = 0.1
+__plugin_author__ = "HibiKier"
+__plugin_block_limit__ = {
+ "rst": "色图正在更新..."
+}
+
+
+update_setu = on_command(
+ "更新色图", rule=to_me(), permission=SUPERUSER, priority=1, block=True
+)
+
+
+@update_setu.handle()
+async def _(bot: Bot, event: Event, state: T_State):
+ if Config.get_config("send_setu", "DOWNLOAD_SETU"):
+ await update_setu.send("开始更新色图...", at_sender=True)
+ await update_setu.send(await update_setu_img(), at_sender=True)
+ else:
+ await update_setu.finish("更新色图配置未开启")
+
+
+# 更新色图
+@scheduler.scheduled_job(
+ "cron",
+ hour=4,
+ minute=30,
+)
+async def _():
+ if Config.get_config("send_setu", "DOWNLOAD_SETU"):
+ await update_setu_img()
diff --git a/plugins/update_setu/data_source.py b/plugins/send_setu_/update_setu/data_source.py
similarity index 85%
rename from plugins/update_setu/data_source.py
rename to plugins/send_setu_/update_setu/data_source.py
index d50f852a..92d81355 100644
--- a/plugins/update_setu/data_source.py
+++ b/plugins/send_setu_/update_setu/data_source.py
@@ -1,164 +1,177 @@
-from configs.path_config import IMAGE_PATH, TEXT_PATH
-from services.log import logger
-from datetime import datetime
-from utils.image_utils import compressed_image, get_img_hash
-from utils.utils import get_bot, get_local_proxy
-from asyncio.exceptions import TimeoutError
-from models.setu import Setu
-from aiohttp.client_exceptions import ClientConnectorError
-from asyncpg.exceptions import UniqueViolationError
-from pathlib import Path
-from nonebot import Driver
-import nonebot
-import aiofiles
-import aiohttp
-import os
-import ujson as json
-
-driver: Driver = nonebot.get_driver()
-
-_path = Path(IMAGE_PATH)
-
-
-# 替换旧色图数据,修复local_id一直是50的问题
-@driver.on_startup
-async def update_old_setu_data():
- 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():
- index = 0
- r18_index = 0
- count = 0
- fail_count = 0
- for file in [setu_data_file, r18_data_file]:
- if file.exists():
- data = json.load(open(file, "r", encoding="utf8"))
- for x in data:
- if file == setu_data_file:
- idx = index
- if 'R-18' in data[x]["tags"]:
- data[x]["tags"].remove('R-18')
- else:
- idx = r18_index
- img_url = (
- data[x]["img_url"].replace("i.pixiv.cat", "i.pximg.net")
- if "i.pixiv.cat" in data[x]["img_url"]
- else data[x]["img_url"]
- )
- # idx = r18_index if 'R-18' in data[x]["tags"] else index
- try:
- await Setu.add_setu_data(
- idx,
- data[x]["title"],
- data[x]["author"],
- data[x]["pid"],
- data[x]["img_hash"],
- img_url,
- ",".join(data[x]["tags"]),
- )
- count += 1
- if 'R-18' in data[x]["tags"]:
- r18_index += 1
- else:
- index += 1
- logger.info(f'添加旧色图数据成功 PID:{data[x]["pid"]} index:{idx}....')
- except UniqueViolationError:
- fail_count += 1
- logger.info(f'添加旧色图数据失败,色图重复 PID:{data[x]["pid"]} index:{idx}....')
- file.unlink()
- setu_url_path = path / "setu_url.json"
- setu_r18_url_path = path / "setu_r18_url.json"
- if setu_url_path.exists():
- setu_url_path.unlink()
- if setu_r18_url_path.exists():
- setu_r18_url_path.unlink()
- logger.info(f"更新旧色图数据完成,成功更新数据:{count} 条,累计失败:{fail_count} 条")
-
-
-headers = {
- "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",
-}
-
-
-async def update_setu_img():
- image_list = await Setu.get_all_setu()
- image_list.reverse()
- _success = 0
- error_info = []
- error_type = []
- count = 0
- async with aiohttp.ClientSession(headers=headers) as session:
- for image in image_list:
- count += 1
- path = _path / "_r18" if image.is_r18 else _path / "_setu"
- rar_path = _path / "r18_rar" if image.is_r18 else _path / "rar"
- local_image = path / f"{image.local_id}.jpg"
- path.mkdir(exist_ok=True, parents=True)
- rar_path.mkdir(exist_ok=True, parents=True)
- if not local_image.exists() or not image.img_hash:
- for _ in range(3):
- try:
- async with session.get(
- image.img_url, proxy=get_local_proxy(), timeout=30
- ) as response:
- if response.status == 200:
- async with aiofiles.open(
- rar_path / f'{image.local_id}.jpg',
- "wb",
- ) as f:
- await f.write(await response.read())
- _success += 1
- try:
- if (
- os.path.getsize(
- 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"
- )
- else:
- logger.info(
- f"不需要压缩,移动图片{rar_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",
- )
- 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
- )
- break
- except (TimeoutError, ClientConnectorError) as e:
- logger.warning(f"{image.local_id}.jpg 更新失败 ..{type(e)}:{e}")
- except Exception as e:
- 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}"
- )
- else:
- logger.info(f'更新色图 {image.local_id}.jpg 已存在')
- error_info = ['无报错..'] if not error_info else 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),
- )
-
-
+from configs.path_config import IMAGE_PATH, TEXT_PATH, TEMP_PATH
+from services.log import logger
+from datetime import datetime
+from utils.image_utils import compressed_image, get_img_hash
+from utils.utils import get_bot, get_local_proxy
+from asyncio.exceptions import TimeoutError
+from ..model import Setu
+from aiohttp.client_exceptions import ClientConnectorError
+from asyncpg.exceptions import UniqueViolationError
+from configs.config import Config
+from pathlib import Path
+from nonebot import Driver
+import nonebot
+import aiofiles
+import aiohttp
+import os
+import ujson as json
+import shutil
+
+driver: Driver = nonebot.get_driver()
+
+_path = Path(IMAGE_PATH)
+
+
+# 替换旧色图数据,修复local_id一直是50的问题
+@driver.on_startup
+async def update_old_setu_data():
+ 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():
+ index = 0
+ r18_index = 0
+ count = 0
+ fail_count = 0
+ for file in [setu_data_file, r18_data_file]:
+ if file.exists():
+ data = json.load(open(file, "r", encoding="utf8"))
+ for x in data:
+ if file == setu_data_file:
+ idx = index
+ if 'R-18' in data[x]["tags"]:
+ data[x]["tags"].remove('R-18')
+ else:
+ idx = r18_index
+ img_url = (
+ data[x]["img_url"].replace("i.pixiv.cat", "i.pximg.net")
+ if "i.pixiv.cat" in data[x]["img_url"]
+ else data[x]["img_url"]
+ )
+ # idx = r18_index if 'R-18' in data[x]["tags"] else index
+ try:
+ await Setu.add_setu_data(
+ idx,
+ data[x]["title"],
+ data[x]["author"],
+ data[x]["pid"],
+ data[x]["img_hash"],
+ img_url,
+ ",".join(data[x]["tags"]),
+ )
+ count += 1
+ if 'R-18' in data[x]["tags"]:
+ r18_index += 1
+ else:
+ index += 1
+ logger.info(f'添加旧色图数据成功 PID:{data[x]["pid"]} index:{idx}....')
+ except UniqueViolationError:
+ fail_count += 1
+ logger.info(f'添加旧色图数据失败,色图重复 PID:{data[x]["pid"]} index:{idx}....')
+ file.unlink()
+ setu_url_path = path / "setu_url.json"
+ setu_r18_url_path = path / "setu_r18_url.json"
+ if setu_url_path.exists():
+ setu_url_path.unlink()
+ if setu_r18_url_path.exists():
+ setu_r18_url_path.unlink()
+ logger.info(f"更新旧色图数据完成,成功更新数据:{count} 条,累计失败:{fail_count} 条")
+
+
+# 删除色图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)
+
+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",
+}
+
+
+async def update_setu_img():
+ image_list = await Setu.get_all_setu()
+ image_list.reverse()
+ _success = 0
+ error_info = []
+ error_type = []
+ count = 0
+ async with aiohttp.ClientSession(headers=headers) as session:
+ 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)
+ if not local_image.exists() or not image.img_hash:
+ url_ = image.img_url
+ ws_url = Config.get_config("pixiv", "PIXIV_NGINX_URL")
+ if ws_url.startswith("http"):
+ ws_url = ws_url.split("//")[-1]
+ url_ = url_.replace("i.pximg.net", ws_url).replace("i.pixiv.cat", ws_url)
+ for _ in range(3):
+ try:
+ async with session.get(
+ url_, proxy=get_local_proxy(), timeout=30
+ ) as response:
+ if response.status == 200:
+ async with aiofiles.open(
+ rar_path / f'{image.local_id}.jpg',
+ "wb",
+ ) as f:
+ await f.write(await response.read())
+ _success += 1
+ try:
+ if (
+ os.path.getsize(
+ 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"
+ )
+ else:
+ logger.info(
+ f"不需要压缩,移动图片{rar_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",
+ )
+ 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
+ )
+ break
+ except (TimeoutError, ClientConnectorError) as e:
+ logger.warning(f"{image.local_id}.jpg 更新失败 ..{type(e)}:{e}")
+ except Exception as e:
+ 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}"
+ )
+ 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):
+ 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),
+ )
+
+
diff --git a/plugins/shop/__init__.py b/plugins/shop/__init__.py
index e0fbec0a..43482d7a 100644
--- a/plugins/shop/__init__.py
+++ b/plugins/shop/__init__.py
@@ -1,84 +1,14 @@
-from pathlib import Path
-from configs.path_config import DATA_PATH
import nonebot
-try:
- import ujson as json
-except ModuleNotFoundError:
- import json
+from configs.config import Config
+
+
+Config.add_plugin_config(
+ "shop",
+ "IMPORT_DEFAULT_SHOP_GOODS",
+ True,
+ help_="导入商店自带的三个商品",
+ default_value=True
+)
+
nonebot.load_plugins("plugins/shop")
-
-# 修改旧数据
-
-statistics_group_file = Path(DATA_PATH) / "statistics" / "_prefix_count.json"
-statistics_user_file = Path(DATA_PATH) / "statistics" / "_prefix_user_count.json"
-
-for file in [statistics_group_file, statistics_user_file]:
- if file.exists():
- with open(file, 'r', encoding='utf8') as f:
- data = json.load(f)
- if not (statistics_group_file.parent / f"{file}.bak").exists():
- with open(f"{file}.bak", 'w', encoding='utf8') as wf:
- json.dump(data, wf, ensure_ascii=False, indent=4)
- for x in ['total_statistics', 'day_statistics']:
- for key in data[x].keys():
- num = 0
- if data[x][key].get('我的道具') is not None:
- num += data[x][key]['我的道具']
- del data[x][key]['我的道具']
- if data[x][key].get('使用道具') is not None:
- num += data[x][key]['使用道具']
- del data[x][key]['使用道具']
- if data[x][key].get('我的金币') is not None:
- num += data[x][key]['我的金币']
- del data[x][key]['我的金币']
- if data[x][key].get('购买') is not None:
- num += data[x][key]['购买']
- del data[x][key]['购买']
- if data[x][key].get('商店') is not None:
- data[x][key]['商店'] += num
- else:
- data[x][key]['商店'] = num
- for x in ['week_statistics', 'month_statistics']:
- for key in data[x].keys():
- if key == 'total':
- if data[x][key].get('我的道具') is not None:
- num += data[x][key]['我的道具']
- del data[x][key]['我的道具']
- if data[x][key].get('使用道具') is not None:
- num += data[x][key]['使用道具']
- del data[x][key]['使用道具']
- if data[x][key].get('我的金币') is not None:
- num += data[x][key]['我的金币']
- del data[x][key]['我的金币']
- if data[x][key].get('购买') is not None:
- num += data[x][key]['购买']
- del data[x][key]['购买']
- if data[x][key].get('商店') is not None:
- data[x][key]['商店'] += num
- else:
- data[x][key]['商店'] = num
- else:
- for day in data[x][key].keys():
- num = 0
- if data[x][key][day].get('我的道具') is not None:
- num += data[x][key][day]['我的道具']
- del data[x][key][day]['我的道具']
- if data[x][key][day].get('使用道具') is not None:
- num += data[x][key][day]['使用道具']
- del data[x][key][day]['使用道具']
- if data[x][key][day].get('我的金币') is not None:
- num += data[x][key][day]['我的金币']
- del data[x][key][day]['我的金币']
- if data[x][key][day].get('购买') is not None:
- num += data[x][key][day]['购买']
- del data[x][key][day]['购买']
- if data[x][key][day].get('商店') is not None:
- data[x][key][day]['商店'] += num
- else:
- data[x][key][day]['商店'] = num
- with open(file, 'w', encoding='utf8') as f:
- json.dump(data, f, ensure_ascii=False, indent=4)
-
-
-
diff --git a/plugins/shop/buy.py b/plugins/shop/buy.py
index 5968360c..7518ccc6 100644
--- a/plugins/shop/buy.py
+++ b/plugins/shop/buy.py
@@ -6,7 +6,7 @@ from utils.utils import get_message_text, is_number
from models.bag_user import BagUser
from services.db_context import db
from nonebot.adapters.cqhttp.permission import GROUP
-from models.goods_info import GoodsInfo
+from .models.goods_info import GoodsInfo
__zx_plugin_name__ = "商店 - 购买道具"
diff --git a/plugins/shop/gold.py b/plugins/shop/gold.py
index e139a23c..688df78b 100644
--- a/plugins/shop/gold.py
+++ b/plugins/shop/gold.py
@@ -4,6 +4,8 @@ from nonebot.typing import T_State
from nonebot.adapters.cqhttp.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
__zx_plugin_name__ = "商店 - 我的金币"
__plugin_usage__ = """
@@ -14,7 +16,7 @@ usage:
""".strip()
__plugin_des__ = "商店 - 我的金币"
__plugin_cmd__ = ["我的金币"]
-__plugin_type__ = ('商店',)
+__plugin_type__ = ("商店",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
@@ -37,9 +39,14 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
@gold_rank.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
+ num = get_message_text(event.json())
+ if is_number(num) and 51 > int(num) > 10:
+ num = int(num)
+ else:
+ num = 10
all_users = await BagUser.get_all_users(event.group_id)
all_user_id = [user.user_qq for user in all_users]
all_user_data = [user.gold for user in all_users]
- await gold_rank.finish(
- "金币排行:\n" + await init_rank(all_user_id, all_user_data, event.group_id)
- )
+ rank_image = await init_rank("金币排行", all_user_id, all_user_data, event.group_id, num)
+ if rank_image:
+ await gold_rank.finish(image(b64=rank_image.pic2bs4()))
diff --git a/plugins/shop/gold_redbag/__init__.py b/plugins/shop/gold_redbag/__init__.py
index a7be458e..2c20c7a3 100644
--- a/plugins/shop/gold_redbag/__init__.py
+++ b/plugins/shop/gold_redbag/__init__.py
@@ -19,6 +19,7 @@ from nonebot.matcher import Matcher
from utils.utils import get_message_text, is_number, scheduler
from utils.message_builder import image
from services.log import logger
+from configs.path_config import IMAGE_PATH
from nonebot.permission import SUPERUSER
from nonebot.rule import to_me
from datetime import datetime, timedelta
@@ -49,6 +50,9 @@ __plugin_settings__ = {
"limit_superuser": False,
"cmd": ["金币红包", "塞红包"],
}
+__plugin_resources__ = {
+ "prts": IMAGE_PATH
+}
gold_redbag = on_command(
"塞红包", aliases={"金币红包"}, priority=5, block=True, permission=GROUP
diff --git a/plugins/shop/gold_redbag/data_source.py b/plugins/shop/gold_redbag/data_source.py
index fb14c094..46640295 100644
--- a/plugins/shop/gold_redbag/data_source.py
+++ b/plugins/shop/gold_redbag/data_source.py
@@ -3,7 +3,7 @@ from utils.utils import is_number, get_local_proxy
from utils.image_utils import CreateImg
from utils.user_agent import get_user_agent
from configs.path_config import IMAGE_PATH
-from models.redbag_user import RedbagUser
+from ..models.redbag_user import RedbagUser
import random
import os
import aiohttp
diff --git a/plugins/shop/models/__init__.py b/plugins/shop/models/__init__.py
new file mode 100644
index 00000000..db1ab9ef
--- /dev/null
+++ b/plugins/shop/models/__init__.py
@@ -0,0 +1 @@
+from .goods_info import *
diff --git a/models/goods_info.py b/plugins/shop/models/goods_info.py
similarity index 100%
rename from models/goods_info.py
rename to plugins/shop/models/goods_info.py
diff --git a/models/redbag_user.py b/plugins/shop/models/redbag_user.py
similarity index 100%
rename from models/redbag_user.py
rename to plugins/shop/models/redbag_user.py
diff --git a/plugins/shop/shop_handle/data_source.py b/plugins/shop/shop_handle/data_source.py
index b9b5d479..915839d4 100644
--- a/plugins/shop/shop_handle/data_source.py
+++ b/plugins/shop/shop_handle/data_source.py
@@ -1,8 +1,8 @@
-from models.goods_info import GoodsInfo
+from ..models.goods_info import GoodsInfo
from utils.image_utils import CreateImg
from utils.utils import is_number
from configs.path_config import IMAGE_PATH
-from configs.config import IMPORT_DEFAULT_SHOP_GOODS
+from configs.config import Config
from nonebot import Driver
import nonebot
import time
@@ -17,7 +17,7 @@ driver: Driver = nonebot.get_driver()
async def init_default_shop_goods():
if os.path.exists(f"{IMAGE_PATH}/shop_help.png"):
os.remove(f"{IMAGE_PATH}/shop_help.png")
- if IMPORT_DEFAULT_SHOP_GOODS:
+ if Config.get_config("shop", "IMPORT_DEFAULT_SHOP_GOODS"):
await add_goods(["好感度双倍加持卡Ⅰ", 30, "下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)"])
await add_goods(["好感度双倍加持卡Ⅱ", 150, "下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)"])
await add_goods(["好感度双倍加持卡Ⅲ", 250, "下次签到双倍好感度概率 + 30%(金币才是真命天子!)(同类商品将覆盖)"])
diff --git a/plugins/sign_in/__init__.py b/plugins/sign_in/__init__.py
index d0df66f1..cece39ab 100644
--- a/plugins/sign_in/__init__.py
+++ b/plugins/sign_in/__init__.py
@@ -6,7 +6,6 @@ from .group_user_checkin import (
)
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, GroupMessageEvent
-from utils.manager import plugins2cd_manager
from nonebot.adapters.cqhttp.permission import GROUP
from utils.message_builder import image
from nonebot import on_command
@@ -15,6 +14,7 @@ from pathlib import Path
from configs.path_config import DATA_PATH
from services.log import logger
from .utils import clear_sign_data_pic
+from utils.utils import is_number
try:
import ujson as json
@@ -43,9 +43,30 @@ __plugin_settings__ = {
"limit_superuser": False,
"cmd": ["签到"],
}
-plugins2cd_manager.add_cd_limit(
- 'sign_in',
-)
+__plugin_cd_limit__ = {}
+__plugin_configs__ = {
+ "MAX_SIGN_GOLD": {
+ "value": 200,
+ "help": "签到好感度加成额外获得的最大金币数",
+ "default_value": 200
+ },
+ "SIGN_CARD1_PROB": {
+ "value": 0.2,
+ "help": "签到好感度双倍加持卡Ⅰ掉落概率",
+ "default_value": 0.2
+ },
+ "SIGN_CARD2_PROB": {
+ "value": 0.09,
+ "help": "签到好感度双倍加持卡Ⅱ掉落概率",
+ "default_value": 0.09
+ },
+ "SIGN_CARD3_PROB": {
+ "value": 0.05,
+ "help": "签到好感度双倍加持卡Ⅲ掉落概率",
+ "default_value": 0.05
+ }
+}
+
_file = Path(f"{DATA_PATH}/not_show_sign_rank_user.json")
try:
@@ -90,7 +111,14 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
@sign_rank.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
- await sign_rank.send(await group_impression_rank(event.group_id))
+ num = get_message_text(event.json())
+ if is_number(num) and 51 > int(num) > 10:
+ num = int(num)
+ else:
+ num = 10
+ _image = await group_impression_rank(event.group_id, num)
+ if _image:
+ await sign_rank.send(image(b64=_image.pic2bs4()))
@total_sign_rank.handle()
diff --git a/plugins/sign_in/config.py b/plugins/sign_in/config.py
index 1e662bcb..68232954 100644
--- a/plugins/sign_in/config.py
+++ b/plugins/sign_in/config.py
@@ -10,16 +10,6 @@ SIGN_BACKGROUND_PATH = Path(SIGN_RESOURCE_PATH) / 'background'
SIGN_BORDER_PATH.mkdir(exist_ok=True, parents=True)
SIGN_BACKGROUND_PATH.mkdir(exist_ok=True, parents=True)
-SIGN_CARD1_PROB = 0.2 # 好感度双倍加持卡Ⅰ
-SIGN_CARD2_PROB = 0.09 # 好感度双倍加持卡Ⅱ
-SIGN_CARD3_PROB = 0.05 # 好感度双倍加持卡Ⅲ
-
-PROB_DATA = {
- SIGN_CARD3_PROB: '好感度双倍加持卡Ⅲ',
- SIGN_CARD2_PROB: '好感度双倍加持卡Ⅱ',
- SIGN_CARD1_PROB: '好感度双倍加持卡Ⅰ'
-}
-
lik2relation = {
'0': '路人',
diff --git a/plugins/sign_in/group_user_checkin.py b/plugins/sign_in/group_user_checkin.py
index a7a10863..18150ab4 100644
--- a/plugins/sign_in/group_user_checkin.py
+++ b/plugins/sign_in/group_user_checkin.py
@@ -5,11 +5,13 @@ from models.bag_user import BagUser
from configs.config import NICKNAME
from nonebot.adapters.cqhttp import MessageSegment
from asyncio.exceptions import TimeoutError
-from utils.image_utils import CreateImg
+from utils.image_utils import CreateImg, CreateMat
from services.db_context import db
from .utils import get_card, SIGN_TODAY_CARD_PATH
+from typing import Optional
from services.log import logger
from .random_event import random_event
+from utils.data_utils import init_rank
from io import BytesIO
import random
import aiohttp
@@ -82,31 +84,9 @@ async def group_user_check(nickname: str, user_qq: int, group: int) -> MessageSe
return await get_card(user, nickname, None, gold, "", is_card_view=True)
-async def group_impression_rank(group: int) -> str:
- result = "\t好感度排行榜\t\n"
+async def group_impression_rank(group: int, num: int) -> Optional[CreateMat]:
user_qq_list, impression_list, _ = await SignGroupUser.get_all_impression(group)
- _count = 11
- if user_qq_list and impression_list:
- for i in range(1, len(user_qq_list)):
- if len(user_qq_list) == 0 or len(impression_list) == 0 or i == _count:
- break
- impression = max(impression_list)
- index = impression_list.index(impression)
- user_qq = user_qq_list[index]
- try:
- user_name = (
- await GroupInfoUser.get_member_info(user_qq, group)
- ).user_name
- except AttributeError:
- logger.info(f"USER {user_qq}, GROUP {group} 不在群内")
- _count += 1
- impression_list.remove(impression)
- user_qq_list.remove(user_qq)
- continue
- result += f"{i - _count + 11}. {user_name}: {impression:.2f}\n"
- impression_list.remove(impression)
- user_qq_list.remove(user_qq)
- return result[:-1]
+ return await init_rank("好感度排行榜", user_qq_list, impression_list, group, num)
async def random_gold(user_id, group_id, impression):
diff --git a/plugins/sign_in/random_event.py b/plugins/sign_in/random_event.py
index f1dda044..c5ea35a8 100644
--- a/plugins/sign_in/random_event.py
+++ b/plugins/sign_in/random_event.py
@@ -1,21 +1,30 @@
-from configs.config import MAX_SIGN_GOLD
-from typing import Union
-from .config import PROB_DATA
+from configs.config import Config
import random
+PROB_DATA = None
+
+
def random_event(impression: float) -> 'Union[str, int], str':
"""
签到随机事件
:param impression: 好感度
:return: 额外奖励 和 类型
"""
+ global PROB_DATA
+ if not PROB_DATA:
+ PROB_DATA = {
+ Config.get_config("sign_in", "SIGN_CARD3_PROB"): '好感度双倍加持卡Ⅲ',
+ Config.get_config("sign_in", "SIGN_CARD2_PROB"): '好感度双倍加持卡Ⅱ',
+ Config.get_config("sign_in", "SIGN_CARD1_PROB"): '好感度双倍加持卡Ⅰ'
+ }
rand = random.random() - impression / 1000
for prob in PROB_DATA.keys():
if rand <= prob:
return PROB_DATA[prob], 'props'
gold = random.randint(1, random.randint(1, int(1 if impression < 1 else impression)))
- gold = MAX_SIGN_GOLD if gold > MAX_SIGN_GOLD else gold
+ max_sign_gold = Config.get_config("sign_in", "MAX_SIGN_GOLD")
+ gold = max_sign_gold if gold > max_sign_gold else gold
return gold, 'gold'
diff --git a/plugins/sign_in/utils.py b/plugins/sign_in/utils.py
index 34092e9b..2bffa5ea 100644
--- a/plugins/sign_in/utils.py
+++ b/plugins/sign_in/utils.py
@@ -11,6 +11,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 utils.utils import get_user_avatar
from utils.image_utils import CreateImg
from utils.message_builder import image
from configs.config import NICKNAME
@@ -22,7 +23,6 @@ from io import BytesIO
import asyncio
import random
import nonebot
-import aiohttp
import os
@@ -41,13 +41,6 @@ async def init_image():
clear_sign_data_pic()
-async def _get_pic(qq):
- url = f"http://q1.qlogo.cn/g?b=qq&nk={qq}&s=100"
- async with aiohttp.ClientSession() as session:
- async with session.get(url, timeout=5) as response:
- return await response.read()
-
-
async def get_card(
user: "SignGroupUser",
nickname: str,
@@ -80,7 +73,7 @@ async def get_card(
"sign/today_card",
)
is_card_view = True
- ava = BytesIO(await _get_pic(user_id))
+ ava = BytesIO(await get_user_avatar(user_id))
uid = await GroupInfoUser.get_group_member_uid(
user.user_qq, user.belonging_group
)
diff --git a/plugins/statistics/__init__.py b/plugins/statistics/__init__.py
index 6b1c8b3c..590246d9 100644
--- a/plugins/statistics/__init__.py
+++ b/plugins/statistics/__init__.py
@@ -2,6 +2,10 @@ from pathlib import Path
from configs.path_config import DATA_PATH
import nonebot
import os
+try:
+ import ujson as json
+except ModuleNotFoundError:
+ import json
nonebot.load_plugins("plugins/statistics")
@@ -13,3 +17,112 @@ if old_file1.exists():
os.rename(old_file1, new_path / "_prefix_count.json")
if old_file2.exists():
os.rename(old_file2, new_path / "_prefix_user_count.json")
+
+
+# 修改旧数据
+
+statistics_group_file = Path(DATA_PATH) / "statistics" / "_prefix_count.json"
+statistics_user_file = Path(DATA_PATH) / "statistics" / "_prefix_user_count.json"
+
+for file in [statistics_group_file, statistics_user_file]:
+ if file.exists():
+ with open(file, "r", encoding="utf8") as f:
+ data = json.load(f)
+ if not (statistics_group_file.parent / f"{file}.bak").exists():
+ with open(f"{file}.bak", "w", encoding="utf8") as wf:
+ json.dump(data, wf, ensure_ascii=False, indent=4)
+ for x in ["total_statistics", "day_statistics"]:
+ for key in data[x].keys():
+ num = 0
+ if data[x][key].get("ai") is not None:
+ if data[x][key].get("Ai") is not None:
+ data[x][key]["Ai"] += data[x][key]["ai"]
+ else:
+ data[x][key]["Ai"] = data[x][key]["ai"]
+ del data[x][key]["ai"]
+ if data[x][key].get("抽卡") is not None:
+ if data[x][key].get("游戏抽卡") is not None:
+ data[x][key]["游戏抽卡"] += data[x][key]["抽卡"]
+ else:
+ data[x][key]["游戏抽卡"] = data[x][key]["抽卡"]
+ del data[x][key]["抽卡"]
+ if data[x][key].get("我的道具") is not None:
+ num += data[x][key]["我的道具"]
+ del data[x][key]["我的道具"]
+ if data[x][key].get("使用道具") is not None:
+ num += data[x][key]["使用道具"]
+ del data[x][key]["使用道具"]
+ if data[x][key].get("我的金币") is not None:
+ num += data[x][key]["我的金币"]
+ del data[x][key]["我的金币"]
+ if data[x][key].get("购买") is not None:
+ num += data[x][key]["购买"]
+ del data[x][key]["购买"]
+ if data[x][key].get("商店") is not None:
+ data[x][key]["商店"] += num
+ else:
+ data[x][key]["商店"] = num
+ for x in ["week_statistics", "month_statistics"]:
+ for key in data[x].keys():
+ if key == "total":
+ if data[x][key].get("ai") is not None:
+ if data[x][key].get("Ai") is not None:
+ data[x][key]["Ai"] += data[x][key]["ai"]
+ else:
+ data[x][key]["Ai"] = data[x][key]["ai"]
+ del data[x][key]["ai"]
+ if data[x][key].get("抽卡") is not None:
+ if data[x][key].get("游戏抽卡") is not None:
+ data[x][key]["游戏抽卡"] += data[x][key]["抽卡"]
+ else:
+ data[x][key]["游戏抽卡"] = data[x][key]["抽卡"]
+ del data[x][key]["抽卡"]
+ if data[x][key].get("我的道具") is not None:
+ num += data[x][key]["我的道具"]
+ del data[x][key]["我的道具"]
+ if data[x][key].get("使用道具") is not None:
+ num += data[x][key]["使用道具"]
+ del data[x][key]["使用道具"]
+ if data[x][key].get("我的金币") is not None:
+ num += data[x][key]["我的金币"]
+ del data[x][key]["我的金币"]
+ if data[x][key].get("购买") is not None:
+ num += data[x][key]["购买"]
+ del data[x][key]["购买"]
+ if data[x][key].get("商店") is not None:
+ data[x][key]["商店"] += num
+ else:
+ data[x][key]["商店"] = num
+ else:
+ for day in data[x][key].keys():
+ num = 0
+ if data[x][key][day].get("ai") is not None:
+ if data[x][key][day].get("Ai") is not None:
+ data[x][key][day]["Ai"] += data[x][key][day]["ai"]
+ else:
+ data[x][key][day]["Ai"] = data[x][key][day]["ai"]
+ del data[x][key][day]["ai"]
+ if data[x][key][day].get("抽卡") is not None:
+ if data[x][key][day].get("游戏抽卡") is not None:
+ data[x][key][day]["游戏抽卡"] += data[x][key][day]["抽卡"]
+ else:
+ data[x][key][day]["游戏抽卡"] = data[x][key][day]["抽卡"]
+ del data[x][key][day]["抽卡"]
+ if data[x][key][day].get("我的道具") is not None:
+ num += data[x][key][day]["我的道具"]
+ del data[x][key][day]["我的道具"]
+ if data[x][key][day].get("使用道具") is not None:
+ num += data[x][key][day]["使用道具"]
+ del data[x][key][day]["使用道具"]
+ if data[x][key][day].get("我的金币") is not None:
+ num += data[x][key][day]["我的金币"]
+ del data[x][key][day]["我的金币"]
+ if data[x][key][day].get("购买") is not None:
+ num += data[x][key][day]["购买"]
+ del data[x][key][day]["购买"]
+ if data[x][key][day].get("商店") is not None:
+ data[x][key][day]["商店"] += num
+ else:
+ data[x][key][day]["商店"] = num
+ with open(file, "w", encoding="utf8") as f:
+ json.dump(data, f, ensure_ascii=False, indent=4)
diff --git a/plugins/statistics/statistics_handle.py b/plugins/statistics/statistics_handle.py
index 9c119d8b..6626bc2c 100644
--- a/plugins/statistics/statistics_handle.py
+++ b/plugins/statistics/statistics_handle.py
@@ -103,8 +103,22 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
itype = 'month_statistics'
else:
itype = 'total_statistics'
- data = data[itype]["total"]
- bar_graph = await init_bar_graph(data, state["_prefix"]["raw_command"])
+ tmp_dict = {}
+ data = data[itype]
+ if itype in ["day_statistics", "total_statistics"]:
+ for key in data['total']:
+ tmp_dict[key] = data['total'][key]
+ else:
+ for group in data.keys():
+ if group != 'total':
+ for day in data[group].keys():
+ for plugin_name in data[group][day].keys():
+ if data[group][day][plugin_name] is not None:
+ if tmp_dict.get(plugin_name) is None:
+ 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"])
await asyncio.get_event_loop().run_in_executor(None, bar_graph.gen_graph)
await statistics.finish(image(b64=bar_graph.pic2bs4()))
return
@@ -157,6 +171,10 @@ async def _(bot: Bot, event: MessageEvent, state: T_State):
async def generate_statistics_img(
data: dict, arg: str, name: str, plugin: str, day_index: int
):
+ try:
+ plugin = plugins2settings_manager.get_plugin_data(plugin)['cmd'][0]
+ except (KeyError, IndexError):
+ pass
bar_graph = None
if arg == "day_statistics":
bar_graph = await init_bar_graph(data, f"{name} 日功能调用统计")
@@ -180,7 +198,6 @@ async def generate_statistics_img(
count.append(0)
else:
try:
- print(data[str(week_lst[i])][plugin])
count.append(data[str(week_lst[i])][plugin])
except KeyError:
count.append(0)
@@ -260,3 +277,4 @@ def update_data(data: dict):
else:
tmp_dict[plugin_name] += data[day][plugin_name]
return tmp_dict
+
diff --git a/plugins/statistics/statistics_hook.py b/plugins/statistics/statistics_hook.py
index e5bc57d1..b2f0b2d6 100644
--- a/plugins/statistics/statistics_hook.py
+++ b/plugins/statistics/statistics_hook.py
@@ -97,7 +97,7 @@ async def _(
if (
matcher.type == "message"
and matcher.priority not in [1, 9]
- and matcher.module not in ["update_info"]
+ and matcher.module not in ["update_info", "statistics_handle"]
):
module = matcher.module
day_index = _prefix_count_dict["day_index"]
@@ -153,7 +153,7 @@ def check_exists_key(group_id: str, user_id: str, plugin_name: str):
data["week_statistics"]["total"][plugin_name] = 0
if not data["month_statistics"]["total"].get(plugin_name):
data["month_statistics"]["total"][plugin_name] = 0
-
+
if not data["total_statistics"].get(key):
data["total_statistics"][key] = {}
if not data["total_statistics"][key].get(plugin_name):
@@ -163,23 +163,24 @@ def check_exists_key(group_id: str, user_id: str, plugin_name: str):
if not data["day_statistics"][key].get(plugin_name):
data["day_statistics"][key][plugin_name] = 0
- if not data["week_statistics"].get(key):
- data["week_statistics"][key] = {}
- if data["week_statistics"][key].get("0") is None:
- for i in range(7):
- data["week_statistics"][key][str(i)] = {}
- if data["week_statistics"][key]["0"].get(plugin_name) is None:
- for i in range(7):
- data["week_statistics"][key][str(i)][plugin_name] = 0
-
- if not data["month_statistics"].get(key):
- data["month_statistics"][key] = {}
- if data["month_statistics"][key].get("0") is None:
- for i in range(30):
- data["month_statistics"][key][str(i)] = {}
- if data["month_statistics"][key]["0"].get(plugin_name) is None:
- for i in range(30):
- data["month_statistics"][key][str(i)][plugin_name] = 0
+ if key != 'total':
+ if not data["week_statistics"].get(key):
+ data["week_statistics"][key] = {}
+ if data["week_statistics"][key].get("0") is None:
+ for i in range(7):
+ data["week_statistics"][key][str(i)] = {}
+ if data["week_statistics"][key]["0"].get(plugin_name) is None:
+ for i in range(7):
+ data["week_statistics"][key][str(i)][plugin_name] = 0
+
+ if not data["month_statistics"].get(key):
+ data["month_statistics"][key] = {}
+ if data["month_statistics"][key].get("0") is None:
+ for i in range(30):
+ data["month_statistics"][key][str(i)] = {}
+ if data["month_statistics"][key]["0"].get(plugin_name) is None:
+ for i in range(30):
+ data["month_statistics"][key][str(i)][plugin_name] = 0
# 天
@@ -213,3 +214,4 @@ async def _():
json.dump(_prefix_count_dict, f, indent=4, ensure_ascii=False)
with open(statistics_user_file, "w", encoding="utf8") as f:
json.dump(_prefix_user_count_dict, f, indent=4, ensure_ascii=False)
+
diff --git a/plugins/super_cmd/__init__.py b/plugins/super_cmd/__init__.py
deleted file mode 100644
index 781ddcbb..00000000
--- a/plugins/super_cmd/__init__.py
+++ /dev/null
@@ -1,289 +0,0 @@
-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, MessageEvent, Message
-from nonebot.rule import to_me
-from utils.utils import get_message_at, get_message_text, is_number, get_bot, scheduler
-from pathlib import Path
-from services.log import logger
-from models.group_info import GroupInfo
-from models.friend_user import FriendUser
-from utils.message_builder import at
-from configs.path_config import IMAGE_PATH
-from utils.manager import plugins2cd_manager, plugins2settings_manager, plugins2block_manager, group_manager
-import asyncio
-import os
-
-
-__zx_plugin_name__ = "超级用户指令 [Superuser]"
-__plugin_usage__ = """
-usage:
- 超级用户集成指令
- 指令:
- 添加权限 [at] [权限]
- 删除权限 [at]
- 开启/关闭广播通知 [group]
- 查看所有好友/查看所有群组
- 退群 [group]
- 更新群信息
- 更新好友信息
- 清理临时数据
- 重载插件配置
-""".strip()
-__plugin_des__ = "超级用户集成指令"
-__plugin_cmd__ = [
- "添加权限 [at] [权限]",
- "删除权限 [at]",
- "开启/关闭广播通知 [group]",
- "查看所有好友/查看所有群组",
- "退群 [group]",
- "更新群信息",
- "更新好友信息",
- "清理临时数据",
- "重载插件配置"
-]
-__plugin_version__ = 0.1
-__plugin_author__ = "HibiKier"
-
-
-super_cmd = on_command(
- "添加管理",
- aliases={"删除管理", "添加权限", "删除权限"},
- rule=to_me(),
- priority=1,
- permission=SUPERUSER,
- block=True,
-)
-oc_gb = on_command(
- "开启广播通知",
- aliases={"关闭广播通知"},
- rule=to_me(),
- permission=SUPERUSER,
- priority=1,
- block=True,
-)
-cls_group = on_command(
- "查看所有群组", rule=to_me(), permission=SUPERUSER, priority=1, block=True
-)
-cls_friend = on_command(
- "查看所有好友", rule=to_me(), permission=SUPERUSER, priority=1, block=True
-)
-del_group = on_command("退群", rule=to_me(), permission=SUPERUSER, priority=1, block=True)
-update_group_info = on_command(
- "更新群信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True
-)
-update_friend_info = on_command(
- "更新好友信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True
-)
-clear_data = on_command(
- "清理临时数据", rule=to_me(), permission=SUPERUSER, priority=1, block=True
-)
-reload_plugins_manager = on_command('重载插件配置', rule=to_me(), permission=SUPERUSER, priority=1, block=True)
-
-
-@super_cmd.handle()
-async def _(bot: Bot, event: MessageEvent, state: T_State):
- try:
- args = get_message_text(event.json()).strip().split(" ")
- qq = get_message_at(event.json())
- flag = -1
- if not qq:
- if len(args) > 2:
- if is_number(args[0]) and is_number(args[1]) and is_number(args[2]):
- qq = int(args[0])
- group_id = int(args[1])
- level = int(args[2])
- flag = 1
- else:
- await super_cmd.finish("所有参数必须是数字!", at_sender=True)
- else:
- await super_cmd.finish(
- "权限参数不完全\n\t格式:添加/删除权限 [at] [level]"
- "\n\t格式:添加/删除权限 [qq] [group] [level]",
- at_sender=True,
- )
- else:
- qq = int(qq[0])
- group_id = event.group_id
- flag = 2
- if is_number(args[0]):
- level = int(args[0])
- else:
- await super_cmd.finish("权限等级必须是数字!", at_sender=True)
- if state["_prefix"]["raw_command"][:2] == "添加":
- if await LevelUser.set_level(qq, group_id, level, 1):
- result = "添加管理成功, 权限: " + str(level)
- else:
- result = "管理已存在, 更新权限: " + str(level)
- else:
- if await LevelUser.delete_level(qq, event.group_id):
- result = "删除管理成功!"
- else:
- result = "该账号无管理权限!"
- if flag == 2:
- await super_cmd.send(result)
- elif flag == 1:
- await bot.send_group_msg(
- group_id=group_id,
- message=Message(f"{at(qq)}管理员修改了你的权限" f"\n--------\n你当前的权限等级:{level}"),
- )
- await super_cmd.send("修改成功")
- except Exception as e:
- await super_cmd.send("执行指令失败!")
- logger.error(f"执行指令失败 e{e}")
-
-
-@oc_gb.handle()
-async def _(bot: Bot, event: MessageEvent, state: T_State):
- group = get_message_text(event.json())
- if group:
- if is_number(group):
- group = int(group)
- for g in await bot.get_group_list():
- if g["group_id"] == group:
- break
- else:
- await oc_gb.finish("没有加入这个群...", at_sender=True)
- # try:
- if state["_prefix"]["raw_command"] == "开启广播通知":
- 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:
- logger.info(f"USER {event.user_id} 关闭了 GROUP {group} 的广播")
- await oc_gb.finish(await group_manager.close_group_task(group, "broadcast"), at_sender=True)
- # except Exception as e:
- # await oc_gb.finish(f'关闭 {group} 的广播失败', at_sender=True)
- else:
- await oc_gb.finish("请输入正确的群号", at_sender=True)
- else:
- await oc_gb.finish("请输入要关闭广播的群号", at_sender=True)
-
-
-@del_group.handle()
-async def _(bot: Bot, event: MessageEvent, state: T_State):
- group = get_message_text(event.json())
- if group:
- if is_number(group):
- try:
- await bot.set_group_leave(group_id=int(group))
- logger.info(f"退出群聊 {group} 成功")
- await del_group.finish(f"退出群聊 {group} 成功", at_sender=True)
- except Exception as e:
- logger.info(f"退出群聊 {group} 失败 e:{e}")
- else:
- await del_group.finish(f"请输入正确的群号", at_sender=True)
- else:
- await del_group.finish(f"请输入群号", at_sender=True)
-
-
-@cls_group.handle()
-async def _(bot: Bot, event: MessageEvent, state: T_State):
- gl = await bot.get_group_list(self_id=int(bot.self_id))
- 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,
- )
-
-
-@cls_friend.handle()
-async def _(bot: Bot, event: MessageEvent, state: T_State):
- gl = await bot.get_friend_list(self_id=int(bot.self_id))
- 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,
- )
-
-
-@update_group_info.handle()
-async def _(bot: Bot, event: MessageEvent, state: T_State):
- bot = get_bot()
- gl = await bot.get_group_list()
- gl = [g["group_id"] for g in gl]
- num = 0
- rst = ""
- for g in gl:
- group_info = await bot.get_group_info(group_id=g)
- if await GroupInfo.add_group_info(
- group_info["group_id"],
- group_info["group_name"],
- group_info["max_member_count"],
- group_info["member_count"],
- ):
- num += 1
- logger.info(f"自动更新群组 {g} 信息成功")
- else:
- logger.info(f"自动更新群组 {g} 信息失败")
- rst += f"{g} 更新失败\n"
- await update_group_info.send(f"成功更新了 {num} 个群的信息\n{rst[:-1]}")
-
-
-@update_friend_info.handle()
-async def _(bot: Bot, event: MessageEvent, state: T_State):
- num = 0
- rst = ""
- fl = await get_bot().get_friend_list()
- for f in fl:
- if await FriendUser.add_friend_info(f["user_id"], f["nickname"]):
- logger.info(f'自动更新好友 {f["user_id"]} 信息成功')
- num += 1
- else:
- logger.warning(f'自动更新好友 {f["user_id"]} 信息失败')
- rst += f'{f["user_id"]} 更新失败\n'
- await update_friend_info.send(f"成功更新了 {num} 个好友的信息\n{rst[:-1]}")
-
-
-@clear_data.handle()
-async def _(bot: Bot, event: MessageEvent, state: T_State):
- 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))
-
-
-@reload_plugins_manager.handle()
-async def _(bot: Bot, event: MessageEvent, state: T_State):
- plugins2settings_manager.reload()
- plugins2cd_manager.reload()
- plugins2block_manager.reload()
- try:
- (Path(IMAGE_PATH) / "help.png").unlink()
- except FileNotFoundError:
- pass
- await reload_plugins_manager.send(f'重载插件配置完成...\n'
- f'已加载 {len(plugins2settings_manager.get_data())} 个非限制插件\n'
- f'已加载 {len(plugins2cd_manager.get_data())} 个Cd限制\n'
- f'已加载 {len(plugins2block_manager.get_data())} 个Block限制')
-
-
-def _clear_data() -> float:
- size = 0
- for dir_name in ["temp", "rar", "r18_rar"]:
- dir_name = f"{IMAGE_PATH}/{dir_name}"
- if os.path.exists(dir_name):
- for file in os.listdir(dir_name):
- try:
- file_size = os.path.getsize(os.path.join(dir_name, file))
- os.remove(os.path.join(dir_name, file))
- except Exception as e:
- logger.error(f"清理临时数据错误...e:{e}")
- file_size = 0
- size += file_size
- return float(size)
-
-
-@scheduler.scheduled_job(
- "cron",
- hour=1,
- minute=1,
-)
-async def _():
- size = await asyncio.get_event_loop().run_in_executor(None, _clear_data)
- logger.info("自动清理临时数据完成," + "共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024))
diff --git a/plugins/update_gocqhttp/__init__.py b/plugins/update_gocqhttp/__init__.py
index 6a088d3b..d910e596 100644
--- a/plugins/update_gocqhttp/__init__.py
+++ b/plugins/update_gocqhttp/__init__.py
@@ -6,7 +6,7 @@ import os
from services.log import logger
from utils.utils import scheduler, get_bot
from nonebot.permission import SUPERUSER
-from configs.config import UPDATE_GOCQ_GROUP
+from configs.config import Config
from pathlib import Path
@@ -20,7 +20,13 @@ usage:
__plugin_cmd__ = ["更新gocq"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
-
+__plugin_configs__ = {
+ "UPDATE_GOCQ_GROUP": {
+ "value": [],
+ "help": "需要为哪些群更新最新版gocq吗?(上传最新版gocq)示例:[434995955, 239483248]",
+ "default_value": [],
+ }
+}
path = str((Path() / "resources" / "gocqhttp_file").absolute()) + "/"
@@ -30,7 +36,7 @@ lasted_gocqhttp = on_command("更新gocq", permission=SUPERUSER, priority=5, blo
@lasted_gocqhttp.handle()
async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
# try:
- if event.group_id in UPDATE_GOCQ_GROUP:
+ if event.group_id in Config.get_config("update_gocqhttp", "UPDATE_GOCQ_GROUP"):
await lasted_gocqhttp.send("检测中...")
info = await download_gocq_lasted(path)
if info == "gocqhttp没有更新!":
@@ -51,14 +57,14 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State):
minute=1,
)
async def _():
- if UPDATE_GOCQ_GROUP:
+ if Config.get_config("update_gocqhttp", "UPDATE_GOCQ_GROUP"):
bot = get_bot()
try:
info = await download_gocq_lasted(path)
if info == "gocqhttp没有更新!":
logger.info("gocqhttp没有更新!")
return
- for group in UPDATE_GOCQ_GROUP:
+ for group in Config.get_config("update_gocqhttp", "UPDATE_GOCQ_GROUP"):
for file in os.listdir(path):
await upload_gocq_lasted(path, file, group)
await bot.send_group_msg(
diff --git a/plugins/weather/__init__.py b/plugins/weather/__init__.py
index 075d9df6..e65b1f63 100644
--- a/plugins/weather/__init__.py
+++ b/plugins/weather/__init__.py
@@ -1,5 +1,5 @@
from nonebot import on_regex
-from .data_source import get_weather_of_city, update_city, get_city_list
+from .data_source import get_weather_of_city, get_city_list
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from jieba import posseg
from services.log import logger
@@ -28,7 +28,7 @@ __plugin_settings__ = {
}
-weather = on_regex(r".*?(.*)市?的?天气.*?", priority=5, block=True)
+weather = on_regex(r".{0,10}市?的?天气.{0,10}", priority=5, block=True)
@weather.handle()
diff --git a/plugins/weather/data_source.py b/plugins/weather/data_source.py
index 0fd8bf27..a787cf67 100644
--- a/plugins/weather/data_source.py
+++ b/plugins/weather/data_source.py
@@ -1,9 +1,7 @@
-from services.log import logger
from utils.message_builder import image
from utils.user_agent import get_user_agent
from configs.path_config import TEXT_PATH
from configs.config import NICKNAME
-from asyncio.exceptions import TimeoutError
from typing import List
from nonebot import Driver
from pathlib import Path
@@ -23,7 +21,7 @@ async def get_weather_of_city(city: str) -> str:
if code == 999:
return "不要查一个省份的天气啊,很累人的!"
elif code == 998:
- return f"{NICKNAME}只可以查询国内城市的天气喔..."
+ return f"{NICKNAME}没查到!!试试查火星的天气?"
else:
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(
@@ -32,7 +30,7 @@ async def get_weather_of_city(city: str) -> str:
data_json = json.loads(await res.text(encoding="utf8"))
if "desc" in data_json:
if data_json["desc"] == "invilad-citykey":
- return f"你为啥不查火星的天气呢?{NICKNAME}只支持国内天气查询!!" + image(
+ return f"{NICKNAME}没查到!!试试查火星的天气?" + image(
"shengqi", "zhenxun"
)
elif data_json["desc"] == "OK":
@@ -48,34 +46,9 @@ async def get_weather_of_city(city: str) -> str:
return "好像出错了?"
-# 更新城市
-@driver.on_startup
-async def update_city():
- global data
- try:
- async with aiohttp.ClientSession(headers=get_user_agent()) as session:
- async with session.get(
- "http://www.weather.com.cn/data/city3jdata/china.html", timeout=5
- ) as res:
- provinces_data = json.loads(await res.text(encoding="utf8"))
- for province in provinces_data.keys():
- data[provinces_data[province]] = []
- async with session.get(
- f"http://www.weather.com.cn/data/city3jdata/provshi/{province}.html",
- timeout=5,
- ) as res:
- city_data = json.loads(await res.text(encoding="utf8"))
- for city in city_data.keys():
- data[provinces_data[province]].append(city_data[city])
- with open(china_city, "w", encoding="utf8") as f:
- json.dump(data, f, indent=4, ensure_ascii=False)
- logger.info("自动更新城市列表完成.....")
- except TimeoutError:
- logger.info("自动更新城市列表超时.....")
-
-
# 城市是否存在或是否是省份
def _check_exists_city(city: str) -> int:
+ global data
city = city if city[-1] != "市" else city[:-1]
for province in data.keys():
for city_ in data[province]:
@@ -99,4 +72,5 @@ def get_city_list() -> List[str]:
for p in data.keys():
for c in data[p]:
city_list.append(c)
+ city_list.append(p)
return city_list
diff --git a/plugins/what_anime/__init__.py b/plugins/what_anime/__init__.py
index b3f09e84..c4c9006d 100644
--- a/plugins/what_anime/__init__.py
+++ b/plugins/what_anime/__init__.py
@@ -15,6 +15,7 @@ usage:
""".strip()
__plugin_des__ = "以图识番"
__plugin_cmd__ = ["识番 [图片]"]
+__plugin_type__ = ("一些工具",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
diff --git a/plugins/white2black_img.py b/plugins/white2black_img.py
index 3519948b..2d5e8e5e 100644
--- a/plugins/white2black_img.py
+++ b/plugins/white2black_img.py
@@ -1,7 +1,7 @@
from nonebot.typing import T_State
from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent
from nonebot import on_command
-from utils.utils import get_message_imgs, get_local_proxy, get_message_text, is_Chinese
+from utils.utils import get_message_imgs, get_local_proxy, get_message_text, is_chinese
from utils.message_builder import image
import aiohttp
import aiofiles
@@ -134,11 +134,11 @@ async def get_translate(msg: str) -> str:
def formalization_msg(msg: str) -> str:
rst = ""
for i in range(len(msg)):
- if is_Chinese(msg[i]):
+ if is_chinese(msg[i]):
rst += msg[i] + " "
else:
rst += msg[i]
- if i + 1 < len(msg) and is_Chinese(msg[i + 1]) and msg[i].isalpha():
+ if i + 1 < len(msg) and is_chinese(msg[i + 1]) and msg[i].isalpha():
rst += " "
return rst
diff --git a/plugins/yiqing/__init__.py b/plugins/yiqing/__init__.py
index 760babb3..8c8926fe 100644
--- a/plugins/yiqing/__init__.py
+++ b/plugins/yiqing/__init__.py
@@ -1,9 +1,10 @@
from nonebot import on_command
-from .data_source import get_yiqing_data
+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 configs.config import NICKNAME
__zx_plugin_name__ = "疫情查询"
@@ -13,7 +14,7 @@ usage:
指令:
疫情 中国
疫情 [省份/城市]
- * 当省份与城市重名时,可在后添加 “市” *
+ * 当省份与城市重名时,可在后添加 "市" 或 "省" *
示例:疫情 吉林 <- [省]
示例:疫情 吉林市 <- [市]
""".strip()
@@ -36,17 +37,21 @@ yiqing = on_command("疫情", aliases={"查询疫情", "疫情查询"}, priority
@yiqing.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State):
msg = get_message_text(event.json())
+ city_and_province_list = get_city_and_province_list()
if msg:
- result = await get_yiqing_data(msg)
- if result:
- await yiqing.send(result)
- logger.info(
- f"(USER {event.user_id}, GROUP "
- f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询疫情: {msg}"
- )
+ if msg in city_and_province_list or msg[:-1] in city_and_province_list:
+ result = await get_yiqing_data(msg)
+ if result:
+ await yiqing.send(result)
+ logger.info(
+ f"(USER {event.user_id}, GROUP "
+ f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询疫情: {msg}"
+ )
+ else:
+ await yiqing.send("查询失败!!!!", at_sender=True)
+ logger.info(
+ f"(USER {event.user_id}, GROUP "
+ f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询疫情失败"
+ )
else:
- await yiqing.send("查询失败!!!!", at_sender=True)
- logger.info(
- f"(USER {event.user_id}, GROUP "
- f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 查询疫情失败"
- )
+ await yiqing.send(f"{NICKNAME}只支持国内的疫情查询喔...")
diff --git a/plugins/yiqing/data_source.py b/plugins/yiqing/data_source.py
index ebb9a0b5..f56c638e 100644
--- a/plugins/yiqing/data_source.py
+++ b/plugins/yiqing/data_source.py
@@ -1,6 +1,5 @@
from utils.user_agent import get_user_agent
from configs.path_config import TEXT_PATH
-from configs.config import NICKNAME
from typing import List
from pathlib import Path
import ujson as json
@@ -22,7 +21,7 @@ async def get_yiqing_data(area: str):
if area == "中国":
province = area
province_type = ""
- elif area in data.keys() and area[-1] != "市":
+ elif area[-1] == '省' or (area in data.keys() and area[-1] != "市"):
province = area if area[-1] != "省" else area[:-1]
if len(data[province]) == 1:
province_type = "市"
@@ -33,8 +32,6 @@ async def get_yiqing_data(area: str):
if area in data[p]:
province = p
city = area
- if not province and not city:
- return f"{NICKNAME}只支持国内的疫情查询喔..."
async with aiohttp.ClientSession(headers=get_user_agent()) as session:
async with session.get(url, timeout=7) as response:
epidemic_data = json.loads((await response.json())["data"])
@@ -77,7 +74,7 @@ async def get_yiqing_data(area: str):
)
-def get_city_list() -> List[str]:
+def get_city_and_province_list() -> List[str]:
global data
if not data:
try:
@@ -85,8 +82,9 @@ def get_city_list() -> List[str]:
data = json.load(f)
except FileNotFoundError:
data = {}
- city_list = []
+ city_list = ["中国"]
for p in data.keys():
for c in data[p]:
city_list.append(c)
+ city_list.append(p)
return city_list
diff --git a/resources/img/background/check/0.jpg b/resources/img/background/check/0.jpg
new file mode 100644
index 00000000..00785805
Binary files /dev/null and b/resources/img/background/check/0.jpg differ
diff --git a/services/__init__.py b/services/__init__.py
index 15a26945..aae2c093 100644
--- a/services/__init__.py
+++ b/services/__init__.py
@@ -1,3 +1,2 @@
from .db_context import *
from .log import *
-from .service_config import *
\ No newline at end of file
diff --git a/services/db_context.py b/services/db_context.py
index 3549ace6..0911a4bb 100644
--- a/services/db_context.py
+++ b/services/db_context.py
@@ -2,7 +2,6 @@
from gino import Gino
from .log import logger
from configs.config import bind, sql_name, user, password, address, port, database
-from .service_config import DATABASE_URI
# 全局数据库连接对象
@@ -10,7 +9,7 @@ db = Gino()
async def init():
- i_bind = DATABASE_URI if DATABASE_URI else bind
+ i_bind = bind
if not i_bind:
i_bind = f"{sql_name}://{user}:{password}@{address}:{port}/{database}"
try:
diff --git a/services/service_config.py b/services/service_config.py
deleted file mode 100644
index 2d89d872..00000000
--- a/services/service_config.py
+++ /dev/null
@@ -1,11 +0,0 @@
-import os
-
-DATABASE_URI = os.environ.get('DATABASE_URI')
-
-TL_M_KEY = os.environ.get('TL_KEY')
-
-SYSTEM_M_PROXY = os.environ.get('SYSTEM_PROXY')
-
-ALAPI_M_TOKEN = os.environ.get('ALAPI_TOKEN')
-
-
diff --git a/update_info.json b/update_info.json
index 560ff4dd..394dbad2 100644
--- a/update_info.json
+++ b/update_info.json
@@ -5,8 +5,8 @@
"models",
"services",
"utils",
- "resources/ttf"
+ "bot.py"
],
- "add_file": ["resources/img/background"],
+ "add_file": ["basic_plugins", "resources/img/background/check"],
"delete_file": []
}
diff --git a/utils/data_utils.py b/utils/data_utils.py
index b3c8cfa5..cc4a7baf 100644
--- a/utils/data_utils.py
+++ b/utils/data_utils.py
@@ -1,31 +1,68 @@
from models.group_member_info import GroupInfoUser
-from typing import List
+from utils.image_utils import CreateMat
+from configs.path_config import IMAGE_PATH
+from typing import List, Union
+import asyncio
+import os
-async def init_rank(all_user_id: List[int], all_user_data: List[int], group_id: int) -> str:
+async def init_rank(
+ title: str, all_user_id: List[int], all_user_data: List[int], group_id: int, total_count: int = 10
+) -> CreateMat:
"""
说明:
初始化通用的数据排行榜
参数:
+ :param title: 排行榜标题
:param all_user_id: 所有用户的qq号
:param all_user_data: 所有用户需要排行的对应数据
:param group_id: 群号,用于从数据库中获取该用户在此群的昵称
+ :param total_count: 获取人数总数
"""
- rst = ''
- for i in range(len(all_user_id) if len(all_user_id) < 10 else 10):
+ _uname_lst = []
+ _num_lst = []
+ for i in range(len(all_user_id) if len(all_user_id) < total_count else total_count):
_max = max(all_user_data)
max_user_id = all_user_id[all_user_data.index(_max)]
all_user_id.remove(max_user_id)
all_user_data.remove(_max)
try:
- user_name = (await GroupInfoUser.get_member_info(max_user_id, group_id)).user_name
+ user_name = (
+ await GroupInfoUser.get_member_info(max_user_id, group_id)
+ ).user_name
except AttributeError:
- user_name = f'{max_user_id}'
- rst += f'{user_name}: {_max}\n'
- return rst[:-1]
-
-
-
-
+ user_name = f"{max_user_id}"
+ _uname_lst.append(user_name)
+ _num_lst.append(_max)
+ _uname_lst.reverse()
+ _num_lst.reverse()
+ return await asyncio.get_event_loop().run_in_executor(
+ None, _init_rank_graph, title, _uname_lst, _num_lst
+ )
+def _init_rank_graph(
+ title: str, _uname_lst: List[str], _num_lst: List[Union[int, float]]
+) -> CreateMat:
+ """
+ 生成排行榜统计图
+ :param title: 排行榜标题
+ :param _uname_lst: 用户名列表
+ :param _num_lst: 数值列表
+ """
+ image = CreateMat(
+ y=_num_lst,
+ y_name="* 可以在命令后添加数字来指定排行人数 至多 50 *",
+ mat_type="barh",
+ title=title,
+ x_index=_uname_lst,
+ display_num=True,
+ x_rotate=30,
+ background=[
+ f"{IMAGE_PATH}/background/create_mat/{x}"
+ for x in os.listdir(f"{IMAGE_PATH}/background/create_mat")
+ ],
+ bar_color=["*"],
+ )
+ image.gen_graph()
+ return image
diff --git a/utils/image_utils.py b/utils/image_utils.py
index fb4945eb..6db72d32 100644
--- a/utils/image_utils.py
+++ b/utils/image_utils.py
@@ -416,6 +416,7 @@ class CreateImg:
color = self.markImg.getpixel((i, k))
color = color[:-1] + (int(100 * alpha_ratio),)
self.markImg.putpixel((i, k), color)
+ self.draw = ImageDraw.Draw(self.markImg)
def pic2bs4(self) -> str:
"""
@@ -501,26 +502,38 @@ class CreateImg:
:param radii: 半径
"""
# 画圆(用于分离4个角)
- circle = Image.new('L', (radii * 2, radii * 2), 0)
+ circle = Image.new("L", (radii * 2, radii * 2), 0)
draw = ImageDraw.Draw(circle)
draw.ellipse((0, 0, radii * 2, radii * 2), fill=255)
self.markImg = self.markImg.convert("RGBA")
w, h = self.markImg.size
- alpha = Image.new('L', self.markImg.size, 255)
+ alpha = Image.new("L", self.markImg.size, 255)
alpha.paste(circle.crop((0, 0, radii, radii)), (0, 0))
alpha.paste(circle.crop((radii, 0, radii * 2, radii)), (w - radii, 0))
- alpha.paste(circle.crop((radii, radii, radii * 2, radii * 2)), (w - radii, h - radii))
+ alpha.paste(
+ circle.crop((radii, radii, radii * 2, radii * 2)), (w - radii, h - radii)
+ )
alpha.paste(circle.crop((0, radii, radii, radii * 2)), (0, h - radii))
self.markImg.putalpha(alpha)
- def rotate(self, angle: int):
+ def rotate(self, angle: int, expand: bool = False):
"""
说明:
旋转图片
参数:
:param angle: 角度
+ :param expand: 放大图片适应角度
"""
- self.markImg = self.markImg.rotate(angle)
+ self.markImg = self.markImg.rotate(angle, expand=expand)
+
+ def transpose(self, angle: int):
+ """
+ 说明:
+ 旋转图片(包括边框)
+ 参数:
+ :param angle: 角度
+ """
+ self.markImg.transpose(angle)
def filter(self, filter_: str, aud: int = None):
"""
@@ -529,21 +542,22 @@ class CreateImg:
:param aud: 利率
"""
_x = None
- if filter_ == 'GaussianBlur': # 高斯模糊
+ if filter_ == "GaussianBlur": # 高斯模糊
_x = ImageFilter.GaussianBlur
- elif filter_ == 'EDGE_ENHANCE': # 锐化效果
+ elif filter_ == "EDGE_ENHANCE": # 锐化效果
_x = ImageFilter.EDGE_ENHANCE
- elif filter_ == 'BLUR': # 模糊效果
+ elif filter_ == "BLUR": # 模糊效果
_x = ImageFilter.BLUR
- elif filter_ == 'CONTOUR': # 铅笔滤镜
+ elif filter_ == "CONTOUR": # 铅笔滤镜
_x = ImageFilter.CONTOUR
- elif filter_ == 'FIND_EDGES': # 边缘检测
+ elif filter_ == "FIND_EDGES": # 边缘检测
_x = ImageFilter.FIND_EDGES
if _x:
if aud:
self.markImg = self.markImg.filter(_x(aud))
else:
self.markImg = self.markImg.filter(_x)
+ self.draw = ImageDraw.Draw(self.markImg)
#
def getchannel(self, type_):
@@ -565,9 +579,11 @@ class CreateMat:
y_name: Optional[str] = None,
x_index: List[Union[str, int, float]] = None,
y_index: List[Union[str, int, float]] = None,
+ x_rotate: int = 0,
title: Optional[str] = None,
size: Tuple[int, int] = (1000, 1000),
- font_size: int = 20,
+ font: str = "msyh.ttf",
+ font_size: Optional[int] = None,
display_num: bool = False,
is_grid: bool = False,
background: Optional[List[str]] = None,
@@ -584,8 +600,10 @@ class CreateMat:
:param y_name: 纵坐标名称
:param x_index: 横坐标值
:param y_index: 纵坐标值
+ :param x_rotate: 横坐标旋转角度
:param title: 标题
:param size: 图像大小,建议默认
+ :param font: 字体
:param font_size: 字体大小,建议默认
:param display_num: 是否显示数值
:param is_grid: 是否添加栅格
@@ -603,8 +621,9 @@ class CreateMat:
self.y_name = y_name
self.x_index = x_index
self.y_index = y_index
+ self.x_rotate = x_rotate
self.title = title
- self.font_size = font_size
+ self.font = font
self.display_num = display_num
self.is_grid = is_grid
self.background = background
@@ -616,6 +635,10 @@ class CreateMat:
self.line_length = 760
self._deviation = 0.905
self._color = {}
+ if not font_size:
+ self.font_size = int(25 * (1 - len(x_index) / 100))
+ else:
+ self.font_size = font_size
if self.bar_color == ["*"]:
self.bar_color = [
"#FF0000",
@@ -629,17 +652,15 @@ class CreateMat:
if not x_index:
raise ValueError("缺少 x_index [横坐标值]...")
self._x_interval = int((self.line_length - 70) / len(x_index))
- self._bar_width = int(
- (self.line_length - (len(x_index) * (10 if len(x_index) >= 18 else 25)))
- / len(x_index)
- )
+ self._bar_width = int(30 * (1 - (len(x_index) + 10) / 100))
# 没有 y_index 时自动生成
if not y_index:
_y_index = []
- _max_value = max(y)
+ _max_value = int(max(y))
_max_value = ceil(
_max_value / eval("1" + "0" * (len(str(_max_value)) - 1))
) * eval("1" + "0" * (len(str(_max_value)) - 1))
+ _max_value = _max_value if _max_value >= 10 else 100
_step = int(_max_value / 10)
for i in range(_step, _max_value + _step, _step):
_y_index.append(i)
@@ -792,9 +813,9 @@ class CreateMat:
self.markImg.text(
(
current_w - w,
- current_h - int(y[i] * self._p * self._deviation) - 25,
+ current_h - int(y[i] * self._p * self._deviation) - 25 - 5,
),
- str(y[i]),
+ f"{y[i]:.2f}" if isinstance(y[i], float) else f"{y[i]}",
)
self.markImg.paste(
_black_point,
@@ -839,15 +860,17 @@ class CreateMat:
current_w = self.padding_w + _interval
current_h = self.padding_h + self.line_length
for i in range(len(y)):
+ # 画出显示数字
if display_num:
+ # 横柱状图
if is_barh:
font_h = self.markImg.getsize(str(y[i]))[1]
self.markImg.text(
(
- self.padding_w + int(y[i] * self._p * self._deviation) + 2,
- current_h - int(font_h / 2),
+ self.padding_w + int(y[i] * self._p * self._deviation) + 2 + 5,
+ current_h - int(font_h / 2) - 1,
),
- str(y[i]),
+ f"{y[i]:.2f}" if isinstance(y[i], float) else f"{y[i]}",
)
else:
w = int(self.markImg.getsize(str(y[i]))[0] / 2)
@@ -856,7 +879,7 @@ class CreateMat:
current_w - w,
current_h - int(y[i] * self._p * self._deviation) - 25,
),
- str(y[i]),
+ f"{y[i]:.2f}" if isinstance(y[i], float) else f"{y[i]}",
)
if i != len(y):
bar_color = random.choice(self.bar_color)
@@ -914,7 +937,7 @@ class CreateMat:
padding_h = self.padding_h
line_length = self.line_length
background = random.choice(self.background) if self.background else None
- A = CreateImg(self.w, self.h, font_size=font_size, background=background)
+ A = CreateImg(self.w, self.h, font_size=font_size, font=self.font, background=background)
if background:
_tmp = CreateImg(self.w, self.h)
_tmp.transparent(2)
@@ -927,6 +950,7 @@ class CreateMat:
color=(255, 255, 255, 0),
font_size=35,
font_color=self._color.get("title"),
+ font=self.font
)
A.paste(title, (0, 25), True, "by_width")
A.line(
@@ -956,8 +980,9 @@ class CreateMat:
y_index = tmp
_interval = self._y_interval
current_w = padding_w + _interval
- _text_font = CreateImg(0, 0, font_size=self.font_size)
+ _text_font = CreateImg(0, 0, font_size=self.font_size, font=self.font)
_grid = self.line_length if is_grid else 10
+ x_rotate_height = 0
for _x in x_index:
_p = CreateImg(1, _grid, color="#a9a9a9")
A.paste(_p, (current_w, padding_h + line_length - _grid))
@@ -968,15 +993,18 @@ class CreateMat:
plain_text=f"{_x}",
font_size=self.font_size,
color=(255, 255, 255, 0),
+ font=self.font
)
+ text.rotate(self.x_rotate, True)
A.paste(text, (current_w - w, padding_h + line_length + 10), alpha=True)
current_w += _interval
+ x_rotate_height = text.h
_interval = self._x_interval if self.mat_type == "barh" else self._y_interval
current_h = padding_h + line_length - _interval
- _text_font = CreateImg(0, 0, font_size=self.font_size)
+ _text_font = CreateImg(0, 0, font_size=self.font_size, font=self.font)
for _y in y_index:
_p = CreateImg(_grid, 1, color="#a9a9a9")
- A.paste(_p, (padding_w, current_h))
+ A.paste(_p, (padding_w + 2, current_h))
w, h = _text_font.getsize(f"{_y}")
h = int(h / 2)
text = CreateImg(
@@ -985,26 +1013,30 @@ class CreateMat:
plain_text=f"{_y}",
font_size=self.font_size,
color=(255, 255, 255, 0),
+ font=self.font
)
- while text.size[0] > self.padding_w - 10:
+ idx = 0
+ while text.size[0] > self.padding_w - 10 and idx < 3:
text = CreateImg(
0,
0,
plain_text=f"{_y}",
- font_size=int(self.font_size * 0.9),
+ font_size=int(self.font_size * 0.75),
color=(255, 255, 255, 0),
+ font=self.font
)
w, _ = text.getsize(f"{_y}")
+ idx += 1
A.paste(text, (padding_w - w - 10, current_h - h), alpha=True)
current_h -= _interval
if x_name:
A.text((int(padding_w / 2), int(padding_w / 2)), x_name)
if y_name:
A.text(
- (int(padding_w + line_length + 50), int(padding_h + line_length + 50)),
+ (int(padding_w + line_length + 50 - A.getsize(y_name)[0]),
+ int(padding_h + line_length + 50 + x_rotate_height)),
y_name,
)
- # A.show()
return A
diff --git a/utils/manager/__init__.py b/utils/manager/__init__.py
index ebf4f88f..ce83637b 100644
--- a/utils/manager/__init__.py
+++ b/utils/manager/__init__.py
@@ -1,11 +1,17 @@
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
from .plugins2block_manager import Plugins2blockManager
+from .plugins2count_manager import Plugins2countManager
from .plugins2settings_manager import Plugins2settingsManager
+from .plugins_manager import PluginsManager
+from .resources_manager import ResourcesManager
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
@@ -19,6 +25,11 @@ group_manager: Optional[GroupManager] = GroupManager(
# 撤回消息管理
withdraw_message_manager: Optional[WithdrawMessageManager] = WithdrawMessageManager()
+# 插件管理
+plugins_manager: Optional[PluginsManager] = PluginsManager(
+ Path(DATA_PATH) / "manager" / "plugins_manager.json"
+)
+
# 插件基本设置管理
plugins2settings_manager: Optional[Plugins2settingsManager] = Plugins2settingsManager(
Path(DATA_PATH) / "configs" / "plugins2settings.yaml"
@@ -34,6 +45,27 @@ plugins2block_manager: Optional[Plugins2blockManager] = Plugins2blockManager(
Path(DATA_PATH) / "configs" / "plugins2block.yaml"
)
+# 插件命令 每次次数限制 管理
+plugins2count_manager: Optional[Plugins2countManager] = Plugins2countManager(
+ Path(DATA_PATH) / "configs" / "plugins2count.yaml"
+)
+
+# 资源管理
+resources_manager: Optional[ResourcesManager] = ResourcesManager(
+ Path(DATA_PATH) / "manager" / "resources_manager.json"
+)
+
+# 插件加载容忍管理
+none_plugin_count_manager: Optional[NonePluginCountManager] = NonePluginCountManager(
+ Path(DATA_PATH) / "manager" / "none_plugin_count_manager.json"
+)
+
+# 好友请求/群聊邀请 管理
+requests_manager: Optional[RequestManager] = RequestManager(
+ Path(DATA_PATH) / "manager" / "requests_manager.json"
+)
+
+
# 管理员命令管理器
admin_manager = AdminManager()
diff --git a/utils/manager/admin_manager.py b/utils/manager/admin_manager.py
index c050ad16..c0a8380e 100644
--- a/utils/manager/admin_manager.py
+++ b/utils/manager/admin_manager.py
@@ -1,8 +1,5 @@
-from typing import Optional, Dict
from .data_class import StaticData
-from utils.utils import FreqLimiter
-from services.log import logger
-from pathlib import Path
+from typing import List, Optional
class AdminManager(StaticData):
@@ -13,15 +10,27 @@ class AdminManager(StaticData):
def __init__(self):
super().__init__(None)
- def add_admin_command(self, plugin: str, level: int):
+ def add_admin_plugin_settings(self, plugin: str, cmd: List[str], level: int):
"""
添加一个管理员命令
+ :param plugin: 模块
+ :param cmd: 别名
+ :param level: 等级
+ """
+ self._data[plugin] = {
+ "level": level,
+ "cmd": cmd,
+ }
+
+ def set_admin_level(self, plugin: str, level: int):
+ """
+ 设置管理员命令等级
:param plugin: 模块名
:param level: 权限等级
"""
- self._data[plugin] = level
+ self._data[plugin]["level"] = level
- def remove_admin_command(self, plugin: str):
+ def remove_admin_plugin_settings(self, plugin: str):
"""
删除一个管理员命令
:param plugin: 模块名
@@ -36,7 +45,7 @@ class AdminManager(StaticData):
:param level: 权限等级
"""
if plugin in self._data.keys():
- return level >= self._data[plugin]
+ return level >= self._data[plugin]["level"]
return True
def get_plugin_level(self, plugin: str) -> int:
@@ -45,7 +54,15 @@ class AdminManager(StaticData):
:param plugin: 模块名
"""
if plugin in self._data.keys():
- return self._data[plugin]
+ return self._data[plugin]["level"]
return 0
-
+ def get_plugin_module(self, cmd: str) -> Optional[str]:
+ """
+ 根据 cmd 获取功能 module
+ :param cmd: 命令
+ """
+ for key in self._data.keys():
+ if self._data[key].get("cmd") and cmd in self._data[key]["cmd"]:
+ return key
+ return None
diff --git a/utils/manager/configs_manager.py b/utils/manager/configs_manager.py
new file mode 100644
index 00000000..9736f21c
--- /dev/null
+++ b/utils/manager/configs_manager.py
@@ -0,0 +1,65 @@
+# from typing import Optional, Any
+# from .data_class import StaticData
+# from pathlib import Path
+# from ruamel.yaml import YAML
+#
+# yaml = YAML(typ="safe")
+#
+#
+# class ConfigsManager(StaticData):
+# """
+# 插件配置 与 资源 管理器
+# """
+#
+# def __init__(self, file: Path):
+# self.file = file
+# super().__init__(file)
+# self._resource_data = {}
+#
+# def add_plugin_config(
+# self,
+# module: str,
+# key: str,
+# value: str,
+# help_: Optional[str] = None,
+# default_value: Optional[str] = None,
+# ):
+# """
+# 为插件添加一个配置
+# :param module: 模块
+# :param key: 键
+# :param value: 值
+# :param help_: 配置注解
+# :param default_value: 默认值
+# """
+# if self._data.get(module) is None:
+# self._data[module] = {}
+# self._data[module][key] = {
+# "value": value,
+# "help": help_,
+# "default_value": default_value,
+# }
+#
+# def remove_plugin_config(self, module: str):
+# """
+# 为插件删除一个配置
+# :param module: 模块名
+# """
+# if module in self._data.keys():
+# del self._data[module]
+#
+# def get_config(self, module: str, key: str) -> Optional[Any]:
+# """
+# 获取指定配置值
+# :param module: 模块名
+# :param key: 配置名称
+# """
+# if module in self._data.keys():
+# if self._data[module].get(key):
+# if self._data[module][key]["value"] is None:
+# return self._data[module][key]["default_value"]
+# return self._data[module][key]["value"]
+# return None
+#
+#
+#
diff --git a/utils/manager/data_class.py b/utils/manager/data_class.py
index 4c55a234..6507be8f 100644
--- a/utils/manager/data_class.py
+++ b/utils/manager/data_class.py
@@ -12,15 +12,25 @@ class StaticData:
"""
def __init__(self, file: Optional[Path]):
- self._data = {}
+ self._data: dict = {}
if file:
file.parent.mkdir(exist_ok=True, parents=True)
self.file = file
if file.exists():
- self._data: dict = json.load(open(file, "r", encoding="utf8"))
+ with open(file, "r", encoding="utf8") as f:
+ if file.name.endswith("json"):
+ self._data: dict = json.load(f)
+ elif file.name.endswith("yaml"):
+ self._data = yaml.load(f)
def set(self, key, value):
self._data[key] = value
+ self.save()
+
+ def set_module_data(self, module, key, value):
+ if module in self._data.keys():
+ self._data[module][key] = value
+ self.save()
def get(self, key):
return self._data.get(key)
@@ -31,20 +41,24 @@ class StaticData:
def delete(self, key):
if self._data.get(key) is not None:
del self._data[key]
+ self.save()
- def get_data(self):
+ def get_data(self) -> dict:
return self._data
def save(self, path: Union[str, Path] = None):
path = path if path else self.file
- with open(path, "w", encoding="utf8") as f:
- json.dump(self._data, f, ensure_ascii=False, indent=4)
+ if isinstance(path, str):
+ path = Path(path)
+ if path:
+ with open(path, "w", encoding="utf8") as f:
+ json.dump(self._data, f, ensure_ascii=False, indent=4)
def reload(self):
if self.file.exists():
- if self.file.name.endswith('json'):
+ if self.file.name.endswith("json"):
self._data: dict = json.load(open(self.file, "r", encoding="utf8"))
- elif self.file.name.endswith('yaml'):
+ elif self.file.name.endswith("yaml"):
self._data: dict = yaml.load(open(self.file, "r", encoding="utf8"))
def is_exists(self):
@@ -61,4 +75,3 @@ class StaticData:
def __getitem__(self, key):
return self._data[key]
-
diff --git a/utils/manager/group_manager.py b/utils/manager/group_manager.py
index f973b452..a0db6af0 100644
--- a/utils/manager/group_manager.py
+++ b/utils/manager/group_manager.py
@@ -1,4 +1,3 @@
-from configs.config import DEFAULT_GROUP_LEVEL
from typing import Optional, List, Union, Dict
from pathlib import Path
from .data_class import StaticData
@@ -15,33 +14,30 @@ class GroupManager(StaticData):
super().__init__(file)
if not self._data:
self._data = {
- "super": {"close_plugins": {}, "white_group_list": []},
+ "super": {"white_group_list": []},
"group_manager": {},
}
self._task = {}
- def block_plugin(
- self, plugin_cmd: str, group_id: Optional[int] = None, block_type: str = "all"
- ):
+ def block_plugin(self, module: str, group_id: int):
"""
说明:
锁定插件
参数:
- :param plugin_cmd: 功能模块名
+ :param module: 功能模块名
:param group_id: 群组,None时为超级用户禁用
- :param block_type: 限制类型
"""
- self._set_plugin_status(plugin_cmd, "block", group_id, block_type)
+ self._set_plugin_status(module, "block", group_id)
- def unblock_plugin(self, plugin_cmd: str, group_id: Optional[int] = None):
+ def unblock_plugin(self, module: str, group_id: int):
"""
说明:
解锁插件
参数:
- :param plugin_cmd: 功能模块名
+ :param module: 功能模块名
:param group_id: 群组
"""
- self._set_plugin_status(plugin_cmd, "unblock", group_id)
+ self._set_plugin_status(module, "unblock", group_id)
def set_group_level(self, group_id: int, level: int):
"""
@@ -57,49 +53,21 @@ class GroupManager(StaticData):
self._data["group_manager"][group_id]["level"] = level
self.save()
- def get_plugin_status(
- self, plugin_cmd: str, group_id: Optional[int] = None, block_type: str = "all"
- ) -> bool:
+ def get_plugin_status(self, module: str, group_id: int) -> bool:
"""
说明:
获取插件状态
参数:
- :param plugin_cmd: 功能模块名
+ :param module: 功能模块名
:param group_id: 群组
- :param block_type: 限制类型
"""
group_id = str(group_id) if group_id else group_id
- if group_id:
- if not self._data["group_manager"].get(group_id):
- self._init_group(group_id)
- return True
- if plugin_cmd in self._data["group_manager"][group_id]["close_plugins"]:
- return False
+ if not self._data["group_manager"].get(group_id):
+ self._init_group(group_id)
return True
- else:
- if plugin_cmd in self._data["super"]["close_plugins"]:
- if (
- self._data["super"]["close_plugins"][plugin_cmd] == "all"
- and block_type == "all"
- ):
- return False
- else:
- return (
- not self._data["super"]["close_plugins"][plugin_cmd]
- == block_type
- )
- return True
-
- def get_plugin_block_type(self, plugin_cmd: str) -> str:
- """
- 说明:
- 获取功能限制类型
- 参数:
- :param plugin_cmd: 模块名称
- """
- if plugin_cmd in self._data["super"]["close_plugins"]:
- return self._data["super"]["close_plugins"][plugin_cmd]
- return ""
+ if module in self._data["group_manager"][group_id]["close_plugins"]:
+ return False
+ return True
def get_group_level(self, group_id: int) -> int:
"""
@@ -149,6 +117,17 @@ class GroupManager(StaticData):
"""
return self._data["super"]["white_group_list"]
+ def delete_group(self, group_id: int):
+ """
+ 删除群配置
+ :param group_id: 群号
+ """
+ if group_id in self._data["group_manager"]:
+ del self._data["group_manager"][str(group_id)]
+ if group_id in self._data["super"]["white_group_list"]:
+ self._data["super"]["white_group_list"].remove(group_id)
+ self.save()
+
async def open_group_task(self, group_id: int, task: str):
"""
开启群被动技能
@@ -181,6 +160,9 @@ class GroupManager(StaticData):
return self._data["group_manager"][group_id]["group_task_status"][task]
def get_task_data(self) -> Dict[str, str]:
+ """
+ 获取所有被动任务
+ """
return self._task
async def group_task_status(self, group_id: int) -> str:
@@ -188,7 +170,7 @@ class GroupManager(StaticData):
查看群被全部动技能状态
:param group_id: 群号
"""
- x = '[群被动技能]:\n'
+ x = "[群被动技能]:\n"
group_id = str(group_id)
if not self._data["group_manager"][group_id].get("group_task_status"):
await self.init_group_task(group_id)
@@ -222,8 +204,8 @@ class GroupManager(StaticData):
if not self._task:
for matcher in get_matchers():
_plugin = nonebot.plugin.get_plugin(matcher.module)
- _module = _plugin.module
try:
+ _module = _plugin.module
plugin_task = _module.__getattribute__("__plugin_task__")
for key in plugin_task.keys():
self._task[key] = plugin_task[key]
@@ -240,18 +222,20 @@ class GroupManager(StaticData):
if not self._data["group_manager"].get(group_id):
self._init_group(group_id)
if not self._data["group_manager"][group_id].get("group_task_status"):
- self._data["group_manager"][group_id]['group_task_status'] = {}
+ self._data["group_manager"][group_id]["group_task_status"] = {}
for task in self._task:
if (
- self._data["group_manager"][group_id][
- "group_task_status"
- ].get(task)
+ self._data["group_manager"][group_id]["group_task_status"].get(
+ task
+ )
is None
):
self._data["group_manager"][group_id]["group_task_status"][
task
] = True
- for task in self._data["group_manager"][group_id]["group_task_status"]:
+ for task in list(
+ self._data["group_manager"][group_id]["group_task_status"]
+ ):
if task not in self._task:
del self._data["group_manager"][group_id]["group_task_status"][
task
@@ -260,48 +244,27 @@ class GroupManager(StaticData):
def _set_plugin_status(
self,
- plugin_cmd: str,
+ module: str,
status: str,
- group_id: Optional[str],
- block_type: str = "all",
+ group_id: int,
):
"""
说明:
设置功能开关状态
参数:
- :param plugin_cmd: 功能模块名
+ :param module: 功能模块名
:param status: 功能状态
:param group_id: 群组
- :param block_type: 限制类型
"""
group_id = str(group_id) if group_id else group_id
- if plugin_cmd:
- if group_id:
- if not self._data["group_manager"].get(group_id):
- self._init_group(group_id)
- if status == "block":
- if (
- plugin_cmd
- not in self._data["group_manager"][group_id]["close_plugins"]
- ):
- self._data["group_manager"][group_id]["close_plugins"].append(
- plugin_cmd
- )
- else:
- if plugin_cmd in self._data["group_manager"][group_id]["close_plugins"]:
- self._data["group_manager"][group_id]["close_plugins"].remove(
- plugin_cmd
- )
- else:
- if status == "block":
- if (
- plugin_cmd not in self._data["super"]["close_plugins"]
- or block_type != self._data["super"]["close_plugins"][plugin_cmd]
- ):
- self._data["super"]["close_plugins"][plugin_cmd] = block_type
- else:
- if plugin_cmd in self._data["super"]["close_plugins"]:
- del self._data["super"]["close_plugins"][plugin_cmd]
+ if not self._data["group_manager"].get(group_id):
+ self._init_group(group_id)
+ if status == "block":
+ if module not in self._data["group_manager"][group_id]["close_plugins"]:
+ self._data["group_manager"][group_id]["close_plugins"].append(module)
+ else:
+ if module in self._data["group_manager"][group_id]["close_plugins"]:
+ self._data["group_manager"][group_id]["close_plugins"].remove(module)
self.save()
def _init_group(self, group_id: str):
@@ -311,9 +274,22 @@ class GroupManager(StaticData):
参数:
:param group_id: 群号
"""
+ default_group_level = 5 # Config.get_config("group_manager")
+ if not default_group_level:
+ default_group_level = 5
if not self._data["group_manager"].get(group_id):
self._data["group_manager"][group_id] = {
- "level": DEFAULT_GROUP_LEVEL,
+ "level": default_group_level,
"close_plugins": [],
"group_task_status": {},
}
+
+ def get_super_old_data(self) -> Optional[dict]:
+ """
+ 获取旧数据,平时使用请不要调用
+ """
+ if self._data["super"].get("close_plugins"):
+ _x = self._data["super"].get("close_plugins")
+ del self._data["super"]["close_plugins"]
+ return _x
+ return None
diff --git a/utils/manager/none_plugin_count_manager.py b/utils/manager/none_plugin_count_manager.py
new file mode 100644
index 00000000..88f5260e
--- /dev/null
+++ b/utils/manager/none_plugin_count_manager.py
@@ -0,0 +1,51 @@
+from .data_class import StaticData
+from typing import Optional
+from pathlib import Path
+
+
+class NonePluginCountManager(StaticData):
+
+ """
+ 插件加载容忍管理器,当连续 max_count 次插件加载,视为删除插件,清楚数据
+ """
+
+ def __init__(self, file: Optional[Path], max_count: int = 5):
+ """
+ :param file: 存储路径
+ :param max_count: 容忍最大次数
+ """
+ super().__init__(file)
+ self._max_count = max_count
+
+ def add_count(self, module: str, count: int = 1):
+ """
+ 添加次数
+ :param module: 模块
+ :param count: 次数,无特殊情况均为 1
+ """
+ if module not in self._data.keys():
+ self._data[module] = count
+ else:
+ self._data[module] += count
+
+ def reset(self, module: str):
+ """
+ 重置次数
+ :param module: 模块
+ """
+ if module in self._data.keys():
+ self._data[module] = 0
+
+ def check(self, module: str):
+ """
+ 检查容忍次数是否到达最大值
+ :param module: 模块
+ """
+ if module in self._data.keys():
+ return self._data.keys() > self._max_count
+ return False
+
+
+
+
+
diff --git a/utils/manager/plugins2block_manager.py b/utils/manager/plugins2block_manager.py
index f97cbf1a..a30ff302 100644
--- a/utils/manager/plugins2block_manager.py
+++ b/utils/manager/plugins2block_manager.py
@@ -12,10 +12,18 @@ class Plugins2blockManager(StaticData):
"""
插件命令阻塞 管理器
"""
+
def __init__(self, file: Path):
self.file = file
super().__init__(None)
self._block_limiter: Dict[str, UserBlockLimiter] = {}
+ if file.exists():
+ with open(file, "r", encoding="utf8") as f:
+ self._data = yaml.load(f)
+ if "PluginBlockLimit" in self._data.keys():
+ self._data = (
+ self._data["PluginBlockLimit"] if self._data["PluginBlockLimit"] else {}
+ )
def add_block_limit(
self,
@@ -36,13 +44,13 @@ class Plugins2blockManager(StaticData):
:param data_dict: 封装好的字典数据
"""
if data_dict:
- status = data_dict.get('status')
- check_type = data_dict.get('check_type')
- limit_type = data_dict.get('limit_type')
- rst = data_dict.get('rst')
+ status = data_dict.get("status")
+ check_type = data_dict.get("check_type")
+ limit_type = data_dict.get("limit_type")
+ rst = data_dict.get("rst")
status = status if status is not None else True
- check_type = check_type if check_type else 'all'
- limit_type = limit_type if limit_type else 'user'
+ check_type = check_type if check_type else "all"
+ limit_type = limit_type if limit_type else "user"
if check_type not in ["all", "group", "private"]:
raise ValueError(
f"{plugin} 添加block限制错误,‘check_type‘ 必须为 'private'/'group'/'all'"
@@ -56,14 +64,6 @@ class Plugins2blockManager(StaticData):
"rst": rst,
}
- def remove_block_limit(self, plugin: str):
- """
- 删除一个插件 block 限制
- :param plugin: 插件模块名称
- """
- if self._data.get(plugin):
- del self._data[plugin]
-
def get_plugin_block_data(self, plugin: str) -> Optional[dict]:
"""
获取插件block数据
@@ -78,10 +78,7 @@ class Plugins2blockManager(StaticData):
检测插件是否有 block
:param plugin: 模块名
"""
- return (
- plugin in self._data.keys()
- and self._data[plugin]["status"]
- )
+ return plugin in self._data.keys() and self._data[plugin]["status"]
def check(self, id_: int, plugin: str) -> bool:
"""
@@ -119,7 +116,7 @@ class Plugins2blockManager(StaticData):
for plugin in self._data:
if self.check_plugin_block_status(plugin):
self._block_limiter[plugin] = UserBlockLimiter()
- logger.info(f'已成功加载 {len(self._block_limiter)} 个Block限制.')
+ logger.info(f"已成功加载 {len(self._block_limiter)} 个Block限制.")
def reload(self):
"""
@@ -128,5 +125,5 @@ class Plugins2blockManager(StaticData):
if self.file.exists():
with open(self.file, "r", encoding="utf8") as f:
self._data: dict = yaml.load(f)
- self._data = self._data['PluginBlockLimit']
+ self._data = self._data["PluginBlockLimit"]
self.reload_block_limit()
diff --git a/utils/manager/plugins2cd_manager.py b/utils/manager/plugins2cd_manager.py
index 8f557757..2ea245c4 100644
--- a/utils/manager/plugins2cd_manager.py
+++ b/utils/manager/plugins2cd_manager.py
@@ -17,6 +17,13 @@ class Plugins2cdManager(StaticData):
self.file = file
super().__init__(None)
self._freq_limiter: Dict[str, FreqLimiter] = {}
+ if file.exists():
+ with open(file, "r", encoding="utf8") as f:
+ self._data = yaml.load(f)
+ if "PluginCdLimit" in self._data.keys():
+ self._data = (
+ self._data["PluginCdLimit"] if self._data["PluginCdLimit"] else {}
+ )
def add_cd_limit(
self,
@@ -40,15 +47,15 @@ class Plugins2cdManager(StaticData):
:param data_dict: 封装好的字典数据
"""
if data_dict:
- cd = data_dict.get('cd')
- status = data_dict.get('status')
- check_type = data_dict.get('check_type')
- limit_type = data_dict.get('limit_type')
- rst = data_dict.get('rst')
+ cd = data_dict.get("cd")
+ status = data_dict.get("status")
+ check_type = data_dict.get("check_type")
+ limit_type = data_dict.get("limit_type")
+ rst = data_dict.get("rst")
cd = cd if cd is not None else 5
status = status if status is not None else True
- check_type = check_type if check_type else 'all'
- limit_type = limit_type if limit_type else 'user'
+ check_type = check_type if check_type else "all"
+ limit_type = limit_type if limit_type else "user"
if check_type not in ["all", "group", "private"]:
raise ValueError(
f"{plugin} 添加cd限制错误,‘check_type‘ 必须为 'private'/'group'/'all'"
@@ -63,14 +70,6 @@ class Plugins2cdManager(StaticData):
"rst": rst,
}
- def remove_cd_limit(self, plugin: str):
- """
- 删除一个插件 cd 限制
- :param plugin: 插件模块名称
- """
- if self._data.get(plugin):
- del self._data[plugin]
-
def get_plugin_cd_data(self, plugin: str) -> Optional[dict]:
"""
获取插件cd数据
@@ -128,8 +127,10 @@ class Plugins2cdManager(StaticData):
"""
for plugin in self._data:
if self.check_plugin_cd_status(plugin):
- self._freq_limiter[plugin] = FreqLimiter(self.get_plugin_cd_data(plugin)['cd'])
- logger.info(f'已成功加载 {len(self._freq_limiter)} 个Cd限制.')
+ self._freq_limiter[plugin] = FreqLimiter(
+ self.get_plugin_cd_data(plugin)["cd"]
+ )
+ logger.info(f"已成功加载 {len(self._freq_limiter)} 个Cd限制.")
def reload(self):
"""
@@ -138,7 +139,5 @@ class Plugins2cdManager(StaticData):
if self.file.exists():
with open(self.file, "r", encoding="utf8") as f:
self._data: dict = yaml.load(f)
- self._data = self._data['PluginCdLimit']
+ self._data = self._data["PluginCdLimit"]
self.reload_cd_limit()
-
-
diff --git a/utils/manager/plugins2count_manager.py b/utils/manager/plugins2count_manager.py
new file mode 100644
index 00000000..724c39ac
--- /dev/null
+++ b/utils/manager/plugins2count_manager.py
@@ -0,0 +1,134 @@
+from typing import Optional, Dict
+from .data_class import StaticData
+from utils.utils import DailyNumberLimiter
+from services.log import logger
+from pathlib import Path
+from ruamel.yaml import YAML
+
+yaml = YAML(typ="safe")
+
+
+class Plugins2countManager(StaticData):
+ """
+ 插件命令 次数 管理器
+ """
+
+ def __init__(self, file: Path):
+ self.file = file
+ super().__init__(None)
+ self._daily_limiter: Dict[str, DailyNumberLimiter] = {}
+ if file.exists():
+ with open(file, "r", encoding="utf8") as f:
+ self._data = yaml.load(f)
+ if "PluginCountLimit" in self._data.keys():
+ self._data = (
+ self._data["PluginCountLimit"] if self._data["PluginCountLimit"] else {}
+ )
+
+ def add_count_limit(
+ self,
+ plugin: str,
+ *,
+ max_count: int = 5,
+ status: Optional[bool] = True,
+ limit_type: Optional[str] = "user",
+ rst: Optional[str] = None,
+ data_dict: Optional[dict] = None,
+ ):
+ """
+ 添加插件调用 次数 限制
+ :param plugin: 插件模块名称
+ :param max_count: 最大次数限制
+ :param status: 默认开关状态
+ :param limit_type: 限制类型 监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id
+ :param rst: 回复的话,为空则不回复
+ :param data_dict: 封装好的字典数据
+ """
+ if data_dict:
+ max_count = data_dict.get("max_count")
+ status = data_dict.get("status")
+ limit_type = data_dict.get("limit_type")
+ rst = data_dict.get("rst")
+ status = status if status is not None else True
+ limit_type = limit_type if limit_type else "user"
+ max_count = max_count if max_count is not None else 5
+ if limit_type not in ["user", "group"]:
+ raise ValueError(f"{plugin} 添加count限制错误,‘limit_type‘ 必须为 'user'/'group'")
+ self._data[plugin] = {
+ "max_count": max_count,
+ "status": status,
+ "limit_type": limit_type,
+ "rst": rst,
+ }
+
+ def get_plugin_count_data(self, plugin: str) -> Optional[dict]:
+ """
+ 获取插件次数数据
+ :param plugin: 模块名
+ """
+ if self.check_plugin_count_status(plugin):
+ return self._data[plugin]
+ return None
+
+ def get_plugin_data(self, plugin: str) -> Optional[dict]:
+ """
+ 获取单个模块限制数据
+ :param plugin: 模块名
+ """
+ if self._data.get(plugin) is not None:
+ return self._data.get(plugin)
+ return None
+
+ def check_plugin_count_status(self, plugin: str) -> bool:
+ """
+ 检测插件是否有 次数 限制
+ :param plugin: 模块名
+ """
+ return (
+ plugin in self._data.keys()
+ and self._data[plugin]["status"]
+ and self._data[plugin]["max_count"] > 0
+ )
+
+ def check(self, plugin: str, id_: int) -> bool:
+ """
+ 检查 count
+ :param plugin: 模块名
+ :param id_: 限制 id
+ """
+ if self._daily_limiter.get(plugin):
+ return self._daily_limiter[plugin].check(id_)
+ return True
+
+ def increase(self, plugin: str, id_: int, num: int = 1):
+ """
+ 增加次数
+ :param plugin: 模块名
+ :param id_: cd 限制类型
+ :param num: 增加次数
+ :return:
+ """
+ if self._daily_limiter.get(plugin):
+ self._daily_limiter[plugin].increase(id_, num)
+
+ def reload_count_limit(self):
+ """
+ 加载 cd 限制器
+ :return:
+ """
+ for plugin in self._data:
+ if self.check_plugin_count_status(plugin):
+ self._daily_limiter[plugin] = DailyNumberLimiter(
+ self.get_plugin_count_data(plugin)["max_count"]
+ )
+ logger.info(f"已成功加载 {len(self._daily_limiter)} 个Count限制.")
+
+ def reload(self):
+ """
+ 重载本地数据
+ """
+ if self.file.exists():
+ with open(self.file, "r", encoding="utf8") as f:
+ self._data: dict = yaml.load(f)
+ self._data = self._data["PluginCountLimit"]
+ self.reload_count_limit()
diff --git a/utils/manager/plugins2settings_manager.py b/utils/manager/plugins2settings_manager.py
index d4183b40..d5f49fe6 100644
--- a/utils/manager/plugins2settings_manager.py
+++ b/utils/manager/plugins2settings_manager.py
@@ -55,17 +55,11 @@ class Plugins2settingsManager(StaticData):
if limit_superuser is not None
else False,
"cmd": cmd,
- "plugin_type": list(plugin_type if plugin_type is not None else ("normal",))
+ "plugin_type": list(
+ plugin_type if plugin_type is not None else ("normal",)
+ ),
}
- def remove_plugin_settings(self, plugin: str):
- """
- 删除一个插件设置
- :param plugin: 插件模块名称
- """
- if self._data.get(plugin):
- del self._data[plugin]
-
def get_plugin_data(self, module: str) -> dict:
"""
通过模块名获取数据
@@ -99,4 +93,4 @@ class Plugins2settingsManager(StaticData):
if self.file.exists():
with open(self.file, "r", encoding="utf8") as f:
self._data: dict = yaml.load(f)
- self._data = self._data['PluginSettings']
+ self._data = self._data["PluginSettings"]
diff --git a/utils/manager/plugins_manager.py b/utils/manager/plugins_manager.py
new file mode 100644
index 00000000..2b0cf854
--- /dev/null
+++ b/utils/manager/plugins_manager.py
@@ -0,0 +1,154 @@
+from typing import Optional
+from pathlib import Path
+from .data_class import StaticData
+from . import group_manager
+
+
+class PluginsManager(StaticData):
+ """
+ 插件 管理器
+ """
+
+ def __init__(self, file: Path):
+ super().__init__(file)
+ if not self._data:
+ self._data = {}
+
+ def add_plugin_data(
+ self,
+ module: str,
+ plugin_name: str,
+ *,
+ status: Optional[bool] = True,
+ error: Optional[bool] = False,
+ block_type: Optional[str] = None,
+ author: Optional[str] = None,
+ version: Optional[int] = None,
+ ):
+ """
+ 添加插件数据
+ :param module: 模块名称
+ :param plugin_name: 插件名称
+ :param status: 插件开关状态
+ :param error: 加载状态
+ :param block_type: 限制类型
+ :param author: 作者
+ :param version: 版本
+ """
+ self._data[module] = {
+ "plugin_name": plugin_name,
+ "status": status,
+ "error": error,
+ "block_type": block_type,
+ "author": author,
+ "version": version,
+ }
+
+ def block_plugin(
+ self, module: str, group_id: Optional[int] = None, block_type: str = "all"
+ ):
+ """
+ 说明:
+ 锁定插件
+ 参数:
+ :param module: 功能模块名
+ :param group_id: 群组,None时为超级用户禁用
+ :param block_type: 限制类型
+ """
+ self._set_plugin_status(module, "block", group_id, block_type)
+
+ def unblock_plugin(self, module: str, group_id: Optional[int] = None):
+ """
+ 说明:
+ 解锁插件
+ 参数:
+ :param module: 功能模块名
+ :param group_id: 群组
+ """
+ self._set_plugin_status(module, "unblock", group_id)
+
+ def get_plugin_status(
+ self, module: str, block_type: str = "all"
+ ) -> bool:
+ """
+ 说明:
+ 获取插件状态
+ 参数:
+ :param module: 功能模块名
+ :param block_type: 限制类型
+ """
+ if module in self._data.keys():
+ if self._data[module]["block_type"] == "all" and block_type == "all":
+ return False
+ else:
+ return not self._data[module]["block_type"] == block_type
+ return True
+
+ def get_plugin_block_type(self, module: str) -> str:
+ """
+ 说明:
+ 获取功能限制类型
+ 参数:
+ :param module: 模块名称
+ """
+ if module in self._data.keys():
+ return self._data[module]["block_type"]
+ return ""
+
+ def get_plugin_error_status(self, module: str) -> bool:
+ """
+ 插件是否成功加载
+ :param module: 模块名称
+ """
+ if module not in self._data.keys():
+ self.init_plugin(module)
+ return self._data[module]["error"]
+
+ def _set_plugin_status(
+ self,
+ module: str,
+ status: str,
+ group_id: Optional[str],
+ block_type: str = "all",
+ ):
+ """
+ 说明:
+ 设置功能开关状态
+ 参数:
+ :param module: 功能模块名
+ :param status: 功能状态
+ :param group_id: 群组
+ :param block_type: 限制类型
+ """
+ group_id = str(group_id) if group_id else group_id
+ if module:
+ if group_id:
+ if status == "block":
+ group_manager.block_plugin(f"{module}:super", int(group_id))
+ else:
+ group_manager.unblock_plugin(f"{module}:super", int(group_id))
+ else:
+ if module not in self._data.keys():
+ self.init_plugin(module)
+ if status == "block":
+ self._data[module]["status"] = False
+ self._data[module]["block_type"] = block_type
+ else:
+ if module in self._data.keys():
+ self._data[module]["status"] = True
+ self.save()
+
+ def init_plugin(self, module: str):
+ """
+ 初始化插件数据
+ :param module: 模块名称
+ """
+ if module not in self._data.keys():
+ self._data[module] = {
+ "plugin_name": module,
+ "status": True,
+ "error": False,
+ "block_type": None,
+ "author": None,
+ "version": None,
+ }
diff --git a/utils/manager/requests_manager.py b/utils/manager/requests_manager.py
new file mode 100644
index 00000000..842926dd
--- /dev/null
+++ b/utils/manager/requests_manager.py
@@ -0,0 +1,246 @@
+from utils.manager.data_class import StaticData
+from nonebot.adapters.cqhttp import Bot
+from nonebot.adapters.cqhttp.exception import ActionFailed
+from services.log import logger
+from typing import Optional
+from utils.image_utils import CreateImg
+from utils.utils import get_user_avatar
+from pathlib import Path
+from io import BytesIO
+
+
+class RequestManager(StaticData):
+
+ """
+ 好友请求/邀请请求 管理
+ """
+
+ def __init__(self, file: Optional[Path]):
+ super().__init__(file)
+ if not self._data:
+ self._data = {"private": {}, "group": {}}
+
+ def add_request(
+ self,
+ id_: int,
+ type_: str,
+ flag: str,
+ *,
+ nickname: Optional[str] = None,
+ level: Optional[int] = None,
+ sex: Optional[str] = None,
+ age: Optional[str] = None,
+ from_: Optional[str] = "",
+ comment: Optional[str] = None,
+ invite_group: Optional[int] = None,
+ group_name: Optional[str] = None,
+ ):
+ """
+ 添加一个请求
+ :param id_: id,用户id或群id
+ :param type_: 类型,private 或 group
+ :param flag: event.flag
+ :param nickname: 用户昵称
+ :param level: 等级
+ :param sex: 性别
+ :param age: 年龄
+ :param from_: 请求来自
+ :param comment: 附加消息
+ :param invite_group: 邀请群聊
+ :param group_name: 群聊名称
+ """
+ self._data[type_][str(len(self._data[type_].keys()))] = {
+ "id": id_,
+ "flag": flag,
+ "nickname": nickname,
+ "level": level,
+ "sex": sex,
+ "age": age,
+ "from": from_,
+ "comment": comment,
+ "invite_group": invite_group,
+ "group_name": group_name,
+ }
+ self.save()
+
+ def remove_request(self, type_: str, id_: int):
+ """
+ 删除一个请求数据
+ :param type_: 类型
+ :param id_: id,user_id 或 group_id
+ """
+ for x in self._data[type_].keys():
+ if self._data[type_][x].get("id") == id_:
+ del self._data[type_][x]
+ break
+ self.save()
+
+ async def approve(self, bot: Bot, id_: int, type_: str) -> Optional[int]:
+ """
+ 同意请求
+ :param bot: Bot
+ :param id_: id
+ :param type_: 类型,private 或 group
+ """
+ return await self._set_add_request(bot, id_, type_, True)
+
+ async def refused(self, bot: Bot, id_: int, type_: str) -> Optional[int]:
+ """
+ 拒绝请求
+ :param bot: Bot
+ :param id_: id
+ :param type_: 类型,private 或 group
+ """
+ return await self._set_add_request(bot, id_, type_, False)
+
+ def clear(self):
+ """
+ 清空所有请求信息,无视请求
+ """
+ self._data = {"private": {}, "group": {}}
+ self.save()
+
+ def set_group_name(self, group_name: str, group_id: int):
+ """
+ 设置群聊名称
+ :param group_name: 名称
+ :param group_id: id
+ """
+ for id_ in self._data["group"].keys():
+ if self._data["group"][id_]["invite_group"] == group_id:
+ self._data["group"][id_]["group_name"] = group_name
+ break
+ self.save()
+
+ async def show(self, type_: str) -> Optional[str]:
+ """
+ 请求可视化
+ """
+ data = self._data[type_]
+ if not data:
+ return None
+ img_list = []
+ id_list = list(data.keys())
+ id_list.reverse()
+ for id_ in id_list:
+ age = data[id_]["age"]
+ nickname = data[id_]["nickname"]
+ comment = data[id_]["comment"] if type_ == "private" else ""
+ from_ = data[id_]["from"]
+ sex = data[id_]["sex"]
+ ava = CreateImg(
+ 80, 80, background=BytesIO(await get_user_avatar(data[id_]["id"]))
+ )
+ ava.circle()
+ age_bk = CreateImg(
+ len(str(age)) * 10 - 5,
+ 15,
+ color="#04CAF7" if sex == "male" else "#F983C1",
+ )
+ age_bk.text((3, 1), f"{age}", fill=(255, 255, 255))
+ x = CreateImg(
+ 90, 32, font_size=15, color="#EEEFF4", font="HYWenHei-85W.ttf"
+ )
+ x.text((0, 0), "同意/拒绝", center_type="center")
+ x.circle_corner(10)
+ A = CreateImg(500, 100, font_size=24, font="msyh.ttf")
+ A.paste(ava, (15, 0), alpha=True, center_type="by_height")
+ A.text((120, 15), nickname)
+ A.paste(age_bk, (120, 50), True)
+ A.paste(
+ CreateImg(
+ 200,
+ 0,
+ font_size=12,
+ plain_text=f"对方留言:{comment}",
+ font_color=(140, 140, 143),
+ ),
+ (120 + age_bk.w + 10, 49),
+ True,
+ )
+ if type_ == "private":
+ A.paste(
+ CreateImg(
+ 200,
+ 0,
+ font_size=12,
+ plain_text=f"来源:{from_}",
+ font_color=(140, 140, 143),
+ ),
+ (120, 70),
+ True,
+ )
+ else:
+ A.paste(
+ CreateImg(
+ 200,
+ 0,
+ font_size=12,
+ plain_text=f"邀请你加入:{data[id_]['group_name']}({data[id_]['invite_group']})",
+ font_color=(140, 140, 143),
+ ),
+ (120, 70),
+ True,
+ )
+ A.paste(x, (380, 35), True)
+ A.paste(
+ CreateImg(
+ 0,
+ 0,
+ plain_text=f"id:{id_}",
+ font_size=13,
+ font_color=(140, 140, 143),
+ ),
+ (400, 10),
+ True,
+ )
+ img_list.append(A)
+ A = CreateImg(500, len(img_list) * 100, 500, 100)
+ for img in img_list:
+ A.paste(img)
+ bk = CreateImg(A.w, A.h + 50, color="#F8F9FB", font_size=20)
+ bk.paste(A, (0, 50))
+ bk.text(
+ (15, 13), "好友请求" if type_ == "private" else "群聊请求", fill=(140, 140, 143)
+ )
+ return bk.pic2bs4()
+
+ async def _set_add_request(
+ self, bot: Bot, id_: int, type_: str, approve: bool
+ ) -> Optional[int]:
+ """
+ 处理请求
+ :param bot: Bot
+ :param id_: id
+ :param type_: 类型,private 或 group
+ :param approve: 是否同意
+ """
+ id_ = str(id_)
+ if id_ in self._data[type_]:
+ try:
+ if type_ == "private":
+ await bot.set_friend_add_request(
+ flag=self._data[type_][id_]["flag"], approve=approve
+ )
+ rid = self._data[type_][id_]["id"]
+ else:
+ await bot.set_group_add_request(
+ flag=self._data[type_][id_]["flag"],
+ sub_type="invite",
+ approve=approve,
+ )
+ rid = self._data[type_][id_]["invite_group"]
+ except ActionFailed:
+ logger.info(
+ f"同意{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})"
+ f"的{'好友' if type_ == 'private' else '入群'}请求失败了..."
+ )
+ return None
+ logger.info(
+ f"同意{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})"
+ f"的{'好友' if type_ == 'private' else '入群'}请求..."
+ )
+ del self._data[type_][id_]
+ self.save()
+ return rid
+ return None
diff --git a/utils/manager/resources_manager.py b/utils/manager/resources_manager.py
new file mode 100644
index 00000000..c517003b
--- /dev/null
+++ b/utils/manager/resources_manager.py
@@ -0,0 +1,109 @@
+from typing import Union, List, Optional
+from .data_class import StaticData
+from pathlib import Path
+from ruamel.yaml import YAML
+from services.log import logger
+import shutil
+
+yaml = YAML(typ="safe")
+
+
+class ResourcesManager(StaticData):
+ """
+ 插件配置 与 资源 管理器
+ """
+
+ def __init__(self, file: Path):
+ self.file = file
+ super().__init__(file)
+ self._temp_dir = []
+ self._abspath = Path()
+
+ def add_resource(
+ self, module: str, source_file: Union[str, Path], move_file: Union[str, Path]
+ ):
+ """
+ 添加一个资源移动路劲
+ :param module: 模块名
+ :param source_file: 源文件路径
+ :param move_file: 移动路径
+ """
+ if isinstance(source_file, Path):
+ source_file = str(source_file.absolute())
+ if isinstance(move_file, Path):
+ move_file = move_file.absolute()
+ if module not in self._data.keys():
+ self._data[module] = {source_file: move_file}
+ else:
+ self._data[module][source_file] = move_file
+
+ def remove_resource(self, module: str, source_file: Optional[Union[str, Path]] = None):
+ """
+ 删除一个资源路径
+ :param module: 模块
+ :param source_file: 源文件路径
+ """
+ if not source_file:
+ if module in self._data.keys():
+ for x in self._data[module].keys():
+ move_file = Path(self._data[module][x])
+ if move_file.exists():
+ shutil.rmtree(move_file.absolute(), ignore_errors=True)
+ logger.info(f"已清除插件 {module} 资源路径:{self._data[module][x]}")
+ del self._data[module][x]
+ else:
+ if isinstance(source_file, Path):
+ source_file = str(source_file.absolute())
+ if source_file:
+ if module in self._data.keys() and source_file in self._data[module].keys():
+ move_file = Path(self._data[module][source_file])
+ if move_file.exists():
+ shutil.rmtree(move_file.absolute(), ignore_errors=True)
+ del self._data[module][source_file]
+ self.save()
+
+ def start_move(self):
+ """
+ 开始移动路径
+ """
+ for module in self._data.keys():
+ for source_path in self._data[module].keys():
+ move_path = Path(self._data[module][source_path])
+ source_path = Path(source_path)
+ file_name = source_path.name
+ move_path = move_path / file_name
+ move_path.mkdir(exist_ok=True, parents=True)
+ try:
+ if source_path.exists():
+ if move_path.exists():
+ shutil.rmtree(str(move_path.absolute()), ignore_errors=True)
+ shutil.move(str(source_path.absolute()), str(move_path.absolute()))
+ logger.info(
+ f"移动资源文件路径 {source_path.absolute()} >>> {move_path.absolute()}"
+ )
+ elif not move_path.exists():
+ logger.warning(
+ f"移动资源路径文件{source_path.absolute()} >>>"
+ f" {move_path.absolute()} 失败,源文件不存在.."
+ )
+ except Exception as e:
+ logger.error(
+ f"移动资源路径文件{source_path.absolute()} >>>"
+ f" {move_path.absolute()}失败,{type(e)}:{e}"
+ )
+ self.save()
+
+ def add_temp_dir(self, path: Union[str, Path]):
+ """
+ 添加临时清理文件夹
+ :param path: 路径
+ """
+ if isinstance(path, str):
+ path = Path(path)
+ self._temp_dir.append(path)
+
+ def get_temp_data_dir(self) -> List[Path]:
+ """
+ 获取临时文件文件夹
+ """
+ return self._temp_dir
diff --git a/utils/manager/withdraw_message_manager.py b/utils/manager/withdraw_message_manager.py
index fa7482cc..57eb3445 100644
--- a/utils/manager/withdraw_message_manager.py
+++ b/utils/manager/withdraw_message_manager.py
@@ -1,8 +1,8 @@
from typing import Tuple, Union, Dict
+from nonebot.adapters.cqhttp import MessageEvent, PrivateMessageEvent, GroupMessageEvent
class WithdrawMessageManager:
-
def __init__(self):
self.data = []
@@ -14,7 +14,7 @@ class WithdrawMessageManager:
:param message_data: 撤回消息id和时间
"""
if isinstance(message_data[0], dict):
- message_data = (message_data[0]['message_id'], message_data[1])
+ message_data = (message_data[0]["message_id"], message_data[1])
self.data.append(message_data)
def remove(self, message_data: Tuple[int, int]):
@@ -26,3 +26,19 @@ class WithdrawMessageManager:
"""
self.data.remove(message_data)
+ def withdraw_message(
+ self, event: MessageEvent, id_: Union[int, Dict[str, int]], conditions: Tuple[int, int]
+ ):
+ """
+ 便捷判断消息撤回
+ :param event: event
+ :param id_: 消息id 或 send 返回的字典
+ :param conditions: 判断条件
+ """
+ if conditions[0]:
+ if (
+ (conditions[1] == 0 and isinstance(event, PrivateMessageEvent))
+ or (conditions[1] == 1 and isinstance(event, GroupMessageEvent))
+ or conditions[1] == 2
+ ):
+ self.append((id_, conditions[0]))
diff --git a/utils/message_builder.py b/utils/message_builder.py
index c66230bf..cb7779a0 100644
--- a/utils/message_builder.py
+++ b/utils/message_builder.py
@@ -1,13 +1,17 @@
from configs.path_config import IMAGE_PATH, VOICE_PATH
from nonebot.adapters.cqhttp.message import MessageSegment
+from configs.config import NICKNAME
from services.log import logger
-from typing import Union
+from typing import Union, List
from pathlib import Path
import os
def image(
- img_name: Union[str, Path] = None, path: str = None, abspath: str = None, b64: str = None
+ img_name: Union[str, Path] = None,
+ path: str = None,
+ abspath: str = None,
+ b64: str = None,
) -> Union[MessageSegment, str]:
"""
说明:
@@ -153,3 +157,27 @@ def poke(qq: int) -> MessageSegment:
:param qq: qq号
"""
return MessageSegment("poke", {"qq": qq})
+
+
+def custom_forward_msg(
+ msg_list: List[str], uin: Union[int, str], name: str = f"这里是{NICKNAME}"
+) -> List[dict]:
+ """
+ 生成自定义合并消息
+ :param msg_list: 消息列表
+ :param uin: 发送者 QQ
+ :param name: 自定义名称
+ """
+ uin = int(uin)
+ mes_list = []
+ for _message in msg_list:
+ data = {
+ "type": "node",
+ "data": {
+ "name": name,
+ "uin": f"{uin}",
+ "content": _message,
+ },
+ }
+ mes_list.append(data)
+ return mes_list
diff --git a/utils/utils.py b/utils/utils.py
index 6d6d32ce..c5c469ec 100644
--- a/utils/utils.py
+++ b/utils/utils.py
@@ -1,15 +1,14 @@
-from datetime import datetime, timedelta
+from datetime import datetime
from collections import defaultdict
from nonebot import require
-from configs.path_config import TEXT_PATH
from configs.config import SYSTEM_PROXY
-from typing import List, Union, Optional, Type
+from typing import List, Union, Optional, Type, Any
from nonebot.adapters.cqhttp import Bot
from nonebot.matcher import matchers, Matcher
+import httpx
import nonebot
import pytz
import pypinyin
-import aiohttp
import time
try:
@@ -30,10 +29,10 @@ class CountLimiter:
self.count = defaultdict(int)
self.max_count = max_count
- def add(self, key: Union[str, int, float]):
+ def add(self, key: Any):
self.count[key] += 1
- def check(self, key: Union[str, int, float]) -> bool:
+ def check(self, key: Any) -> bool:
if self.count[key] >= self.max_count:
self.count[key] = 0
return True
@@ -49,14 +48,14 @@ class UserBlockLimiter:
self.flag_data = defaultdict(bool)
self.time = time.time()
- def set_true(self, key: Union[str, int, float]):
+ def set_true(self, key: Any):
self.time = time.time()
self.flag_data[key] = True
- def set_false(self, key: Union[str, int, float]):
+ def set_false(self, key: Any):
self.flag_data[key] = False
- def check(self, key: Union[str, int, float]) -> bool:
+ def check(self, key: Any) -> bool:
if time.time() - self.time > 30:
self.set_false(key)
return False
@@ -72,15 +71,15 @@ class FreqLimiter:
self.next_time = defaultdict(float)
self.default_cd = default_cd_seconds
- def check(self, key: Union[str, int, float]) -> bool:
+ def check(self, key: Any) -> bool:
return time.time() >= self.next_time[key]
- def start_cd(self, key: Union[str, int, float], cd_time: int = 0):
+ def start_cd(self, key: Any, cd_time: int = 0):
self.next_time[key] = time.time() + (
cd_time if cd_time > 0 else self.default_cd
)
- def left_time(self, key: Union[str, int, float]) -> float:
+ def left_time(self, key: Any) -> float:
return self.next_time[key] - time.time()
@@ -131,8 +130,7 @@ class DailyNumberLimiter:
self.max = max_num
def check(self, key) -> bool:
- now = datetime.now(self.tz)
- day = (now - timedelta(hours=5)).day
+ day = datetime.now(self.tz).day
if day != self.today:
self.today = day
self.count.clear()
@@ -282,18 +280,6 @@ def get_message_json(data: str) -> List[dict]:
return []
-# 获取文本加密后的cookie
-def get_cookie_text(cookie_name: str) -> str:
- """
- 说明:
- 获取 txt/cookie 目录下指定 cookie 的内容
- 参数:
- :param cookie_name: cookie文件名称
- """
- with open(TEXT_PATH + "cookie/" + cookie_name + ".txt", "r") as f:
- return f.read()
-
-
def get_local_proxy():
"""
说明:
@@ -302,7 +288,7 @@ def get_local_proxy():
return SYSTEM_PROXY if SYSTEM_PROXY else None
-def is_Chinese(word: str) -> bool:
+def is_chinese(word: str) -> bool:
"""
说明:
判断字符串是否为纯中文
@@ -315,7 +301,7 @@ def is_Chinese(word: str) -> bool:
return True
-async def user_avatar(qq: int) -> bytes:
+async def get_user_avatar(qq: int) -> bytes:
"""
说明:
快捷获取用户头像
@@ -323,12 +309,15 @@ async def user_avatar(qq: int) -> bytes:
:param qq: qq号
"""
url = f"http://q1.qlogo.cn/g?b=qq&nk={qq}&s=160"
- async with aiohttp.ClientSession() as session:
- async with session.get(url, proxy=get_local_proxy(), timeout=5) as response:
- return await response.read()
+ async with httpx.AsyncClient() as client:
+ for _ in range(3):
+ try:
+ return (await client.get(url)).content
+ except TimeoutError:
+ pass
-async def group_avatar(group_id: int) -> bytes:
+async def get_group_avatar(group_id: int) -> bytes:
"""
说明:
快捷获取用群头像
@@ -336,9 +325,12 @@ async def group_avatar(group_id: int) -> bytes:
:param group_id: 群号
"""
url = f"http://p.qlogo.cn/gh/{group_id}/{group_id}/640/"
- async with aiohttp.ClientSession() as session:
- async with session.get(url, proxy=get_local_proxy(), timeout=5) as response:
- return await response.read()
+ async with httpx.AsyncClient() as client:
+ for _ in range(3):
+ try:
+ return (await client.get(url)).content
+ except TimeoutError:
+ pass
def cn2py(word: str) -> str:
@@ -368,3 +360,4 @@ def change_picture_links(url: str, mode: str):
img_type = img_sp[1]
url = url.replace("original", "master") + f"_master1200.{img_type}"
return url
+