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