mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-04 03:10:01 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ea740aa7c | ||
|
|
5f118471cb | ||
|
|
504f78dd49 | ||
|
|
72723c7d1f | ||
|
|
6a74053853 | ||
|
|
af0b4987a4 | ||
|
|
775140cf79 | ||
|
|
6a8a796add | ||
|
|
8e4bda3760 | ||
|
|
a36e8145a8 | ||
|
|
3cbd899daa | ||
|
|
30f356a2c7 | ||
|
|
1138a115ce | ||
|
|
c397da75e7 | ||
|
|
1d141c9313 | ||
|
|
a4cc365af8 | ||
|
|
4e551bec0d | ||
|
|
e03086062d | ||
|
|
270a5a5e20 | ||
|
|
bda9133ed6 | ||
|
|
749f475f2c | ||
|
|
e38394948c | ||
|
|
51fc4cbb6a | ||
|
|
9a976cda37 | ||
|
|
e42521f0a3 | ||
|
|
0756d39ac5 | ||
|
|
4595bdcee4 | ||
|
|
38160065cc | ||
|
|
3d04f013cd | ||
|
|
8e1a416be3 | ||
|
|
a98bc42f1a | ||
|
|
6c93769838 | ||
|
|
d2dccfebc5 | ||
|
|
82fe59e469 | ||
|
|
afc05e1731 | ||
|
|
0206b0a522 | ||
|
|
0e1e5a5ebe | ||
|
|
9ad088ed6a | ||
|
|
34da04bba5 | ||
|
|
09ce812faf | ||
|
|
1dc8cb2a98 | ||
|
|
e73c509823 | ||
|
|
e70a85400f | ||
|
|
f7aecf8eed | ||
|
|
cc2645aa9d | ||
|
|
52d23c4a8d | ||
|
|
1e57ddb9ee | ||
|
|
7ae883d921 | ||
|
|
27e97214bd | ||
|
|
6321a9e7e0 | ||
|
|
a9eadca46c | ||
|
|
76bef8a725 | ||
|
|
308b76dc7d | ||
|
|
31d4d29f3e | ||
|
|
016a7e87ea | ||
|
|
4ce88c7bfc | ||
|
|
f570bffcf7 | ||
|
|
3bb9aaf637 | ||
|
|
cf7a64c934 | ||
|
|
c466603193 | ||
|
|
bc53f329a9 | ||
|
|
4a5cc5153f | ||
|
|
e70d0df949 | ||
|
|
fcaa469edd | ||
|
|
51508182ef | ||
|
|
27e78c1626 | ||
|
|
0b4d37a0b6 | ||
|
|
ddbebba6f1 | ||
|
|
7f296348e4 | ||
|
|
ca78e32d97 | ||
|
|
4efc561f4d | ||
|
|
3c120ce602 | ||
|
|
6151dfb161 | ||
|
|
f05d4ec931 | ||
|
|
a1308fbdc9 | ||
|
|
946fbbec3c | ||
|
|
bd531c85b1 | ||
|
|
cda9aae8a3 | ||
|
|
a33e785043 |
@@ -159,3 +159,5 @@ resources/
|
|||||||
!/configs/config.yaml
|
!/configs/config.yaml
|
||||||
!/.env
|
!/.env
|
||||||
!/.env.dev
|
!/.env.dev
|
||||||
|
!/plugins/csgo_server/
|
||||||
|
!/plugins/activity/
|
||||||
|
|||||||
@@ -252,6 +252,10 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
|
|||||||
|
|
||||||
### 感谢名单
|
### 感谢名单
|
||||||
(可以告诉我你的 __github__ 地址,我偷偷换掉0v|)
|
(可以告诉我你的 __github__ 地址,我偷偷换掉0v|)
|
||||||
|
[腊条](https://afdian.net/u/f739c4d69eca11eba94b52540025c377)
|
||||||
|
[ze roller](https://afdian.net/u/0e599e96257211ed805152540025c377)
|
||||||
|
[爱发电用户_4jrf](https://afdian.net/u/6b2cdcc817c611ed949152540025c377)
|
||||||
|
[爱发电用户_TBsd](https://afdian.net/u/db638b60217911ed9efd52540025c377)
|
||||||
[烟寒若雨](https://afdian.net/u/067bd2161eec11eda62b52540025c377)
|
[烟寒若雨](https://afdian.net/u/067bd2161eec11eda62b52540025c377)
|
||||||
[ln](https://afdian.net/u/b51914ba1c6611ed8a4e52540025c377)
|
[ln](https://afdian.net/u/b51914ba1c6611ed8a4e52540025c377)
|
||||||
[爱发电用户_b9S4](https://afdian.net/u/3d8f30581a2911edba6d52540025c377)
|
[爱发电用户_b9S4](https://afdian.net/u/3d8f30581a2911edba6d52540025c377)
|
||||||
@@ -275,6 +279,55 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
|
|||||||
|
|
||||||
## 更新
|
## 更新
|
||||||
|
|
||||||
|
### 2022/9/16
|
||||||
|
|
||||||
|
* fix: bilibili_sub, azur_draw_card [@pull/1090](https://github.com/HibiKier/zhenxun_bot/pull/1090)
|
||||||
|
* 修复原神资源查询查询完毕后图片存储错误
|
||||||
|
* b站订阅发送 与 b站订阅 使用相同开关,即:关闭b站订阅
|
||||||
|
|
||||||
|
### 2022/9/10
|
||||||
|
|
||||||
|
* 自定义群欢迎消息参数不完全时提示报错
|
||||||
|
* 修改bt插件的url地址 [@pull/1067](https://github.com/HibiKier/zhenxun_bot/pull/1067)
|
||||||
|
|
||||||
|
### 2022/9/8
|
||||||
|
|
||||||
|
* 添加插件数据初始化判断
|
||||||
|
|
||||||
|
### 2022/9/4
|
||||||
|
|
||||||
|
* 旧词条提供图片迁移(需要重新获取old_model文件,并将数据库中user_qq为0的数据删除)
|
||||||
|
|
||||||
|
### 2022/9/3
|
||||||
|
|
||||||
|
* 原神玩家查询增加须弥地区 [@pull/1053](https://github.com/HibiKier/zhenxun_bot/pull/1053)
|
||||||
|
* av号覆盖全面,且修复av号链接 [@pull/1033](https://github.com/HibiKier/zhenxun_bot/pull/1033)
|
||||||
|
* 修复词条含有CQ回答的模糊匹配无法被解析
|
||||||
|
* 禁言检测图片在内存中获取图片hash
|
||||||
|
* B站订阅在群里中任意群管理员可以统一管理(原来为管理员1无法删除管理员2的订阅)
|
||||||
|
* 修复原神资源查询地图api数据变更导致更新的地图不完全
|
||||||
|
|
||||||
|
### 2022/8/27
|
||||||
|
|
||||||
|
* 修复签到积分双倍后,日志记录获得积分变4倍问题 [@pull/1044](https://github.com/HibiKier/zhenxun_bot/pull/1044)
|
||||||
|
|
||||||
|
### 2022/8/26
|
||||||
|
|
||||||
|
* 修复群管理员无法添加词条
|
||||||
|
* 修复词条关键词"问"前空格问题
|
||||||
|
|
||||||
|
### 2022/8/23
|
||||||
|
|
||||||
|
* 修了下模糊匹配 issue#1026 [@pull/1026](https://github.com/HibiKier/zhenxun_bot/pull/1026)
|
||||||
|
|
||||||
|
### 2022/8/22
|
||||||
|
|
||||||
|
* 修复首次安装时词条旧表出错(因为根本就没有这张表!)
|
||||||
|
* 取消配置替换定时任务,统一存储
|
||||||
|
* 对米游社cookie进行判断,整合米游社签到信息 [@pull/1014](https://github.com/HibiKier/zhenxun_bot/pull/1014)
|
||||||
|
* 修正尘歌壶和质变仪图片获取地址 [@pull/1010](https://github.com/HibiKier/zhenxun_bot/pull/1010)
|
||||||
|
* 修复词库问答 **很多** 问题[@pull/1012](https://github.com/HibiKier/zhenxun_bot/pull/1012)
|
||||||
|
|
||||||
### 2022/8/21 \[v0.1.6.3]
|
### 2022/8/21 \[v0.1.6.3]
|
||||||
|
|
||||||
* 重构群词条,改为词库Plus,增加 精准|模糊|正则 问题匹配,问题与回答均支持at,image,face,超级用户额外提供 全局|私聊 词库设置,数据迁移目前只提供了问题和回答都是纯文本的词条
|
* 重构群词条,改为词库Plus,增加 精准|模糊|正则 问题匹配,问题与回答均支持at,image,face,超级用户额外提供 全局|私聊 词库设置,数据迁移目前只提供了问题和回答都是纯文本的词条
|
||||||
@@ -787,7 +840,7 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
|
|||||||
__..... 更多更新信息请查看文档__
|
__..... 更多更新信息请查看文档__
|
||||||
|
|
||||||
## Todo
|
## Todo
|
||||||
- [ ] web管理
|
- [x] web管理
|
||||||
|
|
||||||
## 感谢
|
## 感谢
|
||||||
[botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议
|
[botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
__version__: v0.1.6.3
|
__version__: v0.1.6.3-fix1
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ custom_welcome = on_command(
|
|||||||
|
|
||||||
@custom_welcome.handle()
|
@custom_welcome.handle()
|
||||||
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
|
||||||
|
msg = arg.extract_plain_text().strip()
|
||||||
|
img = get_message_img(event.json())
|
||||||
|
if not msg and not img:
|
||||||
|
await custom_welcome.finish(__plugin_usage__)
|
||||||
try:
|
try:
|
||||||
msg = arg.extract_plain_text().strip()
|
|
||||||
img = get_message_img(event.json())
|
|
||||||
if not msg and not img:
|
|
||||||
await custom_welcome.finish(__plugin_usage__)
|
|
||||||
await custom_welcome.send(
|
await custom_welcome.send(
|
||||||
await custom_group_welcome(msg, img, event.user_id, event.group_id),
|
await custom_group_welcome(msg, img, event.user_id, event.group_id),
|
||||||
at_sender=True,
|
at_sender=True,
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ async def _():
|
|||||||
try:
|
try:
|
||||||
await bot.send_group_msg(group_id=g, message="[[_task|zwa]]早上好" + result)
|
await bot.send_group_msg(group_id=g, message="[[_task|zwa]]早上好" + result)
|
||||||
except ActionFailed:
|
except ActionFailed:
|
||||||
logger.warning(f"{g} 群被禁言中,无法发送早安")
|
logger.warning(f"{g} 发送早安失败")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"早晚安错误 e:{e}")
|
logger.error(f"早晚安错误 e:{e}")
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ async def _():
|
|||||||
group_id=g, message=f"[[_task|zwa]]{NICKNAME}要睡觉了,你们也要早点睡呀" + result
|
group_id=g, message=f"[[_task|zwa]]{NICKNAME}要睡觉了,你们也要早点睡呀" + result
|
||||||
)
|
)
|
||||||
except ActionFailed:
|
except ActionFailed:
|
||||||
logger.warning(f"{g} 群被禁言中,无法发送晚安")
|
logger.warning(f"{g} 发送晚安失败")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"早晚安错误 e:{e}")
|
logger.error(f"早晚安错误 e:{e}")
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ def init_plugins_config(data_path):
|
|||||||
# 优先使用 metadata 数据
|
# 优先使用 metadata 数据
|
||||||
for matcher in _matchers:
|
for matcher in _matchers:
|
||||||
_plugin = matcher.plugin
|
_plugin = matcher.plugin
|
||||||
|
if not _plugin:
|
||||||
|
continue
|
||||||
metadata = _plugin.metadata
|
metadata = _plugin.metadata
|
||||||
try:
|
try:
|
||||||
_module = _plugin.module
|
_module = _plugin.module
|
||||||
@@ -108,16 +110,16 @@ def init_plugins_config(data_path):
|
|||||||
_data, wf, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
_data, wf, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
|
||||||
)
|
)
|
||||||
user_config_file = Path() / "configs" / "config.yaml"
|
user_config_file = Path() / "configs" / "config.yaml"
|
||||||
if not user_config_file.exists():
|
# if not user_config_file.exists():
|
||||||
_replace_config()
|
_replace_config()
|
||||||
else:
|
# else:
|
||||||
logger.info('五分钟后将进行配置数据替换,请注意...')
|
# logger.info('五分钟后将进行配置数据替换,请注意...')
|
||||||
scheduler.add_job(
|
# scheduler.add_job(
|
||||||
_replace_config,
|
# _replace_config,
|
||||||
"date",
|
# "date",
|
||||||
run_date=datetime.now() + timedelta(minutes=5),
|
# run_date=datetime.now() + timedelta(minutes=5),
|
||||||
id=f"_replace_config"
|
# id=f"_replace_config"
|
||||||
)
|
# )
|
||||||
|
|
||||||
|
|
||||||
def _replace_config():
|
def _replace_config():
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ def init_plugins_data(data_path):
|
|||||||
_matchers = get_matchers(True)
|
_matchers = get_matchers(True)
|
||||||
for matcher in _matchers:
|
for matcher in _matchers:
|
||||||
_plugin = matcher.plugin
|
_plugin = matcher.plugin
|
||||||
|
if not _plugin:
|
||||||
|
continue
|
||||||
metadata = _plugin.metadata
|
metadata = _plugin.metadata
|
||||||
try:
|
try:
|
||||||
_module = _plugin.module
|
_module = _plugin.module
|
||||||
|
|||||||
@@ -34,82 +34,87 @@ def init_plugins_settings(data_path: str):
|
|||||||
logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
|
logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
|
||||||
_tmp_module[x] = ""
|
_tmp_module[x] = ""
|
||||||
for matcher in _matchers:
|
for matcher in _matchers:
|
||||||
if matcher.plugin_name not in plugins2settings_manager.keys():
|
try:
|
||||||
_plugin = matcher.plugin
|
if matcher.plugin_name not in plugins2settings_manager.keys():
|
||||||
metadata = _plugin.metadata
|
_plugin = matcher.plugin
|
||||||
try:
|
if not _plugin:
|
||||||
_module = _plugin.module
|
continue
|
||||||
except AttributeError:
|
metadata = _plugin.metadata
|
||||||
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.")
|
|
||||||
else:
|
|
||||||
try:
|
try:
|
||||||
if metadata:
|
_module = _plugin.module
|
||||||
plugin_name = metadata.name
|
except AttributeError:
|
||||||
|
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
if metadata:
|
||||||
|
plugin_name = metadata.name
|
||||||
|
else:
|
||||||
|
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 level is None:
|
||||||
|
level = 5
|
||||||
|
admin_manager.add_admin_plugin_settings(
|
||||||
|
matcher.plugin_name, cmd, level
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
"[hidden]" in plugin_name.lower()
|
||||||
|
or "[admin]" in plugin_name.lower()
|
||||||
|
or "[superuser]" in plugin_name.lower()
|
||||||
|
or matcher.plugin_name in plugins2settings_manager.keys()
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
except AttributeError:
|
||||||
|
if matcher.plugin_name not in _tmp:
|
||||||
|
logger.warning(
|
||||||
|
f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载."
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
plugin_name = _module.__getattribute__("__zx_plugin_name__")
|
_tmp_module[matcher.plugin_name] = plugin_name
|
||||||
if "[admin]" in plugin_name.lower():
|
|
||||||
try:
|
try:
|
||||||
admin_settings = _module.__getattribute__(
|
plugin_settings = _module.__getattribute__(
|
||||||
"__plugin_settings__"
|
"__plugin_settings__"
|
||||||
)
|
)
|
||||||
level = admin_settings["admin_level"]
|
|
||||||
cmd = admin_settings.get("cmd")
|
|
||||||
except (AttributeError, KeyError):
|
|
||||||
level = 5
|
|
||||||
cmd = None
|
|
||||||
if level is None:
|
|
||||||
level = 5
|
|
||||||
admin_manager.add_admin_plugin_settings(
|
|
||||||
matcher.plugin_name, cmd, level
|
|
||||||
)
|
|
||||||
if (
|
|
||||||
"[hidden]" in plugin_name.lower()
|
|
||||||
or "[admin]" in plugin_name.lower()
|
|
||||||
or "[superuser]" in plugin_name.lower()
|
|
||||||
or matcher.plugin_name in plugins2settings_manager.keys()
|
|
||||||
):
|
|
||||||
continue
|
|
||||||
except AttributeError:
|
|
||||||
if matcher.plugin_name not in _tmp:
|
|
||||||
logger.warning(
|
|
||||||
f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载."
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
_tmp_module[matcher.plugin_name] = plugin_name
|
|
||||||
try:
|
|
||||||
plugin_settings = _module.__getattribute__(
|
|
||||||
"__plugin_settings__"
|
|
||||||
)
|
|
||||||
except AttributeError:
|
|
||||||
plugin_settings = {"cmd": [matcher.plugin_name, plugin_name]}
|
|
||||||
if not plugin_settings.get("cost_gold"):
|
|
||||||
plugin_settings["cost_gold"] = 0
|
|
||||||
if (
|
|
||||||
plugin_settings.get("cmd") is not None
|
|
||||||
and plugin_name not in plugin_settings["cmd"]
|
|
||||||
):
|
|
||||||
plugin_settings["cmd"].append(plugin_name)
|
|
||||||
if plugins2settings_manager.get(
|
|
||||||
matcher.plugin_name
|
|
||||||
) and plugins2settings_manager[matcher.plugin_name].get(
|
|
||||||
"plugin_type"
|
|
||||||
):
|
|
||||||
plugin_type = tuple(
|
|
||||||
plugins2settings_manager.get_plugin_data(
|
|
||||||
matcher.plugin_name
|
|
||||||
)["plugin_type"]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
plugin_type = _module.__getattribute__("__plugin_type__")
|
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
plugin_type = ("normal",)
|
plugin_settings = {"cmd": [matcher.plugin_name, plugin_name]}
|
||||||
if plugin_settings and matcher.plugin_name:
|
if not plugin_settings.get("cost_gold"):
|
||||||
plugins2settings_manager.add_plugin_settings(
|
plugin_settings["cost_gold"] = 0
|
||||||
matcher.plugin_name,
|
if (
|
||||||
plugin_type=plugin_type,
|
plugin_settings.get("cmd") is not None
|
||||||
**plugin_settings,
|
and plugin_name not in plugin_settings["cmd"]
|
||||||
)
|
):
|
||||||
|
plugin_settings["cmd"].append(plugin_name)
|
||||||
|
if plugins2settings_manager.get(
|
||||||
|
matcher.plugin_name
|
||||||
|
) and plugins2settings_manager[matcher.plugin_name].get(
|
||||||
|
"plugin_type"
|
||||||
|
):
|
||||||
|
plugin_type = tuple(
|
||||||
|
plugins2settings_manager.get_plugin_data(
|
||||||
|
matcher.plugin_name
|
||||||
|
)["plugin_type"]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
plugin_type = _module.__getattribute__("__plugin_type__")
|
||||||
|
except AttributeError:
|
||||||
|
plugin_type = ("normal",)
|
||||||
|
if plugin_settings and matcher.plugin_name:
|
||||||
|
plugins2settings_manager.add_plugin_settings(
|
||||||
|
matcher.plugin_name,
|
||||||
|
plugin_type=plugin_type,
|
||||||
|
**plugin_settings,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f'{matcher.plugin_name} 初始化 plugin_settings 发生错误 {type(e)}:{e}')
|
||||||
_tmp.append(matcher.plugin_name)
|
_tmp.append(matcher.plugin_name)
|
||||||
_tmp_data = {"PluginSettings": plugins2settings_manager.get_data()}
|
_tmp_data = {"PluginSettings": plugins2settings_manager.get_data()}
|
||||||
with open(plugins2settings_file, "w", encoding="utf8") as wf:
|
with open(plugins2settings_file, "w", encoding="utf8") as wf:
|
||||||
|
|||||||
@@ -94,13 +94,14 @@ class ConfigsManager:
|
|||||||
del self._data[module]
|
del self._data[module]
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def set_config(self, module: str, key: str, value: Any, save_simple_data: bool = False):
|
def set_config(self, module: str, key: str, value: Any, auto_save: bool = False, save_simple_data: bool = True):
|
||||||
"""
|
"""
|
||||||
设置配置值
|
设置配置值
|
||||||
:param module: 模块名
|
:param module: 模块名
|
||||||
:param key: 配置名称
|
:param key: 配置名称
|
||||||
:param value: 值
|
:param value: 值
|
||||||
:param save_simple_data: 同时保存至config.yaml
|
:param auto_save: 自动保存
|
||||||
|
:param save_simple_data: 保存至config.yaml
|
||||||
"""
|
"""
|
||||||
if module in self._data.keys():
|
if module in self._data.keys():
|
||||||
if (
|
if (
|
||||||
@@ -109,6 +110,7 @@ class ConfigsManager:
|
|||||||
):
|
):
|
||||||
self._data[module][key]["value"] = value
|
self._data[module][key]["value"] = value
|
||||||
self._simple_data[module][key] = value
|
self._simple_data[module][key] = value
|
||||||
|
if auto_save:
|
||||||
self.save(save_simple_data=save_simple_data)
|
self.save(save_simple_data=save_simple_data)
|
||||||
|
|
||||||
def set_help(self, module: str, key: str, help_: str):
|
def set_help(self, module: str, key: str, help_: str):
|
||||||
@@ -145,18 +147,12 @@ class ConfigsManager:
|
|||||||
:param default: 没有key值内容的默认返回值
|
:param default: 没有key值内容的默认返回值
|
||||||
"""
|
"""
|
||||||
key = key.upper()
|
key = key.upper()
|
||||||
# 优先使用simple_data
|
if module in self._data.keys():
|
||||||
if module in self._simple_data.keys():
|
|
||||||
for key in [key, f"{key} [LEVEL]"]:
|
for key in [key, f"{key} [LEVEL]"]:
|
||||||
if self._simple_data[module].get(key) is not None:
|
if self._data[module].get(key) is not None:
|
||||||
return self._simple_data[module][key]
|
if self._data[module][key]["value"] is None:
|
||||||
# if module in self._data.keys():
|
return self._data[module][key]["default_value"]
|
||||||
# if module in self._data.keys():
|
return self._data[module][key]["value"]
|
||||||
# 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]["value"]
|
|
||||||
# return self._data[module][key]["default_value"]
|
|
||||||
if default is not None:
|
if default is not None:
|
||||||
return default
|
return default
|
||||||
return None
|
return None
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 694 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 694 KiB After Width: | Height: | Size: 326 KiB |
@@ -15,6 +15,7 @@ from .data_source import (
|
|||||||
BilibiliSub,
|
BilibiliSub,
|
||||||
)
|
)
|
||||||
from models.level_user import LevelUser
|
from models.level_user import LevelUser
|
||||||
|
from utils.manager import group_manager
|
||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
from utils.utils import is_number, scheduler, get_bot
|
from utils.utils import is_number, scheduler, get_bot
|
||||||
from typing import Optional, Tuple, Any
|
from typing import Optional, Tuple, Any
|
||||||
@@ -160,7 +161,7 @@ async def _(
|
|||||||
async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
|
async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
|
||||||
msg = reg_group[0]
|
msg = reg_group[0]
|
||||||
id_ = (
|
id_ = (
|
||||||
f"{event.user_id}:{event.group_id}"
|
f"{event.group_id}"
|
||||||
if isinstance(event, GroupMessageEvent)
|
if isinstance(event, GroupMessageEvent)
|
||||||
else f"{event.user_id}"
|
else f"{event.user_id}"
|
||||||
)
|
)
|
||||||
@@ -267,7 +268,8 @@ async def send_sub_msg(rst: str, sub: BilibiliSub, bot: Bot):
|
|||||||
and Config.get_config("bilibili_sub", "UP_MSG_AT_ALL")
|
and Config.get_config("bilibili_sub", "UP_MSG_AT_ALL")
|
||||||
):
|
):
|
||||||
rst = "[CQ:at,qq=all]\n" + rst
|
rst = "[CQ:at,qq=all]\n" + rst
|
||||||
await bot.send_group_msg(group_id=group_id, message=Message(rst))
|
if group_manager.get_plugin_status("bilibili_sub", group_id):
|
||||||
|
await bot.send_group_msg(group_id=group_id, message=Message(rst))
|
||||||
else:
|
else:
|
||||||
await bot.send_private_msg(user_id=int(x), message=Message(rst))
|
await bot.send_private_msg(user_id=int(x), message=Message(rst))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -208,7 +208,9 @@ async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
|
|||||||
elif sub_type == "season":
|
elif sub_type == "season":
|
||||||
return await _get_season_status(id_)
|
return await _get_season_status(id_)
|
||||||
except ResponseCodeError:
|
except ResponseCodeError:
|
||||||
return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
|
logger.error(f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试...")
|
||||||
|
return None
|
||||||
|
# return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
|
||||||
# except Exception as e:
|
# except Exception as e:
|
||||||
# logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}")
|
# logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}")
|
||||||
# return "发生了预料之外的错误..请稍后再试或联系管理员....."
|
# return "发生了预料之外的错误..请稍后再试或联系管理员....."
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import platform
|
|||||||
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||||
|
|
||||||
|
|
||||||
url = "http://www.eclzz.plus"
|
url = "http://www.eclzz.cool"
|
||||||
|
|
||||||
|
|
||||||
async def get_bt_info(keyword: str, page: int):
|
async def get_bt_info(keyword: str, page: int):
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
import contextlib
|
||||||
import random
|
import random
|
||||||
import dateparser
|
import dateparser
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from typing import List, Optional
|
from typing import List, Optional, Tuple
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
from pydantic import ValidationError
|
from pydantic import ValidationError
|
||||||
from nonebot.log import logger
|
from nonebot.log import logger
|
||||||
@@ -12,7 +13,6 @@ from .base_handle import BaseHandle, BaseData, UpEvent as _UpEvent, UpChar as _U
|
|||||||
from ..config import draw_config
|
from ..config import draw_config
|
||||||
from ..util import remove_prohibited_str, cn2py
|
from ..util import remove_prohibited_str, cn2py
|
||||||
from utils.image_utils import BuildImage
|
from utils.image_utils import BuildImage
|
||||||
import asyncio
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import ujson as json
|
import ujson as json
|
||||||
@@ -29,7 +29,7 @@ class AzurChar(BaseData):
|
|||||||
|
|
||||||
|
|
||||||
class UpChar(_UpChar):
|
class UpChar(_UpChar):
|
||||||
type_: str # 舰娘类型
|
type_: str # 舰娘类型
|
||||||
|
|
||||||
|
|
||||||
class UpEvent(_UpEvent):
|
class UpEvent(_UpEvent):
|
||||||
@@ -53,7 +53,9 @@ class AzurHandle(BaseHandle[AzurChar]):
|
|||||||
type_ = ["维修", "潜艇", "重巡", "轻航", "航母"]
|
type_ = ["维修", "潜艇", "重巡", "轻航", "航母"]
|
||||||
up_pool_flag = pool_name == "活动"
|
up_pool_flag = pool_name == "活动"
|
||||||
# Up
|
# Up
|
||||||
up_ship = [x for x in self.UP_EVENT.up_char if x.zoom > 0]
|
up_ship = (
|
||||||
|
[x for x in self.UP_EVENT.up_char if x.zoom > 0] if self.UP_EVENT else []
|
||||||
|
)
|
||||||
# print(up_ship)
|
# print(up_ship)
|
||||||
acquire_char = None
|
acquire_char = None
|
||||||
if up_ship and up_pool_flag:
|
if up_ship and up_pool_flag:
|
||||||
@@ -61,19 +63,15 @@ class AzurHandle(BaseHandle[AzurChar]):
|
|||||||
# 初始化概率
|
# 初始化概率
|
||||||
cur_ = up_ship[0].zoom / 100
|
cur_ = up_ship[0].zoom / 100
|
||||||
for i in range(len(up_ship)):
|
for i in range(len(up_ship)):
|
||||||
try:
|
with contextlib.suppress(IndexError):
|
||||||
up_zoom.append((cur_, cur_ + up_ship[i+1].zoom / 100))
|
up_zoom.append((cur_, cur_ + up_ship[i + 1].zoom / 100))
|
||||||
cur_ += up_ship[i+1].zoom / 100
|
cur_ += up_ship[i + 1].zoom / 100
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
rand = random.random()
|
rand = random.random()
|
||||||
# 抽取up
|
# 抽取up
|
||||||
for i, zoom in enumerate(up_zoom):
|
for i, zoom in enumerate(up_zoom):
|
||||||
if zoom[0] <= rand <= zoom[1]:
|
if zoom[0] <= rand <= zoom[1]:
|
||||||
try:
|
with contextlib.suppress(IndexError):
|
||||||
acquire_char = [x for x in self.ALL_CHAR if x.name == up_ship[i].name][0]
|
acquire_char = [x for x in self.ALL_CHAR if x.name == up_ship[i].name][0]
|
||||||
except IndexError:
|
|
||||||
pass
|
|
||||||
# 没有up或者未抽取到up
|
# 没有up或者未抽取到up
|
||||||
if not acquire_char:
|
if not acquire_char:
|
||||||
star = self.get_star(
|
star = self.get_star(
|
||||||
@@ -92,9 +90,6 @@ class AzurHandle(BaseHandle[AzurChar]):
|
|||||||
])
|
])
|
||||||
return acquire_char
|
return acquire_char
|
||||||
|
|
||||||
# async def draw(self, count: int, **kwargs) -> Message:
|
|
||||||
# return await asyncio.get_event_loop().run_in_executor(None, self._draw, count)
|
|
||||||
|
|
||||||
async def draw(self, count: int, **kwargs) -> Message:
|
async def draw(self, count: int, **kwargs) -> Message:
|
||||||
index2card = self.get_cards(count, **kwargs)
|
index2card = self.get_cards(count, **kwargs)
|
||||||
cards = [card[0] for card in index2card]
|
cards = [card[0] for card in index2card]
|
||||||
@@ -162,22 +157,22 @@ class AzurHandle(BaseHandle[AzurChar]):
|
|||||||
return
|
return
|
||||||
dom = etree.HTML(result, etree.HTMLParser())
|
dom = etree.HTML(result, etree.HTMLParser())
|
||||||
contents = dom.xpath(
|
contents = dom.xpath(
|
||||||
"//div[@class='resp-tabs-container']/div[@class='resp-tab-content']"
|
"//div[@class='mw-body-content mw-content-ltr']/div[@class='mw-parser-output']"
|
||||||
)
|
)
|
||||||
for index, content in enumerate(contents):
|
for index, content in enumerate(contents):
|
||||||
char_list = content.xpath("./table/tbody/tr[2]/td/div/div/div/div")
|
char_list = content.xpath("./div[@id='CardSelectTr']/div")
|
||||||
for char in char_list:
|
for char in char_list:
|
||||||
try:
|
try:
|
||||||
name = char.xpath("./a/@title")[0]
|
name = char.xpath("./div/a/@title")[0]
|
||||||
frame = char.xpath("./div/a/img/@alt")[0]
|
frame = char.xpath("./div/div/a/img/@alt")[0]
|
||||||
avatar = char.xpath("./a/img/@srcset")[0]
|
avatar = char.xpath("./div/a/img/@srcset")[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
continue
|
continue
|
||||||
member_dict = {
|
member_dict = {
|
||||||
"名称": remove_prohibited_str(name),
|
"名称": remove_prohibited_str(name),
|
||||||
"头像": unquote(str(avatar).split(" ")[-2]),
|
"头像": unquote(str(avatar).split(" ")[-2]),
|
||||||
"星级": self.parse_star(frame),
|
"星级": self.parse_star(frame),
|
||||||
"类型": self.parse_type(index),
|
"类型": char.xpath("./@data-param1")[0].split(",")[1],
|
||||||
}
|
}
|
||||||
info[member_dict["名称"]] = member_dict
|
info[member_dict["名称"]] = member_dict
|
||||||
# 更新额外信息
|
# 更新额外信息
|
||||||
@@ -225,48 +220,21 @@ class AzurHandle(BaseHandle[AzurChar]):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_star(star: str) -> int:
|
def parse_star(star: str) -> int:
|
||||||
if star in ["舰娘头像外框普通.png", "舰娘头像外框白色.png"]:
|
if star in {"舰娘头像外框普通.png", "舰娘头像外框白色.png"}:
|
||||||
return 1
|
return 1
|
||||||
elif star in ["舰娘头像外框稀有.png", "舰娘头像外框蓝色.png"]:
|
elif star in {"舰娘头像外框稀有.png", "舰娘头像外框蓝色.png"}:
|
||||||
return 2
|
return 2
|
||||||
elif star in ["舰娘头像外框精锐.png", "舰娘头像外框紫色.png"]:
|
elif star in {"舰娘头像外框精锐.png", "舰娘头像外框紫色.png"}:
|
||||||
return 3
|
return 3
|
||||||
elif star in ["舰娘头像外框超稀有.png", "舰娘头像外框金色.png"]:
|
elif star in {"舰娘头像外框超稀有.png", "舰娘头像外框金色.png"}:
|
||||||
return 4
|
return 4
|
||||||
elif star in ["舰娘头像外框海上传奇.png", "舰娘头像外框彩色.png"]:
|
elif star in {"舰娘头像外框海上传奇.png", "舰娘头像外框彩色.png"}:
|
||||||
return 5
|
return 5
|
||||||
elif star in [
|
elif star in {"舰娘头像外框最高方案.png", "舰娘头像外框决战方案.png", "舰娘头像外框超稀有META.png", "舰娘头像外框精锐META.png"}:
|
||||||
"舰娘头像外框最高方案.png",
|
|
||||||
"舰娘头像外框决战方案.png",
|
|
||||||
"舰娘头像外框超稀有META.png",
|
|
||||||
"舰娘头像外框精锐META.png",
|
|
||||||
]:
|
|
||||||
return 6
|
return 6
|
||||||
else:
|
else:
|
||||||
return 6
|
return 6
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def parse_type(index: int) -> str:
|
|
||||||
azur_types = [
|
|
||||||
"驱逐",
|
|
||||||
"轻巡",
|
|
||||||
"重巡",
|
|
||||||
"超巡",
|
|
||||||
"战巡",
|
|
||||||
"战列",
|
|
||||||
"航母",
|
|
||||||
"航站",
|
|
||||||
"轻航",
|
|
||||||
"重炮",
|
|
||||||
"维修",
|
|
||||||
"潜艇",
|
|
||||||
"运输",
|
|
||||||
]
|
|
||||||
try:
|
|
||||||
return azur_types[index]
|
|
||||||
except IndexError:
|
|
||||||
return azur_types[0]
|
|
||||||
|
|
||||||
async def update_up_char(self):
|
async def update_up_char(self):
|
||||||
url = "https://wiki.biligame.com/blhx/游戏活动表"
|
url = "https://wiki.biligame.com/blhx/游戏活动表"
|
||||||
result = await self.get_url(url)
|
result = await self.get_url(url)
|
||||||
@@ -290,7 +258,7 @@ class AzurHandle(BaseHandle[AzurChar]):
|
|||||||
up_chars = []
|
up_chars = []
|
||||||
for ship in ships:
|
for ship in ships:
|
||||||
name = ship.xpath("./tbody/tr/td[2]/p/a/@title")[0]
|
name = ship.xpath("./tbody/tr/td[2]/p/a/@title")[0]
|
||||||
type_ = ship.xpath("./tbody/tr/td[2]/p/small/text()")[0] # 舰船类型
|
type_ = ship.xpath("./tbody/tr/td[2]/p/small/text()")[0] # 舰船类型
|
||||||
try:
|
try:
|
||||||
p = float(str(ship.xpath(".//sup/text()")[0]).strip("%"))
|
p = float(str(ship.xpath(".//sup/text()")[0]).strip("%"))
|
||||||
except (IndexError, ValueError):
|
except (IndexError, ValueError):
|
||||||
@@ -298,7 +266,9 @@ class AzurHandle(BaseHandle[AzurChar]):
|
|||||||
star = self.parse_star(
|
star = self.parse_star(
|
||||||
ship.xpath("./tbody/tr/td[1]/div/div/div/a/img/@alt")[0]
|
ship.xpath("./tbody/tr/td[1]/div/div/div/a/img/@alt")[0]
|
||||||
)
|
)
|
||||||
up_chars.append(UpChar(name=name, star=star, limited=False, zoom=p, type_=type_))
|
up_chars.append(
|
||||||
|
UpChar(name=name, star=star, limited=False, zoom=p, type_=type_)
|
||||||
|
)
|
||||||
self.UP_EVENT = UpEvent(
|
self.UP_EVENT = UpEvent(
|
||||||
title=title,
|
title=title,
|
||||||
pool_img="",
|
pool_img="",
|
||||||
|
|||||||
+6
-15
@@ -1,6 +1,8 @@
|
|||||||
|
from io import BytesIO
|
||||||
|
import imagehash
|
||||||
|
from PIL import Image
|
||||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||||
from configs.path_config import TEMP_PATH
|
from configs.path_config import TEMP_PATH
|
||||||
from utils.image_utils import get_img_hash
|
|
||||||
import random
|
import random
|
||||||
from utils.message_builder import image
|
from utils.message_builder import image
|
||||||
from nonebot import on_message
|
from nonebot import on_message
|
||||||
@@ -8,7 +10,6 @@ from utils.utils import get_message_img, get_message_text
|
|||||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
from nonebot.adapters.onebot.v11 import GroupMessageEvent
|
||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
from utils.http_utils import AsyncHttpx
|
from utils.http_utils import AsyncHttpx
|
||||||
from services.log import logger
|
|
||||||
from configs.config import NICKNAME
|
from configs.config import NICKNAME
|
||||||
|
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ async def _(event: GroupMessageEvent):
|
|||||||
if not img and not msg:
|
if not img and not msg:
|
||||||
return
|
return
|
||||||
if img:
|
if img:
|
||||||
img_hash = await get_fudu_img_hash(img[0], event.group_id)
|
img_hash = await get_fudu_img_hash(img[0])
|
||||||
else:
|
else:
|
||||||
img_hash = ""
|
img_hash = ""
|
||||||
add_msg = msg + "|-|" + img_hash
|
add_msg = msg + "|-|" + img_hash
|
||||||
@@ -123,15 +124,5 @@ async def _(event: GroupMessageEvent):
|
|||||||
await fudu.finish("[[_task|fudu]]" + rst)
|
await fudu.finish("[[_task|fudu]]" + rst)
|
||||||
|
|
||||||
|
|
||||||
async def get_fudu_img_hash(url, group_id):
|
async def get_fudu_img_hash(url):
|
||||||
try:
|
return str(imagehash.average_hash(Image.open(BytesIO((await AsyncHttpx.get(url)).content))))
|
||||||
if await AsyncHttpx.download_file(
|
|
||||||
url, TEMP_PATH / f"compare_{group_id}_img.jpg"
|
|
||||||
):
|
|
||||||
img_hash = get_img_hash(TEMP_PATH / f"compare_{group_id}_img.jpg")
|
|
||||||
return str(img_hash)
|
|
||||||
else:
|
|
||||||
logger.warning(f"复读下载图片失败...")
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"复读读取图片Hash出错 {type(e)}:{e}")
|
|
||||||
return ""
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ __plugin_block_limit__ = {
|
|||||||
qr = on_command("原神资源查询", aliases={"原神资源查找"}, priority=5, block=True)
|
qr = on_command("原神资源查询", aliases={"原神资源查找"}, priority=5, block=True)
|
||||||
qr_lst = on_command("原神资源列表", priority=5, block=True)
|
qr_lst = on_command("原神资源列表", priority=5, block=True)
|
||||||
rex_qr = on_regex(".*?(在哪|在哪里|哪有|哪里有).*?", priority=5, block=True)
|
rex_qr = on_regex(".*?(在哪|在哪里|哪有|哪里有).*?", priority=5, block=True)
|
||||||
update_info = on_command("更新原神资源信息", permission=SUPERUSER, priority=1, block=True)
|
update_info = on_regex("^更新原神资源信息$", permission=SUPERUSER, priority=1, block=True)
|
||||||
|
|
||||||
|
|
||||||
@qr.handle()
|
@qr.handle()
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class Map:
|
|||||||
self._generate_best_route()
|
self._generate_best_route()
|
||||||
self.map.crop((min_width, min_height, max_width, max_height))
|
self.map.crop((min_width, min_height, max_width, max_height))
|
||||||
rand = random.randint(1, 10000)
|
rand = random.randint(1, 10000)
|
||||||
self.map.save(f"{IMAGE_PATH}/temp/genshin_map_{rand}.png")
|
self.map.save(f"{TEXT_PATH}/genshin_map_{rand}.png")
|
||||||
return rand
|
return rand
|
||||||
|
|
||||||
# 资源数量
|
# 资源数量
|
||||||
|
|||||||
@@ -172,28 +172,29 @@ async def download_map_init(semaphore: Semaphore, flag: bool = False):
|
|||||||
if data["message"] == "OK":
|
if data["message"] == "OK":
|
||||||
data = json.loads(data["data"]["info"]["detail"])
|
data = json.loads(data["data"]["info"]["detail"])
|
||||||
CENTER_POINT = (data["origin"][0], data["origin"][1])
|
CENTER_POINT = (data["origin"][0], data["origin"][1])
|
||||||
if not _map.exists():
|
if not _map.exists() or flag:
|
||||||
data = data["slices"]
|
data = data["slices"]
|
||||||
idx = 0
|
idx = 0
|
||||||
for _map_data in data[0]:
|
w_len = len(data[0])
|
||||||
map_url = _map_data["url"]
|
h_len = len(data)
|
||||||
await download_image(
|
for _map_data in data:
|
||||||
map_url,
|
for _map in _map_data:
|
||||||
map_path / f"{idx}.png",
|
map_url = _map["url"]
|
||||||
semaphore,
|
await download_image(
|
||||||
force_flag=flag,
|
map_url,
|
||||||
)
|
map_path / f"{idx}.png",
|
||||||
BuildImage(
|
semaphore,
|
||||||
0, 0, background=f"{map_path}/{idx}.png", ratio=MAP_RATIO
|
force_flag=flag,
|
||||||
).save()
|
)
|
||||||
idx += 1
|
BuildImage(
|
||||||
_w, h = BuildImage(0, 0, background=f"{map_path}/0.png").size
|
0, 0, background=f"{map_path}/{idx}.png", ratio=MAP_RATIO
|
||||||
w = _w * len(os.listdir(map_path))
|
).save()
|
||||||
map_file = BuildImage(w, h, _w, h, ratio=MAP_RATIO)
|
idx += 1
|
||||||
|
w, h = BuildImage(0, 0, background=f"{map_path}/0.png").size
|
||||||
|
map_file = BuildImage(w * w_len, h * h_len, w, h, ratio=MAP_RATIO)
|
||||||
for i in range(idx):
|
for i in range(idx):
|
||||||
map_file.paste(
|
img = BuildImage(0, 0, background=f"{map_path}/{i}.png")
|
||||||
BuildImage(0, 0, background=f"{map_path}/{i}.png")
|
await map_file.apaste(img)
|
||||||
)
|
|
||||||
map_file.save(f"{map_path}/map.png")
|
map_file.save(f"{map_path}/map.png")
|
||||||
else:
|
else:
|
||||||
logger.warning(f'获取原神地图失败 msg: {data["message"]}')
|
logger.warning(f'获取原神地图失败 msg: {data["message"]}')
|
||||||
@@ -202,7 +203,7 @@ async def download_map_init(semaphore: Semaphore, flag: bool = False):
|
|||||||
except (TimeoutError, ConnectTimeout):
|
except (TimeoutError, ConnectTimeout):
|
||||||
logger.warning("下载原神地图数据超时....")
|
logger.warning("下载原神地图数据超时....")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"下载原神地图数据超时 {type(e)}:{e}")
|
logger.error(f"下载原神地图数据失败 {type(e)}:{e}")
|
||||||
|
|
||||||
|
|
||||||
# 下载资源类型数据
|
# 下载资源类型数据
|
||||||
|
|||||||
@@ -93,6 +93,8 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message
|
|||||||
print(cookie)
|
print(cookie)
|
||||||
cookie_json = json.loads(cookie)
|
cookie_json = json.loads(cookie)
|
||||||
print(cookie_json)
|
print(cookie_json)
|
||||||
|
if 'login_ticket' not in cookie_json:
|
||||||
|
await bind.finish("请发送正确完整的cookie!")
|
||||||
login_ticket = cookie_json['login_ticket']
|
login_ticket = cookie_json['login_ticket']
|
||||||
# try:
|
# try:
|
||||||
res = await AsyncHttpx.get(url=bbs_Cookie_url.format(login_ticket))
|
res = await AsyncHttpx.get(url=bbs_Cookie_url.format(login_ticket))
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
|
|||||||
uid = await Genshin.get_user_uid(event.user_id)
|
uid = await Genshin.get_user_uid(event.user_id)
|
||||||
if cmd == "查看我的cookie":
|
if cmd == "查看我的cookie":
|
||||||
my_cookie = await Genshin.get_user_cookie(uid, True)
|
my_cookie = await Genshin.get_user_cookie(uid, True)
|
||||||
|
if isinstance(event, GroupMessageEvent):
|
||||||
|
await genshin_matcher.finish("请私聊查看您的cookie!")
|
||||||
await genshin_matcher.finish("您的cookie为" + my_cookie)
|
await genshin_matcher.finish("您的cookie为" + my_cookie)
|
||||||
if not uid or not await Genshin.get_user_cookie(uid, True):
|
if not uid or not await Genshin.get_user_cookie(uid, True):
|
||||||
await genshin_matcher.finish("请先绑定uid和cookie!")
|
await genshin_matcher.finish("请先绑定uid和cookie!")
|
||||||
@@ -51,9 +53,9 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
|
|||||||
# await genshin_matcher.finish("请更新cookie!")
|
# await genshin_matcher.finish("请更新cookie!")
|
||||||
if cmd == "原神我硬签":
|
if cmd == "原神我硬签":
|
||||||
try:
|
try:
|
||||||
|
await genshin_matcher.send("正在进行签到...", at_sender=True)
|
||||||
msg = await genshin_sign(uid)
|
msg = await genshin_sign(uid)
|
||||||
return_data = await mihoyobbs_sign(event.user_id)
|
return_data = await mihoyobbs_sign(event.user_id)
|
||||||
await genshin_matcher.send(return_data)
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"(USER {event.user_id}, "
|
f"(USER {event.user_id}, "
|
||||||
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) UID:{uid} 原神签到"
|
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) UID:{uid} 原神签到"
|
||||||
@@ -70,7 +72,7 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
|
|||||||
await u.clear_sign_time(uid)
|
await u.clear_sign_time(uid)
|
||||||
next_date = await Genshin.random_sign_time(uid)
|
next_date = await Genshin.random_sign_time(uid)
|
||||||
add_job(event.user_id, uid, next_date)
|
add_job(event.user_id, uid, next_date)
|
||||||
msg += f"\n因开启自动签到\n下一次签到时间为:{next_date.replace(microsecond=0)}"
|
msg += f"\n{return_data}\n因开启自动签到\n下一次签到时间为:{next_date.replace(microsecond=0)}"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = "原神签到失败..请尝试检查cookie或报告至管理员!"
|
msg = "原神签到失败..请尝试检查cookie或报告至管理员!"
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|||||||
@@ -38,16 +38,18 @@ mihoyobbs_matcher = on_command(
|
|||||||
|
|
||||||
@mihoyobbs_matcher.handle()
|
@mihoyobbs_matcher.handle()
|
||||||
async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
|
async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
|
||||||
await mihoyobbs_matcher.send("提交米游社签到申请")
|
await mihoyobbs_matcher.send("提交米游社签到申请", at_sender=True)
|
||||||
return_data = await mihoyobbs_sign(event.user_id)
|
return_data = await mihoyobbs_sign(event.user_id)
|
||||||
if return_data:
|
if return_data:
|
||||||
await mihoyobbs_matcher.finish(return_data)
|
await mihoyobbs_matcher.finish(return_data, at_sender=True)
|
||||||
else:
|
else:
|
||||||
await mihoyobbs_matcher.finish("米游社签到失败,请查看控制台输出")
|
await mihoyobbs_matcher.finish("米游社签到失败,请查看控制台输出", at_sender=True)
|
||||||
|
|
||||||
|
|
||||||
async def mihoyobbs_sign(user_id):
|
async def mihoyobbs_sign(user_id):
|
||||||
uid = await Genshin.get_user_uid(user_id)
|
uid = await Genshin.get_user_uid(user_id)
|
||||||
|
if not uid or not await Genshin.get_user_cookie(uid, True):
|
||||||
|
await mihoyobbs_matcher.finish("请先绑定uid和cookie!", at_sender=True)
|
||||||
stuid = await Genshin.get_stuid(uid)
|
stuid = await Genshin.get_stuid(uid)
|
||||||
stoken = await Genshin.get_stoken(uid)
|
stoken = await Genshin.get_stoken(uid)
|
||||||
cookie = await Genshin.get_user_cookie(uid)
|
cookie = await Genshin.get_user_cookie(uid)
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ async def _():
|
|||||||
"20.png?x-oss-process=image//resize,s_600/quality,q_80/auto-orient,0/interlace,1/format,png",
|
"20.png?x-oss-process=image//resize,s_600/quality,q_80/auto-orient,0/interlace,1/format,png",
|
||||||
"https://patchwiki.biligame.com/images/ys/thumb/c/cc/6k6kuj1kte6m1n7hexqfrn92z6h4yhh.png/60px-委托任务logo.png",
|
"https://patchwiki.biligame.com/images/ys/thumb/c/cc/6k6kuj1kte6m1n7hexqfrn92z6h4yhh.png/60px-委托任务logo.png",
|
||||||
"https://patchwiki.biligame.com/images/ys/d/d9/t1hv6wpucbwucgkhjntmzroh90nmcdv.png",
|
"https://patchwiki.biligame.com/images/ys/d/d9/t1hv6wpucbwucgkhjntmzroh90nmcdv.png",
|
||||||
"https://s3.bmp.ovh/imgs/2022/07/24/28d9338c7da4bcb2.png",
|
"https://s3.bmp.ovh/imgs/2022/08/21/3a3b2e6c22e305ff.png",
|
||||||
"https://genshin.honeyhunterworld.com/img/gadget/i_3016.png",
|
"https://s3.bmp.ovh/imgs/2022/08/21/c2d7ace21e1d46cf.png",
|
||||||
],
|
],
|
||||||
):
|
):
|
||||||
file = memo_path / name
|
file = memo_path / name
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ def parsed_data(
|
|||||||
"magic_chest_number": data["stats"]["magic_chest_number"], # 奇馈宝箱
|
"magic_chest_number": data["stats"]["magic_chest_number"], # 奇馈宝箱
|
||||||
"common_chest_number": data["stats"]["common_chest_number"], # 普通宝箱
|
"common_chest_number": data["stats"]["common_chest_number"], # 普通宝箱
|
||||||
"electroculus_number": data["stats"]["electroculus_number"], # 雷神瞳已收集
|
"electroculus_number": data["stats"]["electroculus_number"], # 雷神瞳已收集
|
||||||
|
"dendroculus_number": data["stats"]["dendroculus_number"], # 草神瞳已收集
|
||||||
}
|
}
|
||||||
world_data_dict = {}
|
world_data_dict = {}
|
||||||
for world in data["world_explorations"]:
|
for world in data["world_explorations"]:
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ def get_user_data_image(
|
|||||||
"""
|
"""
|
||||||
if mys_data:
|
if mys_data:
|
||||||
nickname = [x["nickname"] for x in mys_data if x["game_id"] == 2][0]
|
nickname = [x["nickname"] for x in mys_data if x["game_id"] == 2][0]
|
||||||
region = BuildImage(1440, 450, color="#E3DBD1", font="HYWenHei-85W.ttf")
|
region = BuildImage(1440, 560, color="#E3DBD1", font="HYWenHei-85W.ttf")
|
||||||
region.circle_corner(30)
|
region.circle_corner(30)
|
||||||
uname_img = BuildImage(
|
uname_img = BuildImage(
|
||||||
0,
|
0,
|
||||||
@@ -163,36 +163,42 @@ def get_user_data_image(
|
|||||||
/ random.choice(os.listdir(image_path / "chars_ava")),
|
/ random.choice(os.listdir(image_path / "chars_ava")),
|
||||||
)
|
)
|
||||||
ava_bk.paste(ava_img, (12, 16), alpha=True)
|
ava_bk.paste(ava_img, (12, 16), alpha=True)
|
||||||
region.paste(uname_img, (int(170 + uid_img.w / 2 - uname_img.w / 2), 305), True)
|
region.paste(uname_img, (int(170 + uid_img.w / 2 - uname_img.w / 2), 365), True)
|
||||||
region.paste(uid_img, (170, 355), True)
|
region.paste(uid_img, (170, 415), True)
|
||||||
region.paste(ava_bk, (int(550 / 2 - ava_bk.w / 2), 40), True)
|
region.paste(ava_bk, (int(550 / 2 - ava_bk.w / 2), 100), True)
|
||||||
data_img = BuildImage(
|
data_img = BuildImage(
|
||||||
800, 400, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
800, 510, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
||||||
)
|
)
|
||||||
_height = 0
|
_height = 0
|
||||||
keys = [
|
keys = [
|
||||||
["活跃天数", "成就达成", "获得角色", "深境螺旋"],
|
["活跃天数", "成就达成", "获得角色", "解锁传送"],
|
||||||
["华丽宝箱", "珍贵宝箱", "精致宝箱", "普通宝箱"],
|
["风神瞳", "岩神瞳", "雷神瞳", "草神瞳"],
|
||||||
["奇馈宝箱", "风神瞳", "岩神瞳", "雷神瞳"],
|
["解锁秘境", "深境螺旋", "华丽宝箱", "珍贵宝箱"],
|
||||||
|
["精致宝箱", "普通宝箱", "奇馈宝箱",],
|
||||||
]
|
]
|
||||||
values = [
|
values = [
|
||||||
[
|
[
|
||||||
role_data["active_day_number"],
|
role_data["active_day_number"],
|
||||||
role_data["achievement_number"],
|
role_data["achievement_number"],
|
||||||
role_data["avatar_number"],
|
role_data["avatar_number"],
|
||||||
role_data["spiral_abyss"],
|
role_data["way_point_number"],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
role_data["luxurious_chest_number"],
|
|
||||||
role_data["precious_chest_number"],
|
|
||||||
role_data["exquisite_chest_number"],
|
|
||||||
role_data["common_chest_number"],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
role_data["magic_chest_number"],
|
|
||||||
role_data["anemoculus_number"],
|
role_data["anemoculus_number"],
|
||||||
role_data["geoculus_number"],
|
role_data["geoculus_number"],
|
||||||
role_data["electroculus_number"],
|
role_data["electroculus_number"],
|
||||||
|
role_data["dendroculus_number"],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
role_data["domain_number"],
|
||||||
|
role_data["spiral_abyss"],
|
||||||
|
role_data["luxurious_chest_number"],
|
||||||
|
role_data["precious_chest_number"],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
role_data["exquisite_chest_number"],
|
||||||
|
role_data["common_chest_number"],
|
||||||
|
role_data["magic_chest_number"],
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
for key, value in zip(keys, values):
|
for key, value in zip(keys, values):
|
||||||
@@ -215,7 +221,7 @@ def get_user_data_image(
|
|||||||
)
|
)
|
||||||
tmp_.text((0, 0), str(v), center_type="by_width")
|
tmp_.text((0, 0), str(v), center_type="by_width")
|
||||||
tmp_.paste(t_, (0, 50), True, "by_width")
|
tmp_.paste(t_, (0, 50), True, "by_width")
|
||||||
_tmp_data_img.paste(tmp_, (_width if len(key) > 3 else _width + 15, 0))
|
_tmp_data_img.paste(tmp_, ((_width + 15) if keys.index(key) == 1 else _width, 0))
|
||||||
_width += 200
|
_width += 200
|
||||||
data_img.paste(_tmp_data_img, (0, _height))
|
data_img.paste(_tmp_data_img, (0, _height))
|
||||||
_height += _tmp_data_img.h - 70
|
_height += _tmp_data_img.h - 70
|
||||||
@@ -228,7 +234,7 @@ def get_home_data_image(home_data_list: List[Dict]) -> BuildImage:
|
|||||||
画出家园数据
|
画出家园数据
|
||||||
:param home_data_list: 家园列表
|
:param home_data_list: 家园列表
|
||||||
"""
|
"""
|
||||||
h = 130 + 300 * 4
|
h = 130 + 340 * 4
|
||||||
region = BuildImage(
|
region = BuildImage(
|
||||||
550, h, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
550, h, color="#E3DBD1", font="HYWenHei-85W.ttf", font_size=40
|
||||||
)
|
)
|
||||||
@@ -287,7 +293,7 @@ def get_home_data_image(home_data_list: List[Dict]) -> BuildImage:
|
|||||||
x.paste(black_img, alpha=True, center_type="center")
|
x.paste(black_img, alpha=True, center_type="center")
|
||||||
x.circle_corner(50)
|
x.circle_corner(50)
|
||||||
region.paste(x, (0, height), True, "by_width")
|
region.paste(x, (0, height), True, "by_width")
|
||||||
height += 300
|
height += 340
|
||||||
return region
|
return region
|
||||||
|
|
||||||
|
|
||||||
@@ -297,9 +303,9 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
|
|||||||
:param world_data_dict: 国家数据字典
|
:param world_data_dict: 国家数据字典
|
||||||
"""
|
"""
|
||||||
# 层岩巨渊 和 地下矿区 算一个
|
# 层岩巨渊 和 地下矿区 算一个
|
||||||
region = BuildImage(790, 267 * (len(world_data_dict) - 1), color="#F9F6F2")
|
region = BuildImage(790, 267 * ((len(world_data_dict) - 1) if world_data_dict.get("层岩巨渊·地下矿区") else len(world_data_dict)), color="#F9F6F2")
|
||||||
height = 0
|
height = 0
|
||||||
for country in ["蒙德", "龙脊雪山", "璃月", "层岩巨渊", "稻妻", "渊下宫"]:
|
for country in ["蒙德", "龙脊雪山", "璃月", "层岩巨渊", "稻妻", "渊下宫", "须弥"]:
|
||||||
if not world_data_dict.get(country):
|
if not world_data_dict.get(country):
|
||||||
continue
|
continue
|
||||||
x = BuildImage(790, 250, color="#3A4467")
|
x = BuildImage(790, 250, color="#3A4467")
|
||||||
@@ -311,15 +317,15 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
|
|||||||
)
|
)
|
||||||
content_bk.paste(logo, (50, 0), True, "by_height")
|
content_bk.paste(logo, (50, 0), True, "by_height")
|
||||||
if country in ["蒙德", "璃月"]:
|
if country in ["蒙德", "璃月"]:
|
||||||
content_bk.text((300, 40), "探索", fill=(239, 211, 114))
|
content_bk.text((300, 40), "蒙德探索" if country == "蒙德" else "璃月探索", fill=(239, 211, 114))
|
||||||
content_bk.text(
|
content_bk.text(
|
||||||
(450, 40),
|
(500, 40),
|
||||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||||
fill=(255, 255, 255),
|
fill=(255, 255, 255),
|
||||||
)
|
)
|
||||||
content_bk.text((300, 120), "声望", fill=(239, 211, 114))
|
content_bk.text((300, 120), "蒙德声望" if country == "蒙德" else "璃月声望", fill=(239, 211, 114))
|
||||||
content_bk.text(
|
content_bk.text(
|
||||||
(450, 120),
|
(500, 120),
|
||||||
f"Lv.{world_data_dict[country]['level']}",
|
f"Lv.{world_data_dict[country]['level']}",
|
||||||
fill=(255, 255, 255),
|
fill=(255, 255, 255),
|
||||||
)
|
)
|
||||||
@@ -344,45 +350,65 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
|
|||||||
fill=(255, 255, 255),
|
fill=(255, 255, 255),
|
||||||
)
|
)
|
||||||
elif country in ["龙脊雪山"]:
|
elif country in ["龙脊雪山"]:
|
||||||
content_bk.text((300, 40), "探索", fill=(239, 211, 114))
|
content_bk.text((300, 40), "雪山探索", fill=(239, 211, 114))
|
||||||
content_bk.text(
|
content_bk.text(
|
||||||
(450, 40),
|
(500, 40),
|
||||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||||
fill=(255, 255, 255),
|
fill=(255, 255, 255),
|
||||||
)
|
)
|
||||||
content_bk.text((300, 120), "供奉", fill=(239, 211, 114))
|
content_bk.text((300, 120), "忍冬之树", fill=(239, 211, 114))
|
||||||
content_bk.text(
|
content_bk.text(
|
||||||
(450, 120),
|
(500, 120),
|
||||||
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
|
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
|
||||||
fill=(255, 255, 255),
|
fill=(255, 255, 255),
|
||||||
)
|
)
|
||||||
elif country in ["稻妻"]:
|
elif country in ["稻妻"]:
|
||||||
content_bk.text((300, 20), "探索", fill=(239, 211, 114))
|
content_bk.text((300, 20), "稻妻探索", fill=(239, 211, 114))
|
||||||
content_bk.text(
|
content_bk.text(
|
||||||
(450, 20),
|
(500, 20),
|
||||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||||
fill=(255, 255, 255),
|
fill=(255, 255, 255),
|
||||||
)
|
)
|
||||||
content_bk.text((300, 85), "声望", fill=(239, 211, 114))
|
content_bk.text((300, 85), "稻妻声望", fill=(239, 211, 114))
|
||||||
content_bk.text(
|
content_bk.text(
|
||||||
(450, 85),
|
(500, 85),
|
||||||
f"Lv.{world_data_dict[country]['level']}",
|
f"Lv.{world_data_dict[country]['level']}",
|
||||||
fill=(255, 255, 255),
|
fill=(255, 255, 255),
|
||||||
)
|
)
|
||||||
content_bk.text((300, 150), "神樱", fill=(239, 211, 114))
|
content_bk.text((300, 150), "神樱眷顾", fill=(239, 211, 114))
|
||||||
content_bk.text(
|
content_bk.text(
|
||||||
(450, 150),
|
(500, 150),
|
||||||
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
|
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
|
||||||
fill=(255, 255, 255),
|
fill=(255, 255, 255),
|
||||||
)
|
)
|
||||||
elif country in ["渊下宫"]:
|
elif country in ["渊下宫"]:
|
||||||
content_bk.text((300, 0), "探索", fill=(239, 211, 114), center_type="by_height")
|
content_bk.text((300, 0), "渊下宫探索", fill=(239, 211, 114), center_type="by_height")
|
||||||
content_bk.text(
|
content_bk.text(
|
||||||
(450, 20),
|
(530, 20),
|
||||||
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||||
fill=(255, 255, 255),
|
fill=(255, 255, 255),
|
||||||
center_type="by_height",
|
center_type="by_height",
|
||||||
)
|
)
|
||||||
|
elif country in ["须弥"]:
|
||||||
|
content_bk.text((300, 20), "须弥探索", fill=(239, 211, 114))
|
||||||
|
content_bk.text(
|
||||||
|
(500, 20),
|
||||||
|
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
|
||||||
|
fill=(255, 255, 255),
|
||||||
|
)
|
||||||
|
content_bk.text((300, 85), "须弥声望", fill=(239, 211, 114))
|
||||||
|
content_bk.text(
|
||||||
|
(500, 85),
|
||||||
|
f"Lv.{world_data_dict[country]['level']}",
|
||||||
|
fill=(255, 255, 255),
|
||||||
|
)
|
||||||
|
content_bk.text((300, 150), "梦之树", fill=(239, 211, 114))
|
||||||
|
content_bk.text(
|
||||||
|
(500, 150),
|
||||||
|
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
|
||||||
|
fill=(255, 255, 255),
|
||||||
|
)
|
||||||
|
|
||||||
x.paste(tmp_bk, alpha=True, center_type="center")
|
x.paste(tmp_bk, alpha=True, center_type="center")
|
||||||
x.paste(content_bk, alpha=True, center_type="center")
|
x.paste(content_bk, alpha=True, center_type="center")
|
||||||
x.circle_corner(20)
|
x.circle_corner(20)
|
||||||
|
|||||||
+7
-5
@@ -1,3 +1,7 @@
|
|||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
import imagehash
|
||||||
|
from PIL import Image
|
||||||
from nonebot import on_message, on_command
|
from nonebot import on_message, on_command
|
||||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, ActionFailed
|
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, ActionFailed
|
||||||
from nonebot.adapters.onebot.v11.permission import GROUP
|
from nonebot.adapters.onebot.v11.permission import GROUP
|
||||||
@@ -70,10 +74,8 @@ def save_data():
|
|||||||
json.dump(mute_data, f, indent=4)
|
json.dump(mute_data, f, indent=4)
|
||||||
|
|
||||||
|
|
||||||
async def download_img_and_hash(url, group_id) -> str:
|
async def download_img_and_hash(url) -> str:
|
||||||
if await AsyncHttpx.download_file(url, TEMP_PATH / f"mute_{group_id}_img.jpg"):
|
return str(imagehash.average_hash(Image.open(BytesIO((await AsyncHttpx.get(url)).content))))
|
||||||
return str(get_img_hash(TEMP_PATH / f"mute_{group_id}_img.jpg"))
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
mute_dict = {}
|
mute_dict = {}
|
||||||
@@ -87,7 +89,7 @@ async def _(bot: Bot, event: GroupMessageEvent):
|
|||||||
img_list = get_message_img(event.json())
|
img_list = get_message_img(event.json())
|
||||||
img_hash = ""
|
img_hash = ""
|
||||||
for img in img_list:
|
for img in img_list:
|
||||||
img_hash += await download_img_and_hash(img, event.group_id)
|
img_hash += await download_img_and_hash(img)
|
||||||
msg += img_hash
|
msg += img_hash
|
||||||
if not mute_data.get(group_id):
|
if not mute_data.get(group_id):
|
||||||
mute_data[group_id] = {
|
mute_data[group_id] = {
|
||||||
|
|||||||
@@ -110,10 +110,10 @@ async def _(event: GroupMessageEvent):
|
|||||||
vd_info = await video.get_video_base_info(msg)
|
vd_info = await video.get_video_base_info(msg)
|
||||||
elif "av" in msg:
|
elif "av" in msg:
|
||||||
index = msg.find("av")
|
index = msg.find("av")
|
||||||
if len(msg[index + 2 :]) >= 9:
|
if len(msg[index + 2 :]) >= 1:
|
||||||
msg = msg[index + 2 : index + 11]
|
msg = msg[index + 2 : index + 11]
|
||||||
if is_number(msg):
|
if is_number(msg):
|
||||||
url = f"https://www.bilibili.com/video/{msg}"
|
url = f"https://www.bilibili.com/video/av{msg}"
|
||||||
vd_info = await video.get_video_base_info('av' + msg)
|
vd_info = await video.get_video_base_info('av' + msg)
|
||||||
elif "https://b23.tv" in msg:
|
elif "https://b23.tv" in msg:
|
||||||
url = "https://" + msg[msg.find("b23.tv"): msg.find("b23.tv") + 14]
|
url = "https://" + msg[msg.find("b23.tv"): msg.find("b23.tv") + 14]
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ __plugin_settings__ = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
quotations = on_regex("^[语录|二次元]$", priority=5, block=True)
|
quotations = on_regex("^(语录|二次元)$", priority=5, block=True)
|
||||||
|
|
||||||
url = "https://international.v1.hitokoto.cn/?c=a"
|
url = "https://international.v1.hitokoto.cn/?c=a"
|
||||||
|
|
||||||
|
|||||||
@@ -81,19 +81,15 @@ async def _handle_check_in(
|
|||||||
await BagUser.add_gold(user_qq, group, gold)
|
await BagUser.add_gold(user_qq, group, gold)
|
||||||
await BagUser.add_property(user_qq, group, gift)
|
await BagUser.add_property(user_qq, group, gift)
|
||||||
gift += ' + 1'
|
gift += ' + 1'
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"(USER {user.user_qq}, GROUP {user.group_id})"
|
||||||
|
f" CHECKED IN successfully. score: {user.impression:.2f} "
|
||||||
|
f"(+{impression_added:.2f}).获取金币:{gold + gift if gift == 'gold' else gold}"
|
||||||
|
)
|
||||||
if critx2 + add_probability > 0.97 or critx2 < specify_probability:
|
if critx2 + add_probability > 0.97 or critx2 < specify_probability:
|
||||||
logger.info(
|
|
||||||
f"(USER {user.user_qq}, GROUP {user.group_id})"
|
|
||||||
f" CHECKED IN successfully. score: {user.impression:.2f} "
|
|
||||||
f"(+{impression_added * 2:.2f}).获取金币:{gold + gift if gift == 'gold' else gold}"
|
|
||||||
)
|
|
||||||
return await get_card(user, nickname, impression_added, gold, gift, True)
|
return await get_card(user, nickname, impression_added, gold, gift, True)
|
||||||
else:
|
else:
|
||||||
logger.info(
|
|
||||||
f"(USER {user.user_qq}, GROUP {user.group_id})"
|
|
||||||
f" CHECKED IN successfully. score: {user.impression:.2f} "
|
|
||||||
f"(+{impression_added:.2f}).获取金币:{gold + gift if gift == 'gold' else gold}"
|
|
||||||
)
|
|
||||||
return await get_card(user, nickname, impression_added, gold, gift)
|
return await get_card(user, nickname, impression_added, gold, gift)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import random
|
||||||
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from nonebot.adapters.onebot.v11 import Message, MessageSegment
|
from nonebot.adapters.onebot.v11 import Message, MessageSegment
|
||||||
@@ -187,20 +189,45 @@ async def _():
|
|||||||
if await WordBank.get_group_all_problem(0):
|
if await WordBank.get_group_all_problem(0):
|
||||||
return
|
return
|
||||||
logger.info('开始迁移词条 纯文本 数据')
|
logger.info('开始迁移词条 纯文本 数据')
|
||||||
word_list = await OldWordBank.get_all()
|
try:
|
||||||
for word in word_list:
|
word_list = await OldWordBank.get_all()
|
||||||
problem: str = word.problem
|
new_answer_path = Path() / 'data' / 'word_bank' / 'answer'
|
||||||
user_id = word.user_qq
|
new_problem_path = Path() / 'data' / 'word_bank' / 'problem'
|
||||||
group_id = word.group_id
|
new_answer_path.mkdir(exist_ok=True, parents=True)
|
||||||
format_ = word.format
|
for word in word_list:
|
||||||
answer = word.answer
|
problem: str = word.problem
|
||||||
# 仅对纯文本做处理
|
user_id = word.user_qq
|
||||||
if '[CQ' not in problem and '[CQ' not in answer and '[_to_me' not in problem:
|
group_id = word.group_id
|
||||||
if not format_:
|
format_ = word.format
|
||||||
await WordBank.add_problem_answer(user_id, group_id, 1, 0, problem, answer)
|
answer = word.answer
|
||||||
await WordBank.add_problem_answer(0, 0, 999, 0, '_[OK', '_[OK')
|
# 仅对纯文本做处理
|
||||||
logger.info('词条 纯文本 数据迁移完成')
|
if '[CQ' not in problem and '[CQ' not in answer and '[_to_me' not in problem:
|
||||||
(Path() / 'plugins' / 'word_bank' / '_old_model.py').unlink()
|
if not format_:
|
||||||
|
await WordBank.add_problem_answer(user_id, group_id, 1, 0, problem, answer)
|
||||||
|
else:
|
||||||
|
placeholder = []
|
||||||
|
for m in format_.split('<format>'):
|
||||||
|
x = m.split('<_s>')
|
||||||
|
if x[0]:
|
||||||
|
idx, file_name = x[0], x[1]
|
||||||
|
if 'jpg' in file_name:
|
||||||
|
answer = answer.replace(f'[__placeholder_{idx}]', f'[image:placeholder_{idx}]')
|
||||||
|
file = Path() / 'data' / 'word_bank' / f'{group_id}' / file_name
|
||||||
|
rand = int(time.time()) + random.randint(1, 100000)
|
||||||
|
if file.exists():
|
||||||
|
new_file = new_answer_path / f'{group_id}' / f'{user_id}_{rand}.jpg'
|
||||||
|
new_file.parent.mkdir(exist_ok=True, parents=True)
|
||||||
|
with open(file, 'rb') as rb:
|
||||||
|
with open(new_file, 'wb') as wb:
|
||||||
|
wb.write(rb.read())
|
||||||
|
# file.rename(new_file)
|
||||||
|
placeholder.append(f'answer/{group_id}/{user_id}_{rand}.jpg')
|
||||||
|
await WordBank._move(user_id, group_id, problem, answer, ",".join(placeholder))
|
||||||
|
await WordBank.add_problem_answer(0, 0, 999, 0, '_[OK', '_[OK')
|
||||||
|
logger.info('词条 纯文本 数据迁移完成')
|
||||||
|
(Path() / 'plugins' / 'word_bank' / '_old_model.py').unlink()
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f'迁移词条发生错误,如果为首次安装请无视 {type(e)}:{e}')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+84
-22
@@ -48,6 +48,7 @@ class WordBank(db.Model):
|
|||||||
user_id: Optional[int],
|
user_id: Optional[int],
|
||||||
group_id: Optional[int],
|
group_id: Optional[int],
|
||||||
problem: str,
|
problem: str,
|
||||||
|
answer: Optional[str],
|
||||||
word_scope: Optional[int] = None,
|
word_scope: Optional[int] = None,
|
||||||
word_type: Optional[int] = None,
|
word_type: Optional[int] = None,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
@@ -58,6 +59,7 @@ class WordBank(db.Model):
|
|||||||
:param user_id: 用户id
|
:param user_id: 用户id
|
||||||
:param group_id: 群号
|
:param group_id: 群号
|
||||||
:param problem: 问题
|
:param problem: 问题
|
||||||
|
:param answer: 回答
|
||||||
:param word_scope: 词条范围
|
:param word_scope: 词条范围
|
||||||
:param word_type: 词条类型
|
:param word_type: 词条类型
|
||||||
"""
|
"""
|
||||||
@@ -66,6 +68,8 @@ class WordBank(db.Model):
|
|||||||
query = query.where(cls.user_qq == user_id)
|
query = query.where(cls.user_qq == user_id)
|
||||||
if group_id:
|
if group_id:
|
||||||
query = query.where(cls.group_id == group_id)
|
query = query.where(cls.group_id == group_id)
|
||||||
|
if answer:
|
||||||
|
query = query.where(cls.answer == answer)
|
||||||
if word_type:
|
if word_type:
|
||||||
query = query.where(cls.word_type == word_type)
|
query = query.where(cls.word_type == word_type)
|
||||||
if word_scope:
|
if word_scope:
|
||||||
@@ -105,19 +109,20 @@ class WordBank(db.Model):
|
|||||||
problem = str(get_img_hash(_file))
|
problem = str(get_img_hash(_file))
|
||||||
image_path = f"problem/{group_id}/{user_id}_{int(time.time())}.jpg"
|
image_path = f"problem/{group_id}/{user_id}_{int(time.time())}.jpg"
|
||||||
answer, _list = await cls._answer2format(answer, user_id, group_id)
|
answer, _list = await cls._answer2format(answer, user_id, group_id)
|
||||||
await cls.create(
|
if not await cls.exists(user_id, group_id, problem, answer, word_scope, word_type):
|
||||||
user_qq=user_id,
|
await cls.create(
|
||||||
group_id=group_id,
|
user_qq=user_id,
|
||||||
word_scope=word_scope,
|
group_id=group_id,
|
||||||
word_type=word_type,
|
word_scope=word_scope,
|
||||||
status=True,
|
word_type=word_type,
|
||||||
problem=problem,
|
status=True,
|
||||||
answer=answer,
|
problem=problem,
|
||||||
image_path=image_path,
|
answer=answer,
|
||||||
placeholder=",".join(_list),
|
image_path=image_path,
|
||||||
create_time=datetime.now().replace(microsecond=0),
|
placeholder=",".join(_list),
|
||||||
update_time=datetime.now().replace(microsecond=0),
|
create_time=datetime.now().replace(microsecond=0),
|
||||||
)
|
update_time=datetime.now().replace(microsecond=0),
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def _answer2format(
|
async def _answer2format(
|
||||||
@@ -143,7 +148,7 @@ class WordBank(db.Model):
|
|||||||
text += seg.data["text"]
|
text += seg.data["text"]
|
||||||
elif seg.type == "face":
|
elif seg.type == "face":
|
||||||
text += f"[face:placeholder_{index}]"
|
text += f"[face:placeholder_{index}]"
|
||||||
_list.append(seg.data.id)
|
_list.append(seg.data['id'])
|
||||||
elif seg.type == "at":
|
elif seg.type == "at":
|
||||||
text += f"[at:placeholder_{index}]"
|
text += f"[at:placeholder_{index}]"
|
||||||
_list.append(seg.data["qq"])
|
_list.append(seg.data["qq"])
|
||||||
@@ -234,16 +239,36 @@ class WordBank(db.Model):
|
|||||||
query = query.where(cls.word_scope == word_type)
|
query = query.where(cls.word_scope == word_type)
|
||||||
sql_text += f" and word_scope = {word_scope}"
|
sql_text += f" and word_scope = {word_scope}"
|
||||||
# 完全匹配
|
# 完全匹配
|
||||||
if await query.where(cls.problem == problem).gino.first():
|
if await query.where(
|
||||||
return query.where(cls.problem == problem)
|
((cls.word_type == 0) | (cls.word_type == 3)) & (cls.problem == problem)
|
||||||
|
).gino.first():
|
||||||
|
return query.where(
|
||||||
|
((cls.word_type == 0) | (cls.word_type == 3)) & (cls.problem == problem)
|
||||||
|
)
|
||||||
# 模糊匹配
|
# 模糊匹配
|
||||||
if await query.where(cls.problem.contains(problem)).gino.first():
|
if await db.first(
|
||||||
return query.where(cls.problem.contains(problem))
|
db.text(
|
||||||
|
sql_text
|
||||||
|
+ f" and word_type = 1 and :problem like '%' || problem || '%';"
|
||||||
|
),
|
||||||
|
problem=problem,
|
||||||
|
):
|
||||||
|
return (
|
||||||
|
sql_text
|
||||||
|
+ f" and word_type = 1 and :problem like '%' || problem || '%';"
|
||||||
|
)
|
||||||
# 正则匹配
|
# 正则匹配
|
||||||
if await db.first(
|
if await db.first(
|
||||||
db.text(sql_text + f" and word_type = 2 and word_scope != 999 and '{problem}' ~ problem;")
|
db.text(
|
||||||
|
sql_text
|
||||||
|
+ f" and word_type = 2 and word_scope != 999 and :problem ~ problem;"
|
||||||
|
),
|
||||||
|
problem=problem,
|
||||||
):
|
):
|
||||||
return sql_text + f" and word_type = 2 and word_scope != 999 and '{problem}' ~ problem;"
|
return (
|
||||||
|
sql_text
|
||||||
|
+ f" and word_type = 2 and word_scope != 999 and :problem ~ problem;"
|
||||||
|
)
|
||||||
# if await db.first(
|
# if await db.first(
|
||||||
# db.text(sql_text + f" and word_type = 1 and word_scope != 999 and '{problem}' ~ problem;")
|
# db.text(sql_text + f" and word_type = 1 and word_scope != 999 and '{problem}' ~ problem;")
|
||||||
# ):
|
# ):
|
||||||
@@ -270,10 +295,10 @@ class WordBank(db.Model):
|
|||||||
query = await cls.check(event, problem, word_scope, word_type)
|
query = await cls.check(event, problem, word_scope, word_type)
|
||||||
if query is not None:
|
if query is not None:
|
||||||
if isinstance(query, str):
|
if isinstance(query, str):
|
||||||
answer_list = await db.all(db.text(query))
|
answer_list = await db.all(db.text(query), problem=problem)
|
||||||
answer = random.choice(answer_list)
|
answer = random.choice(answer_list)
|
||||||
return (
|
return (
|
||||||
await cls._format2answer(problem, answer[7], answer[1], answer[2])
|
await cls._format2answer(answer[6], answer[7], answer[1], answer[2])
|
||||||
if answer.placeholder
|
if answer.placeholder
|
||||||
else answer.answer
|
else answer.answer
|
||||||
)
|
)
|
||||||
@@ -459,3 +484,40 @@ class WordBank(db.Model):
|
|||||||
problem_list.append(problem)
|
problem_list.append(problem)
|
||||||
_tmp.append(q.problem)
|
_tmp.append(q.problem)
|
||||||
return problem_list
|
return problem_list
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def _move(
|
||||||
|
cls,
|
||||||
|
user_id: int,
|
||||||
|
group_id: Optional[int],
|
||||||
|
problem: Union[str, Message],
|
||||||
|
answer: Union[str, Message],
|
||||||
|
placeholder: str,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
旧词条图片移动方法
|
||||||
|
参数:
|
||||||
|
:param user_id: 用户id
|
||||||
|
:param group_id: 群号
|
||||||
|
:param problem: 问题
|
||||||
|
:param answer: 回答
|
||||||
|
:param placeholder: 占位符
|
||||||
|
"""
|
||||||
|
word_scope = 0
|
||||||
|
word_type = 0
|
||||||
|
# 对图片做额外处理
|
||||||
|
if not await cls.exists(user_id, group_id, problem, answer, word_scope, word_type):
|
||||||
|
await cls.create(
|
||||||
|
user_qq=user_id,
|
||||||
|
group_id=group_id,
|
||||||
|
word_scope=word_scope,
|
||||||
|
word_type=word_type,
|
||||||
|
status=True,
|
||||||
|
problem=problem,
|
||||||
|
answer=answer,
|
||||||
|
image_path=None,
|
||||||
|
placeholder=placeholder,
|
||||||
|
create_time=datetime.now().replace(microsecond=0),
|
||||||
|
update_time=datetime.now().replace(microsecond=0),
|
||||||
|
)
|
||||||
|
|||||||
+16
-11
@@ -1,31 +1,36 @@
|
|||||||
import random
|
import imagehash
|
||||||
|
from PIL import Image
|
||||||
|
from io import BytesIO
|
||||||
|
from httpx import TimeoutException
|
||||||
|
|
||||||
|
from nonebot.typing import T_State
|
||||||
from nonebot.adapters.onebot.v11 import MessageEvent
|
from nonebot.adapters.onebot.v11 import MessageEvent
|
||||||
|
|
||||||
from configs.path_config import TEMP_PATH
|
|
||||||
from utils.image_utils import get_img_hash
|
|
||||||
from utils.utils import get_message_text, get_message_img, get_message_at
|
from utils.utils import get_message_text, get_message_img, get_message_at
|
||||||
from ._model import WordBank
|
from ._model import WordBank
|
||||||
from utils.http_utils import AsyncHttpx
|
from utils.http_utils import AsyncHttpx
|
||||||
|
|
||||||
|
|
||||||
async def check(event: MessageEvent) -> bool:
|
async def check(event: MessageEvent, state: T_State) -> bool:
|
||||||
text = get_message_text(event.message)
|
text = get_message_text(event.message)
|
||||||
img = get_message_img(event.message)
|
img = get_message_img(event.message)
|
||||||
at = get_message_at(event.message)
|
at = get_message_at(event.message)
|
||||||
rand = random.randint(1, 100)
|
|
||||||
problem = text
|
problem = text
|
||||||
if not text and len(img) == 1:
|
if not text and len(img) == 1:
|
||||||
if await AsyncHttpx.download_file(img[0], TEMP_PATH / f"{event.user_id}_{rand}_word_bank_check.jpg"):
|
try:
|
||||||
problem = str(get_img_hash(TEMP_PATH / f"{event.user_id}_{rand}_word_bank_check.jpg"))
|
r = await AsyncHttpx.get(img[0])
|
||||||
|
problem = str(imagehash.average_hash(Image.open(BytesIO(r.content))))
|
||||||
|
except TimeoutException:
|
||||||
|
pass
|
||||||
if at:
|
if at:
|
||||||
temp = ''
|
temp = ''
|
||||||
for seg in event.message:
|
for seg in event.message:
|
||||||
if seg.type == 'at':
|
if seg.type == 'at':
|
||||||
temp += f"[at:{seg.data['qq']}]"
|
temp += f"[at:{seg.data['qq']}]"
|
||||||
else:
|
elif seg.type == 'text':
|
||||||
temp += seg
|
temp += seg.data["text"]
|
||||||
problem = temp
|
problem = temp
|
||||||
if problem:
|
if problem and (await WordBank.check(event, problem) is not None):
|
||||||
return await WordBank.check(event, problem) is not None
|
state["problem"] = problem
|
||||||
|
return True
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
import random
|
|
||||||
|
|
||||||
from services import logger
|
from services import logger
|
||||||
from utils.image_utils import get_img_hash
|
|
||||||
from ._rule import check
|
from ._rule import check
|
||||||
from ._model import WordBank
|
from ._model import WordBank
|
||||||
from configs.path_config import DATA_PATH, TEMP_PATH
|
from configs.path_config import DATA_PATH
|
||||||
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
|
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
|
||||||
from utils.utils import get_message_img, get_message_text, get_message_at
|
|
||||||
from nonebot import on_message
|
from nonebot import on_message
|
||||||
from utils.http_utils import AsyncHttpx
|
from nonebot.typing import T_State
|
||||||
|
|
||||||
__zx_plugin_name__ = "词库问答回复操作 [Hidden]"
|
__zx_plugin_name__ = "词库问答回复操作 [Hidden]"
|
||||||
|
|
||||||
@@ -19,26 +15,8 @@ message_handle = on_message(priority=6, block=True, rule=check)
|
|||||||
|
|
||||||
|
|
||||||
@message_handle.handle()
|
@message_handle.handle()
|
||||||
async def _(event: MessageEvent):
|
async def _(event: MessageEvent, state: T_State):
|
||||||
text = get_message_text(event.message)
|
if problem := state.get("problem"):
|
||||||
img = get_message_img(event.message)
|
|
||||||
at = get_message_at(event.message)
|
|
||||||
problem = None
|
|
||||||
if not text and img and len(img) == 1:
|
|
||||||
rand = random.randint(1, 10000)
|
|
||||||
if await AsyncHttpx.download_file(img[0], TEMP_PATH / f"{event.user_id}_{rand}_word_bank.jpg"):
|
|
||||||
problem = str(get_img_hash(TEMP_PATH / f"{event.user_id}_{rand}_word_bank.jpg"))
|
|
||||||
elif at:
|
|
||||||
temp = ''
|
|
||||||
for seg in event.message:
|
|
||||||
if seg.type == 'at':
|
|
||||||
temp += f"[at:{seg.data['qq']}]"
|
|
||||||
else:
|
|
||||||
temp += seg
|
|
||||||
problem = temp
|
|
||||||
elif text:
|
|
||||||
problem = text
|
|
||||||
if problem:
|
|
||||||
if msg := await WordBank.get_answer(event, problem):
|
if msg := await WordBank.get_answer(event, problem):
|
||||||
await message_handle.send(msg)
|
await message_handle.send(msg)
|
||||||
logger.info(
|
logger.info(
|
||||||
@@ -46,6 +24,3 @@ async def _(event: MessageEvent):
|
|||||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||||
f" 触发词条 {problem}"
|
f" 触发词条 {problem}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import re
|
||||||
from typing import Tuple, Any, Optional
|
from typing import Tuple, Any, Optional
|
||||||
|
|
||||||
from nonebot.internal.params import Arg, ArgStr
|
from nonebot.internal.params import Arg, ArgStr
|
||||||
@@ -5,11 +6,12 @@ from nonebot.typing import T_State
|
|||||||
|
|
||||||
from utils.utils import get_message_at, is_number, get_message_img
|
from utils.utils import get_message_at, is_number, get_message_img
|
||||||
from nonebot.params import CommandArg, RegexGroup, Command
|
from nonebot.params import CommandArg, RegexGroup, Command
|
||||||
|
from nonebot.exception import FinishedException
|
||||||
from services.log import logger
|
from services.log import logger
|
||||||
from configs.path_config import DATA_PATH
|
from configs.path_config import DATA_PATH
|
||||||
from utils.message_builder import custom_forward_msg
|
from utils.message_builder import custom_forward_msg
|
||||||
from ._model import WordBank
|
from ._model import WordBank
|
||||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent, PrivateMessageEvent
|
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent, PrivateMessageEvent, unescape
|
||||||
from nonebot import on_command, on_regex
|
from nonebot import on_command, on_regex
|
||||||
from configs.config import Config
|
from configs.config import Config
|
||||||
from ._data_source import delete_word, update_word, show_word
|
from ._data_source import delete_word, update_word, show_word
|
||||||
@@ -23,7 +25,7 @@ usage:
|
|||||||
更推荐使用id方式删除
|
更推荐使用id方式删除
|
||||||
问题回答支持的CQ:at, face, image
|
问题回答支持的CQ:at, face, image
|
||||||
查看词条命令:群聊时为 群词条+全局词条,私聊时为 私聊词条+全局词条
|
查看词条命令:群聊时为 群词条+全局词条,私聊时为 私聊词条+全局词条
|
||||||
添加词条正则:添加词条(模糊|正则|图片)?问\s*?(\S*)\s*?答\s?(\S*)
|
添加词条正则:添加词条(模糊|正则|图片)?问\s*?(\S*\s?\S*)\s*?答\s?(\S*)
|
||||||
指令:
|
指令:
|
||||||
添加词条 ?[模糊|正则|图片]问...答...:添加问答词条,可重复添加相同问题的不同回答
|
添加词条 ?[模糊|正则|图片]问...答...:添加问答词条,可重复添加相同问题的不同回答
|
||||||
删除词条 [问题/下标] ?[下标]:删除指定词条指定或全部回答
|
删除词条 [问题/下标] ?[下标]:删除指定词条指定或全部回答
|
||||||
@@ -47,7 +49,7 @@ __plugin_superuser_usage__ = r"""
|
|||||||
usage:
|
usage:
|
||||||
在私聊中超级用户额外设置
|
在私聊中超级用户额外设置
|
||||||
指令:
|
指令:
|
||||||
(全局|私聊)?添加词条\s*?(模糊|正则|图片)?问\s*?(\S*)\s*?答\s?(\S*):添加问答词条,可重复添加相同问题的不同回答
|
(全局|私聊)?添加词条\s*?(模糊|正则|图片)?问\s*?(\S*\s?\S*)\s*?答\s?(\S*):添加问答词条,可重复添加相同问题的不同回答
|
||||||
全局添加词条
|
全局添加词条
|
||||||
私聊添加词条
|
私聊添加词条
|
||||||
(私聊情况下)删除词条: 删除私聊词条
|
(私聊情况下)删除词条: 删除私聊词条
|
||||||
@@ -74,7 +76,7 @@ data_dir = DATA_PATH / "word_bank"
|
|||||||
data_dir.mkdir(parents=True, exist_ok=True)
|
data_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
add_word = on_regex(
|
add_word = on_regex(
|
||||||
r"^(全局|私聊)?添加词条\s*?(模糊|正则|图片)?问\s*?(\S*)\s*?答\s?(\S*)", priority=5, block=True
|
r"^(全局|私聊)?添加词条\s*?(模糊|正则|图片)?问\s*?(\S*\s?\S*)\s*?答\s?(\S*)", priority=5, block=True
|
||||||
)
|
)
|
||||||
|
|
||||||
delete_word_matcher = on_command("删除词条", aliases={'删除全局词条'}, priority=5, block=True)
|
delete_word_matcher = on_command("删除词条", aliases={'删除全局词条'}, priority=5, block=True)
|
||||||
@@ -91,7 +93,7 @@ async def _(
|
|||||||
state: T_State,
|
state: T_State,
|
||||||
reg_group: Tuple[Any, ...] = RegexGroup(),
|
reg_group: Tuple[Any, ...] = RegexGroup(),
|
||||||
):
|
):
|
||||||
if str(event.user_id) not in bot.config.superusers:
|
if isinstance(event, PrivateMessageEvent) and str(event.user_id) not in bot.config.superusers:
|
||||||
await add_word.finish('权限不足捏')
|
await add_word.finish('权限不足捏')
|
||||||
word_scope, word_type, problem, answer = reg_group
|
word_scope, word_type, problem, answer = reg_group
|
||||||
if (
|
if (
|
||||||
@@ -113,18 +115,22 @@ async def _(
|
|||||||
if seg.type == 'text' and '答' in str(seg):
|
if seg.type == 'text' and '答' in str(seg):
|
||||||
_problem = event.message[:index]
|
_problem = event.message[:index]
|
||||||
answer = event.message[index:]
|
answer = event.message[index:]
|
||||||
answer[0] = str(answer[0])[str(answer).index('答')+1:]
|
answer[0] = str(answer[0])[str(answer[0]).index('答')+1:]
|
||||||
_problem[0] = str(_problem[0])[str(_problem).index('问')+1:]
|
_problem[0] = str(_problem[0])[str(_problem[0]).index('问')+1:]
|
||||||
|
if _problem[-1].type != 'at' or seg.data['text'][:seg.data['text'].index('答')].lstrip():
|
||||||
|
_problem.append(seg.data['text'][:seg.data['text'].index('答')])
|
||||||
temp = ''
|
temp = ''
|
||||||
for g in _problem:
|
for g in _problem:
|
||||||
if isinstance(g, str) or g.type == 'text':
|
if isinstance(g, str):
|
||||||
temp += g
|
temp += g
|
||||||
|
elif g.type == 'text':
|
||||||
|
temp += g.data['text']
|
||||||
elif g.type == 'at':
|
elif g.type == 'at':
|
||||||
temp += f"[at:{g.data['qq']}]"
|
temp += f"[at:{g.data['qq']}]"
|
||||||
problem = temp
|
problem = temp
|
||||||
break
|
break
|
||||||
index = len((word_scope or "") + "添加词条" + (word_type or "") + problem) + 1
|
problem = unescape(problem)
|
||||||
event.message[0] = event.message[0].data["text"][index + 1 :].strip()
|
event.message[0] = event.message[0].data["text"].split('答', maxsplit=1)[-1].strip()
|
||||||
state["word_scope"] = word_scope
|
state["word_scope"] = word_scope
|
||||||
state["word_type"] = word_type
|
state["word_type"] = word_type
|
||||||
state["problem"] = problem
|
state["problem"] = problem
|
||||||
@@ -141,6 +147,11 @@ async def _(
|
|||||||
problem_image: Message = Arg("problem_image"),
|
problem_image: Message = Arg("problem_image"),
|
||||||
):
|
):
|
||||||
try:
|
try:
|
||||||
|
if word_type == "正则":
|
||||||
|
try:
|
||||||
|
re.compile(problem)
|
||||||
|
except re.error:
|
||||||
|
await add_word.finish(f"添加词条失败,正则表达式 {problem} 非法!")
|
||||||
await WordBank.add_problem_answer(
|
await WordBank.add_problem_answer(
|
||||||
event.user_id,
|
event.user_id,
|
||||||
event.group_id if isinstance(event, GroupMessageEvent) and (not word_scope or word_scope == '1') else 0,
|
event.group_id if isinstance(event, GroupMessageEvent) and (not word_scope or word_scope == '1') else 0,
|
||||||
@@ -150,6 +161,8 @@ async def _(
|
|||||||
answer,
|
answer,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
if isinstance(e, FinishedException):
|
||||||
|
await add_word.finish()
|
||||||
logger.error(
|
logger.error(
|
||||||
f"(USER {event.user_id}, GROUP "
|
f"(USER {event.user_id}, GROUP "
|
||||||
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
|
||||||
@@ -233,7 +246,7 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
|||||||
not is_number(id_)
|
not is_number(id_)
|
||||||
or int(id_) < 0
|
or int(id_) < 0
|
||||||
or int(id_)
|
or int(id_)
|
||||||
> len(await WordBank.get_group_all_problem(event.group_id))
|
>= len(await WordBank.get_group_all_problem(event.group_id))
|
||||||
):
|
):
|
||||||
await show_word_matcher.finish("id必须为数字且在范围内")
|
await show_word_matcher.finish("id必须为数字且在范围内")
|
||||||
id_ = int(id_)
|
id_ = int(id_)
|
||||||
@@ -243,7 +256,7 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
|
|||||||
not is_number(gid)
|
not is_number(gid)
|
||||||
or int(gid) < 0
|
or int(gid) < 0
|
||||||
or int(gid)
|
or int(gid)
|
||||||
> len(await WordBank.get_problem_by_scope(0))
|
>= len(await WordBank.get_problem_by_scope(0))
|
||||||
):
|
):
|
||||||
await show_word_matcher.finish("gid必须为数字且在范围内")
|
await show_word_matcher.finish("gid必须为数字且在范围内")
|
||||||
gid = int(gid)
|
gid = int(gid)
|
||||||
|
|||||||
@@ -178,8 +178,8 @@ class BuildImage:
|
|||||||
self.h = int(h)
|
self.h = int(h)
|
||||||
self.paste_image_width = int(paste_image_width)
|
self.paste_image_width = int(paste_image_width)
|
||||||
self.paste_image_height = int(paste_image_height)
|
self.paste_image_height = int(paste_image_height)
|
||||||
self.current_w = 0
|
self._current_w = 0
|
||||||
self.current_h = 0
|
self._current_h = 0
|
||||||
self.font = ImageFont.truetype(str(FONT_PATH / font), int(font_size))
|
self.font = ImageFont.truetype(str(FONT_PATH / font), int(font_size))
|
||||||
if not plain_text and not color:
|
if not plain_text and not color:
|
||||||
color = (255, 255, 255)
|
color = (255, 255, 255)
|
||||||
@@ -287,11 +287,11 @@ class BuildImage:
|
|||||||
pos = (width, height)
|
pos = (width, height)
|
||||||
if isinstance(img, BuildImage):
|
if isinstance(img, BuildImage):
|
||||||
img = img.markImg
|
img = img.markImg
|
||||||
if self.current_w == self.w:
|
if self._current_w >= self.w:
|
||||||
self.current_w = 0
|
self._current_w = 0
|
||||||
self.current_h += self.paste_image_height
|
self._current_h += self.paste_image_height
|
||||||
if not pos:
|
if not pos:
|
||||||
pos = (self.current_w, self.current_h)
|
pos = (self._current_w, self._current_h)
|
||||||
if alpha:
|
if alpha:
|
||||||
try:
|
try:
|
||||||
self.markImg.paste(img, pos, img)
|
self.markImg.paste(img, pos, img)
|
||||||
@@ -300,7 +300,7 @@ class BuildImage:
|
|||||||
self.markImg.paste(img, pos, img)
|
self.markImg.paste(img, pos, img)
|
||||||
else:
|
else:
|
||||||
self.markImg.paste(img, pos)
|
self.markImg.paste(img, pos)
|
||||||
self.current_w += self.paste_image_width
|
self._current_w += self.paste_image_width
|
||||||
|
|
||||||
def getsize(self, msg: str) -> Tuple[int, int]:
|
def getsize(self, msg: str) -> Tuple[int, int]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -238,6 +238,25 @@ def get_message_img(data: Union[str, Message]) -> List[str]:
|
|||||||
return img_list
|
return img_list
|
||||||
|
|
||||||
|
|
||||||
|
def get_message_face(data: Union[str, Message]) -> List[str]:
|
||||||
|
"""
|
||||||
|
说明:
|
||||||
|
获取消息中所有的 face Id
|
||||||
|
参数:
|
||||||
|
:param data: event.json()
|
||||||
|
"""
|
||||||
|
face_list = []
|
||||||
|
if isinstance(data, str):
|
||||||
|
data = json.loads(data)
|
||||||
|
for msg in data["message"]:
|
||||||
|
if msg["type"] == "face":
|
||||||
|
face_list.append(msg["data"]["id"])
|
||||||
|
else:
|
||||||
|
for seg in data["face"]:
|
||||||
|
face_list.append(seg.data["id"])
|
||||||
|
return face_list
|
||||||
|
|
||||||
|
|
||||||
def get_message_img_file(data: Union[str, Message]) -> List[str]:
|
def get_message_img_file(data: Union[str, Message]) -> List[str]:
|
||||||
"""
|
"""
|
||||||
说明:
|
说明:
|
||||||
|
|||||||
Reference in New Issue
Block a user