refactor: restructure plugins per MTSS standard, consolidate assets to res/
Per docs/plugin-audit-report.md (plugins normalized to Trigger(handlers) → Service(services) → Model(repository/models) + utils): - Split monolithic __init__.py into handlers/services/utils across dailywife, deer_pipe, dice, galgame_card, helldivers_tools, huoziyinshua, learning_chat, makeaquote, mc_server_status, ncm_saying, picfinder_take, picstatus, random_jm_code, regif, steam_info, video_analysis, group_tools - Move static assets under res/: deer_pipe font/img, makeaquote font, helldivers img/templates, huoziyinshua HuoZiYinShua - Add config.py + register_config_items to ncm_saying, random_jm_code, group_tools; learning_chat unified config bridge - Remove deprecated: voice_trans plugin, bf_bot/test.py, dead code in dailywife/deer_pipe, empty dirs, debug scripts under helldivers temp - Disable brash_general_supercredits_tools (stub comment only) - bot.py: optional stdout/stderr redirect to log file for Web log viewer, force ANSI colorize on non-TTY sinks - Move runtime data (jm_code.json) out of plugin dir into hexi/data - Docs: plugin-audit-report.md; README reflects removed plugins Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
"""聊天类触发(handlers/chat)。"""
|
||||
|
||||
from . import greet, reaction, voice # noqa: F401
|
||||
+8
-78
@@ -1,21 +1,20 @@
|
||||
import random
|
||||
"""群管理工具 —— 聊天互动(问候/尬聊)。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from nonebot import get_driver, on_command, on_fullmatch, on_keyword, require
|
||||
from nonebot.adapters.onebot.v11 import Bot, MessageEvent
|
||||
from nonebot.rule import to_me
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
from nonebot_plugin_alconna import UniMessage
|
||||
|
||||
from ..constants import BANNED_WORDS, RES_DIR
|
||||
from ..services.moderation import silence
|
||||
from ..utils.media import image_to_base64, random_audio
|
||||
from ...constants import RES_DIR
|
||||
from ...services.moderation import silence
|
||||
from ...utils.media import image_to_base64
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
|
||||
SUPERUSERS = get_driver().config.superusers
|
||||
|
||||
|
||||
# ---------- 基础打招呼 ----------
|
||||
|
||||
say_hello = on_command(
|
||||
"zai?",
|
||||
aliases={"在?", "在?", "在吗", "在么?", "在嘛", "在嘛?"},
|
||||
@@ -29,8 +28,6 @@ async def say_hello_handle(ev: MessageEvent):
|
||||
await UniMessage.text("はい!私はいつも貴方の側にいますよ!").send()
|
||||
|
||||
|
||||
# ---------- 关键词/整句互动 ----------
|
||||
|
||||
say_sorry = on_fullmatch("沙雕机器人")
|
||||
|
||||
|
||||
@@ -95,70 +92,3 @@ nihaole = on_fullmatch("我好了")
|
||||
@nihaole.handle()
|
||||
async def nihaole_handle(bot: Bot, ev: MessageEvent):
|
||||
await UniMessage.text("不许好,憋回去!").send()
|
||||
# await silence(bot, ev, 30)
|
||||
|
||||
|
||||
play_zhanshi = on_keyword({"优质的战士"})
|
||||
|
||||
|
||||
@play_zhanshi.handle()
|
||||
async def play_zhanshi_handle(ev: MessageEvent):
|
||||
base64_str = random_audio(RES_DIR / "record" / "voice" / "youzhizhanshi")
|
||||
if base64_str:
|
||||
await UniMessage.voice(url=base64_str).send()
|
||||
|
||||
|
||||
play_ice = on_fullmatch("溜冰")
|
||||
|
||||
|
||||
@play_ice.handle()
|
||||
async def play_ice_handle(ev: MessageEvent):
|
||||
base64_str = random_audio(RES_DIR / "record" / "voice" / "ice")
|
||||
if base64_str:
|
||||
await UniMessage.voice(url=base64_str).send()
|
||||
|
||||
|
||||
play_dxl = on_fullmatch("罕见")
|
||||
|
||||
|
||||
@play_dxl.handle()
|
||||
async def play_dxl_handle(ev: MessageEvent):
|
||||
base64_str = random_audio(RES_DIR / "record" / "voice" / "dxl")
|
||||
if base64_str:
|
||||
await UniMessage.voice(url=base64_str).send()
|
||||
|
||||
|
||||
chat_queshi = on_keyword({"确实", "有一说一", "u1s1", "yysy"})
|
||||
|
||||
|
||||
@chat_queshi.handle()
|
||||
async def chat_queshi_handle(ev: MessageEvent):
|
||||
if random.random() < 0.05:
|
||||
base64_str = image_to_base64(RES_DIR / "img" / "确实.jpg")
|
||||
if base64_str:
|
||||
await UniMessage.image(url=base64_str).send()
|
||||
|
||||
|
||||
chat_neigui = on_keyword({"内鬼"})
|
||||
|
||||
|
||||
@chat_neigui.handle()
|
||||
async def chat_neigui_handle(ev: MessageEvent):
|
||||
if random.random() < 0.10:
|
||||
base64_str = image_to_base64(RES_DIR / "img" / "内鬼.png")
|
||||
if base64_str:
|
||||
await UniMessage.image(url=base64_str).send()
|
||||
|
||||
|
||||
# ---------- 违禁词黑手语音 ----------
|
||||
|
||||
banned_word_voice = on_command(
|
||||
"ban_word", aliases=set(BANNED_WORDS), rule=to_me(), block=True
|
||||
)
|
||||
|
||||
|
||||
@banned_word_voice.handle()
|
||||
async def banned_word_voice_handle(ev: MessageEvent):
|
||||
base64_str = random_audio(RES_DIR / "record" / "voice" / "heishou")
|
||||
if base64_str:
|
||||
await UniMessage.voice(url=base64_str).send()
|
||||
@@ -0,0 +1,37 @@
|
||||
"""群管理工具 —— 聊天互动(概率表情)。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
|
||||
from nonebot import require
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent
|
||||
from nonebot_plugin_alconna import UniMessage
|
||||
from nonebot import on_keyword
|
||||
|
||||
from ...constants import RES_DIR
|
||||
from ...utils.media import image_to_base64
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
|
||||
|
||||
chat_queshi = on_keyword({"确实", "有一说一", "u1s1", "yysy"})
|
||||
|
||||
|
||||
@chat_queshi.handle()
|
||||
async def chat_queshi_handle(ev: MessageEvent):
|
||||
if random.random() < 0.05:
|
||||
base64_str = image_to_base64(RES_DIR / "img" / "确实.jpg")
|
||||
if base64_str:
|
||||
await UniMessage.image(url=base64_str).send()
|
||||
|
||||
|
||||
chat_neigui = on_keyword({"内鬼"})
|
||||
|
||||
|
||||
@chat_neigui.handle()
|
||||
async def chat_neigui_handle(ev: MessageEvent):
|
||||
if random.random() < 0.10:
|
||||
base64_str = image_to_base64(RES_DIR / "img" / "内鬼.png")
|
||||
if base64_str:
|
||||
await UniMessage.image(url=base64_str).send()
|
||||
@@ -0,0 +1,55 @@
|
||||
"""群管理工具 —— 聊天互动(语音)。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from nonebot import on_command, on_fullmatch, on_keyword, require
|
||||
from nonebot.adapters.onebot.v11 import MessageEvent
|
||||
from nonebot.rule import to_me
|
||||
from nonebot_plugin_alconna import UniMessage
|
||||
|
||||
from ...constants import BANNED_WORDS, RES_DIR
|
||||
from ...utils.media import random_audio
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
|
||||
|
||||
play_zhanshi = on_keyword({"优质的战士"})
|
||||
|
||||
|
||||
@play_zhanshi.handle()
|
||||
async def play_zhanshi_handle(ev: MessageEvent):
|
||||
base64_str = random_audio(RES_DIR / "record" / "voice" / "youzhizhanshi")
|
||||
if base64_str:
|
||||
await UniMessage.voice(url=base64_str).send()
|
||||
|
||||
|
||||
play_ice = on_fullmatch("溜冰")
|
||||
|
||||
|
||||
@play_ice.handle()
|
||||
async def play_ice_handle(ev: MessageEvent):
|
||||
base64_str = random_audio(RES_DIR / "record" / "voice" / "ice")
|
||||
if base64_str:
|
||||
await UniMessage.voice(url=base64_str).send()
|
||||
|
||||
|
||||
play_dxl = on_fullmatch("罕见")
|
||||
|
||||
|
||||
@play_dxl.handle()
|
||||
async def play_dxl_handle(ev: MessageEvent):
|
||||
base64_str = random_audio(RES_DIR / "record" / "voice" / "dxl")
|
||||
if base64_str:
|
||||
await UniMessage.voice(url=base64_str).send()
|
||||
|
||||
|
||||
banned_word_voice = on_command(
|
||||
"ban_word", aliases=set(BANNED_WORDS), rule=to_me(), block=True
|
||||
)
|
||||
|
||||
|
||||
@banned_word_voice.handle()
|
||||
async def banned_word_voice_handle(ev: MessageEvent):
|
||||
base64_str = random_audio(RES_DIR / "record" / "voice" / "heishou")
|
||||
if base64_str:
|
||||
await UniMessage.voice(url=base64_str).send()
|
||||
@@ -1,399 +0,0 @@
|
||||
import asyncio
|
||||
import math
|
||||
import random
|
||||
import re
|
||||
import time
|
||||
|
||||
from nonebot import logger, on_fullmatch, on_message, on_regex, on_startswith, require
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent
|
||||
from nonebot.rule import Rule, is_type
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
from nonebot_plugin_alconna import UniMessage
|
||||
|
||||
from hexi.plugins.nonebot_plugin_hexi_core.custom_utils import check_manage
|
||||
|
||||
from ..constants import IMG_DIR, TEMP_DIR
|
||||
from ..services.moderation import group_silence, member_silence, silence
|
||||
from ..services.profile import card_edit, group_name, title_get
|
||||
from ..services.video import download_video, get_video_info, local_video
|
||||
from ..utils.media import image_to_base64
|
||||
from ..utils.message import get_at_id, has_at_all
|
||||
from ..utils.permissions import check_perm, honor_info, self_member_info
|
||||
from ..utils.text import is_number, parse_seconds, strip_prefix
|
||||
|
||||
|
||||
# ============ 管理员与公告 ============
|
||||
|
||||
set_admin = on_startswith("设置管理员")
|
||||
unset_admin = on_startswith("取消管理员")
|
||||
set_group_notice = on_startswith("设置群公告")
|
||||
|
||||
|
||||
@set_admin.handle()
|
||||
async def set_admin_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
if not await check_perm(bot, ev):
|
||||
return
|
||||
for seg in ev.message:
|
||||
if seg.type == "at" and seg.data.get("qq") != "all":
|
||||
await bot.set_group_admin(
|
||||
group_id=ev.group_id, user_id=int(seg.data["qq"]), enable=True
|
||||
)
|
||||
await UniMessage.text("我好了").send()
|
||||
|
||||
|
||||
@unset_admin.handle()
|
||||
async def unset_admin_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
if not await check_perm(bot, ev):
|
||||
return
|
||||
for seg in ev.message:
|
||||
if seg.type == "at" and seg.data.get("qq") != "all":
|
||||
await bot.set_group_admin(
|
||||
group_id=ev.group_id, user_id=int(seg.data["qq"]), enable=False
|
||||
)
|
||||
await UniMessage.text("我好了").send()
|
||||
|
||||
|
||||
@set_group_notice.handle()
|
||||
async def set_group_notice_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
content = ev.message.extract_plain_text().removeprefix("设置群公告").strip()
|
||||
if not content:
|
||||
return
|
||||
if not await check_perm(bot, ev):
|
||||
return
|
||||
await bot.call_api("_send_group_notice", group_id=ev.group_id, content=content)
|
||||
await UniMessage.text("我好了").send()
|
||||
|
||||
|
||||
# ============ 禁言相关 ============
|
||||
|
||||
|
||||
def _is_ban_cmd(event: GroupMessageEvent) -> bool:
|
||||
"""分钟制禁言命令:"禁言@xxx 5" 表示禁言 5 分钟;排除秒制的 "禁言一下" """
|
||||
text = event.message.extract_plain_text()
|
||||
return text.startswith("禁言") and not text.startswith("禁言一下")
|
||||
|
||||
|
||||
ban_user = on_message(rule=Rule(_is_ban_cmd) & is_type(GroupMessageEvent), block=True)
|
||||
ban_member = on_startswith(("来发口球", "塞口球", "禁言一下"))
|
||||
one_for_one = on_startswith("极限一换一")
|
||||
cancel_ban = on_startswith(("解除口球", "取消口球", "摘口球", "脱口球", "取消禁言", "解除禁言", "解禁"))
|
||||
ban_all = on_fullmatch(("全员口球", "全员禁言"))
|
||||
cancel_ban_all = on_fullmatch(("取消全员口球", "取消全员禁言", "解除全员口球", "解除全员禁言"))
|
||||
|
||||
sleep_8h = on_fullmatch(("睡眠套餐", "休眠套餐", "精致睡眠", "来一份精致睡眠套餐"))
|
||||
tea = on_regex(r"(来|來)(.*(份|个)(.*)(睡|茶)(.*))套餐")
|
||||
|
||||
|
||||
@ban_user.handle()
|
||||
async def ban_user_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
if not await check_perm(bot, ev, silent=True):
|
||||
return
|
||||
msg = ev.message.extract_plain_text().removeprefix("禁言").strip()
|
||||
at_seg = next(
|
||||
(seg for seg in ev.message if seg.type == "at" and seg.data.get("qq") != "all"),
|
||||
None,
|
||||
)
|
||||
if not at_seg:
|
||||
return
|
||||
try:
|
||||
uid = int(at_seg.data["qq"])
|
||||
minutes = 1 if not msg else int(msg)
|
||||
await bot.set_group_ban(
|
||||
group_id=ev.group_id, user_id=uid, duration=minutes * 60
|
||||
)
|
||||
await UniMessage.text("我好了").send()
|
||||
except Exception as ex:
|
||||
logger.error(ex)
|
||||
|
||||
|
||||
@ban_member.handle()
|
||||
async def ban_member_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
uid = ev.user_id
|
||||
gid = ev.group_id
|
||||
duration_text = strip_prefix(
|
||||
ev.message.extract_plain_text(), ("来发口球", "塞口球", "禁言一下")
|
||||
)
|
||||
if not duration_text:
|
||||
duration_text = "30"
|
||||
if has_at_all(ev):
|
||||
await group_silence(bot, ev, gid, True)
|
||||
return
|
||||
sid = get_at_id(ev) or uid
|
||||
await member_silence(bot, ev, uid, sid, gid, duration_text, silent=False)
|
||||
|
||||
|
||||
@one_for_one.handle()
|
||||
async def one_for_one_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
uid = ev.user_id
|
||||
gid = ev.group_id
|
||||
duration_text = strip_prefix(ev.message.extract_plain_text(), ("极限一换一",))
|
||||
if has_at_all(ev):
|
||||
await UniMessage.text("人干事?").send(at_sender=True)
|
||||
await member_silence(bot, ev, uid, uid, gid, "180", silent=False)
|
||||
return
|
||||
seconds = parse_seconds(duration_text)
|
||||
if seconds is None:
|
||||
await UniMessage.text("请输入正确时长~").send(at_sender=True)
|
||||
return
|
||||
if seconds > 30:
|
||||
await UniMessage.text("时长不可大于30秒哟~").send(at_sender=True)
|
||||
return
|
||||
sid = get_at_id(ev) or uid
|
||||
await member_silence(bot, ev, uid, sid, gid, str(seconds), silent=True)
|
||||
await member_silence(bot, ev, uid, uid, gid, str(seconds), silent=True)
|
||||
await (
|
||||
UniMessage.at(user_id=str(uid))
|
||||
.text("成功一换一")
|
||||
.at(user_id=str(sid))
|
||||
.text(f"{seconds}秒~")
|
||||
.send()
|
||||
)
|
||||
|
||||
|
||||
@cancel_ban.handle()
|
||||
async def cancel_ban_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
if not await check_manage(bot, ev):
|
||||
await UniMessage.text("权限不足").send()
|
||||
return
|
||||
uid = ev.user_id
|
||||
gid = ev.group_id
|
||||
if has_at_all(ev):
|
||||
await group_silence(bot, ev, gid, False)
|
||||
return
|
||||
sid = get_at_id(ev)
|
||||
if sid is None:
|
||||
await UniMessage.text("请@需要摘口球的群员哦w").send()
|
||||
return
|
||||
await member_silence(bot, ev, uid, sid, gid, "0", silent=False)
|
||||
|
||||
|
||||
@ban_all.handle()
|
||||
async def ban_all_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
if not await check_manage(bot, ev):
|
||||
await UniMessage.text("权限不足").send()
|
||||
return
|
||||
await group_silence(bot, ev, ev.group_id, True)
|
||||
|
||||
|
||||
@cancel_ban_all.handle()
|
||||
async def cancel_ban_all_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
if not await check_manage(bot, ev):
|
||||
await UniMessage.text("权限不足").send()
|
||||
return
|
||||
await group_silence(bot, ev, ev.group_id, False)
|
||||
|
||||
|
||||
@sleep_8h.handle()
|
||||
async def sleep_8h_handle(bot: Bot, ev: MessageEvent):
|
||||
await silence(bot, ev, 8 * 60 * 60)
|
||||
|
||||
|
||||
@tea.handle()
|
||||
async def tea_handle(bot: Bot, ev: MessageEvent):
|
||||
base = 0 if "午" in ev.plain_text else 5 * 60 * 60
|
||||
length = len(ev.plain_text)
|
||||
sleep_time = base + round(
|
||||
math.sqrt(length) * 60 * 30 + 60 * random.randint(-15, 15)
|
||||
)
|
||||
await silence(bot, ev, sleep_time)
|
||||
|
||||
|
||||
# ============ 头衔 / 名片 / 群名 ============
|
||||
|
||||
special_title = on_startswith("申请头衔")
|
||||
del_special_title = on_fullmatch(("删除头衔", "清除头衔", "收回头衔", "回收头衔"))
|
||||
card_set = on_startswith(("修改名片", "修改群名片", "设置名片", "设置群名片"))
|
||||
set_group_name = on_startswith(("修改群名", "设置群名"))
|
||||
|
||||
|
||||
@special_title.handle()
|
||||
async def special_title_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
uid = ev.user_id
|
||||
gid = ev.group_id
|
||||
title = strip_prefix(ev.message.extract_plain_text(), ("申请头衔",))
|
||||
sid = get_at_id(ev) or uid
|
||||
await title_get(bot, ev, uid, sid, gid, title)
|
||||
|
||||
|
||||
# go-cqhttp似乎暂时不支持收回专属头衔...
|
||||
@del_special_title.handle()
|
||||
async def del_special_title_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
uid = ev.user_id
|
||||
gid = ev.group_id
|
||||
sid = get_at_id(ev) or uid
|
||||
await title_get(bot, ev, uid, sid, gid, None)
|
||||
|
||||
|
||||
@card_set.handle()
|
||||
async def card_set_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
uid = ev.user_id
|
||||
gid = ev.group_id
|
||||
card_text = strip_prefix(
|
||||
ev.message.extract_plain_text(), ("修改名片", "修改群名片", "设置名片", "设置群名片")
|
||||
)
|
||||
sid = get_at_id(ev) or uid
|
||||
await card_edit(bot, ev, uid, sid, gid, card_text)
|
||||
|
||||
|
||||
@set_group_name.handle()
|
||||
async def set_group_name_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
if not await check_manage(bot, ev):
|
||||
await UniMessage.text("权限不足").send()
|
||||
return
|
||||
gid = ev.group_id
|
||||
name_text = strip_prefix(ev.message.extract_plain_text(), ("修改群名", "设置群名"))
|
||||
await group_name(bot, ev, gid, name_text)
|
||||
|
||||
|
||||
# ============ 龙王 ============
|
||||
|
||||
whois_dragon = on_fullmatch(("谁是龙王", "迫害龙王", "龙王是谁"))
|
||||
dragon_list = on_fullmatch(("龙王榜", "龙王排行", "龙王排行榜", "龙王榜单"))
|
||||
|
||||
|
||||
@whois_dragon.handle()
|
||||
async def whois_dragon_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
gid = ev.group_id
|
||||
self_info = await self_member_info(bot, gid)
|
||||
sid = self_info["user_id"]
|
||||
ta_info = await honor_info(bot, gid, "talkative")
|
||||
if not ta_info or not ta_info.get("current_talkative"):
|
||||
await UniMessage.text("本群没有开启龙王标志哦~").send()
|
||||
return
|
||||
dk = ta_info["current_talkative"]["user_id"]
|
||||
if sid == dk:
|
||||
pic = image_to_base64(IMG_DIR / "dk_is_me.jpg")
|
||||
await (
|
||||
UniMessage.text("你们这群丢人玩意,龙王怎么又是我\n")
|
||||
.image(url=pic)
|
||||
.send()
|
||||
)
|
||||
else:
|
||||
action = random.choice(["龙王出来挨透", "龙王出来喷水"])
|
||||
dk_avatar = ta_info["current_talkative"]["avatar"] + "640" + f"&t={dk}"
|
||||
await (
|
||||
UniMessage.at(user_id=str(dk))
|
||||
.text(f"\n{action}\n")
|
||||
.image(url=dk_avatar)
|
||||
.send()
|
||||
)
|
||||
|
||||
|
||||
@dragon_list.handle()
|
||||
async def dragon_list_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
gid = ev.group_id
|
||||
ta_info = await honor_info(bot, gid, "talkative")
|
||||
if not ta_info or not ta_info.get("talkative_list"):
|
||||
await UniMessage.text("本群暂时没有龙王数据哦~").send()
|
||||
return
|
||||
dragon_king_list_info = ta_info["talkative_list"]
|
||||
|
||||
# 处理description和nickname关系
|
||||
dkdir = {}
|
||||
for item in dragon_king_list_info:
|
||||
user_id = item["user_id"]
|
||||
nickname = item["nickname"]
|
||||
description = item["description"]
|
||||
temp = re.findall(r"\d+", description)
|
||||
|
||||
# 累计获得龙王的次数
|
||||
dragon_king_days = int(temp[0])
|
||||
# 连续获得龙王
|
||||
dragon_king_days_continuous = int(temp[1])
|
||||
dkdir[nickname] = {
|
||||
"user_id": user_id,
|
||||
"days_max": dragon_king_days,
|
||||
"days_contin": dragon_king_days_continuous,
|
||||
}
|
||||
# 瞎写的排序
|
||||
dkdir_sorted = sorted(dkdir.items(), key=lambda d: d[1]["days_max"], reverse=True)
|
||||
dkk = dkdir_sorted[0][1]["user_id"]
|
||||
msg = UniMessage.text(f"本群获得龙王次数最多的是:\n{dkdir_sorted[0][0]}\n")
|
||||
dk_avatar = f"http://q1.qlogo.cn/g?b=qq&nk={dkk}&s=5"
|
||||
msg += UniMessage.image(url=dk_avatar)
|
||||
msg += UniMessage.text("\n本群龙王榜\n")
|
||||
for i, it in enumerate(dkdir_sorted[:5]):
|
||||
_nickname = it[0]
|
||||
_days_max = it[1]["days_max"]
|
||||
_days_contin = it[1]["days_contin"]
|
||||
msg += UniMessage.text(
|
||||
f"第{i + 1}名:{_nickname},共{_days_max}次,最长连续{_days_contin}天获得龙王\n"
|
||||
)
|
||||
await msg.send()
|
||||
|
||||
|
||||
# ============ 视频下载 ============
|
||||
|
||||
down_video = on_startswith("/video")
|
||||
|
||||
|
||||
@down_video.handle()
|
||||
async def down_video_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
url = ev.message.extract_plain_text().removeprefix("/video").strip()
|
||||
if not url:
|
||||
return
|
||||
match = re.match(r"https?:/{2}\w.+$", url)
|
||||
if not match:
|
||||
await UniMessage.text("参数不合法").send()
|
||||
return
|
||||
|
||||
timespan = int(time.time())
|
||||
filename = f"{timespan}"
|
||||
file = TEMP_DIR / f"{filename}.mp4"
|
||||
fileabs = str(file)
|
||||
cover = TEMP_DIR / f"{filename}.mp4.jpg"
|
||||
|
||||
TEMP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
info = await asyncio.to_thread(get_video_info, url)
|
||||
match = re.search(r"MPEG-4 video(.*)\s*Size:(.*)MiB", info)
|
||||
if not match:
|
||||
await UniMessage.text("参数不正确").send()
|
||||
return
|
||||
info_type = match.group(1).strip()
|
||||
if info_type != "(video/mp4)":
|
||||
await UniMessage.text("未找到视频信息").send()
|
||||
return
|
||||
info_size = match.group(2).strip()
|
||||
if not is_number(info_size):
|
||||
await UniMessage.text("无法获取视频大小").send()
|
||||
return
|
||||
size = float(info_size)
|
||||
if size >= 6.0:
|
||||
await UniMessage.text("视频体积过大").send()
|
||||
return
|
||||
|
||||
await UniMessage.text("正在发送...").send()
|
||||
await asyncio.to_thread(download_video, url, TEMP_DIR, filename)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
await UniMessage.text("获取视频失败了").send()
|
||||
file.unlink(missing_ok=True)
|
||||
cover.unlink(missing_ok=True)
|
||||
return
|
||||
|
||||
try:
|
||||
await local_video(f"file:///{fileabs}").send()
|
||||
except Exception:
|
||||
await UniMessage.text("发送失败了").send()
|
||||
file.unlink(missing_ok=True)
|
||||
cover.unlink(missing_ok=True)
|
||||
|
||||
|
||||
# ============ 病毒消息拦截 ============
|
||||
|
||||
fuck_xxs = on_message(rule=is_type(GroupMessageEvent), block=False)
|
||||
|
||||
|
||||
@fuck_xxs.handle()
|
||||
async def fuck_xxs_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
for m in ev.message:
|
||||
if m.type == "json" and '"app":"com.tencent.autoreply"' in m.data.get(
|
||||
"data", ""
|
||||
):
|
||||
await bot.delete_msg(message_id=ev.message_id)
|
||||
await UniMessage.text(
|
||||
"这是onse病毒码,会获取到你手机的xxs,然后发起攻击...以下省略6行需要全文背诵的金句"
|
||||
).send()
|
||||
return
|
||||
@@ -0,0 +1,3 @@
|
||||
"""管理类触发(handlers/management)。"""
|
||||
|
||||
from . import admin, antivirus, ban, dragon, title, video # noqa: F401
|
||||
@@ -0,0 +1,50 @@
|
||||
"""群管理工具 —— 管理员与公告。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from nonebot import on_startswith, require
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent
|
||||
from nonebot_plugin_alconna import UniMessage
|
||||
|
||||
from ...utils.permissions import check_perm
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
|
||||
set_admin = on_startswith("设置管理员")
|
||||
unset_admin = on_startswith("取消管理员")
|
||||
set_group_notice = on_startswith("设置群公告")
|
||||
|
||||
|
||||
@set_admin.handle()
|
||||
async def set_admin_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
if not await check_perm(bot, ev):
|
||||
return
|
||||
for seg in ev.message:
|
||||
if seg.type == "at" and seg.data.get("qq") != "all":
|
||||
await bot.set_group_admin(
|
||||
group_id=ev.group_id, user_id=int(seg.data["qq"]), enable=True
|
||||
)
|
||||
await UniMessage.text("我好了").send()
|
||||
|
||||
|
||||
@unset_admin.handle()
|
||||
async def unset_admin_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
if not await check_perm(bot, ev):
|
||||
return
|
||||
for seg in ev.message:
|
||||
if seg.type == "at" and seg.data.get("qq") != "all":
|
||||
await bot.set_group_admin(
|
||||
group_id=ev.group_id, user_id=int(seg.data["qq"]), enable=False
|
||||
)
|
||||
await UniMessage.text("我好了").send()
|
||||
|
||||
|
||||
@set_group_notice.handle()
|
||||
async def set_group_notice_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
content = ev.message.extract_plain_text().removeprefix("设置群公告").strip()
|
||||
if not content:
|
||||
return
|
||||
if not await check_perm(bot, ev):
|
||||
return
|
||||
await bot.call_api("_send_group_notice", group_id=ev.group_id, content=content)
|
||||
await UniMessage.text("我好了").send()
|
||||
@@ -0,0 +1,25 @@
|
||||
"""群管理工具 —— 病毒消息拦截。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from nonebot import on_message, require
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent
|
||||
from nonebot.rule import is_type
|
||||
from nonebot_plugin_alconna import UniMessage
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
|
||||
fuck_xxs = on_message(rule=is_type(GroupMessageEvent), block=False)
|
||||
|
||||
|
||||
@fuck_xxs.handle()
|
||||
async def fuck_xxs_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
for m in ev.message:
|
||||
if m.type == "json" and '"app":"com.tencent.autoreply"' in m.data.get(
|
||||
"data", ""
|
||||
):
|
||||
await bot.delete_msg(message_id=ev.message_id)
|
||||
await UniMessage.text(
|
||||
"这是onse病毒码,会获取到你手机的xxs,然后发起攻击...以下省略6行需要全文背诵的金句"
|
||||
).send()
|
||||
return
|
||||
@@ -0,0 +1,145 @@
|
||||
"""群管理工具 —— 禁言相关。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
import random
|
||||
|
||||
from nonebot import logger, on_fullmatch, on_message, on_regex, on_startswith, require
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent
|
||||
from nonebot.rule import Rule, is_type
|
||||
from nonebot_plugin_alconna import UniMessage
|
||||
|
||||
from hexi.plugins.nonebot_plugin_hexi_core.custom_utils import check_manage
|
||||
|
||||
from ...services.moderation import group_silence, member_silence, silence
|
||||
from ...utils.message import get_at_id, has_at_all
|
||||
from ...utils.permissions import check_perm
|
||||
from ...utils.text import parse_seconds, strip_prefix
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
|
||||
|
||||
def _is_ban_cmd(event: GroupMessageEvent) -> bool:
|
||||
text = event.message.extract_plain_text()
|
||||
return text.startswith("禁言") and not text.startswith("禁言一下")
|
||||
|
||||
|
||||
ban_user = on_message(rule=Rule(_is_ban_cmd) & is_type(GroupMessageEvent), block=True)
|
||||
ban_member = on_startswith(("来发口球", "塞口球", "禁言一下"))
|
||||
one_for_one = on_startswith("极限一换一")
|
||||
cancel_ban = on_startswith(("解除口球", "取消口球", "摘口球", "脱口球", "取消禁言", "解除禁言", "解禁"))
|
||||
ban_all = on_fullmatch(("全员口球", "全员禁言"))
|
||||
cancel_ban_all = on_fullmatch(("取消全员口球", "取消全员禁言", "解除全员口球", "解除全员禁言"))
|
||||
sleep_8h = on_fullmatch(("睡眠套餐", "休眠套餐", "精致睡眠", "来一份精致睡眠套餐"))
|
||||
tea = on_regex(r"(来|來)(.*(份|个)(.*)(睡|茶)(.*))套餐")
|
||||
|
||||
|
||||
@ban_user.handle()
|
||||
async def ban_user_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
if not await check_perm(bot, ev, silent=True):
|
||||
return
|
||||
msg = ev.message.extract_plain_text().removeprefix("禁言").strip()
|
||||
at_seg = next(
|
||||
(seg for seg in ev.message if seg.type == "at" and seg.data.get("qq") != "all"),
|
||||
None,
|
||||
)
|
||||
if not at_seg:
|
||||
return
|
||||
try:
|
||||
uid = int(at_seg.data["qq"])
|
||||
minutes = 1 if not msg else int(msg)
|
||||
await bot.set_group_ban(group_id=ev.group_id, user_id=uid, duration=minutes * 60)
|
||||
await UniMessage.text("我好了").send()
|
||||
except Exception as ex:
|
||||
logger.error(ex)
|
||||
|
||||
|
||||
@ban_member.handle()
|
||||
async def ban_member_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
uid = ev.user_id
|
||||
gid = ev.group_id
|
||||
duration_text = strip_prefix(
|
||||
ev.message.extract_plain_text(), ("来发口球", "塞口球", "禁言一下")
|
||||
)
|
||||
if not duration_text:
|
||||
duration_text = "30"
|
||||
if has_at_all(ev):
|
||||
await group_silence(bot, ev, gid, True)
|
||||
return
|
||||
sid = get_at_id(ev) or uid
|
||||
await member_silence(bot, ev, uid, sid, gid, duration_text, silent=False)
|
||||
|
||||
|
||||
@one_for_one.handle()
|
||||
async def one_for_one_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
uid = ev.user_id
|
||||
gid = ev.group_id
|
||||
duration_text = strip_prefix(ev.message.extract_plain_text(), ("极限一换一",))
|
||||
if has_at_all(ev):
|
||||
await UniMessage.text("人干事?").send(at_sender=True)
|
||||
await member_silence(bot, ev, uid, uid, gid, "180", silent=False)
|
||||
return
|
||||
seconds = parse_seconds(duration_text)
|
||||
if seconds is None:
|
||||
await UniMessage.text("请输入正确时长~").send(at_sender=True)
|
||||
return
|
||||
if seconds > 30:
|
||||
await UniMessage.text("时长不可大于30秒哟~").send(at_sender=True)
|
||||
return
|
||||
sid = get_at_id(ev) or uid
|
||||
await member_silence(bot, ev, uid, sid, gid, str(seconds), silent=True)
|
||||
await member_silence(bot, ev, uid, uid, gid, str(seconds), silent=True)
|
||||
await (
|
||||
UniMessage.at(user_id=str(uid))
|
||||
.text("成功一换一")
|
||||
.at(user_id=str(sid))
|
||||
.text(f"{seconds}秒~")
|
||||
.send()
|
||||
)
|
||||
|
||||
|
||||
@cancel_ban.handle()
|
||||
async def cancel_ban_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
if not await check_manage(bot, ev):
|
||||
await UniMessage.text("权限不足").send()
|
||||
return
|
||||
uid = ev.user_id
|
||||
gid = ev.group_id
|
||||
if has_at_all(ev):
|
||||
await group_silence(bot, ev, gid, False)
|
||||
return
|
||||
sid = get_at_id(ev)
|
||||
if sid is None:
|
||||
await UniMessage.text("请@需要摘口球的群员哦w").send()
|
||||
return
|
||||
await member_silence(bot, ev, uid, sid, gid, "0", silent=False)
|
||||
|
||||
|
||||
@ban_all.handle()
|
||||
async def ban_all_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
if not await check_manage(bot, ev):
|
||||
await UniMessage.text("权限不足").send()
|
||||
return
|
||||
await group_silence(bot, ev, ev.group_id, True)
|
||||
|
||||
|
||||
@cancel_ban_all.handle()
|
||||
async def cancel_ban_all_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
if not await check_manage(bot, ev):
|
||||
await UniMessage.text("权限不足").send()
|
||||
return
|
||||
await group_silence(bot, ev, ev.group_id, False)
|
||||
|
||||
|
||||
@sleep_8h.handle()
|
||||
async def sleep_8h_handle(bot: Bot, ev: MessageEvent):
|
||||
await silence(bot, ev, 8 * 60 * 60)
|
||||
|
||||
|
||||
@tea.handle()
|
||||
async def tea_handle(bot: Bot, ev: MessageEvent):
|
||||
base = 0 if "午" in ev.plain_text else 5 * 60 * 60
|
||||
length = len(ev.plain_text)
|
||||
sleep_time = base + round(math.sqrt(length) * 60 * 30 + 60 * random.randint(-15, 15))
|
||||
await silence(bot, ev, sleep_time)
|
||||
@@ -0,0 +1,84 @@
|
||||
"""群管理工具 —— 龙王。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
import re
|
||||
|
||||
from nonebot import on_fullmatch, require
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent
|
||||
from nonebot_plugin_alconna import UniMessage
|
||||
|
||||
from ...constants import IMG_DIR
|
||||
from ...utils.media import image_to_base64
|
||||
from ...utils.permissions import honor_info, self_member_info
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
|
||||
whois_dragon = on_fullmatch(("谁是龙王", "迫害龙王", "龙王是谁"))
|
||||
dragon_list = on_fullmatch(("龙王榜", "龙王排行", "龙王排行榜", "龙王榜单"))
|
||||
|
||||
|
||||
@whois_dragon.handle()
|
||||
async def whois_dragon_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
gid = ev.group_id
|
||||
self_info = await self_member_info(bot, gid)
|
||||
sid = self_info["user_id"]
|
||||
ta_info = await honor_info(bot, gid, "talkative")
|
||||
if not ta_info or not ta_info.get("current_talkative"):
|
||||
await UniMessage.text("本群没有开启龙王标志哦~").send()
|
||||
return
|
||||
dk = ta_info["current_talkative"]["user_id"]
|
||||
if sid == dk:
|
||||
pic = image_to_base64(IMG_DIR / "dk_is_me.jpg")
|
||||
await (
|
||||
UniMessage.text("你们这群丢人玩意,龙王怎么又是我\n")
|
||||
.image(url=pic)
|
||||
.send()
|
||||
)
|
||||
else:
|
||||
action = random.choice(["龙王出来挨透", "龙王出来喷水"])
|
||||
dk_avatar = ta_info["current_talkative"]["avatar"] + "640" + f"&t={dk}"
|
||||
await (
|
||||
UniMessage.at(user_id=str(dk))
|
||||
.text(f"\n{action}\n")
|
||||
.image(url=dk_avatar)
|
||||
.send()
|
||||
)
|
||||
|
||||
|
||||
@dragon_list.handle()
|
||||
async def dragon_list_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
gid = ev.group_id
|
||||
ta_info = await honor_info(bot, gid, "talkative")
|
||||
if not ta_info or not ta_info.get("talkative_list"):
|
||||
await UniMessage.text("本群暂时没有龙王数据哦~").send()
|
||||
return
|
||||
dragon_king_list_info = ta_info["talkative_list"]
|
||||
dkdir = {}
|
||||
for item in dragon_king_list_info:
|
||||
user_id = item["user_id"]
|
||||
nickname = item["nickname"]
|
||||
description = item["description"]
|
||||
temp = re.findall(r"\d+", description)
|
||||
dragon_king_days = int(temp[0])
|
||||
dragon_king_days_continuous = int(temp[1])
|
||||
dkdir[nickname] = {
|
||||
"user_id": user_id,
|
||||
"days_max": dragon_king_days,
|
||||
"days_contin": dragon_king_days_continuous,
|
||||
}
|
||||
dkdir_sorted = sorted(dkdir.items(), key=lambda d: d[1]["days_max"], reverse=True)
|
||||
dkk = dkdir_sorted[0][1]["user_id"]
|
||||
msg = UniMessage.text(f"本群获得龙王次数最多的是:\n{dkdir_sorted[0][0]}\n")
|
||||
dk_avatar = f"http://q1.qlogo.cn/g?b=qq&nk={dkk}&s=5"
|
||||
msg += UniMessage.image(url=dk_avatar)
|
||||
msg += UniMessage.text("\n本群龙王榜\n")
|
||||
for i, it in enumerate(dkdir_sorted[:5]):
|
||||
_nickname = it[0]
|
||||
_days_max = it[1]["days_max"]
|
||||
_days_contin = it[1]["days_contin"]
|
||||
msg += UniMessage.text(
|
||||
f"第{i + 1}名:{_nickname},共{_days_max}次,最长连续{_days_contin}天获得龙王\n"
|
||||
)
|
||||
await msg.send()
|
||||
@@ -0,0 +1,58 @@
|
||||
"""群管理工具 —— 头衔 / 名片 / 群名。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from nonebot import on_fullmatch, on_startswith, require
|
||||
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 ...services.profile import card_edit, group_name, title_get
|
||||
from ...utils.message import get_at_id
|
||||
from ...utils.text import strip_prefix
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
|
||||
special_title = on_startswith("申请头衔")
|
||||
del_special_title = on_fullmatch(("删除头衔", "清除头衔", "收回头衔", "回收头衔"))
|
||||
card_set = on_startswith(("修改名片", "修改群名片", "设置名片", "设置群名片"))
|
||||
set_group_name = on_startswith(("修改群名", "设置群名"))
|
||||
|
||||
|
||||
@special_title.handle()
|
||||
async def special_title_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
uid = ev.user_id
|
||||
gid = ev.group_id
|
||||
title = strip_prefix(ev.message.extract_plain_text(), ("申请头衔",))
|
||||
sid = get_at_id(ev) or uid
|
||||
await title_get(bot, ev, uid, sid, gid, title)
|
||||
|
||||
|
||||
@del_special_title.handle()
|
||||
async def del_special_title_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
uid = ev.user_id
|
||||
gid = ev.group_id
|
||||
sid = get_at_id(ev) or uid
|
||||
await title_get(bot, ev, uid, sid, gid, None)
|
||||
|
||||
|
||||
@card_set.handle()
|
||||
async def card_set_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
uid = ev.user_id
|
||||
gid = ev.group_id
|
||||
card_text = strip_prefix(
|
||||
ev.message.extract_plain_text(), ("修改名片", "修改群名片", "设置名片", "设置群名片")
|
||||
)
|
||||
sid = get_at_id(ev) or uid
|
||||
await card_edit(bot, ev, uid, sid, gid, card_text)
|
||||
|
||||
|
||||
@set_group_name.handle()
|
||||
async def set_group_name_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
if not await check_manage(bot, ev):
|
||||
await UniMessage.text("权限不足").send()
|
||||
return
|
||||
gid = ev.group_id
|
||||
name_text = strip_prefix(ev.message.extract_plain_text(), ("修改群名", "设置群名"))
|
||||
await group_name(bot, ev, gid, name_text)
|
||||
@@ -0,0 +1,71 @@
|
||||
"""群管理工具 —— 视频下载。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import re
|
||||
import time
|
||||
|
||||
from nonebot import logger, on_startswith, require
|
||||
from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent
|
||||
from nonebot_plugin_alconna import UniMessage
|
||||
|
||||
from ...constants import TEMP_DIR
|
||||
from ...services.video import download_video, get_video_info, local_video
|
||||
from ...utils.text import is_number
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
|
||||
down_video = on_startswith("/video")
|
||||
|
||||
|
||||
@down_video.handle()
|
||||
async def down_video_handle(bot: Bot, ev: GroupMessageEvent):
|
||||
url = ev.message.extract_plain_text().removeprefix("/video").strip()
|
||||
if not url:
|
||||
return
|
||||
match = re.match(r"https?:/{2}w.+$", url)
|
||||
if not match:
|
||||
await UniMessage.text("参数不合法").send()
|
||||
return
|
||||
|
||||
timespan = int(time.time())
|
||||
filename = f"{timespan}"
|
||||
file = TEMP_DIR / f"{filename}.mp4"
|
||||
fileabs = str(file)
|
||||
cover = TEMP_DIR / f"{filename}.mp4.jpg"
|
||||
|
||||
TEMP_DIR.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
info = await asyncio.to_thread(get_video_info, url)
|
||||
match = re.search(r"MPEG-4 video(.*)s*Size:(.*)MiB", info)
|
||||
if not match:
|
||||
await UniMessage.text("参数不正确").send()
|
||||
return
|
||||
info_type = match.group(1).strip()
|
||||
if info_type != "(video/mp4)":
|
||||
await UniMessage.text("未找到视频信息").send()
|
||||
return
|
||||
info_size = match.group(2).strip()
|
||||
if not is_number(info_size):
|
||||
await UniMessage.text("无法获取视频大小").send()
|
||||
return
|
||||
size = float(info_size)
|
||||
if size >= 6.0:
|
||||
await UniMessage.text("视频体积过大").send()
|
||||
return
|
||||
await UniMessage.text("正在发送...").send()
|
||||
await asyncio.to_thread(download_video, url, TEMP_DIR, filename)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
await UniMessage.text("获取视频失败了").send()
|
||||
file.unlink(missing_ok=True)
|
||||
cover.unlink(missing_ok=True)
|
||||
return
|
||||
|
||||
try:
|
||||
await local_video(f"file:///{fileabs}").send()
|
||||
except Exception:
|
||||
await UniMessage.text("发送失败了").send()
|
||||
file.unlink(missing_ok=True)
|
||||
cover.unlink(missing_ok=True)
|
||||
Reference in New Issue
Block a user