Add HeXi bot codebase: custom plugins, web frontends, tests
- hexi core: message handling, rate limiting, cooldown, plugin manager - Custom plugins: BF stats, daily check-in, quotes, persona cards, etc. - Community plugins vendored under hexi/plugins with local fixes - Web admin frontends (learning-chat, persona-admin), unified hexi/web - Tests for rate_limit/cooldown/memes/persona; poetry.lock Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""群管理工具插件的业务操作子包。"""
|
||||
@@ -0,0 +1,69 @@
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent
|
||||
|
||||
from nonebot_plugin_alconna import UniMessage
|
||||
|
||||
from hexi.plugins.nonebot_plugin_hexi_core.custom_utils import check_manage
|
||||
|
||||
from ..utils.permissions import is_bot_manage, self_member_info
|
||||
from ..utils.text import parse_seconds
|
||||
|
||||
|
||||
async def group_silence(bot: Bot, ev: GroupMessageEvent, gid: int, status: bool):
|
||||
"""全员禁言(带权限检查)"""
|
||||
self_info = await self_member_info(bot, gid)
|
||||
if not is_bot_manage(self_info):
|
||||
await UniMessage.text("\n不给我管理员还想让我帮忙塞口球?做梦去吧!").send(
|
||||
at_sender=True
|
||||
)
|
||||
return
|
||||
if not await check_manage(bot, ev):
|
||||
await UniMessage.text("只有狗管理才能给大家塞口球哦w").send(at_sender=True)
|
||||
return
|
||||
try:
|
||||
await bot.set_group_whole_ban(group_id=gid, enable=status)
|
||||
if status:
|
||||
await UniMessage.text("嘻嘻大家都被塞口球啦~").send()
|
||||
else:
|
||||
await UniMessage.text("全员禁言取消啦w").send()
|
||||
except Exception as e:
|
||||
await UniMessage.text(f"操作失败惹...\n错误代码:{e}").send(at_sender=True)
|
||||
|
||||
|
||||
async def member_silence(
|
||||
bot: Bot,
|
||||
ev: GroupMessageEvent,
|
||||
uid: int,
|
||||
sid: int,
|
||||
gid: int,
|
||||
time: str,
|
||||
silent: bool = False,
|
||||
):
|
||||
"""单人禁言(带权限检查;uid == sid 时为禁言自己)"""
|
||||
self_info = await self_member_info(bot, gid)
|
||||
if not is_bot_manage(self_info):
|
||||
await UniMessage.text("\n不给我管理员还想让我帮忙塞口球?做梦去吧!").send(
|
||||
at_sender=True
|
||||
)
|
||||
return
|
||||
seconds = parse_seconds(time)
|
||||
if seconds is None:
|
||||
await UniMessage.text("憨批,时长都能输错?").send()
|
||||
return
|
||||
if uid != sid and not await check_manage(bot, ev):
|
||||
await UniMessage.text("只有管理员才可以给别人塞口球哦~").send(at_sender=True)
|
||||
return
|
||||
try:
|
||||
await bot.set_group_ban(group_id=gid, user_id=sid, duration=seconds)
|
||||
if seconds == 0:
|
||||
await UniMessage.at(user_id=str(sid)).text("的口球已经摘下来啦w").send()
|
||||
elif not silent:
|
||||
await UniMessage.at(user_id=str(sid)).text(f"成功禁言{seconds}秒~").send()
|
||||
except Exception as e:
|
||||
await UniMessage.text(f"口球失败惹呜呜呜...\n错误代码:{e}").send(at_sender=True)
|
||||
|
||||
|
||||
async def silence(bot: Bot, ev: MessageEvent, seconds: int) -> None:
|
||||
"""禁言发送者自己 seconds 秒(娱乐用,bot 需具有群管理权限,静默执行)"""
|
||||
await member_silence(
|
||||
bot, ev, ev.user_id, ev.user_id, ev.group_id, str(seconds), silent=True
|
||||
)
|
||||
@@ -0,0 +1,76 @@
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent
|
||||
|
||||
from nonebot_plugin_alconna import UniMessage
|
||||
|
||||
from hexi.plugins.nonebot_plugin_hexi_core.custom_utils import check_manage
|
||||
|
||||
from ..utils.permissions import is_bot_manage, self_member_info
|
||||
|
||||
|
||||
async def title_get(
|
||||
bot: Bot, ev: GroupMessageEvent, uid: int, sid: int, gid: int, title: str | None
|
||||
):
|
||||
"""头衔申请/删除"""
|
||||
self_info = await self_member_info(bot, gid)
|
||||
if not self_info or self_info["role"] != "owner":
|
||||
await UniMessage.text(
|
||||
"\n嘻嘻嘻,把群转移给我才能用这个功能哦!\n我才不告诉你可以去qun.qq.com里找回群主权限呢!"
|
||||
).send(at_sender=True)
|
||||
return
|
||||
if uid != sid and not await check_manage(bot, ev):
|
||||
await UniMessage.text("只有管理员才可以对别人的头衔进行操作哦~").send(at_sender=True)
|
||||
return
|
||||
try:
|
||||
await bot.set_group_special_title(
|
||||
group_id=gid, user_id=sid, special_title=title, duration=-1
|
||||
)
|
||||
if not title:
|
||||
await UniMessage.at(user_id=str(sid)).text("喜提没有头衔的头衔~").send()
|
||||
else:
|
||||
await (
|
||||
UniMessage.text("已为")
|
||||
.at(user_id=str(sid))
|
||||
.text(f"发放专属头衔“{title}”~")
|
||||
.send()
|
||||
)
|
||||
except Exception as e:
|
||||
await UniMessage.text(f"诶...头衔呢?\n错误代码:{e}").send(at_sender=True)
|
||||
|
||||
|
||||
async def card_edit(
|
||||
bot: Bot, ev: GroupMessageEvent, uid: int, sid: int, gid: int, card_text: str
|
||||
):
|
||||
"""群名片修改"""
|
||||
self_info = await self_member_info(bot, gid)
|
||||
if not is_bot_manage(self_info):
|
||||
await UniMessage.text("\n我日,不给我管理改锤子名片").send(at_sender=True)
|
||||
return
|
||||
if uid != sid and not await check_manage(bot, ev):
|
||||
await UniMessage.text("只有狗管理才能给别人设置名片了啦!").send(at_sender=True)
|
||||
return
|
||||
try:
|
||||
await bot.set_group_card(group_id=gid, user_id=sid, card=card_text)
|
||||
await (
|
||||
UniMessage.text("已经把")
|
||||
.at(user_id=str(sid))
|
||||
.text(f"的群名片修改为“{card_text}”啦~")
|
||||
.send()
|
||||
)
|
||||
except Exception as e:
|
||||
await UniMessage.text(f"修改群名片失败勒...\n错误代码:{e}").send(at_sender=True)
|
||||
|
||||
|
||||
async def group_name(bot: Bot, ev: GroupMessageEvent, gid: int, name_text: str):
|
||||
"""群名修改"""
|
||||
self_info = await self_member_info(bot, gid)
|
||||
if not is_bot_manage(self_info):
|
||||
await UniMessage.text("\n我还没获得管理权限呢...").send(at_sender=True)
|
||||
return
|
||||
if not await check_manage(bot, ev):
|
||||
await UniMessage.text("只有狗管理才能修改群名哦!").send(at_sender=True)
|
||||
return
|
||||
try:
|
||||
await bot.set_group_name(group_id=gid, name=name_text)
|
||||
await UniMessage.text(f"群名已修改为“{name_text}”啦").send()
|
||||
except Exception as e:
|
||||
await UniMessage.text(f"群名修改失败惹...\n错误代码:{e}").send(at_sender=True)
|
||||
@@ -0,0 +1,22 @@
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
from nonebot_plugin_alconna import UniMessage
|
||||
|
||||
|
||||
def local_video(path: str) -> UniMessage:
|
||||
"""构造本地视频消息(覆盖 Media.__post_init__ 的 https 前缀规范化)"""
|
||||
msg = UniMessage.video(url=path)
|
||||
msg[0].url = path
|
||||
return msg
|
||||
|
||||
|
||||
def get_video_info(url: str) -> str:
|
||||
res = subprocess.run(["you-get", "-i", url], capture_output=True, text=True)
|
||||
return res.stdout
|
||||
|
||||
|
||||
def download_video(url: str, filepath: Path, filename: str) -> None:
|
||||
subprocess.run(
|
||||
["you-get", "-o", str(filepath), "-O", filename, url], capture_output=True
|
||||
)
|
||||
Reference in New Issue
Block a user