Compare commits

...
70 Commits
Author SHA1 Message Date
HibiKier 8381858742 Update README.md 2022-05-23 22:02:49 +08:00
HibiKier 1040bd0d58 update v0.1.5.6 2022-05-23 22:01:56 +08:00
HibiKier 404e47332e Merge pull request #441 from with9/main
添加pixiv搜图多关键词支持;修复p站搜图数量参数问题
2022-05-23 21:52:33 +08:00
HibiKier 3db128785e Update __init__.py 2022-05-23 21:52:08 +08:00
HibiKier 2189ea11df Update README.md 2022-05-23 19:46:30 +08:00
HibiKier 49b9bd65b0 Merge pull request #552 from jk6589jk/patch-1
修复有置顶的up主B站动态获取失败
2022-05-23 19:45:59 +08:00
jk6589jk b3fdb1ff58 修复B站动态获取失败
bili-dyn-item__tag的父项的父项才是完整的一条置顶动态
2022-05-23 12:59:53 +08:00
HibiKier c79e3fdcf0 Update README.md 2022-05-23 07:52:27 +08:00
HibiKier d7509f7030 Merge pull request #545 from yajiwa/main
修复"清除已删除插件数据"
2022-05-23 07:51:54 +08:00
yajiwa 5c99b55502 fix none_plugin_count 2022-05-23 02:35:57 +08:00
yajiwa fd255f022b Merge branch 'HibiKier:main' into main 2022-05-23 02:27:00 +08:00
HibiKier 41642589ae Update __version__ 2022-05-22 20:56:03 +08:00
HibiKier 619fef3bff update README.md 2022-05-22 20:52:59 +08:00
HibiKier 38c0da0cf8 update v0.1.5.4 2022-05-22 20:51:35 +08:00
HibiKier b241a58e84 update check_update 2022-05-22 19:04:58 +08:00
HibiKier 35c9585b22 delete WindowsSelectorEventLoopPolicy 2022-05-22 19:03:22 +08:00
HibiKier d2fe95cc05 fix query_resource_points and sign_in 2022-05-22 18:08:06 +08:00
HibiKier 92e60ba141 fix epic 2022-05-22 15:22:57 +08:00
HibiKier 2356527791 update word_clouds 2022-05-22 12:51:53 +08:00
HibiKier cab0f7b522 update change_pixiv_image_links 2022-05-22 12:49:32 +08:00
HibiKier 02743d5955 Merge pull request #384 from AkashiCoin/main
Update anime.json of Kyomotoi/AnimeThesaurus
2022-05-21 23:40:13 +08:00
HibiKier a7ffebea35 Merge pull request #503 from yajiwa/main
修复命令不唯一的问题
2022-05-21 23:39:39 +08:00
HibiKier c511ef50a2 update wbtop 2022-05-21 23:34:48 +08:00
HibiKier 82902e0cde update invite_manager 2022-05-21 22:40:05 +08:00
AkashiCoin 1de5ae09bc Merge branch 'HibiKier:main' into main 2022-05-21 20:46:04 +08:00
yajiwa 8b735f1cb5 fix word_clouds 2022-05-21 20:08:53 +08:00
HibiKier 33d1334174 fix what_anime 2022-05-21 19:33:39 +08:00
HibiKier 324b58c21b update README.md 2022-05-21 16:42:19 +08:00
HibiKier b7b1651709 fix what_anime 2022-05-21 16:39:06 +08:00
HibiKier b5a4a6a9ff fix mute and open_case 2022-05-21 15:58:58 +08:00
HibiKier fe2c82b03c fix mute and open_case 2022-05-21 15:58:29 +08:00
HibiKier 81e4bca9ef fix mute 2022-05-21 13:46:29 +08:00
HibiKier c0d055b825 add get_message_img_file 2022-05-21 13:20:58 +08:00
HibiKier 188ae38525 fix bug 2022-05-21 13:15:53 +08:00
HibiKier 86a8fe7096 Merge pull request #462 from yajiwa/main
Update poetry file
2022-05-21 11:47:50 +08:00
yajiwa 0bb2b45f5c Update poetry.lock 2022-05-21 00:23:41 +08:00
yajiwa a17d8731c8 Update pyproject.toml 2022-05-21 00:22:44 +08:00
with9 9cdd2326c8 添加pixiv搜图多关键词支持;修复p站搜图数量参数问题 2022-05-20 19:35:18 +08:00
AkashiCoin d75653631d Merge branch 'HibiKier:main' into main 2022-05-19 23:21:02 +08:00
AkashiCoin e234c8906e Update anime.json 2022-05-19 23:20:00 +08:00
HibiKier 57baea18b5 Merge pull request #348 from sihuan/fix-bilibili_sub
Fix wrong live streamer name, fixes #284
2022-05-19 22:11:59 +08:00
HibiKier 0f3efe29c4 Merge pull request #357 from MingxuanGame/main
fix: mihoyo bbs api changed
2022-05-19 22:04:36 +08:00
HibiKier 89b87a38b3 Merge pull request #342 from yajiwa/main
fix bug
2022-05-19 21:03:23 +08:00
MingxuanGame c52b7ca2e9 fix: mihoyo bbs api changed 2022-05-19 17:47:20 +08:00
SiHuan 371b55dc9e Fix wrong live streamer name, fixes #284 2022-05-19 16:03:33 +08:00
yajiwa 53e572353c fix bug 2022-05-19 15:14:20 +08:00
yajiwa 3ae71c74e9 x 2022-05-19 15:10:42 +08:00
HibiKier cb643c04f7 Merge pull request #265 from yajiwa/main
Add word_clouds
2022-05-19 09:27:54 +08:00
yajiwa faf9ee159b update wordclouds url 2022-05-18 23:10:12 +08:00
yajiwa ffb3b2d73e Add word_clouds 2022-05-18 20:31:14 +08:00
HibiKier ffcc327089 Merge pull request #252 from yajiwa/main
Add wordclouds file
2022-05-18 20:04:13 +08:00
yajiwa dfd5a6a86a Add wordclouds file 2022-05-18 18:45:48 +08:00
HibiKier d43f89b067 Update README.md 2022-05-17 19:52:33 +08:00
HibiKier f15c3ab6a2 Update README.md 2022-05-16 19:20:01 +08:00
HibiKier e27809298e Merge pull request #160 from yajiwa/yajiwa
update word_bank
2022-05-16 19:19:20 +08:00
HibiKier 4b3e28e14b fix shop setu 2022-05-15 21:10:35 +08:00
yajiwa 71ce9153ed no message 2022-05-14 15:54:10 +08:00
yajiwa 25d63966de update word_bank 2022-05-14 15:47:33 +08:00
yajiwa 98afbb54b6 add get imgfile 2022-05-14 15:41:44 +08:00
HibiKier 03a51ca5dd Update README.md 2022-05-14 14:48:11 +08:00
HibiKier 428481b2d5 Merge pull request #159 from noahzark/patch-2
修复B站动态生成失败的问题
2022-05-14 14:47:30 +08:00
Feliciano Long f87c60e6db 修复B站动态生成失败的问题
B站动态样式更改
1. card已变更为bili-dyn-list__item
2. 置顶消息变成了一个tag(此处存疑,暂未发现其他tag
2022-05-13 19:38:24 +08:00
HibiKier 6d824e38bc Update README.md 2022-05-11 22:45:20 +08:00
HibiKier f0fd5bfb9e Merge pull request #155 from AkashiCoin/main
fix: 更改p搜api,解决p搜无法使用的问题
2022-05-11 22:44:32 +08:00
HibiKier 33374df671 Update pyproject.toml 2022-05-10 22:25:43 +08:00
AkashiCoin c035b1b19c Update pid_search.py 2022-05-10 18:47:39 +08:00
HibiKier b3b09ed666 update v0.1.5.3 2022-05-09 21:42:24 +08:00
HibiKier 8029c00a02 Update README.md 2022-05-05 20:32:22 +08:00
HibiKier a2c0921013 Merge pull request #153 from NumberSir/main
修改bilibili_sub插件在windows平台下报错
2022-05-05 20:32:17 +08:00
Number_Sir 31cdabc229 修改bilibili_sub插件在windows平台下报错
改用bilireq库,同时补充部分bilireq暂无的方法如获取番剧、获取用户投稿视频
2022-05-04 17:02:56 +08:00
79 changed files with 3490 additions and 1607 deletions
+73 -6
View File
@@ -18,10 +18,6 @@
## 声明 ## 声明
此项目仅用于学习交流,请勿用于非法用途 此项目仅用于学习交流,请勿用于非法用途
## Gitee
# [Gitee](https://gitee.com/two_Dimension/zhenxun_bot)
## 未完成的文档 ## 未完成的文档
# [传送门](https://hibikier.github.io/zhenxun_bot/) # [传送门](https://hibikier.github.io/zhenxun_bot/)
@@ -242,18 +238,89 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
## 更新 ## 更新
### 2022/5/23 \[v1.5.6]
* 修复"清除已删除插件数据" [@pull/545](https://github.com/HibiKier/zhenxun_bot/pull/545)
* 修复有置顶的up主B站动态获取失败 [@pull/552](https://github.com/HibiKier/zhenxun_bot/pull/552)
* 添加pixiv搜图多关键词支持;修复p站搜图数量参数问题 [@pull/441](https://github.com/HibiKier/zhenxun_bot/pull/441)
* 修复开箱更新价格错误传参
* 修复pix无法正确查询uid
* 新增色图插件添加配置项ALLOW_GROUP_R18:允许群聊中使用色图r
* 新增PIX插件添加配置项ALLOW_GROUP_SETU:允许非超级用户使用-s参数
* 新增PIX插件添加配置项ALLOW_GROUP_R18:允许非超级用户使用-r参数
### 2022/5/22 \[v0.1.5.4]
* 使用action自动更新poetry.lock [@pull/515](https://github.com/HibiKier/zhenxun_bot/pull/515)
* fix(bilibili_sub): card is None and timeout [@pull/516](https://github.com/HibiKier/zhenxun_bot/pull/516)
* 修复了epic有时获取新免费游戏消息时获取不到图片
* 修复好感度满时签到出错(虽然是不可能满的
* 修复原神资源图标下载路径错误
* 修复自动更新群组可能失败
### 2022/5/21
* 修复搜番无结果时报错无正确反馈
* 解锁了windows上无法使用playwright的限制
* 修复p搜对应pid有多张图时出错,改为连续发送图片
* 修复p搜对数字的错误判断
* 修复添加商品折扣无法正确添加
* 修复了bilibili订阅直播间订阅up名称不一致的问题
* 修复原神玩家查询没开地图时报错
* 最低priority修改为 999
* 修复刷屏检测失效
* 修复刷屏检测设置命令无法生效
* 优化刷屏显示设置禁言时长显示,并改为分钟
* 修复了多连开箱无法指定武器箱
* 修复识番链接无法正确获取
* 新增真寻入群时即刻刷新权限
* 提高了微博热搜截图的等待时间
### 2022/5/19
* fix: mihoyo bbs api changed [@pull/357](https://github.com/HibiKier/zhenxun_bot/pull/357)
* Add word_clouds [@pull/265](https://github.com/HibiKier/zhenxun_bot/pull/265)
* Fix wrong live streamer name [@pull/284](https://github.com/HibiKier/zhenxun_bot/pull/284)
### 2022/5/16
* 词条支持图片和@问题 [@pull/160](https://github.com/HibiKier/zhenxun_bot/pull/160)
### 2022/5/15
* 修复了商店商品无法正确添加
* 修复了多张色图无法正确发送
### 2022/5/14
* 修复B站动态生成失败的问题 [@pull/159](https://github.com/HibiKier/zhenxun_bot/pull/159)
### 2022/5/11
* fix: 更改p搜api,解决p搜无法使用的问题 [@pull/155](https://github.com/HibiKier/zhenxun_bot/pull/155)
### 2022/5/9 \[v0.1.5.3]
* 替换了疫情API
* 修复了私聊.ban/.unban出错
### 2022/5/5
* 修改bilibili_sub插件在windows平台下报错 [@pull/153](https://github.com/HibiKier/zhenxun_bot/pull/153)
### 2022/5/3 \[v0.1.5.2] ### 2022/5/3 \[v0.1.5.2]
* 商品使用函数可以添加特定参数,例如:user_id, group_id, ShopParam等以及自己提供的参数 * 商品使用函数可以添加特定参数,例如:user_id, group_id, ShopParam等以及自己提供的参数
* 添加商品注册装饰器shop_register * 添加商品注册装饰器shop_register
* 修复商品函数kwargs无法获取参数值 * 修复商品函数kwargs无法获取参数值
### 2022/5/1 ### 2022/5/1
* 删除了`group_last_chat`插件(该功能可由`chat_history`替代 * 删除了`group_last_chat`插件(该功能可由`chat_history`替代
* 新增敏感词检测(全新反击系统,是时候重拳出击了 * 新增敏感词检测(全新反击系统,是时候重拳出击了
### 2022/4/26 \[v0.5.1.0] ### 2022/4/26
* 修复了群白名单无法正确添加 * 修复了群白名单无法正确添加
* 优化了管理员帮助图片,背景图层将位于最下层 * 优化了管理员帮助图片,背景图层将位于最下层
@@ -488,4 +555,4 @@ __..... 更多更新信息请查看文档__
[NothAmor / nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) :基于nonebot2机器人框架的鲁迅说插件 [NothAmor / nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) :基于nonebot2机器人框架的鲁迅说插件
[Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何bot的词库 [Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何bot的词库
[Ailitonia / omega-miya](https://github.com/Ailitonia/omega-miya) :基于nonebot2的qq机器人 [Ailitonia / omega-miya](https://github.com/Ailitonia/omega-miya) :基于nonebot2的qq机器人
[KimigaiiWuyi / GenshinUID]("https://github.com/KimigaiiWuyi/GenshinUID") :一个基于HoshinoBot/NoneBot2的原神UID查询插件 [KimigaiiWuyi / GenshinUID](https://github.com/KimigaiiWuyi/GenshinUID) :一个基于HoshinoBot/NoneBot2的原神UID查询插件
+1 -1
View File
@@ -1 +1 @@
__version__: v0.1.5.1 __version__: v0.1.5.6
@@ -232,10 +232,7 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
_exist_member_list = [] _exist_member_list = []
# try: # try:
for user_info in _group_user_list: for user_info in _group_user_list:
if user_info["card"] == "": nickname = user_info["card"] or user_info["nickname"]
nickname = user_info["nickname"]
else:
nickname = user_info["card"]
async with db.transaction(): async with db.transaction():
# 更新权限 # 更新权限
if ( if (
@@ -321,3 +318,4 @@ def set_group_bot_status(group_id: int, status: bool) -> str:
# for x in group_manager.get_task_data(): # for x in group_manager.get_task_data():
# group_manager.close_group_task(group_id, x) # group_manager.close_group_task(group_id, x)
return "那我先睡觉了..." return "那我先睡觉了..."
@@ -2,6 +2,7 @@ from nonebot import on_command, on_notice
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent
from ._data_source import update_member_info from ._data_source import update_member_info
__zx_plugin_name__ = "更新群组成员列表 [Admin]" __zx_plugin_name__ = "更新群组成员列表 [Admin]"
__plugin_usage__ = """ __plugin_usage__ = """
usage: usage:
+6 -4
View File
@@ -125,11 +125,13 @@ async def _(
msg = arg.extract_plain_text().strip() msg = arg.extract_plain_text().strip()
if msg: if msg:
if str(event.user_id) in bot.config.superusers: if str(event.user_id) in bot.config.superusers:
if is_number(arg.extract_plain_text().strip().split()[0]): msg_splt = msg.split()
qq = int(msg[0]) if is_number(msg_splt[0]):
msg = msg[1:]
qq = int(msg_splt[0])
msg = msg_splt[1:]
if cmd in [".ban", "/ban"]: if cmd in [".ban", "/ban"]:
time = parse_ban_time(msg) time = parse_ban_time(" ".join(msg))
if isinstance(time, str): if isinstance(time, str):
await ban.finish(time) await ban.finish(time)
result = await a_ban(qq, time, str(qq), event, 9) result = await a_ban(qq, time, str(qq), event, 9)
+5 -12
View File
@@ -25,7 +25,9 @@ def parse_ban_time(msg: str) -> Union[int, str]:
return int(msg[0]) * 60 * 60 + int(msg[1]) * 60 return int(msg[0]) * 60 * 60 + int(msg[1]) * 60
async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_level: int = None) -> str: async def a_ban(
qq: int, time: int, user_name: str, event: MessageEvent, ban_level: int = None
) -> str:
""" """
ban ban
:param qq: qq :param qq: qq
@@ -38,7 +40,8 @@ async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_lev
ban_level = await LevelUser.get_user_level(event.user_id, event.group_id) ban_level = await LevelUser.get_user_level(event.user_id, event.group_id)
if await BanUser.ban(qq, ban_level, time): if await BanUser.ban(qq, ban_level, time):
logger.info( logger.info(
f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time / 60} 分钟" f"USER {event.user_id} GROUP"
f" {event.group_id if isinstance(event, GroupMessageEvent) else ''} 将 USER {qq} 封禁 时长 {time / 60} 分钟"
) )
result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!" result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!"
if time != -1: if time != -1:
@@ -57,13 +60,3 @@ async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_lev
time += " 分钟" time += " 分钟"
result = f"{user_name} 已在黑名单!预计 {time}后解封" result = f"{user_name} 已在黑名单!预计 {time}后解封"
return result return result
+3 -2
View File
@@ -2,6 +2,7 @@ from configs.config import Config
from models.chat_history import ChatHistory from models.chat_history import ChatHistory
from nonebot import on_message from nonebot import on_message
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from utils.utils import get_message_text
from ._rule import rule from ._rule import rule
@@ -22,10 +23,10 @@ chat_history = on_message(rule=rule, priority=1, block=False)
async def _(event: MessageEvent): async def _(event: MessageEvent):
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
await ChatHistory.add_chat_msg( await ChatHistory.add_chat_msg(
event.user_id, event.group_id, str(event.get_message()) event.user_id, event.group_id, str(event.get_message()), get_message_text(event.json())
) )
else: else:
await ChatHistory.add_chat_msg(event.user_id, None, str(event.get_message())) await ChatHistory.add_chat_msg(event.user_id, None, str(event.get_message()), get_message_text(event.json()))
# @test.handle() # @test.handle()
+19 -3
View File
@@ -1,5 +1,6 @@
from nonebot import on_notice, on_request from nonebot import on_notice, on_request
from configs.path_config import IMAGE_PATH, DATA_PATH from configs.path_config import IMAGE_PATH, DATA_PATH
from models.level_user import LevelUser
from utils.message_builder import image from utils.message_builder import image
from models.group_member_info import GroupInfoUser from models.group_member_info import GroupInfoUser
from datetime import datetime from datetime import datetime
@@ -96,6 +97,23 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
for plugin in data.keys(): for plugin in data.keys():
if not data[plugin]["default_status"]: if not data[plugin]["default_status"]:
group_manager.block_plugin(plugin, event.group_id) group_manager.block_plugin(plugin, event.group_id)
# 即刻刷新权限
for user_info in await bot.get_group_member_list(group_id=event.group_id):
if user_info["role"] in [
"owner",
"admin",
] and not await LevelUser.is_group_flag(
user_info["user_id"], event.group_id
):
await LevelUser.set_level(
user_info["user_id"],
user_info["group_id"],
Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"),
)
if str(user_info["user_id"]) in bot.config.superusers:
await LevelUser.set_level(
user_info["user_id"], user_info["group_id"], 9
)
else: else:
join_time = datetime.now() join_time = datetime.now()
user_info = await bot.get_group_member_info( user_info = await bot.get_group_member_info(
@@ -128,9 +146,7 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
msg = msg.replace("[at]", "") msg = msg.replace("[at]", "")
at_flag = True at_flag = True
if (DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg").exists(): if (DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg").exists():
img = image( img = image(DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg")
DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg"
)
if msg or img: if msg or img:
msg = msg.strip() + img msg = msg.strip() + img
msg = "\n" + msg if at_flag else msg msg = "\n" + msg if at_flag else msg
+3
View File
@@ -56,6 +56,9 @@ def _create_help_img(
for matcher in _matchers: for matcher in _matchers:
plugin_name = None plugin_name = None
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name) _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
if not _plugin:
logger.warning(f"获取 功能:{matcher.plugin_name} 失败...")
continue
_module = _plugin.module _module = _plugin.module
try: try:
plugin_name = _module.__getattribute__("__zx_plugin_name__") plugin_name = _module.__getattribute__("__zx_plugin_name__")
+2 -2
View File
@@ -106,7 +106,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
raise IgnoredException("功能总开关关闭状态") raise IgnoredException("功能总开关关闭状态")
except AttributeError: except AttributeError:
pass pass
if module in admin_manager.keys() and matcher.priority not in [1, 9]: if module in admin_manager.keys() and matcher.priority not in [1, 999]:
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
# 个人权限 # 个人权限
if ( if (
@@ -146,7 +146,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if event.is_tome(): if event.is_tome():
status_message_manager.add(event.user_id) status_message_manager.add(event.user_id)
raise IgnoredException("权限不足") raise IgnoredException("权限不足")
if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]: if module in plugins2info_dict.keys() and matcher.priority not in [1, 999]:
# 戳一戳单独判断 # 戳一戳单独判断
if isinstance(event, GroupMessageEvent) or isinstance(event, PokeNotifyEvent) or matcher.plugin_name in other_limit_plugins: if isinstance(event, GroupMessageEvent) or isinstance(event, PokeNotifyEvent) or matcher.plugin_name in other_limit_plugins:
if status_message_manager.get(event.group_id) is None: if status_message_manager.get(event.group_id) is None:
+3 -3
View File
@@ -31,7 +31,7 @@ _flmt = FreqLimiter(300)
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State): async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if ( if (
(isinstance(event, MessageEvent) or isinstance(event, PokeNotifyEvent)) (isinstance(event, MessageEvent) or isinstance(event, PokeNotifyEvent))
and matcher.priority not in [1, 9] and matcher.priority not in [1, 999]
) or matcher.plugin_name in other_limit_plugins: ) or matcher.plugin_name in other_limit_plugins:
try: try:
if ( if (
@@ -58,7 +58,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if not static_flmt.check(event.user_id): if not static_flmt.check(event.user_id):
raise IgnoredException("用户处于黑名单中") raise IgnoredException("用户处于黑名单中")
static_flmt.start_cd(event.user_id) static_flmt.start_cd(event.user_id)
if matcher.priority != 9: if matcher.priority != 999:
try: try:
ban_result = Config.get_config("hook", "BAN_RESULT") ban_result = Config.get_config("hook", "BAN_RESULT")
if ( if (
@@ -79,7 +79,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if not static_flmt.check(event.user_id): if not static_flmt.check(event.user_id):
raise IgnoredException("用户处于黑名单中") raise IgnoredException("用户处于黑名单中")
static_flmt.start_cd(event.user_id) static_flmt.start_cd(event.user_id)
if matcher.priority != 9: if matcher.priority != 999:
try: try:
ban_result = Config.get_config("hook", "BAN_RESULT") ban_result = Config.get_config("hook", "BAN_RESULT")
if ban_result and matcher.plugin_name not in ignore_rst_module: if ban_result and matcher.plugin_name not in ignore_rst_module:
+1 -1
View File
@@ -25,7 +25,7 @@ _blmt = BanCheckLimiter(
async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State): async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State):
if not isinstance(event, MessageEvent): if not isinstance(event, MessageEvent):
return return
if matcher.type == "message" and matcher.priority not in [1, 9]: if matcher.type == "message" and matcher.priority not in [1, 999]:
if state["_prefix"]["raw_command"]: if state["_prefix"]["raw_command"]:
if _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'): if _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'):
if await BanUser.ban( if await BanUser.ban(
@@ -20,26 +20,36 @@ def init_none_plugin_count_manager():
""" """
清除已删除插件数据 清除已删除插件数据
""" """
modules = [x.module for x in get_matchers()] modules = [x.plugin_name for x in get_matchers()]
for module in none_plugin_count_manager.keys(): plugins_manager_list = list(plugins_manager.keys())
if module not in modules: for module in plugins_manager_list:
none_plugin_count_manager.add_count(module) if module not in modules or none_plugin_count_manager.check(module):
else:
none_plugin_count_manager.reset(module)
if none_plugin_count_manager.check(module):
try: try:
plugin_name = plugins_manager.get(module)["plugin_name"] plugin_name = plugins_manager.get(module)["plugin_name"]
except (AttributeError, KeyError): except (AttributeError, KeyError):
plugin_name = "" plugin_name = ""
try: if none_plugin_count_manager.check(module):
plugins2settings_manager.delete(module) try:
plugins2count_manager.delete(module) plugins2settings_manager.delete(module)
plugins2cd_manager.delete(module) plugins2settings_manager.save()
plugins2block_manager.delete(module) plugins2count_manager.delete(module)
plugins_manager.delete(module) plugins2count_manager.save()
resources_manager.remove_resource(module) plugins2cd_manager.delete(module)
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...") plugins2cd_manager.save()
except Exception as e: plugins2block_manager.delete(module)
logger.error( plugins2block_manager.save()
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}:{e}" plugins_manager.delete(module)
) plugins_manager.save()
resources_manager.remove_resource(module)
none_plugin_count_manager.delete(module)
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...")
except Exception as e:
logger.exception(
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}:{e}")
else:
none_plugin_count_manager.add_count(module)
logger.info(
f"{module}:{plugin_name} 插件疑似已删除,加载{none_plugin_count_manager._max_count}次失败后将清除对应插件数据,当前次数:{none_plugin_count_manager._data[module]}")
else:
none_plugin_count_manager.reset(module)
none_plugin_count_manager.save()
+1 -1
View File
@@ -25,7 +25,7 @@ __plugin_configs__ = {
friend_req = on_request(priority=5, block=True) friend_req = on_request(priority=5, block=True)
group_req = on_request(priority=5, block=True) group_req = on_request(priority=5, block=True)
x = on_message(priority=9, block=False) x = on_message(priority=999, block=False)
exists_data = {"private": {}, "group": {}} exists_data = {"private": {}, "group": {}}
+4
View File
@@ -108,6 +108,10 @@ async def _():
"ALTER TABLE genshin ADD bind_group Integer;", "ALTER TABLE genshin ADD bind_group Integer;",
"genshin" "genshin"
), # 新增原神群号绑定字段 ), # 新增原神群号绑定字段
(
"ALTER TABLE chat_history ADD plain_text Text;",
"chat_history"
), # 新增纯文本
] ]
for sql in sql_str: for sql in sql_str:
try: try:
+5 -11
View File
@@ -13,6 +13,7 @@ import time
driver: Driver = nonebot.get_driver() driver: Driver = nonebot.get_driver()
use = require("use") use = require("use")
@@ -139,8 +140,7 @@ async def register_goods(
des: str, des: str,
discount: Optional[float] = 1, discount: Optional[float] = 1,
limit_time: Optional[int] = 0, limit_time: Optional[int] = 0,
**kwargs, ) -> bool:
):
""" """
添加商品 添加商品
例如: 折扣:可选参数↓ 限时时间:可选,单位为小时 例如: 折扣:可选参数↓ 限时时间:可选,单位为小时
@@ -151,18 +151,11 @@ async def register_goods(
:param des: 商品简介 :param des: 商品简介
:param discount: 商品折扣 :param discount: 商品折扣
:param limit_time: 商品限时销售时间,单位为小时 :param limit_time: 商品限时销售时间,单位为小时
:param kwargs: kwargs
:return: 是否添加成功 :return: 是否添加成功
""" """
if kwargs: if not await GoodsInfo.get_goods_info(name):
name = kwargs.get("name")
price = kwargs.get("price")
des = kwargs.get("des")
discount = kwargs.get("discount")
limit_time = kwargs.get("time_limit")
if await GoodsInfo.get_goods_info(name):
limit_time = float(limit_time) if limit_time else limit_time limit_time = float(limit_time) if limit_time else limit_time
discount = discount if discount is None else 1 discount = discount if discount is not None else 1
limit_time = ( limit_time = (
int(time.time() + limit_time * 60 * 60) int(time.time() + limit_time * 60 * 60)
if limit_time is not None and limit_time != 0 if limit_time is not None and limit_time != 0
@@ -171,6 +164,7 @@ async def register_goods(
return await GoodsInfo.add_goods( return await GoodsInfo.add_goods(
name, int(price), des, float(discount), limit_time name, int(price), des, float(discount), limit_time
) )
return False
# 删除商品 # 删除商品
+1 -1
View File
@@ -69,7 +69,7 @@ class GoodsUseFuncManager:
) )
else: else:
return self._data[goods_name]["func"]( return self._data[goods_name]["func"](
**kwargs, *parse_args(args)
) )
else: else:
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]): if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
+1 -1
View File
@@ -92,7 +92,7 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
level = 0 level = 0
if not msg: if not msg:
await add_group_level.finish("用法:修改群权限 [group] [level]") await add_group_level.finish("用法:修改群权限 [group] [level]")
msg = msg.split(" ") msg = msg.split()
if len(msg) < 2: if len(msg) < 2:
await add_group_level.finish("参数不完全..[group] [level]") await add_group_level.finish("参数不完全..[group] [level]")
if is_number(msg[0]) and is_number(msg[1]): if is_number(msg[0]) and is_number(msg[1]):
@@ -45,6 +45,7 @@ async def _():
group_info["group_name"], group_info["group_name"],
group_info["max_member_count"], group_info["max_member_count"],
group_info["member_count"], group_info["member_count"],
1
): ):
num += 1 num += 1
logger.info(f"自动更新群组 {g} 信息成功") logger.info(f"自动更新群组 {g} 信息成功")
+1450 -155
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -11,12 +11,13 @@ class ChatHistory(db.Model):
user_qq = db.Column(db.BigInteger(), nullable=False) user_qq = db.Column(db.BigInteger(), nullable=False)
group_id = db.Column(db.BigInteger()) group_id = db.Column(db.BigInteger())
text = db.Column(db.Text()) text = db.Column(db.Text())
plain_text = db.Column(db.Text())
create_time = db.Column(db.DateTime(timezone=True), nullable=False) create_time = db.Column(db.DateTime(timezone=True), nullable=False)
@classmethod @classmethod
async def add_chat_msg(cls, user_qq: int, group_id: Optional[int], text: str): async def add_chat_msg(cls, user_qq: int, group_id: Optional[int], text: str, plain_text: str):
await cls.create( await cls.create(
user_qq=user_qq, group_id=group_id, text=text, create_time=datetime.now() user_qq=user_qq, group_id=group_id, text=text, plain_text=plain_text, create_time=datetime.now()
) )
@classmethod @classmethod
@@ -97,7 +98,6 @@ class ChatHistory(db.Model):
if date_scope: if date_scope:
sql += f"AND create_time BETWEEN '{date_scope[0]}' AND '{date_scope[1]}' " sql += f"AND create_time BETWEEN '{date_scope[0]}' AND '{date_scope[1]}' "
sql += f"GROUP BY user_qq ORDER BY sum {order if order and order.upper() != 'DES' else ''} LIMIT {limit}" sql += f"GROUP BY user_qq ORDER BY sum {order if order and order.upper() != 'DES' else ''} LIMIT {limit}"
print(sql)
return await db.all(db.text(sql)) return await db.all(db.text(sql))
@classmethod @classmethod
+1 -2
View File
@@ -114,8 +114,7 @@ class GoodsInfo(db.Model):
参数: 参数:
:param goods_name: 商品名称 :param goods_name: 商品名称
""" """
query = await cls.query.where(cls.goods_name == goods_name).gino.first() return await cls.query.where(cls.goods_name == goods_name).gino.first()
return query
@classmethod @classmethod
async def get_all_goods(cls) -> List["GoodsInfo"]: async def get_all_goods(cls) -> List["GoodsInfo"]:
+15 -10
View File
@@ -1,3 +1,5 @@
from asyncpg import UniqueViolationError
from services.db_context import db from services.db_context import db
@@ -44,16 +46,19 @@ class LevelUser(db.Model):
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id)) query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
query = query.with_for_update() query = query.with_for_update()
user = await query.gino.first() user = await query.gino.first()
if user is None: try:
await cls.create( if not user:
user_qq=user_qq, await cls.create(
group_id=group_id, user_qq=user_qq,
user_level=level, group_id=group_id,
group_flag=group_flag, user_level=level,
) group_flag=group_flag,
return True )
else: return True
await user.update(user_level=level, group_flag=group_flag).apply() else:
await user.update(user_level=level, group_flag=group_flag).apply()
return False
except UniqueViolationError:
return False return False
@classmethod @classmethod
+1 -1
View File
@@ -37,7 +37,7 @@ Config.add_plugin_config(
"alapi", "ALAPI_TOKEN", None, help_="在 https://admin.alapi.cn/user/login 登录后获取token" "alapi", "ALAPI_TOKEN", None, help_="在 https://admin.alapi.cn/user/login 登录后获取token"
) )
ai = on_message(rule=to_me(), priority=8) ai = on_message(rule=to_me(), priority=998)
@ai.handle() @ai.handle()
+2
View File
@@ -23,6 +23,8 @@ async def get_data(url: str, params: Optional[dict] = None) -> Tuple[Union[dict,
return "没有搜索到...", 997 return "没有搜索到...", 997
return data, 200 return data, 200
else: else:
if data["code"] == 101:
return "缺失ALAPI TOKEN,请在配置文件中填写!", 999
return f'发生了错误...code:{data["code"]}', 999 return f'发生了错误...code:{data["code"]}', 999
except TimeoutError: except TimeoutError:
return "超时了....", 998 return "超时了....", 998
+2 -2
View File
@@ -60,8 +60,8 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
img = await AsyncPlaywright.screenshot( img = await AsyncPlaywright.screenshot(
url, url,
f"{IMAGE_PATH}/temp/wbtop_{event.user_id}.png", f"{IMAGE_PATH}/temp/wbtop_{event.user_id}.png",
"#pl_feedlist_index", "#pl_feed_main",
wait_time=5 wait_time=12
) )
if img: if img:
await wbtop.send(img) await wbtop.send(img)
+1 -1
View File
@@ -38,7 +38,7 @@ usage:
__plugin_des__ = "非常便利的B站订阅通知" __plugin_des__ = "非常便利的B站订阅通知"
__plugin_cmd__ = ["添加订阅 [主播/UP/番剧] [id/链接/番名]", "删除订阅 [id]", "查看订阅"] __plugin_cmd__ = ["添加订阅 [主播/UP/番剧] [id/链接/番名]", "删除订阅 [id]", "查看订阅"]
__plugin_version__ = 0.1 __plugin_version__ = 0.1
__plugin_author__ = "HibiKier" __plugin_author__ = "HibiKier & NumberSir"
__plugin_settings__ = { __plugin_settings__ = {
"level": 5, "level": 5,
"default_status": True, "default_status": True,
+39 -32
View File
@@ -1,12 +1,13 @@
from bilibili_api.exceptions.ResponseCodeException import ResponseCodeException from bilireq.exceptions import ResponseCodeError
from utils.manager import resources_manager from utils.manager import resources_manager
from asyncio.exceptions import TimeoutError from asyncio.exceptions import TimeoutError
from .model import BilibiliSub from .model import BilibiliSub
from bilibili_api.live import LiveRoom from bilireq.live import get_room_info_by_id
from bilibili_api import bangumi from .utils import get_meta
from utils.message_builder import image from utils.message_builder import image
from bilibili_api.user import User from bilireq.user import get_user_info
from bilibili_api import user from bilireq import dynamic
from .utils import get_videos
from typing import Optional from typing import Optional
from configs.path_config import IMAGE_PATH from configs.path_config import IMAGE_PATH
from datetime import datetime from datetime import datetime
@@ -36,9 +37,9 @@ async def add_live_sub(live_id: int, sub_user: str) -> str:
try: try:
async with db.transaction(): async with db.transaction():
try: try:
live = LiveRoom(live_id) """bilibili_api.live库的LiveRoom类中get_room_info改为bilireq.live库的get_room_info_by_id方法"""
live_info = (await live.get_room_info())["room_info"] live_info = await get_room_info_by_id(live_id)
except ResponseCodeException: except ResponseCodeError:
return f"未找到房间号Id:{live_id} 的信息,请检查Id是否正确" return f"未找到房间号Id:{live_id} 的信息,请检查Id是否正确"
uid = live_info["uid"] uid = live_info["uid"]
room_id = live_info["room_id"] room_id = live_info["room_id"]
@@ -78,16 +79,18 @@ async def add_up_sub(uid: int, sub_user: str) -> str:
try: try:
async with db.transaction(): async with db.transaction():
try: try:
u = user.User(uid) """bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
user_info = await u.get_user_info() user_info = await get_user_info(uid)
except ResponseCodeException: except ResponseCodeError:
return f"未找到UpId:{uid} 的信息,请检查Id是否正确" return f"未找到UpId:{uid} 的信息,请检查Id是否正确"
uname = user_info["name"] uname = user_info["name"]
dynamic_info = await u.get_dynamics(0) """bilibili_api.user库中User类的get_dynamics改为bilireq.dynamic库的get_user_dynamics方法"""
dynamic_info = await dynamic.get_user_dynamics(uid)
dynamic_upload_time = 0 dynamic_upload_time = 0
if dynamic_info.get("cards"): if dynamic_info.get("cards"):
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"] dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
video_info = await u.get_videos() """bilibili_api.user库中User类的get_videos改为bilireq.user库的get_videos方法"""
video_info = await get_videos(uid)
latest_video_created = 0 latest_video_created = 0
if video_info["list"].get("vlist"): if video_info["list"].get("vlist"):
latest_video_created = video_info["list"]["vlist"][0]["created"] latest_video_created = video_info["list"]["vlist"][0]["created"]
@@ -117,8 +120,9 @@ async def add_season_sub(media_id: int, sub_user: str) -> str:
try: try:
async with db.transaction(): async with db.transaction():
try: try:
season_info = await bangumi.get_meta(media_id) """bilibili_api.bangumi库中get_meta改为bilireq.bangumi库的get_meta方法"""
except ResponseCodeException: season_info = await get_meta(media_id)
except ResponseCodeError:
return f"未找到media_id:{media_id} 的信息,请检查Id是否正确" return f"未找到media_id:{media_id} 的信息,请检查Id是否正确"
season_id = season_info["media"]["season_id"] season_id = season_info["media"]["season_id"]
season_current_episode = season_info["media"]["new_ep"]["index"] season_current_episode = season_info["media"]["new_ep"]["index"]
@@ -200,7 +204,7 @@ async def get_sub_status(id_: int, sub_type: str) -> Optional[str]:
return await _get_up_status(id_) return await _get_up_status(id_)
elif sub_type == "season": elif sub_type == "season":
return await _get_season_status(id_) return await _get_season_status(id_)
except ResponseCodeException: except ResponseCodeError:
return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..." 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}")
@@ -212,12 +216,12 @@ async def _get_live_status(id_: int) -> Optional[str]:
获取直播订阅状态 获取直播订阅状态
:param id_: 直播间 id :param id_: 直播间 id
""" """
live = LiveRoom(id_) """bilibili_api.live库的LiveRoom类中get_room_info改为bilireq.live库的get_room_info_by_id方法"""
live_info = (await live.get_room_info())["room_info"] live_info = await get_room_info_by_id(id_)
title = live_info["title"] title = live_info["title"]
room_id = live_info["room_id"] room_id = live_info["room_id"]
live_status = live_info["live_status"] live_status = live_info["live_status"]
cover = live_info["cover"] cover = live_info["user_cover"]
sub = await BilibiliSub.get_sub(id_) sub = await BilibiliSub.get_sub(id_)
if sub.live_status != live_status: if sub.live_status != live_status:
await BilibiliSub.update_sub_info(id_, live_status=live_status) await BilibiliSub.update_sub_info(id_, live_status=live_status)
@@ -238,15 +242,16 @@ async def _get_up_status(id_: int) -> Optional[str]:
:return: :return:
""" """
_user = await BilibiliSub.get_sub(id_) _user = await BilibiliSub.get_sub(id_)
u = user.User(_user.uid) """bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
user_info = await u.get_user_info() user_info = await get_user_info(_user.uid)
uname = user_info["name"] uname = user_info["name"]
video_info = await u.get_videos() """bilibili_api.user库中User类的get_videos改为bilireq.user库的get_videos方法"""
video_info = await get_videos(id_)
latest_video_created = 0 latest_video_created = 0
video = None video = None
if _user.uname != uname: if _user.uname != uname:
await BilibiliSub.update_sub_info(id_, uname=uname) await BilibiliSub.update_sub_info(id_, uname=uname)
dynamic_img, dynamic_upload_time = await get_user_dynamic(u, _user) dynamic_img, dynamic_upload_time = await get_user_dynamic(id_, _user)
if video_info["list"].get("vlist"): if video_info["list"].get("vlist"):
video = video_info["list"]["vlist"][0] video = video_info["list"]["vlist"][0]
latest_video_created = video["created"] latest_video_created = video["created"]
@@ -280,7 +285,8 @@ async def _get_season_status(id_) -> Optional[str]:
获取 番剧 更新状态 获取 番剧 更新状态
:param id_: 番剧 id :param id_: 番剧 id
""" """
season_info = await bangumi.get_meta(id_) """bilibili_api.bangumi库中get_meta改为bilireq.bangumi库的get_meta方法"""
season_info = await get_meta(id_)
title = season_info["media"]["title"] title = season_info["media"]["title"]
_idx = (await BilibiliSub.get_sub(id_)).season_current_episode _idx = (await BilibiliSub.get_sub(id_)).season_current_episode
new_ep = season_info["media"]["new_ep"]["index"] new_ep = season_info["media"]["new_ep"]["index"]
@@ -297,15 +303,16 @@ async def _get_season_status(id_) -> Optional[str]:
async def get_user_dynamic( async def get_user_dynamic(
u: User, local_user: BilibiliSub uid: int, local_user: BilibiliSub
) -> "Optional[MessageSegment], int": ) -> "Optional[MessageSegment], int":
""" """
获取用户动态 获取用户动态
:param u: 用户类 :param uid: 用户uid
:param local_user: 数据库存储的用户数据 :param local_user: 数据库存储的用户数据
:return: 最新动态截图与时间 :return: 最新动态截图与时间
""" """
dynamic_info = await u.get_dynamics(0) """bilibili_api.user库中User类的get_dynamics改为bilireq.dynamic库的get_user_dynamics方法"""
dynamic_info = await dynamic.get_user_dynamics(uid)
browser = await get_browser() browser = await get_browser()
if dynamic_info.get("cards") and browser: if dynamic_info.get("cards") and browser:
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"] dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
@@ -317,21 +324,21 @@ async def get_user_dynamic(
wait_until="networkidle", wait_until="networkidle",
timeout=10000, timeout=10000,
) )
await page.set_viewport_size({"width": 2560, "height": 1080}) await page.set_viewport_size({"width": 2560, "height": 1080, "timeout": 10000*20}) # timeout: 200s
# 删除置顶 # 删除置顶
await page.evaluate( await page.evaluate(
""" """
xs = document.getElementsByClassName('first-card-with-title'); xs = document.getElementsByClassName('bili-dyn-item__tag');
for (x of xs) { for (x of xs) {
x.remove(); x.parentNode.parentNode.remove();
} }
""" """
) )
card = await page.query_selector(".card") card = page.locator(".bili-dyn-list__item").first
await card.wait_for()
# 截图并保存 # 截图并保存
await card.screenshot( await card.screenshot(
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg", path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
timeout=100000,
) )
except Exception as e: except Exception as e:
logger.error(f"B站订阅:获取用户动态 发送错误 {type(e)}:{e}") logger.error(f"B站订阅:获取用户动态 发送错误 {type(e)}:{e}")
+48 -4
View File
@@ -1,7 +1,8 @@
from utils.image_utils import BuildImage from utils.image_utils import BuildImage
from configs.path_config import IMAGE_PATH from configs.path_config import IMAGE_PATH
from utils.http_utils import AsyncHttpx from utils.http_utils import AsyncHttpx
from bilibili_api import user # from bilibili_api import user
from bilireq.user import get_user_info
from io import BytesIO from io import BytesIO
@@ -28,8 +29,8 @@ async def create_live_des_image(uid: int, title: str, cover: str, tags: str, des
:param des: 直播简介 :param des: 直播简介
:return: :return:
""" """
u = user.User(uid)
user_info = await u.get_user_info() user_info = await get_user_info(uid)
name = user_info["name"] name = user_info["name"]
sex = user_info["sex"] sex = user_info["sex"]
face = user_info["face"] face = user_info["face"]
@@ -37,7 +38,6 @@ async def create_live_des_image(uid: int, title: str, cover: str, tags: str, des
ava = BuildImage(100, 100, background=BytesIO(await get_pic(face))) ava = BuildImage(100, 100, background=BytesIO(await get_pic(face)))
ava.circle() ava.circle()
cover = BuildImage(470, 265, background=BytesIO(await get_pic(cover))) cover = BuildImage(470, 265, background=BytesIO(await get_pic(cover)))
print()
def _create_live_des_image( def _create_live_des_image(
@@ -68,3 +68,47 @@ def _create_live_des_image(
border_img = BuildImage(1772, 2657, background=border) border_img = BuildImage(1772, 2657, background=border)
bk = BuildImage(1772, 2657, font_size=30) bk = BuildImage(1772, 2657, font_size=30)
bk.paste(cover, (0, 100), center_type="by_width") bk.paste(cover, (0, 100), center_type="by_width")
async def get_meta(media_id: int, auth=None, reqtype="both", **kwargs):
"""
根据番剧 ID 获取番剧元数据信息,
作为bilibili_api和bilireq的替代品。
如果bilireq.bangumi更新了,可以转为调用bilireq.bangumi的get_meta方法,两者完全一致。
"""
from bilireq.utils import get
BASE_URL = "https://api.bilibili.com"
url = f"{BASE_URL}/pgc/review/user"
params = {"media_id": media_id}
raw_json = await get(url, raw=True, params=params, auth=auth, reqtype=reqtype, **kwargs)
return raw_json['result']
async def get_videos(
uid: int, tid: int = 0, pn: int = 1, keyword: str = "", order: str = "pubdate",
*, auth=None, reqtype="both", **kwargs
):
"""
获取用户投该视频信息
作为bilibili_api和bilireq的替代品。
如果bilireq.user更新了,可以转为调用bilireq.user的get_videos方法,两者完全一致。
:param uid: 用户 UID
:param tid: 分区 ID
:param pn: 页码
:param keyword: 搜索关键词
:param order: 排序方式,可以为 “pubdate(上传日期从新到旧), stow(收藏从多到少), click(播放量从多到少)”
"""
from bilireq.utils import get
BASE_URL = "https://api.bilibili.com"
url = f"{BASE_URL}/x/space/arc/search"
params = {
"mid": uid,
"ps": 30,
"tid": tid,
"pn": pn,
"keyword": keyword,
"order": order
}
return await get(url, params=params, auth=auth, reqtype=reqtype, **kwargs)
-1
View File
@@ -241,7 +241,6 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
uid = int(msg[0]) uid = int(msg[0])
id_ = int(msg[1]) id_ = int(msg[1])
punish_level = int(msg[2]) punish_level = int(msg[2])
print(uid, id_, punish_level)
rst = await set_user_punish(uid, id_, punish_level) rst = await set_user_punish(uid, id_, punish_level)
await set_punish.send(rst) await set_punish.send(rst)
logger.info( logger.info(
+1 -1
View File
@@ -77,7 +77,7 @@ async def show_black_text_image(
(punish_level_str, "等级"), (punish_level_str, "等级"),
(create_time_str, "记录日期"), (create_time_str, "记录日期"),
]: ]:
img = await text2image(s, color="#f9f6f2", _add_height=3.32) img = await text2image(s, color="#f9f6f2", _add_height=2.1)
w = _tmp_img.getsize(type_)[0] if _tmp_img.getsize(type_)[0] > img.w else img.w w = _tmp_img.getsize(type_)[0] if _tmp_img.getsize(type_)[0] > img.w else img.w
A = BuildImage(w + 11, img.h + 50, color="#f9f6f2", font_size=35, font="CJGaoDeGuo.otf") A = BuildImage(w + 11, img.h + 50, color="#f9f6f2", font_size=35, font="CJGaoDeGuo.otf")
await A.atext((10, 10), type_) await A.atext((10, 10), type_)
-1
View File
@@ -68,7 +68,6 @@ class BlackWord(db.Model):
user = await query.where(cls.black_word == black_word).order_by(cls.id.desc()).gino.first() user = await query.where(cls.black_word == black_word).order_by(cls.id.desc()).gino.first()
elif id_: elif id_:
user_list = await query.gino.all() user_list = await query.gino.all()
print(len(user_list))
if len(user_list) == 0 or (id_ < 0 or id_ > len(user_list)): if len(user_list) == 0 or (id_ < 0 or id_ > len(user_list)):
return False return False
user = user_list[id_] user = user_list[id_]
-2
View File
@@ -88,9 +88,7 @@ class BlackWordManager:
:param group_id: 群号 :param group_id: 群号
:param message: 消息 :param message: 消息
""" """
print(user_id, group_id, message)
if data := self._check(message): if data := self._check(message):
print(data)
if data[0]: if data[0]:
await _add_user_black_word( await _add_user_black_word(
user_id, group_id, data[0], message, int(data[1]) user_id, group_id, data[0], message, int(data[1])
+4 -4
View File
@@ -3,10 +3,10 @@ from configs.config import Config
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import platform import platform
if platform.system() == "Windows": # if platform.system() == "Windows":
import asyncio # import asyncio
#
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) # asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
url = "http://www.eclzz.mobi" url = "http://www.eclzz.mobi"
+3 -3
View File
@@ -14,9 +14,9 @@ import tarfile
import shutil import shutil
import os import os
if str(platform.system()).lower() == "windows": # if str(platform.system()).lower() == "windows":
policy = asyncio.WindowsSelectorEventLoopPolicy() # policy = asyncio.WindowsSelectorEventLoopPolicy()
asyncio.set_event_loop_policy(policy) # asyncio.set_event_loop_policy(policy)
driver = nonebot.get_driver() driver = nonebot.get_driver()
+24 -37
View File
@@ -1,58 +1,34 @@
from httpx import AsyncClient
from datetime import datetime from datetime import datetime
from nonebot.log import logger from nonebot.log import logger
from nonebot.adapters.onebot.v11 import Bot from nonebot.adapters.onebot.v11 import Bot
from configs.config import NICKNAME from configs.config import NICKNAME
from utils.http_utils import AsyncHttpx
# 获取所有 Epic Game Store 促销游戏 # 获取所有 Epic Game Store 促销游戏
# 方法参考:RSSHub /epicgames 路由 # 方法参考:RSSHub /epicgames 路由
# https://github.com/DIYgod/RSSHub/blob/master/lib/routes/epicgames/index.js # https://github.com/DIYgod/RSSHub/blob/master/lib/routes/epicgames/index.js
async def get_epic_game(): async def get_epic_game():
# 现在没用 graphql 辣
"""prv_graphql Code
epic_url = "https://www.epicgames.com/store/backend/graphql-proxy"
headers = {
"Referer": "https://www.epicgames.com/store/zh-CN/",
"Content-Type": "application/json; charset=utf-8",
}
data = {
"query": "query searchStoreQuery($allowCountries: String, $category: String, $count: Int, $country: String!, $keywords: String, $locale: String, $namespace: String, $sortBy: String, $sortDir: String, $start: Int, $tag: String, $withPrice: Boolean = false, $withPromotions: Boolean = false) {\n Catalog {\n searchStore(allowCountries: $allowCountries, category: $category, count: $count, country: $country, keywords: $keywords, locale: $locale, namespace: $namespace, sortBy: $sortBy, sortDir: $sortDir, start: $start, tag: $tag) {\n elements {\n title\n id\n namespace\n description\n effectiveDate\n keyImages {\n type\n url\n }\n seller {\n id\n name\n }\n productSlug\n urlSlug\n url\n items {\n id\n namespace\n }\n customAttributes {\n key\n value\n }\n categories {\n path\n }\n price(country: $country) @include(if: $withPrice) {\n totalPrice {\n discountPrice\n originalPrice\n voucherDiscount\n discount\n currencyCode\n currencyInfo {\n decimals\n }\n fmtPrice(locale: $locale) {\n originalPrice\n discountPrice\n intermediatePrice\n }\n }\n lineOffers {\n appliedRules {\n id\n endDate\n discountSetting {\n discountType\n }\n }\n }\n }\n promotions(category: $category) @include(if: $withPromotions) {\n promotionalOffers {\n promotionalOffers {\n startDate\n endDate\n discountSetting {\n discountType\n discountPercentage\n }\n }\n }\n upcomingPromotionalOffers {\n promotionalOffers {\n startDate\n endDate\n discountSetting {\n discountType\n discountPercentage\n }\n }\n }\n }\n }\n paging {\n count\n total\n }\n }\n }\n}\n",
"variables": {
"allowCountries": "CN",
"category": "freegames",
"count": 1000,
"country": "CN",
"locale": "zh-CN",
"sortBy": "effectiveDate",
"sortDir": "asc",
"withPrice": True,
"withPromotions": True,
},
}
"""
epic_url = "https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions?locale=zh-CN&country=CN&allowCountries=CN" epic_url = "https://store-site-backend-static-ipv4.ak.epicgames.com/freeGamesPromotions?locale=zh-CN&country=CN&allowCountries=CN"
headers = { headers = {
"Referer": "https://www.epicgames.com/store/zh-CN/", "Referer": "https://www.epicgames.com/store/zh-CN/",
"Content-Type": "application/json; charset=utf-8", "Content-Type": "application/json; charset=utf-8",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.80 Safari/537.36",
} }
async with AsyncClient(headers=headers) as client: try:
try: res = await AsyncHttpx.get(epic_url, headers=headers, timeout=10)
res = await client.get(epic_url, timeout=10.0) res_json = res.json()
res_json = res.json() games = res_json["data"]["Catalog"]["searchStore"]["elements"]
games = res_json["data"]["Catalog"]["searchStore"]["elements"] return games
return games except Exception as e:
except Exception as e: logger.error(f"Epic 访问接口错误 {type(e)}:{e}")
logger.error(str(e)) return None
return None
# 获取 Epic Game Store 免费游戏信息 # 获取 Epic Game Store 免费游戏信息
# 处理免费游戏的信息方法借鉴 pip 包 epicstore_api 示例 # 处理免费游戏的信息方法借鉴 pip 包 epicstore_api 示例
# https://github.com/SD4RK/epicstore_api/blob/master/examples/free_games_example.py # https://github.com/SD4RK/epicstore_api/blob/master/examples/free_games_example.py
async def get_epic_free(bot: Bot, Type_Event: str): async def get_epic_free(bot: Bot, type_event: str):
games = await get_epic_game() games = await get_epic_game()
if not games: if not games:
return "Epic 可能又抽风啦,请稍后再试(", 404 return "Epic 可能又抽风啦,请稍后再试(", 404
@@ -81,7 +57,7 @@ async def get_epic_free(bot: Bot, Type_Event: str):
end_date = datetime.fromisoformat(end_date_iso).strftime( end_date = datetime.fromisoformat(end_date_iso).strftime(
"%b.%d %H:%M" "%b.%d %H:%M"
) )
if Type_Event == "Group": if type_event == "Group":
_message = "\n由 {} 公司发行的游戏 {} ({}) 在 UTC 时间 {} 即将推出免费游玩,预计截至 {}。".format( _message = "\n由 {} 公司发行的游戏 {} ({}) 在 UTC 时间 {} 即将推出免费游玩,预计截至 {}。".format(
game_corp, game_name, game_price, start_date, end_date game_corp, game_name, game_price, start_date, end_date
) )
@@ -101,8 +77,19 @@ async def get_epic_free(bot: Bot, Type_Event: str):
msg_list.append(msg) msg_list.append(msg)
else: else:
for image in game["keyImages"]: for image in game["keyImages"]:
if image["type"] == "Thumbnail": if (
image.get("url")
and not game_thumbnail
and image["type"]
in [
"Thumbnail",
"VaultOpened",
"DieselStoreFrontWide",
"OfferImageWide",
]
):
game_thumbnail = image["url"] game_thumbnail = image["url"]
break
for pair in game["customAttributes"]: for pair in game["customAttributes"]:
if pair["key"] == "developerName": if pair["key"] == "developerName":
game_dev = pair["value"] game_dev = pair["value"]
@@ -127,7 +114,7 @@ async def get_epic_free(bot: Bot, Type_Event: str):
game_url = "https://www.epicgames.com/store/zh-CN/p/{}".format( game_url = "https://www.epicgames.com/store/zh-CN/p/{}".format(
game_url_part game_url_part
) )
if Type_Event == "Group": if type_event == "Group":
_message = "[CQ:image,file={}]\n\nFREE now :: {} ({})\n{}\n此游戏由 {} 开发、{} 发行,将在 UTC 时间 {} 结束免费游玩,戳链接速度加入你的游戏库吧~\n{}\n".format( _message = "[CQ:image,file={}]\n\nFREE now :: {} ({})\n{}\n此游戏由 {} 开发、{} 发行,将在 UTC 时间 {} 结束免费游玩,戳链接速度加入你的游戏库吧~\n{}\n".format(
game_thumbnail, game_thumbnail,
game_name, game_name,
+4 -3
View File
@@ -9,6 +9,7 @@ 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 services.log import logger
from configs.config import NICKNAME
__zx_plugin_name__ = "复读" __zx_plugin_name__ = "复读"
@@ -74,15 +75,15 @@ class Fudu:
_fudu_list = Fudu() _fudu_list = Fudu()
fudu = on_message(permission=GROUP, priority=9) fudu = on_message(permission=GROUP, priority=999)
@fudu.handle() @fudu.handle()
async def _(event: GroupMessageEvent): async def _(event: GroupMessageEvent):
if event.is_tome(): if event.is_tome():
return return
if get_message_text(event.json()): if msg := get_message_text(event.json()):
if get_message_text(event.json()).find("@可爱的小真寻") != -1: if msg.startswith(f"@可爱的{NICKNAME}"):
await fudu.finish("复制粘贴的虚空艾特?", at_sender=True) await fudu.finish("复制粘贴的虚空艾特?", at_sender=True)
img = get_message_img(event.json()) img = get_message_img(event.json())
msg = get_message_text(event.json()) msg = get_message_text(event.json())
+1 -1
View File
@@ -35,7 +35,7 @@ Config.add_plugin_config(
default_value=True, default_value=True,
) )
almanac = on_command("原神黄历", priority=5, block=True) almanac = on_command("原神黄历", priority=15, block=True)
ALC_PATH = IMAGE_PATH / "genshin" / "alc" ALC_PATH = IMAGE_PATH / "genshin" / "alc"
@@ -1,6 +1,6 @@
from pathlib import Path
from typing import Tuple, Optional, List from typing import Tuple, Optional, List
from configs.path_config import IMAGE_PATH, TEXT_PATH from configs.path_config import IMAGE_PATH, TEXT_PATH
from PIL.Image import UnidentifiedImageError
from utils.message_builder import image from utils.message_builder import image
from services.log import logger from services.log import logger
from utils.image_utils import BuildImage from utils.image_utils import BuildImage
@@ -137,7 +137,7 @@ async def download_resource_data(semaphore: Semaphore):
asyncio.ensure_future( asyncio.ensure_future(
download_image( download_image(
img_url, img_url,
f"{icon_path}/{id_}.png", icon_path / f"{id_}.png",
semaphore, semaphore,
True, True,
) )
@@ -179,7 +179,7 @@ async def download_map_init(semaphore: Semaphore, flag: bool = False):
map_url = _map_data["url"] map_url = _map_data["url"]
await download_image( await download_image(
map_url, map_url,
f"{map_path}/{idx}.png", map_path / f"{idx}.png",
semaphore, semaphore,
force_flag=flag, force_flag=flag,
) )
@@ -228,15 +228,14 @@ async def download_resource_type():
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}")
# 初始化资源图标 # 初始化资源图标
def gen_icon(icon: str): def gen_icon(icon: Path):
A = BuildImage(0, 0, background=f"{icon_path}/box.png") A = BuildImage(0, 0, background=f"{icon_path}/box.png")
B = BuildImage(0, 0, background=f"{icon_path}/box_alpha.png") B = BuildImage(0, 0, background=f"{icon_path}/box_alpha.png")
icon_ = icon_path / f"{icon}" icon_img = BuildImage(115, 115, background=icon)
icon_img = BuildImage(115, 115, background=icon_)
icon_img.circle() icon_img.circle()
B.paste(icon_img, (17, 10), True) B.paste(icon_img, (17, 10), True)
B.paste(A, alpha=True) B.paste(A, alpha=True)
@@ -247,22 +246,22 @@ def gen_icon(icon: str):
# 下载图片 # 下载图片
async def download_image( async def download_image(
img_url: str, img_url: str,
path: str, path: Path,
semaphore: Semaphore, semaphore: Semaphore,
gen_flag: bool = False, gen_flag: bool = False,
force_flag: bool = False, force_flag: bool = False,
): ):
async with semaphore: async with semaphore:
try: try:
if not os.path.exists(path) or not is_valid or force_flag: if not path.exists() or not is_valid(path) or force_flag:
if await AsyncHttpx.download_file(img_url, path, timeout=10): if await AsyncHttpx.download_file(img_url, path, timeout=10):
logger.info(f"下载原神资源图标:{img_url}") logger.info(f"下载原神资源图标:{img_url}")
if gen_flag: if gen_flag:
gen_icon(path) gen_icon(path)
else: else:
logger.info(f"下载原神资源图标:{img_url} 失败,等待下次更新...") logger.info(f"下载原神资源图标:{img_url} 失败,等待下次更新...")
except UnidentifiedImageError: except Exception as e:
logger.warning(f"原神图片打开错误..已删除,等待下次更新... file: {path}") logger.warning(f"原神图片错误..已删除,等待下次更新... file: {path} {type(e)}:{e}")
if os.path.exists(path): if os.path.exists(path):
os.remove(path) os.remove(path)
@@ -128,7 +128,7 @@ async def get_character(
) -> Optional[dict]: ) -> Optional[dict]:
try: try:
req = await AsyncHttpx.post( req = await AsyncHttpx.post(
url="https://api-takumi.mihoyo.com/game_record/app/genshin/api/character", url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/character",
headers={ headers={
"Accept": "application/json, text/plain, */*", "Accept": "application/json, text/plain, */*",
"DS": get_ds( "DS": get_ds(
@@ -232,7 +232,7 @@ async def get_mys_data(uid: str, mys_id: Optional[str]) -> Optional[List[Dict]]:
if mys_id: if mys_id:
try: try:
req = await AsyncHttpx.get( req = await AsyncHttpx.get(
url=f"https://api-takumi.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid={mys_id}", url=f"https://api-takumi-record.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid={mys_id}",
headers={ headers={
"DS": get_ds(f"uid={mys_id}"), "DS": get_ds(f"uid={mys_id}"),
"x-rpc-app_version": Config.get_config("genshin", "mhyVersion"), "x-rpc-app_version": Config.get_config("genshin", "mhyVersion"),
@@ -300,6 +300,8 @@ def get_country_data_image(world_data_dict: Dict) -> BuildImage:
region = BuildImage(790, 267 * (len(world_data_dict) - 1), color="#F9F6F2") region = BuildImage(790, 267 * (len(world_data_dict) - 1), color="#F9F6F2")
height = 0 height = 0
for country in ["蒙德", "龙脊雪山", "璃月", "层岩巨渊", "稻妻", "渊下宫"]: for country in ["蒙德", "龙脊雪山", "璃月", "层岩巨渊", "稻妻", "渊下宫"]:
if not world_data_dict.get(country):
continue
x = BuildImage(790, 250, color="#3A4467") x = BuildImage(790, 250, color="#3A4467")
logo = BuildImage(180, 180, background=image_path / "logo" / f"{country}.png") logo = BuildImage(180, 180, background=image_path / "logo" / f"{country}.png")
tmp_bk = BuildImage(770, 230, color="#606779") tmp_bk = BuildImage(770, 230, color="#606779")
@@ -1,3 +1,5 @@
from nonebot.adapters.onebot.v11 import ActionFailed
from utils.utils import get_bot, scheduler from utils.utils import get_bot, scheduler
from utils.message_builder import at from utils.message_builder import at
from models.group_member_info import GroupInfoUser from models.group_member_info import GroupInfoUser
@@ -178,10 +180,13 @@ async def _remind(user_id: int, uid: str):
group_list = await GroupInfoUser.get_user_all_group(user_id) group_list = await GroupInfoUser.get_user_all_group(user_id)
if group_list: if group_list:
group_id = group_list[0] group_id = group_list[0]
await bot.send_group_msg( try:
group_id=group_id, await bot.send_group_msg(
message=at(user_id) + msg group_id=group_id,
) message=at(user_id) + msg
)
except ActionFailed as e:
logger.error(f"树脂提醒推送发生错误 {type(e)}:{e}")
if not next_time: if not next_time:
if user_manager.check(uid) and Config.get_config("resin_remind", "AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND"): if user_manager.check(uid) and Config.get_config("resin_remind", "AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND"):
await Genshin.set_resin_remind(int(uid), False) await Genshin.set_resin_remind(int(uid), False)
+14 -16
View File
@@ -1,8 +1,7 @@
from nonebot import on_message, on_command from nonebot import on_message, on_command
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message
from nonebot.adapters.onebot.v11.permission import GROUP from nonebot.adapters.onebot.v11.permission import GROUP
from utils.utils import is_number, get_message_img from utils.utils import is_number, get_message_img, get_message_text
from nonebot.typing import T_State
from nonebot.adapters.onebot.v11.exception import ActionFailed from nonebot.adapters.onebot.v11.exception import ActionFailed
from configs.path_config import DATA_PATH, TEMP_PATH from configs.path_config import DATA_PATH, TEMP_PATH
from utils.image_utils import get_img_hash from utils.image_utils import get_img_hash
@@ -10,7 +9,7 @@ from services.log import logger
from configs.config import NICKNAME, Config from configs.config import NICKNAME, Config
from utils.http_utils import AsyncHttpx from utils.http_utils import AsyncHttpx
from nonebot.params import CommandArg, Command from nonebot.params import CommandArg, Command
from typing import Tuple from typing import Tuple, Dict, Any
import time import time
try: try:
@@ -57,7 +56,7 @@ mute_setting = on_command(
) )
def get_data(): def get_data() -> Dict[Any, Any]:
try: try:
with open(DATA_PATH / "group_mute_data.json", "r", encoding="utf8") as f: with open(DATA_PATH / "group_mute_data.json", "r", encoding="utf8") as f:
data = json.load(f) data = json.load(f)
@@ -72,7 +71,7 @@ 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): async def download_img_and_hash(url, group_id) -> str:
if await AsyncHttpx.download_file( if await AsyncHttpx.download_file(
url, TEMP_PATH / f"mute_{group_id}_img.jpg" url, TEMP_PATH / f"mute_{group_id}_img.jpg"
): ):
@@ -85,9 +84,9 @@ mute_data = get_data()
@mute.handle() @mute.handle()
async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): async def _(bot: Bot, event: GroupMessageEvent):
group_id = str(event.group_id) group_id = str(event.group_id)
msg = arg.extract_plain_text().strip() msg = get_message_text(event.json())
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:
@@ -102,8 +101,6 @@ async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command()
if not mute_dict.get(event.user_id): if not mute_dict.get(event.user_id):
mute_dict[event.user_id] = {"time": time.time(), "count": 1, "msg": msg} mute_dict[event.user_id] = {"time": time.time(), "count": 1, "msg": msg}
else: else:
if cmd or not msg:
return
if msg and msg.find(mute_dict[event.user_id]["msg"]) != -1: if msg and msg.find(mute_dict[event.user_id]["msg"]) != -1:
mute_dict[event.user_id]["count"] += 1 mute_dict[event.user_id]["count"] += 1
else: else:
@@ -123,7 +120,7 @@ async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command()
await bot.set_group_ban( await bot.set_group_ban(
group_id=event.group_id, group_id=event.group_id,
user_id=event.user_id, user_id=event.user_id,
duration=mute_data[group_id]["duration"], duration=mute_data[group_id]["duration"] * 60,
) )
await mute.send(f"检测到恶意刷屏,{NICKNAME}要把你关进小黑屋!", at_sender=True) await mute.send(f"检测到恶意刷屏,{NICKNAME}要把你关进小黑屋!", at_sender=True)
mute_dict[event.user_id]["count"] = 0 mute_dict[event.user_id]["count"] = 0
@@ -137,27 +134,28 @@ async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command()
@mute_setting.handle() @mute_setting.handle()
async def _(event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()): async def _(event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
global mute_data
group_id = str(event.group_id) group_id = str(event.group_id)
if not mute_data.get(group_id): if not mute_data.get(group_id):
mute_data[group_id] = {"count": 10, "time": 7, "duration": 0} mute_data[group_id] = {"count": Config.get_config("mute", "MUTE_DEFAULT_COUNT"), "time": Config.get_config("mute", "MUTE_DEFAULT_TIME"), "duration": Config.get_config("mute", "MUTE_DEFAULT_DURATION")}
msg = arg.extract_plain_text().strip() msg = arg.extract_plain_text().strip()
if cmd[0] == "刷屏检测设置": if cmd[0] == "刷屏检测设置":
await mute_setting.finish( await mute_setting.finish(
f'最大次数:{mute_data[group_id]["count"]} 次\n' f'最大次数:{mute_data[group_id]["count"]} 次\n'
f'规定时间:{mute_data[group_id]["time"]} 秒\n' f'规定时间:{mute_data[group_id]["time"]} 秒\n'
f'禁言时长:{mute_data[group_id]["duration"] / 60} 分钟\n' f'禁言时长:{mute_data[group_id]["duration"]:.2f} 分钟\n'
f"【在规定时间内发送相同消息超过最大次数则禁言\n当禁言时长为0时关闭此功能】" f"【在规定时间内发送相同消息超过最大次数则禁言\n当禁言时长为0时关闭此功能】"
) )
if not is_number(msg): if not is_number(msg):
await mute.finish("设置的参数必须是数字啊!", at_sender=True) await mute.finish("设置的参数必须是数字啊!", at_sender=True)
if cmd[0] == "设置检测时间": if cmd[0] == "设置刷屏检测时间":
mute_data[group_id]["time"] = int(msg) mute_data[group_id]["time"] = int(msg)
msg += "秒" msg += "秒"
if cmd[0] == "设置检测次数": if cmd[0] == "设置刷屏检测次数":
mute_data[group_id]["count"] = int(msg) mute_data[group_id]["count"] = int(msg)
msg += " 次" msg += " 次"
if cmd[0] == "设置禁言时长": if cmd[0] == "设置刷屏禁言时长":
mute_data[group_id]["duration"] = int(msg) * 60 mute_data[group_id]["duration"] = int(msg)
msg += " 分钟" msg += " 分钟"
await mute_setting.send(f'刷屏检测:{cmd[0]}为 {msg}') await mute_setting.send(f'刷屏检测:{cmd[0]}为 {msg}')
logger.info( logger.info(
+9 -10
View File
@@ -1,4 +1,4 @@
from typing import Type from typing import Type, Tuple, Any
from nonebot import on_command from nonebot import on_command
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from utils.utils import scheduler, is_number from utils.utils import scheduler, is_number
@@ -9,7 +9,7 @@ from nonebot.permission import SUPERUSER
import random import random
from nonebot.plugin import MatcherGroup from nonebot.plugin import MatcherGroup
from configs.path_config import IMAGE_PATH from configs.path_config import IMAGE_PATH
from nonebot.params import CommandArg from nonebot.params import CommandArg, RegexGroup
from .open_cases_c import ( from .open_cases_c import (
open_case, open_case,
total_open_statistics, total_open_statistics,
@@ -145,12 +145,12 @@ async def _(event: GroupMessageEvent):
) )
open_shilian: Type[Matcher] = cases_matcher_group.on_regex("(.*)连开箱(.*?)") open_shilian: Type[Matcher] = cases_matcher_group.on_regex("(.*)连开箱(.*)?")
@open_shilian.handle() @open_shilian.handle()
async def _(event: GroupMessageEvent, state: T_State): async def _(event: GroupMessageEvent, state: T_State, reg_group: Tuple[Any, ...] = RegexGroup()):
num = state["_matched_groups"][0].strip() num, case_name = reg_group
if is_number(num) or num_dict.get(num): if is_number(num) or num_dict.get(num):
try: try:
num = num_dict[num] num = num_dict[num]
@@ -162,7 +162,6 @@ async def _(event: GroupMessageEvent, state: T_State):
await open_shilian.finish("再负开箱就扣你明天开箱数了!", at_sender=True) await open_shilian.finish("再负开箱就扣你明天开箱数了!", at_sender=True)
else: else:
await open_shilian.finish("必须要是数字切不要超过30啊笨蛋!中文也可!", at_sender=True) await open_shilian.finish("必须要是数字切不要超过30啊笨蛋!中文也可!", at_sender=True)
case_name = state["_matched_groups"][1].strip()
case_name = case_name.replace("武器箱", "").strip() case_name = case_name.replace("武器箱", "").strip()
if not case_name: if not case_name:
case_name = random.choice(cases_name) case_name = random.choice(cases_name)
@@ -212,16 +211,16 @@ update_price = on_command("更新开箱价格", priority=1, permission=SUPERUSER
@update_price.handle() @update_price.handle()
async def _( event: MessageEvent): async def _(event: MessageEvent, arg: Message = CommandArg()):
await update_price.send(await util_get_buff_price(str(event.get_message()))) await update_price.send(await util_get_buff_price(arg.extract_plain_text().strip()))
update_img = on_command("更新开箱图片", priority=1, permission=SUPERUSER, block=True) update_img = on_command("更新开箱图片", priority=1, permission=SUPERUSER, block=True)
@update_img.handle() @update_img.handle()
async def _(event: MessageEvent): async def _(event: MessageEvent, arg: Message = CommandArg()):
await update_img.send(await util_get_buff_img(str(event.get_message()))) await update_img.send(await util_get_buff_img(str(arg.extract_plain_text().strip())))
# 重置开箱 # 重置开箱
+166 -171
View File
@@ -1,171 +1,166 @@
from nonebot import on_message # from nonebot import on_message
from services.log import logger # from services.log import logger
from nonebot.adapters.onebot.v11 import GroupMessageEvent # from nonebot.adapters.onebot.v11 import GroupMessageEvent
from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text # from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text
from nonebot.adapters.onebot.v11.permission import GROUP # from nonebot.adapters.onebot.v11.permission import GROUP
from bilibili_api import video # from utils.message_builder import image
from utils.message_builder import image # from nonebot.adapters.onebot.v11.exception import ActionFailed
from nonebot.adapters.onebot.v11.exception import ActionFailed # from utils.image_utils import BuildImage
from utils.image_utils import BuildImage # from utils.browser import get_browser
from utils.browser import get_browser # from configs.path_config import IMAGE_PATH
from configs.path_config import IMAGE_PATH # from utils.http_utils import AsyncHttpx
from utils.http_utils import AsyncHttpx # from configs.config import Config
from configs.config import Config # from utils.user_agent import get_user_agent
from utils.user_agent import get_user_agent # import aiohttp
import aiohttp # import asyncio
import asyncio # import time
import time # import ujson as json
from bilibili_api import settings #
import ujson as json #
# __zx_plugin_name__ = "B站转发解析"
# __plugin_usage__ = """
__zx_plugin_name__ = "B站转发解析" # usage:
__plugin_usage__ = """ # B站转发解析,解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv,且5分钟内不解析相同url
usage: # """.strip()
B站转发解析,解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv,且5分钟内不解析相同url # __plugin_des__ = "B站转发解析"
""".strip() # __plugin_type__ = ("其他",)
__plugin_des__ = "B站转发解析" # __plugin_version__ = 0.1
__plugin_type__ = ("其他",) # __plugin_author__ = "HibiKier"
__plugin_version__ = 0.1 # __plugin_task__ = {"bilibili_parse": "b站转发解析"}
__plugin_author__ = "HibiKier" # Config.add_plugin_config(
__plugin_task__ = {"bilibili_parse": "b站转发解析"} # "_task",
Config.add_plugin_config( # "DEFAULT_BILIBILI_PARSE",
"_task", # True,
"DEFAULT_BILIBILI_PARSE", # help_="被动 B站转发解析 进群默认开关状态",
True, # default_value=True,
help_="被动 B站转发解析 进群默认开关状态", # )
default_value=True, #
) #
# parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False)
#
if get_local_proxy(): # _tmp = {}
settings.proxy = get_local_proxy() #
#
parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False) # @parse_bilibili_json.handle()
# async def _(event: GroupMessageEvent):
_tmp = {} # vd_info = None
# url = None
# if get_message_json(event.json()):
@parse_bilibili_json.handle() # try:
async def _(event: GroupMessageEvent): # data = json.loads(get_message_json(event.json())[0]["data"])
vd_info = None # except (IndexError, KeyError):
url = None # data = None
if get_message_json(event.json()): # if data:
try: # # 转发视频
data = json.loads(get_message_json(event.json())[0]["data"]) # if data.get("desc") == "哔哩哔哩":
except (IndexError, KeyError): # async with aiohttp.ClientSession(
data = None # headers=get_user_agent()
if data: # ) as session:
# 转发视频 # async with session.get(
if data.get("desc") == "哔哩哔哩": # data["meta"]["detail_1"]["qqdocurl"],
async with aiohttp.ClientSession( # proxy=get_local_proxy(),
headers=get_user_agent() # timeout=7,
) as session: # ) as response:
async with session.get( # url = str(response.url).split("?")[0]
data["meta"]["detail_1"]["qqdocurl"], # bvid = url.split("/")[-1]
proxy=get_local_proxy(), # vd_info = await video.Video(bvid=bvid).get_info()
timeout=7, # # response = await AsyncHttpx.get(
) as response: # # data["meta"]["detail_1"]["qqdocurl"], timeout=7
url = str(response.url).split("?")[0] # # )
bvid = url.split("/")[-1] # # url = str(response.url).split("?")[0]
vd_info = await video.Video(bvid=bvid).get_info() # # bvid = url.split("/")[-1]
# response = await AsyncHttpx.get( # # vd_info = await video.Video(bvid=bvid).get_info()
# data["meta"]["detail_1"]["qqdocurl"], timeout=7 # # 转发专栏
# ) # if (
# url = str(response.url).split("?")[0] # data.get("meta")
# bvid = url.split("/")[-1] # and data["meta"].get("news")
# vd_info = await video.Video(bvid=bvid).get_info() # and data["meta"]["news"].get("desc") == "哔哩哔哩专栏"
# 转发专栏 # ):
if ( # url = data["meta"]["news"]["jumpUrl"]
data.get("meta") # page = None
and data["meta"].get("news") # try:
and data["meta"]["news"].get("desc") == "哔哩哔哩专栏" # browser = await get_browser()
): # if not browser:
url = data["meta"]["news"]["jumpUrl"] # return
page = None # page = await browser.new_page(
try: # user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
browser = await get_browser() # " (KHTML, like Gecko) Chrome/93.0.4530.0 Safari/537.36"
if not browser: # )
return # await page.goto(url, wait_until="networkidle", timeout=10000)
page = await browser.new_page( # await page.set_viewport_size({"width": 2560, "height": 1080})
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" # await page.click("#app > div")
" (KHTML, like Gecko) Chrome/93.0.4530.0 Safari/537.36" # div = await page.query_selector("#app > div")
) # await div.screenshot(
await page.goto(url, wait_until="networkidle", timeout=10000) # path=f"{IMAGE_PATH}/temp/cv_{event.user_id}.png",
await page.set_viewport_size({"width": 2560, "height": 1080}) # timeout=100000,
await page.click("#app > div") # )
div = await page.query_selector("#app > div") # await asyncio.get_event_loop().run_in_executor(
await div.screenshot( # None, resize, f"{IMAGE_PATH}/temp/cv_{event.user_id}.png"
path=f"{IMAGE_PATH}/temp/cv_{event.user_id}.png", # )
timeout=100000, # await parse_bilibili_json.send(
) # "[[_task|bilibili_parse]]" + image(f"cv_{event.user_id}.png", "temp")
await asyncio.get_event_loop().run_in_executor( # )
None, resize, f"{IMAGE_PATH}/temp/cv_{event.user_id}.png" # await page.close()
) # logger.info(
await parse_bilibili_json.send( # f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
"[[_task|bilibili_parse]]" + image(f"cv_{event.user_id}.png", "temp") # )
) # except Exception as e:
await page.close() # logger.error(f"尝试解析bilibili专栏 {url} 失败 {type(e)}:{e}")
logger.info( # if page:
f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}" # await page.close()
) # return
except Exception as e: # # BV
logger.error(f"尝试解析bilibili专栏 {url} 失败 {type(e)}:{e}") # if msg := get_message_text(event.json()):
if page: # if "BV" in msg:
await page.close() # index = msg.find("BV")
return # if len(msg[index + 2 :]) >= 10:
# BV # msg = msg[index : index + 12]
if msg := get_message_text(event.json()): # url = f"https://www.bilibili.com/video/{msg}"
if "BV" in msg: # vd_info = await video.Video(bvid=msg).get_info()
index = msg.find("BV") # elif "av" in msg:
if len(msg[index + 2 :]) >= 10: # index = msg.find("av")
msg = msg[index : index + 12] # if len(msg[index + 2 :]) >= 9:
url = f"https://www.bilibili.com/video/{msg}" # msg = msg[index + 2 : index + 11]
vd_info = await video.Video(bvid=msg).get_info() # if is_number(msg):
elif "av" in msg: # url = f"https://www.bilibili.com/video/{msg}"
index = msg.find("av") # vd_info = await video.Video(aid=int(msg)).get_info()
if len(msg[index + 2 :]) >= 9: # elif "https://b23.tv" in msg:
msg = msg[index + 2 : index + 11] # url = "https://" + msg[msg.find("b23.tv") : msg.find("b23.tv") + 13]
if is_number(msg): # res = await AsyncHttpx.get(url, timeout=7)
url = f"https://www.bilibili.com/video/{msg}" # url = str(res.url).split("?")[0]
vd_info = await video.Video(aid=int(msg)).get_info() # bvid = url.split("/")[-1]
elif "https://b23.tv" in msg: # vd_info = await video.Video(bvid=bvid).get_info()
url = "https://" + msg[msg.find("b23.tv") : msg.find("b23.tv") + 13] # if vd_info:
res = await AsyncHttpx.get(url, timeout=7) # if (
url = str(res.url).split("?")[0] # url in _tmp.keys() and time.time() - _tmp[url] > 30
bvid = url.split("/")[-1] # ) or url not in _tmp.keys():
vd_info = await video.Video(bvid=bvid).get_info() # _tmp[url] = time.time()
if vd_info: # aid = vd_info["aid"]
if ( # title = vd_info["title"]
url in _tmp.keys() and time.time() - _tmp[url] > 30 # author = vd_info["owner"]["name"]
) or url not in _tmp.keys(): # reply = vd_info["stat"]["reply"] # 回复
_tmp[url] = time.time() # favorite = vd_info["stat"]["favorite"] # 收藏
aid = vd_info["aid"] # coin = vd_info["stat"]["coin"] # 投币
title = vd_info["title"] # # like = vd_info['stat']['like'] # 点赞
author = vd_info["owner"]["name"] # # danmu = vd_info['stat']['danmaku'] # 弹幕
reply = vd_info["stat"]["reply"] # 回复 # date = time.strftime("%Y-%m-%d", time.localtime(vd_info["ctime"]))
favorite = vd_info["stat"]["favorite"] # 收藏 # try:
coin = vd_info["stat"]["coin"] # 投币 # await parse_bilibili_json.send(
# like = vd_info['stat']['like'] # 点赞 # "[[_task|bilibili_parse]]" +
# danmu = vd_info['stat']['danmaku'] # 弹幕 # image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n"
date = time.strftime("%Y-%m-%d", time.localtime(vd_info["ctime"])) # f"UP:{author}\n"
try: # f"上传日期:{date}\n"
await parse_bilibili_json.send( # f"回复:{reply},收藏:{favorite},投币:{coin}\n"
"[[_task|bilibili_parse]]" + # f"{url}"
image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n" # )
f"UP:{author}\n" # except ActionFailed:
f"上传日期:{date}\n" # logger.warning(f"{event.group_id} 发送bilibili解析失败")
f"回复:{reply},收藏:{favorite},投币:{coin}\n" # else:
f"{url}" # logger.info(
) # f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
except ActionFailed: # )
logger.warning(f"{event.group_id} 发送bilibili解析失败") #
else: #
logger.info( # def resize(path: str):
f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}" # A = BuildImage(0, 0, background=path, ratio=0.5)
) # A.save(path)
def resize(path: str):
A = BuildImage(0, 0, background=path, ratio=0.5)
A.save(path)
+117 -100
View File
@@ -1,100 +1,117 @@
from asyncio.exceptions import TimeoutError from nonebot import on_command
from nonebot import on_command from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent
from nonebot.adapters.onebot.v11 import MessageEvent, Message, GroupMessageEvent from nonebot.typing import T_State
from nonebot.typing import T_State
from configs.path_config import TEMP_PATH from configs.config import Config
from services.log import logger from utils.utils import is_number, change_pixiv_image_links
from utils.message_builder import image from utils.message_builder import image
from utils.utils import is_number from services.log import logger
from utils.manager import withdraw_message_manager from asyncio.exceptions import TimeoutError
from utils.http_utils import AsyncHttpx from configs.path_config import IMAGE_PATH
from nonebot.params import CommandArg, Arg from utils.manager import withdraw_message_manager
from utils.http_utils import AsyncHttpx
try: from nonebot.params import CommandArg, Arg
import ujson as json
except ModuleNotFoundError:
import json __zx_plugin_name__ = "pid搜索"
__plugin_usage__ = """
usage:
__zx_plugin_name__ = "pid搜索" 通过 pid 搜索图片
__plugin_usage__ = """ 指令:
usage: p搜 [pid]
通过 pid 搜索图片 """.strip()
指令: __plugin_des__ = "通过 pid 搜索图片"
p搜 [pid] __plugin_cmd__ = ["p搜 [pid]"]
""".strip() __plugin_version__ = 0.1
__plugin_des__ = "通过 pid 搜索图片" __plugin_author__ = "HibiKier"
__plugin_cmd__ = ["p搜 [pid]"] __plugin_settings__ = {
__plugin_version__ = 0.1 "level": 5,
__plugin_author__ = "HibiKier" "default_status": True,
__plugin_settings__ = { "limit_superuser": False,
"level": 5, "cmd": ["p搜"],
"default_status": True, }
"limit_superuser": False,
"cmd": ["p搜"], pid_search = on_command("p搜", aliases={"pixiv搜", "P搜"}, priority=5, block=True)
}
pid_search = on_command("p搜", aliases={"pixiv搜", "P搜"}, priority=5, block=True) @pid_search.handle()
async def _h(event: MessageEvent, state: T_State, arg: Message = CommandArg()):
url = "https://api.fantasyzone.cc/tu/search.php" pid = arg.extract_plain_text().strip()
if pid:
state["pid"] = pid
@pid_search.handle()
async def _(state: T_State, arg: Message = CommandArg()):
pid = arg.extract_plain_text().strip() headers = {
if pid: "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;"
state["pid"] = pid " rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
"Referer": "https://www.pixiv.net",
}
@pid_search.got("pid", prompt="需要查询的图片PID是?")
async def _(event: MessageEvent, state: T_State, pid: str = Arg("pid")):
if pid in ["取消", "算了"]: @pid_search.got("pid", prompt="需要查询的图片PID是?")
await pid_search.finish("已取消操作...") async def _g(event: MessageEvent, state: T_State, pid: str = Arg("pid")):
if is_number(pid): url = Config.get_config("hibiapi", "HIBIAPI") + "/api/pixiv/"
await pid_search.reject_arg("pid", "笨蛋,重新输入数!字!") if pid in ["取消", "算了"]:
params = { await pid_search.finish("已取消操作...")
"id": pid, if not is_number(pid):
"p": 1, await pid_search.reject_arg("pid", "笨蛋,重新输入数!字!")
} for _ in range(3):
for _ in range(3): try:
try: data = (
data = (await AsyncHttpx.get(url, params=params, timeout=5)).json() await AsyncHttpx.get(
except TimeoutError: url,
pass params={"id": pid},
except Exception as e: timeout=5,
await pid_search.finish(f"发生了一些错误..{type(e)}:{e}") )
else: ).json()
if not data["width"] and not data["height"]: except TimeoutError:
await pid_search.finish(f"没有搜索到 PID:{pid} 的图片", at_sender=True) pass
pid = data["id"] except Exception as e:
title = data["title"] await pid_search.finish(f"发生了一些错误..{type(e)}:{e}")
author = data["userName"] else:
author_id = data["userId"] if data.get("error"):
img_url = data["url"] await pid_search.finish(data["error"]["user_message"], at_sender=True)
if not await AsyncHttpx.download_file( data = data["illust"]
img_url, TEMP_PATH / f"pid_search_{event.user_id}.png" if not data["width"] and not data["height"]:
): await pid_search.finish(f"没有搜索到 PID:{pid} 的图片", at_sender=True)
await pid_search.finish("图片下载失败了....", at_sender=True) pid = data["id"]
tmp = "" title = data["title"]
if isinstance(event, GroupMessageEvent): author = data["user"]["name"]
tmp = "\n【注】将在30后撤回......" author_id = data["user"]["id"]
msg_id = await pid_search.send( image_list = []
Message( try:
f"title:{title}\n" image_list.append(data["meta_single_page"]["original_image_url"])
f"pid:{pid}\n" except KeyError:
f"author:{author}\n" for image_url in data["meta_pages"]:
f"author_id:{author_id}\n" image_list.append(image_url["image_urls"]["original"])
f'{image(TEMP_PATH / f"pid_search_{event.user_id}.png")}' for i, img_url in enumerate(image_list):
f"{tmp}" img_url = change_pixiv_image_links(img_url)
) if not await AsyncHttpx.download_file(
) img_url,
logger.info( IMAGE_PATH / "temp" / f"pid_search_{event.user_id}_{i}.png",
f"(USER {event.user_id}, " headers=headers,
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" ):
f" 查询图片 PID:{pid}" await pid_search.send("图片下载失败了....", at_sender=True)
) tmp = ""
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
withdraw_message_manager.append((msg_id, 30)) tmp = "\n【注】将在30后撤回......"
break msg_id = await pid_search.send(
else: Message(
await pid_search.finish("图片下载失败了....", at_sender=True) f"title:{title}\n"
f"pid:{pid}\n"
f"author:{author}\n"
f"author_id:{author_id}\n"
f'{image(f"pid_search_{event.user_id}_{i}.png", "temp")}'
f"{tmp}"
)
)
logger.info(
f"(USER {event.user_id}, "
f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 查询图片 PID:{pid}"
)
if isinstance(event, GroupMessageEvent):
withdraw_message_manager.append((msg_id, 30))
break
else:
await pid_search.finish("图片下载失败了....", at_sender=True)
+3 -3
View File
@@ -20,9 +20,9 @@ try:
except ModuleNotFoundError: except ModuleNotFoundError:
import json import json
if str(platform.system()).lower() == "windows": # if str(platform.system()).lower() == "windows":
policy = asyncio.WindowsSelectorEventLoopPolicy() # policy = asyncio.WindowsSelectorEventLoopPolicy()
asyncio.set_event_loop_policy(policy) # asyncio.set_event_loop_policy(policy)
headers = { headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;" "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;"
@@ -139,15 +139,14 @@ class OmegaPixivIllusts(db.Model):
data = await cls.select('pid').gino.all() data = await cls.select('pid').gino.all()
return [x[0] for x in data] return [x[0] for x in data]
@classmethod # async def test(cls, nsfw_tag: int = 1):
async def test(cls, nsfw_tag: int = 1): # if nsfw_tag is not None:
if nsfw_tag is not None: # query = cls.query.where(cls.nsfw_tag == nsfw_tag)
query = cls.query.where(cls.nsfw_tag == nsfw_tag) # else:
else: # query = cls.query
query = cls.query # query = query.where((cls.width - cls.height) < 50)
query = query.where((cls.width - cls.height) < 50) # for x in await query.gino.all():
for x in await query.gino.all(): # print(x.pid)
print(x.pid)
+11 -5
View File
@@ -18,6 +18,7 @@ usage:
查看 pix 好康图库 查看 pix 好康图库
指令: 指令:
pix ?*[tags]: 通过 tag 获取相似图片,不含tag时随机抽取 pix ?*[tags]: 通过 tag 获取相似图片,不含tag时随机抽取
pid [uid]: 通过uid获取图片
pix pid[pid]: 查看图库中指定pid图片 pix pid[pid]: 查看图库中指定pid图片
""".strip() """.strip()
__plugin_superuser_usage__ = """ __plugin_superuser_usage__ = """
@@ -49,7 +50,9 @@ __plugin_configs__ = {
"value": None, "value": None,
"help": "单次发送的图片数量达到指定值时转发为合并消息", "help": "单次发送的图片数量达到指定值时转发为合并消息",
"default_value": None, "default_value": None,
} },
"ALLOW_GROUP_SETU": {"value": False, "help": "允许非超级用户使用-s参数", "default_value": False},
"ALLOW_GROUP_R18": {"value": False, "help": "允许非超级用户使用-r参数", "default_value": False},
} }
@@ -80,10 +83,13 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
nsfw_tag = 2 nsfw_tag = 2
else: else:
nsfw_tag = 0 nsfw_tag = 0
if nsfw_tag != 0 and str(event.user_id) not in bot.config.superusers: if str(event.user_id) not in bot.config.superusers:
await pix.finish("你不能看这些噢,这些都是是留给管理员看的...") if (nsfw_tag == 1 and not Config.get_config("pix", "ALLOW_GROUP_SETU")) or (
if n := len(x) == 1 and is_number(x[0]): nsfw_tag == 2 and not Config.get_config("pix", "ALLOW_GROUP_R18")
num = int(x[-1]) ):
await pix.finish("你不能看这些噢,这些都是是留给管理员看的...")
if n := len(x) == 1 and is_number(x[0]) and int(x[0]) < 100:
num = int(x[0])
keyword = "" keyword = ""
elif n > 1: elif n > 1:
if is_number(x[-1]): if is_number(x[-1]):
+4 -2
View File
@@ -44,6 +44,8 @@ usage:
搜图 樱岛麻衣 搜图 樱岛麻衣
搜图 樱岛麻衣 5 搜图 樱岛麻衣 5
搜图 樱岛麻衣 5 r18 搜图 樱岛麻衣 5 r18
搜图 樱岛麻衣#1000users 5
【多个关键词用#分割】
【默认为 热度排序】 【默认为 热度排序】
【注意空格!!】【在线搜索会较慢】【数量可能不符?可能该页数量不够,也可能被R-18屏蔽】 【注意空格!!】【在线搜索会较慢】【数量可能不符?可能该页数量不够,也可能被R-18屏蔽】
""".strip() """.strip()
@@ -161,8 +163,8 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
info_list = None info_list = None
num = 10 num = 10
page = 1 page = 1
if (n := len(msg)) == 1: if (n := len(msg)) > 0:
keyword = msg[0] keyword = msg[0].replace("#"," ")
if n > 1: if n > 1:
if not is_number(msg[1]): if not is_number(msg[1]):
await pixiv_keyword.finish("图片数量必须是数字!", at_sender=True) await pixiv_keyword.finish("图片数量必须是数字!", at_sender=True)
+4 -4
View File
@@ -8,10 +8,10 @@ from services.log import logger
from pathlib import Path from pathlib import Path
import platform import platform
if platform.system() == "Windows": # if platform.system() == "Windows":
import asyncio # import asyncio
#
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) # asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
headers = { headers = {
+2
View File
@@ -49,6 +49,8 @@ async def _(bot: Bot, event: MessageEvent, state: T_State, key_word: str = ArgSt
Config.get_config("search_anime", "SEARCH_ANIME_MAX_INFO"), Config.get_config("search_anime", "SEARCH_ANIME_MAX_INFO"),
) )
if anime_report: if anime_report:
if isinstance(anime_report, str):
await search_anime.finish(anime_report)
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
mes_list = custom_forward_msg(anime_report, bot.self_id) mes_list = custom_forward_msg(anime_report, bot.self_id)
await bot.send_group_forward_msg(group_id=event.group_id, messages=mes_list) await bot.send_group_forward_msg(group_id=event.group_id, messages=mes_list)
+4 -4
View File
@@ -3,18 +3,18 @@ import feedparser
from urllib import parse from urllib import parse
from services.log import logger from services.log import logger
from utils.http_utils import AsyncHttpx from utils.http_utils import AsyncHttpx
from typing import List from typing import List, Union
import time import time
async def from_anime_get_info(key_word: str, max_: int) -> List[str]: async def from_anime_get_info(key_word: str, max_: int) -> Union[str, List[str]]:
s_time = time.time() s_time = time.time()
repass = ""
url = "https://share.dmhy.org/topics/rss/rss.xml?keyword=" + parse.quote(key_word) url = "https://share.dmhy.org/topics/rss/rss.xml?keyword=" + parse.quote(key_word)
try: try:
repass = await get_repass(url, max_) repass = await get_repass(url, max_)
except Exception as e: except Exception as e:
logger.error("Timeout! {}".format(e)) logger.error(f"发生了一些错误 {type(e)}:{e}")
return "发生了一些错误!"
repass.insert(0, f"搜索 {key_word} 结果(耗时 {int(time.time() - s_time)} 秒):\n") repass.insert(0, f"搜索 {key_word} 结果(耗时 {int(time.time() - s_time)} 秒):\n")
return repass return repass
+1 -1
View File
@@ -25,7 +25,7 @@ async def get_saucenao_image(url: str) -> Union[str, List[str]]:
} }
data = (await AsyncHttpx.post(API_URL_SAUCENAO, params=params)).json() data = (await AsyncHttpx.post(API_URL_SAUCENAO, params=params)).json()
if data["header"]["status"] != 0: if data["header"]["status"] != 0:
return "Saucenao识图失败.." return f"Saucenao识图失败..status:{data['header']['status']}"
data = data["results"] data = data["results"]
data = ( data = (
data data
+23 -29
View File
@@ -4,7 +4,7 @@ from services.log import logger
from models.sign_group_user import SignGroupUser from models.sign_group_user import SignGroupUser
from nonebot.message import run_postprocessor from nonebot.message import run_postprocessor
from nonebot.matcher import Matcher from nonebot.matcher import Matcher
from typing import Optional, Type from typing import Optional, Type, Any
from gino.exceptions import UninitializedError from gino.exceptions import UninitializedError
from utils.utils import ( from utils.utils import (
is_number, is_number,
@@ -33,7 +33,7 @@ from .data_source import (
from nonebot.adapters.onebot.v11.exception import ActionFailed from nonebot.adapters.onebot.v11.exception import ActionFailed
from configs.config import Config, NICKNAME from configs.config import Config, NICKNAME
from utils.manager import withdraw_message_manager from utils.manager import withdraw_message_manager
from nonebot.params import CommandArg, Command from nonebot.params import CommandArg, Command, RegexGroup
from typing import Tuple from typing import Tuple
import re import re
@@ -97,6 +97,7 @@ __plugin_configs__ = {
}, },
"TIMEOUT": {"value": 10, "help": "色图下载超时限制(秒)", "default_value": 10}, "TIMEOUT": {"value": 10, "help": "色图下载超时限制(秒)", "default_value": 10},
"SHOW_INFO": {"value": True, "help": "是否显示色图的基本信息,如PID等", "default_value": True}, "SHOW_INFO": {"value": True, "help": "是否显示色图的基本信息,如PID等", "default_value": True},
"ALLOW_GROUP_R18": {"value": False, "help": "在群聊中启用R18权限", "default_value": False},
} }
Config.add_plugin_config("pixiv", "PIXIV_NGINX_URL", "i.pixiv.re", help_="Pixiv反向代理") Config.add_plugin_config("pixiv", "PIXIV_NGINX_URL", "i.pixiv.re", help_="Pixiv反向代理")
@@ -148,10 +149,16 @@ async def _(
if cmd[0] == "色图r" and isinstance(event, PrivateMessageEvent): if cmd[0] == "色图r" and isinstance(event, PrivateMessageEvent):
r18 = 1 r18 = 1
num = 10 num = 10
elif cmd[0] == "色图r" and isinstance(event, GroupMessageEvent): elif (
await setu.finish( cmd[0] == "色图r"
random.choice(["这种不好意思的东西怎么可能给这么多人看啦", "羞羞脸!给我滚出克私聊!", "变态变态变态变态大变态!"]) and isinstance(event, GroupMessageEvent)
) ):
if not Config.get_config("send_setu", "ALLOW_GROUP_R18"):
await setu.finish(
random.choice(["这种不好意思的东西怎么可能给这么多人看啦", "羞羞脸!给我滚出克私聊!", "变态变态变态变态大变态!"])
)
else:
r18 = 1
# 有 数字 的话先尝试本地色图id # 有 数字 的话先尝试本地色图id
if msg and is_number(msg): if msg and is_number(msg):
setu_list, code = await get_setu_list(int(msg), r18=r18) setu_list, code = await get_setu_list(int(msg), r18=r18)
@@ -190,7 +197,7 @@ num_key = {
@setu_reg.handle() @setu_reg.handle()
async def _(event: MessageEvent, arg: Message = CommandArg()): async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
impression = ( impression = (
await SignGroupUser.ensure(event.user_id, event.group_id) await SignGroupUser.ensure(event.user_id, event.group_id)
@@ -198,28 +205,15 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
luox = get_luoxiang(impression) luox = get_luoxiang(impression)
if luox: if luox:
await setu.finish(luox, at_sender=True) await setu.finish(luox, at_sender=True)
msg = arg.extract_plain_text().strip() num, tags = reg_group
num = 1 num = num or 1
msg = re.search(r"(.*)[份发张个次点](.*)[瑟涩色]图", msg) tags = tags[:-1] if tags and tags[-1] == "的" else tags
# 解析 tags 以及 num if num_key.get(num):
if msg: num = num_key[num]
num = msg.group(1) try:
tags = msg.group(2) num = int(num)
if tags: except ValueError:
tags = tags[:-1] if tags[-1] == "的" else tags num = 1
if num:
num = num[-1]
if num_key.get(num):
num = num_key[num]
elif is_number(num):
try:
num = int(num)
except ValueError:
num = 1
else:
num = 1
else:
return
await send_setu_handle(setu_reg, event, "色图", tags, num, 0) await send_setu_handle(setu_reg, event, "色图", tags, num, 0)
+13 -16
View File
@@ -55,13 +55,10 @@ async def get_card(
date = datetime.now().date() date = datetime.now().date()
_type = "view" if is_card_view else "sign" _type = "view" if is_card_view else "sign"
card_file = ( card_file = (
Path(SIGN_TODAY_CARD_PATH) Path(SIGN_TODAY_CARD_PATH) / f"{user_id}_{user.group_id}_{_type}_{date}.png"
/ f"{user_id}_{user.group_id}_{_type}_{date}.png"
) )
if card_file.exists(): if card_file.exists():
return image( return image(f"{user_id}_{user.group_id}_{_type}_{date}.png", "sign/today_card")
f"{user_id}_{user.group_id}_{_type}_{date}.png", "sign/today_card"
)
else: else:
if add_impression == -1: if add_impression == -1:
card_file = ( card_file = (
@@ -75,9 +72,7 @@ async def get_card(
) )
is_card_view = True is_card_view = True
ava = BytesIO(await get_user_avatar(user_id)) ava = BytesIO(await get_user_avatar(user_id))
uid = await GroupInfoUser.get_group_member_uid( uid = await GroupInfoUser.get_group_member_uid(user.user_qq, user.group_id)
user.user_qq, user.group_id
)
impression_list = None impression_list = None
if is_card_view: if is_card_view:
_, impression_list, _ = await SignGroupUser.get_all_impression( _, impression_list, _ = await SignGroupUser.get_all_impression(
@@ -128,9 +123,13 @@ def _generate_card(
level, next_impression, previous_impression = get_level_and_next_impression( level, next_impression, previous_impression = get_level_and_next_impression(
user.impression user.impression
) )
interpolation = next_impression - user.impression
if level == "9":
level = "8"
interpolation = 0
info_img.text((0, 0), f"· 好感度等级:{level} [{lik2relation[level]}]") info_img.text((0, 0), f"· 好感度等级:{level} [{lik2relation[level]}]")
info_img.text((0, 20), f"· {NICKNAME}对你的态度:{level2attitude[level]}") info_img.text((0, 20), f"· {NICKNAME}对你的态度:{level2attitude[level]}")
info_img.text((0, 40), f"· 距离升级还差 {next_impression - user.impression:.2f} 好感度") info_img.text((0, 40), f"· 距离升级还差 {interpolation:.2f} 好感度")
bar_bk = BuildImage(220, 20, background=SIGN_RESOURCE_PATH / "bar_white.png") bar_bk = BuildImage(220, 20, background=SIGN_RESOURCE_PATH / "bar_white.png")
bar = BuildImage(220, 20, background=SIGN_RESOURCE_PATH / "bar.png") bar = BuildImage(220, 20, background=SIGN_RESOURCE_PATH / "bar.png")
@@ -240,7 +239,9 @@ def _generate_card(
f"上次签到日期:{'从未' if user.checkin_time_last == datetime.min else user.checkin_time_last.date()}", f"上次签到日期:{'从未' if user.checkin_time_last == datetime.min else user.checkin_time_last.date()}",
) )
today_data.text((0, 25), f"总金币:{gold}") today_data.text((0, 25), f"总金币:{gold}")
default_setu_prob = Config.get_config("send_setu", "INITIAL_SETU_PROBABILITY") * 100 default_setu_prob = (
Config.get_config("send_setu", "INITIAL_SETU_PROBABILITY") * 100
)
today_data.text( today_data.text(
(0, 50), (0, 50),
f"色图概率:{(default_setu_prob + user.impression if user.impression < 100 else 100):.2f}%", f"色图概率:{(default_setu_prob + user.impression if user.impression < 100 else 100):.2f}%",
@@ -286,12 +287,8 @@ def _generate_card(
bk.paste(today_sign_text_img, (550, 180), True) bk.paste(today_sign_text_img, (550, 180), True)
bk.paste(today_data, (580, 220), True) bk.paste(today_data, (580, 220), True)
bk.paste(watermark, (15, 400), True) bk.paste(watermark, (15, 400), True)
bk.save( bk.save(SIGN_TODAY_CARD_PATH / f"{user_id}_{user.group_id}_{_type}_{data}.png")
SIGN_TODAY_CARD_PATH / f"{user_id}_{user.group_id}_{_type}_{data}.png" return image(f"{user_id}_{user.group_id}_{_type}_{data}.png", "sign/today_card")
)
return image(
f"{user_id}_{user.group_id}_{_type}_{data}.png", "sign/today_card"
)
def generate_progress_bar_pic(): def generate_progress_bar_pic():
+1 -1
View File
@@ -96,7 +96,7 @@ async def _(
global _prefix_count_dict global _prefix_count_dict
if ( if (
matcher.type == "message" matcher.type == "message"
and matcher.priority not in [1, 9] and matcher.priority not in [1, 999]
and matcher.plugin_name not in ["update_info", "statistics_handle"] and matcher.plugin_name not in ["update_info", "statistics_handle"]
): ):
module = matcher.plugin_name module = matcher.plugin_name
+2 -2
View File
@@ -5,8 +5,8 @@ import asyncio
import platform import platform
import os import os
if platform.system() == "Windows": # if platform.system() == "Windows":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) # asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
url = "https://github.com/Mrs4s/go-cqhttp/releases" url = "https://github.com/Mrs4s/go-cqhttp/releases"
+3 -3
View File
@@ -12,7 +12,7 @@ __plugin_usage__ = """
usage: usage:
普普通通的查天气吧 普普通通的查天气吧
指令: 指令:
[城市]天气/天气[城市] [城市]天气
""".strip() """.strip()
__plugin_des__ = "出门要看看天气,不要忘了带伞" __plugin_des__ = "出门要看看天气,不要忘了带伞"
__plugin_cmd__ = ["[城市]天气/天气[城市]"] __plugin_cmd__ = ["[城市]天气/天气[城市]"]
@@ -27,13 +27,13 @@ __plugin_settings__ = {
} }
weather = on_regex(r".{0,10}?(.*)的?天气.*?.{0,10}", priority=5, block=True) weather = on_regex(r".{0,10}?(.*)的?天气.{0,10}", priority=5, block=True)
@weather.handle() @weather.handle()
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]
if msg[-1] != "市": if msg and msg[-1] != "市":
msg += "市" msg += "市"
city = "" city = ""
if msg: if msg:
+5 -3
View File
@@ -1,8 +1,10 @@
from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message, Bot from nonebot.adapters.onebot.v11 import MessageEvent, GroupMessageEvent, Message, Bot
from nonebot.internal.params import ArgStr, Arg
from nonebot.params import CommandArg
from .data_source import get_anime from .data_source import get_anime
from nonebot import on_command from nonebot import on_command
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot.params import Arg
from utils.utils import get_message_img from utils.utils import get_message_img
from services.log import logger from services.log import logger
@@ -31,10 +33,10 @@ what_anime = on_command("识番", priority=5, block=True)
@what_anime.handle() @what_anime.handle()
async def _(bot: Bot, event: MessageEvent, state: T_State): async def _(bot: Bot, event: MessageEvent, state: T_State, args: Message = CommandArg()):
img_url = get_message_img(event.json()) img_url = get_message_img(event.json())
if img_url: if img_url:
state["img_url"] = img_url[0] state["img_url"] = args
@what_anime.got("img_url", prompt="虚空识番?来图来图GKD") @what_anime.got("img_url", prompt="虚空识番?来图来图GKD")
+11 -5
View File
@@ -7,9 +7,8 @@ class WordBankBuilder:
def __init__(self, user_id: int, group_id: int, problem: str): def __init__(self, user_id: int, group_id: int, problem: str):
self._data = { self._data = {
"user_id": user_id, "user_id": user_id,
"group_id": group_id, "group_id": group_id}
"problem": problem self.problem = problem
}
def set_placeholder(self, id_: int, placeholder: Union[str, int]): def set_placeholder(self, id_: int, placeholder: Union[str, int]):
""" """
@@ -28,13 +27,20 @@ class WordBankBuilder:
""" """
self._data["answer"] = answer self._data["answer"] = answer
async def save(self,search_type): def set_problem(self, problem: str):
"""
设置问题
:param problem: 问题
"""
self._data["problem"] = problem
async def save(self, search_type):
user_id = self._data["user_id"] user_id = self._data["user_id"]
group_id = self._data["group_id"] group_id = self._data["group_id"]
problem = self._data["problem"] problem = self._data["problem"]
answer = self._data["answer"] answer = self._data["answer"]
placeholder = self._data.get("placeholder") placeholder = self._data.get("placeholder")
return await WordBank.add_problem_answer(user_id, group_id, search_type,problem, answer, placeholder) return await WordBank.add_problem_answer(user_id, group_id, search_type, problem, answer, placeholder)
async def update(self, index): async def update(self, index):
user_id = self._data["user_id"] user_id = self._data["user_id"]
+10 -2
View File
@@ -1,12 +1,20 @@
import re
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Event from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Event
from utils.utils import get_message_text from utils.utils import get_message_img_file
from nonebot.typing import T_State from nonebot.typing import T_State
from .model import WordBank from .model import WordBank
async def check(bot: Bot, event: Event, state: T_State) -> bool: async def check(bot: Bot, event: Event, state: T_State) -> bool:
if isinstance(event, GroupMessageEvent): if isinstance(event, GroupMessageEvent):
msg = event.raw_message
list_img = get_message_img_file(event.json())
if list_img:
for img_file in list_img:
strinfo = re.compile(f"{img_file},subType=\d*]")
msg = strinfo.sub(f'{img_file}]', msg)
return bool( return bool(
await WordBank.check(event.group_id, get_message_text(event.json()), event.is_tome()) await WordBank.check(event.group_id, msg, event.is_tome())
) )
return False return False
+75 -2
View File
@@ -3,9 +3,11 @@ from ._rule import check
from .model import WordBank from .model import WordBank
from configs.path_config import DATA_PATH from configs.path_config import DATA_PATH
from nonebot.adapters.onebot.v11 import GroupMessageEvent from nonebot.adapters.onebot.v11 import GroupMessageEvent
from utils.utils import get_message_text from utils.utils import get_message_at, get_message_img
from nonebot import on_message from nonebot import on_message
from models.group_member_info import GroupInfoUser from models.group_member_info import GroupInfoUser
from utils.utils import get_message_img_file, is_number
import re
__zx_plugin_name__ = "词库问答回复操作 [Hidden]" __zx_plugin_name__ = "词库问答回复操作 [Hidden]"
@@ -17,8 +19,14 @@ message_handle = on_message(priority=6, block=True, rule=check)
@message_handle.handle() @message_handle.handle()
async def _(event: GroupMessageEvent): async def _(event: GroupMessageEvent):
msg = event.raw_message
list_img = get_message_img_file(event.json())
if list_img:
for img_file in list_img:
strinfo = re.compile(f"{img_file},subType=\d*]")
msg = strinfo.sub(f'{img_file}]', msg)
q = await WordBank.check( q = await WordBank.check(
event.group_id, get_message_text(event.json()), event.is_tome() event.group_id, msg, event.is_tome()
) )
await message_handle.send(await get_one_answer(event, q.format, q.answer)) await message_handle.send(await get_one_answer(event, q.format, q.answer))
@@ -54,3 +62,68 @@ async def get_one_answer(event, format, _answer, all=1):
answer += _a[: _a.find(f"[__placeholder_{idx}]")] + "@" + q.user_name answer += _a[: _a.find(f"[__placeholder_{idx}]")] + "@" + q.user_name
_a = _a[_a.find(f"[__placeholder_{idx}]") + len(f"[__placeholder_{idx}]"):] _a = _a[_a.find(f"[__placeholder_{idx}]") + len(f"[__placeholder_{idx}]"):]
return answer + _a return answer + _a
# 处理单条问题
async def get_one_problem(event, problem):
strinfo = re.compile(f",subType=\d")
problem = strinfo.sub('', problem)
_problem = problem
_p = problem
problem = ''
for img in get_message_img(event.json()):
_x = img.split("?")[0]
r = re.search(rf"\[CQ:image,file=(.*),url={_x}.*?]", _p)
if r:
_problem = _problem.replace(
rf",url={img}",
f"",
)
problem += _p[: _p.find(f"[CQ:image,file={r.group(1)},url={img}]")] + image(img)
_p = _p[
_p.find(f"[CQ:image,file={r.group(1)},url={img}]") + len(f"[CQ:image,file={r.group(1)},url={img}]"):]
for at_ in get_message_at(event.json()):
r = re.search(rf"\[CQ:at,qq={at_}]", problem)
if r:
q = await GroupInfoUser.get_member_info(
int(at_), event.group_id)
problem += _p[: _p.find(f"[CQ:at,qq={at_}]")] + "@" + q.user_name
_p = _p[_p.find(f"[CQ:at,qq={at_}]") + len(f"[CQ:at,qq={at_}]"):]
return _problem, problem + _p
# 显示单条数据库问题
async def get_one_image_problem(event, problem):
path = data_dir / f"{event.group_id}" / "problem"
placeholder_list = []
idx = 0
img_list = re.findall(rf"\[CQ:image,file=(.*?)]", problem)
at_list = re.findall(rf"\[CQ:at,qq=(.*?)]", problem)
if img_list:
for img in img_list:
problem = problem.replace(f'[CQ:image,file={img}]', f'[__placeholder_{idx}]', 1)
placeholder_list.append([idx, img])
idx += 1
if at_list:
for ats in at_list:
problem = problem.replace(f'[CQ:at,qq={ats}]', f'[__placeholder_{idx}]', 1)
placeholder_list.append([idx, ats])
idx += 1
_p = problem
problem = ''
if not placeholder_list:
problem = _p
return problem
else:
for idx, placeholder in placeholder_list:
if is_number(placeholder):
q = await GroupInfoUser.get_member_info(
int(placeholder), event.group_id)
problem += _p[: _p.find(f"[__placeholder_{idx}]")] + "@" + q.user_name
else:
problem += _p[: _p.find(f"[__placeholder_{idx}]")] + image(
path / f"{placeholder}.jpg"
)
_p = _p[_p.find(f"[__placeholder_{idx}]") + len(f"[__placeholder_{idx}]"):]
return problem + _p
-5
View File
@@ -108,11 +108,6 @@ class WordBank(db.Model):
:param group_id: 群号 :param group_id: 群号
:param problem: 问题 :param problem: 问题
""" """
if problem.startswith("id:"):
problem_index = int(problem.split(":")[-1])
q = await cls.get_group_all_problem(group_id)
if len(q) > problem_index:
problem = q[problem_index]
q = await cls.query.where( q = await cls.query.where(
(cls.group_id == group_id) & (cls.problem == problem) (cls.group_id == group_id) & (cls.problem == problem)
).gino.all() ).gino.all()
+56 -23
View File
@@ -6,7 +6,7 @@ from utils.http_utils import AsyncHttpx
from ._data_source import WordBankBuilder from ._data_source import WordBankBuilder
from utils.message_builder import image from utils.message_builder import image
from utils.image_utils import text2image from utils.image_utils import text2image
from .message_handle import get_one_answer from .message_handle import get_one_answer, get_one_problem, get_one_image_problem
from .model import WordBank from .model import WordBank
from nonebot.adapters.onebot.v11 import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
@@ -19,6 +19,7 @@ import random
import os import os
import re import re
from configs.config import NICKNAME, Config from configs.config import NICKNAME, Config
from models.group_member_info import GroupInfoUser
__zx_plugin_name__ = "词库问答 [Admin]" __zx_plugin_name__ = "词库问答 [Admin]"
__plugin_usage__ = """ __plugin_usage__ = """
@@ -26,7 +27,7 @@ usage:
对指定问题的随机回答,对相同问题可以设置多个不同回答 对指定问题的随机回答,对相同问题可以设置多个不同回答
删除词条后每个词条的id可能会变化,请查看后再删除 删除词条后每个词条的id可能会变化,请查看后再删除
指令: 指令:
添加词条 ?[模糊/关键字]...答...:添加问答词条,可重复添加相同问题的不同回答 添加词条 ?[模糊/关键字|词]...答...:添加问答词条,可重复添加相同问题的不同回答
删除词条 [问题/下标] ?[下标]:删除指定词条指定或全部回答 删除词条 [问题/下标] ?[下标]:删除指定词条指定或全部回答
修改词条 [问题/下标] ?[下标/新回答] [新回答]:修改指定词条指定回答默认修改为第一条 修改词条 [问题/下标] ?[下标/新回答] [新回答]:修改指定词条指定回答默认修改为第一条
查看词条 ?[问题/下标]:查看全部词条或对应词条回答 查看词条 ?[问题/下标]:查看全部词条或对应词条回答
@@ -48,8 +49,8 @@ __plugin_cmd__ = [
"修改词条 [问题/下标] ?[下标/新回答] [新回答]", "修改词条 [问题/下标] ?[下标/新回答] [新回答]",
"查看词条 ?[问题/下标]", "查看词条 ?[问题/下标]",
] ]
__plugin_version__ = 0.2 __plugin_version__ = 0.3
__plugin_author__ = "HibiKier" __plugin_author__ = "HibiKier & yajiwa"
__plugin_settings__ = { __plugin_settings__ = {
"admin_level": Config.get_config("word_bank", "WORD_BANK_LEVEL [LEVEL]"), "admin_level": Config.get_config("word_bank", "WORD_BANK_LEVEL [LEVEL]"),
"cmd": ["词库问答", "添加词条", "删除词条", "修改词条", "查看词条"], "cmd": ["词库问答", "添加词条", "删除词条", "修改词条", "查看词条"],
@@ -87,21 +88,21 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State, arg: Message = C
else: else:
_problem = problem _problem = problem
search_type = 0 search_type = 0
if re.search("^关键字(.*)", msg): if re.search("^关键字|词(.*)", msg):
search_type = 1 search_type = 1
elif re.search("^模糊(.*)", msg): elif re.search("^模糊(.*)", msg):
search_type = 2 search_type = 2
_builder = await get__builder(event, _problem, answer, idx) _builder = await get__builder(event, _problem, answer, idx)
if await _builder.save(search_type): if await _builder.save(search_type):
logger.info(f"已保存词条 问:{problem} 答:{msg}") logger.info(f"已保存词条 问:{_builder.problem} 答:{msg}")
await add_word.send(f"已保存词条:{problem}") await add_word.send("已保存词条:" + _builder.problem)
else: else:
await delete_word.send("保存失败,可能是回答重复") await delete_word.send("保存失败,可能是回答重复")
@delete_word.handle() @delete_word.handle()
async def _(event: GroupMessageEvent, arg: Message = CommandArg()): async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip() msg = str(arg).strip()
if not msg: if not msg:
await delete_word.finish("此命令之后需要跟随指定词条,通过“显示词条“查看") await delete_word.finish("此命令之后需要跟随指定词条,通过“显示词条“查看")
index = None index = None
@@ -119,17 +120,18 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
if p: if p:
problem = p[int(x)] problem = p[int(x)]
try: try:
_problem, problem = await get_one_problem(event, problem)
if answer := await WordBank.delete_problem_answer( if answer := await WordBank.delete_problem_answer(
event.user_id, event.group_id, problem, index event.user_id, event.group_id, _problem, index
): ):
await delete_word.send(f"删除词条成功:{problem}\n回答:\n{answer}") await delete_word.send("删除词条成功:" + problem + f"\n回答:\n{answer}")
logger.info( logger.info(
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'})"
f" 删除词条: {problem}" f" 删除词条: {problem}"
) )
else: else:
await delete_word.send(f"删除词条:{problem} 失败,可能该词条不存在") await delete_word.send("删除词条:" + problem + "失败,可能该词条不存在")
except IndexError: except IndexError:
await delete_word.send("指定下标错误...请通过查看词条来确定..") await delete_word.send("指定下标错误...请通过查看词条来确定..")
@@ -165,21 +167,21 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
try: try:
if await _builder.update(index): if await _builder.update(index):
await update_word.send(f"修改词条成功:{problem}") await update_word.send(f"修改词条成功:" + _builder.problem)
logger.info( logger.info(
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'})"
f" 修改词条: {problem}" f" 修改词条: {problem}"
) )
else: else:
await update_word.send(f"修改词条:{problem} 失败,可能该词条不存在") await update_word.send(f"修改词条:" + _builder.problem + f"失败,可能该词条不存在")
except IndexError: except IndexError:
await update_word.send("指定下标错误...请通过查看词条来确定..") await update_word.send("指定下标错误...请通过查看词条来确定..")
@show_word.handle() @show_word.handle()
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()): async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip() msg = str(arg).strip()
if not msg: if not msg:
_problem_list = await WordBank.get_group_all_problem(event.group_id) _problem_list = await WordBank.get_group_all_problem(event.group_id)
if not _problem_list: if not _problem_list:
@@ -225,17 +227,28 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
) )
) )
else: else:
_answer_list = await WordBank.get_group_all_answer(event.group_id, msg) _answer_list = []
if msg.startswith("id:"):
x = msg.split(":")[-1]
if not is_number(x) or int(x) < 0:
return await delete_word.finish("id必须为数字且符合规范!")
p = await WordBank.get_group_all_problem(event.group_id)
if p:
_problem = p[int(x)]
_answer_list = await WordBank.get_group_all_answer(event.group_id, _problem)
msg += '问' + await get_one_image_problem(event, _problem)
else:
_problem, msg = await get_one_problem(event, msg)
_answer_list = await WordBank.get_group_all_answer(event.group_id, _problem)
if not _answer_list: if not _answer_list:
await show_word.send("未收录该词条...") await show_word.send("未收录该词条...")
else: else:
# 解析图片和@ # 解析图片和@
_answer_img_nu_list = [await get_one_answer(event, format, answer, 0) for answer, format in _answer_list] _answer_img_nu_list = [await get_one_answer(event, format, answer, 0) for answer, format in _answer_list]
word_nu = len(_answer_img_nu_list) word_nu = len(_answer_img_nu_list)
img_nu = 0 img_nu = 0
answer = f"词条 {msg} 回答:" answer = "词条" + msg + "回答:"
for i, x, in enumerate(_answer_img_nu_list): for i, x, in enumerate(_answer_img_nu_list):
r = re.findall(rf"\[CQ:image,file=", str(x)) r = re.findall(rf"\[CQ:image,file=", str(x))
if r: if r:
@@ -254,15 +267,25 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
async def get__builder(event, _problem, answer, idx): async def get__builder(event, _problem, answer, idx):
(data_dir / f"{event.group_id}").mkdir(exist_ok=True, parents=True) (data_dir / f"{event.group_id}").mkdir(exist_ok=True, parents=True)
(data_dir / f"{event.group_id}" / "problem").mkdir(exist_ok=True, parents=True)
_builder = WordBankBuilder(event.user_id, event.group_id, _problem) _builder = WordBankBuilder(event.user_id, event.group_id, _problem)
problem = ''
_p = _problem
for at_ in get_message_at(event.json()): for at_ in get_message_at(event.json()):
r = re.search(rf"\[CQ:at,qq={at_}]", answer) r = re.search(rf"\[CQ:at,qq={at_}]", answer)
if r: if r:
answer = answer.replace(f"[CQ:at,qq={at_}]", f"[__placeholder_{idx}]", 1) answer = answer.replace(f"[CQ:at,qq={at_}]", f"[__placeholder_{idx}]", 1)
_builder.set_placeholder(idx, at_) _builder.set_placeholder(idx, at_)
idx += 1 idx += 1
r_problem = re.search(rf"\[CQ:at,qq={at_}]", _problem)
if r_problem:
q = await GroupInfoUser.get_member_info(
int(at_), event.group_id)
problem += _p[: _p.find(f"[CQ:at,qq={at_}]")] + "@" + q.user_name
_p = _p[_p.find(f"[CQ:at,qq={at_}]") + len(f"[CQ:at,qq={at_}]"):]
for img in get_message_img(event.json()): for img in get_message_img(event.json()):
_x = img.split("?")[0] _x = img.split("?")[0]
_x_list = img.split("?")
r = re.search(rf"\[CQ:image,file=(.*),url={_x}.*?]", answer) r = re.search(rf"\[CQ:image,file=(.*),url={_x}.*?]", answer)
if r: if r:
rand = random.randint(1, 10000) + random.randint(1, 114514) rand = random.randint(1, 10000) + random.randint(1, 114514)
@@ -270,16 +293,26 @@ async def get__builder(event, _problem, answer, idx):
if f"__placeholder_{rand}_{idx}.jpg" not in os.listdir(data_dir / f"{event.group_id}"): if f"__placeholder_{rand}_{idx}.jpg" not in os.listdir(data_dir / f"{event.group_id}"):
break break
rand = random.randint(1, 10000) + random.randint(1, 114514) rand = random.randint(1, 10000) + random.randint(1, 114514)
for i in range(3): strinfo = re.compile(f"\[CQ:image,file={r.group(1)},url={_x_list[0]}\?{_x_list[1]},subType=\d*?]")
answer = answer.replace(f",subType={i}", "") answer = strinfo.sub(f"[__placeholder_{idx}]", answer)
answer = answer.replace(
rf"[CQ:image,file={r.group(1)},url={img}]",
f"[__placeholder_{idx}]",
)
await AsyncHttpx.download_file( await AsyncHttpx.download_file(
img, data_dir / f"{event.group_id}" / f"__placeholder_{rand}_{idx}.jpg" img, data_dir / f"{event.group_id}" / f"__placeholder_{rand}_{idx}.jpg"
) )
_builder.set_placeholder(idx, f"__placeholder_{rand}_{idx}.jpg") _builder.set_placeholder(idx, f"__placeholder_{rand}_{idx}.jpg")
idx += 1 idx += 1
r_problem = re.search(rf"\[CQ:image,file=(.*?),url={_x}.*?]", _p)
if r_problem:
strinfo = re.compile(f",url={_x_list[0]}\?{_x_list[1]},subType=\d*?]")
_problem = strinfo.sub(f"]", _problem)
_p = strinfo.sub(f"]", _p)
problem += _p[: _p.find(f"[CQ:image,file={r_problem.group(1)}]")] + image(img)
_p = _p[_p.find(f"[CQ:image,file={r_problem.group(1)}]") + len(f"[CQ:image,file={r_problem.group(1)}]"):]
problem_img = r_problem.group(1)
if f"{problem_img}.jpg" not in os.listdir(data_dir / f"{event.group_id}" / f"problem"):
await AsyncHttpx.download_file(
img, data_dir / f"{event.group_id}" / f"problem" / f"{problem_img}.jpg"
)
_builder.set_answer(answer) _builder.set_answer(answer)
_builder.set_problem(_problem)
_builder.problem = problem + _p
return _builder return _builder
+196
View File
@@ -0,0 +1,196 @@
import re
from datetime import datetime, timedelta
from typing import Tuple, Union
import pytz
from nonebot import on_command, get_driver
from nonebot.adapters.onebot.v11 import Message, MessageSegment
from nonebot.adapters.onebot.v11.event import GroupMessageEvent
from nonebot.matcher import Matcher
from nonebot.params import Arg, Command, CommandArg, Depends
from nonebot.typing import T_State
from .data_source import draw_word_cloud, get_list_msg
from configs.config import Config
__zx_plugin_name__ = "词云"
__plugin_usage__ = """
usage:
词云
指令:
今日词云:获取今天的词云
昨日词云:获取昨天的词云
本周词云:获取本周词云
本月词云:获取本月词云
年度词云:获取年度词云
历史词云(支持 ISO8601 格式的日期与时间,如 2022-02-22T22:22:22)
获取某日的词云
历史词云 2022-01-01
获取指定时间段的词云
历史词云
示例:历史词云 2022-01-01~2022-02-22
示例:历史词云 2022-02-22T11:11:11~2022-02-22T22:22:22
如果想要获取自己的发言,可在命令前添加 我的
示例:我的今日词云
""".strip()
__plugin_des__ = "词云"
__plugin_cmd__ = ["今日词云", "昨日词云", "本周词云"]
__plugin_version__ = 0.1
__plugin_author__ = "yajiwa"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": __plugin_cmd__,
}
wordcloud_cmd = on_command(
"wordcloud",
aliases={
"词云",
"今日词云",
"昨日词云",
"本周词云",
"本月词云",
"年度词云",
"历史词云",
"我的今日词云",
"我的昨日词云",
"我的本周词云",
"我的本月词云",
"我的年度词云",
"我的历史词云",
}, block=True, priority=5
)
Config.add_plugin_config(
"word_clouds",
"WORD_CLOUDS_TEMPLATE",
1,
help_="词云模板 参1:图片生成,默认使用真寻图片,可在项目路径resources/image/wordcloud下配置图片,多张则随机 | 参2/其他:黑底图片"
)
def parse_datetime(key: str):
"""解析数字,并将结果存入 state 中"""
async def _key_parser(
matcher: Matcher,
state: T_State,
input_: Union[datetime, Message] = Arg(key),
):
if isinstance(input_, datetime):
return
plaintext = input_.extract_plain_text()
try:
state[key] = get_datetime_fromisoformat_with_timezone(plaintext)
except ValueError:
await matcher.reject_arg(key, "请输入正确的日期,不然我没法理解呢!")
return _key_parser
def get_datetime_now_with_timezone() -> datetime:
"""获取当前时间,并包含时区信息"""
return datetime.now().astimezone()
def get_datetime_fromisoformat_with_timezone(date_string: str) -> datetime:
"""从 iso8601 格式字符串中获取时间,并包含时区信息"""
return datetime.fromisoformat(date_string).astimezone()
@wordcloud_cmd.handle()
async def handle_first_receive(
event: GroupMessageEvent,
state: T_State,
commands: Tuple[str, ...] = Command(),
args: Message = CommandArg(),
):
command = commands[0]
if command.startswith("我的"):
state["my"] = True
command = command[2:]
else:
state["my"] = False
if command == "今日词云":
dt = get_datetime_now_with_timezone()
state["start"] = dt.replace(hour=0, minute=0, second=0, microsecond=0)
state["stop"] = dt
elif command == "昨日词云":
dt = get_datetime_now_with_timezone()
state["stop"] = dt.replace(hour=0, minute=0, second=0, microsecond=0)
state["start"] = state["stop"] - timedelta(days=1)
elif command == "本周词云":
dt = get_datetime_now_with_timezone()
state["start"] = dt.replace(
hour=0, minute=0, second=0, microsecond=0
) - timedelta(days=dt.weekday())
state["stop"] = dt
elif command == "本月词云":
dt = get_datetime_now_with_timezone()
state["start"] = dt.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
state["stop"] = dt
elif command == "年度词云":
dt = get_datetime_now_with_timezone()
state["start"] = dt.replace(
month=1, day=1, hour=0, minute=0, second=0, microsecond=0
)
state["stop"] = dt
elif command == "历史词云":
plaintext = args.extract_plain_text().strip()
match = re.match(r"^(.+?)(?:~(.+))?$", plaintext)
if match:
start = match.group(1)
stop = match.group(2)
try:
state["start"] = get_datetime_fromisoformat_with_timezone(start)
if stop:
state["stop"] = get_datetime_fromisoformat_with_timezone(stop)
else:
# 如果没有指定结束日期,则认为是指查询这一天的词云
state["start"] = state["start"].replace(
hour=0, minute=0, second=0, microsecond=0
)
state["stop"] = state["start"] + timedelta(days=1)
except ValueError:
await wordcloud_cmd.finish("请输入正确的日期,不然我没法理解呢!")
else:
await wordcloud_cmd.finish()
@wordcloud_cmd.got(
"start",
prompt="请输入你要查询的起始日期(如 2022-01-01)",
parameterless=[Depends(parse_datetime("start"))],
)
@wordcloud_cmd.got(
"stop",
prompt="请输入你要查询的结束日期(如 2022-02-22)",
parameterless=[Depends(parse_datetime("stop"))],
)
async def handle_message(
event: GroupMessageEvent,
start: datetime = Arg(),
stop: datetime = Arg(),
my: bool = Arg(),
):
# 是否只查询自己的记录
if my:
user_id = int(event.user_id)
else:
user_id = None
# 将时间转换到 东八 时区
messages = await get_list_msg(user_id, int(event.group_id),
days=(start.astimezone(pytz.timezone("Asia/Shanghai")),
stop.astimezone(pytz.timezone("Asia/Shanghai"))))
if messages:
image_bytes = await draw_word_cloud(messages, get_driver().config)
if image_bytes:
await wordcloud_cmd.finish(MessageSegment.image(image_bytes), at_sender=my)
else:
await wordcloud_cmd.finish("生成词云失败", at_sender=my)
else:
await wordcloud_cmd.finish("没有获取到词云数据", at_sender=my)
+129
View File
@@ -0,0 +1,129 @@
import asyncio
import os
import random
import jieba.analyse
import re
from typing import List
from PIL import Image as IMG
import jieba
from emoji import replace_emoji # type: ignore
from wordcloud import WordCloud, ImageColorGenerator
import numpy as np
import matplotlib.pyplot as plt
from io import BytesIO
from configs.path_config import IMAGE_PATH, FONT_PATH
from services import logger
from utils.http_utils import AsyncHttpx
from models.chat_history import ChatHistory
from configs.config import Config
async def pre_precess(msg: List[str], config) -> str:
return await asyncio.get_event_loop().run_in_executor(
None, _pre_precess, msg, config
)
def _pre_precess(msg: List[str], config) -> str:
"""对消息进行预处理"""
# 过滤掉命令
command_start = tuple([i for i in config.command_start if i])
msg = " ".join([m for m in msg if not m.startswith(command_start)])
# 去除网址
msg = re.sub(r"https?://[\w/:%#\$&\?\(\)~\.=\+\-]+", "", msg)
# 去除 \u200b
msg = re.sub(r"[\u200b]", "", msg)
# 去除cq码
msg = re.sub(r"\[CQ:.*?]", "", msg)
# 去除&#91&#93
msg = re.sub("[&#9(1|3);]", "", msg)
# 去除 emoji
# https://github.com/carpedm20/emoji
msg = replace_emoji(msg)
return msg
async def draw_word_cloud(messages, config):
wordcloud_dir = IMAGE_PATH / "wordcloud"
wordcloud_dir.mkdir(exist_ok=True, parents=True)
# 默认用真寻图片
zx_logo_path = wordcloud_dir / "default.png"
wordcloud_ttf = FONT_PATH / "STKAITI.TTF"
if not os.listdir(wordcloud_dir):
url = "https://ghproxy.com/https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/resources/image/wordcloud/default.png"
try:
await AsyncHttpx.download_file(url, zx_logo_path)
except Exception as e:
logger.error(f"词云图片资源下载发生错误 {type(e)}:{e}")
return False
if not wordcloud_ttf.exists():
ttf_url = "https://ghproxy.com/https://raw.githubusercontent.com/HibiKier/zhenxun_bot/main/resources/font/STKAITI.TTF"
try:
await AsyncHttpx.download_file(ttf_url, wordcloud_ttf)
except Exception as e:
logger.error(f"词云字体资源下载发生错误 {type(e)}:{e}")
return False
topK = min(int(len(messages)), 100000)
read_name = jieba.analyse.extract_tags(
await pre_precess(messages, config), topK=topK, withWeight=True, allowPOS=()
)
name = []
value = []
for t in read_name:
name.append(t[0])
value.append(t[1])
for i in range(len(name)):
name[i] = str(name[i])
dic = dict(zip(name, value))
if Config.get_config("word_clouds", "WORD_CLOUDS_TEMPLATE") == 1:
def random_pic(base_path: str) -> str:
path_dir = os.listdir(base_path)
path = random.sample(path_dir, 1)[0]
return str(base_path) + "/" + str(path)
mask = np.array(IMG.open(random_pic(wordcloud_dir)))
wc = WordCloud(
font_path=f"{wordcloud_ttf}",
background_color="white",
max_font_size=100,
width=1920,
height=1080,
mask=mask,
)
wc.generate_from_frequencies(dic)
image_colors = ImageColorGenerator(mask, default_color=(255, 255, 255))
wc.recolor(color_func=image_colors)
plt.imshow(wc.recolor(color_func=image_colors), interpolation="bilinear")
plt.axis("off")
else:
wc = WordCloud(
font_path=str(wordcloud_ttf),
width=1920,
height=1200,
background_color="black",
)
wc.generate_from_frequencies(dic)
bytes_io = BytesIO()
img = wc.to_image()
img.save(bytes_io, format="PNG")
return bytes_io.getvalue()
async def get_list_msg(user_id, group_id, days):
messages_list = (
await ChatHistory()
._get_msg(uid=user_id, gid=group_id, type_="group", days=days)
.gino.all()
)
if messages_list:
messages = [i.text for i in messages_list]
return messages
else:
return False
+8 -8
View File
@@ -11,7 +11,7 @@ china_city = TEXT_PATH / "china_city.json"
data = {} data = {}
url = "https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5" url = "https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=diseaseh5Shelf"
async def get_yiqing_data(area: str) -> Union[str, MessageSegment]: async def get_yiqing_data(area: str) -> Union[str, MessageSegment]:
@@ -37,7 +37,7 @@ async def get_yiqing_data(area: str) -> Union[str, MessageSegment]:
if area in data[p]: if area in data[p]:
province = p province = p
city = area city = area
epidemic_data = json.loads((await AsyncHttpx.get(url)).json()["data"]) epidemic_data = (await AsyncHttpx.get(url)).json()["data"]["diseaseh5Shelf"]
last_update_time = epidemic_data["lastUpdateTime"] last_update_time = epidemic_data["lastUpdateTime"]
if area == "中国": if area == "中国":
data_ = epidemic_data["areaTree"][0] data_ = epidemic_data["areaTree"][0]
@@ -59,12 +59,12 @@ async def get_yiqing_data(area: str) -> Union[str, MessageSegment]:
add_confirm = data_["today"]["confirm"] # 新增确诊 add_confirm = data_["today"]["confirm"] # 新增确诊
grade = "" grade = ""
_grade_color = "" _grade_color = ""
if data_["total"].get("grade"): # if data_["total"].get("grade"):
grade = data_["total"]["grade"] # grade = data_["total"]["grade"]
if "中风险" in grade: # if "中风险" in grade:
_grade_color = "#fa9424" # _grade_color = "#fa9424"
else: # else:
_grade_color = "red" # _grade_color = "red"
dead_rate = f"{dead / confirm * 100:.2f}" # 死亡率 dead_rate = f"{dead / confirm * 100:.2f}" # 死亡率
heal_rate = f"{heal / confirm * 100:.2f}" # 治愈率 heal_rate = f"{heal / confirm * 100:.2f}" # 治愈率
Generated
+764 -804
View File
File diff suppressed because it is too large Load Diff
+5 -3
View File
@@ -6,15 +6,14 @@ authors = ["HibiKier <775757368@qq.com>"]
license = "AGPL" license = "AGPL"
[[tool.poetry.source]] [[tool.poetry.source]]
name = "tsinghua" name = "ali"
default = true default = true
url = "https://pypi.tuna.tsinghua.edu.cn/simple" url = "https://mirrors.aliyun.com/pypi/simple/"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.8" python = "^3.8"
nonebot2 = "^2.0.0-beta.2" nonebot2 = "^2.0.0-beta.2"
nonebot-adapter-onebot = "^2.0.0-beta.1" nonebot-adapter-onebot = "^2.0.0-beta.1"
bilibili-api = "^9.1.0"
aiofiles = "^0.8.0" aiofiles = "^0.8.0"
aiohttp = "3.7.4.post0" aiohttp = "3.7.4.post0"
beautifulsoup4 = "4.9.3" beautifulsoup4 = "4.9.3"
@@ -40,6 +39,9 @@ dateparser = "^1.1.0"
cn2an = "^0.5.16" cn2an = "^0.5.16"
python-jose = "^3.3.0" python-jose = "^3.3.0"
python-multipart = "^0.0.5" python-multipart = "^0.0.5"
bilireq = "^0.1.2"
emoji = "^1.7.0"
wordcloud = "^1.8.1"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 728 KiB

-2
View File
@@ -15,8 +15,6 @@ _browser: Optional[Browser] = None
async def init(**kwargs) -> Optional[Browser]: async def init(**kwargs) -> Optional[Browser]:
global _browser global _browser
if platform.system() == "Windows":
return None
try: try:
browser = await async_playwright().start() browser = await async_playwright().start()
_browser = await browser.chromium.launch(**kwargs) _browser = await browser.chromium.launch(**kwargs)
+6
View File
@@ -0,0 +1,6 @@
+22 -6
View File
@@ -17,13 +17,15 @@ class ShopRegister(dict):
name: Tuple[str, ...], name: Tuple[str, ...],
price: Tuple[float, ...], price: Tuple[float, ...],
des: Tuple[str, ...], des: Tuple[str, ...],
discount: Tuple[float, ...],
limit_time: Tuple[int, ...],
load_status: Tuple[bool, ...], load_status: Tuple[bool, ...],
**kwargs, **kwargs,
): ):
def add_register_item(func: Callable): def add_register_item(func: Callable):
if name in self._data.keys(): if name in self._data.keys():
raise ValueError("该商品已注册,请替换其他名称!") raise ValueError("该商品已注册,请替换其他名称!")
for n, p, d, s in zip(name, price, des, load_status): for n, p, d, dd, l, s in zip(name, price, des, discount, limit_time, load_status):
if s: if s:
_temp_kwargs = {} _temp_kwargs = {}
for key, value in kwargs.items(): for key, value in kwargs.items():
@@ -32,6 +34,8 @@ class ShopRegister(dict):
self._data[n] = { self._data[n] = {
"price": p, "price": p,
"des": d, "des": d,
"discount": dd,
"limit_time": l,
"func": func, "func": func,
"kwargs": _temp_kwargs, "kwargs": _temp_kwargs,
} }
@@ -46,7 +50,7 @@ class ShopRegister(dict):
self._flag = False self._flag = False
for name in self._data.keys(): for name in self._data.keys():
await shop.register_goods( await shop.register_goods(
name, self._data[name]["price"], self._data[name]["des"] name, self._data[name]["price"], self._data[name]["des"], self._data[name]["discount"], self._data[name]["limit_time"]
) )
use.register_use( use.register_use(
name, self._data[name]["func"], **self._data[name]["kwargs"] name, self._data[name]["func"], **self._data[name]["kwargs"]
@@ -57,24 +61,36 @@ class ShopRegister(dict):
name: Union[str, Tuple[str, ...]], name: Union[str, Tuple[str, ...]],
price: Union[float, Tuple[float, ...]], price: Union[float, Tuple[float, ...]],
des: Union[str, Tuple[str, ...]], des: Union[str, Tuple[str, ...]],
discount: Union[float, Tuple[float, ...]] = 1,
limit_time: Union[int, Tuple[int, ...]] = 0,
load_status: Union[bool, Tuple[bool, ...]] = True, load_status: Union[bool, Tuple[bool, ...]] = True,
**kwargs, **kwargs,
): ):
_tuple_list = [] _tuple_list = []
_current_len = -1 _current_len = -1
for x in [name, price, des, load_status]: for x in [name, price, des, discount, limit_time, load_status]:
if isinstance(x, tuple): if isinstance(x, tuple):
if _current_len == -1: if _current_len == -1:
_current_len = len(x) _current_len = len(x)
if _current_len != len(x): if _current_len != len(x):
raise ValueError(f"注册商品 {name} 中 name,price,des,load_status 数量不符!") raise ValueError(f"注册商品 {name} 中 name,price,des,discount,limit_time,load_status 数量不符!")
_current_len = _current_len if _current_len > -1 else 1 _current_len = _current_len if _current_len > -1 else 1
_name = name if isinstance(name, tuple) else tuple(name) _name = name if isinstance(name, tuple) else (name,)
_price = ( _price = (
price price
if isinstance(price, tuple) if isinstance(price, tuple)
else tuple([price for _ in range(_current_len)]) else tuple([price for _ in range(_current_len)])
) )
_discount = (
discount
if isinstance(discount, tuple)
else tuple([discount for _ in range(_current_len)])
)
_limit_time = (
limit_time
if isinstance(limit_time, tuple)
else tuple([limit_time for _ in range(_current_len)])
)
_des = ( _des = (
des if isinstance(des, tuple) else tuple([des for _ in range(_current_len)]) des if isinstance(des, tuple) else tuple([des for _ in range(_current_len)])
) )
@@ -83,7 +99,7 @@ class ShopRegister(dict):
if isinstance(load_status, tuple) if isinstance(load_status, tuple)
else tuple([load_status for _ in range(_current_len)]) else tuple([load_status for _ in range(_current_len)])
) )
return self.register(_name, _price, _des, _load_status, **kwargs) return self.register(_name, _price, _des, _discount, _limit_time, _load_status, **kwargs)
def __setitem__(self, key, value): def __setitem__(self, key, value):
self._data[key] = value self._data[key] = value
+2 -2
View File
@@ -327,14 +327,14 @@ class AsyncPlaywright:
await page.set_viewport_size(viewport_size) await page.set_viewport_size(viewport_size)
if isinstance(element, str): if isinstance(element, str):
if wait_time: if wait_time:
card = await page.wait_for_selector(element, timeout=wait_time) card = await page.wait_for_selector(element, timeout=wait_time * 1000)
else: else:
card = await page.query_selector(element) card = await page.query_selector(element)
else: else:
card = page card = page
for e in element: for e in element:
if wait_time: if wait_time:
card = await card.wait_for_selector(e, timeout=wait_time) card = await card.wait_for_selector(e, timeout=wait_time * 1000)
else: else:
card = await card.query_selector(e) card = await card.query_selector(e)
await card.screenshot(path=path, timeout=timeout, type=type_) await card.screenshot(path=path, timeout=timeout, type=type_)
+6 -5
View File
@@ -121,7 +121,7 @@ def fig2b64(plt_: plt) -> str:
return "base64://" + base64_str return "base64://" + base64_str
def is_valid(file: str) -> bool: def is_valid(file: Union[str, Path]) -> bool:
""" """
说明: 说明:
判断图片是否损坏 判断图片是否损坏
@@ -1493,10 +1493,11 @@ async def text2image(
height = 0 height = 0
_tmp = BuildImage(0, 0, font=font, font_size=font_size) _tmp = BuildImage(0, 0, font=font, font_size=font_size)
for x in text.split("\n"): for x in text.split("\n"):
x = x if x.strip() else "正" if x:
w, h = _tmp.getsize(x) w, _ = _tmp.getsize(x)
height += h + _add_height _, h = _tmp.getsize("正")
width = width if width > w else w height += h + _add_height
width = width if width > w else w
width += pw width += pw
height += ph height += ph
A = BuildImage( A = BuildImage(
+3 -7
View File
@@ -4,7 +4,6 @@ from pathlib import Path
class NonePluginCountManager(StaticData): class NonePluginCountManager(StaticData):
""" """
插件加载容忍管理器,当连续 max_count 次插件加载,视为删除插件,清楚数据 插件加载容忍管理器,当连续 max_count 次插件加载,视为删除插件,清楚数据
""" """
@@ -15,6 +14,8 @@ class NonePluginCountManager(StaticData):
:param max_count: 容忍最大次数 :param max_count: 容忍最大次数
""" """
super().__init__(file) super().__init__(file)
if not self._data:
self._data = {}
self._max_count = max_count self._max_count = max_count
def add_count(self, module: str, count: int = 1): def add_count(self, module: str, count: int = 1):
@@ -42,10 +43,5 @@ class NonePluginCountManager(StaticData):
:param module: 模块 :param module: 模块
""" """
if module in self._data.keys(): if module in self._data.keys():
return self._data.keys() > self._max_count return self._data[module] >= self._max_count
return False return False
+24 -3
View File
@@ -1,7 +1,7 @@
from datetime import datetime from datetime import datetime
from collections import defaultdict from collections import defaultdict
from nonebot import require from nonebot import require
from configs.config import SYSTEM_PROXY from configs.config import SYSTEM_PROXY, Config
from typing import List, Union, Optional, Type, Any from typing import List, Union, Optional, Type, Any
from nonebot.adapters.onebot.v11 import Bot, Message from nonebot.adapters.onebot.v11 import Bot, Message
from nonebot.matcher import matchers, Matcher from nonebot.matcher import matchers, Matcher
@@ -205,8 +205,8 @@ def get_message_at(data: Union[str, Message]) -> List[int]:
qq_list.append(int(msg["data"]["qq"])) qq_list.append(int(msg["data"]["qq"]))
else: else:
for seg in data: for seg in data:
if seg.type == "image": if seg.type == "at":
qq_list.append(seg.data["url"]) qq_list.append(seg.data["qq"])
return qq_list return qq_list
@@ -229,6 +229,25 @@ def get_message_img(data: Union[str, Message]) -> List[str]:
return img_list return img_list
def get_message_img_file(data: Union[str, Message]) -> List[str]:
"""
说明:
获取消息中所有的 图片file
参数:
:param data: event.json()
"""
file_list = []
if isinstance(data, str):
data = json.loads(data)
for msg in data["message"]:
if msg["type"] == "image":
file_list.append(msg["data"]["file"])
else:
for seg in data["image"]:
file_list.append(seg.data["file"])
return file_list
def get_message_text(data: Union[str, Message]) -> str: def get_message_text(data: Union[str, Message]) -> str:
""" """
说明: 说明:
@@ -370,6 +389,8 @@ def change_pixiv_image_links(
url = img_sp[0] url = img_sp[0]
img_type = img_sp[1] img_type = img_sp[1]
url = url.replace("original", "master") + f"_master1200.{img_type}" url = url.replace("original", "master") + f"_master1200.{img_type}"
if not nginx_url:
nginx_url = Config.get_config("pixiv", "PIXIV_NGINX_URL")
if nginx_url: if nginx_url:
url = ( url = (
url.replace("i.pximg.net", nginx_url) url.replace("i.pximg.net", nginx_url)