Compare commits

..
73 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
HibiKier 1059a0aae0 Update README.md 2022-05-03 15:40:19 +08:00
HibiKier e6576e7f40 Update README.md 2022-05-03 15:34:47 +08:00
HibiKier 5837144095 Update data_source.py 2022-05-03 15:31:34 +08:00
79 changed files with 3494 additions and 1611 deletions
+75 -7
View File
@@ -18,10 +18,6 @@
## 声明
此项目仅用于学习交流,请勿用于非法用途
## Gitee
# [Gitee](https://gitee.com/two_Dimension/zhenxun_bot)
## 未完成的文档
# [传送门](https://hibikier.github.io/zhenxun_bot/)
@@ -242,17 +238,89 @@ __Docker 最新版本由 [Sakuracio](https://github.com/Sakuracio) 提供__
## 更新
### 2022/5/3 \[v0.1.5.1]
### 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]
* 商品使用函数可以添加特定参数,例如:user_id, group_id, ShopParam等以及自己提供的参数
* 添加商品注册装饰器shop_register
* 修复商品函数kwargs无法获取参数值
### 2022/5/1
* 删除了`group_last_chat`插件(该功能可由`chat_history`替代
* 新增敏感词检测(全新反击系统,是时候重拳出击了
### 2022/4/26 \[v0.5.1.0]
### 2022/4/26
* 修复了群白名单无法正确添加
* 优化了管理员帮助图片,背景图层将位于最下层
@@ -487,4 +555,4 @@ __..... 更多更新信息请查看文档__
[NothAmor / nonebot2_luxun_says](https://github.com/NothAmor/nonebot2_luxun_says) :基于nonebot2机器人框架的鲁迅说插件
[Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何bot的词库
[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 = []
# try:
for user_info in _group_user_list:
if user_info["card"] == "":
nickname = user_info["nickname"]
else:
nickname = user_info["card"]
nickname = user_info["card"] or user_info["nickname"]
async with db.transaction():
# 更新权限
if (
@@ -321,3 +318,4 @@ def set_group_bot_status(group_id: int, status: bool) -> str:
# for x in group_manager.get_task_data():
# group_manager.close_group_task(group_id, x)
return "那我先睡觉了..."
@@ -2,6 +2,7 @@ from nonebot import on_command, on_notice
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent
from ._data_source import update_member_info
__zx_plugin_name__ = "更新群组成员列表 [Admin]"
__plugin_usage__ = """
usage:
+6 -4
View File
@@ -125,11 +125,13 @@ async def _(
msg = arg.extract_plain_text().strip()
if msg:
if str(event.user_id) in bot.config.superusers:
if is_number(arg.extract_plain_text().strip().split()[0]):
qq = int(msg[0])
msg = msg[1:]
msg_splt = msg.split()
if is_number(msg_splt[0]):
qq = int(msg_splt[0])
msg = msg_splt[1:]
if cmd in [".ban", "/ban"]:
time = parse_ban_time(msg)
time = parse_ban_time(" ".join(msg))
if isinstance(time, str):
await ban.finish(time)
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
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
: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)
if await BanUser.ban(qq, ban_level, time):
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}的黑名单了!"
if time != -1:
@@ -57,13 +60,3 @@ async def a_ban(qq: int, time: int, user_name: str, event: MessageEvent, ban_lev
time += " 分钟"
result = f"{user_name} 已在黑名单!预计 {time}后解封"
return result
+3 -2
View File
@@ -2,6 +2,7 @@ from configs.config import Config
from models.chat_history import ChatHistory
from nonebot import on_message
from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageEvent
from utils.utils import get_message_text
from ._rule import rule
@@ -22,10 +23,10 @@ chat_history = on_message(rule=rule, priority=1, block=False)
async def _(event: MessageEvent):
if isinstance(event, GroupMessageEvent):
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:
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()
+19 -3
View File
@@ -1,5 +1,6 @@
from nonebot import on_notice, on_request
from configs.path_config import IMAGE_PATH, DATA_PATH
from models.level_user import LevelUser
from utils.message_builder import image
from models.group_member_info import GroupInfoUser
from datetime import datetime
@@ -96,6 +97,23 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
for plugin in data.keys():
if not data[plugin]["default_status"]:
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:
join_time = datetime.now()
user_info = await bot.get_group_member_info(
@@ -128,9 +146,7 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent):
msg = msg.replace("[at]", "")
at_flag = True
if (DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg").exists():
img = image(
DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg"
)
img = image(DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg")
if msg or img:
msg = msg.strip() + img
msg = "\n" + msg if at_flag else msg
+3
View File
@@ -56,6 +56,9 @@ def _create_help_img(
for matcher in _matchers:
plugin_name = None
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
if not _plugin:
logger.warning(f"获取 功能:{matcher.plugin_name} 失败...")
continue
_module = _plugin.module
try:
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("功能总开关关闭状态")
except AttributeError:
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 (
@@ -146,7 +146,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if event.is_tome():
status_message_manager.add(event.user_id)
raise IgnoredException("权限不足")
if module in plugins2info_dict.keys() and matcher.priority not in [1, 9]:
if 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 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):
if (
(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:
try:
if (
@@ -58,7 +58,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if not static_flmt.check(event.user_id):
raise IgnoredException("用户处于黑名单中")
static_flmt.start_cd(event.user_id)
if matcher.priority != 9:
if matcher.priority != 999:
try:
ban_result = Config.get_config("hook", "BAN_RESULT")
if (
@@ -79,7 +79,7 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State):
if not static_flmt.check(event.user_id):
raise IgnoredException("用户处于黑名单中")
static_flmt.start_cd(event.user_id)
if matcher.priority != 9:
if matcher.priority != 999:
try:
ban_result = Config.get_config("hook", "BAN_RESULT")
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):
if not isinstance(event, MessageEvent):
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 _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'):
if await BanUser.ban(
@@ -20,26 +20,36 @@ def init_none_plugin_count_manager():
"""
清除已删除插件数据
"""
modules = [x.module for x in get_matchers()]
for module in none_plugin_count_manager.keys():
if module not in modules:
none_plugin_count_manager.add_count(module)
else:
none_plugin_count_manager.reset(module)
if none_plugin_count_manager.check(module):
modules = [x.plugin_name for x in get_matchers()]
plugins_manager_list = list(plugins_manager.keys())
for module in plugins_manager_list:
if module not in modules or none_plugin_count_manager.check(module):
try:
plugin_name = plugins_manager.get(module)["plugin_name"]
except (AttributeError, KeyError):
plugin_name = ""
try:
plugins2settings_manager.delete(module)
plugins2count_manager.delete(module)
plugins2cd_manager.delete(module)
plugins2block_manager.delete(module)
plugins_manager.delete(module)
resources_manager.remove_resource(module)
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...")
except Exception as e:
logger.error(
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}:{e}"
)
if none_plugin_count_manager.check(module):
try:
plugins2settings_manager.delete(module)
plugins2settings_manager.save()
plugins2count_manager.delete(module)
plugins2count_manager.save()
plugins2cd_manager.delete(module)
plugins2cd_manager.save()
plugins2block_manager.delete(module)
plugins2block_manager.save()
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)
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": {}}
+4
View File
@@ -108,6 +108,10 @@ async def _():
"ALTER TABLE genshin ADD bind_group Integer;",
"genshin"
), # 新增原神群号绑定字段
(
"ALTER TABLE chat_history ADD plain_text Text;",
"chat_history"
), # 新增纯文本
]
for sql in sql_str:
try:
+5 -11
View File
@@ -13,6 +13,7 @@ import time
driver: Driver = nonebot.get_driver()
use = require("use")
@@ -139,8 +140,7 @@ async def register_goods(
des: str,
discount: Optional[float] = 1,
limit_time: Optional[int] = 0,
**kwargs,
):
) -> bool:
"""
添加商品
例如: 折扣:可选参数↓ 限时时间:可选,单位为小时
@@ -151,18 +151,11 @@ async def register_goods(
:param des: 商品简介
:param discount: 商品折扣
:param limit_time: 商品限时销售时间,单位为小时
:param kwargs: kwargs
:return: 是否添加成功
"""
if kwargs:
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):
if not await GoodsInfo.get_goods_info(name):
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 = (
int(time.time() + limit_time * 60 * 60)
if limit_time is not None and limit_time != 0
@@ -171,6 +164,7 @@ async def register_goods(
return await GoodsInfo.add_goods(
name, int(price), des, float(discount), limit_time
)
return False
# 删除商品
+3 -4
View File
@@ -61,16 +61,15 @@ class GoodsUseFuncManager:
return param_list_
goods_name = param.goods_name
if self.exists(goods_name):
if args := inspect.signature(self._data[goods_name]["func"]).parameters:
print(parse_args(args))
print(kwargs)
args = inspect.signature(self._data[goods_name]["func"]).parameters
if args and list(args.keys())[0] != "kwargs":
if asyncio.iscoroutinefunction(self._data[goods_name]["func"]):
return await self._data[goods_name]["func"](
*parse_args(args)
)
else:
return self._data[goods_name]["func"](
**kwargs,
*parse_args(args)
)
else:
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
if not msg:
await add_group_level.finish("用法:修改群权限 [group] [level]")
msg = msg.split(" ")
msg = msg.split()
if len(msg) < 2:
await add_group_level.finish("参数不完全..[group] [level]")
if is_number(msg[0]) and is_number(msg[1]):
@@ -45,6 +45,7 @@ async def _():
group_info["group_name"],
group_info["max_member_count"],
group_info["member_count"],
1
):
num += 1
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)
group_id = db.Column(db.BigInteger())
text = db.Column(db.Text())
plain_text = db.Column(db.Text())
create_time = db.Column(db.DateTime(timezone=True), nullable=False)
@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(
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
@@ -97,7 +98,6 @@ class ChatHistory(db.Model):
if date_scope:
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}"
print(sql)
return await db.all(db.text(sql))
@classmethod
+1 -2
View File
@@ -114,8 +114,7 @@ class GoodsInfo(db.Model):
参数:
:param goods_name: 商品名称
"""
query = await cls.query.where(cls.goods_name == goods_name).gino.first()
return query
return await cls.query.where(cls.goods_name == goods_name).gino.first()
@classmethod
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
@@ -44,16 +46,19 @@ class LevelUser(db.Model):
query = cls.query.where((cls.user_qq == user_qq) & (cls.group_id == group_id))
query = query.with_for_update()
user = await query.gino.first()
if user is None:
await cls.create(
user_qq=user_qq,
group_id=group_id,
user_level=level,
group_flag=group_flag,
)
return True
else:
await user.update(user_level=level, group_flag=group_flag).apply()
try:
if not user:
await cls.create(
user_qq=user_qq,
group_id=group_id,
user_level=level,
group_flag=group_flag,
)
return True
else:
await user.update(user_level=level, group_flag=group_flag).apply()
return False
except UniqueViolationError:
return False
@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"
)
ai = on_message(rule=to_me(), priority=8)
ai = on_message(rule=to_me(), priority=998)
@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 data, 200
else:
if data["code"] == 101:
return "缺失ALAPI TOKEN,请在配置文件中填写!", 999
return f'发生了错误...code:{data["code"]}', 999
except TimeoutError:
return "超时了....", 998
+2 -2
View File
@@ -60,8 +60,8 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
img = await AsyncPlaywright.screenshot(
url,
f"{IMAGE_PATH}/temp/wbtop_{event.user_id}.png",
"#pl_feedlist_index",
wait_time=5
"#pl_feed_main",
wait_time=12
)
if img:
await wbtop.send(img)
+1 -1
View File
@@ -38,7 +38,7 @@ usage:
__plugin_des__ = "非常便利的B站订阅通知"
__plugin_cmd__ = ["添加订阅 [主播/UP/番剧] [id/链接/番名]", "删除订阅 [id]", "查看订阅"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_author__ = "HibiKier & NumberSir"
__plugin_settings__ = {
"level": 5,
"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 asyncio.exceptions import TimeoutError
from .model import BilibiliSub
from bilibili_api.live import LiveRoom
from bilibili_api import bangumi
from bilireq.live import get_room_info_by_id
from .utils import get_meta
from utils.message_builder import image
from bilibili_api.user import User
from bilibili_api import user
from bilireq.user import get_user_info
from bilireq import dynamic
from .utils import get_videos
from typing import Optional
from configs.path_config import IMAGE_PATH
from datetime import datetime
@@ -36,9 +37,9 @@ async def add_live_sub(live_id: int, sub_user: str) -> str:
try:
async with db.transaction():
try:
live = LiveRoom(live_id)
live_info = (await live.get_room_info())["room_info"]
except ResponseCodeException:
"""bilibili_api.live库的LiveRoom类中get_room_info改为bilireq.live库的get_room_info_by_id方法"""
live_info = await get_room_info_by_id(live_id)
except ResponseCodeError:
return f"未找到房间号Id:{live_id} 的信息,请检查Id是否正确"
uid = live_info["uid"]
room_id = live_info["room_id"]
@@ -78,16 +79,18 @@ async def add_up_sub(uid: int, sub_user: str) -> str:
try:
async with db.transaction():
try:
u = user.User(uid)
user_info = await u.get_user_info()
except ResponseCodeException:
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
user_info = await get_user_info(uid)
except ResponseCodeError:
return f"未找到UpId:{uid} 的信息,请检查Id是否正确"
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
if dynamic_info.get("cards"):
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
if video_info["list"].get("vlist"):
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:
async with db.transaction():
try:
season_info = await bangumi.get_meta(media_id)
except ResponseCodeException:
"""bilibili_api.bangumi库中get_meta改为bilireq.bangumi库的get_meta方法"""
season_info = await get_meta(media_id)
except ResponseCodeError:
return f"未找到media_id:{media_id} 的信息,请检查Id是否正确"
season_id = season_info["media"]["season_id"]
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_)
elif sub_type == "season":
return await _get_season_status(id_)
except ResponseCodeException:
except ResponseCodeError:
return f"Id:{id_} 获取信息失败...请检查订阅Id是否存在或稍后再试..."
# except Exception as 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
"""
live = LiveRoom(id_)
live_info = (await live.get_room_info())["room_info"]
"""bilibili_api.live库的LiveRoom类中get_room_info改为bilireq.live库的get_room_info_by_id方法"""
live_info = await get_room_info_by_id(id_)
title = live_info["title"]
room_id = live_info["room_id"]
live_status = live_info["live_status"]
cover = live_info["cover"]
cover = live_info["user_cover"]
sub = await BilibiliSub.get_sub(id_)
if sub.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:
"""
_user = await BilibiliSub.get_sub(id_)
u = user.User(_user.uid)
user_info = await u.get_user_info()
"""bilibili_api.user库中User类的get_user_info改为bilireq.user库的get_user_info方法"""
user_info = await get_user_info(_user.uid)
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
video = None
if _user.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"):
video = video_info["list"]["vlist"][0]
latest_video_created = video["created"]
@@ -280,7 +285,8 @@ async def _get_season_status(id_) -> Optional[str]:
获取 番剧 更新状态
: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"]
_idx = (await BilibiliSub.get_sub(id_)).season_current_episode
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(
u: User, local_user: BilibiliSub
uid: int, local_user: BilibiliSub
) -> "Optional[MessageSegment], int":
"""
获取用户动态
:param u: 用户类
:param uid: 用户uid
:param local_user: 数据库存储的用户数据
: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()
if dynamic_info.get("cards") and browser:
dynamic_upload_time = dynamic_info["cards"][0]["desc"]["timestamp"]
@@ -317,21 +324,21 @@ async def get_user_dynamic(
wait_until="networkidle",
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(
"""
xs = document.getElementsByClassName('first-card-with-title');
xs = document.getElementsByClassName('bili-dyn-item__tag');
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(
path=dynamic_path / f"{local_user.sub_id}_{dynamic_upload_time}.jpg",
timeout=100000,
)
except Exception as e:
logger.error(f"B站订阅:获取用户动态 发送错误 {type(e)}:{e}")
+48 -4
View File
@@ -1,7 +1,8 @@
from utils.image_utils import BuildImage
from configs.path_config import IMAGE_PATH
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
@@ -28,8 +29,8 @@ async def create_live_des_image(uid: int, title: str, cover: str, tags: str, des
:param des: 直播简介
:return:
"""
u = user.User(uid)
user_info = await u.get_user_info()
user_info = await get_user_info(uid)
name = user_info["name"]
sex = user_info["sex"]
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.circle()
cover = BuildImage(470, 265, background=BytesIO(await get_pic(cover)))
print()
def _create_live_des_image(
@@ -68,3 +68,47 @@ def _create_live_des_image(
border_img = BuildImage(1772, 2657, background=border)
bk = BuildImage(1772, 2657, font_size=30)
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])
id_ = int(msg[1])
punish_level = int(msg[2])
print(uid, id_, punish_level)
rst = await set_user_punish(uid, id_, punish_level)
await set_punish.send(rst)
logger.info(
+1 -1
View File
@@ -77,7 +77,7 @@ async def show_black_text_image(
(punish_level_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
A = BuildImage(w + 11, img.h + 50, color="#f9f6f2", font_size=35, font="CJGaoDeGuo.otf")
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()
elif id_:
user_list = await query.gino.all()
print(len(user_list))
if len(user_list) == 0 or (id_ < 0 or id_ > len(user_list)):
return False
user = user_list[id_]
-2
View File
@@ -88,9 +88,7 @@ class BlackWordManager:
:param group_id: 群号
:param message: 消息
"""
print(user_id, group_id, message)
if data := self._check(message):
print(data)
if data[0]:
await _add_user_black_word(
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
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
# if platform.system() == "Windows":
# import asyncio
#
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
url = "http://www.eclzz.mobi"
+3 -3
View File
@@ -14,9 +14,9 @@ import tarfile
import shutil
import os
if str(platform.system()).lower() == "windows":
policy = asyncio.WindowsSelectorEventLoopPolicy()
asyncio.set_event_loop_policy(policy)
# if str(platform.system()).lower() == "windows":
# policy = asyncio.WindowsSelectorEventLoopPolicy()
# asyncio.set_event_loop_policy(policy)
driver = nonebot.get_driver()
+24 -37
View File
@@ -1,58 +1,34 @@
from httpx import AsyncClient
from datetime import datetime
from nonebot.log import logger
from nonebot.adapters.onebot.v11 import Bot
from configs.config import NICKNAME
from utils.http_utils import AsyncHttpx
# 获取所有 Epic Game Store 促销游戏
# 方法参考:RSSHub /epicgames 路由
# https://github.com/DIYgod/RSSHub/blob/master/lib/routes/epicgames/index.js
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"
headers = {
"Referer": "https://www.epicgames.com/store/zh-CN/",
"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",
}
async with AsyncClient(headers=headers) as client:
try:
res = await client.get(epic_url, timeout=10.0)
res_json = res.json()
games = res_json["data"]["Catalog"]["searchStore"]["elements"]
return games
except Exception as e:
logger.error(str(e))
return None
try:
res = await AsyncHttpx.get(epic_url, headers=headers, timeout=10)
res_json = res.json()
games = res_json["data"]["Catalog"]["searchStore"]["elements"]
return games
except Exception as e:
logger.error(f"Epic 访问接口错误 {type(e)}:{e}")
return None
# 获取 Epic Game Store 免费游戏信息
# 处理免费游戏的信息方法借鉴 pip 包 epicstore_api 示例
# 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()
if not games:
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(
"%b.%d %H:%M"
)
if Type_Event == "Group":
if type_event == "Group":
_message = "\n由 {} 公司发行的游戏 {} ({}) 在 UTC 时间 {} 即将推出免费游玩,预计截至 {}。".format(
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)
else:
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"]
break
for pair in game["customAttributes"]:
if pair["key"] == "developerName":
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_part
)
if Type_Event == "Group":
if type_event == "Group":
_message = "[CQ:image,file={}]\n\nFREE now :: {} ({})\n{}\n此游戏由 {} 开发、{} 发行,将在 UTC 时间 {} 结束免费游玩,戳链接速度加入你的游戏库吧~\n{}\n".format(
game_thumbnail,
game_name,
+4 -3
View File
@@ -9,6 +9,7 @@ from nonebot.adapters.onebot.v11 import GroupMessageEvent
from configs.config import Config
from utils.http_utils import AsyncHttpx
from services.log import logger
from configs.config import NICKNAME
__zx_plugin_name__ = "复读"
@@ -74,15 +75,15 @@ class Fudu:
_fudu_list = Fudu()
fudu = on_message(permission=GROUP, priority=9)
fudu = on_message(permission=GROUP, priority=999)
@fudu.handle()
async def _(event: GroupMessageEvent):
if event.is_tome():
return
if get_message_text(event.json()):
if get_message_text(event.json()).find("@可爱的小真寻") != -1:
if msg := get_message_text(event.json()):
if msg.startswith(f"@可爱的{NICKNAME}"):
await fudu.finish("复制粘贴的虚空艾特?", at_sender=True)
img = get_message_img(event.json())
msg = get_message_text(event.json())
+1 -1
View File
@@ -35,7 +35,7 @@ Config.add_plugin_config(
default_value=True,
)
almanac = on_command("原神黄历", priority=5, block=True)
almanac = on_command("原神黄历", priority=15, block=True)
ALC_PATH = IMAGE_PATH / "genshin" / "alc"
@@ -1,6 +1,6 @@
from pathlib import Path
from typing import Tuple, Optional, List
from configs.path_config import IMAGE_PATH, TEXT_PATH
from PIL.Image import UnidentifiedImageError
from utils.message_builder import image
from services.log import logger
from utils.image_utils import BuildImage
@@ -137,7 +137,7 @@ async def download_resource_data(semaphore: Semaphore):
asyncio.ensure_future(
download_image(
img_url,
f"{icon_path}/{id_}.png",
icon_path / f"{id_}.png",
semaphore,
True,
)
@@ -179,7 +179,7 @@ async def download_map_init(semaphore: Semaphore, flag: bool = False):
map_url = _map_data["url"]
await download_image(
map_url,
f"{map_path}/{idx}.png",
map_path / f"{idx}.png",
semaphore,
force_flag=flag,
)
@@ -228,15 +228,14 @@ async def download_resource_type():
except (TimeoutError, ConnectTimeout):
logger.warning("下载原神资源类型数据超时....")
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")
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()
B.paste(icon_img, (17, 10), True)
B.paste(A, alpha=True)
@@ -247,22 +246,22 @@ def gen_icon(icon: str):
# 下载图片
async def download_image(
img_url: str,
path: str,
path: Path,
semaphore: Semaphore,
gen_flag: bool = False,
force_flag: bool = False,
):
async with semaphore:
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):
logger.info(f"下载原神资源图标:{img_url}")
if gen_flag:
gen_icon(path)
else:
logger.info(f"下载原神资源图标:{img_url} 失败,等待下次更新...")
except UnidentifiedImageError:
logger.warning(f"原神图片打开错误..已删除,等待下次更新... file: {path}")
except Exception as e:
logger.warning(f"原神图片错误..已删除,等待下次更新... file: {path} {type(e)}:{e}")
if os.path.exists(path):
os.remove(path)
@@ -128,7 +128,7 @@ async def get_character(
) -> Optional[dict]:
try:
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={
"Accept": "application/json, text/plain, */*",
"DS": get_ds(
@@ -232,7 +232,7 @@ async def get_mys_data(uid: str, mys_id: Optional[str]) -> Optional[List[Dict]]:
if mys_id:
try:
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={
"DS": get_ds(f"uid={mys_id}"),
"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")
height = 0
for country in ["蒙德", "龙脊雪山", "璃月", "层岩巨渊", "稻妻", "渊下宫"]:
if not world_data_dict.get(country):
continue
x = BuildImage(790, 250, color="#3A4467")
logo = BuildImage(180, 180, background=image_path / "logo" / f"{country}.png")
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.message_builder import at
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)
if group_list:
group_id = group_list[0]
await bot.send_group_msg(
group_id=group_id,
message=at(user_id) + msg
)
try:
await bot.send_group_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 user_manager.check(uid) and Config.get_config("resin_remind", "AUTO_CLOSE_QUERY_FAIL_RESIN_REMIND"):
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.adapters.onebot.v11 import Bot, GroupMessageEvent, Message
from nonebot.adapters.onebot.v11.permission import GROUP
from utils.utils import is_number, get_message_img
from nonebot.typing import T_State
from utils.utils import is_number, get_message_img, get_message_text
from nonebot.adapters.onebot.v11.exception import ActionFailed
from configs.path_config import DATA_PATH, TEMP_PATH
from utils.image_utils import get_img_hash
@@ -10,7 +9,7 @@ from services.log import logger
from configs.config import NICKNAME, Config
from utils.http_utils import AsyncHttpx
from nonebot.params import CommandArg, Command
from typing import Tuple
from typing import Tuple, Dict, Any
import time
try:
@@ -57,7 +56,7 @@ mute_setting = on_command(
)
def get_data():
def get_data() -> Dict[Any, Any]:
try:
with open(DATA_PATH / "group_mute_data.json", "r", encoding="utf8") as f:
data = json.load(f)
@@ -72,7 +71,7 @@ def save_data():
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(
url, TEMP_PATH / f"mute_{group_id}_img.jpg"
):
@@ -85,9 +84,9 @@ mute_data = get_data()
@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)
msg = arg.extract_plain_text().strip()
msg = get_message_text(event.json())
img_list = get_message_img(event.json())
img_hash = ""
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):
mute_dict[event.user_id] = {"time": time.time(), "count": 1, "msg": msg}
else:
if cmd or not msg:
return
if msg and msg.find(mute_dict[event.user_id]["msg"]) != -1:
mute_dict[event.user_id]["count"] += 1
else:
@@ -123,7 +120,7 @@ async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command()
await bot.set_group_ban(
group_id=event.group_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)
mute_dict[event.user_id]["count"] = 0
@@ -137,27 +134,28 @@ async def _(bot: Bot, event: GroupMessageEvent, cmd: Tuple[str, ...] = Command()
@mute_setting.handle()
async def _(event: GroupMessageEvent, cmd: Tuple[str, ...] = Command(), arg: Message = CommandArg()):
global mute_data
group_id = str(event.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()
if cmd[0] == "刷屏检测设置":
await mute_setting.finish(
f'最大次数:{mute_data[group_id]["count"]} 次\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时关闭此功能】"
)
if not is_number(msg):
await mute.finish("设置的参数必须是数字啊!", at_sender=True)
if cmd[0] == "设置检测时间":
if cmd[0] == "设置刷屏检测时间":
mute_data[group_id]["time"] = int(msg)
msg += "秒"
if cmd[0] == "设置检测次数":
if cmd[0] == "设置刷屏检测次数":
mute_data[group_id]["count"] = int(msg)
msg += " 次"
if cmd[0] == "设置禁言时长":
mute_data[group_id]["duration"] = int(msg) * 60
if cmd[0] == "设置刷屏禁言时长":
mute_data[group_id]["duration"] = int(msg)
msg += " 分钟"
await mute_setting.send(f'刷屏检测:{cmd[0]}为 {msg}')
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.matcher import Matcher
from utils.utils import scheduler, is_number
@@ -9,7 +9,7 @@ from nonebot.permission import SUPERUSER
import random
from nonebot.plugin import MatcherGroup
from configs.path_config import IMAGE_PATH
from nonebot.params import CommandArg
from nonebot.params import CommandArg, RegexGroup
from .open_cases_c import (
open_case,
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()
async def _(event: GroupMessageEvent, state: T_State):
num = state["_matched_groups"][0].strip()
async def _(event: GroupMessageEvent, state: T_State, reg_group: Tuple[Any, ...] = RegexGroup()):
num, case_name = reg_group
if is_number(num) or num_dict.get(num):
try:
num = num_dict[num]
@@ -162,7 +162,6 @@ async def _(event: GroupMessageEvent, state: T_State):
await open_shilian.finish("再负开箱就扣你明天开箱数了!", at_sender=True)
else:
await open_shilian.finish("必须要是数字切不要超过30啊笨蛋!中文也可!", at_sender=True)
case_name = state["_matched_groups"][1].strip()
case_name = case_name.replace("武器箱", "").strip()
if not case_name:
case_name = random.choice(cases_name)
@@ -212,16 +211,16 @@ update_price = on_command("更新开箱价格", priority=1, permission=SUPERUSER
@update_price.handle()
async def _( event: MessageEvent):
await update_price.send(await util_get_buff_price(str(event.get_message())))
async def _(event: MessageEvent, arg: Message = CommandArg()):
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.handle()
async def _(event: MessageEvent):
await update_img.send(await util_get_buff_img(str(event.get_message())))
async def _(event: MessageEvent, arg: Message = CommandArg()):
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 services.log import logger
from nonebot.adapters.onebot.v11 import GroupMessageEvent
from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text
from nonebot.adapters.onebot.v11.permission import GROUP
from bilibili_api import video
from utils.message_builder import image
from nonebot.adapters.onebot.v11.exception import ActionFailed
from utils.image_utils import BuildImage
from utils.browser import get_browser
from configs.path_config import IMAGE_PATH
from utils.http_utils import AsyncHttpx
from configs.config import Config
from utils.user_agent import get_user_agent
import aiohttp
import asyncio
import time
from bilibili_api import settings
import ujson as json
__zx_plugin_name__ = "B站转发解析"
__plugin_usage__ = """
usage:
B站转发解析,解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv,且5分钟内不解析相同url
""".strip()
__plugin_des__ = "B站转发解析"
__plugin_type__ = ("其他",)
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_task__ = {"bilibili_parse": "b站转发解析"}
Config.add_plugin_config(
"_task",
"DEFAULT_BILIBILI_PARSE",
True,
help_="被动 B站转发解析 进群默认开关状态",
default_value=True,
)
if get_local_proxy():
settings.proxy = get_local_proxy()
parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False)
_tmp = {}
@parse_bilibili_json.handle()
async def _(event: GroupMessageEvent):
vd_info = None
url = None
if get_message_json(event.json()):
try:
data = json.loads(get_message_json(event.json())[0]["data"])
except (IndexError, KeyError):
data = None
if data:
# 转发视频
if data.get("desc") == "哔哩哔哩":
async with aiohttp.ClientSession(
headers=get_user_agent()
) as session:
async with session.get(
data["meta"]["detail_1"]["qqdocurl"],
proxy=get_local_proxy(),
timeout=7,
) as response:
url = str(response.url).split("?")[0]
bvid = url.split("/")[-1]
vd_info = await video.Video(bvid=bvid).get_info()
# response = await AsyncHttpx.get(
# data["meta"]["detail_1"]["qqdocurl"], timeout=7
# )
# url = str(response.url).split("?")[0]
# bvid = url.split("/")[-1]
# vd_info = await video.Video(bvid=bvid).get_info()
# 转发专栏
if (
data.get("meta")
and data["meta"].get("news")
and data["meta"]["news"].get("desc") == "哔哩哔哩专栏"
):
url = data["meta"]["news"]["jumpUrl"]
page = None
try:
browser = await get_browser()
if not browser:
return
page = await browser.new_page(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
" (KHTML, like Gecko) Chrome/93.0.4530.0 Safari/537.36"
)
await page.goto(url, wait_until="networkidle", timeout=10000)
await page.set_viewport_size({"width": 2560, "height": 1080})
await page.click("#app > div")
div = await page.query_selector("#app > div")
await div.screenshot(
path=f"{IMAGE_PATH}/temp/cv_{event.user_id}.png",
timeout=100000,
)
await asyncio.get_event_loop().run_in_executor(
None, resize, f"{IMAGE_PATH}/temp/cv_{event.user_id}.png"
)
await parse_bilibili_json.send(
"[[_task|bilibili_parse]]" + image(f"cv_{event.user_id}.png", "temp")
)
await page.close()
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
)
except Exception as e:
logger.error(f"尝试解析bilibili专栏 {url} 失败 {type(e)}:{e}")
if page:
await page.close()
return
# BV
if msg := get_message_text(event.json()):
if "BV" in msg:
index = msg.find("BV")
if len(msg[index + 2 :]) >= 10:
msg = msg[index : index + 12]
url = f"https://www.bilibili.com/video/{msg}"
vd_info = await video.Video(bvid=msg).get_info()
elif "av" in msg:
index = msg.find("av")
if len(msg[index + 2 :]) >= 9:
msg = msg[index + 2 : index + 11]
if is_number(msg):
url = f"https://www.bilibili.com/video/{msg}"
vd_info = await video.Video(aid=int(msg)).get_info()
elif "https://b23.tv" in msg:
url = "https://" + msg[msg.find("b23.tv") : msg.find("b23.tv") + 13]
res = await AsyncHttpx.get(url, timeout=7)
url = str(res.url).split("?")[0]
bvid = url.split("/")[-1]
vd_info = await video.Video(bvid=bvid).get_info()
if vd_info:
if (
url in _tmp.keys() and time.time() - _tmp[url] > 30
) or url not in _tmp.keys():
_tmp[url] = time.time()
aid = vd_info["aid"]
title = vd_info["title"]
author = vd_info["owner"]["name"]
reply = vd_info["stat"]["reply"] # 回复
favorite = vd_info["stat"]["favorite"] # 收藏
coin = vd_info["stat"]["coin"] # 投币
# like = vd_info['stat']['like'] # 点赞
# danmu = vd_info['stat']['danmaku'] # 弹幕
date = time.strftime("%Y-%m-%d", time.localtime(vd_info["ctime"]))
try:
await parse_bilibili_json.send(
"[[_task|bilibili_parse]]" +
image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n"
f"UP:{author}\n"
f"上传日期:{date}\n"
f"回复:{reply},收藏:{favorite},投币:{coin}\n"
f"{url}"
)
except ActionFailed:
logger.warning(f"{event.group_id} 发送bilibili解析失败")
else:
logger.info(
f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
)
def resize(path: str):
A = BuildImage(0, 0, background=path, ratio=0.5)
A.save(path)
# from nonebot import on_message
# from services.log import logger
# from nonebot.adapters.onebot.v11 import GroupMessageEvent
# from utils.utils import get_message_json, get_local_proxy, is_number, get_message_text
# from nonebot.adapters.onebot.v11.permission import GROUP
# from utils.message_builder import image
# from nonebot.adapters.onebot.v11.exception import ActionFailed
# from utils.image_utils import BuildImage
# from utils.browser import get_browser
# from configs.path_config import IMAGE_PATH
# from utils.http_utils import AsyncHttpx
# from configs.config import Config
# from utils.user_agent import get_user_agent
# import aiohttp
# import asyncio
# import time
# import ujson as json
#
#
# __zx_plugin_name__ = "B站转发解析"
# __plugin_usage__ = """
# usage:
# B站转发解析,解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv,且5分钟内不解析相同url
# """.strip()
# __plugin_des__ = "B站转发解析"
# __plugin_type__ = ("其他",)
# __plugin_version__ = 0.1
# __plugin_author__ = "HibiKier"
# __plugin_task__ = {"bilibili_parse": "b站转发解析"}
# Config.add_plugin_config(
# "_task",
# "DEFAULT_BILIBILI_PARSE",
# True,
# help_="被动 B站转发解析 进群默认开关状态",
# default_value=True,
# )
#
#
# parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False)
#
# _tmp = {}
#
#
# @parse_bilibili_json.handle()
# async def _(event: GroupMessageEvent):
# vd_info = None
# url = None
# if get_message_json(event.json()):
# try:
# data = json.loads(get_message_json(event.json())[0]["data"])
# except (IndexError, KeyError):
# data = None
# if data:
# # 转发视频
# if data.get("desc") == "哔哩哔哩":
# async with aiohttp.ClientSession(
# headers=get_user_agent()
# ) as session:
# async with session.get(
# data["meta"]["detail_1"]["qqdocurl"],
# proxy=get_local_proxy(),
# timeout=7,
# ) as response:
# url = str(response.url).split("?")[0]
# bvid = url.split("/")[-1]
# vd_info = await video.Video(bvid=bvid).get_info()
# # response = await AsyncHttpx.get(
# # data["meta"]["detail_1"]["qqdocurl"], timeout=7
# # )
# # url = str(response.url).split("?")[0]
# # bvid = url.split("/")[-1]
# # vd_info = await video.Video(bvid=bvid).get_info()
# # 转发专栏
# if (
# data.get("meta")
# and data["meta"].get("news")
# and data["meta"]["news"].get("desc") == "哔哩哔哩专栏"
# ):
# url = data["meta"]["news"]["jumpUrl"]
# page = None
# try:
# browser = await get_browser()
# if not browser:
# return
# page = await browser.new_page(
# user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
# " (KHTML, like Gecko) Chrome/93.0.4530.0 Safari/537.36"
# )
# await page.goto(url, wait_until="networkidle", timeout=10000)
# await page.set_viewport_size({"width": 2560, "height": 1080})
# await page.click("#app > div")
# div = await page.query_selector("#app > div")
# await div.screenshot(
# path=f"{IMAGE_PATH}/temp/cv_{event.user_id}.png",
# timeout=100000,
# )
# await asyncio.get_event_loop().run_in_executor(
# None, resize, f"{IMAGE_PATH}/temp/cv_{event.user_id}.png"
# )
# await parse_bilibili_json.send(
# "[[_task|bilibili_parse]]" + image(f"cv_{event.user_id}.png", "temp")
# )
# await page.close()
# logger.info(
# f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
# )
# except Exception as e:
# logger.error(f"尝试解析bilibili专栏 {url} 失败 {type(e)}:{e}")
# if page:
# await page.close()
# return
# # BV
# if msg := get_message_text(event.json()):
# if "BV" in msg:
# index = msg.find("BV")
# if len(msg[index + 2 :]) >= 10:
# msg = msg[index : index + 12]
# url = f"https://www.bilibili.com/video/{msg}"
# vd_info = await video.Video(bvid=msg).get_info()
# elif "av" in msg:
# index = msg.find("av")
# if len(msg[index + 2 :]) >= 9:
# msg = msg[index + 2 : index + 11]
# if is_number(msg):
# url = f"https://www.bilibili.com/video/{msg}"
# vd_info = await video.Video(aid=int(msg)).get_info()
# elif "https://b23.tv" in msg:
# url = "https://" + msg[msg.find("b23.tv") : msg.find("b23.tv") + 13]
# res = await AsyncHttpx.get(url, timeout=7)
# url = str(res.url).split("?")[0]
# bvid = url.split("/")[-1]
# vd_info = await video.Video(bvid=bvid).get_info()
# if vd_info:
# if (
# url in _tmp.keys() and time.time() - _tmp[url] > 30
# ) or url not in _tmp.keys():
# _tmp[url] = time.time()
# aid = vd_info["aid"]
# title = vd_info["title"]
# author = vd_info["owner"]["name"]
# reply = vd_info["stat"]["reply"] # 回复
# favorite = vd_info["stat"]["favorite"] # 收藏
# coin = vd_info["stat"]["coin"] # 投币
# # like = vd_info['stat']['like'] # 点赞
# # danmu = vd_info['stat']['danmaku'] # 弹幕
# date = time.strftime("%Y-%m-%d", time.localtime(vd_info["ctime"]))
# try:
# await parse_bilibili_json.send(
# "[[_task|bilibili_parse]]" +
# image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n"
# f"UP:{author}\n"
# f"上传日期:{date}\n"
# f"回复:{reply},收藏:{favorite},投币:{coin}\n"
# f"{url}"
# )
# except ActionFailed:
# logger.warning(f"{event.group_id} 发送bilibili解析失败")
# else:
# logger.info(
# f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}"
# )
#
#
# 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.adapters.onebot.v11 import MessageEvent, Message, GroupMessageEvent
from nonebot.typing import T_State
from configs.path_config import TEMP_PATH
from services.log import logger
from utils.message_builder import image
from utils.utils import is_number
from utils.manager import withdraw_message_manager
from utils.http_utils import AsyncHttpx
from nonebot.params import CommandArg, Arg
try:
import ujson as json
except ModuleNotFoundError:
import json
__zx_plugin_name__ = "pid搜索"
__plugin_usage__ = """
usage:
通过 pid 搜索图片
指令:
p搜 [pid]
""".strip()
__plugin_des__ = "通过 pid 搜索图片"
__plugin_cmd__ = ["p搜 [pid]"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["p搜"],
}
pid_search = on_command("p搜", aliases={"pixiv搜", "P搜"}, priority=5, block=True)
url = "https://api.fantasyzone.cc/tu/search.php"
@pid_search.handle()
async def _(state: T_State, arg: Message = CommandArg()):
pid = arg.extract_plain_text().strip()
if pid:
state["pid"] = pid
@pid_search.got("pid", prompt="需要查询的图片PID是?")
async def _(event: MessageEvent, state: T_State, pid: str = Arg("pid")):
if pid in ["取消", "算了"]:
await pid_search.finish("已取消操作...")
if is_number(pid):
await pid_search.reject_arg("pid", "笨蛋,重新输入数!字!")
params = {
"id": pid,
"p": 1,
}
for _ in range(3):
try:
data = (await AsyncHttpx.get(url, params=params, timeout=5)).json()
except TimeoutError:
pass
except Exception as e:
await pid_search.finish(f"发生了一些错误..{type(e)}:{e}")
else:
if not data["width"] and not data["height"]:
await pid_search.finish(f"没有搜索到 PID:{pid} 的图片", at_sender=True)
pid = data["id"]
title = data["title"]
author = data["userName"]
author_id = data["userId"]
img_url = data["url"]
if not await AsyncHttpx.download_file(
img_url, TEMP_PATH / f"pid_search_{event.user_id}.png"
):
await pid_search.finish("图片下载失败了....", at_sender=True)
tmp = ""
if isinstance(event, GroupMessageEvent):
tmp = "\n【注】将在30后撤回......"
msg_id = await pid_search.send(
Message(
f"title:{title}\n"
f"pid:{pid}\n"
f"author:{author}\n"
f"author_id:{author_id}\n"
f'{image(TEMP_PATH / f"pid_search_{event.user_id}.png")}'
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)
from nonebot import on_command
from nonebot.adapters.onebot.v11 import Bot, MessageEvent, Message, GroupMessageEvent
from nonebot.typing import T_State
from configs.config import Config
from utils.utils import is_number, change_pixiv_image_links
from utils.message_builder import image
from services.log import logger
from asyncio.exceptions import TimeoutError
from configs.path_config import IMAGE_PATH
from utils.manager import withdraw_message_manager
from utils.http_utils import AsyncHttpx
from nonebot.params import CommandArg, Arg
__zx_plugin_name__ = "pid搜索"
__plugin_usage__ = """
usage:
通过 pid 搜索图片
指令:
p搜 [pid]
""".strip()
__plugin_des__ = "通过 pid 搜索图片"
__plugin_cmd__ = ["p搜 [pid]"]
__plugin_version__ = 0.1
__plugin_author__ = "HibiKier"
__plugin_settings__ = {
"level": 5,
"default_status": True,
"limit_superuser": False,
"cmd": ["p搜"],
}
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()):
pid = arg.extract_plain_text().strip()
if pid:
state["pid"] = pid
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6;"
" rv:2.0.1) Gecko/20100101 Firefox/4.0.1",
"Referer": "https://www.pixiv.net",
}
@pid_search.got("pid", prompt="需要查询的图片PID是?")
async def _g(event: MessageEvent, state: T_State, pid: str = Arg("pid")):
url = Config.get_config("hibiapi", "HIBIAPI") + "/api/pixiv/"
if pid in ["取消", "算了"]:
await pid_search.finish("已取消操作...")
if not is_number(pid):
await pid_search.reject_arg("pid", "笨蛋,重新输入数!字!")
for _ in range(3):
try:
data = (
await AsyncHttpx.get(
url,
params={"id": pid},
timeout=5,
)
).json()
except TimeoutError:
pass
except Exception as e:
await pid_search.finish(f"发生了一些错误..{type(e)}:{e}")
else:
if data.get("error"):
await pid_search.finish(data["error"]["user_message"], at_sender=True)
data = data["illust"]
if not data["width"] and not data["height"]:
await pid_search.finish(f"没有搜索到 PID:{pid} 的图片", at_sender=True)
pid = data["id"]
title = data["title"]
author = data["user"]["name"]
author_id = data["user"]["id"]
image_list = []
try:
image_list.append(data["meta_single_page"]["original_image_url"])
except KeyError:
for image_url in data["meta_pages"]:
image_list.append(image_url["image_urls"]["original"])
for i, img_url in enumerate(image_list):
img_url = change_pixiv_image_links(img_url)
if not await AsyncHttpx.download_file(
img_url,
IMAGE_PATH / "temp" / f"pid_search_{event.user_id}_{i}.png",
headers=headers,
):
await pid_search.send("图片下载失败了....", at_sender=True)
tmp = ""
if isinstance(event, GroupMessageEvent):
tmp = "\n【注】将在30后撤回......"
msg_id = await pid_search.send(
Message(
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:
import json
if str(platform.system()).lower() == "windows":
policy = asyncio.WindowsSelectorEventLoopPolicy()
asyncio.set_event_loop_policy(policy)
# if str(platform.system()).lower() == "windows":
# policy = asyncio.WindowsSelectorEventLoopPolicy()
# asyncio.set_event_loop_policy(policy)
headers = {
"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()
return [x[0] for x in data]
@classmethod
async def test(cls, nsfw_tag: int = 1):
if nsfw_tag is not None:
query = cls.query.where(cls.nsfw_tag == nsfw_tag)
else:
query = cls.query
query = query.where((cls.width - cls.height) < 50)
for x in await query.gino.all():
print(x.pid)
# async def test(cls, nsfw_tag: int = 1):
# if nsfw_tag is not None:
# query = cls.query.where(cls.nsfw_tag == nsfw_tag)
# else:
# query = cls.query
# query = query.where((cls.width - cls.height) < 50)
# for x in await query.gino.all():
# print(x.pid)
+11 -5
View File
@@ -18,6 +18,7 @@ usage:
查看 pix 好康图库
指令:
pix ?*[tags]: 通过 tag 获取相似图片,不含tag时随机抽取
pid [uid]: 通过uid获取图片
pix pid[pid]: 查看图库中指定pid图片
""".strip()
__plugin_superuser_usage__ = """
@@ -49,7 +50,9 @@ __plugin_configs__ = {
"value": None,
"help": "单次发送的图片数量达到指定值时转发为合并消息",
"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
else:
nsfw_tag = 0
if nsfw_tag != 0 and str(event.user_id) not in bot.config.superusers:
await pix.finish("你不能看这些噢,这些都是是留给管理员看的...")
if n := len(x) == 1 and is_number(x[0]):
num = int(x[-1])
if str(event.user_id) not in bot.config.superusers:
if (nsfw_tag == 1 and not Config.get_config("pix", "ALLOW_GROUP_SETU")) or (
nsfw_tag == 2 and not Config.get_config("pix", "ALLOW_GROUP_R18")
):
await pix.finish("你不能看这些噢,这些都是是留给管理员看的...")
if n := len(x) == 1 and is_number(x[0]) and int(x[0]) < 100:
num = int(x[0])
keyword = ""
elif n > 1:
if is_number(x[-1]):
+4 -2
View File
@@ -44,6 +44,8 @@ usage:
搜图 樱岛麻衣
搜图 樱岛麻衣 5
搜图 樱岛麻衣 5 r18
搜图 樱岛麻衣#1000users 5
【多个关键词用#分割】
【默认为 热度排序】
【注意空格!!】【在线搜索会较慢】【数量可能不符?可能该页数量不够,也可能被R-18屏蔽】
""".strip()
@@ -161,8 +163,8 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
info_list = None
num = 10
page = 1
if (n := len(msg)) == 1:
keyword = msg[0]
if (n := len(msg)) > 0:
keyword = msg[0].replace("#"," ")
if n > 1:
if not is_number(msg[1]):
await pixiv_keyword.finish("图片数量必须是数字!", at_sender=True)
+4 -4
View File
@@ -8,10 +8,10 @@ from services.log import logger
from pathlib import Path
import platform
if platform.system() == "Windows":
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
# if platform.system() == "Windows":
# import asyncio
#
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
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"),
)
if anime_report:
if isinstance(anime_report, str):
await search_anime.finish(anime_report)
if isinstance(event, GroupMessageEvent):
mes_list = custom_forward_msg(anime_report, bot.self_id)
await bot.send_group_forward_msg(group_id=event.group_id, messages=mes_list)
+4 -4
View File
@@ -3,18 +3,18 @@ import feedparser
from urllib import parse
from services.log import logger
from utils.http_utils import AsyncHttpx
from typing import List
from typing import List, Union
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()
repass = ""
url = "https://share.dmhy.org/topics/rss/rss.xml?keyword=" + parse.quote(key_word)
try:
repass = await get_repass(url, max_)
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")
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()
if data["header"]["status"] != 0:
return "Saucenao识图失败.."
return f"Saucenao识图失败..status:{data['header']['status']}"
data = data["results"]
data = (
data
+23 -29
View File
@@ -4,7 +4,7 @@ from services.log import logger
from models.sign_group_user import SignGroupUser
from nonebot.message import run_postprocessor
from nonebot.matcher import Matcher
from typing import Optional, Type
from typing import Optional, Type, Any
from gino.exceptions import UninitializedError
from utils.utils import (
is_number,
@@ -33,7 +33,7 @@ from .data_source import (
from nonebot.adapters.onebot.v11.exception import ActionFailed
from configs.config import Config, NICKNAME
from utils.manager import withdraw_message_manager
from nonebot.params import CommandArg, Command
from nonebot.params import CommandArg, Command, RegexGroup
from typing import Tuple
import re
@@ -97,6 +97,7 @@ __plugin_configs__ = {
},
"TIMEOUT": {"value": 10, "help": "色图下载超时限制(秒)", "default_value": 10},
"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反向代理")
@@ -148,10 +149,16 @@ async def _(
if cmd[0] == "色图r" and isinstance(event, PrivateMessageEvent):
r18 = 1
num = 10
elif cmd[0] == "色图r" and isinstance(event, GroupMessageEvent):
await setu.finish(
random.choice(["这种不好意思的东西怎么可能给这么多人看啦", "羞羞脸!给我滚出克私聊!", "变态变态变态变态大变态!"])
)
elif (
cmd[0] == "色图r"
and isinstance(event, GroupMessageEvent)
):
if not Config.get_config("send_setu", "ALLOW_GROUP_R18"):
await setu.finish(
random.choice(["这种不好意思的东西怎么可能给这么多人看啦", "羞羞脸!给我滚出克私聊!", "变态变态变态变态大变态!"])
)
else:
r18 = 1
# 有 数字 的话先尝试本地色图id
if msg and is_number(msg):
setu_list, code = await get_setu_list(int(msg), r18=r18)
@@ -190,7 +197,7 @@ num_key = {
@setu_reg.handle()
async def _(event: MessageEvent, arg: Message = CommandArg()):
async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
if isinstance(event, GroupMessageEvent):
impression = (
await SignGroupUser.ensure(event.user_id, event.group_id)
@@ -198,28 +205,15 @@ async def _(event: MessageEvent, arg: Message = CommandArg()):
luox = get_luoxiang(impression)
if luox:
await setu.finish(luox, at_sender=True)
msg = arg.extract_plain_text().strip()
num = 1
msg = re.search(r"(.*)[份发张个次点](.*)[瑟涩色]图", msg)
# 解析 tags 以及 num
if msg:
num = msg.group(1)
tags = msg.group(2)
if tags:
tags = tags[:-1] if tags[-1] == "的" else tags
if num:
num = num[-1]
if num_key.get(num):
num = num_key[num]
elif is_number(num):
try:
num = int(num)
except ValueError:
num = 1
else:
num = 1
else:
return
num, tags = reg_group
num = num or 1
tags = tags[:-1] if tags and tags[-1] == "的" else tags
if num_key.get(num):
num = num_key[num]
try:
num = int(num)
except ValueError:
num = 1
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()
_type = "view" if is_card_view else "sign"
card_file = (
Path(SIGN_TODAY_CARD_PATH)
/ f"{user_id}_{user.group_id}_{_type}_{date}.png"
Path(SIGN_TODAY_CARD_PATH) / f"{user_id}_{user.group_id}_{_type}_{date}.png"
)
if card_file.exists():
return image(
f"{user_id}_{user.group_id}_{_type}_{date}.png", "sign/today_card"
)
return image(f"{user_id}_{user.group_id}_{_type}_{date}.png", "sign/today_card")
else:
if add_impression == -1:
card_file = (
@@ -75,9 +72,7 @@ async def get_card(
)
is_card_view = True
ava = BytesIO(await get_user_avatar(user_id))
uid = await GroupInfoUser.get_group_member_uid(
user.user_qq, user.group_id
)
uid = await GroupInfoUser.get_group_member_uid(user.user_qq, user.group_id)
impression_list = None
if is_card_view:
_, impression_list, _ = await SignGroupUser.get_all_impression(
@@ -128,9 +123,13 @@ def _generate_card(
level, next_impression, previous_impression = get_level_and_next_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, 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 = 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()}",
)
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(
(0, 50),
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_data, (580, 220), True)
bk.paste(watermark, (15, 400), True)
bk.save(
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"
)
bk.save(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")
def generate_progress_bar_pic():
+1 -1
View File
@@ -96,7 +96,7 @@ async def _(
global _prefix_count_dict
if (
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"]
):
module = matcher.plugin_name
+2 -2
View File
@@ -5,8 +5,8 @@ import asyncio
import platform
import os
if platform.system() == "Windows":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
# if platform.system() == "Windows":
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
url = "https://github.com/Mrs4s/go-cqhttp/releases"
+3 -3
View File
@@ -12,7 +12,7 @@ __plugin_usage__ = """
usage:
普普通通的查天气吧
指令:
[城市]天气/天气[城市]
[城市]天气
""".strip()
__plugin_des__ = "出门要看看天气,不要忘了带伞"
__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()
async def _(event: MessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()):
msg = reg_group[0]
if msg[-1] != "市":
if msg and msg[-1] != "市":
msg += "市"
city = ""
if msg:
+5 -3
View File
@@ -1,8 +1,10 @@
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 nonebot import on_command
from nonebot.typing import T_State
from nonebot.params import Arg
from utils.utils import get_message_img
from services.log import logger
@@ -31,10 +33,10 @@ what_anime = on_command("识番", priority=5, block=True)
@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())
if img_url:
state["img_url"] = img_url[0]
state["img_url"] = args
@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):
self._data = {
"user_id": user_id,
"group_id": group_id,
"problem": problem
}
"group_id": group_id}
self.problem = problem
def set_placeholder(self, id_: int, placeholder: Union[str, int]):
"""
@@ -28,13 +27,20 @@ class WordBankBuilder:
"""
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"]
group_id = self._data["group_id"]
problem = self._data["problem"]
answer = self._data["answer"]
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):
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 utils.utils import get_message_text
from utils.utils import get_message_img_file
from nonebot.typing import T_State
from .model import WordBank
async def check(bot: Bot, event: Event, state: T_State) -> bool:
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(
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
+75 -2
View File
@@ -3,9 +3,11 @@ from ._rule import check
from .model import WordBank
from configs.path_config import DATA_PATH
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 models.group_member_info import GroupInfoUser
from utils.utils import get_message_img_file, is_number
import re
__zx_plugin_name__ = "词库问答回复操作 [Hidden]"
@@ -17,8 +19,14 @@ message_handle = on_message(priority=6, block=True, rule=check)
@message_handle.handle()
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(
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))
@@ -54,3 +62,68 @@ async def get_one_answer(event, format, _answer, all=1):
answer += _a[: _a.find(f"[__placeholder_{idx}]")] + "@" + q.user_name
_a = _a[_a.find(f"[__placeholder_{idx}]") + len(f"[__placeholder_{idx}]"):]
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 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(
(cls.group_id == group_id) & (cls.problem == problem)
).gino.all()
+56 -23
View File
@@ -6,7 +6,7 @@ from utils.http_utils import AsyncHttpx
from ._data_source import WordBankBuilder
from utils.message_builder import image
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 nonebot.adapters.onebot.v11 import (
Bot,
@@ -19,6 +19,7 @@ import random
import os
import re
from configs.config import NICKNAME, Config
from models.group_member_info import GroupInfoUser
__zx_plugin_name__ = "词库问答 [Admin]"
__plugin_usage__ = """
@@ -26,7 +27,7 @@ usage:
对指定问题的随机回答,对相同问题可以设置多个不同回答
删除词条后每个词条的id可能会变化,请查看后再删除
指令:
添加词条 ?[模糊/关键字]...答...:添加问答词条,可重复添加相同问题的不同回答
添加词条 ?[模糊/关键字|词]...答...:添加问答词条,可重复添加相同问题的不同回答
删除词条 [问题/下标] ?[下标]:删除指定词条指定或全部回答
修改词条 [问题/下标] ?[下标/新回答] [新回答]:修改指定词条指定回答默认修改为第一条
查看词条 ?[问题/下标]:查看全部词条或对应词条回答
@@ -48,8 +49,8 @@ __plugin_cmd__ = [
"修改词条 [问题/下标] ?[下标/新回答] [新回答]",
"查看词条 ?[问题/下标]",
]
__plugin_version__ = 0.2
__plugin_author__ = "HibiKier"
__plugin_version__ = 0.3
__plugin_author__ = "HibiKier & yajiwa"
__plugin_settings__ = {
"admin_level": Config.get_config("word_bank", "WORD_BANK_LEVEL [LEVEL]"),
"cmd": ["词库问答", "添加词条", "删除词条", "修改词条", "查看词条"],
@@ -87,21 +88,21 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State, arg: Message = C
else:
_problem = problem
search_type = 0
if re.search("^关键字(.*)", msg):
if re.search("^关键字|词(.*)", msg):
search_type = 1
elif re.search("^模糊(.*)", msg):
search_type = 2
_builder = await get__builder(event, _problem, answer, idx)
if await _builder.save(search_type):
logger.info(f"已保存词条 问:{problem} 答:{msg}")
await add_word.send(f"已保存词条:{problem}")
logger.info(f"已保存词条 问:{_builder.problem} 答:{msg}")
await add_word.send("已保存词条:" + _builder.problem)
else:
await delete_word.send("保存失败,可能是回答重复")
@delete_word.handle()
async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
msg = str(arg).strip()
if not msg:
await delete_word.finish("此命令之后需要跟随指定词条,通过“显示词条“查看")
index = None
@@ -119,17 +120,18 @@ async def _(event: GroupMessageEvent, arg: Message = CommandArg()):
if p:
problem = p[int(x)]
try:
_problem, problem = await get_one_problem(event, problem)
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(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 删除词条: {problem}"
)
else:
await delete_word.send(f"删除词条:{problem} 失败,可能该词条不存在")
await delete_word.send("删除词条:" + problem + "失败,可能该词条不存在")
except IndexError:
await delete_word.send("指定下标错误...请通过查看词条来确定..")
@@ -165,21 +167,21 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
try:
if await _builder.update(index):
await update_word.send(f"修改词条成功:{problem}")
await update_word.send(f"修改词条成功:" + _builder.problem)
logger.info(
f"(USER {event.user_id}, GROUP "
f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})"
f" 修改词条: {problem}"
)
else:
await update_word.send(f"修改词条:{problem} 失败,可能该词条不存在")
await update_word.send(f"修改词条:" + _builder.problem + f"失败,可能该词条不存在")
except IndexError:
await update_word.send("指定下标错误...请通过查看词条来确定..")
@show_word.handle()
async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
msg = arg.extract_plain_text().strip()
msg = str(arg).strip()
if not msg:
_problem_list = await WordBank.get_group_all_problem(event.group_id)
if not _problem_list:
@@ -225,17 +227,28 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
)
)
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:
await show_word.send("未收录该词条...")
else:
# 解析图片和@
_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)
img_nu = 0
answer = f"词条 {msg} 回答:"
answer = "词条" + msg + "回答:"
for i, x, in enumerate(_answer_img_nu_list):
r = re.findall(rf"\[CQ:image,file=", str(x))
if r:
@@ -254,15 +267,25 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()):
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}" / "problem").mkdir(exist_ok=True, parents=True)
_builder = WordBankBuilder(event.user_id, event.group_id, _problem)
problem = ''
_p = _problem
for at_ in get_message_at(event.json()):
r = re.search(rf"\[CQ:at,qq={at_}]", answer)
if r:
answer = answer.replace(f"[CQ:at,qq={at_}]", f"[__placeholder_{idx}]", 1)
_builder.set_placeholder(idx, at_)
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()):
_x = img.split("?")[0]
_x_list = img.split("?")
r = re.search(rf"\[CQ:image,file=(.*),url={_x}.*?]", answer)
if r:
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}"):
break
rand = random.randint(1, 10000) + random.randint(1, 114514)
for i in range(3):
answer = answer.replace(f",subType={i}", "")
answer = answer.replace(
rf"[CQ:image,file={r.group(1)},url={img}]",
f"[__placeholder_{idx}]",
)
strinfo = re.compile(f"\[CQ:image,file={r.group(1)},url={_x_list[0]}\?{_x_list[1]},subType=\d*?]")
answer = strinfo.sub(f"[__placeholder_{idx}]", answer)
await AsyncHttpx.download_file(
img, data_dir / f"{event.group_id}" / f"__placeholder_{rand}_{idx}.jpg"
)
_builder.set_placeholder(idx, f"__placeholder_{rand}_{idx}.jpg")
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_problem(_problem)
_builder.problem = problem + _p
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 = {}
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]:
@@ -37,7 +37,7 @@ async def get_yiqing_data(area: str) -> Union[str, MessageSegment]:
if area in data[p]:
province = p
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"]
if area == "中国":
data_ = epidemic_data["areaTree"][0]
@@ -59,12 +59,12 @@ async def get_yiqing_data(area: str) -> Union[str, MessageSegment]:
add_confirm = data_["today"]["confirm"] # 新增确诊
grade = ""
_grade_color = ""
if data_["total"].get("grade"):
grade = data_["total"]["grade"]
if "中风险" in grade:
_grade_color = "#fa9424"
else:
_grade_color = "red"
# if data_["total"].get("grade"):
# grade = data_["total"]["grade"]
# if "中风险" in grade:
# _grade_color = "#fa9424"
# else:
# _grade_color = "red"
dead_rate = f"{dead / 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"
[[tool.poetry.source]]
name = "tsinghua"
name = "ali"
default = true
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
url = "https://mirrors.aliyun.com/pypi/simple/"
[tool.poetry.dependencies]
python = "^3.8"
nonebot2 = "^2.0.0-beta.2"
nonebot-adapter-onebot = "^2.0.0-beta.1"
bilibili-api = "^9.1.0"
aiofiles = "^0.8.0"
aiohttp = "3.7.4.post0"
beautifulsoup4 = "4.9.3"
@@ -40,6 +39,9 @@ dateparser = "^1.1.0"
cn2an = "^0.5.16"
python-jose = "^3.3.0"
python-multipart = "^0.0.5"
bilireq = "^0.1.2"
emoji = "^1.7.0"
wordcloud = "^1.8.1"
[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]:
global _browser
if platform.system() == "Windows":
return None
try:
browser = await async_playwright().start()
_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, ...],
price: Tuple[float, ...],
des: Tuple[str, ...],
discount: Tuple[float, ...],
limit_time: Tuple[int, ...],
load_status: Tuple[bool, ...],
**kwargs,
):
def add_register_item(func: Callable):
if name in self._data.keys():
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:
_temp_kwargs = {}
for key, value in kwargs.items():
@@ -32,6 +34,8 @@ class ShopRegister(dict):
self._data[n] = {
"price": p,
"des": d,
"discount": dd,
"limit_time": l,
"func": func,
"kwargs": _temp_kwargs,
}
@@ -46,7 +50,7 @@ class ShopRegister(dict):
self._flag = False
for name in self._data.keys():
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(
name, self._data[name]["func"], **self._data[name]["kwargs"]
@@ -57,24 +61,36 @@ class ShopRegister(dict):
name: Union[str, Tuple[str, ...]],
price: Union[float, Tuple[float, ...]],
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,
**kwargs,
):
_tuple_list = []
_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 _current_len == -1:
_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
_name = name if isinstance(name, tuple) else tuple(name)
_name = name if isinstance(name, tuple) else (name,)
_price = (
price
if isinstance(price, tuple)
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 if isinstance(des, tuple) else tuple([des for _ in range(_current_len)])
)
@@ -83,7 +99,7 @@ class ShopRegister(dict):
if isinstance(load_status, tuple)
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):
self._data[key] = value
+2 -2
View File
@@ -327,14 +327,14 @@ class AsyncPlaywright:
await page.set_viewport_size(viewport_size)
if isinstance(element, str):
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:
card = await page.query_selector(element)
else:
card = page
for e in element:
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:
card = await card.query_selector(e)
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
def is_valid(file: str) -> bool:
def is_valid(file: Union[str, Path]) -> bool:
"""
说明:
判断图片是否损坏
@@ -1493,10 +1493,11 @@ async def text2image(
height = 0
_tmp = BuildImage(0, 0, font=font, font_size=font_size)
for x in text.split("\n"):
x = x if x.strip() else "正"
w, h = _tmp.getsize(x)
height += h + _add_height
width = width if width > w else w
if x:
w, _ = _tmp.getsize(x)
_, h = _tmp.getsize("正")
height += h + _add_height
width = width if width > w else w
width += pw
height += ph
A = BuildImage(
+3 -7
View File
@@ -4,7 +4,6 @@ from pathlib import Path
class NonePluginCountManager(StaticData):
"""
插件加载容忍管理器,当连续 max_count 次插件加载,视为删除插件,清楚数据
"""
@@ -15,6 +14,8 @@ class NonePluginCountManager(StaticData):
:param max_count: 容忍最大次数
"""
super().__init__(file)
if not self._data:
self._data = {}
self._max_count = max_count
def add_count(self, module: str, count: int = 1):
@@ -42,10 +43,5 @@ class NonePluginCountManager(StaticData):
:param module: 模块
"""
if module in self._data.keys():
return self._data.keys() > self._max_count
return self._data[module] >= self._max_count
return False
+24 -3
View File
@@ -1,7 +1,7 @@
from datetime import datetime
from collections import defaultdict
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 nonebot.adapters.onebot.v11 import Bot, Message
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"]))
else:
for seg in data:
if seg.type == "image":
qq_list.append(seg.data["url"])
if seg.type == "at":
qq_list.append(seg.data["qq"])
return qq_list
@@ -229,6 +229,25 @@ def get_message_img(data: Union[str, Message]) -> List[str]:
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:
"""
说明:
@@ -370,6 +389,8 @@ def change_pixiv_image_links(
url = img_sp[0]
img_type = img_sp[1]
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:
url = (
url.replace("i.pximg.net", nginx_url)