diff --git a/plugins/aconfig/__init__.py b/plugins/aconfig/__init__.py new file mode 100644 index 00000000..a3f2d2f0 --- /dev/null +++ b/plugins/aconfig/__init__.py @@ -0,0 +1,71 @@ +import random +from nonebot import on_keyword +import os +from util.init_result import image +from configs.path_config import IMAGE_PATH +from nonebot import on_command +from nonebot.rule import to_me +from nonebot.typing import T_State +from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent +from nonebot.adapters.cqhttp.permission import GROUP +from util.utils import FreqLimiter + + +__plugin_name__ = '基本设置 [Hidden]' +__plugin_usage__ = '用法: 基本' + + +_flmt = FreqLimiter(300) + + +config_playgame = on_keyword({'打游戏'}, permission=GROUP, priority=1, block=True) + + +@config_playgame.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + if not _flmt.check(event.group_id): + return + _flmt.start_cd(event.group_id) + await config_playgame.finish(image( + random.choice(os.listdir(IMAGE_PATH + "dayouxi/") + ), "dayouxi")) + + +self_introduction = on_command("自我介绍", aliases={'介绍', '你是谁', '你叫什么'}, + rule=to_me(), priority=5, block=True) + + +@self_introduction.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State): + result = "我叫绪山真寻\n" \ + "你们可以叫我真寻,小真寻,哪怕你们叫我小寻子我也能接受!\n" \ + "年龄的话我还是个**岁初中生(至少现在是)\n" \ + "身高保密!!!(也就比美波里(姐姐..(妹妹))矮一点)\n" \ + "我生日是在3月6号, 能记住的话我会很高兴的\n现在是自宅警备系的现役JC\n" \ + "最好的朋友是椛!\n"\ + + image("zhenxun") + await self_introduction.finish(result) + +laopo = on_keyword({'老婆'}, rule=to_me(), priority=5, block=True) + + +@laopo.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State): + await laopo.finish(image('laopo.jpg', 'other')) + + +# config_robot = on_keyword({"机器人"}, permission=GROUP, priority=5, block=True) +# @config_robot.handle() +# async def _(bot: Bot, event: Event, state: T_State): +# if not _flmt.check(event.group_id) or event.group_id == 774261838: +# return +# _flmt.start_cd(event.group_id) +# await config_robot.send("小真寻才不是机器人!") +# result = "我叫绪山真寻\n" \ +# "你们可以叫我真寻,小真寻,哪怕你们叫我小寻子我也能接受!\n" \ +# "年龄的话我还是个**岁初中生(至少现在是)\n" \ +# "身高保密!!!(也就比美波里(姐姐..(妹妹))矮一点)\n" \ +# "我生日是在3月6号, 能记住的话我会很高兴的\n现在是自宅警备系的现役JC\n" \ +# "最好的朋友是椛!\n"\ +# + image("zhenxun", "") +# await config_jieshao.finish(result) diff --git a/plugins/admin_bot_manage/__init__.py b/plugins/admin_bot_manage/__init__.py new file mode 100644 index 00000000..47cf97f4 --- /dev/null +++ b/plugins/admin_bot_manage/__init__.py @@ -0,0 +1,88 @@ +from nonebot import on_command +from util.utils import get_message_text, get_message_imgs, scheduler, get_bot +from nonebot.typing import T_State +from nonebot.adapters.cqhttp import Bot, GroupMessageEvent +from .data_source import set_group_status, custom_group_welcome, change_group_switch, \ + update_member_info, group_current_status +from nonebot.adapters.cqhttp.permission import GROUP +from services.log import logger +from configs.config import plugins2name_dict +from nonebot.plugin import export + +__plugin_usage__ = '''自定义进群欢迎消息: + 自定义进群欢迎消息 xxxx(图片) + 示例:自定义进群欢迎消息 欢迎新人!(后面可以跟一张图片噢)''' + +export = export() +export.update_member_info = update_member_info + +cmds = [] +for cmd_list in plugins2name_dict.values(): + for cmd in cmd_list: + cmds.append(f'开启{cmd}') + cmds.append(f'关闭{cmd}') +cmds = set(cmds) + +group_status = on_command('oc_reminds', aliases={'开启早晚安', '关闭早晚安', + '开启进群欢迎', '关闭进群欢迎', + '开启每日开箱重置提醒', '关闭每日开箱重置提醒', + '开启b站转发解析', '关闭b站转发解析', + '开启epic通知', '关闭epic通知', + '开启丢人爬', '关闭丢人爬', + '开启原神黄历提醒', '关闭原神黄历提醒', + '开启全部通知', '开启所有通知', '关闭全部通知', '关闭所有通知', + '群通知状态'}, permission=GROUP, priority=4, block=True) + +switch_rule = on_command('switch_rule', aliases=cmds, permission=GROUP, priority=4, block=True) +custom_welcome = on_command('自定义进群欢迎消息', aliases={'自定义欢迎消息', '自定义群欢迎消息'}, permission=GROUP, priority=5, block=True) +refresh_member_group = on_command("更新群组成员列表", aliases={"更新群组成员信息"}, permission=GROUP, priority=5, block=True) + + +@switch_rule.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + await switch_rule.send(await change_group_switch(state["_prefix"]["raw_command"].strip(), event.group_id)) + logger.info(f'USER {event.user_id} GROUP {event.group_id} 使用群功能管理命令 {state["_prefix"]["raw_command"]}') + + +@group_status.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + if state["_prefix"]["raw_command"] in ['群通知状态']: + await group_status.finish(await group_current_status(event.group_id)) + await group_status.send(await set_group_status(state["_prefix"]["raw_command"], event.group_id), + at_sender=True) + logger.info(f'USER {event.user_id} GROUP {event.group_id} 使用群通知管理命令 {state["_prefix"]["raw_command"]}') + + +@custom_welcome.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + if str(event.get_message()) in ['帮助'] or str(event.get_message()) == '': + await custom_welcome.finish(__plugin_usage__) + msg = get_message_text(event.json()) + imgs = get_message_imgs(event.json()) + await custom_welcome.finish(await custom_group_welcome(msg, imgs, event.user_id, event.group_id), at_sender=True) + + +@refresh_member_group.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + if await update_member_info(event.group_id): + await refresh_member_group.finish("更新群员信息成功!", at_sender=True) + else: + await refresh_member_group.finish("更新群员信息失败!", at_sender=True) + + +# 自动更新群员信息 +@scheduler.scheduled_job( + 'cron', + hour=2, + minute=1, +) +async def _(): + bot = get_bot() + gl = await bot.get_group_list(self_id=bot.self_id) + gl = [g['group_id'] for g in gl] + for g in gl: + try: + await update_member_info(g) + logger.info(f'更新群组 g:{g} 成功') + except Exception as e: + logger.error(f'更新群组错误 g:{g} e:{e}') diff --git a/plugins/admin_bot_manage/data_source.py b/plugins/admin_bot_manage/data_source.py new file mode 100644 index 00000000..e91a5908 --- /dev/null +++ b/plugins/admin_bot_manage/data_source.py @@ -0,0 +1,210 @@ +from models.group_remind import GroupRemind +from services.log import logger +from configs.path_config import DATA_PATH +import os +import aiofiles +import aiohttp +from util.init_result import image +from util.utils import get_local_proxy, get_bot +from pathlib import Path +from nonebot import require +from configs.config import plugins2name_dict +from models.group_member_info import GroupInfoUser +import time +from datetime import datetime +from services.db_context import db +from models.level_user import LevelUser +from configs.config import ADMIN_DEFAULT_AUTH +try: + import ujson as json +except ModuleNotFoundError: + import json + + +export = require("nonebot_plugin_manager") + + +command_dict = { + '早晚安': 'zwa', + '进群欢迎': 'hy', + '每日开箱重置提醒': 'kxcz', + 'b站转发解析': 'blpar', + 'epic': 'epic', + '丢人爬': 'pa', + '原神黄历提醒': 'almanac', +} +command_list = list(command_dict.values()) +command_info_dt = { + '早晚安': '将会在每晚11:59晚安,在6:01早安哦', + '每日开箱重置提醒': '将会在每日00:01提示开箱重置!', + 'epic': '将会在每日中午12:01发送可白嫖的epic游戏', + '原神黄历提醒': '将会在每日8:00发送当日的原神黄历', +} + + +async def remind_status(group: int, name: str, flag: bool) -> str: + _name = '' + if name in command_dict.values(): + _name = list(command_dict.keys())[list(command_dict.values()).index(name)] + if flag: + rst = '开启' + if await GroupRemind.get_status(group, name): + return f'该群已经{rst}过 {_name},请勿重复开启!' + else: + rst = '关闭' + if not await GroupRemind.get_status(group, name): + return f'该群已经{rst}过 {_name},请勿重复开启!' + if await GroupRemind.set_status(group, name, flag): + info = command_info_dt[_name] if command_info_dt.get(_name) else '' + if info: + info = '\n' + info + return f'成功{rst} {_name}!0v0 {info}' + else: + return f'{rst} {_name} 失败了...' + + +async def set_group_status(name: str, group_id: int): + flag = None + if name[:2] == '开启': + flag = True + elif name[:2] == '关闭': + flag = False + cmd = name[2:] + if cmd in ['全部通知', '所有通知']: + for command in command_list: + await remind_status(group_id, command, flag) + return f'已{name[:2]}所有通知!' + return await remind_status(group_id, command_dict[cmd], flag) + + +async def group_current_status(group_id: int): + result = f'(被动技能)\n早晚安通知:{"√" if await GroupRemind.get_status(group_id, "zwa") else "×"}\n' \ + f'进群欢迎:{"√" if await GroupRemind.get_status(group_id, "hy") else "×"}\n' \ + f'每日开箱重置通知:{"√" if await GroupRemind.get_status(group_id, "kxcz") else "×"}\n' \ + f'b站转发解析:{"√" if await GroupRemind.get_status(group_id, "blpar") else "×"}\n' \ + f'丢人爬:{"√" if await GroupRemind.get_status(group_id, "pa") else "×"}\n' \ + f'epic免费游戏:{"√" if await GroupRemind.get_status(group_id, "epic") else "×"}\n' \ + f'原神黄历提醒:{"√" if await GroupRemind.get_status(group_id, "almanac") else "×"}' + return result + + +custom_welcome_msg_json = Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json" + + +async def custom_group_welcome(msg, imgs, user_id, group_id): + img_result = '' + img = imgs[0] if imgs else '' + result = '' + if os.path.exists(DATA_PATH + f'custom_welcome_msg/{group_id}.jpg'): + os.remove(DATA_PATH + f'custom_welcome_msg/{group_id}.jpg') + # print(custom_welcome_msg_json) + if not custom_welcome_msg_json.exists(): + custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True) + data = {} + else: + try: + data = json.load(open(custom_welcome_msg_json, 'r')) + except FileNotFoundError: + data = {} + try: + if msg: + data[str(group_id)] = str(msg) + json.dump(data, open(custom_welcome_msg_json, 'w'), indent=4, ensure_ascii=False) + logger.info(f'USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}') + result += msg + if img: + async with aiohttp.ClientSession() as session: + async with session.get(img, proxy=get_local_proxy()) as response: + async with aiofiles.open(DATA_PATH + f'custom_welcome_msg/{group_id}.jpg', 'wb') as f: + await f.write(await response.read()) + img_result = image(abspath=DATA_PATH + f'custom_welcome_msg/{group_id}.jpg') + logger.info(f'USER {user_id} GROUP {group_id} 更换群欢迎消息图片') + except Exception as e: + logger.error(f'GROUP {group_id} 替换群消息失败 e:{e}') + return '替换群消息失败..' + return f'替换群欢迎消息成功:\n{result}' + img_result + + +async def change_group_switch(cmd: str, group_id: int): + group_id = str(group_id) + status = cmd[:2] + cmd = cmd[2:] + try: + with open(DATA_PATH + 'manager/plugin_list.json', 'r', encoding='utf8') as f: + plugin_list = json.load(f) + except ValueError: + pass + except FileNotFoundError: + pass + for plugin_cmd in plugins2name_dict.keys(): + if cmd in plugins2name_dict[plugin_cmd]: + # print(plugin_list[plugin_cmd]) + if status == '开启': + # if group_id in plugin_list[plugin_cmd]: + if group_id not in plugin_list[plugin_cmd] or plugin_list[plugin_cmd][group_id]: + return f'功能 {cmd} 正处于开启状态!不要重复开启.' + export.unblock_plugin(group_id, plugin_cmd) + else: + if group_id in plugin_list[plugin_cmd]: + if not plugin_list[plugin_cmd][group_id]: + return f'功能 {cmd} 正处于关闭状态!不要重复关闭.' + export.block_plugin(group_id, plugin_cmd) + if os.path.exists(DATA_PATH + f'group_help/{group_id}.png'): + os.remove(DATA_PATH + f'group_help/{group_id}.png') + + return f'{status} {cmd} 功能!' + return f'没有找到 {cmd} 功能喔' + + +async def update_member_info(group_id: int) -> bool: + bot = get_bot() + _group_user_list = await bot.get_group_member_list(group_id=group_id) + _error_member_list = [] + _exist_member_list = [] + # try: + for user_info in _group_user_list: + if user_info['card'] == "": + nickname = user_info['nickname'] + else: + nickname = user_info['card'] + async with db.transaction(): + # 更新权限 + if user_info['role'] in ['owner', 'admin'] and not await LevelUser.is_group_flag(user_info['user_id'], group_id): + await LevelUser.set_level(user_info['user_id'], user_info['group_id'], 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) + user = await GroupInfoUser.select_member_info(user_info['user_id'], user_info['group_id']) + if user: + if user.user_name != nickname: + await user.update(user_name=nickname).apply() + logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新群昵称成功") + _exist_member_list.append(int(user_info['user_id'])) + continue + join_time = datetime.strptime( + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(user_info['join_time'])), "%Y-%m-%d %H:%M:%S") + if await GroupInfoUser.insert( + user_info['user_id'], + user_info['group_id'], + nickname, + join_time,): + _exist_member_list.append(int(user_info['user_id'])) + logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功") + else: + _error_member_list.append(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败\n") + _del_member_list = list(set(_exist_member_list).difference(set(await GroupInfoUser.query_group_member_list(group_id)))) + if _del_member_list: + for del_user in _del_member_list: + if await GroupInfoUser.delete_member_info(del_user, group_id): + logger.info(f"退群用户{del_user} 所属{group_id} 已删除") + else: + logger.info(f"退群用户{del_user} 所属{group_id} 删除失败") + if _error_member_list: + result = "" + for error_user in _error_member_list: + result += error_user + await bot.send_private_msg(user_id=int(list(bot.config.superusers)[0]), message=result[:-1]) + return True + + + + diff --git a/plugins/admin_help/__init__.py b/plugins/admin_help/__init__.py new file mode 100644 index 00000000..9425fd46 --- /dev/null +++ b/plugins/admin_help/__init__.py @@ -0,0 +1,46 @@ +from nonebot import on_command +from nonebot.typing import T_State +from nonebot.adapters import Bot +from nonebot.adapters.cqhttp import GroupMessageEvent +from util.img_utils import CreateImg +from configs.path_config import IMAGE_PATH +from util.init_result import image + + +__plugin_name__ = '管理帮助 [Hidden]' +__plugin_usage__ = '''管理帮助(权限等级): + 1.更新群组成员列表(1) + 2.功能开关 --> 指令:开启/关闭xx功能(2) + 3.查看群被动技能 --> 指令:群通知状态(2) + 4.自定义群欢迎 --> 指令:自定义进群欢迎消息(2) + 5.将用户拉入真寻黑名单 --> .ban/.unban(5) + 6.刷屏禁言相关 --> 指令:刷屏检测设置/设置检测时间 + \t\t/设置检测次数/设置禁言时长(5) + 7.上传图片(6) + 8.移动图片(7) + 9.删除图片(7) +对我说 “指令名 帮助” 获取对应详细帮助 +群主与管理员默认 5 级权限 +''' + +passive_help = '''【被动技能开关(2): + 开启/关闭进群欢迎 + 开启/关闭每日开箱重置提醒 + 开启/关闭b站转发解析 + 开启/关闭丢人爬 + 开启/关闭epic通知 + 开启/关闭全部通知 + 开启/关闭原神黄历提醒】 +''' + +admin_help = on_command("管理员帮助", aliases={"管理帮助"}, priority=5, block=True) + +admin_help_img = CreateImg(1000, 600, font_size=24) +admin_help_img.text((10, 10), __plugin_usage__) +admin_help_img.paste(CreateImg(400, 600, font_size=24).text((0, 0), passive_help), (600, 50)) +admin_help_img.save(IMAGE_PATH + 'admin_help_img.png') + + +@admin_help.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + await admin_help.send(image('admin_help_img.png')) diff --git a/plugins/ai/__init__.py b/plugins/ai/__init__.py new file mode 100644 index 00000000..a999f07f --- /dev/null +++ b/plugins/ai/__init__.py @@ -0,0 +1,61 @@ +from .data_source import get_qqbot_chat_result, hello, no_result +from services.log import logger +from nonebot import on_message +from nonebot.rule import to_me +from nonebot.typing import T_State +from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, PrivateMessageEvent +from util.utils import get_message_text, get_message_imgs +from models.friend_user import FriendUser +from models.group_member_info import GroupInfoUser + +__plugin_name__ = 'AI' + + +ai = on_message(rule=to_me(), priority=8) + + +@ai.handle() +async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): + msg = get_message_text(event.json()) + imgs = get_message_imgs(event.json()) + if str(event.get_message()).find('CQ:xml') != -1: + return + # 打招呼 + if not msg and not imgs: + await ai.finish(hello()) + img = imgs[0] if imgs else '' + nickname = await FriendUser.get_friend_nickname(event.user_id) + if not nickname: + nickname = await FriendUser.get_user_name(event.user_id) + if not nickname: + nickname = "你" + result = await get_qqbot_chat_result(msg, img, event.user_id, nickname) + logger.info(f"USER {event.user_id} 问题:{msg}\n回答:{result}") + if result: + await ai.finish(result) + else: + await ai.finish(no_result()) + + +@ai.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + # if await GroupRemind.get_status(event.group_id, 'ai'): + msg = get_message_text(event.json()) + imgs = get_message_imgs(event.json()) + # 打招呼 + if not msg and not imgs: + await ai.finish(hello()) + img = imgs[0] if imgs else '' + nickname = await GroupInfoUser.get_group_member_nickname(event.user_id, event.group_id) + if not nickname: + try: + nickname = (await GroupInfoUser.select_member_info(event.user_id, event.group_id)).user_name + except AttributeError: + nickname = "你" + result = await get_qqbot_chat_result(msg, img, event.user_id, nickname) + logger.info(f"问题:{msg}\n回答:{result}") + if result: + await ai.finish(result) + else: + await ai.finish(no_result()) + diff --git a/plugins/ai/data_source.py b/plugins/ai/data_source.py new file mode 100644 index 00000000..6280a386 --- /dev/null +++ b/plugins/ai/data_source.py @@ -0,0 +1,142 @@ +from configs.config import TL_KEY +import aiohttp +import random +import os +from configs.path_config import IMAGE_PATH, DATA_PATH +from util.init_result import image +from util.utils import get_bot + +try: + import ujson as json +except ModuleNotFoundError: + import json + +url = "http://openapi.tuling123.com/openapi/api/v2" + +index = 0 + +anime_data = json.load(open(DATA_PATH + 'anime.json', 'r', encoding='utf8')) + + +# 图灵AI +async def get_qqbot_chat_result(text: str, img_url: str, user_id: int, user_name: str) -> str: + global index + if index == 5: + index = 0 + if len(text) < 6 and random.random() < 0.6: + keys = anime_data.keys() + for key in keys: + if text.find(key) != -1: + return random.choice(anime_data[key]).replace('你', user_name) + if text: + req = { + "perception": + { + "inputText": + { + "text": text + }, + "selfInfo": + { + "location": + { + "city": "陨石坑", + "province": "火星", + "street": "第5坑位" + } + } + }, + "userInfo": + { + "apiKey": TL_KEY[index], + "userId": str(user_id) + } + } + elif img_url: + req = { + "reqType": 1, + "perception": + { + "inputImage": { + "url": img_url + }, + "selfInfo": + { + "location": + { + "city": "陨石坑", + "province": "火星", + "street": "第5坑位" + } + } + }, + "userInfo": + { + "apiKey": TL_KEY[index], + "userId": str(user_id) + } + } + async with aiohttp.ClientSession() as sess: + async with sess.post(url, json=req) as response: + if response.status != 200: + return '' + resp_payload = json.loads(await response.text()) + if resp_payload['intent']: + if resp_payload['intent']['code'] == 4003: + index += 1 + # 该AI很屑!!!!!!!!!!!! + async with sess.get(f'http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}') as res: + data = json.loads(await res.text()) + if data['result'] == 0: + content = data['content'] + if content.find('菲菲') != -1: + content = content.replace('菲菲', list(get_bot().config.nickname)[0]) + if content.find('公众号') != -1: + content = '' + if content.find('{br}') != -1: + content = content.replace('{br}', '\n') + if content.find('提示') != -1: + content = content[:content.find('提示')] + return content + if resp_payload['results']: + for result in resp_payload['results']: + if result['resultType'] == 'text': + text = result['values']['text'] + if user_name: + text = text.replace('小朋友', user_name) + if len(user_name) < 5: + if random.random() < 0.5: + user_name = "~".join(user_name) + '~' + if random.random() < 0.5: + if user_name.find('大人') == -1: + user_name += '大~人~' + text = text.replace('小主人', user_name) + return text + + +def hello() -> str: + result = random.choice(( + "哦豁?!", + "你好!Ov<", + f"库库库,呼唤{list(get_bot().config.nickname)[0]}做什么呢", + "我在呢!", + "呼呼,叫俺干嘛" + )) + img = random.choice(os.listdir(IMAGE_PATH + "zai/")) + if img[-4:] == ".gif": + result += image(img, "zai") + else: + result += image(img, "zai") + return result + + +def no_result() -> str: + return random.choice([ + '你在说啥子?', + f'纯洁的{list(get_bot().config.nickname)[0]}没听懂', + '下次再告诉你(下次一定)', + '你觉得我听懂了吗?嗯?', + '我!不!知!道!' + ]) + image( + random.choice(os.listdir(IMAGE_PATH + "noresult/") + ), "noresult") diff --git a/plugins/auto_invite/__init__.py b/plugins/auto_invite/__init__.py new file mode 100644 index 00000000..06a83336 --- /dev/null +++ b/plugins/auto_invite/__init__.py @@ -0,0 +1,44 @@ +from nonebot import on_request +from nonebot.adapters.cqhttp import Bot, FriendRequestEvent, GroupRequestEvent +from models.friend_user import FriendUser +from datetime import datetime +from configs.config import AUTO_ADD_FRIEND +from nonebot.adapters.cqhttp.exception import ActionFailed + +__plugin_name__ = '处理请求' + +friend_req = on_request(priority=5) + + +@friend_req.handle() +async def _(bot: Bot, event: FriendRequestEvent, state: dict): + if AUTO_ADD_FRIEND: + nickname = '' + for user in await bot.get_friend_list(): + if user['user_id'] == event.user_id: + nickname = user['nickname'] + await FriendUser.add_friend_info(user['user_id'], user['nickname']) + break + await bot.send_private_msg(user_id=int(list(bot.config.superusers)[0]), message=f"{nickname}({event.user_id})" + f" 添加小真寻好友(已自动同意)") + await bot.set_friend_add_request(flag=event.flag, approve=True) + + +group_req = on_request(priority=5, block=True) + + +@group_req.handle() +async def _(bot: Bot, event: GroupRequestEvent, state: dict): + if event.sub_type == 'invite': + nickname = await FriendUser.get_user_name(event.user_id) + if str(event.user_id) in bot.config.superusers: + try: + await bot.set_group_add_request(flag=event.flag, sub_type='invite', approve=True) + except ActionFailed: + pass + else: + await bot.send_private_msg(user_id=int(list(bot.config.superusers)[0]), + message=f"报告..\n{nickname}({event.user_id})" + f" 希望邀请我加入 {event.group_id}\n邀请日期:{str(datetime.now()).split('.')[0]}") + await bot.send_private_msg(user_id=event.user_id, + message="想要邀请我偷偷入群嘛~~已经提醒管理员了\n等待管理员处理吧~") diff --git a/plugins/ban/__init__.py b/plugins/ban/__init__.py new file mode 100644 index 00000000..5c66ef95 --- /dev/null +++ b/plugins/ban/__init__.py @@ -0,0 +1,82 @@ +from nonebot import on_command +from models.ban_user import BanUser +from models.level_user import LevelUser +from nonebot.typing import T_State +from nonebot.adapters import Bot +from nonebot.adapters.cqhttp import GroupMessageEvent +from nonebot.adapters.cqhttp.permission import GROUP +from util.utils import get_message_at, get_message_text, is_number +from services.log import logger +from models.group_member_info import GroupInfoUser + + +__plugin_name__ = 'Ban/unBan' +__plugin_usage__ = f'用法: 封禁/解封用户(不是禁言!是针对bot是否处理封禁用户消息)\n' \ + '示例:.ban @djdsk\n' \ + '示例:.ban @djdsk 0(小时) 30(分钟)\n' \ + '示例:.ban @sdasf 4(小时)\n' \ + '示例:.unban @sdasf' + + +ban = on_command(".ban", aliases={'.unban', '/ban', '/unban'}, priority=5, permission=GROUP, block=True) + + +@ban.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + if get_message_text(event.json()) in ['帮助'] or str(event.get_message()) == '': + await ban.finish(__plugin_usage__) + # try: + result = '' + qq = int(get_message_at(event.json())[0]) + if qq: + nickname = await GroupInfoUser.get_group_member_nickname(qq, event.group_id) + if not nickname: + nickname = '用户' + msg = get_message_text(event.json()) + if msg: + msg = msg.split(" ") + if len(msg) == 2: + if not is_number(msg[0].strip()) or not is_number(msg[1].strip()): + await ban.finish('参数必须是数字!', at_sender=True) + time = int(msg[0]) * 60 * 60 + int(msg[1]) * 60 + else: + if not is_number(msg[0].strip()): + await ban.finish('参数必须是数字!', at_sender=True) + time = int(msg[0]) * 60 * 60 + else: + time = -1 + if state["_prefix"]["raw_command"] in [".ban", '/ban']: + if await LevelUser.get_user_level(event.user_id, event.group_id) <= await \ + LevelUser.get_user_level(qq, event.group_id) and str(event.user_id) not in bot.config.superusers: + await ban.finish(f"您的权限等级比对方低或相等, {list(bot.config.nickname)[0]}不能为您使用此功能!", at_sender=True) + if await BanUser.ban(qq, await LevelUser.get_user_level(event.user_id, event.group_id), time): + logger.info(f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time/60} 分钟") + result = f"已经将 {nickname} 加入{list(bot.config.nickname)[0]}的黑名单了!" + if time != -1: + result += f"将在 {time/60} 分钟后解封" + else: + time = await BanUser.check_ban_time(qq) + if is_number(time): + time = abs(time) + if time < 60: + time = str(int(time)) + ' 秒' + else: + time = str(int(time / 60)) + ' 分钟' + else: + time += ' 分钟' + result = f"{nickname} 已在黑名单!预计 {time}后解封" + else: + if await BanUser.check_ban_level(qq, await LevelUser.get_user_level(event.user_id, event.group_id)) and\ + str(event.user_id) not in bot.config.superusers: + await ban.finish(f"ban掉 {nickname} 的管理员权限比您高,无法进行unban", at_sender=True) + if await BanUser.unban(qq): + logger.info(f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 解禁") + result = f"已经把 {nickname} 从黑名单中删除了!" + else: + result = f"{nickname} 不在黑名单!" + else: + await ban.finish('艾特人了吗??', at_sender=True) + # except Exception as e: + # result = 'ban/unban执行出错,确定艾特人了吗?' + # logger.error(f'ban/unban执行出错 e:{e}') + await ban.finish(result, at_sender=True) diff --git a/plugins/broadcast/__init__.py b/plugins/broadcast/__init__.py new file mode 100644 index 00000000..54c94a3b --- /dev/null +++ b/plugins/broadcast/__init__.py @@ -0,0 +1,44 @@ +from nonebot import on_command +from nonebot.typing import T_State +from nonebot.adapters import Bot, Event +from nonebot.permission import SUPERUSER +import asyncio +from util.utils import get_message_text, get_message_imgs +from services.log import logger +from models.group_remind import GroupRemind +from util.init_result import image + +broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True) + + +@broadcast.handle() +async def _(bot: Bot, event: Event, state: T_State): + msg = get_message_text(event.json()) + imgs = get_message_imgs(event.json()) + rst = '' + for img in imgs: + rst += image(img) + sid = bot.self_id + gl = await bot.get_group_list(self_id=sid) + gl = [g['group_id'] for g in gl] + for g in gl: + if await GroupRemind.get_status(g, 'gb'): + await asyncio.sleep(0.5) + try: + await bot.send_group_msg(self_id=sid, group_id=g, message=msg+rst) + logger.info(f'群{g} 投递广播成功') + except Exception as e: + logger.error(f'群{g} 投递广播失败:{type(e)}') + try: + await broadcast.send(f'群{g} 投递广播失败:{type(e)}') + except Exception as e: + logger.critical(f'向广播发起者进行错误回报时发生错误:{type(e)}') + await broadcast.send(f'广播完成!') + + + + + + + + diff --git a/plugins/bt/__init__.py b/plugins/bt/__init__.py new file mode 100644 index 00000000..cd9a16e1 --- /dev/null +++ b/plugins/bt/__init__.py @@ -0,0 +1,95 @@ +from nonebot import on_command +from .data_source import get_bt_info +from services.log import logger +from nonebot.typing import T_State +from nonebot.adapters import Bot +from nonebot.adapters.cqhttp import PrivateMessageEvent +from util.utils import get_message_text +from nonebot.adapters.cqhttp.permission import PRIVATE +from util.utils import UserExistLimiter + +__plugin_name__ = '磁力搜索' +__plugin_usage__ = r""" +* 请各位使用后不要转发 * +* 有时可能搜不到,再试一次就行了 * +参数: -U(时间) -H(热度) -S(大小) + -V(仅视频) -P(仅图片) -A(仅压缩包) + -R (R18懂的都懂) + num(页数, 如果不知道页数请不要填,并且是倒叙,比如页数总数是29,你想查看第一页的内容, 就使用 bt 29 xxx) +-按相关度检索(默认) +bt [关键词] +-按更新时间检索(参数不区分大小写,但要注意空格) +bt -U [关键词] +-搜索第10页数 +bt 10(倒着) [关键词] +""".strip() + +_ulmt = UserExistLimiter() + +bt = on_command('bt', permission=PRIVATE, priority=5, block=True) + + +@bt.args_parser +async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): + if str(event.get_message()) in ['取消', '算了']: + await bt.finish("已取消操作..", at_sender=True) + msg = get_message_text(event.json()) + if not msg: + await bt.reject('你想搜索什么呢?', at_sender=True) + mp = msg.split(" ") + if len(mp) > 1: + args = '' + for i in range(len(mp) - 1): + args += mp[i] + ' ' + state['args'] = args + state['bt'] = mp[1] + else: + state['bt'] = get_message_text(event.json()) + state['args'] = '' + + +@bt.handle() +async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): + if get_message_text(event.json()) in ['帮助'] or str(event.get_message()) == '': + await bt.finish(__plugin_usage__) + if _ulmt.check(event.user_id): + await bt.finish('您有bt任务正在进行,请等待结束.', at_sender=True) + mp = get_message_text(event.json()).split(" ") + if len(mp) > 1: + args = '' + for i in range(len(mp) - 1): + args += mp[i] + ' ' + state['args'] = args.strip() + state['bt'] = mp[-1] + else: + state['bt'] = get_message_text(event.json()) + state['args'] = '' + + +@bt.got('bt', prompt='虚空磁力?查什么GKD') +async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): + _ulmt.set_True(event.user_id) + keyword = state['bt'] + args = state['args'] + await bt.send('开始搜索....', at_sender=True) + try: + if args.find('-R') == -1 and args.find('-r') == -1: + bt_report = await get_bt_info(keyword, args) + else: + bt_report = await get_bt_info(keyword, args, '0') + if bt_report: + if len(bt_report.split("\n")) < 2: + await bt.finish(bt_report + '搜索失败了,再试一次也许能成', at_sender=True) + else: + await bt.send("如果有页数没资源请再试一次\n" + bt_report) + logger.info( + f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'})" + f" 搜索bt {args} {keyword}") + else: + logger.error("没查询到资源") + await bt.send("没有查询到资源(也有可能是超时,再试一次?)", at_sender=True) + _ulmt.set_False(event.user_id) + except Exception as e: + _ulmt.set_False(event.user_id) + await bt.send("bt出错啦,再试一次?", at_sender=True) + logger.info(f'bt {keyword} 出错 e:{e}') diff --git a/plugins/bt/data_source.py b/plugins/bt/data_source.py new file mode 100644 index 00000000..8115cb71 --- /dev/null +++ b/plugins/bt/data_source.py @@ -0,0 +1,96 @@ +from util.user_agent import get_user_agent +import aiohttp +from lxml import etree +from lxml.etree import Element +from configs.config import MAXINFO_BT +from urllib import parse +from html import unescape +from util.utils import get_local_proxy, is_number +import time +import platform +if platform.system() == 'Windows': + import asyncio + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + + +url = 'https://www.btmet.com/search.php' + + +async def get_bt_info(keyword: str, args: str, r18: str = '1') -> str: + cookiesDit = { + 'r18': r18 + } + s_time = time.time() + params = get_params(keyword, args) + async with aiohttp.ClientSession(headers=get_user_agent(), cookies=cookiesDit) as session: + async with session.get(url, proxy=get_local_proxy(), params=params, timeout=30) as response: + html = etree.HTML(await response.text()) + print(response.url) + num = html.xpath('//div[@id="wall"]//span/b/text()')[0] + print(num) + if num.find(",") != -1: + num = num.split(',')[0] + if num == '0': + return "没有找到记录" + + div_all = html.xpath('//div[@class="search-item"]')[1:] + div_all = div_all[:MAXINFO_BT] if len(div_all) > MAXINFO_BT else div_all + line_list = [await get_item_line(div) for div in div_all] + clist = [] + for line in line_list: + if line.strip() != '': + clist.append(line) + + return f"搜索 {keyword} 结果(共 {int(int(num.text) / 10) if int(num) % 10 == 0 else int(int(num) / 10) + 1} " \ + f"页)(耗时 {int(time.time() - s_time)} 秒):\n" + "\n\n".join(clist) + + +async def get_item_line(div: Element) -> str: + try: + magent = div.xpath('./div[2]/a/@href')[0] + size = div.xpath('./div[@class="f_left"]/div[@class="item-bar"]/span/b/font/text()')[0] + type = div.xpath('./div[@class="f_left"]/div[@class="item-bar"]/span[@class="cpill blue-pill"]/text()')[0].strip() + + title_doc = div.xpath('.//a[@class="smashTitle"]//text()')[0] + title_code = title_doc[title_doc.find('("') + 2: title_doc.find('")')] + title_xml_code = parse.unquote(title_code) + title_xml = etree.HTML(unescape(title_xml_code)) + title = title_xml.xpath('string(.)') + except Exception: + return '' + return "【{}】| {}\n【{}】| {}".format(type, title, size, magent) + + +# https://www.btmet.com/search.php?q=%E9%92%A2%E9%93%81%E4%BE%A0&c=5&o=0&l=&p=2 +def get_params(keyword: str, args: str) -> dict: + params = { + 'q': keyword, + 'c': '', + 'l': '', + 'o': 0, + 'p': '' + } + if not args: + return params + args = args.split(" ") + for arg in args: + if '-U' == arg.upper(): + params['o'] = 1 + if '-S' == arg.upper(): + params['o'] = 2 + if '-H' == arg.upper(): + params['o'] = 3 + if '-V' == arg.upper(): + params['c'] = 1 + if '-P' == arg.upper(): + params['c'] = 2 + if '-A' == arg.upper(): + params['c'] = 5 + if is_number(arg): + params['p'] = arg + return params + + +# print(asyncio.get_event_loop().run_until_complete(get_bt_info('钢铁侠', ''))) + + diff --git a/plugins/check/__init__.py b/plugins/check/__init__.py new file mode 100644 index 00000000..85292fc3 --- /dev/null +++ b/plugins/check/__init__.py @@ -0,0 +1,20 @@ + +from nonebot import on_command +from .data_source import Check +from nonebot.adapters.cqhttp import Bot, Event +from nonebot.typing import T_State +from nonebot.rule import to_me +from nonebot.permission import SUPERUSER + + +__plugin_name__ = '自我检查' + +check = Check() + + +check_ = on_command('自检', aliases={'check'}, rule=to_me(), permission=SUPERUSER, block=True, priority=1) + + +@check_.handle() +async def _(bot: Bot, event: Event, state: T_State): + await check_.send(await check.show()) diff --git a/plugins/check/data_source.py b/plugins/check/data_source.py new file mode 100644 index 00000000..9911e300 --- /dev/null +++ b/plugins/check/data_source.py @@ -0,0 +1,67 @@ +import psutil +import aiohttp +import time +from datetime import datetime +from util.user_agent import get_user_agent +from asyncio.exceptions import TimeoutError +from aiohttp.client_exceptions import ClientConnectorError +from util.utils import get_local_proxy +import asyncio +from services.log import logger + + +class Check: + def __init__(self): + self.cpu = None + self.memory = None + self.disk = None + self.user = None + self.baidu = 200 + self.google = 200 + + async def check_all(self): + await self.check_network() + await asyncio.sleep(0.1) + self.check_system() + self.check_user() + + def check_system(self): + self.cpu = psutil.cpu_percent() + self.memory = psutil.virtual_memory().percent + self.disk = psutil.disk_usage("/").percent + + async def check_network(self): + async with aiohttp.ClientSession(headers=get_user_agent()) as session: + try: + async with session.get('https://www.baidu.com/', proxy=get_local_proxy(), timeout=3) as response: + pass + except (TimeoutError, ClientConnectorError) as e: + logger.warning(f'访问BaiDu失败... e: {e}') + self.baidu = 404 + try: + async with session.get('https://www.google.com/', proxy=get_local_proxy(), timeout=3) as response: + pass + except (TimeoutError, ClientConnectorError) as e: + logger.warning(f'访问Google失败... e: {e}') + self.google = 404 + + def check_user(self): + rst = '' + for user in psutil.users(): + rst += f'[{user.name}] {time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(user.started))}\n' + self.user = rst[:-1] + + async def show(self): + await self.check_all() + rst = f'[Time] {str(datetime.now()).split(".")[0]}\n' \ + f'-----System-----\n' \ + f'[CPU] {self.cpu}%\n' \ + f'[Memory] {self.memory}%\n' \ + f'[Disk] {self.disk}%\n' \ + f'-----Network-----\n' \ + f'[BaiDu] {self.baidu}\n' \ + f'[Google] {self.google}\n' + if self.user: + rst += '-----User-----\n' + self.user + return rst + diff --git a/plugins/coser/__init__.py b/plugins/coser/__init__.py new file mode 100644 index 00000000..f2589abc --- /dev/null +++ b/plugins/coser/__init__.py @@ -0,0 +1,39 @@ +from nonebot import on_command +from util.utils import get_message_text +from nonebot.typing import T_State +from nonebot.adapters import Bot, Event +from services.log import logger +from util.init_result import image +import requests + +__plugin_usage_coser__ = '不得看看可爱的coser?发送‘coser’' + + +coser = on_command('cos', aliases={'coser', '括丝'}, priority=5, block=True) + + +url_2 = 'http://api.rosysun.cn/cos' + + +@coser.handle() +async def _(bot: Bot, event: Event, state: T_State): + if get_message_text(event.json()) in ['帮助']: + await coser.finish(__plugin_usage_coser__) + img_url = requests.get(url_2).text + await coser.send(image(img_url)) + logger.info( + f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 发送COSER") + + + + + + + + + + + + + + diff --git a/plugins/delete_img/__init__.py b/plugins/delete_img/__init__.py new file mode 100644 index 00000000..5ca22837 --- /dev/null +++ b/plugins/delete_img/__init__.py @@ -0,0 +1,79 @@ +from configs.path_config import IMAGE_PATH, TEMP_PATH +import os +from util.init_result import image +from services.log import logger +from nonebot import on_command +from nonebot.rule import to_me +from nonebot.typing import T_State +from nonebot.adapters import Bot, Event +from configs.config import IMAGE_DIR_LIST +from util.utils import is_number, cn2py + +__plugin_name__ = '删除图片' +__plugin_usage__ = '删除图片帮助:\n\t' \ + '1.查看列表 --> 指令: 删除图片 列表/目录\n\t' \ + '2.删除图片 图库 id, 即在相应目录下删除图片\n\t\t示例: 删除图片 色图 1 ' + + +delete_img = on_command("删除图片", priority=5, rule=to_me(), block=True) + + +@delete_img.args_parser +async def parse(bot: Bot, event: Event, state: T_State): + if str(event.get_message()) in ['取消', '算了']: + await delete_img.finish("已取消操作..", at_sender=True) + if state["_current_key"] in ['path']: + if str(event.get_message()) not in IMAGE_DIR_LIST: + await delete_img.reject("此目录不正确,请重新输入目录!") + state[state["_current_key"]] = str(event.get_message()) + if state["_current_key"] == 'id': + if not is_number(str(event.get_message())): + await delete_img.reject("id不正确!请重新输入数字...") + state[state["_current_key"]] = str(event.get_message()) + + +@delete_img.handle() +async def _(bot: Bot, event: Event, state: T_State): + raw_arg = str(event.get_message()).strip() + if raw_arg: + args = raw_arg.split(" ") + if args[0] in ['帮助']: + await delete_img.finish(__plugin_usage__) + if len(args) >= 2 and args[0] in IMAGE_DIR_LIST and is_number(args[1]): + state['path'] = args[0] + state['id'] = args[1] + + +@delete_img.got("path", prompt="请输入要删除的目标图库?") +@delete_img.got("id", prompt="请输入要删除的图片id?") +async def arg_handle(bot: Bot, event: Event, state: T_State): + path = cn2py(state['path']) + img_id = state['id'] + path = IMAGE_PATH + path + max_id = len(os.listdir(path)) - 1 + if int(img_id) > max_id or int(img_id) < 0: + await delete_img.finish(f"Id超过上下限,上限:{max_id}", at_sender=True) + try: + if os.path.exists(IMAGE_PATH + TEMP_PATH + "delete.jpg"): + os.remove(IMAGE_PATH + TEMP_PATH + "delete.jpg") + logger.info("删除图片 delete.jpg 成功") + except Exception as e: + logger.warning(f"删除图片 delete.jpg 失败 e{e}") + try: + os.rename(path + img_id + ".jpg", IMAGE_PATH + TEMP_PATH + "delete.jpg") + logger.info(f"移动 {path}{img_id}.jpg 移动成功") + except Exception as e: + logger.warning(f"{path}{img_id}.jpg --> 移动失败 e:{e}") + if not os.path.exists(path + img_id + ".jpg"): + try: + if int(img_id) != max_id: + os.rename(path + str(max_id) + ".jpg", path + img_id + ".jpg") + except FileExistsError: + logger.error(f"{path}{max_id}.jpg 替换 {path}{img_id}.jpg 失败 e:{e}") + logger.info(f"{path}{max_id}.jpg 替换 {path}{img_id}.jpg 成功") + logger.info(f"USER {event.user_id} GROUP {event.group_id if event.message_type != 'private' else 'private'}" + f" -> id: {img_id} 删除成功") + await delete_img.finish(f"id: {img_id} 删除成功" + image("delete.jpg", TEMP_PATH), at_sender=True) + await delete_img.finish(f"id: {img_id} 删除失败!") + + diff --git a/plugins/dialogue/__init__.py b/plugins/dialogue/__init__.py new file mode 100644 index 00000000..e2064b9d --- /dev/null +++ b/plugins/dialogue/__init__.py @@ -0,0 +1,54 @@ +from nonebot import on_command +from nonebot.typing import T_State +from nonebot.adapters import Bot, Event +from nonebot.permission import SUPERUSER +from util.utils import get_message_text, is_number +from services.log import logger +from util.init_result import at + + +__plugin_name__ = '联系管理员' +__plugin_usage__ = '滴滴滴- 后接内容 联系管理员' + + +dialogue = on_command("[滴滴滴]", aliases={"滴滴滴-"}, priority=1, block=True) +reply = on_command("/t", priority=1, permission=SUPERUSER, block=True) + + +@dialogue.handle() +async def _(bot: Bot, event: Event, state: T_State): + uid = event.user_id + coffee = int(list(bot.config.superusers)[0]) + text = get_message_text(event.json()) + if not text or text in ['帮助']: + await dialogue.send("请发送[滴滴滴]+您要说的内容~", at_sender=True) + else: + if event.get_event_name() == "message.private.friend": + group_id = "" + else: + group_id = event.group_id + await bot.send_private_msg(user_id=coffee, message=f'Q{uid}@群{group_id}\n{text}') + await dialogue.send(f'您的话已发送至管理员!\n======\n{text}', at_sender=True) + logger.info(f"Q{uid}@群{group_id} 联系管理员:{coffee} text:{text}") + + +@reply.handle() +async def _(bot: Bot, event: Event, state: T_State): + if get_message_text(event.json()) in ['帮助']: + await reply.finish(f'/t qq group text') + msg = get_message_text(event.json()).split(" ") + user_id = int(msg[0]) + if is_number(msg[1]) and len(msg[1]) > 5: + group_id = int(msg[1]) + text = msg[2] + else: + group_id = "" + text = msg[1] + if group_id: + await bot.send_group_msg(group_id=group_id, message=at(user_id) + "\n管理员回复\n=======\n" + text) + else: + if user_id in [qq['user_id'] for qq in await bot.get_friend_list()]: + await bot.send_private_msg(user_id=user_id, message="管理员回复\n=======\n" + text) + await reply.finish("发送成功", at_sender=True) + else: + await reply.send(f"对象不是{list(bot.config.nickname)[0]}的好友...", at_sender=True)