Compare commits

..
79 Commits
Author SHA1 Message Date
HibiKier 0ea740aa7c Update __version__ 2022-09-16 19:35:33 +08:00
HibiKier 5f118471cb 修复一些问题 2022-09-16 19:29:05 +08:00
HibiKier 504f78dd49 Merge pull request #1090 from NumberSir/main
fix: bilibili_sub, azur_draw_card
2022-09-16 19:14:19 +08:00
Number_Sir 72723c7d1f 修复碧蓝航线抽卡错误 2022-09-16 12:55:22 +08:00
Number_Sir 6a74053853 bilibili_sub更新检查失败时改为logger通知,不在群里发消息 2022-09-16 12:43:22 +08:00
HibiKier af0b4987a4 Merge pull request #1067 from DDS-DS/main
fix:bt url打开失败
2022-09-10 00:20:44 +08:00
HibiKier 775140cf79 自定义群欢迎消息参数不完全时提示报错 2022-09-09 22:41:39 +08:00
HibiKier 6a8a796add 添加插件数据初始化判断 2022-09-08 20:13:26 +08:00
DDS-DS 8e4bda3760 fix bt url打开失败 2022-09-08 01:35:41 +08:00
HibiKier a36e8145a8 旧词条提供图片迁移 2022-09-04 22:05:56 +08:00
HibiKier 3cbd899daa 修复原神资源查询地图api数据变更导致更新的地图不完全 2022-09-03 18:17:42 +08:00
HibiKier 30f356a2c7 Merge remote-tracking branch 'origin/main' 2022-09-03 17:30:21 +08:00
HibiKier 1138a115ce B站订阅在群里中任意群管理员可以统一管理 2022-09-03 17:30:03 +08:00
HibiKier c397da75e7 Merge pull request #1033 from q56535/main
av号覆盖全面,且修复av号链接
2022-09-03 17:14:22 +08:00
HibiKier 1d141c9313 Merge pull request #1059 from unknownsno/main
fix bug
2022-09-03 16:56:49 +08:00
q56535 a4cc365af8 Merge branch 'HibiKier:main' into main 2022-09-03 16:44:57 +08:00
HibiKier 4e551bec0d 修复词条含有CQ回答的模糊匹配无法被解析 2022-09-03 16:16:33 +08:00
unknwonsno e03086062d fix bug 2022-09-03 14:43:13 +08:00
HibiKier 270a5a5e20 Merge pull request #1053 from unknownsno/main
原神玩家查询增加须弥地区
2022-09-03 14:24:18 +08:00
unknwonsno bda9133ed6 原神玩家查询增加须弥地区 2022-08-31 22:22:00 +08:00
HibiKier 749f475f2c UPDATE README.md 2022-08-27 18:25:30 +08:00
HibiKier e38394948c Merge pull request #1044 from zyj3421/main
修复签到积分双倍后,日志记录获得积分变4倍问题
2022-08-27 18:22:35 +08:00
zyj2134 51fc4cbb6a 修复签到积分双倍后,日志记录获得积分变4倍问题 2022-08-26 22:49:51 +08:00
zyj2134 9a976cda37 Merge remote-tracking branch 'origin/main' 2022-08-26 22:39:48 +08:00
HibiKier e42521f0a3 修复词条关键词"问"前空格问题 2022-08-26 19:39:23 +08:00
HibiKier 0756d39ac5 修复群管理员无法添加词条 2022-08-26 19:26:09 +08:00
zyj2134 4595bdcee4 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	README.md
#	plugins/bilibili_sub/__init__.py
2022-08-25 23:00:49 +08:00
HibiKier 38160065cc UPDATE README.md 2022-08-23 23:02:06 +08:00
HibiKier 3d04f013cd Merge pull request #1032 from LambdaYH/p1
修了下模糊匹配 issue#1026
2022-08-23 20:21:25 +08:00
q56535 8e1a416be3 av号覆盖全面 2022-08-23 13:43:43 +08:00
LambdaYH a98bc42f1a fix https://github.com/HibiKier/zhenxun_bot/issues/1026 2022-08-23 13:16:14 +08:00
HibiKier 6c93769838 UPDATE README.md 2022-08-22 22:51:36 +08:00
HibiKier d2dccfebc5 取消配置替换定时任务,统一存储 2022-08-22 22:49:35 +08:00
HibiKier 82fe59e469 修复首次安装时词条旧表出错 2022-08-22 20:59:08 +08:00
HibiKier afc05e1731 Merge remote-tracking branch 'origin/main' 2022-08-22 20:48:57 +08:00
HibiKier 0206b0a522 UPDATE README.md 2022-08-22 20:47:32 +08:00
HibiKier 0e1e5a5ebe Merge pull request #1012 from LambdaYH/patch-4
修复词库问答几个问题
2022-08-22 20:45:31 +08:00
HibiKier 9ad088ed6a Merge pull request #1010 from CRAZYShimakaze/main
修正尘歌壶和质变仪图片获取地址
2022-08-22 20:43:22 +08:00
HibiKier 34da04bba5 Merge pull request #1014 from xiayingLIULI/main
对米游社cookie进行判断,整合米游社签到信息
2022-08-22 20:41:32 +08:00
HibiKier 09ce812faf Update __init__.py 2022-08-22 20:39:03 +08:00
xiayingLIULI 1dc8cb2a98 修复米游社签到在无用户cookie的情况下执行的错误 2022-08-22 13:45:04 +08:00
xiayingLIULI e73c509823 修复米游社签到在无用户cookie的情况下执行的错误 2022-08-22 13:33:49 +08:00
Cinte e70a85400f 查看词条的id范围判断少了个等号 2022-08-22 12:56:35 +08:00
Cinte f7aecf8eed Update word_handle.py 2022-08-22 12:37:06 +08:00
Cinte cc2645aa9d Update word_handle.py 2022-08-22 12:34:21 +08:00
xiayingLIULI 52d23c4a8d 修复能在群聊中查看我的cookie 2022-08-22 11:44:21 +08:00
Cinte 1e57ddb9ee 处理at后自动接空格的情况,problem中允许单空白字符号 & 修复二次元触发 2022-08-22 11:14:04 +08:00
Cinte 7ae883d921 使用check构造的problem而不在message_handle中重新构造 2022-08-22 10:14:59 +08:00
Cinte 27e97214bd 仅仅是检查图片hash就将图片下载到磁盘是否有些浪费io,于是改成了内存中直接计算 2022-08-22 09:49:33 +08:00
LambdaYH 6321a9e7e0 使用gino提供的方法,避免构建sql字符串时出现非法查询语句 2022-08-22 00:49:30 +08:00
xiayingLIULI a9eadca46c 对米游社cookie进行判断,整合米游社签到信息 2022-08-22 00:42:00 +08:00
xiayingLIULI 76bef8a725 对米游社cookie进行判断,整合米游社签到信息 2022-08-22 00:40:51 +08:00
LambdaYH 308b76dc7d _rule中使用messagesegment中未转义的字符串,而添加词条时使用了转义后的字符串,导致二者不一致 2022-08-22 00:38:25 +08:00
LambdaYH 31d4d29f3e 修复匹配时候忽视了word_type的约束 2022-08-21 23:47:21 +08:00
LambdaYH 016a7e87ea Merge branch 'HibiKier-main' into patch-4 2022-08-21 23:46:46 +08:00
LambdaYH 4ce88c7bfc merge 2022-08-21 23:46:38 +08:00
LambdaYH f570bffcf7 修复匹配时候忽视了word_type的约束 2022-08-21 23:42:46 +08:00
LambdaYH 3bb9aaf637 添加正则词条前先检查正则有效性 & 正则词条先进行转义,不然符号都乱了 2022-08-21 23:21:34 +08:00
LambdaYH cf7a64c934 fix: 问答为[at + 文本]的情况时无法正常添加 2022-08-21 22:24:06 +08:00
LambdaYH c466603193 Fix at messages with suffixed text 2022-08-21 21:58:31 +08:00
CRAZY bc53f329a9 修正尘歌壶和质变仪图片获取地址 2022-08-21 20:33:06 +08:00
CRAZY 4a5cc5153f 修正质变仪图片获取地址 2022-08-21 20:11:44 +08:00
zyj2134 e70d0df949 Merge remote-tracking branch 'origin/main' 2022-08-19 23:49:16 +08:00
HibiKier fcaa469edd Merge pull request #996 from shinianj/patch-1
Update README.md
2022-08-16 08:46:10 +08:00
shinianj 51508182ef Update README.md 2022-08-16 00:38:14 +08:00
HibiKier 27e78c1626 update README.md 2022-08-14 22:11:36 +08:00
HibiKier 0b4d37a0b6 修复订阅主播时动态获取的id是直播间id 2022-08-14 21:31:57 +08:00
HibiKier ddbebba6f1 修复epic未获取时间时出错 2022-08-14 21:18:29 +08:00
zyj2134 7f296348e4 Merge remote-tracking branch 'origin/main' 2022-08-09 22:20:32 +08:00
HibiKier ca78e32d97 Update README.md 2022-08-08 04:23:05 +08:00
HibiKier 4efc561f4d Merge pull request #969 from DDS-DS/main
修复赛马娘重载卡池失败的问题
2022-08-08 04:22:24 +08:00
dingshan 3c120ce602 增加备注说明 2022-08-05 15:49:21 +08:00
dingshan 6151dfb161 修复赛马娘重载卡池失败的问题 2022-08-05 15:42:53 +08:00
dingshan f05d4ec931 修复赛马娘重载卡池失败的问题 2022-08-05 15:35:45 +08:00
zyj2134 a1308fbdc9 Merge remote-tracking branch 'origin/main' 2022-07-24 22:16:51 +08:00
zyj2134 946fbbec3c Merge remote-tracking branch 'origin/main' 2022-07-17 15:34:18 +08:00
zyj2134 bd531c85b1 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	README.md
2022-07-14 20:44:12 +08:00
HibiKier cda9aae8a3 Update README.md 2022-07-07 22:02:33 +08:00
HibiKier a33e785043 Merge pull request #891 from yajiwa/main
更新微博热搜
2022-07-07 22:01:53 +08:00
36 changed files with 513 additions and 355 deletions
+2
View File
@@ -159,3 +159,5 @@ resources/
!/configs/config.yaml
!/.env
!/.env.dev
!/plugins/csgo_server/
!/plugins/activity/
+54 -1
View File
@@ -252,6 +252,10 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
### 感谢名单
(可以告诉我你的 __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)
[ln](https://afdian.net/u/b51914ba1c6611ed8a4e52540025c377)
[爱发电用户_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]
* 重构群词条,改为词库Plus,增加 精准|模糊|正则 问题匹配,问题与回答均支持at,image,face,超级用户额外提供 全局|私聊 词库设置,数据迁移目前只提供了问题和回答都是纯文本的词条
@@ -787,7 +840,7 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
__..... 更多更新信息请查看文档__
## Todo
- [ ] web管理
- [x] web管理
## 感谢
[botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议
+1 -1
View File
@@ -1 +1 @@
__version__: v0.1.6.3
__version__: v0.1.6.3-fix1
@@ -36,11 +36,11 @@ custom_welcome = on_command(
@custom_welcome.handle()
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:
msg = arg.extract_plain_text().strip()
img = get_message_img(event.json())
if not msg and not img:
await custom_welcome.finish(__plugin_usage__)
await custom_welcome.send(
await custom_group_welcome(msg, img, event.user_id, event.group_id),
at_sender=True,
+2 -2
View File
@@ -60,7 +60,7 @@ async def _():
try:
await bot.send_group_msg(group_id=g, message="[[_task|zwa]]早上好" + result)
except ActionFailed:
logger.warning(f"{g} 群被禁言中,无法发送早安")
logger.warning(f"{g} 发送早安失败")
except Exception as e:
logger.error(f"早晚安错误 e:{e}")
@@ -83,7 +83,7 @@ async def _():
group_id=g, message=f"[[_task|zwa]]{NICKNAME}要睡觉了,你们也要早点睡呀" + result
)
except ActionFailed:
logger.warning(f"{g} 群被禁言中,无法发送晚安")
logger.warning(f"{g} 发送晚安失败")
except Exception as e:
logger.error(f"早晚安错误 e:{e}")
@@ -27,6 +27,8 @@ def init_plugins_config(data_path):
# 优先使用 metadata 数据
for matcher in _matchers:
_plugin = matcher.plugin
if not _plugin:
continue
metadata = _plugin.metadata
try:
_module = _plugin.module
@@ -108,16 +110,16 @@ def init_plugins_config(data_path):
_data, wf, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
user_config_file = Path() / "configs" / "config.yaml"
if not user_config_file.exists():
_replace_config()
else:
logger.info('五分钟后将进行配置数据替换,请注意...')
scheduler.add_job(
_replace_config,
"date",
run_date=datetime.now() + timedelta(minutes=5),
id=f"_replace_config"
)
# if not user_config_file.exists():
_replace_config()
# else:
# logger.info('五分钟后将进行配置数据替换,请注意...')
# scheduler.add_job(
# _replace_config,
# "date",
# run_date=datetime.now() + timedelta(minutes=5),
# id=f"_replace_config"
# )
def _replace_config():
@@ -25,6 +25,8 @@ def init_plugins_data(data_path):
_matchers = get_matchers(True)
for matcher in _matchers:
_plugin = matcher.plugin
if not _plugin:
continue
metadata = _plugin.metadata
try:
_module = _plugin.module
@@ -34,82 +34,87 @@ def init_plugins_settings(data_path: str):
logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
_tmp_module[x] = ""
for matcher in _matchers:
if matcher.plugin_name not in plugins2settings_manager.keys():
_plugin = matcher.plugin
metadata = _plugin.metadata
try:
_module = _plugin.module
except AttributeError:
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.")
else:
try:
if matcher.plugin_name not in plugins2settings_manager.keys():
_plugin = matcher.plugin
if not _plugin:
continue
metadata = _plugin.metadata
try:
if metadata:
plugin_name = metadata.name
_module = _plugin.module
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:
plugin_name = _module.__getattribute__("__zx_plugin_name__")
if "[admin]" in plugin_name.lower():
_tmp_module[matcher.plugin_name] = plugin_name
try:
admin_settings = _module.__getattribute__(
plugin_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:
_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:
plugin_type = ("normal",)
if plugin_settings and matcher.plugin_name:
plugins2settings_manager.add_plugin_settings(
matcher.plugin_name,
plugin_type=plugin_type,
**plugin_settings,
)
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:
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_data = {"PluginSettings": plugins2settings_manager.get_data()}
with open(plugins2settings_file, "w", encoding="utf8") as wf:
+9 -13
View File
@@ -94,13 +94,14 @@ class ConfigsManager:
del self._data[module]
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 key: 配置名称
:param value: 值
:param save_simple_data: 同时保存至config.yaml
:param auto_save: 自动保存
:param save_simple_data: 保存至config.yaml
"""
if module in self._data.keys():
if (
@@ -109,6 +110,7 @@ class ConfigsManager:
):
self._data[module][key]["value"] = value
self._simple_data[module][key] = value
if auto_save:
self.save(save_simple_data=save_simple_data)
def set_help(self, module: str, key: str, help_: str):
@@ -145,18 +147,12 @@ class ConfigsManager:
:param default: 没有key值内容的默认返回值
"""
key = key.upper()
# 优先使用simple_data
if module in self._simple_data.keys():
if module in self._data.keys():
for key in [key, f"{key} [LEVEL]"]:
if self._simple_data[module].get(key) is not None:
return self._simple_data[module][key]
# if module in self._data.keys():
# 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]["value"]
# return self._data[module][key]["default_value"]
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"]
if default is not None:
return default
return None
Binary file not shown.

After

Width:  |  Height:  |  Size: 694 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 694 KiB

After

Width:  |  Height:  |  Size: 326 KiB

+4 -2
View File
@@ -15,6 +15,7 @@ from .data_source import (
BilibiliSub,
)
from models.level_user import LevelUser
from utils.manager import group_manager
from configs.config import Config
from utils.utils import is_number, scheduler, get_bot
from typing import Optional, Tuple, Any
@@ -160,7 +161,7 @@ async def _(
async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
msg = reg_group[0]
id_ = (
f"{event.user_id}:{event.group_id}"
f"{event.group_id}"
if isinstance(event, GroupMessageEvent)
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")
):
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:
await bot.send_private_msg(user_id=int(x), message=Message(rst))
except Exception as e:
+3 -1
View File
@@ -208,7 +208,9 @@ async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
elif sub_type == "season":
return await _get_season_status(id_)
except ResponseCodeError:
return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
logger.error(f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试...")
return None
# return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
# except Exception as e:
# logger.error(f"获取订阅状态发生预料之外的错误 id_:{id_} {type(e)}:{e}")
# return "发生了预料之外的错误..请稍后再试或联系管理员....."
+1 -1
View File
@@ -9,7 +9,7 @@ import platform
# 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):
+26 -56
View File
@@ -1,7 +1,8 @@
import contextlib
import random
import dateparser
from lxml import etree
from typing import List, Optional
from typing import List, Optional, Tuple
from urllib.parse import unquote
from pydantic import ValidationError
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 ..util import remove_prohibited_str, cn2py
from utils.image_utils import BuildImage
import asyncio
try:
import ujson as json
@@ -29,7 +29,7 @@ class AzurChar(BaseData):
class UpChar(_UpChar):
type_: str # 舰娘类型
type_: str # 舰娘类型
class UpEvent(_UpEvent):
@@ -53,7 +53,9 @@ class AzurHandle(BaseHandle[AzurChar]):
type_ = ["维修", "潜艇", "重巡", "轻航", "航母"]
up_pool_flag = pool_name == "活动"
# 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)
acquire_char = None
if up_ship and up_pool_flag:
@@ -61,19 +63,15 @@ class AzurHandle(BaseHandle[AzurChar]):
# 初始化概率
cur_ = up_ship[0].zoom / 100
for i in range(len(up_ship)):
try:
up_zoom.append((cur_, cur_ + up_ship[i+1].zoom / 100))
cur_ += up_ship[i+1].zoom / 100
except IndexError:
pass
with contextlib.suppress(IndexError):
up_zoom.append((cur_, cur_ + up_ship[i + 1].zoom / 100))
cur_ += up_ship[i + 1].zoom / 100
rand = random.random()
# 抽取up
for i, zoom in enumerate(up_zoom):
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]
except IndexError:
pass
# 没有up或者未抽取到up
if not acquire_char:
star = self.get_star(
@@ -92,9 +90,6 @@ class AzurHandle(BaseHandle[AzurChar]):
])
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:
index2card = self.get_cards(count, **kwargs)
cards = [card[0] for card in index2card]
@@ -162,22 +157,22 @@ class AzurHandle(BaseHandle[AzurChar]):
return
dom = etree.HTML(result, etree.HTMLParser())
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):
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:
try:
name = char.xpath("./a/@title")[0]
frame = char.xpath("./div/a/img/@alt")[0]
avatar = char.xpath("./a/img/@srcset")[0]
name = char.xpath("./div/a/@title")[0]
frame = char.xpath("./div/div/a/img/@alt")[0]
avatar = char.xpath("./div/a/img/@srcset")[0]
except IndexError:
continue
member_dict = {
"名称": remove_prohibited_str(name),
"头像": unquote(str(avatar).split(" ")[-2]),
"星级": self.parse_star(frame),
"类型": self.parse_type(index),
"类型": char.xpath("./@data-param1")[0].split(",")[1],
}
info[member_dict["名称"]] = member_dict
# 更新额外信息
@@ -225,48 +220,21 @@ class AzurHandle(BaseHandle[AzurChar]):
@staticmethod
def parse_star(star: str) -> int:
if star in ["舰娘头像外框普通.png", "舰娘头像外框白色.png"]:
if star in {"舰娘头像外框普通.png", "舰娘头像外框白色.png"}:
return 1
elif star in ["舰娘头像外框稀有.png", "舰娘头像外框蓝色.png"]:
elif star in {"舰娘头像外框稀有.png", "舰娘头像外框蓝色.png"}:
return 2
elif star in ["舰娘头像外框精锐.png", "舰娘头像外框紫色.png"]:
elif star in {"舰娘头像外框精锐.png", "舰娘头像外框紫色.png"}:
return 3
elif star in ["舰娘头像外框超稀有.png", "舰娘头像外框金色.png"]:
elif star in {"舰娘头像外框超稀有.png", "舰娘头像外框金色.png"}:
return 4
elif star in ["舰娘头像外框海上传奇.png", "舰娘头像外框彩色.png"]:
elif star in {"舰娘头像外框海上传奇.png", "舰娘头像外框彩色.png"}:
return 5
elif star in [
"舰娘头像外框最高方案.png",
"舰娘头像外框决战方案.png",
"舰娘头像外框超稀有META.png",
"舰娘头像外框精锐META.png",
]:
elif star in {"舰娘头像外框最高方案.png", "舰娘头像外框决战方案.png", "舰娘头像外框超稀有META.png", "舰娘头像外框精锐META.png"}:
return 6
else:
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):
url = "https://wiki.biligame.com/blhx/游戏活动表"
result = await self.get_url(url)
@@ -290,7 +258,7 @@ class AzurHandle(BaseHandle[AzurChar]):
up_chars = []
for ship in ships:
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:
p = float(str(ship.xpath(".//sup/text()")[0]).strip("%"))
except (IndexError, ValueError):
@@ -298,7 +266,9 @@ class AzurHandle(BaseHandle[AzurChar]):
star = self.parse_star(
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(
title=title,
pool_img="",
+6 -15
View File
@@ -1,6 +1,8 @@
from io import BytesIO
import imagehash
from PIL import Image
from nonebot.adapters.onebot.v11.permission import GROUP
from configs.path_config import TEMP_PATH
from utils.image_utils import get_img_hash
import random
from utils.message_builder import image
from nonebot import on_message
@@ -8,7 +10,6 @@ from utils.utils import get_message_img, get_message_text
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from configs.config import Config
from utils.http_utils import AsyncHttpx
from services.log import logger
from configs.config import NICKNAME
@@ -90,7 +91,7 @@ async def _(event: GroupMessageEvent):
if not img and not msg:
return
if img:
img_hash = await get_fudu_img_hash(img[0], event.group_id)
img_hash = await get_fudu_img_hash(img[0])
else:
img_hash = ""
add_msg = msg + "|-|" + img_hash
@@ -123,15 +124,5 @@ async def _(event: GroupMessageEvent):
await fudu.finish("[[_task|fudu]]" + rst)
async def get_fudu_img_hash(url, group_id):
try:
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 ""
async def get_fudu_img_hash(url):
return str(imagehash.average_hash(Image.open(BytesIO((await AsyncHttpx.get(url)).content))))
@@ -47,7 +47,7 @@ __plugin_block_limit__ = {
qr = on_command("原神资源查询", aliases={"原神资源查找"}, priority=5, block=True)
qr_lst = on_command("原神资源列表", 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()
+1 -1
View File
@@ -118,7 +118,7 @@ class Map:
self._generate_best_route()
self.map.crop((min_width, min_height, max_width, max_height))
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
# 资源数量
@@ -172,28 +172,29 @@ async def download_map_init(semaphore: Semaphore, flag: bool = False):
if data["message"] == "OK":
data = json.loads(data["data"]["info"]["detail"])
CENTER_POINT = (data["origin"][0], data["origin"][1])
if not _map.exists():
if not _map.exists() or flag:
data = data["slices"]
idx = 0
for _map_data in data[0]:
map_url = _map_data["url"]
await download_image(
map_url,
map_path / f"{idx}.png",
semaphore,
force_flag=flag,
)
BuildImage(
0, 0, background=f"{map_path}/{idx}.png", ratio=MAP_RATIO
).save()
idx += 1
_w, h = BuildImage(0, 0, background=f"{map_path}/0.png").size
w = _w * len(os.listdir(map_path))
map_file = BuildImage(w, h, _w, h, ratio=MAP_RATIO)
w_len = len(data[0])
h_len = len(data)
for _map_data in data:
for _map in _map_data:
map_url = _map["url"]
await download_image(
map_url,
map_path / f"{idx}.png",
semaphore,
force_flag=flag,
)
BuildImage(
0, 0, background=f"{map_path}/{idx}.png", ratio=MAP_RATIO
).save()
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):
map_file.paste(
BuildImage(0, 0, background=f"{map_path}/{i}.png")
)
img = BuildImage(0, 0, background=f"{map_path}/{i}.png")
await map_file.apaste(img)
map_file.save(f"{map_path}/map.png")
else:
logger.warning(f'获取原神地图失败 msg: {data["message"]}')
@@ -202,7 +203,7 @@ async def download_map_init(semaphore: Semaphore, flag: bool = False):
except (TimeoutError, ConnectTimeout):
logger.warning("下载原神地图数据超时....")
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)
cookie_json = json.loads(cookie)
print(cookie_json)
if 'login_ticket' not in cookie_json:
await bind.finish("请发送正确完整的cookie!")
login_ticket = cookie_json['login_ticket']
# try:
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)
if cmd == "查看我的cookie":
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)
if not uid or not await Genshin.get_user_cookie(uid, True):
await genshin_matcher.finish("请先绑定uid和cookie!")
@@ -51,9 +53,9 @@ async def _(event: MessageEvent, cmd: Tuple[str, ...] = Command()):
# await genshin_matcher.finish("请更新cookie!")
if cmd == "原神我硬签":
try:
await genshin_matcher.send("正在进行签到...", at_sender=True)
msg = await genshin_sign(uid)
return_data = await mihoyobbs_sign(event.user_id)
await genshin_matcher.send(return_data)
logger.info(
f"(USER {event.user_id}, "
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)
next_date = await Genshin.random_sign_time(uid)
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:
msg = "原神签到失败..请尝试检查cookie或报告至管理员!"
logger.info(
@@ -38,16 +38,18 @@ mihoyobbs_matcher = on_command(
@mihoyobbs_matcher.handle()
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)
if return_data:
await mihoyobbs_matcher.finish(return_data)
await mihoyobbs_matcher.finish(return_data, at_sender=True)
else:
await mihoyobbs_matcher.finish("米游社签到失败,请查看控制台输出")
await mihoyobbs_matcher.finish("米游社签到失败,请查看控制台输出", at_sender=True)
async def mihoyobbs_sign(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)
stoken = await Genshin.get_stoken(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",
"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://s3.bmp.ovh/imgs/2022/07/24/28d9338c7da4bcb2.png",
"https://genshin.honeyhunterworld.com/img/gadget/i_3016.png",
"https://s3.bmp.ovh/imgs/2022/08/21/3a3b2e6c22e305ff.png",
"https://s3.bmp.ovh/imgs/2022/08/21/c2d7ace21e1d46cf.png",
],
):
file = memo_path / name
@@ -195,6 +195,7 @@ def parsed_data(
"magic_chest_number": data["stats"]["magic_chest_number"], # 奇馈宝箱
"common_chest_number": data["stats"]["common_chest_number"], # 普通宝箱
"electroculus_number": data["stats"]["electroculus_number"], # 雷神瞳已收集
"dendroculus_number": data["stats"]["dendroculus_number"], # 草神瞳已收集
}
world_data_dict = {}
for world in data["world_explorations"]:
@@ -129,7 +129,7 @@ def get_user_data_image(
"""
if mys_data:
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)
uname_img = BuildImage(
0,
@@ -163,36 +163,42 @@ def get_user_data_image(
/ random.choice(os.listdir(image_path / "chars_ava")),
)
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(uid_img, (170, 355), True)
region.paste(ava_bk, (int(550 / 2 - ava_bk.w / 2), 40), True)
region.paste(uname_img, (int(170 + uid_img.w / 2 - uname_img.w / 2), 365), True)
region.paste(uid_img, (170, 415), True)
region.paste(ava_bk, (int(550 / 2 - ava_bk.w / 2), 100), True)
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
keys = [
["活跃天数", "成就达成", "获得角色", "深境螺旋"],
["华丽宝箱", "珍贵宝箱", "精致宝箱", "普通宝箱"],
["奇馈宝箱", "风神瞳", "岩神瞳", "雷神瞳"],
["活跃天数", "成就达成", "获得角色", "解锁传送"],
["风神瞳", "岩神瞳", "雷神瞳", "草神瞳"],
["解锁秘境", "深境螺旋", "华丽宝箱", "珍贵宝箱"],
["精致宝箱", "普通宝箱", "奇馈宝箱",],
]
values = [
[
role_data["active_day_number"],
role_data["achievement_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["geoculus_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):
@@ -215,7 +221,7 @@ def get_user_data_image(
)
tmp_.text((0, 0), str(v), center_type="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
data_img.paste(_tmp_data_img, (0, _height))
_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: 家园列表
"""
h = 130 + 300 * 4
h = 130 + 340 * 4
region = BuildImage(
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.circle_corner(50)
region.paste(x, (0, height), True, "by_width")
height += 300
height += 340
return region
@@ -297,9 +303,9 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
: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
for country in ["蒙德", "龙脊雪山", "璃月", "层岩巨渊", "稻妻", "渊下宫"]:
for country in ["蒙德", "龙脊雪山", "璃月", "层岩巨渊", "稻妻", "渊下宫", "须弥"]:
if not world_data_dict.get(country):
continue
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")
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(
(450, 40),
(500, 40),
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
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(
(450, 120),
(500, 120),
f"Lv.{world_data_dict[country]['level']}",
fill=(255, 255, 255),
)
@@ -344,45 +350,65 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
fill=(255, 255, 255),
)
elif country in ["龙脊雪山"]:
content_bk.text((300, 40), "探索", fill=(239, 211, 114))
content_bk.text((300, 40), "雪山探索", fill=(239, 211, 114))
content_bk.text(
(450, 40),
(500, 40),
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
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(
(450, 120),
(500, 120),
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
fill=(255, 255, 255),
)
elif country in ["稻妻"]:
content_bk.text((300, 20), "探索", fill=(239, 211, 114))
content_bk.text((300, 20), "稻妻探索", fill=(239, 211, 114))
content_bk.text(
(450, 20),
(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((300, 85), "稻妻声望", fill=(239, 211, 114))
content_bk.text(
(450, 85),
(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((300, 150), "神樱眷顾", fill=(239, 211, 114))
content_bk.text(
(450, 150),
(500, 150),
f"Lv.{world_data_dict[country]['offerings'][0]['level']}",
fill=(255, 255, 255),
)
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(
(450, 20),
(530, 20),
f"{world_data_dict[country]['exploration_percentage'] / 10}%",
fill=(255, 255, 255),
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(content_bk, alpha=True, center_type="center")
x.circle_corner(20)
+7 -5
View File
@@ -1,3 +1,7 @@
from io import BytesIO
import imagehash
from PIL import Image
from nonebot import on_message, on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, ActionFailed
from nonebot.adapters.onebot.v11.permission import GROUP
@@ -70,10 +74,8 @@ def save_data():
json.dump(mute_data, f, indent=4)
async def download_img_and_hash(url, group_id) -> str:
if await AsyncHttpx.download_file(url, TEMP_PATH / f"mute_{group_id}_img.jpg"):
return str(get_img_hash(TEMP_PATH / f"mute_{group_id}_img.jpg"))
return ""
async def download_img_and_hash(url) -> str:
return str(imagehash.average_hash(Image.open(BytesIO((await AsyncHttpx.get(url)).content))))
mute_dict = {}
@@ -87,7 +89,7 @@ async def _(bot: Bot, event: GroupMessageEvent):
img_list = get_message_img(event.json())
img_hash = ""
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
if not mute_data.get(group_id):
mute_data[group_id] = {
+2 -2
View File
@@ -110,10 +110,10 @@ async def _(event: GroupMessageEvent):
vd_info = await video.get_video_base_info(msg)
elif "av" in msg:
index = msg.find("av")
if len(msg[index + 2 :]) >= 9:
if len(msg[index + 2 :]) >= 1:
msg = msg[index + 2 : index + 11]
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)
elif "https://b23.tv" in msg:
url = "https://" + msg[msg.find("b23.tv"): msg.find("b23.tv") + 14]
+1 -1
View File
@@ -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"
+6 -10
View File
@@ -81,19 +81,15 @@ async def _handle_check_in(
await BagUser.add_gold(user_qq, group, gold)
await BagUser.add_property(user_qq, group, gift)
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:
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)
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)
+41 -14
View File
@@ -1,3 +1,5 @@
import random
import time
from pathlib import Path
from nonebot.adapters.onebot.v11 import Message, MessageSegment
@@ -187,20 +189,45 @@ async def _():
if await WordBank.get_group_all_problem(0):
return
logger.info('开始迁移词条 纯文本 数据')
word_list = await OldWordBank.get_all()
for word in word_list:
problem: str = word.problem
user_id = word.user_qq
group_id = word.group_id
format_ = word.format
answer = word.answer
# 仅对纯文本做处理
if '[CQ' not in problem and '[CQ' not in answer and '[_to_me' not in problem:
if not format_:
await WordBank.add_problem_answer(user_id, group_id, 1, 0, problem, answer)
await WordBank.add_problem_answer(0, 0, 999, 0, '_[OK', '_[OK')
logger.info('词条 纯文本 数据迁移完成')
(Path() / 'plugins' / 'word_bank' / '_old_model.py').unlink()
try:
word_list = await OldWordBank.get_all()
new_answer_path = Path() / 'data' / 'word_bank' / 'answer'
new_problem_path = Path() / 'data' / 'word_bank' / 'problem'
new_answer_path.mkdir(exist_ok=True, parents=True)
for word in word_list:
problem: str = word.problem
user_id = word.user_qq
group_id = word.group_id
format_ = word.format
answer = word.answer
# 仅对纯文本做处理
if '[CQ' not in problem and '[CQ' not in answer and '[_to_me' not in problem:
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
View File
@@ -48,6 +48,7 @@ class WordBank(db.Model):
user_id: Optional[int],
group_id: Optional[int],
problem: str,
answer: Optional[str],
word_scope: Optional[int] = None,
word_type: Optional[int] = None,
) -> bool:
@@ -58,6 +59,7 @@ class WordBank(db.Model):
:param user_id: 用户id
:param group_id: 群号
:param problem: 问题
:param answer: 回答
:param word_scope: 词条范围
:param word_type: 词条类型
"""
@@ -66,6 +68,8 @@ class WordBank(db.Model):
query = query.where(cls.user_qq == user_id)
if group_id:
query = query.where(cls.group_id == group_id)
if answer:
query = query.where(cls.answer == answer)
if word_type:
query = query.where(cls.word_type == word_type)
if word_scope:
@@ -105,19 +109,20 @@ class WordBank(db.Model):
problem = str(get_img_hash(_file))
image_path = f"problem/{group_id}/{user_id}_{int(time.time())}.jpg"
answer, _list = await cls._answer2format(answer, user_id, group_id)
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=image_path,
placeholder=",".join(_list),
create_time=datetime.now().replace(microsecond=0),
update_time=datetime.now().replace(microsecond=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=image_path,
placeholder=",".join(_list),
create_time=datetime.now().replace(microsecond=0),
update_time=datetime.now().replace(microsecond=0),
)
@classmethod
async def _answer2format(
@@ -143,7 +148,7 @@ class WordBank(db.Model):
text += seg.data["text"]
elif seg.type == "face":
text += f"[face:placeholder_{index}]"
_list.append(seg.data.id)
_list.append(seg.data['id'])
elif seg.type == "at":
text += f"[at:placeholder_{index}]"
_list.append(seg.data["qq"])
@@ -234,16 +239,36 @@ class WordBank(db.Model):
query = query.where(cls.word_scope == word_type)
sql_text += f" and word_scope = {word_scope}"
# 完全匹配
if await query.where(cls.problem == problem).gino.first():
return query.where(cls.problem == problem)
if await query.where(
((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():
return query.where(cls.problem.contains(problem))
if await db.first(
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(
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(
# 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)
if query is not None:
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)
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
else answer.answer
)
@@ -459,3 +484,40 @@ class WordBank(db.Model):
problem_list.append(problem)
_tmp.append(q.problem)
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
View File
@@ -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 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 ._model import WordBank
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)
img = get_message_img(event.message)
at = get_message_at(event.message)
rand = random.randint(1, 100)
problem = text
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"):
problem = str(get_img_hash(TEMP_PATH / f"{event.user_id}_{rand}_word_bank_check.jpg"))
try:
r = await AsyncHttpx.get(img[0])
problem = str(imagehash.average_hash(Image.open(BytesIO(r.content))))
except TimeoutException:
pass
if at:
temp = ''
for seg in event.message:
if seg.type == 'at':
temp += f"[at:{seg.data['qq']}]"
else:
temp += seg
elif seg.type == 'text':
temp += seg.data["text"]
problem = temp
if problem:
return await WordBank.check(event, problem) is not None
if problem and (await WordBank.check(event, problem) is not None):
state["problem"] = problem
return True
return False
+4 -29
View File
@@ -1,14 +1,10 @@
import random
from services import logger
from utils.image_utils import get_img_hash
from ._rule import check
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 utils.utils import get_message_img, get_message_text, get_message_at
from nonebot import on_message
from utils.http_utils import AsyncHttpx
from nonebot.typing import T_State
__zx_plugin_name__ = "词库问答回复操作 [Hidden]"
@@ -19,26 +15,8 @@ message_handle = on_message(priority=6, block=True, rule=check)
@message_handle.handle()
async def _(event: MessageEvent):
text = get_message_text(event.message)
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:
async def _(event: MessageEvent, state: T_State):
if problem := state.get("problem"):
if msg := await WordBank.get_answer(event, problem):
await message_handle.send(msg)
logger.info(
@@ -46,6 +24,3 @@ async def _(event: MessageEvent):
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 触发词条 {problem}"
)
+25 -12
View File
@@ -1,3 +1,4 @@
import re
from typing import Tuple, Any, Optional
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 nonebot.params import CommandArg, RegexGroup, Command
from nonebot.exception import FinishedException
from services.log import logger
from configs.path_config import DATA_PATH
from utils.message_builder import custom_forward_msg
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 configs.config import Config
from ._data_source import delete_word, update_word, show_word
@@ -23,7 +25,7 @@ usage:
更推荐使用id方式删除
问题回答支持的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:
在私聊中超级用户额外设置
指令:
(全局|私聊)?添加词条\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)
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)
@@ -91,7 +93,7 @@ async def _(
state: T_State,
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('权限不足捏')
word_scope, word_type, problem, answer = reg_group
if (
@@ -113,18 +115,22 @@ async def _(
if seg.type == 'text' and '答' in str(seg):
_problem = event.message[:index]
answer = event.message[index:]
answer[0] = str(answer[0])[str(answer).index('答')+1:]
_problem[0] = str(_problem[0])[str(_problem).index('问')+1:]
answer[0] = str(answer[0])[str(answer[0]).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 = ''
for g in _problem:
if isinstance(g, str) or g.type == 'text':
if isinstance(g, str):
temp += g
elif g.type == 'text':
temp += g.data['text']
elif g.type == 'at':
temp += f"[at:{g.data['qq']}]"
problem = temp
break
index = len((word_scope or "") + "添加词条" + (word_type or "") + problem) + 1
event.message[0] = event.message[0].data["text"][index + 1 :].strip()
problem = unescape(problem)
event.message[0] = event.message[0].data["text"].split('答', maxsplit=1)[-1].strip()
state["word_scope"] = word_scope
state["word_type"] = word_type
state["problem"] = problem
@@ -141,6 +147,11 @@ async def _(
problem_image: Message = Arg("problem_image"),
):
try:
if word_type == "正则":
try:
re.compile(problem)
except re.error:
await add_word.finish(f"添加词条失败,正则表达式 {problem} 非法!")
await WordBank.add_problem_answer(
event.user_id,
event.group_id if isinstance(event, GroupMessageEvent) and (not word_scope or word_scope == '1') else 0,
@@ -150,6 +161,8 @@ async def _(
answer,
)
except Exception as e:
if isinstance(e, FinishedException):
await add_word.finish()
logger.error(
f"(USER {event.user_id}, GROUP "
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_)
or int(id_) < 0
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必须为数字且在范围内")
id_ = int(id_)
@@ -243,7 +256,7 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
not is_number(gid)
or int(gid) < 0
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必须为数字且在范围内")
gid = int(gid)
+7 -7
View File
@@ -178,8 +178,8 @@ class BuildImage:
self.h = int(h)
self.paste_image_width = int(paste_image_width)
self.paste_image_height = int(paste_image_height)
self.current_w = 0
self.current_h = 0
self._current_w = 0
self._current_h = 0
self.font = ImageFont.truetype(str(FONT_PATH / font), int(font_size))
if not plain_text and not color:
color = (255, 255, 255)
@@ -287,11 +287,11 @@ class BuildImage:
pos = (width, height)
if isinstance(img, BuildImage):
img = img.markImg
if self.current_w == self.w:
self.current_w = 0
self.current_h += self.paste_image_height
if self._current_w >= self.w:
self._current_w = 0
self._current_h += self.paste_image_height
if not pos:
pos = (self.current_w, self.current_h)
pos = (self._current_w, self._current_h)
if alpha:
try:
self.markImg.paste(img, pos, img)
@@ -300,7 +300,7 @@ class BuildImage:
self.markImg.paste(img, pos, img)
else:
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]:
"""
+19
View File
@@ -238,6 +238,25 @@ def get_message_img(data: Union[str, Message]) -> List[str]:
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]:
"""
说明: