diff --git a/.env.dev b/.env.dev index 4a2eacf2..00d51e29 100644 --- a/.env.dev +++ b/.env.dev @@ -10,7 +10,7 @@ NICKNAME=["真寻", "小真寻", "绪山真寻", "小寻子"] SESSION_EXPIRE_TIMEOUT=30 -DEBUG=true +DEBUG=False # 服务器和端口 HOST = 127.0.0.1 PORT = 8080 diff --git a/configs/config.py b/configs/config.py index 9d982528..19ff4aeb 100644 --- a/configs/config.py +++ b/configs/config.py @@ -1,4 +1,3 @@ -from .utils.util import get_config_data from typing import List, Optional, Tuple from services.service_config import TL_M_KEY, SYSTEM_M_PROXY, ALAPI_M_TOKEN @@ -11,6 +10,8 @@ except ModuleNotFoundError: # 是否使用配置文件 USE_CONFIG_FILE: bool = False +# 回复消息名称 +NICKNAME: str = '小真寻' # API KEY(必要) RSSHUBAPP: str = "https://rsshub.app" # rsshub @@ -35,7 +36,7 @@ SYSTEM_PROXY: Optional[str] = None # 全局代理 BUFF_PROXY: Optional[str] = None # Buff代理 # 公开图库列表 -IMAGE_DIR_LIST: List[str] = ["色图", "美图", "萝莉", "壁纸"] +IMAGE_DIR_LIST: List[str] = ["美图", "萝莉", "壁纸"] # 对被ban用户发送的消息 BAN_RESULT: str = "才不会给你发消息." @@ -77,6 +78,8 @@ MUTE_DEFAULT_COUNT: int = 10 # 刷屏禁言默认检测次数 MUTE_DEFAULT_TIME: int = 7 # 刷屏检测默认规定时间 MUTE_DEFAULT_DURATION: int = 10 # 刷屏检测默禁言时长(分钟) +CHECK_NOTICE_INFO_CD = 300 # 群检测,个人权限检测等各种检测提示信息cd + # 注:即在 MALICIOUS_CHECK_TIME 时间内触发相同命令 MALICIOUS_BAN_COUNT 将被ban MALICIOUS_BAN_TIME 分钟 MALICIOUS_BAN_TIME: int = 30 # 恶意命令触发检测触发后ban的时长(分钟) MALICIOUS_BAN_COUNT: int = 8 # 恶意命令触发检测最大触发次数 @@ -190,6 +193,14 @@ plugins2info_dict = { "level": 5, "cmd": ["pix", "PIX", "pIX", "Pix", "PIx"], }, + "wbtop": { + "level": 5, + "cmd": ['微博热搜', "微博", "wbtop"] + }, + "update_info": { + "level": 5, + "cmd": ['更新信息', '更新日志'] + } } if TL_M_KEY: diff --git a/configs/path_config.py b/configs/path_config.py index b4472c01..32c6c474 100644 --- a/configs/path_config.py +++ b/configs/path_config.py @@ -1,6 +1,6 @@ from .utils.util import get_config_data from pathlib import Path -from configs.config import USE_CONFIG_FILE +# from configs.config import USE_CONFIG_FILE # 图片路径 IMAGE_PATH = Path("resources/img/") @@ -20,24 +20,24 @@ TEMP_PATH = Path("resources/img/temp/") def init_path(): global IMAGE_PATH, VOICE_PATH, TXT_PATH, LOG_PATH, TTF_PATH, DATA_PATH, TEMP_PATH - if USE_CONFIG_FILE: - data = get_config_data() - if data.get('IMAGE_PATH'): - IMAGE_PATH = Path(data['IMAGE_PATH']) - if data.get('VOICE_PATH'): - VOICE_PATH = Path(data['VOICE_PATH']) - if data.get('TXT_PATH'): - TXT_PATH = Path(data['TXT_PATH']) - if data.get('LOG_PATH'): - LOG_PATH = Path(data['LOG_PATH']) - if data.get('TTF_PATH'): - TTF_PATH = Path(data['TTF_PATH']) - if data.get('DATA_PATH'): - DATA_PATH = Path(data['DATA_PATH']) - if data.get('DRAW_PATH'): - DRAW_PATH = Path(data['DRAW_PATH']) - if data.get('TEMP_PATH'): - TEMP_PATH = Path(data['TEMP_PATH']) + # if USE_CONFIG_FILE: + # data = get_config_data() + # if data.get('IMAGE_PATH'): + # IMAGE_PATH = Path(data['IMAGE_PATH']) + # if data.get('VOICE_PATH'): + # VOICE_PATH = Path(data['VOICE_PATH']) + # if data.get('TXT_PATH'): + # TXT_PATH = Path(data['TXT_PATH']) + # if data.get('LOG_PATH'): + # LOG_PATH = Path(data['LOG_PATH']) + # if data.get('TTF_PATH'): + # TTF_PATH = Path(data['TTF_PATH']) + # if data.get('DATA_PATH'): + # DATA_PATH = Path(data['DATA_PATH']) + # if data.get('DRAW_PATH'): + # DRAW_PATH = Path(data['DRAW_PATH']) + # if data.get('TEMP_PATH'): + # TEMP_PATH = Path(data['TEMP_PATH']) IMAGE_PATH.mkdir(parents=True, exist_ok=True) VOICE_PATH.mkdir(parents=True, exist_ok=True) TXT_PATH.mkdir(parents=True, exist_ok=True) diff --git a/plugins/aconfig/__init__.py b/plugins/aconfig/__init__.py index 2ead8e17..df5663f0 100644 --- a/plugins/aconfig/__init__.py +++ b/plugins/aconfig/__init__.py @@ -9,6 +9,7 @@ from nonebot.typing import T_State from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent from nonebot.adapters.cqhttp.permission import GROUP from utils.utils import FreqLimiter +from configs.config import NICKNAME __plugin_name__ = "基本设置 [Hidden]" @@ -38,15 +39,16 @@ self_introduction = on_command( @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) + if NICKNAME.find('真寻') != -1: + result = ( + "我叫绪山真寻\n" + "你们可以叫我真寻,小真寻,哪怕你们叫我小寻子我也能接受!\n" + "年龄的话我还是个**岁初中生(至少现在是)\n" + "身高保密!!!(也就比美波里(姐姐..(妹妹))矮一点)\n" + "我生日是在3月6号, 能记住的话我会很高兴的\n现在是自宅警备系的现役JC\n" + "最好的朋友是椛!\n" + image("zhenxun") + ) + await self_introduction.finish(result) my_wife = on_keyword({"老婆"}, rule=to_me(), priority=5, block=True) diff --git a/plugins/admin_bot_manage/data_source.py b/plugins/admin_bot_manage/data_source.py index 92d54136..5c7d60b2 100644 --- a/plugins/admin_bot_manage/data_source.py +++ b/plugins/admin_bot_manage/data_source.py @@ -7,7 +7,6 @@ import aiohttp from utils.message_builder import image from utils.utils import get_local_proxy, get_bot from pathlib import Path -from nonebot import require from configs.config import plugins2info_dict from models.group_member_info import GroupInfoUser import time @@ -15,145 +14,181 @@ from datetime import datetime from services.db_context import db from models.level_user import LevelUser from configs.config import ADMIN_DEFAULT_AUTH +from utils.static_data import group_manager +from utils.image_utils import CreateImg +import asyncio + 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', + "早晚安": "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发送当日的原神黄历', + "早晚安": "将会在每晚11:59晚安,在6:01早安哦", + "每日开箱重置提醒": "将会在每日00:01提示开箱重置!", + "epic": "将会在每日中午12:01发送可白嫖的epic游戏", + "原神黄历提醒": "将会在每日8:00发送当日的原神黄历", } async def remind_status(group: int, name: str, flag: bool) -> str: - _name = '' + _name = "" if name in command_dict.values(): _name = list(command_dict.keys())[list(command_dict.values()).index(name)] if flag: - rst = '开启' + rst = "开启" if await GroupRemind.get_status(group, name): - return f'该群已经{rst}过 {_name},请勿重复开启!' + return f"该群已经{rst}过 {_name},请勿重复开启!" else: - rst = '关闭' + rst = "关闭" if not await GroupRemind.get_status(group, name): - return f'该群已经{rst}过 {_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 '' + info = command_info_dt[_name] if command_info_dt.get(_name) else "" if info: - info = '\n' + info - return f'成功{rst} {_name}!0v0 {info}' + info = "\n" + info + return f"成功{rst} {_name}!0v0 {info}" else: - return f'{rst} {_name} 失败了...' + return f"{rst} {_name} 失败了..." async def set_group_status(name: str, group_id: int): flag = None - if name[:2] == '开启': + if name[:2] == "开启": flag = True - elif name[:2] == '关闭': + elif name[:2] == "关闭": flag = False cmd = name[2:] - if cmd in ['全部通知', '所有通知']: + if cmd in ["全部通知", "所有通知"]: for command in command_list: await remind_status(group_id, command, flag) - return f'已{name[:2]}所有通知!' + 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 "×"}' + 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" +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') + 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')) + 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}') + 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: + 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} 更换群欢迎消息图片') + 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 + 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): +def change_group_switch(cmd: str, group_id: int, is_super: bool = False): + group_help_file = Path(DATA_PATH) / "group_help" / f"{group_id}.png" 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 plugins2info_dict.keys(): - if cmd in plugins2info_dict[plugin_cmd]['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) + if cmd in plugins2info_dict[plugin_cmd]["cmd"]: + if is_super: + plugin_cmd = f'{plugin_cmd}:super' + if status == "开启": + if group_manager.get_plugin_status(plugin_cmd, group_id): + return f"功能 {cmd} 正处于开启状态!不要重复开启." + group_manager.unblock_plugin(plugin_cmd, group_id) 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') + if not group_manager.get_plugin_status(plugin_cmd, group_id): + return f"功能 {cmd} 正处于关闭状态!不要重复关闭." + group_manager.block_plugin(plugin_cmd, group_id) + if group_help_file.exists(): + group_help_file.unlink() + return f"{status} {cmd} 功能!" + return f"没有找到 {cmd} 功能..." - return f'{status} {cmd} 功能!' - return f'没有找到 {cmd} 功能喔' + +def set_plugin_status(cmd: str, block_type: str = "all"): + status = cmd[:2] + cmd = cmd[2:] + for plugin_cmd in plugins2info_dict.keys(): + if cmd in plugins2info_dict[plugin_cmd]["cmd"]: + if status == "开启": + group_manager.unblock_plugin(plugin_cmd) + else: + group_manager.block_plugin(plugin_cmd, block_type=block_type) + break + + +async def get_plugin_status(): + return await asyncio.get_event_loop().run_in_executor(None, _get_plugin_status) + + +def _get_plugin_status(): + rst = '\t功能\n' + flag_str = '状态'.rjust(4) + '\n' + for plugin_cmd in plugins2info_dict: + flag = group_manager.get_plugin_block_type(plugin_cmd) + flag = flag.upper() + ' CLOSE' if flag else 'OPEN' + rst += f'{plugins2info_dict[plugin_cmd]["cmd"][0]}\n' + flag_str += f'{flag}\n' + height = len(rst.split('\n')) * 24 + a = CreateImg(150, height, font_size=20) + a.text((10, 10), rst) + b = CreateImg(200, height, font_size=20) + b.text((10, 10), flag_str) + A = CreateImg(380, height) + A.paste(a) + A.paste(b, (150, 0)) + return image(b64=A.pic2bs4()) async def update_member_info(group_id: int) -> bool: @@ -163,35 +198,61 @@ async def update_member_info(group_id: int) -> bool: _exist_member_list = [] # try: for user_info in _group_user_list: - if user_info['card'] == "": - nickname = user_info['nickname'] + if user_info["card"] == "": + nickname = user_info["nickname"] else: - nickname = user_info['card'] + 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.get_member_info(user_info['user_id'], user_info['group_id']) + 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.get_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'])) + 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") + time.strftime( + "%Y-%m-%d %H:%M:%S", time.localtime(user_info["join_time"]) + ), + "%Y-%m-%d %H:%M:%S", + ) if await GroupInfoUser.add_member_info( - user_info['user_id'], - user_info['group_id'], - nickname, - join_time,): - _exist_member_list.append(int(user_info['user_id'])) + 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.get_group_member_id_list(group_id)))) + _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.get_group_member_id_list(group_id)) + ) + ) if _del_member_list: for del_user in _del_member_list: if await GroupInfoUser.delete_member_info(del_user, group_id): @@ -202,9 +263,7 @@ async def update_member_info(group_id: int) -> bool: 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]) + await bot.send_private_msg( + user_id=int(list(bot.config.superusers)[0]), message=result[:-1] + ) return True - - - - diff --git a/plugins/admin_bot_manage/group_notification_state.py b/plugins/admin_bot_manage/group_notification_state.py index c406b5ea..c6df4b61 100644 --- a/plugins/admin_bot_manage/group_notification_state.py +++ b/plugins/admin_bot_manage/group_notification_state.py @@ -39,7 +39,7 @@ group_status = on_command( "群通知状态", }, permission=GROUP, - priority=1, + priority=5, block=True, ) diff --git a/plugins/admin_bot_manage/switch_rule.py b/plugins/admin_bot_manage/switch_rule.py index 56021317..710b4675 100644 --- a/plugins/admin_bot_manage/switch_rule.py +++ b/plugins/admin_bot_manage/switch_rule.py @@ -1,10 +1,11 @@ from nonebot import on_command from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from .data_source import change_group_switch -from nonebot.adapters.cqhttp.permission import GROUP +from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent +from .data_source import change_group_switch, set_plugin_status, get_plugin_status from services.log import logger -from configs.config import plugins2info_dict +from configs.config import plugins2info_dict, NICKNAME +from utils.utils import get_message_text, is_number +from nonebot.permission import SUPERUSER __plugin_name__ = "群功能开关" @@ -25,17 +26,52 @@ cmds = set(cmds) switch_rule = on_command( - "switch_rule", aliases=cmds, permission=GROUP, priority=4, block=True + "switch_rule", aliases=cmds, priority=5, block=True ) +plugins_status = on_command('功能状态', permission=SUPERUSER, 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 +async def _(bot: Bot, event: MessageEvent, state: T_State): + if isinstance(event, GroupMessageEvent): + await switch_rule.send( + 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"]}' - ) + logger.info( + f'USER {event.user_id} GROUP {event.group_id} 使用群功能管理命令 {state["_prefix"]["raw_command"]}' + ) + else: + if str(event.user_id) in bot.config.superusers: + block_type = get_message_text(event.json()) + _cmd = state["_prefix"]["raw_command"].strip() + if is_number(block_type): + if not int(block_type) in [g["group_id"] for g in await bot.get_group_list(self_id=int(bot.self_id))]: + await switch_rule.finish(f'{NICKNAME}未加入群聊:{block_type}') + change_group_switch(_cmd, int(block_type), True) + group_name = (await bot.get_group_info(group_id=int(block_type)))['group_name'] + await switch_rule.send(f'已禁用群聊 {group_name}({block_type}) 的 {_cmd[2:]} 功能') + else: + if block_type not in ['all', 'private', 'group', 'a', 'p', 'g']: + block_type = 'all' + block_type = 'all' if block_type == 'a' else block_type + block_type = 'private' if block_type == 'p' else block_type + block_type = 'group' if block_type == 'g' else block_type + set_plugin_status(_cmd, block_type) + if block_type == 'all': + await switch_rule.send(f'已{_cmd[:2]}功能:{_cmd[2:]}') + elif block_type == 'private': + await switch_rule.send(f'已在私聊中{_cmd[:2]}功能:{_cmd[2:]}') + else: + await switch_rule.send(f'已在群聊中{_cmd[:2]}功能:{_cmd[2:]}') + logger.info( + f'USER {event.user_id} 使用功能管理命令 {state["_prefix"]["raw_command"]} | {block_type}' + ) + + +@plugins_status.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State): + await plugins_status.send(await get_plugin_status()) + diff --git a/plugins/admin_help/__init__.py b/plugins/admin_help/__init__.py index 8fe969a9..628fb1b1 100644 --- a/plugins/admin_help/__init__.py +++ b/plugins/admin_help/__init__.py @@ -5,25 +5,22 @@ from nonebot.adapters.cqhttp import GroupMessageEvent from utils.image_utils import CreateImg from configs.path_config import IMAGE_PATH from utils.message_builder import image +from configs.config import NICKNAME __plugin_name__ = '管理帮助 [Hidden]' -__plugin_usage__ = '''管理帮助(权限等级): +__plugin_usage__ = f'''管理帮助(权限等级): 1.更新群组成员列表(1) 2.功能开关 --> 指令:开启/关闭xx功能(2) 3.查看群被动技能 --> 指令:群通知状态(2) 4.自定义群欢迎 --> 指令:自定义进群欢迎消息(2) - 5.将用户拉入真寻黑名单 --> .ban/.unban(5) + 5.将用户拉入{NICKNAME}黑名单 --> .ban/.unban(5) 6.刷屏禁言相关 --> 指令:刷屏检测设置/设置检测时间 \t\t/设置检测次数/设置禁言时长(5) - 7.群员活跃度相关 --> 指令:群员活跃检测设置 - 设置群员活跃检测时长(天) - 添加群员活跃检测白名单[at]... - 查看群员活跃检测白名单(5) - 8.上传图片(6) + 8.上传图片/连续上传图片(6) 9.移动图片(7) 10.删除图片(7) -对我说 “真寻帮助 指令” 获取对应详细帮助 +对我说 “{NICKNAME}帮助 指令” 获取对应详细帮助 群主与管理员默认 5 级权限 ''' diff --git a/plugins/ai/data_source.py b/plugins/ai/data_source.py index aee2cb9a..f4a03247 100644 --- a/plugins/ai/data_source.py +++ b/plugins/ai/data_source.py @@ -1,4 +1,4 @@ -from configs.config import TL_KEY, ALAPI_TOKEN, ALAPI_AI_CHECK +from configs.config import TL_KEY, ALAPI_TOKEN, ALAPI_AI_CHECK, NICKNAME from configs.path_config import IMAGE_PATH, DATA_PATH from aiohttp.client import ClientSession from services.log import logger @@ -104,7 +104,7 @@ async def xie_ai(text: str, sess: ClientSession): if data["result"] == 0: content = data["content"] if "菲菲" in content: - content = content.replace("菲菲", "真寻") + content = content.replace("菲菲", f"{NICKNAME}") if "公众号" in content: content = "" if "{br}" in content: @@ -150,7 +150,7 @@ def no_result() -> str: random.choice( [ "你在说啥子?", - f"纯洁的小真寻没听懂", + f"纯洁的{NICKNAME}没听懂", "下次再告诉你(下次一定)", "你觉得我听懂了吗?嗯?", "我!不!知!道!", diff --git a/plugins/alapi/comments_163.py b/plugins/alapi/comments_163.py index a4d0a7d6..18bd9e47 100644 --- a/plugins/alapi/comments_163.py +++ b/plugins/alapi/comments_163.py @@ -1,8 +1,8 @@ from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, MessageEvent +from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from nonebot.typing import T_State from configs.config import ALAPI_TOKEN -from .util import get_data +from .data_source import get_data from services.log import logger __plugin_name__ = '网易云热评' @@ -27,7 +27,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): song_name = data['title'] await comments_163.send(f'{comment}\n\t——《{song_name}》') logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'})" + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" f" 发送网易云热评: {comment} \n\t\t————{song_name}") diff --git a/plugins/alapi/cover.py b/plugins/alapi/cover.py index 71914a08..c722c300 100644 --- a/plugins/alapi/cover.py +++ b/plugins/alapi/cover.py @@ -1,10 +1,10 @@ from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, MessageEvent, Message +from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent from nonebot.typing import T_State from configs.config import ALAPI_TOKEN from utils.message_builder import image from utils.utils import get_message_text -from .util import get_data +from .data_source import get_data from services.log import logger __plugin_name__ = 'b封面' @@ -33,7 +33,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): img = data['cover'] await cover.send(Message(f'title:{title}\n{image(img)}')) logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'})" + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" f" 获取b站封面: {title} url:{img}") diff --git a/plugins/alapi/data_source.py b/plugins/alapi/data_source.py new file mode 100644 index 00000000..c0f38e24 --- /dev/null +++ b/plugins/alapi/data_source.py @@ -0,0 +1,39 @@ +from nonebot.adapters.cqhttp import MessageSegment +from utils.image_utils import CreateImg +from utils.message_builder import image +from configs.path_config import IMAGE_PATH +import aiohttp + + +async def get_data(url: str, params: dict): + async with aiohttp.ClientSession() as session: + try: + async with session.get( + url, timeout=2, params=params + ) as response: + data = await response.json() + if data["code"] == 200: + if not data["data"]: + return "没有搜索到...", 997 + return data, 200 + else: + return f'发生了错误...code:{data["code"]}', 999 + except TimeoutError: + return "超时了....", 998 + + +def gen_wbtop_pic(data) -> MessageSegment: + bk = CreateImg(700, 32 * 50 + 280, 700, 32, color='#797979') + wbtop_bk = CreateImg(700, 280, background=f'{IMAGE_PATH}/other/webtop.png') + bk.paste(wbtop_bk) + text_bk = CreateImg(700, 32 * 50, 700, 32, color='#797979') + for i, data in enumerate(data): + title = f"{i+1}. {data['hot_word']}" + hot = data['hot_word_num'] + img = CreateImg(700, 30, font_size=20) + w, h = img.getsize(title) + img.text((10, int((30 - h) / 2)), title) + img.text((580, int((30 - h) / 2)), hot) + text_bk.paste(img) + bk.paste(text_bk, (0, 280)) + return image(b64=bk.pic2bs4()) diff --git a/plugins/alapi/poetry.py b/plugins/alapi/poetry.py index f03faa1a..d2c2fa5e 100644 --- a/plugins/alapi/poetry.py +++ b/plugins/alapi/poetry.py @@ -1,9 +1,9 @@ from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, MessageEvent +from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from nonebot.typing import T_State from configs.config import ALAPI_TOKEN from services.log import logger -from .util import get_data +from .data_source import get_data __plugin_name__ = '古诗' __plugin_usage__ = '用法: 无' @@ -29,7 +29,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): author = data['author'] await poetry.send(f'{content}\n\t——{author}《{title}》') logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'})" + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" f" 发送古诗: f'{content}\n\t--{author}《{title}》'") diff --git a/plugins/alapi/util.py b/plugins/alapi/util.py deleted file mode 100644 index a4ae61fb..00000000 --- a/plugins/alapi/util.py +++ /dev/null @@ -1,17 +0,0 @@ -import aiohttp -from utils.utils import get_local_proxy - - -async def get_data(url: str, params: dict): - async with aiohttp.ClientSession() as session: - try: - async with session.get(url, proxy=get_local_proxy(), timeout=2, params=params) as response: - data = await response.json() - if data['code'] == 200: - if not data['data']: - return '没有搜索到...', 997 - return data, 200 - else: - return f'发生了错误...code:{data["code"]}', 999 - except TimeoutError: - return '超时了....', 998 \ No newline at end of file diff --git a/plugins/alapi/wbtop.py b/plugins/alapi/wbtop.py new file mode 100644 index 00000000..d3a83691 --- /dev/null +++ b/plugins/alapi/wbtop.py @@ -0,0 +1,62 @@ +from nonebot import on_command +from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from nonebot.typing import T_State +from configs.config import ALAPI_TOKEN +from services.log import logger +from .data_source import get_data, gen_wbtop_pic +from utils.browser import get_browser +from utils.utils import get_message_text, is_number +from configs.path_config import IMAGE_PATH +from utils.message_builder import image +import asyncio + +__plugin_name__ = '微博热搜' +__plugin_usage__ = '用法: 无' + + +wbtop = on_command("wbtop", aliases={'微博热搜'}, priority=5, block=True) + + +wbtop_url = 'https://v2.alapi.cn/api/new/wbtop' + +wbtop_data = [] + + +@wbtop.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State): + global wbtop_data + msg = get_message_text(event.json()) + if not wbtop_data or not msg: + params = { + 'token': ALAPI_TOKEN + } + data, code = await get_data(wbtop_url, params) + if code != 200: + await wbtop.finish(data, at_sender=True) + wbtop_data = data['data'] + img = await asyncio.get_event_loop().run_in_executor(None, gen_wbtop_pic, wbtop_data) + await wbtop.send(img) + logger.info( + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" + f" 查询微博热搜") + if is_number(msg) and 0 < int(msg) <= 50: + url = wbtop_data[int(msg) - 1]['url'] + browser = await get_browser() + page = None + try: + if not browser: + logger.warning('获取 browser 失败,请部署至 linux 环境....') + await wbtop.finish('获取 browser 对象失败...') + page = await browser.new_page() + await page.goto(url, wait_until='networkidle', timeout=10000) + await page.set_viewport_size({"width": 2560, "height": 1080}) + div = await page.query_selector("#pl_feedlist_index") + await div.screenshot(path=f'{IMAGE_PATH}/temp/webtop_{event.user_id}.png', timeout=100000) + await page.close() + await wbtop.send(image(f'webtop_{event.user_id}.png', 'temp')) + except Exception as e: + logger.error(f'微博热搜截图出错... {type(e)}: {e}') + if page: + await page.close() + await wbtop.send('发生了一些错误.....') + diff --git a/plugins/auto_invite/__init__.py b/plugins/auto_invite/__init__.py index 9ec5e381..ee42f678 100644 --- a/plugins/auto_invite/__init__.py +++ b/plugins/auto_invite/__init__.py @@ -2,7 +2,7 @@ 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 configs.config import AUTO_ADD_FRIEND, NICKNAME from nonebot.adapters.cqhttp.exception import ActionFailed from utils.utils import scheduler import time @@ -70,7 +70,9 @@ async def _(bot: Bot, event: GroupRequestEvent, state: dict): ) await bot.send_private_msg( user_id=event.user_id, - message="想要邀请我偷偷入群嘛~已经提醒真寻的管理员大人了\n" "请确保已经群主或群管理沟通过!\n" "等待管理员处理吧!", + message=f"想要邀请我偷偷入群嘛~已经提醒{NICKNAME}的管理员大人了\n" + "请确保已经群主或群管理沟通过!\n" + "等待管理员处理吧!", ) diff --git a/plugins/ban/__init__.py b/plugins/ban/__init__.py index b733893a..af4d70c7 100644 --- a/plugins/ban/__init__.py +++ b/plugins/ban/__init__.py @@ -3,16 +3,17 @@ from models.ban_user import BanUser from models.level_user import LevelUser from nonebot.typing import T_State from nonebot.adapters.cqhttp import Bot -from nonebot.adapters.cqhttp import GroupMessageEvent +from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent from nonebot.adapters.cqhttp.permission import GROUP from utils.utils import get_message_at, get_message_text, is_number +from configs.config import NICKNAME from services.log import logger __plugin_name__ = "Ban/unBan" __plugin_usage__ = ( "用法:\n" - "(不是禁言!是针对真寻是否处理封禁用户消息)\n" + f"(不是禁言!是针对{NICKNAME}是否处理封禁用户消息)\n" "封禁/解封用户 [小时] [分钟]\n" "示例:.ban @djdsk\n" "示例:.ban @djdsk 0 30\n" @@ -25,7 +26,6 @@ ban = on_command( ".ban", aliases={".unban", "/ban", "/unban"}, priority=5, - permission=GROUP, block=True, ) @@ -58,7 +58,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): and str(event.user_id) not in bot.config.superusers ): await ban.finish( - f"您的权限等级比对方低或相等, {list(bot.config.nickname)[0]}不能为您使用此功能!", + f"您的权限等级比对方低或相等, {NICKNAME}不能为您使用此功能!", at_sender=True, ) if await BanUser.ban( @@ -67,7 +67,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): logger.info( f"USER {event.user_id} GROUP {event.group_id} 将 USER {qq} 封禁 时长 {time/60} 分钟" ) - result = f"已经将 {user_name} 加入{list(bot.config.nickname)[0]}的黑名单了!" + result = f"已经将 {user_name} 加入{NICKNAME}的黑名单了!" if time != -1: result += f"将在 {time/60} 分钟后解封" else: @@ -102,6 +102,58 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): await ban.finish("艾特人了吗??", at_sender=True) await ban.finish(result, at_sender=True) - + +@ban.handle() +async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): + if str(event.user_id) in bot.config.superusers: + msg = get_message_text(event.json()) + msg = msg.split() + if is_number(msg[0]): + qq = int(msg[0]) + if state["_prefix"]["raw_command"] in [".ban", "/ban"]: + hour = 0 + minute = 0 + if len(msg) > 1 and is_number(msg[1]): + hour = int(msg[1]) + if len(msg) > 2 and is_number(msg[2]): + minute = int(msg[2]) + time = hour * 60 * 60 + minute * 60 + time = time if time else -1 + if await BanUser.ban( + qq, 9, time + ): + logger.info( + f"USER {event.user_id} 将 USER {qq} 封禁 时长 {time/60} 分钟" + ) + result = f"已经将 {qq} 加入{NICKNAME}的黑名单了!" + if time != -1: + result += f"将在 {time/60} 分钟后解封" + else: + result += f"将在 ∞ 分钟后解封" + await ban.send(result) + else: + time = await BanUser.check_ban_time(qq) + if is_number(time): + time = abs(int(time)) + if time < 60: + time = str(time) + " 秒" + else: + time = str(int(time / 60)) + " 分钟" + else: + time += " 分钟" + await ban.send(f"{qq} 已在黑名单!预计 {time}后解封") + else: + if await BanUser.unban(qq): + logger.info( + f"USER {event.user_id} 将 USER {qq} 解禁" + ) + result = f"已经把 {qq} 从黑名单中删除了!" + else: + result = f"{qq} 不在黑名单!" + await ban.send(result) + else: + await ban.finish('qq号必须是数字!\n格式:.ban [qq] [hour]? [minute]?', at_sender=True) + + diff --git a/plugins/check_zhenxun_update/__init__.py b/plugins/check_zhenxun_update/__init__.py index 434c10e8..d83ceda5 100644 --- a/plugins/check_zhenxun_update/__init__.py +++ b/plugins/check_zhenxun_update/__init__.py @@ -2,7 +2,7 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent from nonebot.typing import T_State from nonebot.permission import SUPERUSER from nonebot import on_command -from .data_source import check_update, get_latest_version +from .data_source import check_update, get_latest_version_data from services.log import logger from utils.utils import scheduler, get_bot from pathlib import Path @@ -65,8 +65,9 @@ async def _(): _version = ( open(_version_file, "r", encoding="utf8").readline().split(":")[-1].strip() ) - latest_version, tar_gz_url = await get_latest_version() - if latest_version and tar_gz_url: + data = await get_latest_version_data() + if data: + latest_version = data["name"] if _version != latest_version: bot = get_bot() await bot.send_private_msg( diff --git a/plugins/check_zhenxun_update/data_source.py b/plugins/check_zhenxun_update/data_source.py index 95fe8cad..46a7621c 100644 --- a/plugins/check_zhenxun_update/data_source.py +++ b/plugins/check_zhenxun_update/data_source.py @@ -1,11 +1,11 @@ from aiohttp.client_exceptions import ClientConnectorError from nonebot.adapters.cqhttp import Bot from utils.user_agent import get_user_agent -from utils.utils import get_local_proxy, get_bot +from utils.utils import get_local_proxy +from utils.image_utils import CreateImg +from configs.path_config import IMAGE_PATH from typing import List -from bs4.element import Tag from services.log import logger -from bs4 import BeautifulSoup from pathlib import Path import ujson as json import nonebot @@ -24,8 +24,7 @@ if str(platform.system()).lower() == "windows": driver = nonebot.get_driver() -version_url = "https://github.com/HibiKier/zhenxun_bot/releases" -main_url = "https://github.com/HibiKier/zhenxun_bot" +release_url = "https://api.github.com/repos/HibiKier/zhenxun_bot/releases/latest" _version_file = Path() / "__version__" zhenxun_latest_tar_gz = Path() / "zhenxun_latest_file.tar.gz" @@ -33,30 +32,24 @@ temp_dir = Path() / "temp" backup_dir = Path() / "backup" -@driver.on_startup -def init(): +@driver.on_bot_connect +async def remind(bot: Bot): if str(platform.system()).lower() != "windows": restart = Path() / "restart.sh" - env_file = Path() / ".env.dev" - if not restart.exists() and env_file.exists(): - with open(env_file, "r", encoding="utf8") as ef: - data = ef.readlines() - port = [x.split("=")[1].strip() for x in data if "port" in x.lower()][0] + if not restart.exists(): with open(restart, "w", encoding="utf8") as f: f.write( - "pid=$(netstat -tunlp | grep " + port + " | awk '{print $7}')\n" + f"pid=$(netstat -tunlp | grep " + + str(bot.config.port) + + " | awk '{print $7}')\n" "pid=${pid%/*}\n" "kill -9 $pid\n" "sleep 3\n" "python3 bot.py" ) os.system("chmod +x ./restart.sh") - logger.info("已自动生成 restart.sh(重启) 文件,请检查是否与本地指令符合...") - - -@driver.on_bot_connect -async def remind(bot: Bot): - is_restart_file = Path() / 'is_restart' + logger.info("已自动生成 restart.sh(重启) 文件,请检查脚本是否与本地指令符合...") + is_restart_file = Path() / "is_restart" if is_restart_file.exists(): await bot.send_private_msg( user_id=int(list(bot.config.superusers)[0]), @@ -72,9 +65,11 @@ async def check_update(bot: Bot) -> int: _version = ( open(_version_file, "r", encoding="utf8").readline().split(":")[-1].strip() ) - latest_version, tar_gz_url = await get_latest_version() - if latest_version and tar_gz_url: + data = await get_latest_version_data() + if data: + latest_version = data["name"] if _version != latest_version: + tar_gz_url = data["tarball_url"] logger.info(f"检测真寻已更新,当前版本:{_version},最新版本:{latest_version}") await bot.send_private_msg( user_id=int(list(bot.config.superusers)[0]), @@ -88,22 +83,22 @@ async def check_update(bot: Bot) -> int: ) logger.info("真寻更新完毕,清理文件完成....") logger.info("开始获取真寻更新日志.....") - update_info = await get_updated_info() - if update_info: - logger.info("获取真寻更新日志成功...开始发送日志...") - await bot.send_private_msg( - user_id=int(list(bot.config.superusers)[0]), - message=f"真寻更新完成,版本:{_version} -> {latest_version}\n" - f"更新日志:\n" - f"{update_info}", - ) - else: - logger.warning("获取真寻更新日志失败...") - await bot.send_private_msg( - user_id=int(list(bot.config.superusers)[0]), - message=f"真寻更新完成,版本:{_version} -> {latest_version}\n" - f"获取真寻更新日志失败...", - ) + update_info = data["body"] + await bot.send_private_msg( + user_id=int(list(bot.config.superusers)[0]), + message=f"真寻更新完成,版本:{_version} -> {latest_version}\n" + f"更新日期:{data['created_at']}\n" + f"更新日志:\n" + f"{update_info}", + ) + width = 0 + height = len(update_info.split('\n')) * 24 + for m in update_info.split('\n'): + if len(m) * 20 > width: + width = len(m) * 17 + A = CreateImg(800, height, font_size=20) + A.text((10, 10), update_info) + A.save(f'{IMAGE_PATH}/update_info.png') return 200 else: logger.warning(f"下载真寻最新版本失败...版本号:{latest_version}") @@ -187,29 +182,16 @@ def _file_handle(latest_version: str): # 获取最新版本号 -async def get_latest_version() -> "str, str": +async def get_latest_version_data() -> dict: async with aiohttp.ClientSession(headers=get_user_agent()) as session: for _ in range(3): try: - async with session.get(version_url, proxy=get_local_proxy()) as res: + async with session.get(release_url, proxy=get_local_proxy()) as res: if res.status == 200: - soup = BeautifulSoup(await res.text(), "lxml") - div = soup.find("div", {"class": "release-entry"}) - latest_version = ( - div.find( - "div", {"class": "f1 flex-auto min-width-0 text-normal"} - ) - .find("a") - .text - ) - tar_gz_url = div.find_all( - "a", {"class": "d-flex flex-items-center"} - )[-1].get("href") - tar_gz_url = f"https://github.com{tar_gz_url}" - return latest_version, tar_gz_url + return await res.json() except (TimeoutError, ClientConnectorError): pass - return "", "" + return {} # 下载文件 @@ -236,33 +218,3 @@ def check_old_lines(lines: List[str], line: str) -> str: if len(l) > len(line): return l return line - - -async def get_updated_info() -> str: - async with aiohttp.ClientSession(headers=get_user_agent()) as session: - for _ in range(3): - try: - async with session.get(main_url, proxy=get_local_proxy()) as res: - soup = BeautifulSoup(await res.text(), "lxml") - children_list = list(soup.find("article").children) - children_list = [x for x in children_list if x != "\n"] - for i, children in enumerate(children_list): - a = children.find("a") - if a and isinstance(a, Tag) and a.get("href") == "#更新": - update_info = "" - tmp_children_list = children_list[i:] - tmp_children_list = [ - x for x in tmp_children_list if "ul" in str(x) - ] - for j, chi in enumerate(tmp_children_list): - if "ul" in str(chi): - update_time = children_list[i:][j + 1].text - update_info += f"更新日期:{update_time}\n" - ul = children_list[i:][j + 2] - break - for li in ul.find_all("li"): - update_info += f"\t● {li.text}\n" - return update_info - except (TimeoutError, ClientConnectorError): - pass - return "" diff --git a/plugins/delete_img/__init__.py b/plugins/delete_img/__init__.py index e6891b82..e741bfba 100644 --- a/plugins/delete_img/__init__.py +++ b/plugins/delete_img/__init__.py @@ -7,6 +7,7 @@ from nonebot.typing import T_State from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from configs.config import IMAGE_DIR_LIST from utils.utils import is_number, cn2py +from pathlib import Path import os __plugin_name__ = "删除图片" @@ -51,28 +52,30 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): async def arg_handle(bot: Bot, event: MessageEvent, state: T_State): path = cn2py(state["path"]) img_id = state["id"] - path = IMAGE_PATH + path + # path = IMAGE_PATH + path + path = Path(IMAGE_PATH) / path + temp = Path(IMAGE_PATH) / 'temp' 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") + if os.path.exists(temp / "delete.jpg"): + os.remove(temp / "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 移动成功") + os.rename(path / f"{img_id}.jpg", temp / "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"): + logger.warning(f"{path}/{img_id}.jpg --> 移动失败 e:{e}") + if not os.path.exists(path / f"{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 成功") + os.rename(path / f"{max_id}.jpg", path / f"{img_id}.jpg") + except FileExistsError as e: + 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 isinstance(event, GroupMessageEvent) else 'private'}" f" -> id: {img_id} 删除成功" diff --git a/plugins/epic/__init__.py b/plugins/epic/__init__.py index 872ff952..47e9e261 100644 --- a/plugins/epic/__init__.py +++ b/plugins/epic/__init__.py @@ -1,6 +1,6 @@ from nonebot import on_command from services.log import logger -from nonebot.adapters.cqhttp import Bot, MessageEvent +from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from nonebot.typing import T_State from utils.utils import scheduler, get_bot from .data_source import get_epic_game @@ -20,7 +20,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): result, code = await get_epic_game() await epic.send(result) logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'})" + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" f" 获取epic免费游戏" ) diff --git a/plugins/fudu.py b/plugins/fudu.py index d2a106c6..a3ac3d5b 100644 --- a/plugins/fudu.py +++ b/plugins/fudu.py @@ -16,22 +16,40 @@ from configs.config import FUDU_PROBABILITY class Fudu: def __init__(self): - self.mlist = defaultdict(list) + self.data = {} def append(self, key, content): - self.mlist[key].append(content) + self._create(key) + self.data[key]['data'].append(content) def clear(self, key): - self.mlist[key] = [] + self._create(key) + self.data[key]['data'] = [] + self.data[key]['is_repeater'] = False def size(self, key) -> int: - return len(self.mlist[key]) + self._create(key) + return len(self.data[key]['data']) def check(self, key, content) -> bool: - return self.mlist[key][0] == content + self._create(key) + return self.data[key]['data'][0] == content def get(self, key): - return self.mlist[key][0] + self._create(key) + return self.data[key]['data'][0] + + def is_repeater(self, key): + self._create(key) + return self.data[key]['is_repeater'] + + def set_repeater(self, key): + self._create(key) + self.data[key]['is_repeater'] = True + + def _create(self, key): + if self.data.get(key) is None: + self.data[key] = {'is_repeater': False, 'data': []} _fudulist = Fudu() @@ -64,7 +82,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): _fudulist.clear(event.group_id) _fudulist.append(event.group_id, add_msg) if _fudulist.size(event.group_id) > 2: - if random.random() < FUDU_PROBABILITY: + if random.random() < FUDU_PROBABILITY and not _fudulist.is_repeater(event.group_id): if random.random() < 0.2: await fudu.finish("打断施法!") if imgs and msg: @@ -77,7 +95,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): rst = "" if rst: await fudu.send(rst) - _fudulist.clear(event.group_id) + _fudulist.set_repeater(event.group_id) async def get_fudu_img_hash(url, group_id): diff --git a/plugins/genshin/query_resource_points/__init__.py b/plugins/genshin/query_resource_points/__init__.py index 26906682..9211954f 100644 --- a/plugins/genshin/query_resource_points/__init__.py +++ b/plugins/genshin/query_resource_points/__init__.py @@ -5,6 +5,7 @@ from utils.utils import get_message_text, scheduler from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent, Message from nonebot.typing import T_State from services.log import logger +from nonebot.permission import SUPERUSER import re try: @@ -21,7 +22,7 @@ __plugin_usage__ = ( qr = on_command("原神资源查询", priority=5, block=True) qr_lst = on_command("原神资源列表", priority=5, block=True) rex_qr = on_regex(".*?(在哪|在哪里|哪有|哪里有).*?", rule=to_me(), priority=5, block=True) -update_info = on_command('更新原神资源信息', priority=1, block=True) +update_info = on_command('更新原神资源信息', permission=SUPERUSER, priority=1, block=True) @qr.handle() diff --git a/plugins/genshin/query_resource_points/query_resource.py b/plugins/genshin/query_resource_points/query_resource.py index d5389186..b15a731a 100644 --- a/plugins/genshin/query_resource_points/query_resource.py +++ b/plugins/genshin/query_resource_points/query_resource.py @@ -46,7 +46,7 @@ MAP_RATIO = 0.5 async def query_resource(resource_name: str) -> str: global CENTER_POINT planning_route: bool = False - if resource_name and resource_name[-2:] == "路径": + if resource_name and resource_name[-2:] in ["路径", "路线"]: resource_name = resource_name[:-2].strip() planning_route = True if not resource_name or resource_name not in resource_name_list: diff --git a/plugins/group_handle/__init__.py b/plugins/group_handle/__init__.py index 2a41f718..64344ab5 100644 --- a/plugins/group_handle/__init__.py +++ b/plugins/group_handle/__init__.py @@ -81,7 +81,7 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict): @group_decrease_handle.handle() async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict): - # 真寻被踢出群 + # 被踢出群 if event.sub_type == "kick_me": group_id = event.group_id operator_id = event.operator_id diff --git a/plugins/group_level/__init__.py b/plugins/group_level/__init__.py deleted file mode 100644 index 6ccc2010..00000000 --- a/plugins/group_level/__init__.py +++ /dev/null @@ -1,116 +0,0 @@ -from nonebot import on_command, on_regex -from utils.utils import get_message_text, is_number, FreqLimiter -from nonebot.rule import to_me -from services.log import logger -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent, GROUP -from nonebot.typing import T_State -from nonebot.matcher import Matcher -from nonebot.permission import SUPERUSER -from pathlib import Path -from configs.config import plugins2info_dict -from nonebot.message import run_preprocessor, IgnoredException - -try: - import ujson as json -except ModuleNotFoundError: - import json - -__plugin_name__ = "群权限" -__plugin_usage__ = "区分权限功能" - -flmt = FreqLimiter(60) - -group_level_data = Path() / "data" / "manager" / "group_level.json" -group_level_data.parent.mkdir(exist_ok=True, parents=True) -group_data = {} -if group_level_data.exists(): - group_data = json.load(open(group_level_data, "r", encoding="utf8")) - - -@run_preprocessor -async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State): - if not isinstance(event, MessageEvent): - return - if matcher.type == "message" and matcher.priority not in [1, 9]: - if isinstance(event, GroupMessageEvent): - if not group_data.get(str(event.group_id)): - group_data[str(event.group_id)] = 5 - if not check_level_group(matcher.module, event.group_id): - try: - if flmt.check(event.group_id): - flmt.start_cd(event.group_id) - await bot.send_group_msg( - group_id=event.group_id, message="群权限不足..." - ) - except AttributeError: - pass - raise IgnoredException("群权限不足") - - -add_group_level = on_command("修改群权限", priority=1, permission=SUPERUSER, block=True) -my_group_level = on_command( - "查看群权限", aliases={"群权限"}, priority=5, permission=GROUP, block=True -) -what_up_group_level = on_regex( - ".*?(提高|提升|升高|增加|加上)(.*?)群权限.*?", - rule=to_me(), - priority=5, - permission=GROUP, - block=True, -) - - -@add_group_level.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) - if not msg: - await add_group_level.finish("用法:修改群权限 [group] [level]") - msg = msg.split(" ") - if len(msg) < 2: - await add_group_level.finish("参数不完全..[group] [level]") - if is_number(msg[0]) and is_number(msg[1]): - group_id = msg[0] - level = int(msg[1]) - else: - await add_group_level.finish("参数错误...group和level必须是数字..") - if not group_data.get(group_id): - group_data[group_id] = 5 - await add_group_level.send("修改成功...", at_sender=True) - await bot.send_group_msg( - group_id=int(group_id), message=f"管理员修改了此群权限:{group_data[group_id]} -> {level}" - ) - group_data[group_id] = level - with open(group_level_data, "w", encoding="utf8") as f: - json.dump(group_data, f, ensure_ascii=False, indent=4) - logger.info(f"{event.user_id} 修改了 {group_id} 的权限:{level}") - - -@my_group_level.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - if group_data.get(str(event.group_id)): - level = group_data[str(event.group_id)] - tmp = "" - for plugin in plugins2info_dict: - if plugins2info_dict[plugin]["level"] > level: - plugin_name = plugins2info_dict[plugin]["cmd"][0] - if plugin_name == "pixiv": - plugin_name = "搜图 p站排行" - tmp += f"{plugin_name}\n" - if tmp: - tmp = "\n目前无法使用的功能:\n" + tmp - await my_group_level.finish(f"当前群权限:{level}{tmp}") - - -@what_up_group_level.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - await what_up_group_level.finish( - f"[此功能用于防止内鬼,如果引起不便那真是抱歉了]\n" f"目前提高群权限的方法:\n" f"\t1.管理员修改权限" - ) - - -# 检查权限 -def check_level_group(module: str, group_id: int) -> bool: - if plugins2info_dict.get(module): - if plugins2info_dict[module]["level"] > group_data[str(group_id)]: - return False - return True diff --git a/plugins/group_manager/__init__.py b/plugins/group_manager/__init__.py new file mode 100644 index 00000000..1ef81650 --- /dev/null +++ b/plugins/group_manager/__init__.py @@ -0,0 +1,102 @@ +from nonebot import on_command, on_regex +from utils.utils import get_message_text, is_number +from nonebot.rule import to_me +from services.log import logger +from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent, GROUP +from nonebot.typing import T_State +from nonebot.permission import SUPERUSER +from configs.config import plugins2info_dict, NICKNAME +from utils.static_data import group_manager + +try: + import ujson as json +except ModuleNotFoundError: + import json + +__plugin_name__ = "群权限操作" +__plugin_usage__ = "区分权限功能" + + +add_group_level = on_command("修改群权限", priority=1, permission=SUPERUSER, block=True) +my_group_level = on_command( + "查看群权限", aliases={"群权限"}, priority=5, permission=GROUP, block=True +) +what_up_group_level = on_regex( + ".*?(提高|提升|升高|增加|加上)(.*?)群权限.*?", + rule=to_me(), + priority=5, + permission=GROUP, + block=True, +) + +manager_group_whitelist = on_command( + "添加群白名单", aliases={"删除群白名单"}, priority=1, permission=SUPERUSER, block=True +) + + +@add_group_level.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State): + msg = get_message_text(event.json()) + if not msg: + await add_group_level.finish("用法:修改群权限 [group] [level]") + msg = msg.split(" ") + if len(msg) < 2: + await add_group_level.finish("参数不完全..[group] [level]") + if is_number(msg[0]) and is_number(msg[1]): + group_id = msg[0] + level = int(msg[1]) + else: + await add_group_level.finish("参数错误...group和level必须是数字..") + old_level = group_manager.get_group_level(group_id) + group_manager.set_group_level(group_id, level) + await add_group_level.send("修改成功...", at_sender=True) + await bot.send_group_msg( + group_id=int(group_id), message=f"管理员修改了此群权限:{old_level} -> {level}" + ) + logger.info(f"{event.user_id} 修改了 {group_id} 的权限:{level}") + + +@my_group_level.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + level = group_manager.get_group_level(str(event.group_id)) + tmp = "" + for plugin in plugins2info_dict: + if plugins2info_dict[plugin]["level"] > level: + plugin_name = plugins2info_dict[plugin]["cmd"][0] + if plugin_name == "pixiv": + plugin_name = "搜图 p站排行" + tmp += f"{plugin_name}\n" + if tmp: + tmp = "\n目前无法使用的功能:\n" + tmp + await my_group_level.finish(f"当前群权限:{level}{tmp}") + + +@what_up_group_level.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + await what_up_group_level.finish( + f"[此功能用于防止内鬼,如果引起不便那真是抱歉了]\n" f"目前提高群权限的方法:\n" f"\t1.管理员修改权限" + ) + + +@manager_group_whitelist.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State): + msg = get_message_text(event.json()).split() + all_group = [ + g["group_id"] for g in await bot.get_group_list(self_id=int(bot.self_id)) + ] + group_list = [] + for group in msg: + if is_number(group) and int(group) in all_group: + group_list.append(int(group)) + if group_list: + for group in group_list: + if state["_prefix"]["raw_command"] in ["添加群白名单"]: + group_manager.add_group_white_list(group) + else: + group_manager.delete_group_white_list(group) + group_list = [str(x) for x in group_list] + await manager_group_whitelist.send( + "已成功将 " + "\n".join(group_list) + " " + state["_prefix"]["raw_command"] + ) + else: + await manager_group_whitelist.send(f"添加失败,请检查{NICKNAME}是否已加入这些群聊或重复添加/删除群白单名") diff --git a/plugins/help/__init__.py b/plugins/help/__init__.py index 76c8e8e1..487973f5 100644 --- a/plugins/help/__init__.py +++ b/plugins/help/__init__.py @@ -6,12 +6,9 @@ from configs.path_config import DATA_PATH from utils.message_builder import image import os from .data_source import create_help_img, create_group_help_img, get_plugin_help -from nonebot import require from utils.utils import get_message_text -export = require("nonebot_plugin_manager") - __plugin_name__ = "帮助" diff --git a/plugins/help/config.py b/plugins/help/config.py index aabae177..6b2c9b9c 100644 --- a/plugins/help/config.py +++ b/plugins/help/config.py @@ -1,3 +1,5 @@ +from configs.config import NICKNAME + # 实用 utility_help = { "update_pic": "一些对图片的操作 --> 指令:操作图片/图片/修改图片(包含 10 种图片操作)", @@ -46,12 +48,13 @@ entertainment_help = { "qiu_qiu_translation": "这家伙到底在说什么? --> 指令:丘丘翻译/丘丘一下/丘丘语翻译", "query_resource_points": "地图资源速速查看 --> 指令:原神资源查询xx[路径]/原神资源列表/哪里有xx/xx在哪(xx=资源名称)", "russian": "紧张刺激的俄罗斯轮盘 --> 指令:俄罗斯轮盘帮助", - "gold_redbag": "运气项目又来啦! --> 指令:塞红包/ 抢红包指令: 开/抢/戳一戳真寻/ 退回:退回未抢完的红包", - "poetry": "突然文艺的真寻是否搞错了什么 --> 指令:念诗/来首诗/念首诗", + "gold_redbag": f"运气项目又来啦! --> 指令:塞红包/ 抢红包指令: 开/抢/戳一戳{NICKNAME}/ 退回:退回未抢完的红包", + "poetry": f"突然文艺的{NICKNAME}是否搞错了什么 --> 指令:念诗/来首诗/念首诗", "comments_163": "生了个人,我很抱歉 --> 指令:到点了/12点了/网易云热评/网易云评论", "pix_gallery": "偶尔也想看看美图? --> 指令:PIX [关键词/uid/pid:pid] [num]/查看pix图库 [关键词]/显示pix关键词", 'nbnhhsh': "会说话就多说点! --> 指令:nbnhhsh/能不能好好说话 [文本](空格划分)", - "roll": "让真寻来帮你决定吧! --> 指令:roll/ roll [文本](空格划分)" + "roll": f"让{NICKNAME}来帮你决定吧! --> 指令:roll/ roll [文本](空格划分)", + "wbtop": f"刚买完瓜,在吃瓜现场 --> 指令:微博热搜/微博热搜 [数字]" } # 其他 other_help = [ @@ -60,7 +63,7 @@ other_help = [ "不得看看自己权力多大? --> 指令:我的权限", "有人记得你是什么时候加入我们的 --> 指令:我的信息", "让我看看更新了什么 --> 指令:更新信息", - "真寻给我把话收回去! --> 指令:撤回 [id](默认0)", + f"{NICKNAME}给我把话收回去! --> 指令:撤回 [id](默认0)", "群拥有的权限 --> 指令:查看群权限", "数据统计可视化_1 --> 指令:功能调用统计/日功能调用统计/周功能调用统计/月功能调用统计", "数据统计可视化_2 --> 指令:周功能调用统计 [功能名称]/月功能调用统计 [功能名称]", diff --git a/plugins/help/data_source.py b/plugins/help/data_source.py index 4598bb12..f459fcd5 100644 --- a/plugins/help/data_source.py +++ b/plugins/help/data_source.py @@ -1,18 +1,16 @@ from utils.image_utils import CreateImg from configs.path_config import IMAGE_PATH, DATA_PATH -import ujson as json -import os +from pathlib import Path from .config import * -from nonebot import require from configs.config import ( INITIAL_OPEN_CASE_COUNT, INITIAL_SETU_PROBABILITY, ADMIN_DEFAULT_AUTH, ) -from configs.config import plugins2info_dict +from configs.config import plugins2info_dict, NICKNAME +from utils.static_data import group_manager import nonebot -export = require("nonebot_plugin_manager") width = 1600 e_height = 0 @@ -22,8 +20,9 @@ o_height = 1500 def create_help_img(): - if os.path.exists(IMAGE_PATH + "help.png"): - os.remove(IMAGE_PATH + "help.png") + help_img_file = Path(IMAGE_PATH) / 'help.png' + if help_img_file.exists(): + help_img_file.unlink() h = ( 100 + len(utility_help) * 24 @@ -60,10 +59,10 @@ def create_help_img(): A.paste(o, (0, o_height)) A.text( (10, h * 0.68), - "大部分交互功能可以通过输入‘取消’,‘算了’来取消当前交互\n对真寻说 “真寻帮助 指令名” 获取对应详细帮助\n" + f"大部分交互功能可以通过输入‘取消’,‘算了’来取消当前交互\n对{NICKNAME}说 “{NICKNAME}帮助 指令名” 获取对应详细帮助\n" "可以通过 “滴滴滴- [消息]” 联系管理员(有趣的想法尽管来吧!<还有Bug和建议>)" "\n[群管理员请看 管理员帮助(群主与管理员自带 5 级权限)]\n\n" - "\t「如果真寻回复了一些不符合人设的话,那是因为每日白嫖的图灵次数已用完,使用的是备用接口【QAQ】」", + f"\t「如果{NICKNAME}回复了一些不符合人设的话,那是因为每日白嫖的图灵次数已用完,使用的是备用接口【QAQ】」", ) A.save(IMAGE_PATH + "help.png") @@ -71,11 +70,6 @@ def create_help_img(): def create_group_help_img(group_id: int): group_id = str(group_id) - try: - with open(DATA_PATH + "manager/plugin_list.json", "r", encoding="utf8") as f: - plugin_list = json.load(f) - except (ValueError, FileNotFoundError): - pass h = ( 100 + len(utility_help) * 24 @@ -89,7 +83,7 @@ def create_group_help_img(group_id: int): rst = "" i = 1 for cmd in entertainment_help.keys(): - flag, dfg = parse_cmd(cmd, group_id, plugin_list) + flag, dfg = parse_cmd(cmd, group_id) if dfg: cmd = rcmd(dfg) rst += f"【{flag}】{i}.{entertainment_help[cmd]}\n" @@ -100,7 +94,7 @@ def create_group_help_img(group_id: int): rst = "" i = 1 for cmd in utility_help.keys(): - flag, dfg = parse_cmd(cmd, group_id, plugin_list) + flag, dfg = parse_cmd(cmd, group_id) rst += f"【{flag}】{i}.{utility_help[cmd]}\n" i += 1 u.text((10, 10), "实用功能:", fill=(255, 255, 255)) @@ -118,7 +112,7 @@ def create_group_help_img(group_id: int): # A.text((width, 10), f'总开关【{"√" if data["总开关"] else "×"}】') A.text( (10, h * 0.68), - "大部分交互功能可以通过输入‘取消’,‘算了’来取消当前交互\n对真寻说 “真寻帮助 指令名” 获取对应详细帮助\n" + f"大部分交互功能可以通过输入‘取消’,‘算了’来取消当前交互\n对{NICKNAME}说 “{NICKNAME}帮助 指令名” 获取对应详细帮助\n" "可以通过 “滴滴滴- [消息]” 联系管理员(有趣的想法尽管来吧!<还有Bug和建议>)" f"\n[群管理员请看 管理员帮助(群主与管理员自带 {ADMIN_DEFAULT_AUTH} 级权限)]", ) @@ -130,12 +124,12 @@ def create_group_help_img(group_id: int): f"\t\t示例:开启签到\n" f"\t\t可以通过管理员开关自动发送消息(早晚安等)\n" f"\t\t^请查看管理员帮助^\n\n" - f"\t「如果真寻回复了一些不符合人设的话,那是因为每日白嫖的图灵次数已用完,使用的是备用接口【QAQ】」", + f"\t「如果{NICKNAME}回复了一些不符合人设的话,那是因为每日白嫖的图灵次数已用完,使用的是备用接口【QAQ】」", ) A.save(DATA_PATH + f"group_help/{group_id}.png") -def parse_cmd(cmd, group_id, plugin_list): +def parse_cmd(cmd, group_id): flag = "√" dfg = None if cmd.find("draw_card") != -1: @@ -148,9 +142,8 @@ def parse_cmd(cmd, group_id, plugin_list): elif cmd == "pixiv_s": cmd = "pixiv" dfg = "s" - if group_id in plugin_list[cmd]: - if not plugin_list[cmd][group_id]: - flag = "×" + if not group_manager.get_plugin_status(cmd, group_id): + flag = "×" if cmd in ["bt", "reimu", "nickname"]: flag = "- " return flag, dfg diff --git a/plugins/hook.py b/plugins/hook.py index c0c84be1..bede26c8 100644 --- a/plugins/hook.py +++ b/plugins/hook.py @@ -1,5 +1,6 @@ from nonebot.matcher import Matcher from nonebot.message import run_preprocessor, IgnoredException +from nonebot.adapters.cqhttp.exception import ActionFailed from nonebot.typing import T_State from nonebot.adapters.cqhttp import ( Bot, @@ -13,12 +14,16 @@ from configs.config import ( MALICIOUS_BAN_TIME, MALICIOUS_CHECK_TIME, MALICIOUS_BAN_COUNT, + CHECK_NOTICE_INFO_CD, + plugins2info_dict, ) from models.ban_user import BanUser from utils.utils import is_number, static_flmt, BanCheckLimiter from utils.message_builder import at from services.log import logger from models.level_user import LevelUser +from utils.static_data import group_manager +from utils.utils import FreqLimiter try: import ujson as json @@ -45,24 +50,34 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): time = str(int(time / 60)) + " 分" else: time = str(time) + " 分" - if event.message_type == "group": + if isinstance(event, GroupMessageEvent): if not static_flmt.check(event.user_id): raise IgnoredException("用户处于黑名单中") static_flmt.start_cd(event.user_id) if matcher.priority != 9: - await bot.send_group_msg( - group_id=event.group_id, - message=at(event.user_id) + BAN_RESULT + f" 在..在 {time}后才会理你喔", - ) + try: + await bot.send_group_msg( + group_id=event.group_id, + message=at(event.user_id) + + BAN_RESULT + + f" 在..在 {time}后才会理你喔", + ) + except ActionFailed: + pass else: if not static_flmt.check(event.user_id): raise IgnoredException("用户处于黑名单中") static_flmt.start_cd(event.user_id) if matcher.priority != 9: - await bot.send_private_msg( - user_id=event.user_id, - message=at(event.user_id) + BAN_RESULT + f" 在..在 {time}后才会理你喔", - ) + try: + await bot.send_private_msg( + user_id=event.user_id, + message=at(event.user_id) + + BAN_RESULT + + f" 在..在 {time}后才会理你喔", + ) + except ActionFailed: + pass raise IgnoredException("用户处于黑名单中") @@ -85,47 +100,153 @@ async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State if not static_flmt.check(event.user_id): return static_flmt.start_cd(event.user_id) - await bot.send_group_msg( - group_id=event.group_id, - message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟", - ) + try: + await bot.send_group_msg( + group_id=event.group_id, + message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟", + ) + except ActionFailed: + pass else: if not static_flmt.check(event.user_id): return static_flmt.start_cd(event.user_id) - await bot.send_private_msg( - user_id=event.user_id, - message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟", - ) + try: + await bot.send_private_msg( + user_id=event.user_id, + message=at(event.user_id) + "检测到恶意触发命令,您将被封禁 30 分钟", + ) + except ActionFailed: + pass raise IgnoredException("检测到恶意触发命令") _blmt.add(f'{event.user_id}{state["_prefix"]["raw_command"]}') +_flmt = FreqLimiter(CHECK_NOTICE_INFO_CD) +_flmt_g = FreqLimiter(CHECK_NOTICE_INFO_CD) +_flmt_s = FreqLimiter(CHECK_NOTICE_INFO_CD) +_flmt_c = FreqLimiter(CHECK_NOTICE_INFO_CD) + + # 权限检测 @run_preprocessor async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): - if not isinstance(event, MessageEvent) or await BanUser.is_ban(event.user_id): + if ( + not isinstance(event, MessageEvent) + or await BanUser.is_ban(event.user_id) + or str(event.user_id) in bot.config.superusers + ): return - if matcher.module in admin_plugins_auth.keys() and matcher.priority not in [1, 9]: - if event.message_type == "group": + module = matcher.module + if module in admin_plugins_auth.keys() and matcher.priority not in [1, 9]: + if isinstance(event, GroupMessageEvent): + # 个人权限 if not await LevelUser.check_level( - event.user_id, event.group_id, admin_plugins_auth[matcher.module] + event.user_id, event.group_id, admin_plugins_auth[module] ): - await bot.send_group_msg( - group_id=event.group_id, - message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:" - f"{admin_plugins_auth[matcher.module]}", - ) + try: + if _flmt.check(event.user_id): + _flmt.start_cd(event.user_id) + await bot.send_group_msg( + group_id=event.group_id, + message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:" + f"{admin_plugins_auth[module]}", + ) + except ActionFailed: + pass raise IgnoredException("权限不足") else: if not await LevelUser.check_level( - event.user_id, 0, admin_plugins_auth[matcher.module] + event.user_id, 0, admin_plugins_auth[module] ): - await bot.send_private_msg( - user_id=event.user_id, - message=f"你的权限不足喔,该功能需要的权限等级:{admin_plugins_auth[matcher.module]}", - ) + try: + await bot.send_private_msg( + user_id=event.user_id, + message=f"你的权限不足喔,该功能需要的权限等级:{admin_plugins_auth[module]}", + ) + except ActionFailed: + pass raise IgnoredException("权限不足") + if module in plugins2info_dict.keys(): + if isinstance(event, GroupMessageEvent): + # 群权限 + if plugins2info_dict[module]["level"] > group_manager.get_group_level( + str(event.group_id) + ): + try: + if _flmt_g.check(event.user_id): + _flmt_g.start_cd(event.user_id) + await bot.send_group_msg( + group_id=event.group_id, message="群权限不足..." + ) + except ActionFailed: + pass + raise IgnoredException("群权限不足") + # 插件状态 + if not group_manager.get_plugin_status(module, str(event.group_id)): + try: + if _flmt_s.check(event.group_id): + _flmt_s.start_cd(event.group_id) + await bot.send_group_msg( + group_id=event.group_id, message="该群未开启此功能.." + ) + except ActionFailed: + pass + raise IgnoredException("未开启此功能...") + # 管理员禁用 + if not group_manager.get_plugin_status( + f"{module}:super", str(event.group_id) + ): + try: + if _flmt_s.check(event.group_id): + _flmt_s.start_cd(event.group_id) + await bot.send_group_msg( + group_id=event.group_id, message="管理员禁用了此群该功能..." + ) + except ActionFailed: + pass + raise IgnoredException("管理员禁用了此群该功能...") + # 群聊禁用 + if not group_manager.get_plugin_status(module, block_type="group"): + try: + if _flmt_c.check(event.group_id): + _flmt_c.start_cd(event.group_id) + await bot.send_group_msg( + group_id=event.group_id, message="该功能在群聊中已被禁用..." + ) + except ActionFailed: + pass + raise IgnoredException("该插件在群聊中已被禁用...") + else: + # 私聊禁用 + if not group_manager.get_plugin_status(module, block_type="private"): + try: + if _flmt_c.check(event.user_id): + _flmt_c.start_cd(event.user_id) + await bot.send_private_msg( + user_id=event.user_id, message="该功能在私聊中已被禁用..." + ) + except ActionFailed: + pass + raise IgnoredException("该插件在私聊中已被禁用...") + # 维护 + if not group_manager.get_plugin_status( + module, block_type="all" + ) and not group_manager.check_group_is_white(event.group_id): + try: + if _flmt_c.check(event.group_id): + _flmt_c.start_cd(event.group_id) + if isinstance(event, GroupMessageEvent): + await bot.send_group_msg( + group_id=event.group_id, message="此功能正在维护..." + ) + else: + await bot.send_private_msg( + user_id=event.user_id, message="此功能正在维护..." + ) + except ActionFailed: + pass + raise IgnoredException("此功能正在维护...") # 为什么AI会自己和自己聊天 @@ -145,5 +266,3 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): if matcher.type == "message": if state["_prefix"]["raw_command"] and matcher.module == "ai": raise IgnoredException("有命令就别说话了") - - diff --git a/plugins/jitang.py b/plugins/jitang.py index 1f57fa26..26271453 100644 --- a/plugins/jitang.py +++ b/plugins/jitang.py @@ -5,9 +5,10 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from nonebot.typing import T_State import aiohttp from asyncio.exceptions import TimeoutError +from configs.config import NICKNAME __plugin_name__ = "鸡汤" -__plugin_usage__ = "用法: 发送’鸡汤‘,真寻亲自为你喝鸡汤" +__plugin_usage__ = f"用法: 发送’鸡汤‘,{NICKNAME}亲自为你喝鸡汤" url = "https://v2.alapi.cn/api/soul" diff --git a/plugins/move_img/__init__.py b/plugins/move_img/__init__.py index 2bc033b6..65fb7b5f 100644 --- a/plugins/move_img/__init__.py +++ b/plugins/move_img/__init__.py @@ -7,6 +7,7 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from configs.config import IMAGE_DIR_LIST from utils.utils import is_number, cn2py from configs.path_config import IMAGE_PATH +from pathlib import Path __plugin_name__ = "移动图片" @@ -59,31 +60,32 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @move_img.got("id", prompt="要移动的图片id是?") async def _(bot: Bot, event: MessageEvent, state: T_State): img_id = state["id"] - source_path = IMAGE_PATH + cn2py(state["source_path"]) - destination_path = IMAGE_PATH + cn2py(state["destination_path"]) + source_path = Path(IMAGE_PATH) / cn2py(state["source_path"]) + destination_path = Path(IMAGE_PATH) / cn2py(state["destination_path"]) + destination_path.mkdir(parents=True, exist_ok=True) max_id = len(os.listdir(source_path)) - 1 des_max_id = len(os.listdir(destination_path)) if int(img_id) > max_id or int(img_id) < 0: await move_img.finish(f"Id超过上下限,上限:{max_id}", at_sender=True) try: os.rename( - source_path + img_id + ".jpg", destination_path + str(des_max_id) + ".jpg" + source_path / f"{img_id}.jpg", destination_path / f"{des_max_id}.jpg" ) logger.info( - f"移动 {source_path}{img_id}.jpg ---> {destination_path}{des_max_id} 移动成功" + f"移动 {source_path}/{img_id}.jpg ---> {destination_path}/{des_max_id} 移动成功" ) except Exception as e: logger.warning( - f"移动 {source_path}{img_id}.jpg ---> {destination_path}{des_max_id} 移动失败 e:{e}" + f"移动 {source_path}/{img_id}.jpg ---> {destination_path}/{des_max_id} 移动失败 e:{e}" ) await move_img.finish(f"移动图片id:{img_id} 失败了...", at_sender=True) if max_id > 0: try: - os.rename(source_path + str(max_id) + ".jpg", source_path + img_id + ".jpg") - logger.info(f"{source_path}{max_id}.jpg 替换 {source_path}{img_id}.jpg 成功") + os.rename(source_path / f"{max_id}.jpg", source_path / f"{img_id}.jpg") + logger.info(f"{source_path}/{max_id}.jpg 替换 {source_path}/{img_id}.jpg 成功") except Exception as e: logger.warning( - f"{source_path}{max_id}.jpg 替换 {source_path}{img_id}.jpg 失败 e:{e}" + f"{source_path}/{max_id}.jpg 替换 {source_path}/{img_id}.jpg 失败 e:{e}" ) await move_img.finish(f"替换图片id:{max_id} -> {img_id} 失败了...", at_sender=True) logger.info( diff --git a/plugins/mute.py b/plugins/mute.py index 23763ecb..3f124ef0 100644 --- a/plugins/mute.py +++ b/plugins/mute.py @@ -11,7 +11,7 @@ from utils.image_utils import get_img_hash from services.log import logger import aiohttp import aiofiles -from configs.config import MUTE_DEFAULT_COUNT, MUTE_DEFAULT_TIME, MUTE_DEFAULT_DURATION +from configs.config import MUTE_DEFAULT_COUNT, MUTE_DEFAULT_TIME, MUTE_DEFAULT_DURATION, NICKNAME try: import ujson as json @@ -105,7 +105,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): user_id=event.user_id, duration=mute_data[group_id]["duration"], ) - await mute.send("检测到恶意刷屏,真寻要把你关进小黑屋!", at_sender=True) + await mute.send(f"检测到恶意刷屏,{NICKNAME}要把你关进小黑屋!", at_sender=True) mute_dict[event.user_id]["count"] = 0 logger.info( f"USER {event.user_id} GROUP {event.group_id} " diff --git a/plugins/nickname.py b/plugins/nickname.py index 7d2a8aec..97c6ee91 100644 --- a/plugins/nickname.py +++ b/plugins/nickname.py @@ -8,11 +8,12 @@ from models.friend_user import FriendUser import random from models.ban_user import BanUser from services.log import logger +from configs.config import NICKNAME __plugin_name__ = "昵称系统" -__plugin_usage__ = "用法:\n" "以后叫我 [名称]\n" "真寻我是谁" +__plugin_usage__ = f"用法:\n以后叫我 [名称]\n{NICKNAME}我是谁" nickname = on_command( "nickname", @@ -46,13 +47,13 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): await nickname.send( random.choice( [ - "好啦好啦,我知道啦,{},以后就这么叫你吧", - "嗯嗯,小真寻记住你的昵称了哦,{}", - "好突然,突然要叫你昵称什么的...{}..", - "小真寻会好好记住的{}的,放心吧", - "好..好.,那窝以后就叫你{}了.", + f"好啦好啦,我知道啦,{msg},以后就这么叫你吧", + f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}", + f"好突然,突然要叫你昵称什么的...{msg}..", + f"{NICKNAME}会好好记住的{msg}的,放心吧", + f"好..好.,那窝以后就叫你{msg}了.", ] - ).format(msg) + ) ) logger.info(f"USER {event.user_id} GROUP {event.group_id} 设置群昵称 {msg}") else: @@ -71,13 +72,13 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): await nickname.send( random.choice( [ - "好啦好啦,我知道啦,{},以后就这么叫你吧", - "嗯嗯,小真寻记住你的昵称了哦,{}", - "好突然,突然要叫你昵称什么的...{}..", - "小真寻会好好记住的{}的,放心吧", - "好..好.,那窝以后就叫你{}了.", + f"好啦好啦,我知道啦,{msg},以后就这么叫你吧", + f"嗯嗯,{NICKNAME}记住你的昵称了哦,{msg}", + f"好突然,突然要叫你昵称什么的...{msg}..", + f"{NICKNAME}会好好记住的{msg}的,放心吧", + f"好..好.,那窝以后就叫你{msg}了.", ] - ).format(msg) + ) ) logger.info(f"USER {event.user_id} 设置昵称 {msg}") else: @@ -97,14 +98,14 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): await my_nickname.send( random.choice( [ - "我肯定记得你啊,你是{}啊", - "我不会忘记你的,你也不要忘记我!{}", - "哼哼,真寻记忆力可是很好的,{}", - "嗯?你是失忆了嘛...{}..", - "不要小看真寻的记忆力啊!笨蛋{}!QAQ", - "哎?{}..怎么了吗..突然这样问..", + f"我肯定记得你啊,你是{nickname_}啊", + f"我不会忘记你的,你也不要忘记我!{nickname_}", + f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}", + f"嗯?你是失忆了嘛...{nickname_}..", + f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ", + f"哎?{nickname_}..怎么了吗..突然这样问..", ] - ).format(nickname_) + ) ) else: nickname_ = event.sender.card if event.sender.card else event.sender.nickname @@ -122,14 +123,14 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): await my_nickname.send( random.choice( [ - "我肯定记得你啊,你是{}啊", - "我不会忘记你的,你也不要忘记我!{}", - "哼哼,真寻记忆力可是很好的,{}", - "嗯?你是失忆了嘛...{}..", - "不要小看真寻的记忆力啊!笨蛋{}!QAQ", - "哎?{}..怎么了吗..突然这样问..", + f"我肯定记得你啊,你是{nickname_}啊", + f"我不会忘记你的,你也不要忘记我!{nickname_}", + f"哼哼,{NICKNAME}记忆力可是很好的,{nickname_}", + f"嗯?你是失忆了嘛...{nickname_}..", + f"不要小看{NICKNAME}的记忆力啊!笨蛋{nickname_}!QAQ", + f"哎?{nickname_}..怎么了吗..突然这样问..", ] - ).format(nickname_) + ) ) else: nickname_ = (await bot.get_stranger_info(user_id=event.user_id))["nickname"] @@ -149,13 +150,13 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): await cancel_nickname.send( random.choice( [ - "呜..真寻睡一觉就会忘记的..和梦一样..{}", - "窝知道了..{}..", - "是真寻哪里做的不好嘛..好吧..晚安{}", - "呃,{},下次我绝对绝对绝对不会再忘记你!", - "可..可恶!{}!太可恶了!呜", + f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}", + f"窝知道了..{nickname_}..", + f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}", + f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!", + f"可..可恶!{nickname_}!太可恶了!呜", ] - ).format(nickname_) + ) ) await GroupInfoUser.set_group_member_nickname(event.user_id, event.group_id, "") await BanUser.ban(event.user_id, 9, 60) @@ -170,13 +171,13 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): await cancel_nickname.send( random.choice( [ - "呜..真寻睡一觉就会忘记的..和梦一样..{}", - "窝知道了..{}..", - "是真寻哪里做的不好嘛..好吧..晚安 {}", - "呃,{},下次我绝对绝对绝对不会再忘记你!", - "可..可恶!{}!太可恶了!呜", + f"呜..{NICKNAME}睡一觉就会忘记的..和梦一样..{nickname_}", + f"窝知道了..{nickname_}..", + f"是{NICKNAME}哪里做的不好嘛..好吧..晚安{nickname_}", + f"呃,{nickname_},下次我绝对绝对绝对不会再忘记你!", + f"可..可恶!{nickname_}!太可恶了!呜", ] - ).format(nickname_) + ) ) await FriendUser.get_user_name(event.user_id) await BanUser.ban(event.user_id, 9, 60) diff --git a/plugins/nonebot_plugin_manager/__init__.py b/plugins/nonebot_plugin_manager/__init__.py deleted file mode 100644 index 52fe47b0..00000000 --- a/plugins/nonebot_plugin_manager/__init__.py +++ /dev/null @@ -1,122 +0,0 @@ -from nonebot.plugin import on_shell_command, get_loaded_plugins, export -from nonebot.matcher import Matcher -from nonebot.typing import T_State -from nonebot.exception import IgnoredException -from nonebot.message import run_preprocessor -from nonebot.adapters.cqhttp import ( - Event, - Bot, - GroupMessageEvent, - PrivateMessageEvent, - MessageEvent, -) -from configs.config import plugins2info_dict -from utils.utils import FreqLimiter -from models.ban_user import BanUser -from .data import ( - block_plugin, - unblock_plugin, - get_group_plugin_list, - auto_update_plugin_list, -) -from .parser import npm_parser - -# 导出给其他插件使用 -export = export() -export.block_plugin = block_plugin -export.unblock_plugin = unblock_plugin -export.get_group_plugin_list = get_group_plugin_list - -# 注册 shell_like 事件响应器 -plugin_manager = on_shell_command("npm", parser=npm_parser, priority=1) - -flmt = FreqLimiter(60) - - -# 在 Matcher 运行前检测其是否启用 -@run_preprocessor -async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State): - if not isinstance(event, MessageEvent) and matcher.module != 'poke': - return - plugin = matcher.module - group_id = _get_group_id(event) - loaded_plugin_list = _get_loaded_plugin_list() - plugin_list = auto_update_plugin_list(loaded_plugin_list) - - # 无视本插件的 Matcher - if ( - plugin not in plugins2info_dict - or matcher.priority in [1, 9] - or await BanUser.is_ban(event.user_id) - ): - return - if isinstance(event, PrivateMessageEvent) and plugin_list[plugin]["default"]: - return - if not plugin_list[plugin]["default"]: - if str(event.user_id) in bot.config.superusers: - return - if isinstance(event, GroupMessageEvent): - if flmt.check(event.group_id): - flmt.start_cd(event.group_id) - await bot.send_group_msg(group_id=event.group_id, message="此功能正在维护...") - else: - if flmt.check(event.user_id): - flmt.start_cd(event.user_id) - await bot.send_private_msg(user_id=event.user_id, message="此功能正在维护...") - raise IgnoredException(f"Nonebot Plugin Manager has blocked {plugin} !") - - if group_id in plugin_list[plugin]: - if not plugin_list[plugin][group_id]: - if plugin != "ai" and matcher.type == "message": - if flmt.check(event.group_id): - flmt.start_cd(event.group_id) - await bot.send_group_msg( - group_id=event.group_id, message="该群未开启此功能.." - ) - raise IgnoredException(f"Nonebot Plugin Manager has blocked {plugin} !") - - -@plugin_manager.handle() -async def _(bot: Bot, event: Event, state: T_State): - args = state["args"] - group_id = _get_group_id(event) - is_admin = _is_admin(event) - is_superuser = _is_superuser(bot, event) - if group_id == 0: - group_id = "default" - - if hasattr(args, "handle"): - await plugin_manager.finish(args.handle(args, group_id, is_admin, is_superuser)) - - -# 获取插件列表,并自动排除本插件 -def _get_loaded_plugin_list() -> list: - return list( - filter( - lambda plugin: plugin != "nonebot_plugin_manager", - map(lambda plugin: plugin.name, get_loaded_plugins()), - ) - ) - - -def _get_group_id(event: Event) -> str: - try: - group_id = event.group_id - except AttributeError: - group_id = "default" - return str(group_id) if group_id else "default" - - -def _is_admin(event: Event) -> bool: - return ( - event.sender.role in ["admin", "owner"] - if isinstance(event, GroupMessageEvent) - else False - ) - - -def _is_superuser(bot: Bot, event: Event) -> bool: - return str(event.user_id) in bot.config.superusers - - -plugins_dict = {} diff --git a/plugins/nonebot_plugin_manager/data.py b/plugins/nonebot_plugin_manager/data.py deleted file mode 100644 index ed5363c5..00000000 --- a/plugins/nonebot_plugin_manager/data.py +++ /dev/null @@ -1,121 +0,0 @@ -import json -import httpx -from pathlib import Path -from configs.config import plugins2info_dict - -_DATA_PATH = Path() / "data" / "manager" / "plugin_list.json" - - -def get_store_plugin_info(plugin: str) -> str: - store_plugin_list = _get_store_plugin_list() - if plugin in store_plugin_list: - plugin = store_plugin_list[plugin] - return ( - f"ID: {plugin['id']}\n" - f"Name: {plugin['name']}\n" - f"Description: {plugin['desc']}\n" - f"Version: {httpx.get('https://pypi.org/pypi/'+plugin['link']+'/json').json()['info']['version']}\n" - f"Author: {plugin['author']}\n" - f"Repo: https://github.com/{plugin['repo']}" - ) - else: - return "查无此插件!" - - -def get_group_plugin_list(group_id: str) -> dict: - plugin_list = _load_plugin_list() - group_plugin_list = {} - for plugin in plugin_list: - if group_id in plugin_list[plugin]: - group_plugin_list[plugin] = plugin_list[plugin][group_id] - else: - group_plugin_list[plugin] = plugin_list[plugin]["default"] - return group_plugin_list - - -def get_store_pulgin_list() -> str: - message = "商店插件列表如下:" - for plugin in _get_store_plugin_list(): - if plugin in _load_plugin_list() or plugin == "nonebot_plugin_manager": - message += f"\n[o] {plugin}" - else: - message += f"\n[x] {plugin}" - return message - - -def auto_update_plugin_list(loaded_plugin_list: list, keep_history: bool = False): - plugin_list = _load_plugin_list() - for plugin in loaded_plugin_list: - if plugin not in plugin_list: - plugin_list[plugin] = {"default": True} - if not keep_history: - plugin_list = { - key: plugin_list[key] for key in plugin_list if key in loaded_plugin_list - } - _dump_plugin_list(plugin_list) - return plugin_list - - -def block_plugin(group_id: str, *plugins: str): - return _update_plugin_list(group_id, True, *plugins) - - -def unblock_plugin(group_id: str, *plugins: str): - return _update_plugin_list(group_id, False, *plugins) - - -# 获取商店插件列表 -def _get_store_plugin_list() -> dict: - store_plugin_list = {} - for plugin in httpx.get( - "https://cdn.jsdelivr.net/gh/nonebot/nonebot2@master/docs/.vuepress/public/plugins.json" - ).json(): - store_plugin_list.update({plugin["id"]: plugin}) - return store_plugin_list - - -# 更新插件列表 -def _update_plugin_list(group_id: str, block: bool, *plugins: str) -> str: - plugin_list = _load_plugin_list() - message = "结果如下:" - operate = "屏蔽" if block else "启用" - for plugin in plugins: - for values in plugins2info_dict.values(): - if plugin in values['cmd']: - plugin = list(plugins2info_dict.keys())[list(plugins2info_dict.values()).index(values)] - # print(plugin) - break - message += "\n" - if plugin in plugin_list: - if ( - not group_id in plugin_list[plugin] - or plugin_list[plugin][group_id] == block - ): - plugin_list[plugin][group_id] = not block - message += f"插件{plugin}{operate}成功!" - print(plugin_list[plugin][group_id]) - else: - message += f"插件{plugin}已经{operate}!" - else: - message += f"插件{plugin}不存在!" - _dump_plugin_list(plugin_list) - return message - - -# 加载插件列表 -def _load_plugin_list() -> dict: - try: - return json.load(_DATA_PATH.open("r", encoding="utf-8")) - except FileNotFoundError: - return {} - - -# 保存插件列表 -def _dump_plugin_list(plugin_list: dict): - _DATA_PATH.parent.mkdir(parents=True, exist_ok=True) - json.dump( - plugin_list, - _DATA_PATH.open("w", encoding="utf-8"), - indent=4, - separators=(",", ": "), - ) diff --git a/plugins/nonebot_plugin_manager/handle.py b/plugins/nonebot_plugin_manager/handle.py deleted file mode 100644 index 1900ed2f..00000000 --- a/plugins/nonebot_plugin_manager/handle.py +++ /dev/null @@ -1,138 +0,0 @@ -from argparse import Namespace - -from .data import * - - -def handle_list( - args: Namespace, - group_id: str, - is_admin: bool, - is_superuser: bool, -) -> str: - message = "" - - if args.store: - if is_superuser: - return get_store_pulgin_list() - else: - return "获取商店插件列表需要超级用户权限!" - - if args.default: - if is_superuser: - group_id = "default" - message += "默认" - else: - return "获取默认插件列表需要超级用户权限!" - - if args.group: - if is_superuser: - group_id = args.group - message += f"群{args.group}" - else: - return "获取指定群插件列表需要超级用户权限!" - - message += "插件列表如下:\n" - message += "\n".join( - f"[{'o' if get_group_plugin_list(group_id)[plugin] else 'x'}] {plugin}" - for plugin in get_group_plugin_list(group_id) - ) - return message - - -def handle_block( - args: Namespace, - group_id: str, - is_admin: bool, - is_superuser: bool, -) -> str: - - if not is_admin and not is_superuser: - return "管理插件需要群管理员权限!" - - message = "" - - if args.default: - if is_superuser: - group_id = "default" - message += "默认" - else: - return "管理默认插件需要超级用户权限!" - - if args.group: - if is_superuser: - group_id = args.group - message += f"群{args.group}" - else: - return "管理指定群插件需要超级用户权限!" - - message += block_plugin(group_id, *args.plugins) - return message - - -def handle_unblock( - args: Namespace, - group_id: str, - is_admin: bool, - is_superuser: bool, -) -> str: - message = "" - - if not is_admin and not is_superuser: - return "管理插件需要群管理员权限!" - - if args.default: - if is_superuser: - group_id = "default" - message += "默认" - else: - return "管理默认插件需要超级用户权限!" - - if args.group: - if is_superuser: - group_id = args.group - message += f"群{args.group}" - else: - return "管理指定群插件需要超级用户权限!" - - message += unblock_plugin(group_id, *args.plugins) - return message - - -def handle_info( - args: Namespace, - group_id: str, - is_admin: bool, - is_superuser: bool, -) -> str: - - if not is_admin and not is_superuser: - return "管理插件需要超级权限!" - - return get_store_plugin_info(args.plugin) - - -def handle_install( - args: Namespace, - group_id: str, - is_admin: bool, - is_superuser: bool, -) -> str: - pass - - -def handle_update( - args: Namespace, - group_id: str, - is_admin: bool, - is_superuser: bool, -) -> str: - pass - - -def handle_uninstall( - args: Namespace, - group_id: str, - is_admin: bool, - is_superuser: bool, -) -> str: - pass diff --git a/plugins/nonebot_plugin_manager/parser.py b/plugins/nonebot_plugin_manager/parser.py deleted file mode 100644 index 71d2455d..00000000 --- a/plugins/nonebot_plugin_manager/parser.py +++ /dev/null @@ -1,60 +0,0 @@ -from nonebot.rule import ArgumentParser - -from .handle import * - -npm_parser = ArgumentParser("npm", add_help=False) -npm_parser.add_argument( - "-h", "--help", action="store_true", help="show this help message and exit" -) - -npm_subparsers = npm_parser.add_subparsers() - -list_parser = npm_subparsers.add_parser("list", help="show plugin list") -list_parser.add_argument( - "-s", "--store", action="store_true", help="show plugin store list" -) -list_parser.add_argument( - "-d", "--default", action="store_true", help="show default plugin list" -) -list_parser.add_argument("-g", "--group", action="store", help="show group plugin list") -list_parser.set_defaults(handle=handle_list) - -block_parser = npm_subparsers.add_parser("block", help="block plugin") -block_parser.add_argument("plugins", nargs="*", help="plugins you want to block") -block_parser.add_argument("-d", "--default", action="store_true", help="set default") -block_parser.add_argument("-a", "--all", action="store_true", help="select all plugin") -block_parser.add_argument("-g", "--group", action="store", help="set in group") -block_parser.set_defaults(handle=handle_block) - -unblock_parser = npm_subparsers.add_parser("unblock", help="unblock plugin") -unblock_parser.add_argument("plugins", nargs="*", help="plugins you want to unblock") -unblock_parser.add_argument("-d", "--default", action="store_true", help="set default") -unblock_parser.add_argument( - "-a", "--all", action="store_true", help="select all plugin" -) -unblock_parser.add_argument("-g", "--group", action="store", help="set in group") -unblock_parser.set_defaults(handle=handle_unblock) - -info_parser = npm_subparsers.add_parser("info", help="show plugin info") -info_parser.add_argument("plugin", help="plugins you want to know") -info_parser.set_defaults(handle=handle_info) - -install_parser = npm_subparsers.add_parser("install", help="install plugin") -install_parser.add_argument("plugins", nargs="*", help="plugins you want to install") -install_parser.add_argument("-i", "--index", action="store", help="point to a mirror") -install_parser.set_defaults(handle=handle_install) - -update_parser = npm_subparsers.add_parser("update", help="update plugin") -update_parser.add_argument("plugins", nargs="*", help="plugins you want to update") -update_parser.add_argument("-a", "--all", action="store_true", help="select all plugin") -update_parser.add_argument("-i", "--index", action="store", help="point to a mirror") -update_parser.set_defaults(handle=handle_update) - -uninstall_parser = npm_subparsers.add_parser("uninstall", help="uninstall plugin") -uninstall_parser.add_argument( - "plugins", nargs="*", help="plugins you want to uninstall" -) -uninstall_parser.add_argument( - "-a", "--all", action="store_true", help="select all plugin" -) -uninstall_parser.set_defaults(handle=handle_uninstall) diff --git a/plugins/one_friend/__init__.py b/plugins/one_friend/__init__.py index 2ae2763f..60a9217d 100644 --- a/plugins/one_friend/__init__.py +++ b/plugins/one_friend/__init__.py @@ -15,7 +15,7 @@ __plugin_name__ = "我有一个朋友" __plugin_usage__ = "用法:我有一个朋友说/问 [消息] [at](不艾特则群员随机)" one_friend = on_regex( - "^我.*?朋友.*?(想问问|说|让我问问|想问|让我问|想知道|让我帮他问问|让我" "帮他问|让我帮忙问|让我帮忙问问|问).*", + "^我.*?朋友.*?(想问问|说|让我问问|想问|让我问|想知道|让我帮他问问|让我帮他问|让我帮忙问|让我帮忙问问|问).*", priority=5, block=True, ) @@ -41,10 +41,13 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): ) ] ) + user_name = '朋友' else: qq = qq[0] + at_user = await bot.get_group_member_info(group_id=event.group_id, user_id=qq) + user_name = at_user['card'] if at_user['card'] else at_user['nickname'] msg = re.search( - r"^我.*?朋友.*?" r"(想问问|说|让我问问|想问|让我问|想知道|让我帮他问问|让我帮他问|让我帮忙问|让我帮忙问问|问)(.*)", msg + r"^我.*?朋友.*?(想问问|说|让我问问|想问|让我问|想知道|让我帮他问问|让我帮他问|让我帮忙问|让我帮忙问问|问)(.*)", msg ) msg = msg.group(2) if not msg: @@ -52,9 +55,8 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): msg = msg.replace("他", "我").replace("她", "我").replace("它", "我") ava = CreateImg(100, 100, background=BytesIO(await get_pic(qq))) ava.circle() - text = CreateImg(60, 30, font_size=30) - text.text((0, 0), "朋友") - # text.show() + text = CreateImg(300, 30, font_size=30) + text.text((0, 0), user_name) A = CreateImg(700, 150, font_size=25, color="white") A.paste(ava, (30, 25), True) A.paste(text, (150, 40)) diff --git a/plugins/open_cases/__init__.py b/plugins/open_cases/__init__.py index d779667c..4a8a1ee7 100644 --- a/plugins/open_cases/__init__.py +++ b/plugins/open_cases/__init__.py @@ -15,6 +15,7 @@ from .open_cases_c import ( open_shilian_case, ) from .utils import util_get_buff_price, util_get_buff_img, update_count_daily +from configs.config import NICKNAME __plugin_name__ = "开箱" __plugin_usage__ = ( @@ -26,7 +27,7 @@ __plugin_usage__ = ( "3.命悬一线武器箱\n\t" "4.裂空武器箱\n\t" "5.光谱武器箱\n" - "示例:小真寻开箱 突围大行动(不输入指定武器箱则随机)\n" + f"示例:{NICKNAME}开箱 突围大行动(不输入指定武器箱则随机)\n" "示例:我的开箱(开箱统计)\n" "示例:群开箱统计\n" "示例:我的金色" diff --git a/plugins/parse_bilibili_json.py b/plugins/parse_bilibili_json.py index 2cee2340..ff02bfe5 100644 --- a/plugins/parse_bilibili_json.py +++ b/plugins/parse_bilibili_json.py @@ -2,17 +2,21 @@ from nonebot import on_message from services.log import logger from nonebot.adapters.cqhttp import Bot, GroupMessageEvent from nonebot.typing import T_State -from utils.utils import get_message_json, get_local_proxy -import json +from utils.utils import get_message_json, get_local_proxy, get_message_text from utils.user_agent import get_user_agent from nonebot.adapters.cqhttp.permission import GROUP from bilibili_api import video from utils.message_builder import image from models.group_remind import GroupRemind from nonebot.adapters.cqhttp.exception import ActionFailed +from utils.image_utils import CreateImg +from utils.browser import get_browser +from configs.path_config import IMAGE_PATH +import asyncio import time import aiohttp from bilibili_api import settings +import ujson as json if get_local_proxy(): settings.proxy = get_local_proxy() @@ -22,43 +26,110 @@ parse_bilibili_json = on_message(priority=1, permission=GROUP, block=False) @parse_bilibili_json.handle() async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - if await GroupRemind.get_status(event.group_id, "blpar") and get_message_json( - event.json() - ): - try: - data = json.loads(get_message_json(event.json())[0]["data"]) - except (IndexError, KeyError): - return - if data: - if data.get("desc") == "哔哩哔哩": + if await GroupRemind.get_status(event.group_id, "blpar"): + vd_info = None + if get_message_json(event.json()): + try: + data = json.loads(get_message_json(event.json())[0]["data"]) + except (IndexError, KeyError): + data = None + if data: + # 转发视频 + if data.get("desc") == "哔哩哔哩": + async with aiohttp.ClientSession( + headers=get_user_agent() + ) as session: + async with session.get( + data["meta"]["detail_1"]["qqdocurl"], + proxy=get_local_proxy(), + timeout=7, + ) as response: + url = str(response.url).split("?")[0] + bvid = url.split("/")[-1] + vd_info = await video.Video(bvid=bvid).get_info() + # 转发专栏 + if ( + data.get("meta") + and data["meta"].get("news") + and data["meta"]["news"].get("desc") == "哔哩哔哩专栏" + ): + url = data["meta"]["news"]["jumpUrl"] + page = None + try: + browser = await get_browser() + if not browser: + return + page = await browser.new_page( + user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" + " (KHTML, like Gecko) Chrome/93.0.4530.0 Safari/537.36" + ) + await page.goto(url, wait_until="networkidle", timeout=10000) + await page.set_viewport_size({"width": 2560, "height": 1080}) + await page.click("#app > div") + # await page.click("text=继续阅读全文", timeout=3000) + div = await page.query_selector("#app > div") + await div.screenshot( + path=f"{IMAGE_PATH}/temp/cv_{event.user_id}.png", + timeout=100000, + ) + await asyncio.get_event_loop().run_in_executor( + None, resize, f"{IMAGE_PATH}/temp/cv_{event.user_id}.png" + ) + await parse_bilibili_json.send( + image(f"cv_{event.user_id}.png", "temp") + ) + await page.close() + logger.info( + f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}" + ) + except Exception as e: + logger.error(f"尝试解析bilibili专栏 {url} 失败 {type(e)}:{e}") + if page: + await page.close() + return + # BV + if get_message_text(event.json()): + msg = get_message_text(event.json()) + if "https://b23.tv" in msg: + url = "https://" + msg[msg.find("b23.tv") : msg.find("b23.tv") + 13] async with aiohttp.ClientSession(headers=get_user_agent()) as session: async with session.get( - data["meta"]["detail_1"]["qqdocurl"], + url, proxy=get_local_proxy(), timeout=7, ) as response: url = str(response.url).split("?")[0] bvid = url.split("/")[-1] vd_info = await video.Video(bvid=bvid).get_info() - aid = vd_info["aid"] - title = vd_info["title"] - author = vd_info["owner"]["name"] - reply = vd_info["stat"]["reply"] # 回复 - favorite = vd_info["stat"]["favorite"] # 收藏 - coin = vd_info["stat"]["coin"] # 投币 - # like = vd_info['stat']['like'] # 点赞 - # danmu = vd_info['stat']['danmaku'] # 弹幕 - date = time.strftime("%Y-%m-%d", time.localtime(vd_info["ctime"])) - try: - await parse_bilibili_json.send( - image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n" - f"UP:{author}\n" - f"上传日期:{date}\n" - f"回复:{reply},收藏:{favorite},投币:{coin}\n" - f"{url}" - ) - except ActionFailed: - logger.warning(f"{event.group_id} 发送bilibili解析失败") - logger.info( - f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}" + if "https://www.bilibili.com/video" in msg: + url = msg.split("?")[0] + msg = url.split("/")[-1] + vd_info = await video.Video(bvid=msg).get_info() + if vd_info: + aid = vd_info["aid"] + title = vd_info["title"] + author = vd_info["owner"]["name"] + reply = vd_info["stat"]["reply"] # 回复 + favorite = vd_info["stat"]["favorite"] # 收藏 + coin = vd_info["stat"]["coin"] # 投币 + # like = vd_info['stat']['like'] # 点赞 + # danmu = vd_info['stat']['danmaku'] # 弹幕 + date = time.strftime("%Y-%m-%d", time.localtime(vd_info["ctime"])) + try: + await parse_bilibili_json.send( + image(vd_info["pic"]) + f"\nav{aid}\n标题:{title}\n" + f"UP:{author}\n" + f"上传日期:{date}\n" + f"回复:{reply},收藏:{favorite},投币:{coin}\n" + f"{url}" ) + except ActionFailed: + logger.warning(f"{event.group_id} 发送bilibili解析失败") + logger.info( + f"USER {event.user_id} GROUP {event.group_id} 解析bilibili转发 {url}" + ) + + +def resize(path: str): + A = CreateImg(0, 0, background=path, ratio=0.5) + A.save(path) diff --git a/plugins/pixiv/__init__.py b/plugins/pixiv/__init__.py index 22481b2b..7b55d199 100644 --- a/plugins/pixiv/__init__.py +++ b/plugins/pixiv/__init__.py @@ -81,7 +81,6 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State): user_id=event.user_id, message=f"P站排行榜或搜图正在搜索噢,不要重复触发命令呀" ) raise IgnoredException("pixiv插件正在访问!") - _ulmt.set_True(event.user_id) @run_postprocessor @@ -106,6 +105,7 @@ pixiv_keyword = on_command("搜图", priority=5, block=True) @pixiv_rank.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = get_message_text(event.json()).strip() + _ulmt.set_True(event.user_id) msg = msg.split(" ") msg = [m for m in msg if m] if not msg: @@ -150,6 +150,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @pixiv_keyword.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = get_message_text(event.json()).strip() + _ulmt.set_True(event.user_id) if event.message_type == "group": if msg.find("r18") != -1: await pixiv_keyword.finish("(脸红#) 你不会害羞的 八嘎!", at_sender=True) diff --git a/plugins/reimu/__init__.py b/plugins/reimu/__init__.py index 95e74a9f..26b7b46b 100644 --- a/plugins/reimu/__init__.py +++ b/plugins/reimu/__init__.py @@ -2,11 +2,11 @@ from nonebot import on_command from nonebot.adapters.cqhttp.permission import PRIVATE from .data_source import from_reimu_get_info from services.log import logger -from nonebot.adapters.cqhttp import Bot, Event, PrivateMessageEvent +from nonebot.adapters.cqhttp import Bot, PrivateMessageEvent from nonebot.typing import T_State from utils.utils import is_number, get_message_text, UserExistLimiter, scheduler from models.count_user import UserCount -from configs.config import COUNT_PER_DAY_REIMU +from configs.config import COUNT_PER_DAY_REIMU, NICKNAME __plugin_name__ = "上车" __plugin_usage__ = r""" @@ -63,7 +63,7 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): keyword = state["keyword"] page = state["page"] await UserCount.add_count(event.user_id, "reimu") - await reimu.send("已经帮你关好车门了,请等待发车(不加真寻好友的话是欣赏不到旅途的风景的)", at_sender=True) + await reimu.send(f"已经帮你关好车门了,请等待发车(不加{NICKNAME}好友的话是欣赏不到旅途的风景的)", at_sender=True) reimu_report = await from_reimu_get_info(keyword, page) if reimu_report: await reimu.send(reimu_report) diff --git a/plugins/remind/__init__.py b/plugins/remind/__init__.py index dc912641..02b763d8 100644 --- a/plugins/remind/__init__.py +++ b/plugins/remind/__init__.py @@ -5,6 +5,7 @@ from models.group_remind import GroupRemind from models.group_info import GroupInfo from models.friend_user import FriendUser from nonebot.adapters.cqhttp.exception import ActionFailed +from configs.config import NICKNAME __name__ = "早晚安 [Hidden]" @@ -56,7 +57,7 @@ async def _(): result = image("sleep.jpg", "zhenxun") try: await bot.send_group_msg( - group_id=g, message="小真寻要睡觉了,你们也要早点睡呀" + result + group_id=g, message=f"{NICKNAME}要睡觉了,你们也要早点睡呀" + result ) except ActionFailed: logger.warning(f"{g} 群被禁言中,无法发送晚安") diff --git a/plugins/roll.py b/plugins/roll.py index 9aee9ffb..14968aaa 100644 --- a/plugins/roll.py +++ b/plugins/roll.py @@ -3,6 +3,7 @@ from nonebot.typing import T_State from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from utils.utils import get_message_text from services.log import logger +from configs.config import NICKNAME import random import asyncio @@ -36,7 +37,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): await roll.send( random.choice( [ - f"让真寻看看是什么结果!答案是:‘{x}’", + f"让{NICKNAME}看看是什么结果!答案是:‘{x}’", f"根据命运的指引,接下来{user_name} ‘{x}’ 会比较好", f"祈愿被回应了!是 ‘{x}’!", f"结束了,{user_name},命运之轮停在了 ‘{x}’!", diff --git a/plugins/russian/__init__.py b/plugins/russian/__init__.py index 5f24ae28..c9b68326 100644 --- a/plugins/russian/__init__.py +++ b/plugins/russian/__init__.py @@ -11,7 +11,7 @@ from models.bag_user import BagUser from services.log import logger import time from .data_source import rank -from configs.config import MAX_RUSSIAN_BET_GOLD +from configs.config import MAX_RUSSIAN_BET_GOLD, NICKNAME __plugin_name__ = '俄罗斯轮盘' @@ -248,7 +248,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): if event.user_id != rs_player[event.group_id][1] and event.user_id != rs_player[event.group_id][2]: await shot.finish(random.choice([ f'不要打扰 {player1_name} 和 {player2_name} 的决斗啊!', - '给我好好做好一个观众!不然小真寻就要生气了', + f'给我好好做好一个观众!不然{NICKNAME}就要生气了', f'不要捣乱啊baka{(await GroupInfoUser.get_member_info(event.user_id, event.group_id)).user_name}!' ]), at_sender=True) await shot.finish(f'你的左轮不是连发的!该 ' @@ -322,7 +322,7 @@ async def end_game(bot: Bot, event: GroupMessageEvent): f'\t累计败场:{lose_user.fail_count}\n' f'\t累计输掉金币:{lose_user.lose_money}\n' f'-------------------\n' - f'哼哼,真寻从中收取了 {float(rand)}%({fee}金币) 作为手续费!\n' + f'哼哼,{NICKNAME}从中收取了 {float(rand)}%({fee}金币) 作为手续费!\n' f'子弹排列:{bullet_str[:-1]}') rs_player[event.group_id] = {} diff --git a/plugins/search_anime/data_source.py b/plugins/search_anime/data_source.py index 6526387e..d4498ac5 100644 --- a/plugins/search_anime/data_source.py +++ b/plugins/search_anime/data_source.py @@ -1,4 +1,5 @@ from lxml import etree +from lxml import etree import feedparser from urllib import parse from services.log import logger diff --git a/plugins/search_buff_skin_price/__init__.py b/plugins/search_buff_skin_price/__init__.py index 485e1afc..b5d0890c 100644 --- a/plugins/search_buff_skin_price/__init__.py +++ b/plugins/search_buff_skin_price/__init__.py @@ -6,6 +6,7 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from nonebot.rule import to_me from nonebot.permission import SUPERUSER from utils.utils import UserExistLimiter, get_message_text +from configs.config import NICKNAME __plugin_name__ = "查询皮肤" @@ -50,7 +51,7 @@ async def arg_handle(bot: Bot, event: MessageEvent, state: T_State): try: result, status_code = await get_price(name) except FileNotFoundError: - await search_skin.finish('请先对真寻说"设置cookie"来设置cookie!') + await search_skin.finish(F'请先对{NICKNAME}说"设置cookie"来设置cookie!') if status_code in [996, 997, 998]: _ulmt.set_False(event.user_id) await search_skin.finish(result) diff --git a/plugins/send_img/__init__.py b/plugins/send_img/__init__.py index 66db756f..56fc54eb 100644 --- a/plugins/send_img/__init__.py +++ b/plugins/send_img/__init__.py @@ -27,7 +27,6 @@ __plugin_usage__ = ( _flmt = FreqLimiter(1) -IMAGE_DIR_LIST.remove("色图") cmd = set(IMAGE_DIR_LIST) # print(cmd) diff --git a/plugins/send_setu/__init__.py b/plugins/send_setu/__init__.py index 367184bd..0879efea 100644 --- a/plugins/send_setu/__init__.py +++ b/plugins/send_setu/__init__.py @@ -34,7 +34,7 @@ from .data_source import ( add_data_to_database, ) from nonebot.adapters.cqhttp.exception import ActionFailed -from configs.config import ONLY_USE_LOCAL_SETU, WITHDRAW_SETU_TIME +from configs.config import ONLY_USE_LOCAL_SETU, WITHDRAW_SETU_TIME, NICKNAME from utils.message_builder import at import re import asyncio @@ -60,7 +60,10 @@ __plugin_usage__ = f"""示例: 如果图片数量与数字不符, 原因1:网络不好,网线被拔QAQ 原因2:搜索到的总数小于数字 - 原因3:图太色或者小错误了】""" + 原因3:图太色或者小错误了】 +示例: + 色图 萝莉|少女 白丝|黑丝 + 色图 萝莉 猫娘""" _flmt = FreqLimiter(5) _ulmt = UserExistLimiter() @@ -83,7 +86,6 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): user_id=event.user_id, message=f"您有色图正在处理,请稍等....." ) raise IgnoredException("色图正在处理!") - _ulmt.set_True(event.user_id) @run_postprocessor @@ -118,7 +120,7 @@ setu = on_command( "色图", aliases={"涩图", "不够色", "来一发", "再来点", "色图r"}, priority=5, block=True ) -setu_reg = on_regex("(.*)[份|发|张|个|次|点](.*)[瑟|色|涩]图", priority=5, block=True) +setu_reg = on_regex("(.*)[份|发|张|个|次|点](.*)[瑟|色|涩]图$", priority=5, block=True) find_setu = on_command("查色图", priority=5, block=True) @@ -134,6 +136,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): luox = get_luoxiang(impression) if luox: await setu.finish(luox) + _ulmt.set_True(event.user_id) if not _flmt.check(event.user_id): await setu.finish("您冲得太快了,请稍候再冲", at_sender=True) _flmt.start_cd(event.user_id) @@ -253,7 +256,7 @@ async def send_setu_handle( # 非 id,在线搜索 tags = msg.split() # 真寻的色图?怎么可能 - if "真寻" in tags: + if f"{NICKNAME}" in tags: await matcher.finish("咳咳咳,虽然我很可爱,但是我木有自己的色图~~~有的话记得发我一份呀") # 本地先拿图,下载失败补上去 setu_list, code = await get_setu_list(tags=msg.split(), r18=r18) @@ -301,6 +304,8 @@ async def send_setu_handle( return # 本地无图 或 超过上下限 if code != 200 or (not setu_list and ONLY_USE_LOCAL_SETU): + if code == 999: + await matcher.finish('网络连接失败...', at_sender=True) await matcher.finish(setu_list[0], at_sender=True) elif not setu_list: await matcher.finish(error_info, at_sender=True) diff --git a/plugins/send_setu/data_source.py b/plugins/send_setu/data_source.py index 1463f5ca..c44c5fb0 100644 --- a/plugins/send_setu/data_source.py +++ b/plugins/send_setu/data_source.py @@ -7,6 +7,7 @@ from asyncpg.exceptions import UniqueViolationError from utils.utils import get_local_proxy from asyncio.exceptions import TimeoutError from typing import List, Optional +from configs.config import INITIAL_SETU_PROBABILITY, NICKNAME from models.setu import Setu import aiohttp import aiofiles @@ -29,12 +30,12 @@ r18_path = "_r18/" async def get_setu_urls( tags: List[str], num: int = 1, r18: int = 0, command: str = "" ) -> "List[str], List[str], List[tuple], int": - tags = tags[:20] if len(tags) > 20 else tags + tags = tags[:3] if len(tags) > 3 else tags params = { "r18": r18, # 添加r18参数 0为否,1为是,2为混合 - "tag": "|".join(tags), # 若指定tag - "num": 100, # 一次返回的结果数量,范围为1到10,不提供 APIKEY 时固定为1 - "size": ["original"], # 是否使用 master_1200 缩略图,以节省流量或提升加载速度 + "tag": tags, # 若指定tag + "num": 100, # 一次返回的结果数量 + "size": ["original"], } async with aiohttp.ClientSession() as session: for count in range(3): @@ -105,8 +106,7 @@ async def search_online_setu( > 1024 * 1024 * 1.5 ): compressed_image( - os.path.join(path_, f"{index}.jpg"), - os.path.join(path_, f"{index}.jpg"), + f"{IMAGE_PATH}/{path_}/{index}.jpg", ) logger.info(f"下载 lolicon图片 {url_} 成功, id:{index}") return image(file, path_), index @@ -188,12 +188,12 @@ def gen_message(setu_image: Setu, img_msg: bool = False): # 罗翔老师! def get_luoxiang(impression): - probability = impression + 70 + probability = impression + INITIAL_SETU_PROBABILITY * 100 if probability < random.randint(1, 101): return ( "我为什么要给你发这个?" + image(random.choice(os.listdir(IMAGE_PATH + "luoxiang/")), "luoxiang") - + "\n(快向小真寻签到提升好感度吧!)" + + f"\n(快向{NICKNAME}签到提升好感度吧!)" ) return None diff --git a/plugins/shop/gold_redbag/__init__.py b/plugins/shop/gold_redbag/__init__.py index 4a6e1c78..2b78f3a3 100644 --- a/plugins/shop/gold_redbag/__init__.py +++ b/plugins/shop/gold_redbag/__init__.py @@ -22,6 +22,7 @@ from services.log import logger from nonebot.permission import SUPERUSER from nonebot.rule import to_me from datetime import datetime, timedelta +from configs.config import NICKNAME import random import time @@ -278,7 +279,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): gl = await bot.get_group_list(self_id=int(bot.self_id)) gl = [g["group_id"] for g in gl] for g in gl: - init_redbag(int(bot.self_id), g, "可爱的小真寻", amount, num, int(bot.self_id), 1) + init_redbag(int(bot.self_id), g, f"{NICKNAME}", amount, num, int(bot.self_id), 1) scheduler.add_job( end_festive_redbag, "date", @@ -289,7 +290,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): try: await bot.send_group_msg( group_id=g, - message=f"可爱的小真寻发起了金币红包\n金额:{amount}\n数量:{num}\n" + message=f"{NICKNAME}发起了金币红包\n金额:{amount}\n数量:{num}\n" + image( b64=await generate_send_redbag_pic(int(bot.self_id), greetings) ), @@ -380,7 +381,7 @@ async def get_redbag_img(user_id: int, group_id: int): async def end_festive_redbag(bot: Bot, group_id: int): global festive_redbag_data message = ( - f"真寻的节日红包过时了,一共开启了 " + f"{NICKNAME}的节日红包过时了,一共开启了 " f"{festive_redbag_data[group_id]['num'] - len(festive_redbag_data[group_id]['redbag'])}" f" 个红包,共 {festive_redbag_data[group_id]['open_amount']} 金币" ) diff --git a/plugins/sign_in/group_user_checkin.py b/plugins/sign_in/group_user_checkin.py index 90f2a554..4fa4f75b 100644 --- a/plugins/sign_in/group_user_checkin.py +++ b/plugins/sign_in/group_user_checkin.py @@ -6,7 +6,7 @@ from services.db_context import db from models.sigin_group_user import SignGroupUser from models.group_member_info import GroupInfoUser from models.bag_user import BagUser -from configs.config import MAX_SIGN_GOLD +from configs.config import MAX_SIGN_GOLD, NICKNAME from utils.image_utils import CreateImg import aiohttp from asyncio.exceptions import TimeoutError @@ -219,6 +219,6 @@ async def _pst(users: list, impressions: list, groups: list): width += 580 W = CreateImg(1740, 3700, color="#FFE4C4", font_size=130) W.paste(A, (0, 260)) - font_w, font_h = W.getsize("真寻的好感度总榜") - W.text((int((1740 - font_w) / 2), int((260 - font_h) / 2)), "真寻的好感度总榜") + font_w, font_h = W.getsize(f"{NICKNAME}的好感度总榜") + W.text((int((1740 - font_w) / 2), int((260 - font_h) / 2)), f"{NICKNAME}的好感度总榜") return W.pic2bs4() diff --git a/plugins/statistics_hook.py b/plugins/statistics_hook.py index 6eb2be98..fa274eb7 100644 --- a/plugins/statistics_hook.py +++ b/plugins/statistics_hook.py @@ -86,7 +86,7 @@ async def _( state: T_State, ): global _prefix_count_dict - if matcher.type == "message" and matcher.priority not in [1, 9]: + if matcher.type == "message" and matcher.priority not in [1, 9] and matcher.module not in ['update_info']: model = matcher.module day_index = _prefix_count_dict["day_index"] # print(f'model --> {model}') diff --git a/plugins/super_help/__init__.py b/plugins/super_help/__init__.py index f41b1fc5..992ba559 100644 --- a/plugins/super_help/__init__.py +++ b/plugins/super_help/__init__.py @@ -3,24 +3,21 @@ from nonebot.permission import SUPERUSER from nonebot.typing import T_State from nonebot.adapters import Bot, Event from nonebot.rule import to_me +from utils.image_utils import CreateImg +from configs.path_config import IMAGE_PATH +from utils.message_builder import image -super_help = on_command( - "超级用户帮助", rule=to_me(), priority=1, permission=SUPERUSER, block=True -) - - -@super_help.handle() -async def _(bot: Bot, event: Event, state: T_State): - result = """超级用户帮助: +result = """超级用户帮助: +*:可多个类型参数 ?:可省略参数 1.添加/删除管理 [at] [level] 2.查看群组/查看好友 - 3.广播 --> 指令:广播- [msg] + 3.广播- [msg] 4.更新色图 - 5.回复 --> 指令:/t命令帮助 - 6.更新/设置cookie --> 指令:更新/设置cookie [cookie] - 7.开启广播通知 --> 指令:开启广播通知 [群号] - 8.退群 --> 指令:退群 [群号] + 5./t命令帮助 + 6.更新/设置cookie [cookie] + 7.开启/关闭广播通知 [群号] + 8.退群 [群号] 9.自检 10.更新价格/更加图片 [武器箱] 11.更新好友信息 @@ -29,16 +26,31 @@ async def _(bot: Bot, event: Event, state: T_State): 14.添加商品 [名称]-[价格]-[描述]-[折扣]-[限时时间] 15.删除商品 [名称(序号)] 16.修改商品 -name [名称(序号)] -price [价格] -des [描述] -discount [折扣] -time [限时] - 17.节日红包 [金额] [数量] [祝福语](可省) *[指定群](可省) + 17.节日红包 [金额] [数量] [祝福语](可省) *?[指定群 18.更新原神今日素材 19.更新原神资源信息 - 20.添加pix关键词/uid/pid *[关键词/uid/pid] [-f](强制通过不检测) + 20.添加pix关键词/uid/pid *[关键词/uid/pid] ?[-f](强制通过不检测) 21.通过/取消pix关键词 [keyword/pid:pid/uid:uid] 22.删除pix关键词 [keyword/uid/pid:pid] 23.更新pix关键词 [keyword/pid:pid/uid:uid] [num] - 24.删除pix图片 *[pid] [-b](同时加入黑名单)? + 24.删除pix图片 *[pid] ?[-b](同时加入黑名单) 25.查看pix图库 [keyword] 26.pix检测更新 [update] 27.检查更新真寻 - 28.真寻重启""" - await super_help.finish(result, at_sender=True) + 28.真寻重启 + 29.添加/删除群白名单 *[群号] + 30.关闭[功能] ?[群号](有群号时禁用指定群)""" + +height = len(result.split('\n')) * 24 +A = CreateImg(1000, height, font_size=20) +A.text((10, 10), result) +A.save(f'{IMAGE_PATH}/super_help.png') + +super_help = on_command( + "超级用户帮助", rule=to_me(), priority=1, permission=SUPERUSER, block=True +) + + +@super_help.handle() +async def _(bot: Bot, event: Event, state: T_State): + await super_help.finish(image('super_help.png'), at_sender=True) diff --git a/plugins/update_info.py b/plugins/update_info.py index abfe89fc..f31b37d1 100644 --- a/plugins/update_info.py +++ b/plugins/update_info.py @@ -8,7 +8,7 @@ __plugin_name__ = '更新信息' __plugin_usage__ = '无' -update_info = on_command("更新信息", priority=5, block=True) +update_info = on_command("更新信息", aliases={'更新日志'}, priority=5, block=True) @update_info.handle() diff --git a/plugins/update_pic.py b/plugins/update_pic.py index bfa14ecc..b6c92b21 100644 --- a/plugins/update_pic.py +++ b/plugins/update_pic.py @@ -11,33 +11,34 @@ import aiofiles import aiohttp from utils.utils import is_number, get_message_text from utils.image_utils import CreateImg, pic2b64 +from configs.config import NICKNAME import cv2 import numpy as np __plugin_name__ = "图片" -__plugin_usage__ = """图片用法(目前): +__plugin_usage__ = f"""图片用法(目前): 可以输入 指定操作 或 序号 来进行选择 1.修改尺寸 宽(x) 高(y) 图片(在文字后跟图片即可) - 示例:小真寻修改图片 修改尺寸 200 300 图片(在文字后跟图片即可) + 示例:{NICKNAME}修改图片 修改尺寸 200 300 图片(在文字后跟图片即可) 2.等比压缩 比例(x) 图片(在文字后跟图片即可) - 示例:小真寻修改图片 等比压缩 2 图片(在文字后跟图片即可) + 示例:{NICKNAME}修改图片 等比压缩 2 图片(在文字后跟图片即可) 3.旋转图片 角度(x) 图片(在文字后跟图片即可) - 示例:小真寻修改图片 旋转图片 45 图片(在文字后跟图片即可) + 示例:{NICKNAME}修改图片 旋转图片 45 图片(在文字后跟图片即可) 4.水平翻转 - 示例:小真寻修改图片 水平翻转 图片 + 示例:{NICKNAME}修改图片 水平翻转 图片 5.铅笔滤镜 - 示例:小真寻修改图片 铅笔滤镜 图片 + 示例:{NICKNAME}修改图片 铅笔滤镜 图片 6.模糊效果 - 示例:小真寻修改图片 模糊效果 图片 + 示例:{NICKNAME}修改图片 模糊效果 图片 7.锐化效果 - 示例:小真寻修改图片 锐化效果 图片 + 示例:{NICKNAME}修改图片 锐化效果 图片 8.高斯模糊 - 示例:小真寻修改图片 高斯模糊 图片 + 示例:{NICKNAME}修改图片 高斯模糊 图片 9.边缘检测 - 示例:小真寻修改图片 边缘检测 图片 + 示例:{NICKNAME}修改图片 边缘检测 图片 10.底色替换 颜色 颜色 图片 (不专业)支持:(红,蓝)->(红,蓝,白,绿,黄) - 示例:小真寻修改图片 底色替换 蓝色 红色 图片""" + 示例:{NICKNAME}修改图片 底色替换 蓝色 红色 图片""" # IMAGE_LOCAL = IMAGE_PATH + "temp/{}_update.png" method_flag = "" @@ -219,7 +220,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): img = img.resize((int(x * width), int(x * height))) result += image(b64=pic2b64(img)) else: - await update_img.finish("小真寻不支持图片压缩后宽或高大于8000的存在!!") + await update_img.finish(f"{NICKNAME}不支持图片压缩后宽或高大于8000的存在!!") if method in ["旋转图片", "3"]: for i in range(index): img = Image.open(IMAGE_PATH + f"temp/{event.user_id}_{i}_update.png") diff --git a/plugins/update_setu/data_source.py b/plugins/update_setu/data_source.py index 4cceb2a1..fcc776a8 100644 --- a/plugins/update_setu/data_source.py +++ b/plugins/update_setu/data_source.py @@ -93,8 +93,10 @@ async def update_setu_img(): for image in image_list: count += 1 path = _path / "_r18" if image.is_r18 else _path / "_setu" - rar_path = "r18_rar" if image.is_r18 else "rar" + rar_path = _path / "r18_rar" if image.is_r18 else _path / "rar" local_image = path / f"{image.local_id}.jpg" + path.mkdir(exist_ok=True, parents=True) + rar_path.mkdir(exist_ok=True, parents=True) if not local_image.exists() or not image.img_hash: for _ in range(3): try: @@ -103,7 +105,7 @@ async def update_setu_img(): ) as response: if response.status == 200: async with aiofiles.open( - f"{IMAGE_PATH}/{rar_path}/{image.local_id}.jpg", + rar_path / f'{image.local_id}.jpg', "wb", ) as f: await f.write(await response.read()) @@ -111,28 +113,25 @@ async def update_setu_img(): try: if ( os.path.getsize( - f"{IMAGE_PATH}/{rar_path}/{image.local_id}.jpg" + rar_path / f'{image.local_id}.jpg', ) > 1024 * 1024 * 1.5 ): compressed_image( - os.path.join( - rar_path, f"{image.local_id}.jpg" - ), - os.path.join(path, f"{image.local_id}.jpg"), + rar_path / f"{image.local_id}.jpg", + path / f"{image.local_id}.jpg" ) else: logger.info( - f"不需要压缩,移动图片 {IMAGE_PATH}/{rar_path}/{image.local_id}.jpg " + f"不需要压缩,移动图片{rar_path}/{image.local_id}.jpg " f"--> /{path}/{image.local_id}.jpg" ) os.rename( - f"{IMAGE_PATH}/{rar_path}/{image.local_id}.jpg", + f"{rar_path}/{image.local_id}.jpg", f"{path}/{image.local_id}.jpg", ) except FileNotFoundError: logger.warning(f"文件 {image.local_id}.jpg 不存在,跳过...") - _success -= 1 continue img_hash = str( get_img_hash( @@ -146,7 +145,6 @@ async def update_setu_img(): except (TimeoutError, ClientConnectorError) as e: logger.warning(f"{image.local_id}.jpg 更新失败 ..{type(e)}:{e}") except Exception as e: - _success -= 1 logger.error(f"更新色图 {image.local_id}.jpg 错误 {type(e)}: {e}") if type(e) not in error_type: error_type.append(type(e)) diff --git a/plugins/upload_img/__init__.py b/plugins/upload_img/__init__.py index 82ca5741..107051f9 100644 --- a/plugins/upload_img/__init__.py +++ b/plugins/upload_img/__init__.py @@ -1,15 +1,9 @@ from nonebot import on_command -from configs.path_config import IMAGE_PATH -from services.log import logger -import os from nonebot.rule import to_me from nonebot.typing import T_State from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from utils.utils import get_message_imgs, get_message_text -import aiohttp -import aiofiles -from utils.utils import cn2py -from configs.config import IMAGE_DIR_LIST +from .data_source import upload_image_to_local __plugin_name__ = "上传图片" __plugin_usage__ = ( @@ -18,22 +12,24 @@ __plugin_usage__ = ( "2.上传图片 [序号] [图片], 即在相应目录下添加图片\n\t\t示例: 上传图片 1 [图片]" ) - upload_img = on_command("上传图片", rule=to_me(), priority=5, block=True) +continuous_upload_img = on_command('连续上传图片', rule=to_me(), priority=5, block=True) + @upload_img.args_parser -async def parse(bot: Bot, event: MessageEvent, state: T_State): - if str(event.get_message()) in ["取消", "算了"]: +async def _(bot: Bot, event: MessageEvent, state: T_State): + msg = get_message_text(event.json()) + if msg in ["取消", "算了"]: await upload_img.finish("已取消操作..", at_sender=True) if state["_current_key"] in ["path"]: - if str(event.get_message()) not in IMAGE_DIR_LIST: + if msg not in IMAGE_DIR_LIST: await upload_img.reject("此目录不正确,请重新输入目录!") - state[state["_current_key"]] = str(event.get_message()) + state['path'] = msg if state["_current_key"] in ["imgs"]: if not get_message_imgs(event.json()): await upload_img.reject("图呢图呢图呢图呢!GKD!") - state[state["_current_key"]] = get_message_imgs(event.json()) + state['imgs'] = get_message_imgs(event.json()) @upload_img.handle() @@ -41,59 +37,65 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): raw_arg = get_message_text(event.json()) img_list = get_message_imgs(event.json()) if raw_arg: - if str(event.get_message()) in ["帮助"]: - await upload_img.finish(__plugin_usage__) - if raw_arg.split("[")[0] in IMAGE_DIR_LIST: - state["path"] = raw_arg.split("[")[0] + if raw_arg in IMAGE_DIR_LIST: + state["path"] = raw_arg if img_list: state["imgs"] = img_list -@upload_img.got("path", prompt="要将图片上传至什么图库呢?") +@upload_img.got('path', prompt='要将图片上传至什么图库呢?') +async def _(bot: Bot, event: MessageEvent, state: T_State): + pass + + @upload_img.got("imgs", prompt="图呢图呢图呢图呢!GKD!") async def _(bot: Bot, event: MessageEvent, state: T_State): - path = IMAGE_PATH + cn2py(state["path"]) + '/' - img_list = state["imgs"] - img_id = len(os.listdir(path)) - failed_list = [] - success_id = "" - async with aiohttp.ClientSession() as session: - for img_url in img_list: - try: - async with session.get(img_url, timeout=7) as response: - if response.status == 200: - async with aiofiles.open( - path + str(img_id) + ".jpg", "wb" - ) as f: - await f.write(await response.read()) - success_id += str(img_id) + "," - img_id += 1 - else: - failed_list.append(img_url) - logger.warning(f"图片:{img_url} 下载失败....") - except TimeoutError as e: - logger.warning(f"图片:{img_url} 下载超时....e:{e}") - if img_url not in failed_list: - failed_list.append(img_url) - failed_result = "" - for img in failed_list: - failed_result += str(img) + "\n" - logger.info( - f"USER {event.user_id} GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}" - f" 上传图片至 {state['path']} 共 {len(img_list)} 张,失败 {len(failed_list)} 张,id={success_id[:-1]}" - ) - if failed_result: - await upload_img.finish( - f"这次一共为 {state['path']}库 添加了 {len(img_list) - len(failed_list)} 张图片\n" - f"依次的Id为:{success_id[:-1]}\n" - f"上传失败:{failed_result[:-1]}\n" - f"小真寻感谢您对图库的扩充!WW", - at_sender=True, - ) + path = state['path'] + img_list = state['imgs'] + group_id = 0 + if isinstance(event, GroupMessageEvent): + group_id = event.group_id + await upload_img.send(await upload_image_to_local(img_list, path, event.user_id, group_id)) + + +@continuous_upload_img.args_parser +async def _(bot: Bot, event: MessageEvent, state: T_State): + if str(event.get_message()) in ["取消", "算了"]: + await continuous_upload_img.finish("已取消操作..", at_sender=True) + if state["_current_key"] in ["path"]: + if str(event.get_message()) not in IMAGE_DIR_LIST: + await continuous_upload_img.reject("此目录不正确,请重新输入目录!") + state[state["_current_key"]] = str(event.get_message()) else: - await upload_img.finish( - f"这次一共为 {state['path']}库 添加了 {len(img_list)} 张图片\n" - f"依次的Id为:{success_id[:-1]}\n" - f"小真寻感谢您对图库的扩充!WW", - at_sender=True, - ) + if get_message_text(event.json()) not in ['stop']: + img = get_message_imgs(event.json()) + if img: + state['tmp'].extend(img) + await continuous_upload_img.reject('图再来!!') + else: + state['imgs'] = state['tmp'] + + +@continuous_upload_img.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State): + path = get_message_imgs(event.json()) + if path in IMAGE_DIR_LIST: + state['path'] = path + await continuous_upload_img.send('图来!!') + state['tmp'] = [] + + +@continuous_upload_img.got("path", prompt="要将图片上传至什么图库呢?") +async def _(bot: Bot, event: MessageEvent, state: T_State): + pass + + +@continuous_upload_img.got("imgs", prompt="图呢图呢图呢图呢!GKD!") +async def _(bot: Bot, event: MessageEvent, state: T_State): + path = state['path'] + img_list = state['imgs'] + group_id = 0 + if isinstance(event, GroupMessageEvent): + group_id = event.group_id + await continuous_upload_img.send(await upload_image_to_local(img_list, path, event.user_id, group_id)) + diff --git a/plugins/upload_img/data_source.py b/plugins/upload_img/data_source.py new file mode 100644 index 00000000..7123d04b --- /dev/null +++ b/plugins/upload_img/data_source.py @@ -0,0 +1,51 @@ +from configs.config import NICKNAME +from typing import List +from configs.path_config import IMAGE_PATH +from services.log import logger +from utils.utils import cn2py +from pathlib import Path +import aiofiles +import aiohttp +import os + + +async def upload_image_to_local( + img_list: List[str], path: str, user_id: int, group_id: int = 0 +) -> str: + _path = path + path = Path(IMAGE_PATH) / cn2py(path) + path.mkdir(parents=True, exist_ok=True) + img_id = len(os.listdir(path)) + failed_list = [] + success_id = "" + async with aiohttp.ClientSession() as session: + for img_url in img_list: + try: + async with session.get(img_url, timeout=7) as response: + if response.status == 200: + async with aiofiles.open(path / f"{img_id}.jpg", "wb") as f: + await f.write(await response.read()) + success_id += str(img_id) + "," + img_id += 1 + else: + failed_list.append(img_url) + logger.warning(f"图片:{img_url} 下载失败....") + except TimeoutError as e: + logger.warning(f"图片:{img_url} 下载超时....e:{e}") + if img_url not in failed_list: + failed_list.append(img_url) + failed_result = "" + for img in failed_list: + failed_result += str(img) + "\n" + logger.info( + f"USER {user_id} GROUP {group_id}" + f" 上传图片至 {_path} 共 {len(img_list)} 张,失败 {len(failed_list)} 张,id={success_id[:-1]}" + ) + if failed_list: + return ( + f"这次一共为 {_path}库 添加了 {len(img_list) - len(failed_list)} 张图片\n" + f"依次的Id为:{success_id[:-1]}\n上传失败:{failed_result[:-1]}\n{NICKNAME}感谢您对图库的扩充!WW" + ) + else: + return f"这次一共为 {_path}库 添加了 {len(img_list)} 张图片\n依次的Id为:" \ + f"{success_id[:-1]}\n{NICKNAME}感谢您对图库的扩充!WW" diff --git a/plugins/weather/__init__.py b/plugins/weather/__init__.py index 0fecb438..f48c891b 100644 --- a/plugins/weather/__init__.py +++ b/plugins/weather/__init__.py @@ -17,8 +17,11 @@ weather = on_regex(r".*?(.*)市?的?天气.*?", priority=5, block=True) @weather.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = get_message_text(event.json()) - msg = re.search(r".*?(.*)市?的?天气.*?", msg) - msg = msg.group(1) + msg1 = re.search(r".*?(.*)市?的?天气.*?", msg) + msg2 = re.search(r".*?天气(.*).*?", msg) + msg1 = msg1.group(1) + msg2 = msg2.group(1) + msg = msg1 if msg1 else msg2 if msg[-1] == "的": msg = msg[:-1] if msg[-1] != "市": diff --git a/plugins/weather/data_source.py b/plugins/weather/data_source.py index c8f6c7f0..bb7806d4 100644 --- a/plugins/weather/data_source.py +++ b/plugins/weather/data_source.py @@ -2,6 +2,7 @@ from services.log import logger from utils.message_builder import image from utils.user_agent import get_user_agent from configs.path_config import TXT_PATH +from configs.config import NICKNAME from asyncio.exceptions import TimeoutError from typing import List from nonebot import Driver @@ -26,7 +27,7 @@ async def get_weather_of_city(city: str) -> str: if code == 999: return "不要查一个省份的天气啊,很累人的!" elif code == 998: - return "真寻只可以查询国内的天气喔..." + return f"{NICKNAME}只可以查询国内城市的天气喔..." else: async with aiohttp.ClientSession(headers=get_user_agent()) as session: async with session.get( @@ -35,7 +36,7 @@ async def get_weather_of_city(city: str) -> str: data_json = json.loads(await res.text(encoding="utf8")) if "desc" in data_json: if data_json["desc"] == "invilad-citykey": - return "你为啥不查火星的天气呢?小真寻只支持国内天气查询!!" + image( + return f"你为啥不查火星的天气呢?{NICKNAME}只支持国内天气查询!!" + image( "shengqi", "zhenxun" ) elif data_json["desc"] == "OK": diff --git a/plugins/yiqing/data_source.py b/plugins/yiqing/data_source.py index 5248de41..c3aed80a 100644 --- a/plugins/yiqing/data_source.py +++ b/plugins/yiqing/data_source.py @@ -1,5 +1,6 @@ from utils.user_agent import get_user_agent from configs.path_config import TXT_PATH +from configs.config import NICKNAME from typing import List from pathlib import Path import ujson as json @@ -37,7 +38,7 @@ async def get_yiqing_data(area: str): province = p city = area if not province and not city: - return "小真寻只支持国内的疫情查询喔..." + return f"{NICKNAME}只支持国内的疫情查询喔..." async with aiohttp.ClientSession(headers=get_user_agent()) as session: async with session.get(url, timeout=7) as response: epidemic_data = json.loads((await response.json())["data"]) diff --git a/resources/img/other/webtop.png b/resources/img/other/webtop.png new file mode 100644 index 00000000..6f2eb1ef Binary files /dev/null and b/resources/img/other/webtop.png differ diff --git a/update_info.json b/update_info.json index 99069eb3..31e31e89 100644 --- a/update_info.json +++ b/update_info.json @@ -1,21 +1,49 @@ { "update_file": [ + ".env.dev", "configs/config.py", + "configs/path_config.py", + "plugins/aconfig", + "plugins/admin_bot_manage", + "plugins/admin_help", + "plugins/ai", + "plugins/alapi", "plugins/auto_invite", "plugins/ban", "plugins/check_zhenxun_update", - "plugins/genshin/material_remind", + "plugins/delete_img", + "plugins/fudu.py", "plugins/genshin/query_resource_points", + "plugins/group_handle", "plugins/help", + "plugins/hook.py", + "plugins/jitang.py", + "plugins/move_img", + "plugins/mute.py", + "plugins/nickname.py", + "plugins/one_friend", + "plugins/open_cases", + "plugins/parse_bilibili_json.py", + "plugins/pixiv", + "plugins/reimu", + "plugins/remind", + "plugins/roll.py", "plugins/russian", + "plugins/search_anime", "plugins/search_buff_skin_price", + "plugins/send_img", + "plugins/send_setu", + "plugins/shop/gold_redbag", + "plugins/sign_in/group_user_checkin.py", + "plugins/statistics_hook.py", "plugins/super_help", + "plugins/update_info.py", "plugins/update_setu", + "plugins/upload_img", + "plugins/weather", "plugins/yiqing", - "bot.py", - "plugins/admin_bot_manage/update_group_member_info.py", - "plugins/send_img" + "utils/image_utils.py" ], - "add_file": ["plugins/nbnhhsh.py", "plugins/roll.py"], - "delete_file": [" plugins/admin_bot_manage/__init__.py"] + "add_file": ["plugins/group_manager", "resources/img/other/webtop.png", "utils/static_data"], + "delete_file": ["plugins/group_level", "plugins/nonebot_plugin_manager"] } diff --git a/plugins/alapi/__init__.py b/utils/__init__.py similarity index 100% rename from plugins/alapi/__init__.py rename to utils/__init__.py diff --git a/utils/browser.py b/utils/browser.py index a953116f..e4eee6c4 100644 --- a/utils/browser.py +++ b/utils/browser.py @@ -13,14 +13,14 @@ _browser: Optional[Browser] = None async def init(**kwargs) -> Optional[Browser]: - try: - global _browser - browser = await async_playwright().start() - _browser = await browser.chromium.launch(**kwargs) - return _browser - except NotImplementedError: - logger.warning("win环境下 初始化playwright失败....请替换环境至linux") - return None + # try: + global _browser + browser = await async_playwright().start() + _browser = await browser.chromium.launch(**kwargs) + return _browser + # except NotImplementedError: + # logger.warning("win环境下 初始化playwright失败....请替换环境至linux") + # return None async def get_browser(**kwargs) -> Browser: diff --git a/utils/image_utils.py b/utils/image_utils.py index fc16df56..7b8fa547 100644 --- a/utils/image_utils.py +++ b/utils/image_utils.py @@ -3,7 +3,7 @@ from PIL import Image, ImageFile, ImageDraw, ImageFont from imagehash import ImageHash from io import BytesIO from matplotlib import pyplot as plt -from typing import Tuple, Optional +from typing import Tuple, Optional, Union from pathlib import Path import cv2 import base64 @@ -45,7 +45,7 @@ def get_img_hash(image_file: str) -> ImageHash: return hash_value -def compressed_image(in_file: str, out_file: str = None, ratio: float = 0.9): +def compressed_image(in_file: Union[str, Path], out_file: Union[str, Path] = None, ratio: float = 0.9): """ 说明: 压缩图片 @@ -54,8 +54,11 @@ def compressed_image(in_file: str, out_file: str = None, ratio: float = 0.9): :param out_file: 压缩后输出的文件路径 :param ratio: 压缩率,宽高 * 压缩率 """ - in_file = Path(IMAGE_PATH) / in_file - out_file = Path(IMAGE_PATH) / out_file if out_file else in_file + in_file = Path(IMAGE_PATH) / in_file if isinstance(in_file, str) else in_file + if out_file: + out_file = Path(IMAGE_PATH) / out_file if isinstance(out_file, str) else out_file + else: + out_file = in_file h, w, d = cv2.imread(str(in_file.absolute())).shape img = cv2.resize(cv2.imread(str(in_file.absolute())), (int(w * ratio), int(h * ratio))) cv2.imwrite(str(out_file.absolute()), img) diff --git a/utils/static_data/__init__.py b/utils/static_data/__init__.py new file mode 100644 index 00000000..7563e9c0 --- /dev/null +++ b/utils/static_data/__init__.py @@ -0,0 +1,11 @@ +from typing import Optional +from .group_manager import GroupManager +from pathlib import Path +from .data_source import init + +# 群权限 +group_manager: Optional[GroupManager] = GroupManager( + Path() / "data" / "manager" / "group_manager.json" +) + +init(group_manager) diff --git a/utils/static_data/data_class.py b/utils/static_data/data_class.py new file mode 100644 index 00000000..cca80a3b --- /dev/null +++ b/utils/static_data/data_class.py @@ -0,0 +1,51 @@ +from typing import Union +from pathlib import Path +import ujson as json + + +class StaticData: + """ + 静态数据共享类 + """ + + def __init__(self, file: Path): + file.parent.mkdir(exist_ok=True, parents=True) + self.file = file + self.data = {} + if file.exists(): + self.data: dict = json.load(open(file, "r", encoding="utf8")) + + def set(self, key, value): + self.data[key] = value + + def get(self, key): + return self.data.get(key) + + def delete(self, key): + if self.data.get(key) is not None: + del self.data[key] + + def save(self, path: Union[str, Path] = None): + path = path if path else self.file + with open(path, "w", encoding="utf8") as f: + json.dump(self.data, f, ensure_ascii=False, indent=4) + + def reload(self): + if self.file.exists(): + self.data: dict = json.load(open(self.file, "r", encoding="utf8")) + + def is_exists(self): + return self.file.exists() + + def is_empty(self): + return bool(len(self.data)) + + def __str__(self): + return str(self.data) + + def __setitem__(self, key, value): + self.data[key] = value + + def __getitem__(self, key): + return self.data[key] + diff --git a/utils/static_data/data_source.py b/utils/static_data/data_source.py new file mode 100644 index 00000000..75ce71cc --- /dev/null +++ b/utils/static_data/data_source.py @@ -0,0 +1,27 @@ +from pathlib import Path +import ujson as json +from .group_manager import GroupManager + + +def init(group_manager: GroupManager): + old_group_level_file = Path() / "data" / "manager" / "group_level.json" + old_plugin_list_file = Path() / "data" / "manager" / "plugin_list.json" + if old_group_level_file.exists(): + data = json.load(open(old_group_level_file, 'r', encoding='utf8')) + for key in data.keys(): + group = key + level = data[key] + group_manager.set_group_level(group, level) + old_group_level_file.unlink() + group_manager.save() + + if old_plugin_list_file.exists(): + data = json.load(open(old_plugin_list_file, 'r', encoding='utf8')) + for plugin in data.keys(): + for group in data[plugin].keys(): + if group == 'default' and not data[plugin]['default']: + group_manager.block_plugin(plugin) + elif not data[plugin][group]: + group_manager.block_plugin(plugin, group) + old_plugin_list_file.unlink() + group_manager.save() diff --git a/utils/static_data/group_manager.py b/utils/static_data/group_manager.py new file mode 100644 index 00000000..d34bfc74 --- /dev/null +++ b/utils/static_data/group_manager.py @@ -0,0 +1,186 @@ +from typing import Optional +from pathlib import Path +from .data_class import StaticData + + +class GroupManager(StaticData): + """ + 群权限 | 功能 | 聊天时间 管理器 + """ + + def __init__(self, file: Path): + super().__init__(file) + if not self.data: + self.data = {"super": {"close_plugins": {}, "white_group_list": []}, "group_manager": {}} + + def block_plugin( + self, plugin_cmd: str, group_id: Optional[str] = None, block_type: str = "all" + ): + """ + 说明: + 锁定插件 + 参数: + :param plugin_cmd: 功能模块名 + :param group_id: 群组,None时为超级用户禁用 + :param block_type: 限制类型 + """ + self._set_plugin_status(plugin_cmd, "block", group_id, block_type) + + def unblock_plugin(self, plugin_cmd: str, group_id: Optional[str] = None): + """ + 说明: + 解锁插件 + 参数: + :param plugin_cmd: 功能模块名 + :param group_id: 群组 + """ + self._set_plugin_status(plugin_cmd, "unblock", group_id) + + def set_group_level(self, group_id: str, level: int): + """ + 说明: + 设置群权限 + 参数: + :param group_id: 群组 + :param level: 权限等级 + """ + if not self.data["group_manager"].get(group_id): + self._init_group(group_id) + self.data["group_manager"][group_id]["level"] = level + self.save() + + def get_plugin_status( + self, plugin_cmd: str, group_id: Optional[str] = None, block_type: str = "all" + ) -> bool: + """ + 说明: + 获取插件状态 + 参数: + :param plugin_cmd: 功能模块名 + :param group_id: 群组 + :param block_type: 限制类型 + """ + if group_id: + if not self.data["group_manager"].get(group_id): + self._init_group(group_id) + return True + if plugin_cmd in self.data["group_manager"][group_id]["close_plugins"]: + return False + return True + else: + if plugin_cmd in self.data["super"]["close_plugins"]: + if ( + self.data["super"]["close_plugins"][plugin_cmd] == "all" + and block_type == "all" + ): + return False + else: + return ( + not self.data["super"]["close_plugins"][plugin_cmd] + == block_type + ) + return True + + def get_plugin_block_type(self, plugin_cmd: str) -> str: + """ + 说明: + 获取功能限制类型 + 参数: + :param plugin_cmd: 模块名称 + """ + if plugin_cmd in self.data["super"]["close_plugins"]: + return self.data["super"]["close_plugins"][plugin_cmd] + return "" + + def get_group_level(self, group_id: str) -> int: + """ + 说明: + 获取群等级 + 参数: + :param group_id: 群号 + """ + if not self.data["group_manager"].get(group_id): + self._init_group(group_id) + return self.data["group_manager"][group_id]["level"] + + def check_group_is_white(self, group_id: int) -> bool: + """ + 说明: + 检测群聊是否在白名单 + 参数: + :param group_id: 群号 + """ + return group_id in self.data['super']['white_group_list'] + + def add_group_white_list(self, group_id: int): + """ + 说明: + 将群聊加入白名单 + 参数: + :param group_id: 群号 + """ + if group_id not in self.data['super']['white_group_list']: + self.data['super']['white_group_list'].append(group_id) + + def delete_group_white_list(self, group_id: int): + """ + 说明: + 将群聊从白名单中删除 + 参数: + :param group_id: 群号 + """ + if group_id in self.data['super']['white_group_list']: + self.data['super']['white_group_list'].remove(group_id) + + def _set_plugin_status( + self, + plugin_cmd: str, + status: str, + group_id: Optional[str], + block_type: str = "all", + ): + """ + 说明: + 设置功能开关状态 + 参数: + :param plugin_cmd: 功能模块名 + :param status: 功能状态 + :param group_id: 群组 + :param block_type: 限制类型 + """ + if group_id: + if not self.data["group_manager"].get(group_id): + self._init_group(group_id) + if status == "block": + if ( + plugin_cmd + not in self.data["group_manager"][group_id]["close_plugins"] + ): + self.data["group_manager"][group_id]["close_plugins"].append( + plugin_cmd + ) + else: + if plugin_cmd in self.data["group_manager"][group_id]["close_plugins"]: + self.data["group_manager"][group_id]["close_plugins"].remove( + plugin_cmd + ) + else: + if status == "block": + if ( + plugin_cmd not in self.data["super"]["close_plugins"] + or block_type != self.data["super"]["close_plugins"][plugin_cmd] + ): + self.data["super"]["close_plugins"][plugin_cmd] = block_type + else: + if plugin_cmd in self.data["super"]["close_plugins"]: + del self.data["super"]["close_plugins"][plugin_cmd] + self.save() + + def _init_group(self, group_id: str): + """ + 说明: + 初始化群数据 + 参数: + :param group_id: 群号 + """ + self.data["group_manager"][group_id] = {"level": 5, "close_plugins": []}