diff --git a/__version__ b/__version__ index 31c50097..a244d235 100644 --- a/__version__ +++ b/__version__ @@ -1 +1 @@ -__version__: v0.0.4.7 +__version__: v0.0.5.0 diff --git a/bot.py b/bot.py index f33e7cf6..d384928d 100644 --- a/bot.py +++ b/bot.py @@ -2,19 +2,14 @@ import nonebot from nonebot.adapters.cqhttp import Bot as CQHTTPBot from services.db_context import init, disconnect + nonebot.init() driver = nonebot.get_driver() driver.register_adapter("cqhttp", CQHTTPBot) config = driver.config driver.on_startup(init) driver.on_shutdown(disconnect) -nonebot.load_builtin_plugins() nonebot.load_plugins("plugins") -nonebot.load_plugins("plugins/shop") -nonebot.load_plugins("plugins/genshin") -nonebot.load_plugins("plugins/alapi") -nonebot.load_plugins("plugins/pix_gallery") -nonebot.load_plugins("plugins/admin_bot_manage") if __name__ == "__main__": diff --git a/configs/config.py b/configs/config.py index f8aa2304..85c72659 100644 --- a/configs/config.py +++ b/configs/config.py @@ -1,20 +1,11 @@ from typing import List, Optional, Tuple from services.service_config import TL_M_KEY, SYSTEM_M_PROXY, ALAPI_M_TOKEN -from .utils.init_config import init_config -from configs.path_config import DATA_PATH try: import ujson as json except ModuleNotFoundError: import json -# 是否使用配置文件 -# 使用配置文件在每次启动时 plugins2info_dict, plugins2cd_dict, plugins2exists_dict 将从本地读取 -# 除了 plugins2info_dict 新增内容键值会写入 plugins2info_file -# 其他修改或新增在 configs.config.py中对 plugins2info_dict, plugins2cd_dict, plugins2exists_dict 的配置无效 -# 目录:data/configs/ -USE_CONFIG_FILE: bool = False - # 回复消息名称 NICKNAME: str = "小真寻" @@ -95,13 +86,13 @@ CHECK_NOTICE_INFO_CD = 300 # 群检测,个人权限检测等各种检测提 # 注:即在 MALICIOUS_CHECK_TIME 时间内触发相同命令 MALICIOUS_BAN_COUNT 将被ban MALICIOUS_BAN_TIME 分钟 MALICIOUS_BAN_TIME: int = 30 # 恶意命令触发检测触发后ban的时长(分钟) -MALICIOUS_BAN_COUNT: int = 3 # 恶意命令触发检测最大触发次数 +MALICIOUS_BAN_COUNT: int = 6 # 恶意命令触发检测最大触发次数 MALICIOUS_CHECK_TIME: int = 5 # 恶意命令触发检测规定时间内(秒) # LEVEL DELETE_IMG_LEVEL: int = 7 # 删除图片权限 MOVE_IMG_LEVEL: int = 7 # 移动图片权限 -UPLOAD_LEVEL: int = 6 # 上传图片权限 +UPLOAD_IMG_LEVEL: int = 6 # 上传图片权限 BAN_LEVEL: int = 5 # BAN权限 OC_LEVEL: int = 2 # 开关群功能权限 MUTE_LEVEL: int = 5 # 更改禁言设置权限 @@ -117,7 +108,7 @@ HIBIAPI_BOOKMARKS: int = 5000 # 需要为哪些群更新最新版gocq吗?(上传最新版gocq) # 示例:[434995955, 239483248] -UPDATE_GOCQ_GROUP: List[int] = [] +UPDATE_GOCQ_GROUP: List[int] = [774261838] # 是否存储色图 DOWNLOAD_SETU: bool = True @@ -132,173 +123,6 @@ IMPORT_DEFAULT_SHOP_GOODS: bool = True # 真寻是否自动更新 AUTO_UPDATE_ZHENXUN: bool = True -# 群管理员功能 与 对应权限 -admin_plugins_auth = { - "custom_welcome_message": OC_LEVEL, - "group_notification_state": OC_LEVEL, - "switch_rule": OC_LEVEL, - "update_group_member_info": OC_LEVEL, - "ban": BAN_LEVEL, - "delete_img": DELETE_IMG_LEVEL, - "move_img": MOVE_IMG_LEVEL, - "upload_img": UPLOAD_LEVEL, - "admin_help": 1, - "mute": MUTE_LEVEL, - "member_activity_handle": MEMBER_ACTIVITY_LEVEL, -} - -# 需要cd的功能(方便管理)[秒] -# 自定义的功能需要cd也可以在此配置 -# key:模块名称 -# cd:cd 时长(秒) -# status:此限制的开关状态 -# check_type:'private'/'group'/'all',限制私聊/群聊/全部 -# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id -# 示例:'user':用户N秒内触发1次,'group':群N秒内触发1次 -# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称 -# rst 为 "" 或 None 时则不回复 -# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]" -# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批" -# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑ -plugins2cd_dict = { - "open_cases": { - "cd": 5, - "status": True, - "check_type": "all", - "limit_type": "user", - "rst": "着什么急啊,慢慢来!", - }, - "send_setu": { - "cd": 5, - "status": True, - "check_type": "all", - "limit_type": "user", - "rst": "您冲得太快了,请稍候再冲", - }, - "sign_in": { - "cd": 5, - "status": True, - "check_type": "group", - "limit_type": "user", - "rst": None, - } -} - -# 用户调用阻塞(方便管理) -# 即 当用户调用此功能还未结束时 -# 用发送消息阻止用户重复调用此命令直到该命令结束 -# 参数同上 plugin2cd_dict -plugins2exists_dict = { - "send_setu": { - "status": True, - "check_type": "all", - "limit_type": "user", - "rst": "您有色图正在处理,请稍等.....", - }, - "pixiv": { - "status": True, - "check_type": "all", - "limit_type": "user", - "rst": "P站排行榜或搜图正在搜索,请不要重复触发命令...", - }, - "pix": { - "status": True, - "check_type": "all", - "limit_type": "user", - "rst": "您有PIX图片正在处理,请稍等...", - } -} - -# 模块与对应命令和对应群权限 -# 用于生成帮助图片 和 开关功能 -# key:模块名称 -# level:需要的群等级 -# default_status:加入群时功能的默认开关状态 -# cmd:关闭[cmd] 都会触发命令 关闭对应功能,cmd列表第一个词为统计的功能名称 -plugins2info_dict = { - "sign_in": {"level": 5, "default_status": True, "cmd": ["签到"]}, - "send_img": { - "level": 5, - "default_status": True, - "cmd": ["发送图片", "发图", "萝莉", "美图", "壁纸"], - }, - "send_setu": {"level": 9, "default_status": True, "cmd": ["色图", "涩图", "瑟图", "查色图"]}, - "white2black": {"level": 5, "default_status": True, "cmd": ["黑白图", "黑白草图"]}, - "coser": {"level": 9, "default_status": True, "cmd": ["coser", "cos"]}, - "quotations": {"level": 5, "default_status": True, "cmd": ["语录"]}, - "jitang": {"level": 5, "default_status": True, "cmd": ["鸡汤"]}, - "send_dinggong_voice": { - "level": 5, - "default_status": True, - "cmd": ["骂我", "骂老子", "骂劳资"], - }, - "open_cases": { - "level": 5, - "default_status": True, - "cmd": ["开箱", "我的开箱", "群开箱统计", "我的金色"], - }, - "luxun": {"level": 5, "default_status": True, "cmd": ["鲁迅说", "鲁迅说过"]}, - "fake_msg": {"level": 5, "default_status": True, "cmd": ["假消息"]}, - "buy": {"level": 5, "default_status": True, "cmd": ["购买", "购买道具"]}, - "my_gold": {"level": 5, "default_status": True, "cmd": ["我的金币"]}, - "my_props": {"level": 5, "default_status": True, "cmd": ["我的道具"]}, - "shop_handle": {"level": 5, "default_status": True, "cmd": ["商店"]}, - "update_pic": {"level": 5, "default_status": True, "cmd": ["图片", "操作图片", "修改图片"]}, - "search_buff_skin_price": {"level": 5, "default_status": True, "cmd": ["查询皮肤"]}, - "weather": {"level": 5, "default_status": True, "cmd": ["天气", "查询天气", "天气查询"]}, - "yiqing": {"level": 5, "default_status": True, "cmd": ["疫情", "疫情查询", "查询疫情"]}, - "what_anime": {"level": 5, "default_status": True, "cmd": ["识番"]}, - "search_anime": {"level": 5, "default_status": True, "cmd": ["搜番"]}, - "songpicker2": {"level": 5, "default_status": True, "cmd": ["点歌"]}, - "epic": {"level": 5, "default_status": True, "cmd": ["epic"]}, - "pixiv": {"level": 9, "default_status": True, "cmd": ["pixiv", "p站排行", "搜图"]}, - "poke": {"level": 5, "default_status": True, "cmd": ["戳一戳", "拍一拍"]}, - "draw_card": { - "level": 5, - "default_status": True, - "cmd": [ - "抽卡", - "游戏抽卡", - ], - }, - "ai": {"level": 5, "default_status": True, "cmd": ["ai", "Ai", "AI", "aI"]}, - "one_friend": {"level": 5, "default_status": True, "cmd": ["我有一个朋友", "我有一个朋友想问问"]}, - "translate": { - "level": 5, - "default_status": True, - "cmd": ["翻译", "英翻", "翻英", "日翻", "翻日", "韩翻", "翻韩"], - }, - "nonebot_plugin_picsearcher": {"level": 5, "default_status": True, "cmd": ["识图"]}, - "almanac": {"level": 5, "default_status": True, "cmd": ["原神黄历", "黄历"]}, - "material_remind": {"level": 5, "default_status": True, "cmd": ["今日素材", "天赋材料"]}, - "qiu_qiu_translation": { - "level": 5, - "default_status": True, - "cmd": ["丘丘翻译", "丘丘一下", "丘丘语翻译"], - }, - "query_resource_points": { - "level": 5, - "default_status": True, - "cmd": ["原神资源查询", "原神资源列表"], - }, - "russian": {"level": 5, "default_status": True, "cmd": ["俄罗斯轮盘", "俄罗斯转盘", "装弹"]}, - "gold_redbag": {"level": 5, "default_status": True, "cmd": ["塞红包", "红包", "抢红包"]}, - "poetry": {"level": 5, "default_status": True, "cmd": ["念诗", "来首诗", "念首诗"]}, - "comments_163": { - "level": 5, - "default_status": True, - "cmd": ["到点了", "12点了", "网易云热评", "网易云评论"], - }, - "cover": {"level": 5, "default_status": True, "cmd": ["b封面", "B封面"]}, - "pid_search": {"level": 9, "default_status": True, "cmd": ["p搜", "P搜"]}, - "pix": { - "level": 5, - "default_status": True, - "cmd": ["pix", "PIX", "pIX", "Pix", "PIx"], - }, - "wbtop": {"level": 5, "default_status": True, "cmd": ["微博热搜", "微博", "wbtop"]}, - "update_info": {"level": 5, "default_status": True, "cmd": ["更新信息", "更新日志"]}, -} if TL_M_KEY: TL_KEY = TL_M_KEY @@ -312,9 +136,4 @@ HIBIAPI = HIBIAPI[:-1] if HIBIAPI[-1] == "/" else HIBIAPI RSSHUBAPP = RSSHUBAPP[:-1] if RSSHUBAPP[-1] == "/" else RSSHUBAPP -if USE_CONFIG_FILE: - # 读取配置文件 - plugins2info_dict, plugins2cd_dict, plugins2exists_dict = init_config( - plugins2info_dict, plugins2cd_dict, plugins2exists_dict, DATA_PATH - ) diff --git a/configs/path_config.py b/configs/path_config.py index 32c6c474..7bae46d4 100644 --- a/configs/path_config.py +++ b/configs/path_config.py @@ -1,17 +1,15 @@ -from .utils.util import get_config_data from pathlib import Path -# from configs.config import USE_CONFIG_FILE # 图片路径 IMAGE_PATH = Path("resources/img/") # 音频路径 VOICE_PATH = Path("resources/voice/") # 文本路径 -TXT_PATH = Path("resources/txt/") +TEXT_PATH = Path("resources/txt/") # 日志路径 LOG_PATH = Path("log/") # 字体路径 -TTF_PATH = Path("resources/ttf/") +FONT_PATH = Path("resources/ttf/") # 数据路径 DATA_PATH = Path("data/") # 临时图片路径 @@ -19,38 +17,20 @@ 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']) + global IMAGE_PATH, VOICE_PATH, TEXT_PATH, LOG_PATH, FONT_PATH, DATA_PATH, 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) + TEXT_PATH.mkdir(parents=True, exist_ok=True) LOG_PATH.mkdir(parents=True, exist_ok=True) - TTF_PATH.mkdir(parents=True, exist_ok=True) + FONT_PATH.mkdir(parents=True, exist_ok=True) DATA_PATH.mkdir(parents=True, exist_ok=True) TEMP_PATH.mkdir(parents=True, exist_ok=True) IMAGE_PATH = str(IMAGE_PATH.absolute()) + '/' VOICE_PATH = str(VOICE_PATH.absolute()) + '/' - TXT_PATH = str(TXT_PATH.absolute()) + '/' + TEXT_PATH = str(TEXT_PATH.absolute()) + '/' LOG_PATH = str(LOG_PATH.absolute()) + '/' - TTF_PATH = str(TTF_PATH.absolute()) + '/' + FONT_PATH = str(FONT_PATH.absolute()) + '/' DATA_PATH = str(DATA_PATH.absolute()) + '/' TEMP_PATH = str(TEMP_PATH.absolute()) + '/' @@ -58,5 +38,4 @@ def init_path(): init_path() -if __name__ == '__main__': - print(IMAGE_PATH) + diff --git a/configs/utils/init_config.py b/configs/utils/init_config.py deleted file mode 100644 index 1dc9b06a..00000000 --- a/configs/utils/init_config.py +++ /dev/null @@ -1,42 +0,0 @@ -from pathlib import Path -try: - import ujson as json -except ModuleNotFoundError: - import json - - -def init_config(plugins2info_dict, plugins2cd_dict, plugins2exists_dict, DATA_PATH): - plugins2info_file = Path(DATA_PATH) / 'configs' / 'plugins2info.json' - plugins2info_file.parent.mkdir(exist_ok=True, parents=True) - - if plugins2info_file.exists(): - with open(plugins2info_file, 'r', encoding='utf8') as f: - _data = json.load(f) - for p in plugins2info_dict: - if not _data.get(p): - _data[p] = plugins2info_dict[p] - with open(plugins2info_file, 'w') as wf: - json.dump(_data, wf, ensure_ascii=False, indent=4) - plugins2info_dict = _data - else: - with open(plugins2info_file, 'w', encoding='utf8') as wf: - json.dump(plugins2info_dict, wf, ensure_ascii=False, indent=4) - - plugins2cd_file = Path(DATA_PATH) / 'configs' / 'plugins2cd.json' - if plugins2cd_file.exists(): - with open(plugins2cd_file, 'r', encoding='utf8') as f: - plugins2cd_dict = json.load(f) - else: - with open(plugins2cd_file, 'w', encoding='utf8') as wf: - json.dump(plugins2cd_dict, wf, ensure_ascii=False, indent=4) - - plugins2exists_file = Path(DATA_PATH) / 'configs' / 'plugins2exists.json' - if plugins2exists_file.exists(): - with open(plugins2exists_file, 'r', encoding='utf8') as f: - plugins2exists_dict = json.load(f) - else: - with open(plugins2exists_file, 'w', encoding='utf8') as wf: - json.dump(plugins2exists_dict, wf, ensure_ascii=False, indent=4) - return plugins2info_dict, plugins2cd_dict, plugins2exists_dict - - diff --git a/configs/utils/util.py b/configs/utils/util.py deleted file mode 100644 index 08c7fb55..00000000 --- a/configs/utils/util.py +++ /dev/null @@ -1,35 +0,0 @@ -from pathlib import Path -from configs.utils.init_config import init_config -try: - import ujson as json -except ModuleNotFoundError: - import json - - -data: dict = {} - - -def get_config_data(): - global data - if not data: - try: - base_config = json.load(open(Path() / "config.json", 'r', encoding='utf8')) - plugins2cmd_config = json.load(open(Path() / 'configs' / 'plugins2cmd_config.json', 'r', encoding='utf8')) - other_config = json.load(open(Path() / 'configs' / 'other_config.json', 'r', encoding='utf8')) - for key in base_config.keys(): - data.update(base_config[key]) - for key in plugins2cmd_config.keys(): - data.update(plugins2cmd_config[key]) - for key in other_config.keys(): - data.update(other_config[key]) - except FileNotFoundError: - # logger.warning('配置文件不存在,生成默认配置....请填写数据库等必要数据后再次启动bot...') - init_config() - raise FileNotFoundError('配置文件不存在,生成默认配置....请填写数据库等必要数据后再次启动bot...') - except ValueError: - # logger.error('配置文件错误....') - raise ValueError('配置文件错误....') - return data - - - diff --git a/models/group_remind.py b/models/group_remind.py index 4f7216f7..0dab8985 100644 --- a/models/group_remind.py +++ b/models/group_remind.py @@ -102,4 +102,4 @@ class GroupRemind(db.Model): ).apply() return True except Exception as e: - return False + return False \ No newline at end of file diff --git a/plugins/Yu-Gi-Oh/__init__.py b/plugins/Yu-Gi-Oh/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/plugins/aconfig/__init__.py b/plugins/aconfig/__init__.py index df5663f0..a7dd57d3 100644 --- a/plugins/aconfig/__init__.py +++ b/plugins/aconfig/__init__.py @@ -12,22 +12,24 @@ from utils.utils import FreqLimiter from configs.config import NICKNAME -__plugin_name__ = "基本设置 [Hidden]" +__zx_plugin_name__ = "基本设置 [Hidden]" __plugin_usage__ = "用法: 无" +__plugin_version__ = 0.1 +__plugin_author__ = 'HibiKier' _flmt = FreqLimiter(300) -config_playgame = on_keyword({"打游戏"}, permission=GROUP, priority=1, block=True) +config_play_game = on_keyword({"打游戏"}, permission=GROUP, priority=1, block=True) -@config_playgame.handle() +@config_play_game.handle() async def _(bot: Bot, event: GroupMessageEvent, state: T_State): if not _flmt.check(event.group_id): return _flmt.start_cd(event.group_id) - await config_playgame.finish( + await config_play_game.finish( image(random.choice(os.listdir(IMAGE_PATH + "dayouxi/")), "dayouxi") ) diff --git a/plugins/admin_bot_manage/__init__.py b/plugins/admin_bot_manage/__init__.py new file mode 100644 index 00000000..4985070c --- /dev/null +++ b/plugins/admin_bot_manage/__init__.py @@ -0,0 +1,3 @@ +import nonebot + +nonebot.load_plugins("plugins/admin_bot_manage") diff --git a/plugins/admin_bot_manage/custom_welcome_message.py b/plugins/admin_bot_manage/custom_welcome_message.py index a83a047d..1a570c2e 100644 --- a/plugins/admin_bot_manage/custom_welcome_message.py +++ b/plugins/admin_bot_manage/custom_welcome_message.py @@ -4,16 +4,26 @@ from nonebot.typing import T_State from nonebot.adapters.cqhttp import Bot, GroupMessageEvent from .data_source import custom_group_welcome from nonebot.adapters.cqhttp.permission import GROUP +from configs.config import OC_LEVEL from services.log import logger -__plugin_name__ = "自定义进群欢迎消息" - +__zx_plugin_name__ = "自定义进群欢迎消息 [Admin]" __plugin_usage__ = """ - 自定义进群欢迎消息 [消息] [图片](可省略) - 示例:自定义进群欢迎消息 欢迎新人![图片] -""" - +usage: + 指令: + 自定义进群欢迎消息 ?[文本] ?[图片] + 示例:自定义进群欢迎消息 欢迎新人![图片] + Note:可以通过[at]来确认是否艾特新成员 + 示例:自定义进群欢迎消息 欢迎你[at] +""".strip() +__plugin_des__ = '简易的自定义群欢迎消息' +__plugin_cmd__ = ['自定义群欢迎消息 ?[文本] ?[图片]'] +__plugin_version__ = 0.1 +__plugin_author__ = 'HibiKier' +__plugin_settings__ = { + "admin_level": OC_LEVEL, +} custom_welcome = on_command( "自定义进群欢迎消息", @@ -26,12 +36,16 @@ custom_welcome = on_command( @custom_welcome.handle() async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - msg = get_message_text(event.json()) - imgs = get_message_imgs(event.json()) - if not msg and not imgs: - await custom_welcome.finish(__plugin_usage__) - await custom_welcome.send( - await custom_group_welcome(msg, imgs, event.user_id, event.group_id), - at_sender=True, - ) - logger.info(f"USER {event.user_id} GROUP {event.group_id} 自定义群欢迎消息:{msg}") + try: + msg = get_message_text(event.json()) + imgs = get_message_imgs(event.json()) + if not msg and not imgs: + await custom_welcome.finish(__plugin_usage__) + await custom_welcome.send( + await custom_group_welcome(msg, imgs, event.user_id, event.group_id), + at_sender=True, + ) + logger.info(f"USER {event.user_id} GROUP {event.group_id} 自定义群欢迎消息:{msg}") + except Exception as e: + logger.error(f"自定义进群欢迎消息发生错误 {type(e)}:{e}") + await custom_welcome.send("发生了一些未知错误...") diff --git a/plugins/admin_bot_manage/data_source.py b/plugins/admin_bot_manage/data_source.py index 5d08e24b..a6edb684 100644 --- a/plugins/admin_bot_manage/data_source.py +++ b/plugins/admin_bot_manage/data_source.py @@ -1,4 +1,5 @@ -from models.group_remind import GroupRemind +from typing import List +from nonebot.adapters.cqhttp.message import MessageSegment from services.log import logger from configs.path_config import DATA_PATH from utils.message_builder import image @@ -9,9 +10,8 @@ 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.manager import group_manager, plugins2settings_manager from utils.image_utils import CreateImg -from configs.config import plugins2info_dict import aiofiles import aiohttp import asyncio @@ -24,70 +24,16 @@ except ModuleNotFoundError: import json -command_dict = { - "早晚安": "zwa", - "进群欢迎": "hy", - "每日开箱重置提醒": "kxcz", - "b站转发解析": "blpar", - "epic": "epic", - "丢人爬": "pa", - "原神黄历提醒": "almanac", -} -command_list = list(command_dict.values()) -command_info_dt = { - "早晚安": "将会在每晚11:59晚安,在6:01早安哦", - "每日开箱重置提醒": "将会在每日00:01提示开箱重置!", - "epic": "将会在每日中午12:01发送可白嫖的epic游戏", - "原神黄历提醒": "将会在每日8:00发送当日的原神黄历", -} - - -async def remind_status(group: int, name: str, flag: bool) -> str: - _name = "" - if name in command_dict.values(): - _name = list(command_dict.keys())[list(command_dict.values()).index(name)] - if flag: - rst = "开启" - if await GroupRemind.get_status(group, name): - return f"该群已经{rst}过 {_name},请勿重复开启!" - else: - rst = "关闭" - if not await GroupRemind.get_status(group, name): - return f"该群已经{rst}过 {_name},请勿重复关闭!" - if await GroupRemind.set_status(group, name, flag): - info = command_info_dt[_name] if command_info_dt.get(_name) else "" - if info: - info = "\n" + info - return f"成功{rst} {_name}!0v0 {info}" - else: - return f"{rst} {_name} 失败了..." - - -async def set_group_status(name: str, group_id: int): - flag = None - if name[:2] == "开启": - flag = True - elif name[:2] == "关闭": - flag = False - cmd = name[2:] - if cmd in ["全部通知", "所有通知"]: - for command in command_list: - await remind_status(group_id, command, flag) - return f"已{name[:2]}所有通知!" - return await remind_status(group_id, command_dict[cmd], flag) - - -async def group_current_status(group_id: int): - result = ( - f'(被动技能)\n早晚安通知:{"√" if await GroupRemind.get_status(group_id, "zwa") else "×"}\n' - f'进群欢迎:{"√" if await GroupRemind.get_status(group_id, "hy") else "×"}\n' - f'每日开箱重置通知:{"√" if await GroupRemind.get_status(group_id, "kxcz") else "×"}\n' - f'b站转发解析:{"√" if await GroupRemind.get_status(group_id, "blpar") else "×"}\n' - f'丢人爬:{"√" if await GroupRemind.get_status(group_id, "pa") else "×"}\n' - f'epic免费游戏:{"√" if await GroupRemind.get_status(group_id, "epic") else "×"}\n' - f'原神黄历提醒:{"√" if await GroupRemind.get_status(group_id, "almanac") else "×"}' - ) - return result +async def group_current_status(group_id: int) -> str: + """ + 获取当前所有通知的开关 + :param group_id: 群号 + """ + rst = "[被动技能 状态]\n" + _data = group_manager.get_task_data() + for task in _data.keys(): + rst += f'{_data[task]}: {"√" if await group_manager.check_group_task_status(group_id, task) else "×"}\n' + return rst.strip() custom_welcome_msg_json = ( @@ -95,13 +41,21 @@ custom_welcome_msg_json = ( ) -async def custom_group_welcome(msg, imgs, user_id, group_id): +async def custom_group_welcome( + msg: str, imgs: List[str], user_id: int, group_id: int +) -> str: + """ + 替换群欢迎消息 + :param msg: 欢迎消息文本 + :param imgs: 欢迎消息图片,只取第一张 + :param user_id: 用户id,用于log记录 + :param group_id: 群号 + """ img_result = "" img = imgs[0] if imgs else "" result = "" if os.path.exists(DATA_PATH + f"custom_welcome_msg/{group_id}.jpg"): os.remove(DATA_PATH + f"custom_welcome_msg/{group_id}.jpg") - # print(custom_welcome_msg_json) if not custom_welcome_msg_json.exists(): custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True) data = {} @@ -133,54 +87,99 @@ async def custom_group_welcome(msg, imgs, user_id, group_id): return f"替换群欢迎消息成功:\n{result}" + img_result -def change_group_switch(cmd: str, group_id: int, is_super: bool = False): +task_data = None + + +async def change_group_switch(cmd: str, group_id: int, is_super: bool = False): + global task_data + """ + 修改群功能状态 + :param cmd: 功能名称 + :param group_id: 群号 + :param is_super: 是否位超级用户,超级用户用于私聊开关功能状态 + """ + if not task_data: + task_data = group_manager.get_task_data() group_help_file = Path(DATA_PATH) / "group_help" / f"{group_id}.png" - group_id = str(group_id) status = cmd[:2] cmd = cmd[2:] - for plugin_cmd in plugins2info_dict.keys(): - if cmd in plugins2info_dict[plugin_cmd]["cmd"]: - if is_super: - plugin_cmd = f'{plugin_cmd}:super' + type_ = 'plugin' + modules = plugins2settings_manager.get_plugin_module(cmd, True) + if cmd == '全部被动': + for task in task_data: if status == "开启": - if group_manager.get_plugin_status(plugin_cmd, group_id): - return f"功能 {cmd} 正处于开启状态!不要重复开启." - group_manager.unblock_plugin(plugin_cmd, group_id) + if not await group_manager.check_group_task_status(group_id, task): + await group_manager.open_group_task(group_id, task) else: - if not group_manager.get_plugin_status(plugin_cmd, group_id): + if await group_manager.check_group_task_status(group_id, task): + await group_manager.close_group_task(group_id, task) + return f"已 {status} 全部被动技能!" + if cmd in [task_data[x] for x in task_data.keys()]: + type_ = 'task' + modules = [x for x in task_data.keys() if task_data[x] == cmd] + for module in modules: + if is_super: + module = f"{module}:super" + if status == "开启": + if type_ == 'task': + if await group_manager.check_group_task_status(group_id, module): + return f"被动 {task_data[module]} 正处于开启状态!不要重复开启." + await group_manager.open_group_task(group_id, module) + else: + if group_manager.get_plugin_status(module, group_id): + return f"功能 {cmd} 正处于开启状态!不要重复开启." + group_manager.unblock_plugin(module, group_id) + else: + if type_ == 'task': + if not await group_manager.check_group_task_status(group_id, module): + return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭." + await group_manager.close_group_task(group_id, module) + else: + if not group_manager.get_plugin_status(module, 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} 功能..." + group_manager.block_plugin(module, group_id) + if group_help_file.exists(): + group_help_file.unlink() + return f"{status} {cmd} 功能!" def set_plugin_status(cmd: str, block_type: str = "all"): + """ + 设置插件功能状态(超级用户使用) + :param cmd: 功能名称 + :param block_type: 限制类型, 'all': 私聊+群里, 'private': 私聊, 'group': 群聊 + """ 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 + module = plugins2settings_manager.get_plugin_module(cmd) + if status == "开启": + group_manager.unblock_plugin(module) + else: + group_manager.block_plugin(module, block_type=block_type) 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 +def _get_plugin_status() -> MessageSegment: + """ + 合成功能状态图片 + """ + rst = "\t功能\n" + flag_str = "状态".rjust(4) + "\n" + for module in plugins2settings_manager.get_data(): + flag = group_manager.get_plugin_block_type(module) + flag = flag.upper() + " CLOSE" if flag else "OPEN" + try: + rst += f'{plugins2settings_manager.get(module)["cmd"][0]}\n' + except IndexError: + rst += f"{module}\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) @@ -192,6 +191,10 @@ def _get_plugin_status(): async def update_member_info(group_id: int) -> bool: + """ + 更新群成员信息 + :param group_id: 群号 + """ bot = get_bot() _group_user_list = await bot.get_group_member_list(group_id=group_id) _error_member_list = [] @@ -267,7 +270,3 @@ async def update_member_info(group_id: int) -> bool: 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 deleted file mode 100644 index c6df4b61..00000000 --- a/plugins/admin_bot_manage/group_notification_state.py +++ /dev/null @@ -1,57 +0,0 @@ -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from .data_source import set_group_status, group_current_status -from nonebot.adapters.cqhttp.permission import GROUP -from services.log import logger -from nonebot import on_command - - -__plugin_name__ = "群通知开关" - -__plugin_usage__ = """ - 示例: - 开启早晚安 - 关闭早晚安 -""" - - -group_status = on_command( - "oc_reminds", - aliases={ - "开启早晚安", - "关闭早晚安", - "开启进群欢迎", - "关闭进群欢迎", - "开启每日开箱重置提醒", - "关闭每日开箱重置提醒", - "开启b站转发解析", - "关闭b站转发解析", - "开启epic通知", - "关闭epic通知", - "开启丢人爬", - "关闭丢人爬", - "开启原神黄历提醒", - "关闭原神黄历提醒", - "开启全部通知", - "开启所有通知", - "关闭全部通知", - "关闭所有通知", - "群通知状态", - }, - permission=GROUP, - priority=5, - block=True, -) - - -@group_status.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - if state["_prefix"]["raw_command"] in ["群通知状态"]: - await group_status.finish(await group_current_status(event.group_id)) - await group_status.send( - await set_group_status(state["_prefix"]["raw_command"], event.group_id), - at_sender=True, - ) - logger.info( - f'USER {event.user_id} GROUP {event.group_id} 使用群通知管理命令 {state["_prefix"]["raw_command"]}' - ) diff --git a/plugins/admin_bot_manage/rule.py b/plugins/admin_bot_manage/rule.py new file mode 100644 index 00000000..397b9c8d --- /dev/null +++ b/plugins/admin_bot_manage/rule.py @@ -0,0 +1,42 @@ +from nonebot.adapters.cqhttp import Bot, Event +from nonebot.typing import T_State +from utils.manager import group_manager, plugins2settings_manager +from utils.utils import get_message_text +from services.log import logger + +cmd = [] + + +def switch_rule(bot: Bot, event: Event, state: T_State) -> bool: + """ + 检测文本是否是关闭功能命令 + :param bot: pass + :param event: pass + :param state: pass + """ + try: + if not cmd: + cmd.append('关闭全部被动') + cmd.append('开启全部被动') + _data = group_manager.get_task_data() + for key in _data: + cmd.append(f"开启{_data[key]}") + cmd.append(f"关闭{_data[key]}") + cmd.append(f"开启 {_data[key]}") + cmd.append(f"关闭 {_data[key]}") + _data = plugins2settings_manager.get_data() + for key in _data: + try: + for x in _data[key]["cmd"]: + cmd.append(f"开启{x}") + cmd.append(f"关闭{x}") + cmd.append(f"开启 {x}") + cmd.append(f"关闭 {x}") + except KeyError: + pass + msg = get_message_text(event.json()).split() + msg = msg[0] if msg else "" + return msg in cmd + except Exception as e: + logger.error(f"检测是否为功能开关命令发生错误 {type(e)}: {e}") + return False diff --git a/plugins/admin_bot_manage/switch_rule.py b/plugins/admin_bot_manage/switch_rule.py index 80d6c5ac..2f2a5b84 100644 --- a/plugins/admin_bot_manage/switch_rule.py +++ b/plugins/admin_bot_manage/switch_rule.py @@ -1,78 +1,106 @@ -from nonebot import on_command +from nonebot import on_command, on_message from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent -from .data_source import change_group_switch, set_plugin_status, get_plugin_status +from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent, GROUP +from .data_source import ( + change_group_switch, + set_plugin_status, + get_plugin_status, + group_current_status, +) from services.log import logger -from configs.config import plugins2info_dict, NICKNAME +from configs.config import NICKNAME, OC_LEVEL from utils.utils import get_message_text, is_number from nonebot.permission import SUPERUSER +from .rule import switch_rule -__plugin_name__ = "群功能开关" +__zx_plugin_name__ = "群功能开关 [Admin]" __plugin_usage__ = """ - 示例: - 开启色图 - 关闭色图 -""" +usage: + 群内功能与被动技能开关 + 指令: + 开启/关闭[功能] + 群被动状态 + 开启全部被动 + 关闭全部被动 + 示例:开启/关闭色图 +""".strip() +__plugin_superuser_usage__ = """ +usage: + 功能总开关与指定群禁用 + 指令: + 功能状态 + 开启/关闭[功能] [group] + 开启/关闭[功能] ['private'/'group'] +""".strip() +__plugin_des__ = "群内功能开关" +__plugin_cmd__ = [ + "开启/关闭[功能]", + "群被动状态", + "开启全部被动", + "关闭全部被动", + "功能状态 [_superuser]", + "开启/关闭[功能] [group] [_superuser]", + "开启/关闭[功能] ['private'/'group'] [_superuser]", +] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "admin_level": OC_LEVEL, +} + +switch_rule_matcher = on_message(rule=switch_rule, priority=4, block=True) + +plugins_status = on_command("功能状态", permission=SUPERUSER, priority=5, block=True) + +group_task_status = on_command("群被动状态", permission=GROUP, priority=5, block=True) -cmds = [] -for cmd_list in plugins2info_dict.values(): - for cmd in cmd_list["cmd"]: - cmds.append(f"开启{cmd}") - cmds.append(f"关闭{cmd}") -cmds = set(cmds) - - -switch_rule = on_command( - "switch_rule", aliases=cmds, priority=5, block=True -) - -plugins_status = on_command('功能状态', permission=SUPERUSER, priority=5, block=True) - - -@switch_rule.handle() +@switch_rule_matcher.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): + _cmd = get_message_text(event.json()).split()[0] 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"]}' - ) + await switch_rule_matcher.send(await change_group_switch(_cmd, event.group_id)) + logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用群功能管理命令 {_cmd}") else: if str(event.user_id) in bot.config.superusers: - block_type = get_message_text(event.json()) - block_type = block_type if block_type else 'a' - _cmd = state["_prefix"]["raw_command"].strip() + block_type = " ".join(get_message_text(event.json()).split()[1:]) + block_type = block_type if block_type else "a" 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:]} 功能') - elif block_type in ['all', 'private', 'group', 'a', 'p', 'g']: - 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 + 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_matcher.finish(f"{NICKNAME}未加入群聊:{block_type}") + await 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_matcher.send( + f"已禁用群聊 {group_name}({block_type}) 的 {_cmd[2:]} 功能" + ) + elif block_type in ["all", "private", "group", "a", "p", "g"]: + 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:]}') + if block_type == "all": + await switch_rule_matcher.send(f"已{_cmd[:2]}功能:{_cmd[2:]}") + elif block_type == "private": + await switch_rule_matcher.send(f"已在私聊中{_cmd[:2]}功能:{_cmd[2:]}") else: - await switch_rule.send(f'已在群聊中{_cmd[:2]}功能:{_cmd[2:]}') + await switch_rule_matcher.send(f"已在群聊中{_cmd[:2]}功能:{_cmd[2:]}") else: - await switch_rule.finish('格式错误:关闭[功能] [group]/[p/g]') - logger.info( - f'USER {event.user_id} 使用功能管理命令 {state["_prefix"]["raw_command"]} | {block_type}' - ) + await switch_rule_matcher.finish("格式错误:关闭[功能] [group]/[p/g]") + logger.info(f"USER {event.user_id} 使用功能管理命令 {_cmd} | {block_type}") @plugins_status.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await plugins_status.send(await get_plugin_status()) + +@group_task_status.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + await group_task_status.send(await group_current_status(event.group_id)) diff --git a/plugins/admin_bot_manage/timing_task.py b/plugins/admin_bot_manage/timing_task.py index 8fcee5ab..598ab7ea 100644 --- a/plugins/admin_bot_manage/timing_task.py +++ b/plugins/admin_bot_manage/timing_task.py @@ -5,6 +5,13 @@ from models.group_info import GroupInfo from asyncpg.exceptions import ConnectionDoesNotExistError +__zx_plugin_name__ = '管理方面定时任务 [Hidden]' +__plugin_usage__ = '无' +__plugin_des__ = '成员信息和管理权限的定时更新' +__plugin_version__ = 0.1 +__plugin_author__ = 'HibiKier' + + # 自动更新群员信息 @scheduler.scheduled_job( "cron", @@ -13,14 +20,15 @@ from asyncpg.exceptions import ConnectionDoesNotExistError ) async def _(): bot = get_bot() - gl = await bot.get_group_list(self_id=bot.self_id) - gl = [g["group_id"] for g in gl] - for g in gl: - try: - await update_member_info(g) - logger.info(f"更新群组 g:{g} 成功") - except Exception as e: - logger.error(f"更新群组错误 g:{g} e:{e}") + if bot: + gl = await bot.get_group_list() + gl = [g["group_id"] for g in gl] + for g in gl: + try: + await update_member_info(g) + logger.info(f"更新群组 g:{g} 成功") + except Exception as e: + logger.error(f"更新群组错误 g:{g} e:{e}") # 快速更新群员信息以及管理员权限 @@ -31,12 +39,13 @@ async def _(): async def _(): try: bot = get_bot() - gl = await bot.get_group_list(self_id=bot.self_id) - gl = [g["group_id"] for g in gl] - all_group = [x.group_id for x in await GroupInfo.get_all_group()] - for g in gl: - if g not in all_group: - await update_member_info(g) - logger.info(f"快速更新群信息以及权限:{g}") + if bot: + gl = await bot.get_group_list() + gl = [g["group_id"] for g in gl] + all_group = [x.group_id for x in await GroupInfo.get_all_group()] + for g in gl: + if g not in all_group: + await update_member_info(g) + logger.info(f"快速更新群信息以及权限:{g}") except (IndexError, ConnectionDoesNotExistError): pass diff --git a/plugins/admin_bot_manage/update_group_member_info.py b/plugins/admin_bot_manage/update_group_member_info.py index f21c2837..9a5cddec 100644 --- a/plugins/admin_bot_manage/update_group_member_info.py +++ b/plugins/admin_bot_manage/update_group_member_info.py @@ -3,14 +3,20 @@ from nonebot.typing import T_State from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent from .data_source import update_member_info -__plugin_name__ = "更新群组成员列表" - +__zx_plugin_name__ = "更新群组成员列表 [Admin]" __plugin_usage__ = """ - 说明: - 更新群组成员的基本信息 - 示例: - 更新群组成员列表 -""" +usage: + 更新群组成员的基本信息 + 指令: + 更新群组成员列表/更新群组成员信息 +""".strip() +__plugin_des__ = '更新群组成员列表' +__plugin_cmd__ = ['更新群组成员列表'] +__plugin_version__ = 0.1 +__plugin_author__ = 'HibiKier' +__plugin_settings__ = { + "admin_level": 1, +} refresh_member_group = on_command( diff --git a/plugins/admin_config.py b/plugins/admin_config.py index 797c97df..82a750e6 100644 --- a/plugins/admin_config.py +++ b/plugins/admin_config.py @@ -7,9 +7,9 @@ from models.group_member_info import GroupInfoUser from configs.config import ADMIN_DEFAULT_AUTH -__plugin_name__ = "群管理员监测" - -__plugin_usage__ = "无" +__zx_plugin_name__ = "群管理员变动监测 [Hidden]" +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" admin_notice = on_notice(priority=5) diff --git a/plugins/admin_help/__init__.py b/plugins/admin_help/__init__.py index 7922d5da..0b110162 100644 --- a/plugins/admin_help/__init__.py +++ b/plugins/admin_help/__init__.py @@ -2,55 +2,26 @@ from nonebot import on_command from nonebot.typing import T_State from nonebot.adapters import Bot 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 +from .data_source import create_help_image, admin_help_image -__plugin_name__ = '管理帮助 [Hidden]' -__plugin_usage__ = f'''[权限等级]管理帮助: - [1]1.更新群组成员列表 - [2]2.功能开关 --> 指令:开启/关闭xx功能 - [2]3.查看群被动技能 --> 指令:群通知状态 - [2]4.自定义群欢迎 --> 指令:自定义进群欢迎消息 - [5]5.将用户拉入{NICKNAME}黑名单 --> .ban/.unban - [5]6.刷屏禁言相关 -> 指令:刷屏检测设置/设置检测时间 - \t\t/设置检测次数/设置禁言时长 - [5]7.群订阅相关 -> 指令:添加订阅 [主播/up/番剧] [id/番名/链接] - \t\t/删除订阅 [id]/ 查看订阅 - [5]8.群员活跃度相关 --> 指令:群员活跃检测设置 - 设置群员活跃检测时长(天) - 添加群员活跃检测白名单[at]... - 查看群员活跃检测白名单 - [6]8.上传图片/连续上传图片(6) - [7]9.移动图片(7) - [7]10.删除图片(7) -对我说 “{NICKNAME}帮助 指令” 获取对应详细帮助 -群主与管理员默认 5 级权限 -''' - -passive_help = '''【被动技能开关(2): - 开启/关闭早晚安 - 开启/关闭进群欢迎 - 开启/关闭每日开箱重置提醒 - 开启/关闭b站转发解析 - 开启/关闭丢人爬 - 开启/关闭epic通知 - 开启/关闭原神黄历提醒 - 开启/关闭全部通知】 -''' +__zx_plugin_name__ = '管理帮助 [Admin]' +__plugin_usage__ = '管理员帮助,在群内回复“管理员帮助”' +__plugin_version__ = 0.1 +__plugin_author__ = 'HibiKier' +__plugin_settings__ = { + "admin_level": 1, +} admin_help = on_command("管理员帮助", aliases={"管理帮助"}, priority=5, block=True) -admin_help_img = CreateImg(1200, 600, font_size=24) -admin_help_img.text((10, 10), __plugin_usage__) -text_img = CreateImg(450, 600, font_size=24) -text_img.text((0, 0), passive_help) -admin_help_img.paste(text_img, (850, 50)) -admin_help_img.save(IMAGE_PATH + 'admin_help_img.png') +if admin_help_image.exists(): + admin_help_image.unlink() @admin_help.handle() async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + if not admin_help_image.exists(): + await create_help_image() await admin_help.send(image('admin_help_img.png')) diff --git a/plugins/admin_help/data_source.py b/plugins/admin_help/data_source.py new file mode 100644 index 00000000..48d87832 --- /dev/null +++ b/plugins/admin_help/data_source.py @@ -0,0 +1,91 @@ +from utils.image_utils import CreateImg +from configs.path_config import IMAGE_PATH +from services.log import logger +from utils.utils import get_matchers +from utils.manager import group_manager +from nonebot.adapters.cqhttp import Bot +from pathlib import Path +from nonebot import Driver +import asyncio +import nonebot + + +driver: Driver = nonebot.get_driver() + +background = Path(IMAGE_PATH) / "background" / "0.png" + +admin_help_image = Path(IMAGE_PATH) / 'admin_help_img.png' + + +@driver.on_bot_connect +async def create_help_image(bot: Bot = None): + """ + 创建管理员帮助图片 + """ + if not group_manager.get_task_data(): + await group_manager.init_group_task() + logger.info(f'已成功加载 {len(group_manager.get_task_data())} 个被动技能.') + await asyncio.get_event_loop().run_in_executor( + None, _create_help_image + ) + + +def _create_help_image(): + """ + 创建管理员帮助图片 + """ + _matchers = get_matchers() + _plugin_name_list = [] + width = 0 + _plugin_level = {} + for matcher in _matchers: + _plugin = nonebot.plugin.get_plugin(matcher.module) + _module = _plugin.module + try: + plugin_name = _module.__getattribute__("__zx_plugin_name__") + except AttributeError: + continue + try: + if ( + "[admin]" in plugin_name.lower() + and plugin_name not in _plugin_name_list + and plugin_name != "管理帮助 [Admin]" + ): + _plugin_name_list.append(plugin_name) + plugin_settings = _module.__getattribute__("__plugin_settings__") + plugin_des = _module.__getattribute__("__plugin_des__") + plugin_cmd = _module.__getattribute__("__plugin_cmd__") + plugin_cmd = [x for x in plugin_cmd if "[_superuser]" not in x] + admin_level = int(plugin_settings["admin_level"]) + if _plugin_level.get(admin_level): + _plugin_level[admin_level].append( + f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd) + ) + else: + _plugin_level[admin_level] = [ + f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd) + ] + x = len(f"[{admin_level}] {plugin_des} -> " + " / ".join(plugin_cmd)) * 23 + width = width if width > x else x + except AttributeError: + logger.warning(f"获取管理插件 {matcher.module}: {plugin_name} 设置失败...") + help_str = "* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" \ + "[权限等级] 管理员帮助:\n\n" + x = list(_plugin_level.keys()) + x.sort() + for level in x: + for help_ in _plugin_level[level]: + help_str += f"\t{help_}\n\n" + help_str += '-----[被动技能开关]-----\n\n' + task_data = group_manager.get_task_data() + for i, x in enumerate(task_data.keys()): + help_str += f'{i+1}.开启/关闭{task_data[x]}\n\n' + height = len(help_str.split("\n")) * 33 + A = CreateImg(width, height, font_size=24) + _background = CreateImg(width, height, background=background) + A.text((150, 110), help_str) + A.paste(_background, alpha=True) + A.save(admin_help_image) + logger.info(f'已成功加载 {len(_plugin_name_list)} 条管理员命令') + + diff --git a/plugins/ai/__init__.py b/plugins/ai/__init__.py index 7781e929..96af27e7 100644 --- a/plugins/ai/__init__.py +++ b/plugins/ai/__init__.py @@ -1,20 +1,33 @@ -from .data_source import get_chat_result, hello, no_result -from services.log import logger from nonebot import on_message -from nonebot.rule import to_me -from nonebot.typing import T_State from nonebot.adapters.cqhttp import ( Bot, - PrivateMessageEvent, + GroupMessageEvent, Message, MessageEvent, ) -from utils.utils import get_message_text, get_message_imgs +from nonebot.rule import to_me +from nonebot.typing import T_State + from models.friend_user import FriendUser from models.group_member_info import GroupInfoUser +from services.log import logger +from utils.utils import get_message_text, get_message_imgs +from .data_source import get_chat_result, hello, no_result +from configs.config import NICKNAME -__plugin_name__ = "AI [Hidden]" - +__zx_plugin_name__ = "AI" +__plugin_usage__ = f""" +usage: + 与{NICKNAME}普普通通的对话吧! +""" +__plugin_version__ = 0.1 +__plugin_author__ = 'HibiKier' +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["Ai", "ai", "AI", "aI"], +} ai = on_message(rule=to_me(), priority=8) @@ -38,20 +51,20 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): ]: await ai.finish(hello()) img = imgs[0] if imgs else "" - if isinstance(event, PrivateMessageEvent): - nickname = await FriendUser.get_friend_nickname(event.user_id) - else: + if isinstance(event, GroupMessageEvent): nickname = await GroupInfoUser.get_group_member_nickname( event.user_id, event.group_id ) + else: + nickname = await FriendUser.get_friend_nickname(event.user_id) if not nickname: - if isinstance(event, PrivateMessageEvent): - nickname = event.sender.nickname - else: + if isinstance(event, GroupMessageEvent): nickname = event.sender.card if event.sender.card else event.sender.nickname + else: + nickname = event.sender.nickname result = await get_chat_result(msg, img, event.user_id, nickname) logger.info( - f"USER {event.user_id} GROUP {event.group_id if not isinstance(event, PrivateMessageEvent) else ''} " + f"USER {event.user_id} GROUP {event.group_id if isinstance(event, GroupMessageEvent) else ''} " f"问题:{msg} ---- 回答:{result}" ) if result: diff --git a/plugins/ai/data_source.py b/plugins/ai/data_source.py index 3ad6faef..d197b83f 100644 --- a/plugins/ai/data_source.py +++ b/plugins/ai/data_source.py @@ -1,19 +1,21 @@ +import os +import random +import re + +import aiohttp +from aiohttp.client import ClientSession + 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 from utils.message_builder import image, face -from utils.utils import get_bot -import re -import aiohttp -import random -import os try: import ujson as json except ModuleNotFoundError: import json + url = "http://openapi.tuling123.com/openapi/api/v2" check_url = "https://v2.alapi.cn/api/censor/text" @@ -24,6 +26,14 @@ anime_data = json.load(open(DATA_PATH + "anime.json", "r", encoding="utf8")) async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str) -> str: + """ + 获取 AI 返回值,顺序:图灵 -> 青云客 + :param text: 问题 + :param img_url: 图片链接 + :param user_id: 用户id + :param nickname: 用户昵称 + :return: 回答 + """ global index if index == 5: index = 0 @@ -50,7 +60,15 @@ async def get_chat_result(text: str, img_url: str, user_id: int, nickname: str) # 图灵接口 -async def tu_ling(text: str, img_url: str, user_id: int, sess: ClientSession): +async def tu_ling(text: str, img_url: str, user_id: int, sess: ClientSession) -> str: + """ + 获取图灵接口的回复 + :param text: 问题 + :param img_url: 图片链接 + :param user_id: 用户id + :param sess: AIOHTTP SESSION + :return: 图灵回复 + """ global index try: if text: @@ -94,7 +112,13 @@ async def tu_ling(text: str, img_url: str, user_id: int, sess: ClientSession): # 屑 AI -async def xie_ai(text: str, sess: ClientSession): +async def xie_ai(text: str, sess: ClientSession) -> str: + """ + 获取青云客回复 + :param text: 问题 + :param sess: AIOHTTP SESSION + :return: 青云可回复 + """ async with sess.get( f"http://api.qingyunke.com/api.php?key=free&appid=0&msg={text}" ) as res: @@ -104,8 +128,8 @@ async def xie_ai(text: str, sess: ClientSession): content = data["content"] if "菲菲" in content: content = content.replace("菲菲", NICKNAME) - if '艳儿' in content: - content = content.replace('艳儿', NICKNAME) + if "艳儿" in content: + content = content.replace("艳儿", NICKNAME) if "公众号" in content: content = "" if "{br}" in content: @@ -123,11 +147,17 @@ async def xie_ai(text: str, sess: ClientSession): ) else: break - return content if not content and not ALAPI_AI_CHECK else await check_text(content, sess) + return ( + content + if not content and not ALAPI_AI_CHECK + else await check_text(content, sess) + ) -# 打招呼内容 def hello() -> str: + """ + 一些打招呼的内容 + """ result = random.choice( ( "哦豁?!", @@ -147,6 +177,9 @@ def hello() -> str: # 没有回答时回复内容 def no_result() -> str: + """ + 没有回答时的回复 + """ return ( random.choice( [ @@ -161,8 +194,12 @@ def no_result() -> str: ) -# 检测屑AI回复的文本是否是 *话 async def check_text(text: str, sess: ClientSession) -> str: + """ + ALAPI文本检测,主要针对青云客API,检测为恶俗文本改为无回复的回答 + :param text: 回复 + :param sess: AIOHTTP SESSION + """ if not ALAPI_TOKEN: return text params = {"token": ALAPI_TOKEN, "text": text} @@ -170,8 +207,8 @@ async def check_text(text: str, sess: ClientSession) -> str: async with sess.get(check_url, timeout=2, params=params) as response: data = await response.json() if data["code"] == 200: - if data['data']["conclusion_type"] == 2: - return '' + if data["data"]["conclusion_type"] == 2: + return "" except Exception as e: logger.error(f"检测违规文本错误...{type(e)}:{e}") return text diff --git a/plugins/alapi/__init__.py b/plugins/alapi/__init__.py new file mode 100644 index 00000000..f4c7b35f --- /dev/null +++ b/plugins/alapi/__init__.py @@ -0,0 +1,3 @@ +import nonebot + +nonebot.load_plugins("plugins/alapi") diff --git a/plugins/alapi/comments_163.py b/plugins/alapi/comments_163.py index 18bd9e47..12d10ba8 100644 --- a/plugins/alapi/comments_163.py +++ b/plugins/alapi/comments_163.py @@ -5,32 +5,44 @@ from configs.config import ALAPI_TOKEN from .data_source import get_data from services.log import logger -__plugin_name__ = '网易云热评' -__plugin_usage__ = '用法: 生了个人,我很抱歉' - -comments_163 = on_command("网易云热评", aliases={'网易云评论', '到点了', '12点了'}, priority=5, block=True) +__zx_plugin_name__ = "网易云热评" +__plugin_usage__ = """ +usage: + 到点了,还是防不了下塔 + 指令: + 网易云热评/到点了/12点了 +""".strip() +__plugin_des__ = "生了个人,我很抱歉" +__plugin_cmd__ = ["网易云热评", "到点了", "12点了"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["网易云热评", "网易云评论", "到点了", "12点了"], +} -comments_163_url = 'https://v2.alapi.cn/api/comment' +comments_163 = on_command( + "网易云热评", aliases={"网易云评论", "到点了", "12点了"}, priority=5, block=True +) + + +comments_163_url = "https://v2.alapi.cn/api/comment" @comments_163.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): - params = { - 'token': ALAPI_TOKEN - } + params = {"token": ALAPI_TOKEN} data, code = await get_data(comments_163_url, params) if code != 200: await comments_163.finish(data, at_sender=True) - data = data['data'] - comment = data['comment_content'] - song_name = data['title'] - await comments_163.send(f'{comment}\n\t——《{song_name}》') + data = data["data"] + comment = data["comment_content"] + 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 isinstance(event, GroupMessageEvent) else 'private'})" - f" 发送网易云热评: {comment} \n\t\t————{song_name}") - - - - - + f" 发送网易云热评: {comment} \n\t\t————{song_name}" + ) diff --git a/plugins/alapi/cover.py b/plugins/alapi/cover.py index c722c300..48efbbcc 100644 --- a/plugins/alapi/cover.py +++ b/plugins/alapi/cover.py @@ -7,9 +7,22 @@ from utils.utils import get_message_text from .data_source import get_data from services.log import logger -__plugin_name__ = 'b封面' -__plugin_usage__ = '用法: b封面 (链接,av,bv,cv,直播id)\n\t' \ - '示例:b封面 av86863038' +__zx_plugin_name__ = 'b封面' +__plugin_usage__ = """usage: + b封面 [链接/av/bv/cv/直播id] + 示例:b封面 av86863038 +""" +__plugin_des__ = '快捷的b站视频封面获取方式' +__plugin_cmd__ = ['b封面/B封面'] +__plugin_type__ = ('一些工具',) +__plugin_version__ = 0.1 +__plugin_author__ = 'HibiKier' +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["b封面", 'B封面'], +} cover = on_command('b封面', aliases={'B封面'}, priority=5, block=True) diff --git a/plugins/alapi/data_source.py b/plugins/alapi/data_source.py index c0f38e24..7c13ab5c 100644 --- a/plugins/alapi/data_source.py +++ b/plugins/alapi/data_source.py @@ -2,10 +2,16 @@ 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 +from typing import Union import aiohttp -async def get_data(url: str, params: dict): +async def get_data(url: str, params: dict) -> 'Union[dict, str], int': + """ + 获取ALAPI数据 + :param url: 请求链接 + :param params: 参数 + """ async with aiohttp.ClientSession() as session: try: async with session.get( @@ -22,7 +28,11 @@ async def get_data(url: str, params: dict): return "超时了....", 998 -def gen_wbtop_pic(data) -> MessageSegment: +def gen_wbtop_pic(data: dict) -> MessageSegment: + """ + 生成微博热搜图片 + :param data: 微博热搜数据 + """ 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) diff --git a/plugins/alapi/poetry.py b/plugins/alapi/poetry.py index d2c2fa5e..009ef226 100644 --- a/plugins/alapi/poetry.py +++ b/plugins/alapi/poetry.py @@ -5,9 +5,21 @@ from configs.config import ALAPI_TOKEN from services.log import logger from .data_source import get_data -__plugin_name__ = '古诗' -__plugin_usage__ = '用法: 无' - +__zx_plugin_name__ = '古诗' +__plugin_usage__ = """usage: + 平白无故念首诗 + 示例:念诗/来首诗/念首诗 +""" +__plugin_des__ = '为什么突然文艺起来了!' +__plugin_cmd__ = ['念诗/来首诗/念首诗'] +__plugin_version__ = 0.1 +__plugin_author__ = 'HibiKier' +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ['念诗', '来首诗', '念首诗'], +} poetry = on_command("念诗", aliases={'来首诗', '念首诗'}, priority=5, block=True) diff --git a/plugins/alapi/wbtop.py b/plugins/alapi/wbtop.py index 817e3a61..deca4604 100644 --- a/plugins/alapi/wbtop.py +++ b/plugins/alapi/wbtop.py @@ -10,9 +10,25 @@ from configs.path_config import IMAGE_PATH from utils.message_builder import image import asyncio -__plugin_name__ = '微博热搜' -__plugin_usage__ = '用法: 无' - +__zx_plugin_name__ = '微博热搜' +__plugin_usage__ = """ +usage: + 在QQ上吃个瓜 + 指令: + 微博热搜:发送实时热搜 + 微博热搜 [id]:截图该热搜页面 + 示例:微博热搜 5 +""".strip() +__plugin_des__ = '刚买完瓜,在吃瓜现场' +__plugin_cmd__ = ['微博热搜', '微博热搜 [id]'] +__plugin_version__ = 0.1 +__plugin_author__ = 'HibiKier' +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ['微博热搜'], +} wbtop = on_command("wbtop", aliases={'微博热搜'}, priority=5, block=True) @@ -52,9 +68,9 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): 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 div.screenshot(path=f'{IMAGE_PATH}/temp/wbtop_{event.user_id}.png', timeout=100000) await page.close() - await wbtop.send(image(f'webtop_{event.user_id}.png', 'temp')) + await wbtop.send(image(f'wbtop_{event.user_id}.png', 'temp')) except Exception as e: logger.error(f'微博热搜截图出错... {type(e)}: {e}') if page: diff --git a/plugins/auto_invite/__init__.py b/plugins/auto_invite/__init__.py index ee42f678..74009e7d 100644 --- a/plugins/auto_invite/__init__.py +++ b/plugins/auto_invite/__init__.py @@ -7,7 +7,9 @@ from nonebot.adapters.cqhttp.exception import ActionFailed from utils.utils import scheduler import time -__plugin_name__ = "好友群聊处理请求 [Hidden]" +__zx_plugin_name__ = "好友群聊处理请求 [Hidden]" +__plugin_version__ = 0.1 +__plugin_author__ = 'HibiKier' friend_req = on_request(priority=5) diff --git a/plugins/ban/__init__.py b/plugins/ban/__init__.py index 6a4c7eac..f05900b9 100644 --- a/plugins/ban/__init__.py +++ b/plugins/ban/__init__.py @@ -5,21 +5,37 @@ from nonebot.typing import T_State from nonebot.adapters.cqhttp import Bot from nonebot.adapters.cqhttp import GroupMessageEvent, PrivateMessageEvent from utils.utils import get_message_at, get_message_text, is_number -from configs.config import NICKNAME +from configs.config import NICKNAME, BAN_LEVEL from nonebot.permission import SUPERUSER from services.log import logger -__plugin_name__ = "Ban/unBan" -__plugin_usage__ = ( - "用法:\n" - f"(不是禁言!是针对{NICKNAME}是否处理封禁用户消息)\n" - "封禁/解封用户 [小时] [分钟]\n" - "示例:.ban @djdsk\n" - "示例:.ban @djdsk 0 30\n" - "示例:.ban @sdasf 4\n" - "示例:.unban @sdasf" -) +__zx_plugin_name__ = "封禁Ban用户 [Admin]" +__plugin_usage__ = """ +usage: + 将用户拉入或拉出黑名单 + 指令: + .ban [at] ?[小时] ?[分钟] + .unban + 示例:.ban @user + 示例:.ban @user 6 + 示例:.ban @user 3 10 + 示例:.unban @user +""".strip() +__plugin_superuser_usage__ = """ +usage: + 屏蔽用户消息,相当于最上级.ban + 指令: + b了 [at] + 示例:b了 @user +""".strip() +__plugin_des__ = '你被逮捕了!丢进小黑屋!' +__plugin_cmd__ = ['.ban [at] ?[小时] ?[分钟]', '.unban [at]', 'b了 [at] [_superuser]'] +__plugin_version__ = 0.1 +__plugin_author__ = 'HibiKier' +__plugin_settings__ = { + "admin_level": BAN_LEVEL, +} ban = on_command( @@ -167,7 +183,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): if not await BanUser.ban(qq, 10, 99999999): await BanUser.unban(qq) await BanUser.ban(qq, 10, 99999999) - await ban.send(f"{user_name} 已在黑名单!预计不解封了..") + await ban.send(f"已将 {user_name} 拉入黑名单!") else: await super_ban.send('需要艾特被super ban的对象..') diff --git a/plugins/bilibili_sub/__init__.py b/plugins/bilibili_sub/__init__.py index 7499abaf..e13d0859 100644 --- a/plugins/bilibili_sub/__init__.py +++ b/plugins/bilibili_sub/__init__.py @@ -19,12 +19,31 @@ from services.log import logger from nonebot import Driver import nonebot -__plugin_name__ = "B站订阅" - -__plugin_usage__ = """B站订阅帮助: - 添加订阅 [主播/UP/番剧] [id/链接/番名] - 删除订阅 [id] - 查看订阅""" +__zx_plugin_name__ = "B站订阅" +__plugin_usage__ = """ +usage: + B站直播,番剧,UP动态开播等提醒 + 主播订阅相当于 直播间订阅 + UP订阅 + 指令:[示例Id乱打的,仅做示例] + 添加订阅 ['主播'/'UP'/'番剧'] [id/链接/番名] + 删除订阅 [id] + 查看订阅 + 示例:添加订阅主播 2345344 <-(直播房间id) + 示例:添加订阅UP 2355543 <-(个人主页id) + 示例:添加订阅番剧 史莱姆 <-(支持模糊搜索) + 示例:添加订阅番剧 125344 <-(番剧id) + 示例:删除订阅 2324344 <-(任意id,通过查看订阅获取) +""".strip() +__plugin_des__ = '非常便利的B站订阅通知' +__plugin_cmd__ = ['添加订阅 [主播/UP/番剧] [id/链接/番名]', '删除订阅 [id]', '查看订阅'] +__plugin_version__ = 0.1 +__plugin_author__ = 'HibiKier' +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["B站订阅", 'b站订阅', '添加订阅', '删除订阅', '查看订阅'], +} add_sub = on_command("添加订阅", priority=5, block=True) del_sub = on_command("删除订阅", priority=5, block=True) diff --git a/plugins/broadcast/__init__.py b/plugins/broadcast/__init__.py index e899398c..328d73c7 100644 --- a/plugins/broadcast/__init__.py +++ b/plugins/broadcast/__init__.py @@ -5,12 +5,21 @@ from nonebot.permission import SUPERUSER import asyncio from utils.utils import get_message_text, get_message_imgs from services.log import logger -from models.group_remind import GroupRemind from utils.message_builder import image +from utils.manager import group_manager -__plugin_name__ = "广播 [Hidden]" - -__plugin_usage__ = '广播- [消息] or [图片]' +__zx_plugin_name__ = "广播 [Superuser]" +__plugin_usage__ = """ +usage: + 指令: + 广播- ?[消息] ?[图片] + 示例:广播- 你们好! +""".strip() +__plugin_des__ = "昭告天下!" +__plugin_cmd__ = ["广播-"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_task__ = {"broadcast": "广播"} broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True) @@ -19,30 +28,32 @@ broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True) async def _(bot: Bot, event: Event, state: T_State): msg = get_message_text(event.json()) imgs = get_message_imgs(event.json()) - rst = '' + rst = "" for img in imgs: rst += image(img) sid = bot.self_id gl = await bot.get_group_list(self_id=sid) - gl = [g['group_id'] for g in gl] + gl = [ + g["group_id"] + for g in gl + if await group_manager.check_group_task_status(g["group_id"], "broadcast") + ] + g_cnt = len(gl) + cnt = 0 + error = "" + x = 0.25 for g in gl: - if await GroupRemind.get_status(g, 'gb'): - await asyncio.sleep(0.5) - try: - await bot.send_group_msg(self_id=sid, group_id=g, message=msg+rst) - logger.info(f'群{g} 投递广播成功') - except Exception as e: - logger.error(f'群{g} 投递广播失败:{type(e)}') - try: - await broadcast.send(f'群{g} 投递广播失败:{type(e)}') - except Exception as e: - logger.critical(f'向广播发起者进行错误回报时发生错误:{type(e)}') - await broadcast.send(f'广播完成!') - - - - - - - - + cnt += 1 + if cnt / g_cnt > x: + await broadcast.send(f"已播报至 {int(cnt / g_cnt * 100)}% 的群聊") + x += 0.25 + try: + await bot.send_group_msg(self_id=sid, group_id=g, message=msg + rst) + logger.info(f"GROUP {g} 投递广播成功") + except Exception as e: + logger.error(f"GROUP {g} 投递广播失败:{type(e)}") + error += f"GROUP {g} 投递广播失败:{type(e)}\n" + await asyncio.sleep(0.5) + await broadcast.send(f"已播报至 100% 的群聊") + if error: + await broadcast.send(f"播报时错误:{error}") diff --git a/plugins/bt/__init__.py b/plugins/bt/__init__.py index 46af7cce..f99020e6 100644 --- a/plugins/bt/__init__.py +++ b/plugins/bt/__init__.py @@ -6,21 +6,33 @@ from nonebot.adapters import Bot from nonebot.adapters.cqhttp import PrivateMessageEvent from utils.utils import get_message_text from nonebot.adapters.cqhttp.permission import PRIVATE -from utils.utils import UserExistLimiter from asyncio.exceptions import TimeoutError from aiohttp.client_exceptions import ServerDisconnectedError -__plugin_name__ = "磁力搜索" -__plugin_usage__ = r""" -* 请各位使用后不要转发 * -* 拒绝反冲斗士! * -bt [关键词] [页数](默认为1) -示例: -bt 钢铁侠 -bt 钢铁侠 3 +__zx_plugin_name__ = "磁力搜索" +__plugin_usage__ = """ +usage: + * 请各位使用后不要转发 * + * 拒绝反冲斗士! * + 指令: + bt [关键词] ?[页数] + 示例:bt 钢铁侠 + 示例:bt 钢铁侠 3 """.strip() +__plugin_des__ = "bt(磁力搜索)[仅支持私聊,懂的都懂]" +__plugin_cmd__ = ["bt [关键词] ?[页数]"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["bt", "磁力搜索", "Bt", "BT"], +} +__plugin_block_limit__ = { + "rst": "您有bt任务正在进行,请等待结束." +} -_ulmt = UserExistLimiter() bt = on_command("bt", permission=PRIVATE, priority=5, block=True) @@ -38,8 +50,6 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): @bt.handle() async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): - if _ulmt.check(event.user_id): - await bt.finish("您有bt任务正在进行,请等待结束.", at_sender=True) mp = get_message_text(event.json()) if not mp: return @@ -54,7 +64,6 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): @bt.got("keyword", prompt="虚空磁力?查什么GKD") async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): - _ulmt.set_true(event.user_id) keyword = state["keyword"] page = state["page"] await bt.send("开始搜索....", at_sender=True) @@ -72,16 +81,12 @@ async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): ) send_flag = True except TimeoutError: - _ulmt.set_false(event.user_id) await bt.finish(f"搜索 {keyword} 超时...") except ServerDisconnectedError: - _ulmt.set_false(event.user_id) await bt.finish(f"搜索 {keyword} 连接失败") except Exception as e: - _ulmt.set_false(event.user_id) await bt.finish(f"bt 其他未知错误..") logger.error(f"bt 错误 e:{e}") if not send_flag: await bt.send(f"{keyword} 未搜索到...") logger.info(f"USER {event.user_id} BT搜索 {keyword} 第 {page} 页") - _ulmt.set_false(event.user_id) diff --git a/plugins/c_song/__init__.py b/plugins/c_song/__init__.py new file mode 100644 index 00000000..c2195941 --- /dev/null +++ b/plugins/c_song/__init__.py @@ -0,0 +1,57 @@ +from .music_163 import get_song_id, get_song_info +from nonebot.adapters.cqhttp import Bot, Event, GroupMessageEvent +from nonebot.typing import T_State +from services.log import logger +from nonebot import on_command + + +__zx_plugin_name__ = "点歌" +__plugin_usage__ = """ +usage: + 在线点歌 + 指令: + 点歌 [歌名] +""".strip() +__plugin_des__ = "为你点播了一首曾经的歌" +__plugin_cmd__ = ["点歌 [歌名]"] +__plugin_type__ = ("一些工具",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["点歌"], +} + + +songpicker = on_command("点歌", priority=5, block=True) + + +@songpicker.handle() +async def handle_first_receive(bot: Bot, event: Event, state: T_State): + args = str(event.get_message()).strip() + if args: + state["song_name"] = args + + +@songpicker.got("song_name", prompt="歌名是?") +async def _(bot: Bot, event: Event, state: T_State): + song = state["song_name"] + song_id = await get_song_id(song) + if not song_id: + await songpicker.finish("没有找到这首歌!", at_sender=True) + for _ in range(3): + song_content = [{"type": "music", "data": {"type": 163, "id": song_id}}] + logger.info( + f"(USER {event.user_id}, GROUP " + f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" + f" 点歌 :{song}" + ) + await songpicker.finish(song_content) + else: + await songpicker.finish("网易云繁忙...") + + + + diff --git a/plugins/c_song/music_163.py b/plugins/c_song/music_163.py new file mode 100644 index 00000000..0202313b --- /dev/null +++ b/plugins/c_song/music_163.py @@ -0,0 +1,47 @@ +import aiohttp +import json + + +headers = {"referer": "http://music.163.com"} +cookies = {"appver": "2.0.2"} + + +async def search_song(song_name: str): + async with aiohttp.ClientSession( + headers=headers, cookies=cookies + ) as session: + async with session.post( + f"http://music.163.com/api/search/get/", + data={"s": song_name, "limit": 1, "type": 1, "offset": 0}, + ) as r: + if r.status != 200: + return None + r = await r.text() + return json.loads(r) + + +async def get_song_id(songName: str) -> int: + """ + 根据用户输入的songName 获取候选songId列表 [默认songId数量:5] + """ + r = await search_song(songName) + return r["result"]["songs"][0]["id"] + + +async def get_song_info(songId: int): + """ + 获取歌曲信息 + """ + async with aiohttp.ClientSession( + headers=headers, cookies=cookies + ) as session: + async with session.post( + f"http://music.163.com/api/song/detail/?id={songId}&ids=%5B{songId}%5D", + ) as r: + if r.status != 200: + return None + r = await r.text() + return json.loads(r) + + + diff --git a/plugins/check/__init__.py b/plugins/check/__init__.py index 22415f46..0861ffb2 100644 --- a/plugins/check/__init__.py +++ b/plugins/check/__init__.py @@ -6,9 +6,18 @@ from nonebot.rule import to_me from nonebot.permission import SUPERUSER -__plugin_name__ = "自我检查 [Hidden]" +__zx_plugin_name__ = "服务器自我检查 [Superuser]" +__plugin_usage__ = """ +usage: + 查看服务器当前状态 + 指令: + 自检 +""" +__plugin_des__ = "查看服务器当前状态" +__plugin_cmd__ = ["自检/check"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" -__plugin_usage__ = "用法:自检" check = Check() diff --git a/plugins/check_zhenxun_update/__init__.py b/plugins/check_zhenxun_update/__init__.py index 1476587b..525fbf4b 100644 --- a/plugins/check_zhenxun_update/__init__.py +++ b/plugins/check_zhenxun_update/__init__.py @@ -12,9 +12,29 @@ import platform import os -update_zhenxun = on_command('检查更新真寻', permission=SUPERUSER, priority=1, block=True) +__zx_plugin_name__ = "自动更新 [Superuser]" +__plugin_usage__ = """ +usage: + 检查更新真寻最新版本,包括了自动更新 + 指令: + 检查更新真寻 + 重启 +""".strip() +__plugin_des__ = "就算是真寻也会成长的" +__plugin_cmd__ = ["检查更新真寻", "重启"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" -restart = on_command('重启', aliases={'restart'}, permission=SUPERUSER, rule=to_me(), priority=1, block=True) +update_zhenxun = on_command("检查更新真寻", permission=SUPERUSER, priority=1, block=True) + +restart = on_command( + "重启", + aliases={"restart"}, + permission=SUPERUSER, + rule=to_me(), + priority=1, + block=True, +) @update_zhenxun.handle() @@ -22,40 +42,38 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): try: code, error = await check_update(bot) if error: - logger.error(f'更新真寻未知错误 {error}') + logger.error(f"更新真寻未知错误 {error}") await bot.send_private_msg( - user_id=int(list(bot.config.superusers)[0]), - message=f'更新真寻未知错误 {error}' + user_id=int(list(bot.config.superusers)[0]), message=f"更新真寻未知错误 {error}" ) except Exception as e: - logger.error(f'更新真寻未知错误 {type(e)}:{e}') + logger.error(f"更新真寻未知错误 {type(e)}:{e}") await bot.send_private_msg( user_id=int(list(bot.config.superusers)[0]), - message=f'更新真寻未知错误 {type(e)}:{e}' + message=f"更新真寻未知错误 {type(e)}:{e}", ) else: if code == 200: await bot.send_private_msg( - user_id=int(list(bot.config.superusers)[0]), - message=f'更新完毕,请重启真寻....' + user_id=int(list(bot.config.superusers)[0]), message=f"更新完毕,请重启真寻...." ) @restart.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): - if str(platform.system()).lower() == 'windows': - await restart.finish('暂无windows重启脚本...') + if str(platform.system()).lower() == "windows": + await restart.finish("暂无windows重启脚本...") -@restart.got('flag', prompt='确定是否重启真寻?(重启失败咱们将失去联系,请谨慎!)') +@restart.got("flag", prompt="确定是否重启真寻?(重启失败咱们将失去联系,请谨慎!)") async def _(bot: Bot, event: MessageEvent, state: T_State): - flag = state['flag'] - if flag.lower() in ['true', '是', '好', '确定', '确定是']: - await restart.send('开始重启真寻..请稍等...') - open('is_restart', 'w') - os.system('./restart.sh') + flag = state["flag"] + if flag.lower() in ["true", "是", "好", "确定", "确定是"]: + await restart.send("开始重启真寻..请稍等...") + open("is_restart", "w") + os.system("./restart.sh") else: - await restart.send('已取消操作...') + await restart.send("已取消操作...") @scheduler.scheduled_job( @@ -69,7 +87,10 @@ async def _(): _version_file = Path() / "__version__" if _version_file.exists(): _version = ( - open(_version_file, "r", encoding="utf8").readline().split(":")[-1].strip() + open(_version_file, "r", encoding="utf8") + .readline() + .split(":")[-1] + .strip() ) data = await get_latest_version_data() if data: @@ -78,24 +99,21 @@ async def _(): bot = get_bot() await bot.send_private_msg( user_id=int(list(bot.config.superusers)[0]), - message=f'检测到真寻版本更新\n' - f'当前版本:{_version},最新版本:{latest_version}\n' - f'尝试自动更新...' + message=f"检测到真寻版本更新\n" + f"当前版本:{_version},最新版本:{latest_version}\n" + f"尝试自动更新...", ) try: code = await check_update(bot) except Exception as e: - logger.error(f'更新真寻未知错误 {type(e)}:{e}') + logger.error(f"更新真寻未知错误 {type(e)}:{e}") await bot.send_private_msg( user_id=int(list(bot.config.superusers)[0]), - message=f'更新真寻未知错误 {type(e)}:{e}\n' + message=f"更新真寻未知错误 {type(e)}:{e}\n", ) else: if code == 200: await bot.send_private_msg( user_id=int(list(bot.config.superusers)[0]), - message=f'更新完毕,请重启真寻....' + message=f"更新完毕,请重启真寻....", ) - - - diff --git a/plugins/check_zhenxun_update/data_source.py b/plugins/check_zhenxun_update/data_source.py index 87ac12d1..c240fefe 100644 --- a/plugins/check_zhenxun_update/data_source.py +++ b/plugins/check_zhenxun_update/data_source.py @@ -117,7 +117,6 @@ async def check_update(bot: Bot) -> 'int, str': user_id=int(list(bot.config.superusers)[0]), message=f"自动获取真寻版本成功:{latest_version},当前版本为最新版,无需更新...", ) - return 200, '' else: logger.warning("自动获取真寻版本失败....") await bot.send_private_msg( @@ -227,6 +226,6 @@ def check_old_lines(lines: List[str], line: str) -> str: return line for l in lines: if "=" in l and l.split("=")[0].strip() == line.split("=")[0].strip(): - if len(l) > len(line): + if l.split("=")[1].strip() == 'None': return l return line diff --git a/plugins/coser/__init__.py b/plugins/coser/__init__.py index 1c4e5846..9e5d78cc 100644 --- a/plugins/coser/__init__.py +++ b/plugins/coser/__init__.py @@ -5,21 +5,34 @@ from services.log import logger from asyncio.exceptions import TimeoutError from utils.message_builder import image from configs.path_config import IMAGE_PATH +from utils.utils import get_local_proxy import aiohttp import aiofiles -import re - -__plugin_name__ = "coser" - -__plugin_usage__ = "用法:发送‘coser’" +__zx_plugin_name__ = "coser" +__plugin_usage__ = """ +usage: + 三次元也不戳,嘿嘿嘿 + 指令: + cos/coser +""".strip() +__plugin_des__ = "三次元也不戳,嘿嘿嘿" +__plugin_cmd__ = ["cos/coser"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["cos", "coser", "括丝", "COS", "Cos", "cOS", "coS"], +} coser = on_command( "cos", aliases={"coser", "括丝", "COS", "Cos", "cOS", "coS"}, priority=5, block=True ) -url = "http://api520.ltd/api/cosplay.php" +url = "http://ovooa.com/API/cosplay/api.php" @coser.handle() @@ -28,24 +41,29 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): try: for _ in range(3): try: - async with session.get(url, timeout=2) as response: - _url = await response.text() - async with session.get(_url, timeout=5, verify_ssl=False) as res: + async with session.get(url, proxy=get_local_proxy(), timeout=2) as response: + _url = (await response.json())['text'] + async with session.get( + _url, timeout=5, proxy=get_local_proxy(), verify_ssl=False + ) as res: if res.status == 200: - async with aiofiles.open(f'{IMAGE_PATH}/temp/{event.user_id}_coser.jpg', 'wb') as f: + async with aiofiles.open( + f"{IMAGE_PATH}/temp/{event.user_id}_coser.jpg", "wb" + ) as f: await f.write(await res.read()) logger.info( f"(USER {event.user_id}, " f"GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" f" 发送COSER" ) - await coser.send(image(f'{event.user_id}_coser.jpg', 'temp')) + await coser.send( + image(f"{event.user_id}_coser.jpg", "temp") + ) break - except TimeoutError: + except (TimeoutError, KeyError): pass else: - await coser.send('你cos给我看!') + await coser.send("你cos给我看!") except Exception as e: - await coser.send('发生了预料之外的错误..请稍后再试或联系管理员修复...') - logger.error(f'coser 发送了未知错误 {type(e)}:{e}') - + await coser.send("发生了预料之外的错误..请稍后再试或联系管理员修复...") + logger.error(f"coser 发送了未知错误 {type(e)}:{e}") diff --git a/plugins/database_scripts.py b/plugins/database_scripts.py deleted file mode 100644 index 160a31af..00000000 --- a/plugins/database_scripts.py +++ /dev/null @@ -1,29 +0,0 @@ -from pathlib import Path -from services.db_context import db -from asyncpg.exceptions import DuplicateColumnError -import nonebot - -driver = nonebot.get_driver() - - -@driver.on_startup -async def _init_database(): - file = Path() / 'plugins' / 'database_scripts.py' - if file.exists(): - update_sql = [ - 'ALTER TABLE russian_users ADD winning_streak Integer default 0;', - 'ALTER TABLE russian_users ADD losing_streak Integer default 0;', - 'ALTER TABLE russian_users ADD max_winning_streak Integer default 0;', - 'ALTER TABLE russian_users ADD max_losing_streak Integer default 0;', - 'ALTER TABLE group_info_users ADD uid Integer default 0;' - ] - for sql in update_sql: - try: - query = db.text(sql) - await db.first(query) - except DuplicateColumnError: - pass - file.unlink() - - - diff --git a/plugins/dialogue/__init__.py b/plugins/dialogue/__init__.py index 3dc9c506..cfb0a818 100644 --- a/plugins/dialogue/__init__.py +++ b/plugins/dialogue/__init__.py @@ -8,9 +8,46 @@ from services.log import logger from utils.message_builder import at -__plugin_name__ = "联系管理员" -__plugin_usage__ = "用法:滴滴滴- [消息]" - +__zx_plugin_name__ = "联系管理员" +__plugin_usage__ = """ +usage: + 有什么话想对管理员说嘛? + 指令: + [滴滴滴]/滴滴滴- ?[文本] ?[图片] + 示例:滴滴滴- 我喜欢你 +""".strip() +__plugin_superuser_usage__ = """ +superuser usage: + 管理员对消息的回复 + 指令[以下qq与group均为乱打]: + /t: 查看当前存储的消息 + /t [qq] [group] [文本]: 在group回复指定用户 + /t [qq] [文本]: 私聊用户 + /t -1 [group] [文本]: 在group内发送消息 + /t [id] [文本]: 回复指定id的对话,id在 /t 中获取 + 示例:/t 73747222 32848432 你好啊 + 示例:/t 73747222 你好不好 + 示例:/t -1 32848432 我不太好 + 示例:/t 0 我收到你的话了 +""" +__plugin_des__ = "跨越空间与时间跟管理员对话" +__plugin_cmd__ = [ + "滴滴滴-/[滴滴滴] ?[文本] ?[图片]", + "/t [_superuser]", + "t [qq] [group] [文本] [_superuser]", + "/t [qq] [文本] [_superuser]", + "/t -1 [group] [_superuser]", + "/t [id] [文本] [_superuser]", +] +__plugin_type__ = ("联系管理员",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["滴滴滴-", "滴滴滴"], +} dialogue_data = {} @@ -57,7 +94,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): "user_id": event.user_id, "group_id": group_id, "group_name": group_name, - "msg": f'{text} {img_msg}', + "msg": f"{text} {img_msg}", } # print(dialogue_data) logger.info(f"Q{uid}@群{group_id} 联系管理员:{coffee} text:{text}") @@ -66,22 +103,15 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @reply.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = get_message_text(event.json()) - if msg in ["帮助"]: - await reply.finish( - f"/t [qq] [group] [text] -> 回复指定用户\n" - f"/t [qq] [text] -> 私聊用户\n" - f"/t -1 [group] -> 在某群发送消息\n" - f"/t [id] [text] -> 回复指定id的对话" - ) if not msg: result = "*****待回复消息总览*****\n" for key in dialogue_data.keys(): result += ( - f'id:{key}\n' + f"id:{key}\n" f'\t昵称:{dialogue_data[key]["nickname"]}({dialogue_data[key]["user_id"]})\n' f'\t群群:{dialogue_data[key]["group_name"]}({dialogue_data[key]["group_id"]})\n' f'\t消息:{dialogue_data[key]["msg"]}' - f'\n--------------------\n' + f"\n--------------------\n" ) await reply.finish(Message(result[:-1])) msg = msg.split() diff --git a/plugins/draw_card/__init__.py b/plugins/draw_card/__init__.py index 99a450f9..4a2a1126 100644 --- a/plugins/draw_card/__init__.py +++ b/plugins/draw_card/__init__.py @@ -1,8 +1,13 @@ from nonebot import on_regex, on_keyword -from nonebot.adapters.cqhttp import Bot, MessageEvent, Message +from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent from nonebot.permission import SUPERUSER from nonebot.typing import T_State -from .genshin_handle import genshin_draw, update_genshin_info, reset_count, reload_genshin_pool +from .genshin_handle import ( + genshin_draw, + update_genshin_info, + reset_count, + reload_genshin_pool, +) from .prts_handle import update_prts_info, prts_draw, reload_prts_pool from .pretty_handle import update_pretty_info, pretty_draw, reload_pretty_pool from .guardian_handle import update_guardian_info, guardian_draw @@ -13,52 +18,164 @@ from .onmyoji_handle import update_onmyoji_info, onmyoji_draw from .update_game_info import update_info from .util import is_number, check_num from .rule import is_switch -from .config import PRTS_FLAG, PRETTY_FLAG, GUARDIAN_FLAG, GENSHIN_FLAG, PCR_FLAG, AZUR_FLAG, FGO_FLAG, ONMYOJI_FLAG +from .config import ( + PRTS_FLAG, + PRETTY_FLAG, + GUARDIAN_FLAG, + GENSHIN_FLAG, + PCR_FLAG, + AZUR_FLAG, + FGO_FLAG, + ONMYOJI_FLAG, +) from .async_update_game_info import async_update_game import re import asyncio from utils.utils import scheduler from services.log import logger -__plugin_name__ = '游戏抽卡' +__zx_plugin_name__ = "游戏抽卡" +__plugin_usage__ = """ +usage: + 模拟赛马娘,原神,明日方舟,坎公骑冠剑,公主连结(国/台),碧蓝航线,FGO,阴阳师进行抽卡 + 指令: + 原神[1-300]抽: 原神常驻池 + 原神角色[1-300]抽: 原神角色UP池子 + 原神武器[1-300]抽: 原神武器UP池子 + 重置原神抽卡: 清空当前卡池的抽卡次数[即从0开始计算UP概率] + 方舟[1-300]抽: 方舟卡池,当有当期UP时指向UP池 + 赛马娘[1-200]抽: 赛马娘卡池,当有当期UP时指向UP池 + 坎公骑冠剑[1-300]抽: 坎公骑冠剑卡池,当有当期UP时指向UP池 + pcr/公主连接[1-300]抽: 公主连接卡池 + 碧蓝航线/碧蓝[重型/轻型/特型][1-300]抽: 碧蓝航线重型/轻型/特型卡池 + fgo[1-300]抽: fgo卡池 + 阴阳师[1-300]抽: 阴阳师卡池 + * 以上指令可以通过 XX一井 来指定最大抽取数量 * + * 示例:原神一井 * +""".strip() +__plugin_superuser_usage__ = """ +usage: + 卡池方面的更新 + 指令: + 更新方舟信息 + 重载方舟卡池 + 更新原神信息 + 重载原神卡池 + 更新赛马娘信息 + 重载赛马娘卡池 + 更新坎公骑冠剑信息 + 更新碧蓝航线信息 + 更新fgo信息 + 更新阴阳师信息 +""".strip() +__plugin_des__ = "就算是模拟抽卡也不能改变自己是个非酋" +__plugin_cmd__ = [ + "原神[1-300]抽", + "原神角色[1-300]抽", + "原神武器[1-300]抽", + "重置原神抽卡", + "方舟[1-300]抽", + "赛马娘[1-200]抽", + "坎公骑冠剑[1-300]抽", + "pcr/公主连接[1-300]抽", + "fgo[1-300]抽", + "阴阳师[1-300]抽", + "更新方舟信息 [_superuser]", + "重载方舟卡池 [_superuser]", + "更新原神信息 [_superuser]", + "重载原神卡池 [_superuser]", + "更新赛马娘信息 [_superuser]", + "重载赛马娘卡池 [_superuser]", + "更新坎公骑冠剑信息 [_superuser]", + "更新碧蓝航线信息 [_superuser]", + "更新fgo信息 [_superuser]", + "更新阴阳师信息 [_superuser]", +] +__plugin_type__ = ("抽卡相关", 1) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["游戏抽卡", "抽卡"], +} -prts = on_regex(r'.*?方舟[1-9|一][0-9]{0,2}[抽|井]', rule=is_switch('prts'), priority=5, block=True) -prts_update = on_keyword({'更新方舟信息', '更新明日方舟信息'}, permission=SUPERUSER, priority=1, block=True) -prts_up_reload = on_keyword({'重载方舟卡池'}, priority=1, block=True) +prts = on_regex( + r".*?方舟[1-9|一][0-9]{0,2}[抽|井]", rule=is_switch("prts"), priority=5, block=True +) +prts_update = on_keyword( + {"更新方舟信息", "更新明日方舟信息"}, permission=SUPERUSER, priority=1, block=True +) +prts_up_reload = on_keyword({"重载方舟卡池"}, priority=1, block=True) -genshin = on_regex('.*?原神(武器|角色)?池?[1-9|一][0-9]{0,2}[抽|井]', rule=is_switch('genshin'), priority=5, block=True) -genshin_update = on_keyword({'更新原神信息'}, permission=SUPERUSER, priority=1, block=True) -genshin_reset = on_keyword({'重置原神抽卡'}, priority=1, block=True) -genshin_up_reload = on_keyword({'重载原神卡池'}, priority=1, block=True) +genshin = on_regex( + ".*?原神(武器|角色)?池?[1-9|一][0-9]{0,2}[抽|井]", + rule=is_switch("genshin"), + priority=5, + block=True, +) +genshin_update = on_keyword({"更新原神信息"}, permission=SUPERUSER, priority=1, block=True) +genshin_reset = on_keyword({"重置原神抽卡"}, priority=1, block=True) +genshin_up_reload = on_keyword({"重载原神卡池"}, priority=1, block=True) -pretty = on_regex('.*?马娘卡?[1-9|一][0-9]{0,2}[抽|井]', rule=is_switch('pretty'), priority=5, block=True) -pretty_update = on_keyword({'更新马娘信息', '更新赛马娘信息'}, permission=SUPERUSER, priority=1, block=True) -pretty_up_reload = on_keyword({'重载赛马娘卡池'}, priority=1, block=True) +pretty = on_regex( + ".*?马娘卡?[1-9|一][0-9]{0,2}[抽|井]", rule=is_switch("pretty"), priority=5, block=True +) +pretty_update = on_keyword( + {"更新马娘信息", "更新赛马娘信息"}, permission=SUPERUSER, priority=1, block=True +) +pretty_up_reload = on_keyword({"重载赛马娘卡池"}, priority=1, block=True) -guardian = on_regex('.*?坎公骑冠剑武?器?[1-9|一][0-9]{0,2}[抽|井]', rule=is_switch('guardian'), priority=5, block=True) -guardian_update = on_keyword({'更新坎公骑冠剑信息'}, permission=SUPERUSER, priority=1, block=True) +guardian = on_regex( + ".*?坎公骑冠剑武?器?[1-9|一][0-9]{0,2}[抽|井]", + rule=is_switch("guardian"), + priority=5, + block=True, +) +guardian_update = on_keyword( + {"更新坎公骑冠剑信息"}, permission=SUPERUSER, priority=1, block=True +) -pcr = on_regex('.*?(pcr|公主连结|公主连接|公主链接|公主焊接)[1-9|一][0-9]{0,2}[抽|井]', rule=is_switch('pcr'), priority=5, block=True) -pcr_update = on_keyword({'更新pcr信息', '更新公主连结信息'}, permission=SUPERUSER, priority=1, block=True) +pcr = on_regex( + ".*?(pcr|公主连结|公主连接|公主链接|公主焊接)[1-9|一][0-9]{0,2}[抽|井]", + rule=is_switch("pcr"), + priority=5, + block=True, +) +pcr_update = on_keyword( + {"更新pcr信息", "更新公主连结信息"}, permission=SUPERUSER, priority=1, block=True +) -azur = on_regex('.*?碧蓝航?线?(轻型|重型|特型)池?[1-9|一][0-9]{0,2}[抽]', rule=is_switch('azur'), priority=5, block=True) -azur_update = on_keyword({'更新碧蓝信息', '更新碧蓝航线信息'}, permission=SUPERUSER, priority=1, block=True) +azur = on_regex( + ".*?碧蓝航?线?(轻型|重型|特型)池?[1-9|一][0-9]{0,2}[抽]", + rule=is_switch("azur"), + priority=5, + block=True, +) +azur_update = on_keyword( + {"更新碧蓝信息", "更新碧蓝航线信息"}, permission=SUPERUSER, priority=1, block=True +) -fgo = on_regex('.*?fgo[1-9|一][0-9]{0,2}[抽]', rule=is_switch('fgo'), priority=5, block=True) -fgo_update = on_keyword({'更新fgo信息'}, permission=SUPERUSER, priority=1, block=True) +fgo = on_regex( + ".*?fgo[1-9|一][0-9]{0,2}[抽]", rule=is_switch("fgo"), priority=5, block=True +) +fgo_update = on_keyword({"更新fgo信息"}, permission=SUPERUSER, priority=1, block=True) -onmyoji = on_regex('.*?阴阳师[1-9|一][0-9]{0,2}[抽]', rule=is_switch('onmyoji'), priority=5, block=True) -onmyoji_update = on_keyword({'更新阴阳师信息'}, permission=SUPERUSER, priority=1, block=True) +onmyoji = on_regex( + ".*?阴阳师[1-9|一][0-9]{0,2}[抽]", rule=is_switch("onmyoji"), priority=5, block=True +) +onmyoji_update = on_keyword({"更新阴阳师信息"}, permission=SUPERUSER, priority=1, block=True) @prts.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - if msg in ['方舟一井', '方舟1井']: + if msg in ["方舟一井", "方舟1井"]: num = 300 else: - rmsg = re.search(r'.*?方舟(.*)抽', msg) + rmsg = re.search(r".*?方舟(.*)抽", msg) if rmsg: num, flag = check_num(rmsg.group(1), 300) if not flag: @@ -67,29 +184,30 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): return await prts.send(await prts_draw(int(num)), at_sender=True) logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 方舟 {num}抽") + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 方舟 {num}抽" + ) @prts_up_reload.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): text = await reload_prts_pool() - await prts_up_reload.finish(Message(f'重载完成!\n{text}')) + await prts_up_reload.finish(Message(f"重载完成!\n{text}")) @genshin.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - rmsg = re.search(r'.*?原神(武器|角色)?池?(.*)[抽|井]', msg) + rmsg = re.search(r".*?原神(武器|角色)?池?(.*)[抽|井]", msg) if rmsg: pool_name = rmsg.group(1) - if pool_name == '武器': - pool_name = 'arms' - elif pool_name == '角色': - pool_name = 'char' + if pool_name == "武器": + pool_name = "arms" + elif pool_name == "角色": + pool_name = "char" else: - pool_name = '' + pool_name = "" num = rmsg.group(2) - if msg.find('一井') != -1 or msg.find('1井') != -1: + if msg.find("一井") != -1 or msg.find("1井") != -1: num = 180 else: num, flag = check_num(num, 180) @@ -97,41 +215,44 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): await genshin.finish(num, at_sender=True) else: return - await genshin.send(await genshin_draw(event.user_id, int(num), pool_name), at_sender=True) + await genshin.send( + await genshin_draw(event.user_id, int(num), pool_name), at_sender=True + ) logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 原神 {num}抽") + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 原神 {num}抽" + ) @genshin_up_reload.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): text = await reload_genshin_pool() - await genshin_reset.finish(Message(f'重载成功!\n{text}')) + await genshin_reset.finish(Message(f"重载成功!\n{text}")) @genshin_reset.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): reset_count(event.user_id) - await genshin_reset.send('重置了原神抽卡次数', at_sender=True) + await genshin_reset.send("重置了原神抽卡次数", at_sender=True) @pretty.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - if msg.find('1井') != -1 or msg.find('一井') != -1: + if msg.find("1井") != -1 or msg.find("一井") != -1: num = 200 if msg.find("卡") == -1: - pool_name = 'char' + pool_name = "char" else: - pool_name = 'card' + pool_name = "card" else: - rmsg = re.search(r'.*?马娘(.*)抽', msg) + rmsg = re.search(r".*?马娘(.*)抽", msg) if rmsg: num = rmsg.group(1) - if num[0] == '卡': + if num[0] == "卡": num = num[1:] - pool_name = 'card' + pool_name = "card" else: - pool_name = 'char' + pool_name = "char" num, flag = check_num(num, 200) if not flag: await pretty.finish(num, at_sender=True) @@ -139,30 +260,31 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): return await pretty.send(await pretty_draw(int(num), pool_name), at_sender=True) logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 赛马娘 {num}抽") + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 赛马娘 {num}抽" + ) @pretty_up_reload.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): text = await reload_pretty_pool() - await genshin_reset.finish(Message(f'重载成功!\n{text}')) + await genshin_reset.finish(Message(f"重载成功!\n{text}")) @guardian.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - pool_name = 'char' - if msg.find('1井') != -1 or msg.find('一井') != -1: + pool_name = "char" + if msg.find("1井") != -1 or msg.find("一井") != -1: num = 300 - if msg.find('武器') != -1: - pool_name = 'arms' + if msg.find("武器") != -1: + pool_name = "arms" else: - rmsg = re.search(r'.*?坎公骑冠剑(.*)抽', msg) + rmsg = re.search(r".*?坎公骑冠剑(.*)抽", msg) if rmsg: num = rmsg.group(1) - if num.find('武器') != -1: - pool_name = 'arms' - num = num.replace('武器', '') + if num.find("武器") != -1: + pool_name = "arms" + num = num.replace("武器", "") num, flag = check_num(num, 300) if not flag: await guardian.finish(num, at_sender=True) @@ -170,16 +292,17 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): return await guardian.send(await guardian_draw(int(num), pool_name), at_sender=True) logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 坎公骑冠剑 {num}抽") + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 坎公骑冠剑 {num}抽" + ) @pcr.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - if msg.find('1井') != -1 or msg.find('一井') != -1: + if msg.find("1井") != -1 or msg.find("一井") != -1: num = 300 else: - rmsg = re.search(r'.*?(pcr|公主连结)(.*)[抽|井]', msg) + rmsg = re.search(r".*?(pcr|公主连结)(.*)[抽|井]", msg) if rmsg: num, flag = check_num(rmsg.group(2), 300) if not flag: @@ -188,13 +311,14 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): return await pcr.send(await pcr_draw(int(num)), at_sender=True) logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 公主连结 {num}抽") + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 公主连结 {num}抽" + ) @azur.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - rmsg = re.search('.*?碧蓝航?线?(轻型|重型|特型)池?(.*)[抽]', msg) + rmsg = re.search(".*?碧蓝航?线?(轻型|重型|特型)池?(.*)[抽]", msg) if rmsg: pool_name = rmsg.group(1) num, flag = check_num(rmsg.group(2), 300) @@ -204,13 +328,14 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): return await azur.send(await azur_draw(int(num), pool_name), at_sender=True) logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 碧蓝航线 {num}抽") + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 碧蓝航线 {num}抽" + ) @fgo.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - rmsg = re.search('.*?fgo(.*)抽', msg) + rmsg = re.search(".*?fgo(.*)抽", msg) if rmsg: num, flag = check_num(rmsg.group(1), 300) if not flag: @@ -219,13 +344,14 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): return await fgo.send(await fgo_draw(int(num)), at_sender=True) logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) fgo {num}抽") + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) fgo {num}抽" + ) @onmyoji.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = str(event.get_message()).strip() - rmsg = re.search('.*?阴阳师(.*)抽', msg) + rmsg = re.search(".*?阴阳师(.*)抽", msg) if rmsg: num, flag = check_num(rmsg.group(1), 300) if not flag: @@ -234,60 +360,61 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): return await onmyoji.send(await onmyoji_draw(int(num)), at_sender=True) logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'}) 阴阳师 {num}抽") + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 阴阳师 {num}抽" + ) @prts_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_prts_info() - await prts_update.finish('更新完成!') + await prts_update.finish("更新完成!") @genshin_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_genshin_info() - await genshin_update.finish('更新完成!') + await genshin_update.finish("更新完成!") @pretty_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_pretty_info() - await genshin_update.finish('更新完成!') + await genshin_update.finish("更新完成!") @guardian_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_guardian_info() - await genshin_update.finish('更新完成!') + await genshin_update.finish("更新完成!") @pcr_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_pcr_info() - await genshin_update.finish('更新完成!') + await genshin_update.finish("更新完成!") @azur_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_azur_info() - await genshin_update.finish('更新完成!') + await genshin_update.finish("更新完成!") @fgo_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_fgo_info() - await genshin_update.finish('更新完成!') + await genshin_update.finish("更新完成!") @onmyoji_update.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await update_onmyoji_info() - await genshin_update.finish('更新完成!') + await genshin_update.finish("更新完成!") # 更新资源 @scheduler.scheduled_job( - 'cron', + "cron", hour=4, minute=1, ) @@ -310,42 +437,40 @@ async def _(): if ONMYOJI_FLAG: tasks.append(asyncio.ensure_future(update_onmyoji_info())) await asyncio.gather(*tasks) - logger.info('draw_card 抽卡自动更新完成...') + logger.info("draw_card 抽卡自动更新完成...") # 每天四点重载方舟up卡池 @scheduler.scheduled_job( - 'cron', + "cron", hour=4, minute=1, ) async def _(): if PRTS_FLAG: await reload_prts_pool() - logger.info('自动重载方舟卡池UP成功') + logger.info("自动重载方舟卡池UP成功") # 每天四点重载赛马娘up卡池 @scheduler.scheduled_job( - 'cron', + "cron", hour=4, minute=1, ) async def _(): if PRETTY_FLAG: await reload_pretty_pool() - logger.info('自动重载赛马娘UP成功') + logger.info("自动重载赛马娘UP成功") # 每天下午六点点重载原神up卡池 @scheduler.scheduled_job( - 'cron', + "cron", hour=18, minute=1, ) async def _(): if PRTS_FLAG: await reload_genshin_pool() - logger.info('自动重载原神卡池UP成功') - - + logger.info("自动重载原神卡池UP成功") diff --git a/plugins/draw_card/init_card_pool.py b/plugins/draw_card/init_card_pool.py index d4406d25..797659e9 100644 --- a/plugins/draw_card/init_card_pool.py +++ b/plugins/draw_card/init_card_pool.py @@ -1,5 +1,6 @@ from typing import Any from .config import DATA_PATH +from utils.utils import is_number from pathlib import Path try: import ujson as json @@ -65,11 +66,12 @@ def init_game_pool(game: str, data: dict, Operator: Any): tmp_lst.append(Operator(name=data[key]['名称'], star=int(data[key]['星级']), limited=limited)) if game == 'azur': for key in data.keys(): - limited = False - if '可以建造' not in data[key]['获取途径']: - limited = True - tmp_lst.append(Operator(name=data[key]['名称'], star=int(data[key]['星级']), - limited=limited, itype=data[key]['类型'])) + if is_number(data[key]['星级']): + limited = False + if '可以建造' not in data[key]['获取途径']: + limited = True + tmp_lst.append(Operator(name=data[key]['名称'], star=int(data[key]['星级']), + limited=limited, itype=data[key]['类型'])) if game in ['fgo', 'fgo_card']: for key in data.keys(): limited = False diff --git a/plugins/draw_card/rule.py b/plugins/draw_card/rule.py index 28939bf1..899bc1dd 100644 --- a/plugins/draw_card/rule.py +++ b/plugins/draw_card/rule.py @@ -1,42 +1,37 @@ from nonebot.rule import Rule from nonebot.adapters.cqhttp import Bot, MessageEvent from nonebot.typing import T_State -from .config import GENSHIN_FLAG, PRTS_FLAG, PRETTY_FLAG, GUARDIAN_FLAG, PCR_FLAG, AZUR_FLAG, FGO_FLAG, ONMYOJI_FLAG +from .config import ( + GENSHIN_FLAG, + PRTS_FLAG, + PRETTY_FLAG, + GUARDIAN_FLAG, + PCR_FLAG, + AZUR_FLAG, + FGO_FLAG, + ONMYOJI_FLAG, +) def is_switch(game_name: str) -> Rule: - async def _is_switch(bot: Bot, event: MessageEvent, state: T_State) -> bool: - if game_name == 'prts': + if game_name == "prts": return PRTS_FLAG - if game_name == 'genshin': + if game_name == "genshin": return GENSHIN_FLAG - if game_name == 'pretty': + if game_name == "pretty": return PRETTY_FLAG - if game_name == 'guardian': + if game_name == "guardian": return GUARDIAN_FLAG - if game_name == 'pcr': + if game_name == "pcr": return PCR_FLAG - if game_name == 'azur': + if game_name == "azur": return AZUR_FLAG - if game_name == 'fgo': + if game_name == "fgo": return FGO_FLAG - if game_name == 'onmyoji': + if game_name == "onmyoji": return ONMYOJI_FLAG else: return False return Rule(_is_switch) - - - - - - - - - - - - - diff --git a/plugins/draw_card/update_game_simple_info.py b/plugins/draw_card/update_game_simple_info.py index 47ad790d..c708e6f5 100644 --- a/plugins/draw_card/update_game_simple_info.py +++ b/plugins/draw_card/update_game_simple_info.py @@ -83,6 +83,8 @@ async def _last_check(data: dict, game_name: str, session: aiohttp.ClientSession '-舰娘头像外框精锐.png', 'https://patchwiki.biligame.com/images/blhx/thumb/a/a2/ptog1j220x5q02hytpwc8al7f229qk9.png/60px-' '舰娘头像外框超稀有.png' + 'https://patchwiki.biligame.com/images/blhx/thumb/0/0f/n28p7p3opfn5mhgjyio55ljsllhknwz.png/60px-' + '舰娘头像外框精锐META.png' ]: await download_img(url, 'azur', f'{idx}_star') idx += 1 @@ -135,7 +137,7 @@ async def retrieve_char_data(char: bs4.element.Tag, game_name: str, data: dict, member_dict['头像'] = unquote(str(avatar_img['src']).split(' ')[-2]) except TypeError: member_dict['头像'] = "img link not find..." - logger(f'{member_dict["名称"]} 图片缺失....') + logger.warning(f'{member_dict["名称"]} 图片缺失....') star = char.find('div').find('img')['alt'] if star == '舰娘头像外框普通.png': star = 1 @@ -147,7 +149,9 @@ async def retrieve_char_data(char: bs4.element.Tag, game_name: str, data: dict, star = 4 elif star == '舰娘头像外框海上传奇.png': star = 5 - elif star in ['舰娘头像外框最高方案.png', '舰娘头像外框决战方案.png', '舰娘头像外框超稀有META.png']: + elif star in ['舰娘头像外框最高方案.png', '舰娘头像外框决战方案.png', '舰娘头像外框超稀有META.png', '舰娘头像外框精锐META.png']: + star = 6 + else: star = 6 member_dict['星级'] = star member_dict['类型'] = azur_type[str(index)] diff --git a/plugins/epic/__init__.py b/plugins/epic/__init__.py index 47e9e261..62dd0c06 100644 --- a/plugins/epic/__init__.py +++ b/plugins/epic/__init__.py @@ -4,13 +4,28 @@ 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 -from models.group_remind import GroupRemind -from nonebot.adapters.cqhttp.exception import ActionFailed - -__plugin_name__ = "epic免费游戏提醒" - -__plugin_usage__ = "用法:发送’epic‘" +from utils.manager import group_manager +__zx_plugin_name__ = "epic免费游戏" +__plugin_usage__ = """ +usage: + 可以不玩,不能没有,每日白嫖 + 指令: + epic +""".strip() +__plugin_des__ = "可以不玩,不能没有,每日白嫖" +__plugin_cmd__ = ["epic"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["epic"], +} +__plugin_task__ = { + 'epic_free_game': 'epic免费游戏' +} epic = on_command("epic", priority=5, block=True) @@ -33,13 +48,13 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): ) async def _(): bot = get_bot() - gl = await bot.get_group_list(self_id=bot.self_id) + gl = await bot.get_group_list() gl = [g["group_id"] for g in gl] for g in gl: - if await GroupRemind.get_status(g, "epic"): - result, code = await get_epic_game() - if code == 200: - try: + if await group_manager.check_group_task_status(g, 'epic_free_game'): + try: + result, code = await get_epic_game() + if code == 200: await bot.send_group_msg(group_id=g, message=result) - except ActionFailed: - logger.error(f"{g}群 epic免费游戏推送错误") + except Exception as e: + logger.error(f"GROUP {g} epic免费游戏推送错误 {type(e)}: {e}") diff --git a/plugins/fake_msg.py b/plugins/fake_msg.py index 78c68151..cb18c40f 100644 --- a/plugins/fake_msg.py +++ b/plugins/fake_msg.py @@ -6,12 +6,24 @@ from utils.message_builder import share from services.log import logger -__plugin_name = "假消息" - -__plugin_usage__ = ( - "用法:\n格式:假消息 [网址] [标题] [内容](可省) [图片](可省)\n" - "示例:假消息 www.4399.com 我喜欢萝莉 为什么我喜欢... [图片]" -) +__zx_plugin_name__ = "构造分享消息" +__plugin_usage__ = """ +usage: + 自定义的分享消息构造 + 指令: + 假消息 [网址] [标题] ?[内容] ?[图片] + 示例:假消息 www.4399.com 我喜欢萝莉 为什么我喜欢... [图片] +""".strip() +__plugin_des__ = "自定义的分享消息构造" +__plugin_cmd__ = ["假消息 [网址] [标题] ?[内容] ?[图片]"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["假消息"], +} fake_msg = on_command("假消息", priority=5, block=True) diff --git a/plugins/fudu.py b/plugins/fudu.py index c8406722..1c36f524 100644 --- a/plugins/fudu.py +++ b/plugins/fudu.py @@ -11,6 +11,19 @@ import aiohttp import aiofiles from asyncio.exceptions import TimeoutError from configs.config import FUDU_PROBABILITY +from utils.manager import group_manager + + +__zx_plugin_name__ = "复读" +__plugin_usage__ = """ +usage: + 重复3次相同的消息时会复读 +""".strip() +__plugin_des__ = "群友的本质是什么?是复读机哒!" +__plugin_type__ = ("被动相关",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_task__ = {"fudu": "复读"} class Fudu: @@ -59,7 +72,11 @@ fudu = on_message(permission=GROUP, priority=9) @fudu.handle() async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - if event.is_tome() or state["_prefix"]["raw_command"]: + if ( + event.is_tome() + or state["_prefix"]["raw_command"] + or not await group_manager.check_group_task_status(event.group_id, "fudu") + ): return if get_message_text(event.json()): if get_message_text(event.json()).find("@可爱的小真寻") != -1: diff --git a/plugins/genshin/__init__.py b/plugins/genshin/__init__.py new file mode 100644 index 00000000..d16bafc6 --- /dev/null +++ b/plugins/genshin/__init__.py @@ -0,0 +1,3 @@ +import nonebot + +nonebot.load_plugins("plugins/genshin") diff --git a/plugins/genshin/almanac/__init__.py b/plugins/genshin/almanac/__init__.py index 7bf55422..94785243 100644 --- a/plugins/genshin/almanac/__init__.py +++ b/plugins/genshin/almanac/__init__.py @@ -1,25 +1,44 @@ -from .alc import get_almanac_base64_str, load_data -import os from utils.utils import get_bot, scheduler from nonebot import on_command -from models.level_user import LevelUser from nonebot.typing import T_State from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent -from utils.message_builder import image from services.log import logger -from models.group_remind import GroupRemind +from configs.path_config import IMAGE_PATH +from .data_source import get_alc_image +from utils.manager import group_manager +from pathlib import Path - -FILE_PATH = os.path.dirname(__file__) +__zx_plugin_name__ = "原神老黄历" +__plugin_usage__ = """ +usage: + 有时候也该迷信一回!特别是运气方面 + 指令: + 原神黄历 +""".strip() +__plugin_des__ = "有时候也该迷信一回!特别是运气方面" +__plugin_cmd__ = ["原神黄历"] +__plugin_type__ = ("原神相关",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["原神黄历", "原神老黄历"], +} +__plugin_task__ = {"genshin_alc": "原神黄历提醒"} almanac = on_command("原神黄历", priority=5, block=True) -reload = on_command("重载原神黄历数据", priority=5, block=True) + + +ALC_PATH = Path(IMAGE_PATH) / "genshin" / "alc" +ALC_PATH.mkdir(parents=True, exist_ok=True) @almanac.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): - almanac_base64 = get_almanac_base64_str() - mes = image(b64=almanac_base64) + "\n ※ 黄历数据来源于 genshin.pub" + alc_img = await get_alc_image(ALC_PATH) + mes = alc_img + "\n ※ 黄历数据来源于 genshin.pub" await almanac.send(mes) logger.info( f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" @@ -27,13 +46,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): ) -@reload.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - if await LevelUser.check_level(event.user_id, event.group_id, 5): - load_data() - await reload.send("重载成功") - - @scheduler.scheduled_job( "cron", hour=10, @@ -42,10 +54,11 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): async def _(): # 每日提醒 bot = get_bot() - gl = await bot.get_group_list(self_id=bot.self_id) - gl = [g["group_id"] for g in gl] - almanac_base64 = get_almanac_base64_str() - mes = image(b64=almanac_base64) + "\n ※ 黄历数据来源于 genshin.pub" - for gid in gl: - if await GroupRemind.get_status(gid, "almanac"): - await bot.send_group_msg(group_id=int(gid), message=mes) + if bot: + gl = await bot.get_group_list() + gl = [g["group_id"] for g in gl] + alc_img = await get_alc_image(ALC_PATH) + mes = alc_img + "\n ※ 黄历数据来源于 genshin.pub" + for gid in gl: + if await group_manager.check_group_task_status(gid, "genshin_alc"): + await bot.send_group_msg(group_id=int(gid), message=mes) diff --git a/plugins/genshin/almanac/alc.py b/plugins/genshin/almanac/alc.py deleted file mode 100644 index 94c656b2..00000000 --- a/plugins/genshin/almanac/alc.py +++ /dev/null @@ -1,123 +0,0 @@ -from PIL import Image, ImageDraw, ImageFont -from io import BytesIO - -import os -import json -import random -import base64 -import time - -FILE_PATH = os.path.dirname(__file__) -FONT_PATH = os.path.join(FILE_PATH, "汉仪文黑.ttf") - -data = {} # configs.json里的数据 - -almanac_data = { - # 生成的黄历base64字符串和黄历更新日期 - "date": "", - "almanac_base64_str": "" -} - -chinese = {"0": "", "1": "一", "2": "二", "3": "三", "4": "四", "5": "五", "6": "六", "7": "七", "8": "八", "9": "九"} - - -def month_to_chinese(month: str): - # 把日期数字转成中文数字 - m = int(month) - if m < 10: - return chinese[month[-1]] - elif m < 20: - return "十" + chinese[month[-1]] - else: - return chinese[month[0]] + "十" + chinese[month[-1]] - - -def load_data(): - # 载入config.json文件的数据 - global data - with open(os.path.join(FILE_PATH, 'config.json'), 'r', encoding='UTF-8') as f: - data = json.load(f) - - almanac_data["date"] = "" - almanac_data["almanac_base64_str"] = "" - - -load_data() - - -def seed_random_list(seed: str, l: list): - # 使用随机种子随机选择列表中的元素,相同的种子和列表将返回同样的输出 - seed = seed + str(l) - random.seed(seed) - index = random.random() * len(l) - return l[int(index)] - - -def generate_almanac(): - # 生成黄历图片,然后转换成base64保存到 almanac_data["almanac_base64_str"] - - seed = time.strftime("%Y-%m-%d") - offset = 1 - today_luck = [] - l = list(data.keys()) - - while len(today_luck) < 6: - # 随机6个不同的运势放到 today_luck - r = seed_random_list(str(offset) + seed, l) - if r in today_luck: - offset += 1 - else: - today_luck.append(r) - - back = Image.open(os.path.join(FILE_PATH, "back.png")) - - year = time.strftime("%Y") - month = month_to_chinese(time.strftime("%m")) + "月" - day = month_to_chinese(time.strftime("%d")) + "日" - - draw = ImageDraw.Draw(back) - draw.text((118, 165), year, fill="#8d7650ff", font=ImageFont.truetype(FONT_PATH, size=30), anchor="mm", - align="center") - draw.text((260, 165), day, fill="#f7f8f2ff", font=ImageFont.truetype(FONT_PATH, size=35), anchor="mm", - align="center") - draw.text((410, 165), month, fill="#8d7650ff", font=ImageFont.truetype(FONT_PATH, size=30), anchor="mm", - align="center") - - buff = Image.new("RGBA", (325, 160)) - debuff = Image.new("RGBA", (325, 160)) - - buff_draw = ImageDraw.Draw(buff) - debuff_draw = ImageDraw.Draw(debuff) - - for i in range(3): - buff_name = today_luck[i] - debuff_name = today_luck[(i + 3)] - - buff_effect = seed_random_list(seed, data[buff_name]["buff"]) - debuff_effect = seed_random_list(seed, data[debuff_name]["debuff"]) - - buff_draw.text((0, i * 53), buff_name, fill="#756141ff", font=ImageFont.truetype(FONT_PATH, size=25)) - debuff_draw.text((0, i * 53), debuff_name, fill="#756141ff", font=ImageFont.truetype(FONT_PATH, size=25)) - - buff_draw.text((0, i * 53 + 28), buff_effect, fill="#b5b3acff", font=ImageFont.truetype(FONT_PATH, size=19)) - debuff_draw.text((0, i * 53 + 28), debuff_effect, fill="#b5b3acff", font=ImageFont.truetype(FONT_PATH, size=19)) - - back.paste(buff, (150, 230), buff) - back.paste(debuff, (150, 400), debuff) - - bio = BytesIO() - back.save(bio, format='PNG') - base64_str = base64.b64encode(bio.getvalue()).decode() - - almanac_data["date"] = time.strftime("%Y-%m-%d") - almanac_data["almanac_base64_str"] = 'base64://' + base64_str - - -def get_almanac_base64_str(): - # if almanac_data["date"] == time.strftime("%Y-%m-%d"): - # return almanac_data["almanac_base64_str"] - # else: - # generate_almanac() - # return almanac_data["almanac_base64_str"] - generate_almanac() - return almanac_data["almanac_base64_str"] diff --git a/plugins/genshin/almanac/back.png b/plugins/genshin/almanac/back.png deleted file mode 100644 index bce9428b..00000000 Binary files a/plugins/genshin/almanac/back.png and /dev/null differ diff --git a/plugins/genshin/almanac/config.json b/plugins/genshin/almanac/config.json deleted file mode 100644 index ebd1e35b..00000000 --- a/plugins/genshin/almanac/config.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "抽卡":{ - "buff": ["欧气满满,十连出金","出金不歪"], - "debuff": ["武器大师","保底出金","金色会是痛苦大剑"] - }, - "刷世界boss":{ - "buff": ["双攻双爆角斗士"], - "debuff": ["只有保底材料","贪生怕死角斗士"] - }, - "刷风本":{ - "buff": ["会有极品猎人套","会掉真正的少女心","治疗加成少女头"], - "debuff": ["勇往直前少女心","少女飘摇的杀意","少女暴怒的容颜"] - }, - "刷火本":{ - "buff": ["魔女帽子火伤杯","暴伤魔女帽!","火伤魔女心!"], - "debuff": ["幡 然 醒 悟","这么阴间的地方真的会有魔女套吗?","不务正业火魔女","会匹配到3个卢姥爷"] - }, - "刷岩本":{ - "buff": ["悠久的磐岩伴你左右","岩神的庇护常在"], - "debuff": ["防御流星杯,你值得拥有"] - }, - "刷宗室":{ - "buff": ["物理伤害骑士道,元素精通宗室套"], - "debuff": ["贪生怕死骑士道,物理伤害宗室杯"] - }, - "刷冰本":{ - "buff": ["双暴词条概率up"], - "debuff": ["防御力船帽,无人可及"] - }, - "刷雷本":{ - "buff": ["愿雷鸟伴你左右"], - "debuff": ["来表演一个只掉平雷套的绝活","风神忽悠雷凶兆"] - }, - "锄大地":{ - "buff": ["会掉一大堆紫色材料"], - "debuff": ["深渊法师爱你哟","会被冰水法控到死"] - }, - "挖矿":{ - "buff": ["开矿出双材料"], - "debuff": ["去别人世界会被拒"] - }, - "刷天赋本":{ - "buff": ["金色!我看到了金色的书!"], - "debuff": ["2蓝2绿不会变"] - }, - "刷突破材料":{ - "buff": ["金色!我看到了金色的材料!"], - "debuff": ["2蓝2绿不会变"] - }, - "升级圣遗物":{ - "buff": ["稀有词条跳跳跳","会双爆拉满"], - "debuff": ["女 仆 狂 喜","无中生有防御力","生命拉满","完美避开双爆"] - }, - "打风魔龙":{ - "buff": ["看我一箭一个风魔鸡","今天特瓦林可以给想要的突破材料","5金加原胚!"], - "debuff": ["会不小心掉下平台","不小心被地板烫死了"] - }, - "打狼王":{ - "buff": ["今天安德琉斯的心情不错,可以py一下","5金加原胚!"], - "debuff": ["狼尾巴*1"] - }, - "打公子":{ - "buff": ["今天可以和公子py想要的突破材料","5金加原胚!"], - "debuff": ["要角没有!要命一条!"] - } -} - - - - diff --git a/plugins/genshin/almanac/data_source.py b/plugins/genshin/almanac/data_source.py new file mode 100644 index 00000000..c9cec6f4 --- /dev/null +++ b/plugins/genshin/almanac/data_source.py @@ -0,0 +1,43 @@ +from utils.browser import get_browser +from utils.message_builder import image +from datetime import datetime +from services.log import logger +from pathlib import Path +import os + +url = "https://genshin.pub" + + +async def get_alc_image(path: Path): + date = datetime.now().date() + for file in os.listdir(path): + if f'{date}.png' != file: + file = path / file + file.unlink() + if f'{date}.png' in os.listdir(path): + return image(f'{date}.png', 'genshin/alc') + page = None + try: + browser = await get_browser() + page = await browser.new_page() + await page.goto(url, wait_until="networkidle", timeout=10000) + await page.set_viewport_size({"width": 2560, "height": 1080}) + card = await page.query_selector('.GSAlmanacs_gs_almanacs__3qT_A') + await card.screenshot(path=path / f'{date}.png', timeout=100000) + except Exception as e: + logger.error(f'获取原神黄历发生错误..{type(e)}: {e}') + finally: + if page: + await page.close() + return image(f'{date}.png', 'genshin/alc') + + + + + + + + + + + diff --git a/plugins/genshin/material_remind/__init__.py b/plugins/genshin/material_remind/__init__.py index 20456748..c54bef37 100644 --- a/plugins/genshin/material_remind/__init__.py +++ b/plugins/genshin/material_remind/__init__.py @@ -12,14 +12,39 @@ from nonebot.permission import SUPERUSER from typing import List import os import asyncio - import time + +__zx_plugin_name__ = "原神今日素材" +__plugin_usage__ = """ +usage: + 看看原神今天要刷什么 + 指令: + 今日素材/今天素材 +""".strip() +__plugin_superuser_usage__ = """ +usage: + 更新原神今日素材 + 指令: + 更新原神今日素材 +""".strip() +__plugin_des__ = "看看原神今天要刷什么" +__plugin_cmd__ = ["今日素材/今天素材", "更新原神今日素材 [_superuser]"] +__plugin_type__ = ("原神相关",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["今日素材", "今天素材"], +} + driver: Driver = nonebot.get_driver() -material = on_command('今日素材', aliases={'今日材料', '今天素材', '今天材料'}, priority=5, block=True) +material = on_command("今日素材", aliases={"今日材料", "今天素材", "今天材料"}, priority=5, block=True) -super_cmd = on_command('更新原神今日素材', permission=SUPERUSER, priority=1, block=True) +super_cmd = on_command("更新原神今日素材", permission=SUPERUSER, priority=1, block=True) @material.handle() @@ -27,49 +52,62 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): if time.strftime("%w") == "0": await material.send("今天是周日,所有材料副本都开放了。") return - await material.send(Message(image('daily_material.png', 'genshin/material') + '\n※ 每日素材数据来源于 genshin.pub')) + await material.send( + Message( + image("daily_material.png", "genshin/material") + + "\n※ 每日素材数据来源于 genshin.pub" + ) + ) logger.info( f"(USER {event.user_id}, GROUP {event.group_id if event.message_type != 'private' else 'private'})" - f" 发送查看今日素材") + f" 发送查看今日素材" + ) @super_cmd.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): if await update_image(): - await super_cmd.send('更新成功...') - logger.info(f'更新每日天赋素材成功...') + await super_cmd.send("更新成功...") + logger.info(f"更新每日天赋素材成功...") else: - await super_cmd.send(f'更新失败...') + await super_cmd.send(f"更新失败...") @driver.on_startup async def update_image(): page = None try: - if not os.path.exists(f'{IMAGE_PATH}/genshin/material'): - os.mkdir(f'{IMAGE_PATH}/genshin/material') - for file in os.listdir(f'{IMAGE_PATH}/genshin/material'): - os.remove(f'{IMAGE_PATH}/genshin/material/{file}') + if not os.path.exists(f"{IMAGE_PATH}/genshin/material"): + os.mkdir(f"{IMAGE_PATH}/genshin/material") + for file in os.listdir(f"{IMAGE_PATH}/genshin/material"): + os.remove(f"{IMAGE_PATH}/genshin/material/{file}") browser = await get_browser() if not browser: - logger.warning('获取 browser 失败,请部署至 linux 环境....') + logger.warning("获取 browser 失败,请部署至 linux 环境....") return False - url = 'https://genshin.pub/daily' + url = "https://genshin.pub/daily" page = await browser.new_page() - await page.goto(url, wait_until='networkidle', timeout=10000) + await page.goto(url, wait_until="networkidle", timeout=10000) await page.set_viewport_size({"width": 2560, "height": 1080}) - await page.evaluate(""" + await page.evaluate( + """ document.getElementsByClassName('GSTitleBar_gs_titlebar__2IJqy')[0].remove(); e = document.getElementsByClassName('GSContainer_gs_container__2FbUz')[0]; e.setAttribute("style", "height:880px"); - """) + """ + ) await page.click("button") div = await page.query_selector(".GSContainer_content_box__1sIXz") - for i, card in enumerate(await page.query_selector_all(".GSTraitCotainer_trait_section__1f3bc")): + for i, card in enumerate( + await page.query_selector_all(".GSTraitCotainer_trait_section__1f3bc") + ): index = 0 - type_ = 'char' if not i else 'weapons' + type_ = "char" if not i else "weapons" for x in await card.query_selector_all("xpath=child::*"): - await x.screenshot(path=f'{IMAGE_PATH}/genshin/material/{type_}_{index}.png', timeout=100000) + await x.screenshot( + path=f"{IMAGE_PATH}/genshin/material/{type_}_{index}.png", + timeout=100000, + ) # 下滑两次 for _ in range(3): await div.press("PageDown") @@ -77,13 +115,23 @@ async def update_image(): # 结束后上滑至顶 for _ in range(index * 3): await div.press("PageUp") - file_list = os.listdir(f'{IMAGE_PATH}/genshin/material') - char_imgs = [f'{IMAGE_PATH}/genshin/material/{x}' for x in file_list if x.startswith('char')] - weapons_imgs = [f'{IMAGE_PATH}/genshin/material/{x}' for x in file_list if x.startswith('weapons')] + file_list = os.listdir(f"{IMAGE_PATH}/genshin/material") + char_imgs = [ + f"{IMAGE_PATH}/genshin/material/{x}" + for x in file_list + if x.startswith("char") + ] + weapons_imgs = [ + f"{IMAGE_PATH}/genshin/material/{x}" + for x in file_list + if x.startswith("weapons") + ] char_imgs.sort() weapons_imgs.sort() - height = await asyncio.get_event_loop().run_in_executor(None, get_background_height, weapons_imgs) - background_img = CreateImg(1200, height + 100, color='#f6f2ee') + height = await asyncio.get_event_loop().run_in_executor( + None, get_background_height, weapons_imgs + ) + background_img = CreateImg(1200, height + 100, color="#f6f2ee") current_width = 50 for imgs in [char_imgs, weapons_imgs]: current_height = 20 @@ -92,11 +140,11 @@ async def update_image(): background_img.paste(x, (current_width, current_height)) current_height += x.size[1] current_width += 600 - background_img.save(f'{IMAGE_PATH}/genshin/material/daily_material.png') + background_img.save(f"{IMAGE_PATH}/genshin/material/daily_material.png") await page.close() return True except Exception as e: - logger.error(f'原神每日素材更新出错... {type(e)}: {e}') + logger.error(f"原神每日素材更新出错... {type(e)}: {e}") if page: await page.close() return False @@ -116,7 +164,7 @@ def get_background_height(weapons_imgs: List[str]) -> int: @scheduler.scheduled_job( - 'cron', + "cron", hour=4, minute=1, ) @@ -124,11 +172,7 @@ async def _(): for _ in range(5): try: await update_image() - logger.info(f'更新每日天赋素材成功...') + logger.info(f"更新每日天赋素材成功...") break except Exception as e: - logger.error(f'更新每日天赋素材出错 e:{e}') - - - - + logger.error(f"更新每日天赋素材出错 e:{e}") diff --git a/plugins/genshin/qiu_qiu_translation/__init__.py b/plugins/genshin/qiu_qiu_translation/__init__.py index a8beb978..512639a6 100644 --- a/plugins/genshin/qiu_qiu_translation/__init__.py +++ b/plugins/genshin/qiu_qiu_translation/__init__.py @@ -5,9 +5,24 @@ from nonebot import on_command from utils.utils import get_message_text from services.log import logger -__plugin_name__ = "丘丘语翻译" - -__plugin_usage__ = "用法:丘丘翻译 [消息]" +__zx_plugin_name__ = "丘丘语翻译" +__plugin_usage__ = """ +usage: + 异世界旅游小助手,仅支持丘丘语翻译至中文 + 指令: + 丘丘语翻译/丘丘一下 [文本] +""".strip() +__plugin_des__ = "其实我听得懂丘丘人讲话" +__plugin_cmd__ = ["丘丘语翻译/丘丘一下 [文本]"] +__plugin_type__ = ("原神相关",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["丘丘语翻译", "丘丘一下"], +} qiuqiu = on_command("丘丘语翻译", aliases={"丘丘一下", "丘丘翻译"}, priority=5, block=True) diff --git a/plugins/genshin/query_resource_points/__init__.py b/plugins/genshin/query_resource_points/__init__.py index caa2d0e3..1339d059 100644 --- a/plugins/genshin/query_resource_points/__init__.py +++ b/plugins/genshin/query_resource_points/__init__.py @@ -1,6 +1,5 @@ from nonebot import on_command, on_regex -from nonebot.rule import to_me -from .query_resource import get_resource_type_list, query_resource, init +from .query_resource import get_resource_type_list, query_resource, init, check_resource_exists from utils.utils import get_message_text, scheduler from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent, Message from nonebot.typing import T_State @@ -14,28 +13,53 @@ try: except ModuleNotFoundError: import json -__plugin_name__ = "原神资源查询" +__zx_plugin_name__ = "原神资源查询" +__plugin_usage__ = """ +usage: + 不需要打开网页,就能帮你生成资源图片 + 指令: + 原神资源查询 [资源名称] + 原神资源列表 + [资源名称]在哪 + 哪有[资源名称] +""".strip() +__plugin_superuser_usage__ = """ +usage: + 更新原神资源信息 + 指令: + 更新原神资源信息 +""".strip() +__plugin_des__ = "原神大地图资源速速查看" +__plugin_cmd__ = ["原神资源查询 [资源名称]", "原神资源列表", "[资源名称]在哪/哪有[资源名称]", "更新原神资源信息 [_superuser]"] +__plugin_type__ = ("原神相关",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["原神资源查询", "原神资源列表"], +} -__plugin_usage__ = ( - "用法:\n" "\t原神资源查询 [消息]\n" "\t原神资源列表\n" "\t[消息]在哪\n" "\t哪有[消息]\n" "[消息] = 资源名称" -) - -qr = on_command("原神资源查询", priority=5, block=True) +qr = on_command("原神资源查询", aliases={"原神资源查找"}, 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('更新原神资源信息', permission=SUPERUSER, priority=1, block=True) +rex_qr = on_regex(".*?(在哪|在哪里|哪有|哪里有).*?", priority=5, block=True) +update_info = on_command("更新原神资源信息", permission=SUPERUSER, priority=1, block=True) @qr.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): resource_name = get_message_text(event.json()) - await qr.send('正在生成位置....') - rst = await query_resource(resource_name) - await qr.send(Message(rst), at_sender=True) - logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" - f" 查询原神材料:" + resource_name - ) + if check_resource_exists(resource_name): + await qr.send("正在生成位置....") + resource = await query_resource(resource_name) + await qr.send(Message(resource), at_sender=True) + logger.info( + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" + f" 查询原神材料:" + resource_name + ) + else: + await qr.send(f"未查找到 {resource_name} 资源,可通过 “原神资源列表” 获取全部资源名称..") @rex_qr.handle() @@ -47,14 +71,15 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): else: rs = re.search(".*?(哪有|哪里有)(.*)", msg) resource_name = rs.group(2) if rs else "" - if resource_name: - await qr.send('正在生成位置....') - msg = await query_resource(resource_name) - await rex_qr.send(Message(msg), at_sender=True) - logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" - f" 查询原神材料:" + resource_name - ) + if check_resource_exists(resource_name): + await qr.send("正在生成位置....") + resource = await query_resource(resource_name) + if resource: + await rex_qr.send(Message(resource), at_sender=True) + logger.info( + f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" + f" 查询原神材料:" + resource_name + ) @qr_lst.handle() @@ -87,17 +112,17 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @update_info.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await init(True) - await update_info.send('更新原神资源信息完成...') + await update_info.send("更新原神资源信息完成...") @scheduler.scheduled_job( - 'cron', + "cron", hour=5, minute=1, ) async def _(): try: await init() - logger.info(f'每日更新原神材料信息成功!') + logger.info(f"每日更新原神材料信息成功!") except Exception as e: - logger.error(f'每日更新原神材料信息错误:{e}') + logger.error(f"每日更新原神材料信息错误:{e}") diff --git a/plugins/genshin/query_resource_points/map.py b/plugins/genshin/query_resource_points/map.py index c9007983..6efcc1e0 100644 --- a/plugins/genshin/query_resource_points/map.py +++ b/plugins/genshin/query_resource_points/map.py @@ -1,5 +1,5 @@ from pathlib import Path -from configs.path_config import IMAGE_PATH, TXT_PATH +from configs.path_config import IMAGE_PATH, TEXT_PATH from utils.image_utils import CreateImg from typing import Tuple, List from math import sqrt, pow @@ -12,8 +12,8 @@ except ModuleNotFoundError: icon_path = Path(IMAGE_PATH) / "genshin" / "genshin_icon" map_path = Path(IMAGE_PATH) / "genshin" / "map" / "map.png" -resource_label_file = Path(TXT_PATH) / "genshin" / "resource_label_file.json" -resource_point_file = Path(TXT_PATH) / "genshin" / "resource_point_file.json" +resource_label_file = Path(TEXT_PATH) / "genshin" / "resource_label_file.json" +resource_point_file = Path(TEXT_PATH) / "genshin" / "resource_point_file.json" class Map: diff --git a/plugins/genshin/query_resource_points/query_resource.py b/plugins/genshin/query_resource_points/query_resource.py index 3ab17e9f..d763ec5a 100644 --- a/plugins/genshin/query_resource_points/query_resource.py +++ b/plugins/genshin/query_resource_points/query_resource.py @@ -1,5 +1,5 @@ from typing import Tuple, Optional, List -from configs.path_config import IMAGE_PATH, TXT_PATH +from configs.path_config import IMAGE_PATH, TEXT_PATH from PIL.Image import UnidentifiedImageError from utils.message_builder import image from services.log import logger @@ -30,9 +30,9 @@ MAP_URL = "https://api-static.mihoyo.com/common/map_user/ys_obc/v1/map/info?map_ icon_path = Path(IMAGE_PATH) / "genshin" / "genshin_icon" map_path = Path(IMAGE_PATH) / "genshin" / "map" -resource_label_file = Path(TXT_PATH) / "genshin" / "resource_label_file.json" -resource_point_file = Path(TXT_PATH) / "genshin" / "resource_point_file.json" -resource_type_file = Path(TXT_PATH) / "genshin" / "resource_type_file.json" +resource_label_file = Path(TEXT_PATH) / "genshin" / "resource_label_file.json" +resource_point_file = Path(TEXT_PATH) / "genshin" / "resource_point_file.json" +resource_type_file = Path(TEXT_PATH) / "genshin" / "resource_type_file.json" # 地图中心坐标 CENTER_POINT: Optional[Tuple[int, int]] = None @@ -50,7 +50,8 @@ async def query_resource(resource_name: str) -> str: resource_name = resource_name[:-2].strip() planning_route = True if not resource_name or resource_name not in resource_name_list: - return f"未查找到 {resource_name} 资源,可通过 “原神资源列表” 获取全部资源名称.." + # return f"未查找到 {resource_name} 资源,可通过 “原神资源列表” 获取全部资源名称.." + return '' map_ = Map( resource_name, CENTER_POINT, planning_route=planning_route, ratio=MAP_RATIO ) @@ -81,23 +82,36 @@ def get_resource_type_list(): return mes +def check_resource_exists(resource: str) -> bool: + """ + 检查资源是否存在 + :param resource: 资源名称 + """ + resource = resource.replace('路径', '').replace('路线', '') + return resource in resource_name_list + + @driver.on_startup async def init(flag: bool = False): global CENTER_POINT, resource_name_list - semaphore = asyncio.Semaphore(10) - async with aiohttp.ClientSession(headers=get_user_agent()) as session: - await download_map_init(session, semaphore, MAP_RATIO, flag) - await download_resource_data(session, semaphore) - await download_resource_type(session) - if not CENTER_POINT: - CENTER_POINT = json.load(open(resource_label_file, "r", encoding="utf8"))[ - "CENTER_POINT" - ] - with open(resource_type_file, "r", encoding="utf8") as f: - data = json.load(f) - for id_ in data: - for x in data[id_]["children"]: - resource_name_list.append(x["name"]) + try: + semaphore = asyncio.Semaphore(10) + async with aiohttp.ClientSession(headers=get_user_agent()) as session: + await download_map_init(session, semaphore, MAP_RATIO, flag) + await download_resource_data(session, semaphore) + await download_resource_type(session) + if not CENTER_POINT: + CENTER_POINT = json.load(open(resource_label_file, "r", encoding="utf8"))[ + "CENTER_POINT" + ] + with open(resource_type_file, "r", encoding="utf8") as f: + data = json.load(f) + for id_ in data: + for x in data[id_]["children"]: + resource_name_list.append(x["name"]) + except TimeoutError: + logger.warning('原神资源查询信息初始化超时....') + pass # 图标及位置资源 diff --git a/plugins/remind/__init__.py b/plugins/group_apscheduler/__init__.py similarity index 86% rename from plugins/remind/__init__.py rename to plugins/group_apscheduler/__init__.py index 02b763d8..3f0b6168 100644 --- a/plugins/remind/__init__.py +++ b/plugins/group_apscheduler/__init__.py @@ -1,197 +1,195 @@ -from utils.message_builder import image -from utils.utils import scheduler, get_bot -from services.log import logger -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]" - - -# 早上好 -@scheduler.scheduled_job( - "cron", - # year=None, - # month=None, - # day=None, - # week=None, - # day_of_week="mon,tue,wed,thu,fri", - hour=6, - minute=1, - # second=None, - # start_date=None, - # end_date=None, - # timezone=None, -) -async def _(): - try: - bot = get_bot() - gl = await bot.get_group_list(self_id=bot.self_id) - gl = [g["group_id"] for g in gl] - for g in gl: - if await GroupRemind.get_status(g, "zwa"): - result = image("zao.jpg", "zhenxun") - try: - await bot.send_group_msg(group_id=g, message="早上好" + result) - except ActionFailed: - logger.warning(f"{g} 群被禁言中,无法发送早安") - except Exception as e: - logger.error(f"早晚安错误 e:{e}") - - -# 睡觉了 -@scheduler.scheduled_job( - "cron", - hour=23, - minute=59, -) -async def _(): - try: - bot = get_bot() - gl = await bot.get_group_list(self_id=bot.self_id) - gl = [g["group_id"] for g in gl] - for g in gl: - if await GroupRemind.get_status(g, "zwa"): - result = image("sleep.jpg", "zhenxun") - try: - await bot.send_group_msg( - group_id=g, message=f"{NICKNAME}要睡觉了,你们也要早点睡呀" + result - ) - except ActionFailed: - logger.warning(f"{g} 群被禁言中,无法发送晚安") - except Exception as e: - logger.error(f"早晚安错误 e:{e}") - - -# 自动更新群组信息 -@scheduler.scheduled_job( - "cron", - hour=3, - minute=1, -) -async def _(): - try: - bot = get_bot() - gl = await bot.get_group_list(self_id=bot.self_id) - gl = [g["group_id"] for g in gl] - for g in gl: - group_info = await bot.get_group_info(group_id=g) - await GroupInfo.add_group_info( - group_info["group_id"], - group_info["group_name"], - group_info["max_member_count"], - group_info["member_count"], - ) - logger.info(f"自动更新群组 {g} 信息成功") - except Exception as e: - logger.error(f"自动更新群组信息错误 e:{e}") - - -# 自动更新好友信息 -@scheduler.scheduled_job( - "cron", - hour=3, - minute=1, -) -async def _(): - try: - bot = get_bot() - fl = await bot.get_friend_list(self_id=bot.self_id) - for f in fl: - if await FriendUser.add_friend_info(f["user_id"], f["nickname"]): - logger.info(f'自动更新好友 {f["user_id"]} 信息成功') - else: - logger.warning(f'自动更新好友 {f["user_id"]} 信息失败') - except Exception as e: - logger.error(f"自动更新群组信息错误 e:{e}") - - -# 一次性任务 -# 固定时间触发,仅触发一次: -# -# from datetime import datetime -# -# @nonebot.scheduler.scheduled_job( -# 'date', -# run_date=datetime(2021, 1, 1, 0, 0), -# # timezone=None, -# ) -# async def _(): -# await bot.send_group_msg(group_id=123456, -# message="2021,新年快乐!") - -# 定期任务 -# 从 start_date 开始到 end_date 结束,根据类似 Cron -# -# 的规则触发任务: -# -# @nonebot.scheduler.scheduled_job( -# 'cron', -# # year=None, -# # month=None, -# # day=None, -# # week=None, -# day_of_week="mon,tue,wed,thu,fri", -# hour=7, -# # minute=None, -# # second=None, -# # start_date=None, -# # end_date=None, -# # timezone=None, -# ) -# async def _(): -# await bot.send_group_msg(group_id=123456, -# message="起床啦!") - -# 间隔任务 -# -# interval 触发器 -# -# 从 start_date 开始,每间隔一段时间触发,到 end_date 结束: -# -# @nonebot.scheduler.scheduled_job( -# 'interval', -# # weeks=0, -# # days=0, -# # hours=0, -# minutes=5, -# # seconds=0, -# # start_date=time.now(), -# # end_date=None, -# ) -# async def _(): -# has_new_item = check_new_item() -# if has_new_item: -# await bot.send_group_msg(group_id=123456, -# message="XX有更新啦!") - - -# 动态的计划任务 -# import datetime -# -# from apscheduler.triggers.date import DateTrigger # 一次性触发器 -# # from apscheduler.triggers.cron import CronTrigger # 定期触发器 -# # from apscheduler.triggers.interval import IntervalTrigger # 间隔触发器 -# from nonebot import on_command, scheduler -# -# @on_command('赖床') -# async def _(session: CommandSession): -# await session.send('我会在5分钟后再喊你') -# -# # 制作一个“5分钟后”触发器 -# delta = datetime.timedelta(minutes=5) -# trigger = DateTrigger( -# run_date=datetime.datetime.now() + delta -# ) -# -# # 添加任务 -# scheduler.add_job( -# func=session.send, # 要添加任务的函数,不要带参数 -# trigger=trigger, # 触发器 -# args=('不要再赖床啦!',), # 函数的参数列表,注意:只有一个值时,不能省略末尾的逗号 -# # kwargs=None, -# misfire_grace_time=60, # 允许的误差时间,建议不要省略 -# # jobstore='default', # 任务储存库,在下一小节中说明 -# ) +from utils.message_builder import image +from utils.utils import scheduler, get_bot +from nonebot import on_message +from services.log import logger +from models.group_info import GroupInfo +from models.friend_user import FriendUser +from nonebot.adapters.cqhttp.exception import ActionFailed +from configs.config import NICKNAME +from utils.manager import group_manager + +__zx_plugin_name__ = "群定时任务相关 [Hidden]" +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_task__ = {'zwa': '早晚安'} + + +x = on_message(priority=9, block=False) + + +# 早上好 +@scheduler.scheduled_job( + "cron", + hour=6, + minute=1, +) +async def _(): + try: + bot = get_bot() + gl = await bot.get_group_list() + gl = [g["group_id"] for g in gl] + for g in gl: + if await group_manager.check_group_task_status(g, 'zwa'): + result = image("zao.jpg", "zhenxun") + try: + await bot.send_group_msg(group_id=g, message="早上好" + result) + except ActionFailed: + logger.warning(f"{g} 群被禁言中,无法发送早安") + except Exception as e: + logger.error(f"早晚安错误 e:{e}") + + +# 睡觉了 +@scheduler.scheduled_job( + "cron", + hour=23, + minute=59, +) +async def _(): + try: + bot = get_bot() + gl = await bot.get_group_list() + gl = [g["group_id"] for g in gl] + for g in gl: + if await group_manager.check_group_task_status(g, 'zwa'): + result = image("sleep.jpg", "zhenxun") + try: + await bot.send_group_msg( + group_id=g, message=f"{NICKNAME}要睡觉了,你们也要早点睡呀" + result + ) + except ActionFailed: + logger.warning(f"{g} 群被禁言中,无法发送晚安") + except Exception as e: + logger.error(f"早晚安错误 e:{e}") + + +# 自动更新群组信息 +@scheduler.scheduled_job( + "cron", + hour=3, + minute=1, +) +async def _(): + try: + bot = get_bot() + gl = await bot.get_group_list() + gl = [g["group_id"] for g in gl] + for g in gl: + group_info = await bot.get_group_info(group_id=g) + await GroupInfo.add_group_info( + group_info["group_id"], + group_info["group_name"], + group_info["max_member_count"], + group_info["member_count"], + ) + logger.info(f"自动更新群组 {g} 信息成功") + except Exception as e: + logger.error(f"自动更新群组信息错误 e:{e}") + + +# 自动更新好友信息 +@scheduler.scheduled_job( + "cron", + hour=3, + minute=1, +) +async def _(): + try: + bot = get_bot() + fl = await bot.get_friend_list() + for f in fl: + if await FriendUser.add_friend_info(f["user_id"], f["nickname"]): + logger.info(f'自动更新好友 {f["user_id"]} 信息成功') + else: + logger.warning(f'自动更新好友 {f["user_id"]} 信息失败') + except Exception as e: + logger.error(f"自动更新群组信息错误 e:{e}") + + +# 一次性任务 +# 固定时间触发,仅触发一次: +# +# from datetime import datetime +# +# @nonebot.scheduler.scheduled_job( +# 'date', +# run_date=datetime(2021, 1, 1, 0, 0), +# # timezone=None, +# ) +# async def _(): +# await bot.send_group_msg(group_id=123456, +# message="2021,新年快乐!") + +# 定期任务 +# 从 start_date 开始到 end_date 结束,根据类似 Cron +# +# 的规则触发任务: +# +# @nonebot.scheduler.scheduled_job( +# 'cron', +# # year=None, +# # month=None, +# # day=None, +# # week=None, +# day_of_week="mon,tue,wed,thu,fri", +# hour=7, +# # minute=None, +# # second=None, +# # start_date=None, +# # end_date=None, +# # timezone=None, +# ) +# async def _(): +# await bot.send_group_msg(group_id=123456, +# message="起床啦!") + +# 间隔任务 +# +# interval 触发器 +# +# 从 start_date 开始,每间隔一段时间触发,到 end_date 结束: +# +# @nonebot.scheduler.scheduled_job( +# 'interval', +# # weeks=0, +# # days=0, +# # hours=0, +# minutes=5, +# # seconds=0, +# # start_date=time.now(), +# # end_date=None, +# ) +# async def _(): +# has_new_item = check_new_item() +# if has_new_item: +# await bot.send_group_msg(group_id=123456, +# message="XX有更新啦!") + + +# 动态的计划任务 +# import datetime +# +# from apscheduler.triggers.date import DateTrigger # 一次性触发器 +# # from apscheduler.triggers.cron import CronTrigger # 定期触发器 +# # from apscheduler.triggers.interval import IntervalTrigger # 间隔触发器 +# from nonebot import on_command, scheduler +# +# @on_command('赖床') +# async def _(session: CommandSession): +# await session.send('我会在5分钟后再喊你') +# +# # 制作一个“5分钟后”触发器 +# delta = datetime.timedelta(minutes=5) +# trigger = DateTrigger( +# run_date=datetime.datetime.now() + delta +# ) +# +# # 添加任务 +# scheduler.add_job( +# func=session.send, # 要添加任务的函数,不要带参数 +# trigger=trigger, # 触发器 +# args=('不要再赖床啦!',), # 函数的参数列表,注意:只有一个值时,不能省略末尾的逗号 +# # kwargs=None, +# misfire_grace_time=60, # 允许的误差时间,建议不要省略 +# # jobstore='default', # 任务储存库,在下一小节中说明 +# ) diff --git a/plugins/group_handle/__init__.py b/plugins/group_handle/__init__.py index 310329e5..ec6c348c 100644 --- a/plugins/group_handle/__init__.py +++ b/plugins/group_handle/__init__.py @@ -4,28 +4,31 @@ from utils.message_builder import image from models.group_member_info import GroupInfoUser from datetime import datetime from services.log import logger -from models.group_remind import GroupRemind from nonebot.adapters.cqhttp import ( Bot, GroupIncreaseNoticeEvent, GroupDecreaseNoticeEvent, ) from nonebot.adapters.cqhttp.exception import ActionFailed -from configs.config import plugins2info_dict -from utils.static_data import group_manager +from utils.manager import group_manager, plugins2settings_manager from models.group_info import GroupInfo from pathlib import Path import random import os + try: import ujson as json except ModuleNotFoundError: import json -__plugin_name__ = "群事件处理 [Hidden]" - -__usage__ = "用法:无" +__zx_plugin_name__ = "群事件处理 [Hidden]" +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_task__ = { + 'group_welcome': '进群欢迎', + 'refund_group_remind': '退群提醒' +} # 群员增加处理 @@ -39,10 +42,11 @@ add_group = on_request(priority=1, block=False) @group_increase_handle.handle() async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict): if event.user_id == int(bot.self_id): - if event.group_id not in group_manager['group_manager'].keys(): - for plugin in plugins2info_dict.keys(): - if not plugins2info_dict[plugin]['default_status']: - group_manager.block_plugin(plugin, str(event.group_id)) + if event.group_id not in group_manager["group_manager"].keys(): + data = plugins2settings_manager.get_data() + for plugin in data.keys(): + if not data[plugin]["default_status"]: + group_manager.block_plugin(plugin, event.group_id) else: join_time = datetime.now() user_info = await bot.get_group_member_info( @@ -59,7 +63,7 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict): logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新失败") # 群欢迎消息 - if await GroupRemind.get_status(event.group_id, "hy"): + if await group_manager.check_group_task_status(event.group_id, 'group_welcome'): msg = "" img = "" at_flag = False @@ -74,7 +78,9 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent, state: dict): msg = msg.replace("[at]", "") at_flag = True if os.path.exists(DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg"): - img = image(abspath=DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg") + img = image( + abspath=DATA_PATH + f"custom_welcome_msg/{event.group_id}.jpg" + ) if msg or img: await group_increase_handle.send( "\n" + msg.strip() + img, at_sender=at_flag @@ -104,9 +110,9 @@ async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict): await bot.send_private_msg( user_id=coffee, message=f"****呜..一份踢出报告****\n" - f"我被 {operator_name}({operator_id})\n" - f"踢出了 {group_name}({group_id})\n" - f"日期:{str(datetime.now()).split('.')[0]}", + f"我被 {operator_name}({operator_id})\n" + f"踢出了 {group_name}({group_id})\n" + f"日期:{str(datetime.now()).split('.')[0]}", ) return try: @@ -115,20 +121,21 @@ async def _(bot: Bot, event: GroupDecreaseNoticeEvent, state: dict): ).user_name except AttributeError: user_name = str(event.user_id) - rst = "" - if event.sub_type == "leave": - rst = f"{user_name}离开了我们..." - if event.sub_type == "kick": - operator = await bot.get_group_member_info( - user_id=event.operator_id, group_id=event.group_id - ) - operator_name = operator["card"] if operator["card"] else operator["nickname"] - rst = f"{user_name} 被 {operator_name} 送走了." if await GroupInfoUser.delete_member_info(event.user_id, event.group_id): logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除成功") else: logger.info(f"用户{user_name}, qq={event.user_id} 所属{event.group_id} 删除失败") - try: - await group_decrease_handle.send(f"{rst}") - except ActionFailed: - return + if await group_manager.check_group_task_status(event.group_id, 'refund_group_remind'): + rst = "" + if event.sub_type == "leave": + rst = f"{user_name}离开了我们..." + if event.sub_type == "kick": + operator = await bot.get_group_member_info( + user_id=event.operator_id, group_id=event.group_id + ) + operator_name = operator["card"] if operator["card"] else operator["nickname"] + rst = f"{user_name} 被 {operator_name} 送走了." + try: + await group_decrease_handle.send(f"{rst}") + except ActionFailed: + return diff --git a/plugins/last_chat/__init__.py b/plugins/group_last_chat/__init__.py similarity index 91% rename from plugins/last_chat/__init__.py rename to plugins/group_last_chat/__init__.py index 8078b551..b741ae43 100644 --- a/plugins/last_chat/__init__.py +++ b/plugins/group_last_chat/__init__.py @@ -1,35 +1,35 @@ -from nonebot import on_message -from nonebot.adapters.cqhttp.permission import GROUP -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -import time -from .data_source import cancel_all_notice, save_data, get_data, set_data_value -from services.log import logger - - -__plugin_name__ = "查看群最后聊天时间 [Hidden]" - -__plugin_usage__ = "用法:无" - - -last_chat = on_message(priority=1, block=False, permission=GROUP) - - -@last_chat.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - time_data = await get_data() - set_data_value(event.group_id, time.time()) - if event.group_id in time_data["_group"]: - time_data["_group"].remove(event.group_id) - set_data_value("_group", time_data["_group"]) - for key in time_data.keys(): - if key not in ["check_time", "_group"]: - if key not in time_data["_group"]: - if time.time() - time_data[key] > 60 * 60 * 36: - await cancel_all_notice(key) - time_data["_group"].append(key) - set_data_value("_group", time_data["_group"]) - logger.info(f"GROUP {event.group_id} 因群内发言时间大于36小时被取消全部通知") - if time.time() - time_data["check_time"] > 60 * 60 * 1: - set_data_value("check_time", time.time()) - save_data() +from nonebot import on_message +from nonebot.adapters.cqhttp.permission import GROUP +from nonebot.typing import T_State +from nonebot.adapters.cqhttp import Bot, GroupMessageEvent +import time +from .data_source import cancel_all_notice, save_data, get_data, set_data_value +from services.log import logger + + +__zx_plugin_name__ = "群聊最后聊天时间记录 [Hidden]" +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" + + +last_chat = on_message(priority=1, block=False, permission=GROUP) + + +@last_chat.handle() +async def _(bot: Bot, event: GroupMessageEvent, state: T_State): + time_data = await get_data() + set_data_value(event.group_id, time.time()) + if event.group_id in time_data["_group"]: + time_data["_group"].remove(event.group_id) + set_data_value("_group", time_data["_group"]) + for key in time_data.keys(): + if key not in ["check_time", "_group"]: + if key not in time_data["_group"]: + if time.time() - time_data[key] > 60 * 60 * 36: + await cancel_all_notice(key) + time_data["_group"].append(key) + set_data_value("_group", time_data["_group"]) + logger.info(f"GROUP {event.group_id} 因群内发言时间大于36小时被取消全部通知") + if time.time() - time_data["check_time"] > 60 * 60 * 1: + set_data_value("check_time", time.time()) + save_data() diff --git a/plugins/last_chat/data_source.py b/plugins/group_last_chat/data_source.py similarity index 78% rename from plugins/last_chat/data_source.py rename to plugins/group_last_chat/data_source.py index 269f62a9..924f81d1 100644 --- a/plugins/last_chat/data_source.py +++ b/plugins/group_last_chat/data_source.py @@ -1,71 +1,67 @@ -from configs.path_config import DATA_PATH -from utils.utils import get_bot -from models.group_remind import GroupRemind -from datetime import datetime -import time -from services.log import logger - -try: - import ujson as json -except ModuleNotFoundError: - import json - - -time_data = {} - - -async def init(): - global time_data - bot = get_bot() - gl = await bot.get_group_list(self_id=bot.self_id) - gl = [g["group_id"] for g in gl] - data = read_data("group_last_chat_time.json") - for g in gl: - if not data.get(g): - time_data[g] = time.time() - if not time_data.get("check_time"): - time_data["check_time"] = time.time() - if not time_data.get("_group"): - time_data["_group"] = [] - save_data() - return time_data - - -def read_data(file_name: str): - try: - with open(DATA_PATH + file_name, "r", encoding="utf8") as f: - return json.load(f) - except (ValueError, FileNotFoundError): - return {} - - -def save_data(): - with open(DATA_PATH + "group_last_chat_time.json", "w") as f: - json.dump(time_data, f, indent=4) - logger.info( - f'自动存储 group_last_chat_time.json 时间:{str(datetime.now()).split(".")[0]}' - ) - - -command_list = ["zwa", "hy", "kxcz", "blpar", "epic", "pa", "gb"] - - -# 取消全部通知 -async def cancel_all_notice(group_id): - group_id = int(group_id) - for command in command_list: - if await GroupRemind.get_status(group_id, command): - await GroupRemind.set_status(group_id, command, False) - logger.info(f"关闭了 {group_id} 群的全部通知") - - -async def get_data(): - global time_data - if not time_data: - time_data = await init() - return time_data - - -def set_data_value(key, value): - global time_data - time_data[key] = value +from configs.path_config import DATA_PATH +from utils.utils import get_bot +from datetime import datetime +import time +from services.log import logger +from utils.manager import group_manager +try: + import ujson as json +except ModuleNotFoundError: + import json + + +time_data = {} + + +async def init(): + global time_data + bot = get_bot() + gl = await bot.get_group_list() + gl = [g["group_id"] for g in gl] + data = read_data("group_last_chat_time.json") + for g in gl: + if not data.get(g): + time_data[g] = time.time() + if not time_data.get("check_time"): + time_data["check_time"] = time.time() + if not time_data.get("_group"): + time_data["_group"] = [] + save_data() + return time_data + + +def read_data(file_name: str): + try: + with open(DATA_PATH + file_name, "r", encoding="utf8") as f: + return json.load(f) + except (ValueError, FileNotFoundError): + return {} + + +def save_data(): + with open(DATA_PATH + "group_last_chat_time.json", "w") as f: + json.dump(time_data, f, indent=4) + logger.info( + f'自动存储 group_last_chat_time.json 时间:{str(datetime.now()).split(".")[0]}' + ) + + +# 取消全部通知 +async def cancel_all_notice(group_id): + group_id = int(group_id) + for command in group_manager.get_task_data(): + if await group_manager.check_group_task_status(group_id, command): + await group_manager.close_group_task(group_id, command) + logger.info(f"关闭了 {group_id} 群的全部通知") + + +async def get_data(): + global time_data + if not time_data: + time_data = await init() + return time_data + + +def set_data_value(key, value): + global time_data + time_data[key] = value diff --git a/plugins/group_manager/__init__.py b/plugins/group_manager/__init__.py index b294187b..b7d73855 100644 --- a/plugins/group_manager/__init__.py +++ b/plugins/group_manager/__init__.py @@ -5,16 +5,28 @@ 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 +from configs.config import NICKNAME +from utils.manager import group_manager, plugins2settings_manager try: import ujson as json except ModuleNotFoundError: import json -__plugin_name__ = "群权限操作" -__plugin_usage__ = "区分权限功能" +__zx_plugin_name__ = "群权限操作 [Superuser]" +__plugin_usage__ = """ +usage: + 对群权限 | 群白名单 的操作 + 指令: + 修改群权限 [group] [等级] + 添加群白名单 *[group] + 删除群白名单 *[group] + 查看群白名单 +""".strip() +__plugin_des__ = "对群权限 | 群白名单 的操作" +__plugin_cmd__ = ["修改群权限 [group] [等级]", "添加群白名单 *[group]", "删除群白名单 *[group]", "查看群白名单"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" add_group_level = on_command("修改群权限", priority=1, permission=SUPERUSER, block=True) @@ -33,12 +45,16 @@ manager_group_whitelist = on_command( "添加群白名单", aliases={"删除群白名单"}, priority=1, permission=SUPERUSER, block=True ) -show_group_whitelist = on_command('查看群白名单', priority=1, permission=SUPERUSER, block=True) +show_group_whitelist = on_command( + "查看群白名单", 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()) + group_id = 0 + level = 0 if not msg: await add_group_level.finish("用法:修改群权限 [group] [level]") msg = msg.split(" ") @@ -52,19 +68,21 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): 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}" - ) + if level > -1: + 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)) + level = group_manager.get_group_level(event.group_id) tmp = "" - for plugin in plugins2info_dict: - if plugins2info_dict[plugin]["level"] > level: - plugin_name = plugins2info_dict[plugin]["cmd"][0] + data = plugins2settings_manager.get_data() + for module in data: + if data[module]["level"] > level: + plugin_name = data[module]["cmd"][0] if plugin_name == "pixiv": plugin_name = "搜图 p站排行" tmp += f"{plugin_name}\n" @@ -109,6 +127,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): x = group_manager.get_group_white_list() x = [str(g) for g in x] if x: - await show_group_whitelist.send("目前的群白名单:\n" + '\n'.join(x)) + await show_group_whitelist.send("目前的群白名单:\n" + "\n".join(x)) else: - await show_group_whitelist.send('没有任何群在群白名单...') + await show_group_whitelist.send("没有任何群在群白名单...") diff --git a/plugins/group_welcome_msg.py b/plugins/group_welcome_msg.py index 63e8ba88..8831758a 100644 --- a/plugins/group_welcome_msg.py +++ b/plugins/group_welcome_msg.py @@ -12,9 +12,23 @@ try: except ModuleNotFoundError: import json -__plugin_name__ = "查看群欢迎消息" - -__plugin_usage__ = "无" +__zx_plugin_name__ = "查看群欢迎消息" +__plugin_usage__ = """ +usage: + 查看当前的群欢迎消息 + 指令: + 查看群欢迎消息 +""".strip() +__plugin_des__ = "查看群欢迎消息" +__plugin_cmd__ = ["查看群欢迎消息"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["查看群欢迎消息"], +} view_custom_welcome = on_command( "群欢迎消息", aliases={"查看群欢迎消息", "查看当前群欢迎消息"}, permission=GROUP, priority=5, block=True diff --git a/plugins/help/__init__.py b/plugins/help/__init__.py index 487973f5..6fc4deb4 100644 --- a/plugins/help/__init__.py +++ b/plugins/help/__init__.py @@ -1,43 +1,61 @@ from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, PrivateMessageEvent +from nonebot.adapters.cqhttp import ( + Bot, + MessageEvent, +) from nonebot.typing import T_State from nonebot.rule import to_me -from configs.path_config import DATA_PATH +from configs.path_config import IMAGE_PATH from utils.message_builder import image -import os -from .data_source import create_help_img, create_group_help_img, get_plugin_help +from .data_source import create_help_img, get_plugin_help from utils.utils import get_message_text +from pathlib import Path -__plugin_name__ = "帮助" +__zx_plugin_name__ = "帮助" -if not os.path.exists(DATA_PATH + "group_help/"): - os.mkdir(DATA_PATH + "group_help/") -create_help_img() -for file in os.listdir(DATA_PATH + "group_help/"): - os.remove(DATA_PATH + "group_help/" + file) +help_image = Path(IMAGE_PATH) / "help.png" +simple_help_image = Path(IMAGE_PATH) / "simple_help.png" +if help_image.exists(): + help_image.unlink() +if simple_help_image.exists(): + simple_help_image.unlink() -_help = on_command("功能", rule=to_me(), aliases={"help", "帮助"}, priority=1, block=True) +_help = on_command("详细功能", rule=to_me(), aliases={"详细帮助"}, priority=1, block=True) +simple_help = on_command("功能", rule=to_me(), aliases={"help", "帮助"}, priority=1, block=True) @_help.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - msg = get_message_text(event.json()) - if not msg: - if not os.path.exists(DATA_PATH + f"group_help/{event.group_id}.png"): - create_group_help_img(event.group_id) - await _help.finish( - image(abspath=DATA_PATH + f"group_help/{event.group_id}.png") - ) - else: - await _help.finish(get_plugin_help(msg)) +async def _(bot: Bot, event: MessageEvent, state: T_State): + if not help_image.exists(): + if help_image.exists(): + help_image.unlink() + if simple_help_image.exists(): + simple_help_image.unlink() + await create_help_img(help_image, simple_help_image) + await _help.finish(image("help.png")) -@_help.handle() -async def _(bot: Bot, event: PrivateMessageEvent, state: T_State): +@simple_help.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State): msg = get_message_text(event.json()) - if not msg: - await _help.finish(image("help.png")) + is_super = False + if msg: + if '-super' in msg: + if str(event.user_id) in bot.config.superusers: + is_super = True + msg = msg.replace('-super', '') + msg = get_plugin_help(msg, is_super) + if msg: + await _help.send(image(b64=msg)) + else: + await _help.send("没有此功能的帮助信息...") else: - await _help.finish(get_plugin_help(msg)) + if not simple_help_image.exists(): + if help_image.exists(): + help_image.unlink() + if simple_help_image.exists(): + simple_help_image.unlink() + await create_help_img(help_image, simple_help_image) + await _help.finish(image("simple_help.png")) diff --git a/plugins/help/config.py b/plugins/help/config.py deleted file mode 100644 index 08b02c28..00000000 --- a/plugins/help/config.py +++ /dev/null @@ -1,72 +0,0 @@ -from configs.config import NICKNAME - -# 实用 -utility_help = { - "update_pic": "一些对图片的操作 --> 指令:操作图片/图片/修改图片(包含 10 种图片操作)", - "search_buff_skin_price": "BUFF皮肤底价查询 --> 指令:查询皮肤(代理ip不得劲)", - "weather": "天气查询 --> 指令:xx天气", - "yiqing": "实时疫情数据 --> 指令:疫情查询/疫情/查询疫情", - "bt": "bt(磁力搜索){仅支持私聊,懂的都懂} --> 指令:bt", - "reimu": "老司机必备!{仅支持私聊,懂的都懂}-> 指令:上车", - "what_anime": "靠图识番 --> 指令:识番", - "nonebot_plugin_picsearcher": "以图搜图 --> 指令:识图/这是什么/上一张图是什么", - "search_anime": "找不到想看的动漫吗? --> 指令:搜番", - "songpicker2": "来一首歌听听? --> 指令:点歌", - "epic": "epic速速白嫖 --> 指令:epic", - "pixiv_r": "P站排行榜直接冲 --> 指令:p站排行(可含参数)", - "pixiv_s": "P站的图随便搜搜 --> 指令:搜图(可含参数)", - "pid_search": "通过PID搜索图片 --> 指令:p搜 [pid]", - "translate": "出国旅游助手(狗头) --> 指令:英翻/翻英/日翻/翻日/韩翻/翻韩", - "cover": "快捷的b站封面获取方式 --> 指令:b封面 [连接/av/bv/cv/直播id]", -} -# 娱乐 -entertainment_help = { - "sign_in": "签到(影响色图和开箱) --> 指令:签到/我的签到/好感度排行/好感度总榜/好感度总榜[屏蔽我/显示我]", - "send_img": "发送图片 --> 指令:美图/萝莉/壁纸/(美图/萝莉/壁纸[id])/N张图xx(N<=9)", - "send_setu": "不要小看涩图啊混蛋! --> 指令:色图/色图[id]/n张色图/n张xx色图/查色图/...(请查看 色图 帮助)", - "white2black_img": "黑白草图 --> 指令:黑白图/黑白草图", - "coser": "三次元也不戳 --> 指令:coser", - "jitang": "不喝点什么不舒服 --> 指令:鸡汤/语录", - "send_dinggong_voice": "骂我(傲娇?) --> 指令:骂老子", - "poke": "戳一戳发送语音美图萝莉图不美哉?", - "open_cases": "模拟开箱(戒赌) --> 指令:开箱(N连开箱[N<=30])/我的开箱/群开箱统计/我的金色", - "luxun": "鲁迅说过 --> 指令:鲁迅说", - "fake_msg": "构造一个假消息 --> 指令:假消息", - "shop_handle": "商店系统(初始送100金币) --> 指令:商店/我的金币/购买道具/使用道具", - "draw_card_prts": "换个地方当非酋TvT... --> 指令:方舟一井/方舟N抽(0 指令:原神一井/原神N抽(0 指令:赛马娘一井/赛马娘N抽/赛马娘卡一井/赛马娘卡N抽(0 指令:坎公骑冠剑一井/坎公骑冠剑武器一井/坎公骑冠剑N抽/坎公骑冠剑武器N抽(0 指令:pcr一井/pcrN抽(0 指令:碧蓝轻型/重型/特型N抽(0 指令:fgoN抽(0 指令:阴阳师N抽(0 指令:我有一个朋友想问问xxx(内容)", - "nickname": "区区昵称! --> 指令:以后叫我xx(昵称)/我是谁/取消昵称", - "almanac": "这是一张正经的黄历 --> 指令:原神黄历", - "material_remind": "看看原神今天要刷什么 --> 指令:今日素材/今日材料/今天素材/今天材料", - "qiu_qiu_translation": "这家伙到底在说什么? --> 指令:丘丘翻译/丘丘一下/丘丘语翻译", - "query_resource_points": "地图资源速速查看 --> 指令:原神资源查询xx[路径]/原神资源列表/哪里有xx/xx在哪(xx=资源名称)", - "russian": "紧张刺激的俄罗斯轮盘 --> 指令:俄罗斯轮盘帮助", - "gold_redbag": f"运气项目又来啦! --> 指令:塞红包/ 抢红包指令: 开/抢/戳一戳{NICKNAME}/ 退回:退回未抢完的红包", - "poetry": f"突然文艺的{NICKNAME}是否搞错了什么 --> 指令:念诗/来首诗/念首诗", - "comments_163": "生了个人,我很抱歉 --> 指令:到点了/12点了/网易云热评/网易云评论", - "pix_gallery": "偶尔也想看看美图? --> 指令:PIX [关键词/uid/pid:pid] [num]/查看pix图库 [关键词]/显示pix关键词", - 'nbnhhsh': "会说话就多说点! --> 指令:nbnhhsh/能不能好好说话 [文本](空格划分)", - "roll": f"让{NICKNAME}来帮你决定吧! --> 指令:roll/ roll [文本](空格划分)", - "wbtop": f"刚买完瓜,在吃瓜现场 --> 指令:微博热搜/微博热搜 [数字]", - "bilibili_sub": f"非常快捷的订阅播报 --> 指令:添加订阅 [主播/up/番剧] [id/番名/链接] / 删除订阅 [id]/ 查看订阅" -} -# 其他 -other_help = [ - "查看当前的群欢迎消息 --> 指令:群欢迎消息", - "这是一份正经的自我介绍 --> 指令:自我介绍", - "不得看看自己权力多大? --> 指令:我的权限", - "有人记得你是什么时候加入我们的 --> 指令:我的信息", - "让我看看更新了什么 --> 指令:更新信息", - f"{NICKNAME}给我把话收回去! --> 指令:撤回 [id](默认0)", - "群拥有的权限 --> 指令:查看群权限", - "数据统计可视化_1 --> 指令:功能调用统计/日功能调用统计/周功能调用统计/月功能调用统计", - "数据统计可视化_2 --> 指令:周功能调用统计 [功能名称]/月功能调用统计 [功能名称]", - "这里是PIX图库! --> 指令:添加pix关键词 [关键词]/添加pixuid/pid [UID/PID]/我的pix关键词", -] diff --git a/plugins/help/data_source.py b/plugins/help/data_source.py index d13c0cb8..2512f321 100644 --- a/plugins/help/data_source.py +++ b/plugins/help/data_source.py @@ -1,175 +1,289 @@ from utils.image_utils import CreateImg -from configs.path_config import IMAGE_PATH, DATA_PATH +from configs.path_config import IMAGE_PATH +from utils.manager import plugins2settings_manager +from typing import Optional +from services.log import logger from pathlib import Path -from .config import * -from configs.config import ( - INITIAL_OPEN_CASE_COUNT, - INITIAL_SETU_PROBABILITY, - ADMIN_DEFAULT_AUTH, -) -from configs.config import plugins2info_dict, NICKNAME -from utils.static_data import group_manager +from utils.utils import get_matchers +import random +import asyncio import nonebot +import os -width = 1600 +random_bk_path = Path(IMAGE_PATH) / "background" / "help" / "simple_help" + +background = Path(IMAGE_PATH) / "background" / "0.png" -def create_help_img(): - help_img_file = Path(IMAGE_PATH) / 'help.png' - if help_img_file.exists(): - help_img_file.unlink() - h = ( - 100 - + len(utility_help) * 24 - + len(entertainment_help) * 24 - + len(other_help) * 24 - ) + 800 - A = CreateImg(width, h - 200, font_size=24) - e = CreateImg(width, len(entertainment_help) * 26 + 100, font_size=24) - rst = "" - i = 0 - for cmd in entertainment_help: - rst += f"{i + 1}.{entertainment_help[cmd]}\n" - i += 1 - e.text((10, 10), "娱乐功能:") - e.text((40, 40), rst) - u = CreateImg(width, len(utility_help) * 26 + 100, font_size=24, color="black") - rst = "" - i = 0 - for cmd in utility_help: - rst += f"{i + 1}.{utility_help[cmd]}\n" - i += 1 - u.text((10, 10), "实用功能:", fill=(255, 255, 255)) - u.text((40, 40), rst, fill=(255, 255, 255)) - o = CreateImg(width, len(other_help) * 26 + 100, font_size=24) - rst = "" - for i in range(len(other_help)): - rst += f"{i + 1}.{other_help[i]}\n" - i += 1 - o.text((10, 10), "其他功能:") - o.text((40, 40), rst) - A.paste(e, (0, 0)) - A.paste(u, (0, e.h)) - A.paste(o, (0, e.h + u.h)) - A.text( - (10, e.h + u.h + o.h + 50), - f"大部分交互功能可以通过输入‘取消’,‘算了’来取消当前交互\n对{NICKNAME}说 “{NICKNAME}帮助 指令名” 获取对应详细帮助\n" - "可以通过 “滴滴滴- [消息]” 联系管理员(有趣的想法尽管来吧!<还有Bug和建议>)" - "\n[群管理员请看 管理员帮助(群主与管理员自带 5 级权限)]\n\n" - f"\t「如果{NICKNAME}回复了一些不符合人设的话,那是因为每日白嫖的图灵次数已用完,使用的是备用接口【QAQ】」", +async def create_help_img(help_image: Path, simple_help_image: Path): + """ + 生成帮助图片 + :param help_image: 图片路径 + :param simple_help_image: 简易帮助图片路径 + """ + return await asyncio.get_event_loop().run_in_executor( + None, _create_help_img, help_image, simple_help_image ) - A.save(IMAGE_PATH + "help.png") - -def create_group_help_img(group_id: int): - group_id = str(group_id) - h = ( - 100 - + len(utility_help) * 24 - + len(entertainment_help) * 24 - + len(other_help) * 24 - ) + 800 - A = CreateImg(width, h, font_size=24) - u = CreateImg(width, len(utility_help) * 26 + 100, font_size=24, color="black") - o = CreateImg(width, len(other_help) * 26 + 100, font_size=24) - e = CreateImg(width, len(entertainment_help) * 26 + 100, font_size=24) - rst = "" - i = 1 - for cmd in entertainment_help.keys(): - flag, dfg = parse_cmd(cmd, group_id) - if dfg: - cmd = rcmd(dfg) - rst += f"【{flag}】{i}.{entertainment_help[cmd]}\n" - i += 1 - e.text((10, 10), "娱乐功能:") - e.text((40, 40), rst) - - rst = "" - i = 1 - for cmd in utility_help.keys(): - 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)) - u.text((40, 40), rst, fill=(255, 255, 255)) - - rst = "" - for i in range(len(other_help)): - rst += f"{i + 1}.{other_help[i]}\n" - o.text((10, 10), "其他功能:") - o.text((40, 40), rst) - - A.paste(e, (0, 0)) - A.paste(u, (0, e.h)) - A.paste(o, (0, e.h + u.h)) - # A.text((width, 10), f'总开关【{"√" if data["总开关"] else "×"}】') - A.text( - (10, e.h + u.h + o.h + 50), - f"大部分交互功能可以通过输入‘取消’,‘算了’来取消当前交互\n对{NICKNAME}说 “{NICKNAME}帮助 指令名” 获取对应详细帮助\n" - "可以通过 “滴滴滴- [消息]” 联系管理员(有趣的想法尽管来吧!<还有Bug和建议>)" - f"\n[群管理员请看 管理员帮助(群主与管理员自带 {ADMIN_DEFAULT_AUTH} 级权限)]", +def _create_help_img(help_image: Path, simple_help_image: Path): + """ + 生成帮助图片 + :param help_image: 图片路径 + :param simple_help_image: 简易帮助图片路径 + """ + _matchers = get_matchers() + width = 0 + matchers_data = {} + _des_tmp = {} + _plugin_name_tmp = [] + _tmp = [] + tmp_img = CreateImg(0, 0, plain_text="1", font_size=24) + font_height = tmp_img.h + for matcher in _matchers: + plugin_name = None + _plugin = nonebot.plugin.get_plugin(matcher.module) + _module = _plugin.module + try: + plugin_name = _module.__getattribute__("__zx_plugin_name__") + try: + plugin_des = _module.__getattribute__("__plugin_des__") + except AttributeError: + plugin_des = "_" + if ( + "[hidden]" in plugin_name.lower() + or "[admin]" in plugin_name.lower() + or "[superuser]" in plugin_name.lower() + or plugin_name in _plugin_name_tmp + or plugin_name == "帮助" + ): + continue + plugin_type = ("normal",) + text_type = 0 + if plugins2settings_manager.get( + matcher.module + ) and plugins2settings_manager[matcher.module].get("plugin_type"): + plugin_type = tuple( + plugins2settings_manager.get_plugin_data(matcher.module)[ + "plugin_type" + ] + ) + else: + try: + plugin_type = _module.__getattribute__("__plugin_type__") + except AttributeError: + pass + if len(plugin_type) > 1: + try: + text_type = int(plugin_type[1]) + except ValueError as e: + logger.warning(f"生成列向帮助排列失败 {plugin_name}: {type(e)}: {e}") + plugin_type = plugin_type[0] + else: + plugin_type = plugin_type[0] + try: + plugin_cmd = _module.__getattribute__("__plugin_cmd__") + plugin_cmd = [x for x in plugin_cmd if "[_superuser]" not in x] + except AttributeError: + plugin_cmd = [] + if plugin_type not in matchers_data.keys(): + matchers_data[plugin_type] = {} + if plugin_des in _des_tmp.keys(): + try: + matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"] = ( + matchers_data[plugin_type][_des_tmp[plugin_des]]["cmd"] + + plugin_cmd + ) + except KeyError as e: + logger.warning(f"{type(e)}: {e}") + else: + matchers_data[plugin_type][plugin_name] = { + "des": plugin_des, + "cmd": plugin_cmd, + "text_type": text_type, + } + try: + if text_type == 0: + x = tmp_img.getsize( + f'{plugin_name}: {matchers_data[plugin_type][plugin_name]["des"]} ->' + + " / ".join(matchers_data[plugin_type][plugin_name]["cmd"]) + )[0] + width = width if width > x else x + except KeyError: + pass + if plugin_des not in _des_tmp: + _des_tmp[plugin_des] = plugin_name + except AttributeError as e: + if plugin_name not in _plugin_name_tmp: + logger.warning(f"获取功能 {matcher.module}: {plugin_name} 设置失败...e:{e}") + if plugin_name not in _plugin_name_tmp: + _plugin_name_tmp.append(plugin_name) + help_img_list = [] + simple_help_img_list = [] + types = list(matchers_data.keys()) + types.sort() + ix = 0 + for type_ in types: + keys = list(matchers_data[type_].keys()) + keys.sort() + help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n" + simple_help_str = f"{type_ if type_ != 'normal' else '功能'}:\n\n" + for i, k in enumerate(keys): + simple_help_str += f"{i+1}.{k}\n" + if matchers_data[type_][k]["text_type"] == 1: + _x = tmp_img.getsize( + f"{i+1}".rjust(5) + + f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} ' + )[0] + _str = ( + f"{i+1}".rjust(5) + + f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} ' + ) + _str += matchers_data[type_][k]["cmd"][0] + "\n" + for c in matchers_data[type_][k]["cmd"][1:]: + _str += "".rjust(int(_x * 0.125) + 1) + f"{c}\n" + help_str += _str + else: + help_str += ( + f"{i+1}".rjust(5) + + f'.{k}: {matchers_data[type_][k]["des"]} {"->" if matchers_data[type_][k]["cmd"] else ""} ' + + " / ".join(matchers_data[type_][k]["cmd"]) + + "\n" + ) + height = len(help_str.split("\n")) * (font_height + 5) + simple_height = len(simple_help_str.split("\n")) * (font_height + 5) + A = CreateImg( + width + 150, height, font_size=24, color="white" if not ix % 2 else "black" + ) + A.text((10, 10), help_str, (255, 255, 255) if ix % 2 else (0, 0, 0)) + simple_width = 0 + for x in [tmp_img.getsize(x)[0] for x in simple_help_str.split("\n")]: + simple_width = simple_width if simple_width > x else x + bk = CreateImg( + simple_width + 20, simple_height, font_size=24, color="#6495ED" + ) + B = CreateImg( + simple_width + 20, + simple_height, + font_size=24, + color="white" if not ix % 2 else "black", + ) + B.text((10, 10), simple_help_str, (255, 255, 255) if ix % 2 else (0, 0, 0)) + bk.paste(B, center_type="center") + bk.transparent(2) + ix += 1 + help_img_list.append(A) + simple_help_img_list.append(bk) + height = 0 + for img in help_img_list: + height += img.h + A = CreateImg(width + 150, height + 50, font_size=24) + A.text((10, 10), '* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" "功能名: 功能简介 -> 指令\n\n') + current_height = 50 + for img in help_img_list: + A.paste(img, (0, current_height)) + current_height += img.h + A.save(help_image) + height = 0 + width = 0 + for img in simple_help_img_list: + if img.h > height: + height = img.h + width += img.w + 10 + B = CreateImg(width + 100, height + 250, font_size=24) + width, _ = get_max_width_or_paste(simple_help_img_list, B) + bk = None + random_bk = os.listdir(random_bk_path) + if random_bk: + bk = random.choice(random_bk) + x = max(width + 50, height + 250) + B = CreateImg( + x, + x, + font_size=24, + color="#FFEFD5", + background=random_bk_path / bk, ) - A.text( - (10, e.h + u.h + o.h + 250), - f"【注】「色图概率:好感度 + {int(INITIAL_SETU_PROBABILITY*100)}%\n" - f"\t\t每 3 点好感度 + 1次开箱,初始 {INITIAL_OPEN_CASE_COUNT} 次\n" - f"\t\t开启/关闭功能只需输入‘开启/关闭 指令名’(每个功能的第一个指令)」\n" - f"\t\t示例:开启签到\n" - f"\t\t可以通过管理员开关自动发送消息(早晚安等)\n" - f"\t\t^请查看管理员帮助^\n\n" - f"\t「如果{NICKNAME}回复了一些不符合人设的话,那是因为每日白嫖的图灵次数已用完,使用的是备用接口【QAQ】」", - ) - A.save(DATA_PATH + f"group_help/{group_id}.png") + B.filter("GaussianBlur", 10) + _, B = get_max_width_or_paste(simple_help_img_list, B, True) + w = 10 + h = 10 + for msg in ['目前支持的功能列表:', '可以通过 ‘帮助[功能名称]’ 来获取对应功能的使用方法', '或者使用 ‘详细帮助’ 来获取所有功能方法']: + text = CreateImg( + 0, + 0, + plain_text=msg, + font_size=24, + color=(255, 255, 255, 0), + font='yuanshen.ttf' + ) + B.paste(text, (w, h), True) + h += 50 + if msg == '目前支持的功能列表:': + w += 50 + B.save(simple_help_image) -def parse_cmd(cmd, group_id): - flag = "√" - dfg = None - if cmd.find("draw_card") != -1: - lst = cmd.split("_") - cmd = lst[0] + "_" + lst[1] - dfg = lst[-1] - elif cmd == "pixiv_r": - cmd = "pixiv" - dfg = "r" - elif cmd == "pixiv_s": - cmd = "pixiv" - dfg = "s" - if not group_manager.get_plugin_status(cmd, group_id): - flag = "×" - if cmd in ["bt", "reimu", "nickname"]: - flag = "- " - return flag, dfg +def get_max_width_or_paste( + simple_help_img_list: list, B: CreateImg = None, is_paste: bool = False +) -> "int, CreateImg": + """ + 获取最大宽度,或直接贴图 + :param simple_help_img_list: 简单帮助图片列表 + :param B: 背景图 + :param is_paste: 是否直接贴图 + """ + current_width = 50 + current_height = 180 + max_width = simple_help_img_list[0].w + for i in range(len(simple_help_img_list)): + try: + if is_paste and B: + B.paste(simple_help_img_list[i], (current_width, current_height), True) + current_height += simple_help_img_list[i].h + 40 + if current_height + simple_help_img_list[i + 1].h > B.h - 10: + current_height = 180 + current_width += max_width + 30 + max_width = 0 + elif simple_help_img_list[i].w > max_width: + max_width = simple_help_img_list[i].w + except IndexError: + pass + if current_width > simple_help_img_list[0].w + 50: + current_width += simple_help_img_list[-1].w + return current_width, B -def rcmd(dfg): - if dfg in [ - "prts", - "genshin", - "pretty", - "guardian", - "pcr", - "azur", - "onmyoji", - "fgo", - ]: - return "draw_card_" + dfg - if dfg == "r": - return "pixiv_r" - if dfg == "s": - return "pixiv_s" - - -def get_plugin_help(msg: str) -> str: - plugin = None - for p in plugins2info_dict.keys(): - if msg in plugins2info_dict[p]["cmd"]: - plugin = nonebot.plugin.get_plugin(p) - break - if plugin: - result = plugin.module.__getattribute__("__plugin_usage__") - return result - else: - return "没有此功能的帮助信息..." +def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]: + """ + 获取功能的帮助信息 + :param msg: 功能cmd + :param is_super: 是否为超级用户 + """ + module = plugins2settings_manager.get_plugin_module(msg) + if module: + try: + plugin = nonebot.plugin.get_plugin(module) + if plugin: + if is_super: + result = plugin.module.__getattribute__( + "__plugin_superuser_usage__" + ) + else: + result = plugin.module.__getattribute__("__plugin_usage__") + width = 0 + for x in result.split("\n"): + _width = len(x) * 24 + width = width if width > _width else _width + height = len(result.split("\n")) * 45 + A = CreateImg(width, height, font_size=24) + bk = CreateImg( + width, height, background=Path(IMAGE_PATH) / "background" / "1.png" + ) + A.paste(bk, alpha=True) + A.text((int(width * 0.048), int(height * 0.21)), result) + return A.pic2bs4() + except AttributeError: + pass + return None diff --git a/plugins/hook.py b/plugins/hook.py index 56e47b39..ac244d6e 100644 --- a/plugins/hook.py +++ b/plugins/hook.py @@ -2,6 +2,12 @@ from nonebot.matcher import Matcher from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException from nonebot.adapters.cqhttp.exception import ActionFailed from models.group_member_info import GroupInfoUser +from utils.manager import ( + plugins2cd_manager, + plugins2block_manager, + plugins2settings_manager, + admin_manager +) from models.friend_user import FriendUser from typing import Optional from nonebot.typing import T_State @@ -16,14 +22,10 @@ from nonebot.adapters.cqhttp import ( ) from configs.config import ( BAN_RESULT, - admin_plugins_auth, MALICIOUS_BAN_TIME, MALICIOUS_CHECK_TIME, MALICIOUS_BAN_COUNT, CHECK_NOTICE_INFO_CD, - plugins2info_dict, - plugins2cd_dict, - plugins2exists_dict, ) from models.ban_user import BanUser from utils.utils import ( @@ -31,13 +33,12 @@ from utils.utils import ( static_flmt, BanCheckLimiter, FreqLimiter, - UserExistLimiter, ) -from utils.static_data import withdraw_message_id_manager +from utils.manager import withdraw_message_manager 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.manager import group_manager import asyncio try: @@ -45,8 +46,6 @@ try: except ModuleNotFoundError: import json -withdraw_message_id_manager["message_id"] = [] - # 检查是否被ban @run_preprocessor @@ -153,18 +152,27 @@ ignore_rst_module = ["ai", "poke"] @run_preprocessor async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): global _exists_msg + module = matcher.module + plugins2info_dict = plugins2settings_manager.get_data() if ( - (not isinstance(event, MessageEvent) and matcher.module != "poke") + (not isinstance(event, MessageEvent) and module != "poke") or await BanUser.is_ban(event.user_id) - or str(event.user_id) in bot.config.superusers + and str(event.user_id) not in bot.config.superusers + ) or ( + str(event.user_id) in bot.config.superusers + and plugins2info_dict.get(module) + and not plugins2info_dict[module]["limit_superuser"] ): return - module = matcher.module - if module in admin_plugins_auth.keys() and matcher.priority not in [1, 9]: + # 黑名单检测 + if isinstance(event, GroupMessageEvent): + if group_manager.get_group_level(event.group_id) < 0: + raise IgnoredException("群黑名单") + if module in admin_manager.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[module] + event.user_id, event.group_id, admin_manager.get_plugin_level(module) ): try: if _flmt.check(event.user_id): @@ -172,19 +180,19 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): await bot.send_group_msg( group_id=event.group_id, message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:" - f"{admin_plugins_auth[module]}", + f"{admin_manager.get_plugin_level(module)}", ) except ActionFailed: pass raise IgnoredException("权限不足") else: if not await LevelUser.check_level( - event.user_id, 0, admin_plugins_auth[module] + event.user_id, 0, admin_manager.get_plugin_level(module) ): try: await bot.send_private_msg( user_id=event.user_id, - message=f"你的权限不足喔,该功能需要的权限等级:{admin_plugins_auth[module]}", + message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(module)}", ) except ActionFailed: pass @@ -198,7 +206,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): _exists_msg[event.group_id] = False # 群权限 if plugins2info_dict[module]["level"] > group_manager.get_group_level( - str(event.group_id) + event.group_id ): try: if _flmt_g.check(event.user_id) and module not in ignore_rst_module: @@ -211,7 +219,7 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): _exists_msg[event.group_id] = True raise IgnoredException("群权限不足") # 插件状态 - if not group_manager.get_plugin_status(module, str(event.group_id)): + if not group_manager.get_plugin_status(module, event.group_id): try: if module not in ignore_rst_module and _flmt_s.check( event.group_id @@ -223,11 +231,10 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): except ActionFailed: pass _exists_msg[event.group_id] = True + print(123123) raise IgnoredException("未开启此功能...") # 管理员禁用 - if not group_manager.get_plugin_status( - f"{module}:super", str(event.group_id) - ): + if not group_manager.get_plugin_status(f"{module}:super", event.group_id): try: if ( _flmt_s.check(event.group_id) @@ -295,18 +302,6 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): raise IgnoredException("此功能正在维护...") -check_flmt = {} -for plugin in plugins2cd_dict.keys(): - if plugins2cd_dict[plugin]["status"]: - check_flmt[plugin] = FreqLimiter(plugins2cd_dict[plugin]["cd"]) - - -check_elmt = {} -for plugin in plugins2exists_dict.keys(): - if plugins2exists_dict[plugin]["status"]: - check_elmt[plugin] = UserExistLimiter() - - # 命令cd 和 命令阻塞 @run_preprocessor async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): @@ -316,56 +311,46 @@ async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): module = matcher.module if isinstance(event, GroupMessageEvent) and _exists_msg.get(event.group_id) is None: _exists_msg[event.group_id] = False - if module in plugins2cd_dict.keys() and module in check_flmt.keys(): + if plugins2cd_manager.check_plugin_cd_status(module): + plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module) + check_type = plugin_cd_data["check_type"] + limit_type = plugin_cd_data["limit_type"] + rst = plugin_cd_data["rst"] if ( - ( - isinstance(event, PrivateMessageEvent) - and plugins2cd_dict[module]["check_type"] == "private" - ) - or ( - isinstance(event, GroupMessageEvent) - and plugins2cd_dict[module]["check_type"] == "group" - ) - or plugins2cd_dict[module]["check_type"] == "all" - ) and plugins2cd_dict[module]["cd"] > 0: + (isinstance(event, PrivateMessageEvent) and check_type == "private") + or (isinstance(event, GroupMessageEvent) and check_type == "group") + or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all" + ): cd_type_ = event.user_id - if plugins2cd_dict[module]["limit_type"] == "group" and isinstance( - event, GroupMessageEvent - ): + if limit_type == "group" and isinstance(event, GroupMessageEvent): cd_type_ = event.group_id - if not check_flmt[module].check(cd_type_): - rst = plugins2cd_dict[module]["rst"] + if not plugins2cd_manager.check(module, cd_type_): if rst: rst = await init_rst(rst, event) await send_msg(rst, bot, event) raise IgnoredException(f"{module} 正在cd中...") else: - check_flmt[module].start_cd(cd_type_) - if module in plugins2exists_dict.keys() and module in check_elmt.keys(): + plugins2cd_manager.start_cd(module, cd_type_) + if plugins2block_manager.check_plugin_block_status(module): + plugin_block_data = plugins2block_manager.get_plugin_block_data(module) + check_type = plugin_block_data["check_type"] + limit_type = plugin_block_data["limit_type"] + rst = plugin_block_data["rst"] if ( - ( - isinstance(event, PrivateMessageEvent) - and plugins2exists_dict[module]["check_type"] == "private" - ) - or ( - isinstance(event, GroupMessageEvent) - and plugins2exists_dict[module]["check_type"] == "group" - ) - or plugins2exists_dict[module]["check_type"] == "all" + (isinstance(event, PrivateMessageEvent) and check_type == "private") + or (isinstance(event, GroupMessageEvent) and check_type == "group") + or check_type == "all" ): - exists_type_ = event.user_id - if plugins2exists_dict[module]["limit_type"] == "group" and isinstance( - event, GroupMessageEvent - ): - exists_type_ = event.group_id - if check_elmt[module].check(exists_type_): - rst = plugins2exists_dict[module]["rst"] + block_type_ = event.user_id + if limit_type == "group" and isinstance(event, GroupMessageEvent): + block_type_ = event.group_id + if plugins2block_manager.check(block_type_, module): if rst: rst = await init_rst(rst, event) await send_msg(rst, bot, event) raise IgnoredException(f"{event.user_id}正在调用{module}....") else: - check_elmt[module].set_true(exists_type_) + plugins2block_manager.set_true(block_type_, module) async def send_msg(rst: str, bot: Bot, event: MessageEvent): @@ -399,23 +384,18 @@ async def _( if not isinstance(event, MessageEvent) and matcher.module != "poke": return module = matcher.module - if module in plugins2exists_dict.keys() and module in check_elmt.keys(): + if plugins2block_manager.check_plugin_block_status(module): + plugin_block_data = plugins2block_manager.get_plugin_block_data(module) + check_type = plugin_block_data["check_type"] + limit_type = plugin_block_data["limit_type"] if not ( - ( - isinstance(event, GroupMessageEvent) - and plugins2exists_dict[module]["check_type"] == "private" - ) - or ( - isinstance(event, PrivateMessageEvent) - and plugins2exists_dict[module]["check_type"] == "group" - ) + (isinstance(event, GroupMessageEvent) and check_type == "private") + or (isinstance(event, PrivateMessageEvent) and check_type == "group") ): - exists_type_ = event.user_id - if plugins2exists_dict[module]["limit_type"] == "group" and isinstance( - event, GroupMessageEvent - ): - exists_type_ = event.group_id - check_elmt[module].set_false(exists_type_) + block_type_ = event.user_id + if limit_type == "group" and isinstance(event, GroupMessageEvent): + block_type_ = event.group_id + plugins2block_manager.set_false(block_type_, module) async def init_rst(rst: str, event: MessageEvent): @@ -445,9 +425,9 @@ async def _( state: T_State, ): tasks = [] - for id_, time in withdraw_message_id_manager["message_id"]: + for id_, time in withdraw_message_manager.data: tasks.append(asyncio.ensure_future(_withdraw_message(bot, id_, time))) - withdraw_message_id_manager["message_id"].remove((id_, time)) + withdraw_message_manager.remove((id_, time)) await asyncio.gather(*tasks) diff --git a/plugins/image_management/__init__.py b/plugins/image_management/__init__.py new file mode 100644 index 00000000..60531929 --- /dev/null +++ b/plugins/image_management/__init__.py @@ -0,0 +1,3 @@ +import nonebot + +nonebot.load_plugins("plugins/image_management") diff --git a/plugins/delete_img/__init__.py b/plugins/image_management/delete_img/__init__.py similarity index 75% rename from plugins/delete_img/__init__.py rename to plugins/image_management/delete_img/__init__.py index e741bfba..e3e85ff9 100644 --- a/plugins/delete_img/__init__.py +++ b/plugins/image_management/delete_img/__init__.py @@ -1,86 +1,97 @@ -from configs.path_config import IMAGE_PATH, TEMP_PATH -from utils.message_builder import image -from services.log import logger -from nonebot import on_command -from nonebot.rule import to_me -from nonebot.typing import T_State -from nonebot.adapters.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__ = "删除图片" -__plugin_usage__ = ( - "删除图片帮助:\n\t" - "1.查看列表 --> 指令: 删除图片 列表/目录\n\t" - "2.删除图片 图库 id, 即在相应目录下删除图片\n\t\t示例: 删除图片 色图 1 " -) - - -delete_img = on_command("删除图片", priority=5, rule=to_me(), block=True) - - -@delete_img.args_parser -async def parse(bot: Bot, event: MessageEvent, state: T_State): - if str(event.get_message()) in ["取消", "算了"]: - await delete_img.finish("已取消操作..", at_sender=True) - if state["_current_key"] in ["path"]: - if str(event.get_message()) not in IMAGE_DIR_LIST: - await delete_img.reject("此目录不正确,请重新输入目录!") - state[state["_current_key"]] = str(event.get_message()) - if state["_current_key"] == "id": - if not is_number(str(event.get_message())): - await delete_img.reject("id不正确!请重新输入数字...") - state[state["_current_key"]] = str(event.get_message()) - - -@delete_img.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - raw_arg = str(event.get_message()).strip() - if raw_arg: - args = raw_arg.split(" ") - if args[0] in ["帮助"]: - await delete_img.finish(__plugin_usage__) - if len(args) >= 2 and args[0] in IMAGE_DIR_LIST and is_number(args[1]): - state["path"] = args[0] - state["id"] = args[1] - - -@delete_img.got("path", prompt="请输入要删除的目标图库?") -@delete_img.got("id", prompt="请输入要删除的图片id?") -async def arg_handle(bot: Bot, event: MessageEvent, state: T_State): - path = cn2py(state["path"]) - img_id = state["id"] - # 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(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 / 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 / f"{img_id}.jpg"): - try: - if int(img_id) != max_id: - 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} 删除成功" - ) - await delete_img.finish( - f"id: {img_id} 删除成功" + image("delete.jpg", TEMP_PATH), at_sender=True - ) - await delete_img.finish(f"id: {img_id} 删除失败!") +from configs.path_config import IMAGE_PATH, TEMP_PATH +from utils.message_builder import image +from services.log import logger +from nonebot import on_command +from nonebot.rule import to_me +from nonebot.typing import T_State +from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from configs.config import DELETE_IMG_LEVEL +from configs.config import IMAGE_DIR_LIST +from utils.utils import is_number, cn2py, get_message_text +from pathlib import Path +import os + +__zx_plugin_name__ = "删除图片 [Admin]" +__plugin_usage__ = """ +usage: + 删除图库指定图片 + 指令: + 删除图片 [图库] [id] + 查看图库 + 示例:删除图片 美图 666 +""".strip() +__plugin_des__ = "不好看的图片删掉删掉!" +__plugin_cmd__ = ["删除图片 [图库] [id]", "查看公开图库"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "admin_level": DELETE_IMG_LEVEL +} + + +delete_img = on_command("删除图片", priority=5, rule=to_me(), block=True) + + +@delete_img.args_parser +async def parse(bot: Bot, event: MessageEvent, state: T_State): + if get_message_text(event.json()) in ["取消", "算了"]: + await delete_img.finish("已取消操作..", at_sender=True) + if state["_current_key"] in ["path"]: + if get_message_text(event.json()) not in IMAGE_DIR_LIST: + await delete_img.reject("此目录不正确,请重新输入目录!") + state[state["_current_key"]] = get_message_text(event.json()) + if state["_current_key"] == "id": + if not is_number(get_message_text(event.json())): + await delete_img.reject("id不正确!请重新输入数字...") + state[state["_current_key"]] = get_message_text(event.json()) + + +@delete_img.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State): + raw_arg = get_message_text(event.json()).strip() + if raw_arg: + args = raw_arg.split(" ") + if args[0] in ["帮助"]: + await delete_img.finish(__plugin_usage__) + if len(args) >= 2 and args[0] in IMAGE_DIR_LIST and is_number(args[1]): + state["path"] = args[0] + state["id"] = args[1] + + +@delete_img.got("path", prompt="请输入要删除的目标图库?") +@delete_img.got("id", prompt="请输入要删除的图片id?") +async def arg_handle(bot: Bot, event: MessageEvent, state: T_State): + path = cn2py(state["path"]) + img_id = state["id"] + # 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(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 / 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 / f"{img_id}.jpg"): + try: + if int(img_id) != max_id: + 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} 删除成功" + ) + await delete_img.finish( + f"id: {img_id} 删除成功" + image("delete.jpg", TEMP_PATH), at_sender=True + ) + await delete_img.finish(f"id: {img_id} 删除失败!") diff --git a/plugins/move_img/__init__.py b/plugins/image_management/move_img/__init__.py similarity index 86% rename from plugins/move_img/__init__.py rename to plugins/image_management/move_img/__init__.py index 65fb7b5f..f541e883 100644 --- a/plugins/move_img/__init__.py +++ b/plugins/image_management/move_img/__init__.py @@ -1,95 +1,105 @@ -import os -from services.log import logger -from nonebot import on_command -from nonebot.rule import to_me -from nonebot.typing import T_State -from nonebot.adapters.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__ = "移动图片" -__plugin_usage__ = ( - "移动图片帮助:\n\t" - "1.查看列表 --> 指令: 移动图片 列表/目录\n\t" - "2.移动图片 源 目的 id\n\t\t示例: 移动图片 色图 美图 1234" -) - - -move_img = on_command("移动图片", priority=5, rule=to_me(), block=True) - - -@move_img.args_parser -async def parse(bot: Bot, event: MessageEvent, state: T_State): - if str(event.get_message()) in ["取消", "算了"]: - await move_img.finish("已取消操作..", at_sender=True) - if state["_current_key"] in ["source_path", "destination_path"]: - if str(event.get_message()) not in IMAGE_DIR_LIST: - await move_img.reject("此目录不正确,请重新输入目录!") - state[state["_current_key"]] = str(event.get_message()) - if state["_current_key"] == "id": - if not is_number(str(event.get_message())): - await move_img.reject("id不正确!请重新输入数字...") - state[state["_current_key"]] = str(event.get_message()) - - -@move_img.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - raw_arg = str(event.get_message()).strip() - if raw_arg: - args = raw_arg.split(" ") - if args[0] in ["帮助"]: - await move_img.finish(__plugin_usage__) - if ( - len(args) >= 3 - and args[0] in IMAGE_DIR_LIST - and args[1] in IMAGE_DIR_LIST - and is_number(args[2]) - ): - state["source_path"] = args[0] - state["destination_path"] = args[1] - state["id"] = args[2] - else: - await move_img.finish("参数错误,请重试", at_sender=True) - - -@move_img.got("source_path", prompt="要从哪个图库移出?") -@move_img.got("destination_path", prompt="要移动到哪个图库?") -@move_img.got("id", prompt="要移动的图片id是?") -async def _(bot: Bot, event: MessageEvent, state: T_State): - img_id = state["id"] - 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 / f"{img_id}.jpg", destination_path / f"{des_max_id}.jpg" - ) - logger.info( - 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}" - ) - await move_img.finish(f"移动图片id:{img_id} 失败了...", at_sender=True) - if max_id > 0: - try: - 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}" - ) - await move_img.finish(f"替换图片id:{max_id} -> {img_id} 失败了...", at_sender=True) - logger.info( - f"USER {event.user_id} GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'} ->" - f" {source_path} --> {destination_path} (id:{img_id}) 移动图片成功" - ) - await move_img.finish(f"移动图片 id:{img_id} --> id:{des_max_id}成功", at_sender=True) +import os +from services.log import logger +from nonebot import on_command +from nonebot.rule import to_me +from nonebot.typing import T_State +from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent +from configs.config import IMAGE_DIR_LIST, MOVE_IMG_LEVEL +from utils.utils import is_number, cn2py +from configs.path_config import IMAGE_PATH +from pathlib import Path + + +__zx_plugin_name__ = "移动图片 [Admin]" +__plugin_usage__ = """ +usage: + 图库间的图片移动操作 + 指令: + 移动图片 [源图库] [目标图库] [id] + 查看图库 + 示例:移动图片 萝莉 美图 234 +""".strip() +__plugin_des__ = "图库间的图片移动操作" +__plugin_cmd__ = ["移动图片 [源图库] [目标图库] [id]", "查看公开图库"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "admin_level": MOVE_IMG_LEVEL +} + + +move_img = on_command("移动图片", priority=5, rule=to_me(), block=True) + + +@move_img.args_parser +async def parse(bot: Bot, event: MessageEvent, state: T_State): + if str(event.get_message()) in ["取消", "算了"]: + await move_img.finish("已取消操作..", at_sender=True) + if state["_current_key"] in ["source_path", "destination_path"]: + if str(event.get_message()) not in IMAGE_DIR_LIST: + await move_img.reject("此目录不正确,请重新输入目录!") + state[state["_current_key"]] = str(event.get_message()) + if state["_current_key"] == "id": + if not is_number(str(event.get_message())): + await move_img.reject("id不正确!请重新输入数字...") + state[state["_current_key"]] = str(event.get_message()) + + +@move_img.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State): + raw_arg = str(event.get_message()).strip() + if raw_arg: + args = raw_arg.split(" ") + if args[0] in ["帮助"]: + await move_img.finish(__plugin_usage__) + if ( + len(args) >= 3 + and args[0] in IMAGE_DIR_LIST + and args[1] in IMAGE_DIR_LIST + and is_number(args[2]) + ): + state["source_path"] = args[0] + state["destination_path"] = args[1] + state["id"] = args[2] + else: + await move_img.finish("参数错误,请重试", at_sender=True) + + +@move_img.got("source_path", prompt="要从哪个图库移出?") +@move_img.got("destination_path", prompt="要移动到哪个图库?") +@move_img.got("id", prompt="要移动的图片id是?") +async def _(bot: Bot, event: MessageEvent, state: T_State): + img_id = state["id"] + 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 / f"{img_id}.jpg", destination_path / f"{des_max_id}.jpg" + ) + logger.info( + 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}" + ) + await move_img.finish(f"移动图片id:{img_id} 失败了...", at_sender=True) + if max_id > 0: + try: + 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}" + ) + await move_img.finish(f"替换图片id:{max_id} -> {img_id} 失败了...", at_sender=True) + logger.info( + f"USER {event.user_id} GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'} ->" + f" {source_path} --> {destination_path} (id:{img_id}) 移动图片成功" + ) + await move_img.finish(f"移动图片 id:{img_id} --> id:{des_max_id}成功", at_sender=True) diff --git a/plugins/upload_img/__init__.py b/plugins/image_management/upload_img/__init__.py similarity index 59% rename from plugins/upload_img/__init__.py rename to plugins/image_management/upload_img/__init__.py index e507737a..082b0184 100644 --- a/plugins/upload_img/__init__.py +++ b/plugins/image_management/upload_img/__init__.py @@ -1,103 +1,127 @@ -from nonebot import on_command -from nonebot.rule import to_me -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 get_message_imgs, get_message_text -from .data_source import upload_image_to_local - -__plugin_name__ = "上传图片" -__plugin_usage__ = ( - "上传图片帮助:\n\t" - "1.查看列表 --> 指令: 上传图片 列表/目录\n\t" - "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 _(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 msg not in IMAGE_DIR_LIST: - await upload_img.reject("此目录不正确,请重新输入目录!") - state['path'] = msg - if state["_current_key"] in ["imgs"]: - if not get_message_imgs(event.json()): - await upload_img.reject("图呢图呢图呢图呢!GKD!") - state['imgs'] = get_message_imgs(event.json()) - - -@upload_img.handle() -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 raw_arg in IMAGE_DIR_LIST: - state["path"] = raw_arg - if img_list: - state["imgs"] = img_list - - -@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 = 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: - 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)) - +from nonebot import on_command +from nonebot.rule import to_me +from nonebot.typing import T_State +from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent + +from configs.config import IMAGE_DIR_LIST, UPLOAD_IMG_LEVEL +from utils.utils import get_message_imgs, get_message_text +from .data_source import upload_image_to_local + + +__zx_plugin_name__ = "上传图片 [Admin]" +__plugin_usage__ = """ +usage: + 上传图片至指定图库 + 指令: + 查看图库 + 上传图片 [图库] [图片] + 连续上传图片 [图库] + 示例:上传图片 美图 [图片] + * 连续上传图片可以通过发送 “stop” 表示停止收集发送的图片,可以开始上传 * +""".strip() +__plugin_des__ = "指定图库图片上传" +__plugin_cmd__ = ["上传图片 [图库] [图片]", "连续上传图片 [图库]", "查看公开图库"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = {"admin_level": UPLOAD_IMG_LEVEL} + +upload_img = on_command("上传图片", rule=to_me(), priority=5, block=True) + +continuous_upload_img = on_command("连续上传图片", rule=to_me(), priority=5, block=True) + +show_gallery = on_command("查看公开图库", priority=1, block=True) + + +@show_gallery.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State): + x = '公开图库列表:\n' + for i, e in enumerate(IMAGE_DIR_LIST): + x += f'\t{i+1}.{e}\n' + await show_gallery.send(x[:-1]) + + +@upload_img.args_parser +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 msg not in IMAGE_DIR_LIST: + await upload_img.reject("此目录不正确,请重新输入目录!") + state["path"] = msg + if state["_current_key"] in ["imgs"]: + if not get_message_imgs(event.json()): + await upload_img.reject("图呢图呢图呢图呢!GKD!") + state["imgs"] = get_message_imgs(event.json()) + + +@upload_img.handle() +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 raw_arg in IMAGE_DIR_LIST: + state["path"] = raw_arg + if img_list: + state["imgs"] = img_list + + +@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 = 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: + 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/image_management/upload_img/data_source.py similarity index 100% rename from plugins/upload_img/data_source.py rename to plugins/image_management/upload_img/data_source.py diff --git a/plugins/init_config/__init__.py b/plugins/init_config/__init__.py new file mode 100644 index 00000000..926c6f5c --- /dev/null +++ b/plugins/init_config/__init__.py @@ -0,0 +1,36 @@ +from .data_source import ( + init_plugins_settings, + init_plugins_cd_limit, + init_plugins_block_limit, + init_group_manager, +) +from nonebot.adapters.cqhttp import Bot +from configs.path_config import DATA_PATH +from services.log import logger +from nonebot import Driver +import nonebot + + +__zx_plugin_name__ = "初始化插件数据 [Hidden]" +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" + + +driver: Driver = nonebot.get_driver() + + +@driver.on_startup +def _(): + """ + 初始化数据 + """ + init_plugins_settings(DATA_PATH) + init_plugins_cd_limit(DATA_PATH) + init_plugins_block_limit(DATA_PATH) + logger.info("初始化数据完成...") + + +@driver.on_bot_connect +async def _(bot: Bot): + await init_group_manager() + diff --git a/plugins/init_config/data_source.py b/plugins/init_config/data_source.py new file mode 100644 index 00000000..ae90a75d --- /dev/null +++ b/plugins/init_config/data_source.py @@ -0,0 +1,290 @@ +from pathlib import Path +from ruamel.yaml import YAML, round_trip_load, round_trip_dump +from utils.manager import ( + plugins2settings_manager, + plugins2cd_manager, + plugins2block_manager, + group_manager, + admin_manager +) +from services.db_context import db +from asyncpg.exceptions import DuplicateColumnError +from services.log import logger +from utils.utils import get_matchers +import nonebot + +try: + import ujson as json +except ModuleNotFoundError: + import json +try: + from models.group_remind import GroupRemind +except ModuleNotFoundError: + pass + +yaml = YAML(typ="safe") + + +def init_plugins_settings(data_path: str): + """ + 初始化插件设置,从插件中获取 __zx_plugin_name__,__plugin_cmd__,__plugin_settings__ + """ + plugins2config_file = Path(data_path) / "configs" / "plugins2settings.yaml" + plugins2config_file.parent.mkdir(exist_ok=True, parents=True) + _matchers = get_matchers() + _data = {} + if plugins2config_file.exists(): + with open(plugins2config_file, "r", encoding="utf8") as f: + _data = yaml.load(f) + _data = _data["PluginSettings"] if _data else {} + _tmp_module = {} + _tmp = [] + for matcher in _matchers: + if matcher.module in _data.keys(): + plugins2settings_manager.add_plugin_settings( + matcher.module, + plugin_type=_data[matcher.module]["plugin_type"], + data_dict=_data[matcher.module], + ) + if _data[matcher.module]['cmd']: + _tmp_module[matcher.module] = _data[matcher.module]['cmd'][0] + else: + _plugin = nonebot.plugin.get_plugin(matcher.module) + _module = _plugin.module + try: + plugin_name = _module.__getattribute__("__zx_plugin_name__") + if "[admin]" in plugin_name.lower(): + try: + level = (_module.__getattribute__("__plugin_settings__"))['admin_level'] + except (AttributeError, KeyError): + level = 5 + admin_manager.add_admin_command(matcher.module, level) + if ( + "[hidden]" in plugin_name.lower() + or "[admin]" in plugin_name.lower() + or "[superuser]" in plugin_name.lower() + or matcher.module in plugins2settings_manager.keys() + ): + continue + except AttributeError: + if matcher.module not in _tmp: + logger.warning( + f"获取插件 {matcher.module} __zx_plugin_name__ 失败...,插件控制未加载." + ) + else: + try: + _tmp_module[matcher.module] = plugin_name + plugin_settings = _module.__getattribute__("__plugin_settings__") + if plugin_settings['cmd'] and plugin_name not in plugin_settings['cmd']: + plugin_settings['cmd'].append(plugin_name) + if plugins2settings_manager.get( + matcher.module + ) and plugins2settings_manager[matcher.module].get("plugin_type"): + plugin_type = tuple( + plugins2settings_manager.get_plugin_data(matcher.module)[ + "plugin_type" + ] + ) + else: + try: + plugin_type = _module.__getattribute__("__plugin_type__") + except AttributeError: + plugin_type = ("normal",) + if plugin_settings and matcher.module: + plugins2settings_manager.add_plugin_settings( + matcher.module, + plugin_type=plugin_type, + data_dict=plugin_settings, + ) + except AttributeError: + pass + _tmp.append(matcher.module) + _tmp_data = {"PluginSettings": plugins2settings_manager.get_data()} + with open(plugins2config_file, "w", encoding="utf8") as wf: + yaml.dump(_tmp_data, wf) + _data = round_trip_load(open(plugins2config_file, encoding="utf8")) + _data["PluginSettings"].yaml_set_start_comment( + """# 模块与对应命令和对应群权限 +# 用于生成帮助图片 和 开关功能 +# key:模块名称 +# level:需要的群等级 +# default_status:加入群时功能的默认开关状态 +# limit_superuser: 功能状态是否限制超级用户 +# cmd: 关闭[cmd] 都会触发命令 关闭对应功能,cmd列表第一个词为统计的功能名称 +# plugin_type: 帮助类别 示例:('原神相关',) 或 ('原神相关', 1),1代表帮助命令列向排列,否则为横向排列""", + indent=2, + ) + for plugin in _data["PluginSettings"].keys(): + _data["PluginSettings"][plugin].yaml_set_start_comment( + f"{plugin}:{_tmp_module[plugin]}", indent=2 + ) + with open(plugins2config_file, "w", encoding="utf8") as wf: + round_trip_dump(_data, wf) + logger.info(f"已成功加载 {len(plugins2settings_manager.get_data())} 个非限制插件.") + print(admin_manager) + + +def init_plugins_cd_limit(data_path): + """ + 加载 cd 限制 + """ + plugins2cd_file = Path(data_path) / "configs" / "plugins2cd.yaml" + plugins2cd_file.parent.mkdir(exist_ok=True, parents=True) + _data = {} + _matchers = get_matchers() + for matcher in _matchers: + if not plugins2cd_manager.get_plugin_cd_data(matcher.module): + _plugin = nonebot.plugin.get_plugin(matcher.module) + _module = _plugin.module + try: + plugin_cd_limit = _module.__getattribute__("__plugin_cd_limit__") + plugins2cd_manager.add_cd_limit( + matcher.module, data_dict=plugin_cd_limit + ) + except AttributeError: + pass + if plugins2cd_file.exists(): + with open(plugins2cd_file, "r", encoding="utf8") as f: + _data = yaml.load(f) + _data = _data if _data else {} + if _data.get("PluginCdLimit"): + for plugin in _data["PluginCdLimit"].keys(): + plugins2cd_manager.add_cd_limit( + plugin, data_dict=_data["PluginCdLimit"][plugin] + ) + _tmp_data = {"PluginCdLimit": plugins2cd_manager.get_data()} + with open(plugins2cd_file, "w", encoding="utf8") as wf: + yaml.dump(_tmp_data, wf) + _data = round_trip_load(open(plugins2cd_file, encoding="utf8")) + _data["PluginCdLimit"].yaml_set_start_comment( + """# 需要cd的功能 +# 自定义的功能需要cd也可以在此配置 +# key:模块名称 +# cd:cd 时长(秒) +# status:此限制的开关状态 +# check_type:'private'/'group'/'all',限制私聊/群聊/全部 +# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id +# 示例:'user':用户N秒内触发1次,'group':群N秒内触发1次 +# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称 +# rst 为 "" 或 None 时则不回复 +# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]" +# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批" +# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""", + indent=2, + ) + with open(plugins2cd_file, "w", encoding="utf8") as wf: + round_trip_dump(_data, wf) + plugins2cd_manager.reload_cd_limit() + + +def init_plugins_block_limit(data_path): + """ + 加载阻塞限制 + """ + plugins2block_file = Path(data_path) / "configs" / "plugins2block.yaml" + plugins2block_file.parent.mkdir(exist_ok=True, parents=True) + _data = {} + _matchers = get_matchers() + for matcher in _matchers: + if not plugins2block_manager.get_plugin_block_data(matcher.module): + _plugin = nonebot.plugin.get_plugin(matcher.module) + _module = _plugin.module + try: + plugin_block_limit = _module.__getattribute__("__plugin_block_limit__") + plugins2block_manager.add_block_limit( + matcher.module, data_dict=plugin_block_limit + ) + except AttributeError: + pass + if plugins2block_file.exists(): + with open(plugins2block_file, "r", encoding="utf8") as f: + _data = yaml.load(f) + _data = _data if _data else {} + if _data.get("PluginBlockLimit"): + for plugin in _data["PluginBlockLimit"].keys(): + plugins2block_manager.add_block_limit( + plugin, data_dict=_data["PluginBlockLimit"][plugin] + ) + _tmp_data = {"PluginBlockLimit": plugins2block_manager.get_data()} + with open(plugins2block_file, "w", encoding="utf8") as wf: + yaml.dump(_tmp_data, wf) + _data = round_trip_load(open(plugins2block_file, encoding="utf8")) + _data["PluginBlockLimit"].yaml_set_start_comment( + """# 用户调用阻塞 +# 即 当用户调用此功能还未结束时 +# 用发送消息阻止用户重复调用此命令直到该命令结束 +# key:模块名称 +# cd:cd 时长(秒) +# status:此限制的开关状态 +# check_type:'private'/'group'/'all',限制私聊/群聊/全部 +# limit_type:监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id +# 示例:'user':用户N秒内触发1次,'group':群N秒内触发1次 +# rst:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称 +# rst 为 "" 或 None 时则不回复 +# rst示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]" +# rst回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批" +# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""", + indent=2, + ) + with open(plugins2block_file, "w", encoding="utf8") as wf: + round_trip_dump(_data, wf) + plugins2block_manager.reload_block_limit() + + +async def init_group_manager(): + """ + 旧数据格式替换为新格式 + 初始化数据 + """ + 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() + old_data_table = Path() / "models" / "group_remind.py" + try: + if old_data_table.exists(): + b = { + "hy": "group_welcome", + "kxcz": "open_case_reset_remind", + "zwa": "zwa", + "blpar": "bilibili_parse", + "epic": "epic_free_game", + "pa": "pa", + "almanac": "genshin_alc", + } + for group in group_manager.get_data()["group_manager"]: + for remind in b: + try: + status = await GroupRemind.get_status(int(group), remind) + if status is not None: + if status: + await group_manager.open_group_task(group, b[remind]) + logger.info(f"读取旧数据-->{group} 开启 {b[remind]}") + else: + await group_manager.close_group_task(group, b[remind]) + logger.info(f"读取旧数据-->{group} 关闭 {b[remind]}") + except Exception as e: + pass + query = db.text("DROP TABLE group_reminds;") + await db.first(query) + old_data_table.unlink() + logger.info("旧数据读取完毕,删除了舍弃表 group_reminds...") + except (ModuleNotFoundError, DuplicateColumnError): + pass + group_manager.save() diff --git a/plugins/jitang.py b/plugins/jitang.py index 26271453..e631126b 100644 --- a/plugins/jitang.py +++ b/plugins/jitang.py @@ -5,11 +5,25 @@ 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__ = f"用法: 发送’鸡汤‘,{NICKNAME}亲自为你喝鸡汤" +__zx_plugin_name__ = "鸡汤" +__plugin_usage__ = """ +usage: + 不喝点什么感觉有点不舒服 + 指令: + 鸡汤 +""".strip() +__plugin_des__ = "喏,亲手为你煮的鸡汤" +__plugin_cmd__ = ["鸡汤"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["鸡汤", "毒鸡汤"], +} url = "https://v2.alapi.cn/api/soul" diff --git a/plugins/luxun/__init__.py b/plugins/luxun/__init__.py index d3e989dd..d3e58e23 100644 --- a/plugins/luxun/__init__.py +++ b/plugins/luxun/__init__.py @@ -1,28 +1,41 @@ -from PIL import ImageFont, ImageDraw, Image -import textwrap -from configs.path_config import IMAGE_PATH, TTF_PATH +from configs.path_config import IMAGE_PATH from nonebot import on_command from nonebot.typing import T_State from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from utils.message_builder import image from services.log import logger -from utils.utils import UserExistLimiter, get_message_text -from utils.image_utils import pic2b64 - -__plugin_name__ = "鲁迅说" - -__plugin_usage__ = "用法:鲁迅说 [消息]" - -_ulmt = UserExistLimiter() +from utils.utils import get_message_text +from utils.image_utils import CreateImg +__zx_plugin_name__ = "鲁迅说" +__plugin_usage__ = """ +usage: + 鲁迅说了啥? + 指令: + 鲁迅说 [文本] +""".strip() +__plugin_des__ = "鲁迅说他没说过这话!" +__plugin_cmd__ = ["鲁迅说"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["鲁迅说"], +} +__plugin_block_limit__ = { + "rst": "你的鲁迅正在说,等会" +} luxun = on_command("鲁迅说过", aliases={"鲁迅说"}, priority=5, block=True) +luxun_author = CreateImg(0, 0, plain_text="--鲁迅", font_size=30, font='msyh.ttf', font_color=(255, 255, 255)) + + @luxun.handle() async def handle(bot: Bot, event: MessageEvent, state: T_State): - if _ulmt.check(event.user_id): - await luxun.finish("你的鲁迅正在说,等会", at_sender=True) args = get_message_text(event.json()) if args: state["content"] = args if args else "烦了,不说了" @@ -30,39 +43,24 @@ async def handle(bot: Bot, event: MessageEvent, state: T_State): @luxun.got("content", prompt="你让鲁迅说点啥?") async def handle_event(bot: Bot, event: MessageEvent, state: T_State): - filename = str(event.user_id) + "_.jpg" content = state["content"].strip() if content.startswith(",") or content.startswith(","): content = content[1:] - _ulmt.set_true(event.user_id) - if len(content) > 20: - _ulmt.set_false(event.user_id) - await luxun.finish("太长了, 鲁迅说不完!", at_sender=True) - else: - if len(content) >= 12: - content = content[:12] + "\n" + content[12:] - img = image(b64=process_pic(content, filename)) - logger.info( - f"USER {event.user_id} GROUP " - f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'} 鲁迅说过 {content}" - ) - await luxun.send(img) - _ulmt.set_false(event.user_id) - - -def process_pic(content, filename) -> str: - text = content - para = textwrap.wrap(text, width=15) - MAX_W, MAX_H = 480, 280 - bk_img = Image.open(IMAGE_PATH + "other/luxun.jpg") - font_path = TTF_PATH + "/msyh.ttf" - font = ImageFont.truetype(font_path, 37) - font2 = ImageFont.truetype(font_path, 30) - draw = ImageDraw.Draw(bk_img) - current_h, pad = 300, 10 - for line in para: - w, h = draw.textsize(line, font=font) - draw.text(((MAX_W - w) / 2, current_h), line, font=font) - current_h += h + pad - draw.text((320, 400), "——鲁迅", font=font2, fill=(255, 255, 255)) - return pic2b64(bk_img) + A = CreateImg(0, 0, font_size=37, background=f'{IMAGE_PATH}/other/luxun.jpg', font='msyh.ttf') + x = "" + if len(content) > 40: + await luxun.finish('太长了,鲁迅说不完...') + while A.getsize(content)[0] > A.w - 50: + n = int(len(content) / 2) + x += content[:n] + '\n' + content = content[n:] + x += content + if len(x.split('\n')) > 2: + await luxun.finish('太长了,鲁迅说不完...') + A.text((int((480 - A.getsize(x.split("\n")[0])[0]) / 2), 300), x, (255, 255, 255)) + A.paste(luxun_author, (320, 400), True) + await luxun.send(image(b64=A.pic2bs4())) + logger.info( + f"USER {event.user_id} GROUP " + f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'} 鲁迅说过 {content}" + ) diff --git a/plugins/mute.py b/plugins/mute.py index 2ed9f922..9035386d 100644 --- a/plugins/mute.py +++ b/plugins/mute.py @@ -9,27 +9,47 @@ from nonebot.adapters.cqhttp.exception import ActionFailed from configs.path_config import DATA_PATH, IMAGE_PATH from utils.image_utils import get_img_hash from services.log import logger +from configs.config import MUTE_LEVEL import aiohttp import aiofiles -from configs.config import MUTE_DEFAULT_COUNT, MUTE_DEFAULT_TIME, MUTE_DEFAULT_DURATION, NICKNAME +from configs.config import ( + MUTE_DEFAULT_COUNT, + MUTE_DEFAULT_TIME, + MUTE_DEFAULT_DURATION, + NICKNAME, +) try: import ujson as json except ModuleNotFoundError: import json -__plugin_name__ = "刷屏禁言" -__plugin_usage__ = "刷屏禁言检测" +__zx_plugin_name__ = "刷屏禁言 [Admin]" +__plugin_usage__ = f""" +usage: + 刷屏禁言相关操作,需要 {NICKNAME} 有群管理员权限 + 指令: + 设置刷屏检测时间 [秒] + 设置刷屏检测次数 [次数] + 设置刷屏禁言时长 [分钟] + 刷屏检测设置: 查看当前的刷屏检测设置 + * 即 X 秒内发送同样消息 N 次,禁言 M 分钟 * +""".strip() +__plugin_des__ = "刷屏禁言相关操作" +__plugin_cmd__ = ["设置刷屏检测时间 [秒]", "设置刷屏检测次数 [次数]", "设置刷屏禁言时长 [分钟]", "刷屏检测设置"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = {"admin_level": MUTE_LEVEL} mute = on_message(priority=1, block=False) mute_setting = on_command( "mute_setting", - aliases={"设置检测时间", "设置检测次数", "设置禁言时长", "刷屏检测设置"}, + aliases={"设置刷屏检测时间", "设置刷屏检测次数", "设置刷屏禁言时长", "刷屏检测设置"}, permission=GROUP, block=True, - priority=5 + priority=5, ) @@ -51,14 +71,16 @@ def save_data(): async def download_img_and_hash(url, group_id): try: async with aiohttp.ClientSession() as session: - async with session.get(url, proxy=get_local_proxy(), timeout=10) as response: + async with session.get( + url, proxy=get_local_proxy(), timeout=10 + ) as response: async with aiofiles.open( IMAGE_PATH + f"temp/mute_{group_id}_img.jpg", "wb" ) as f: await f.write(await response.read()) return str(get_img_hash(IMAGE_PATH + f"temp/mute_{group_id}_img.jpg")) except TimeoutError: - return '' + return "" mute_dict = {} diff --git a/plugins/my_info.py b/plugins/my_info.py index edca6e2f..e9b2c510 100644 --- a/plugins/my_info.py +++ b/plugins/my_info.py @@ -6,8 +6,19 @@ from models.group_member_info import GroupInfoUser from datetime import timedelta from models.level_user import LevelUser -__plugin_name__ = "更新群组成员列表 [Hidden]" -__plugin_usage__ = "用法:\n" "更新群员的信息" + +__zx_plugin_name__ = "个人信息权限查看" +__plugin_usage__ = """ +usage: + 个人信息权限查看 + 指令: + 我的信息 + 我的权限 +""".strip() +__plugin_des__ = "我们还记得你和你的权利" +__plugin_cmd__ = ["我的信息", "我的权限"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" get_my_group_info = on_command("我的信息", permission=GROUP, priority=1, block=True) diff --git a/plugins/nbnhhsh.py b/plugins/nbnhhsh.py index ada948f5..2d0da4cc 100644 --- a/plugins/nbnhhsh.py +++ b/plugins/nbnhhsh.py @@ -6,9 +6,24 @@ from services.log import logger import ujson as json import aiohttp -__plugin_name__ = "能不能好好说话" -__plugin_usage__ = "用法:\n nbnhhsh [文本]" +__zx_plugin_name__ = "能不能好好说话" +__plugin_usage__ = """ +usage: + 说人话 + 指令: + nbnhhsh [文本] +""".strip() +__plugin_des__ = "能不能好好说话,说人话" +__plugin_cmd__ = ["nbnhhsh [文本]"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["能不能好好说话", "nbnhhsh"], +} HHSH_GUESS_URL = "https://lab.magiconch.com/api/nbnhhsh/guess" @@ -18,6 +33,8 @@ nbnhhsh = on_command("nbnhhsh", aliases={"能不能好好说话"}, priority=5, b @nbnhhsh.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): msg = get_message_text(event.json()) + if not msg: + await nbnhhsh.finish('没话说就别说话!') async with aiohttp.ClientSession( headers={"content-type": "application/json"} ) as session: diff --git a/plugins/nickname.py b/plugins/nickname.py index 97c6ee91..f06018b8 100644 --- a/plugins/nickname.py +++ b/plugins/nickname.py @@ -11,9 +11,18 @@ from services.log import logger from configs.config import NICKNAME -__plugin_name__ = "昵称系统" - -__plugin_usage__ = f"用法:\n以后叫我 [名称]\n{NICKNAME}我是谁" +__zx_plugin_name__ = "昵称系统" +__plugin_usage__ = f""" +usage: + 个人昵称系统,群聊 与 私聊 昵称相互独立 + 指令: + 以后叫我 [昵称] + {NICKNAME}我是谁 +""".strip() +__plugin_des__ = "区区昵称,才不想叫呢!" +__plugin_cmd__ = ["以后叫我 [昵称]", f"{NICKNAME}我是谁"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" nickname = on_command( "nickname", diff --git a/plugins/nonebot_plugin_picsearcher/__init__.py b/plugins/nonebot_plugin_picsearcher/__init__.py index a3baf29c..48659189 100644 --- a/plugins/nonebot_plugin_picsearcher/__init__.py +++ b/plugins/nonebot_plugin_picsearcher/__init__.py @@ -19,16 +19,31 @@ from .trace import get_des as get_des_trace from .yandex import get_des as get_des_yandex -__plugin_name__ = "识图" - -__plugin_usage__ = "用法:识图 [参数](默认nao) [图片]\n" "参数列表:\n" "\t1.nao\n" "\t2.asc" +__zx_plugin_name__ = "识图" +__plugin_usage__ = """ +usage: + 识别图片 [二次元图片] + 指令: + 识图 [图片] +""".strip() +__plugin_des__ = "以图搜图,看破本源" +__plugin_cmd__ = ["识图"] +__plugin_type__ = ("一些工具",) +__plugin_version__ = 0.1 +__plugin_author__ = "synodriver" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["识图"], +} async def get_des(url: str, mode: str, user_id: int): """ :param url: 图片链接 :param mode: 图源 - :return: + :param user_id: 用户 id """ if mode == "iqdb": async for msg in get_des_iqdb(url): @@ -57,8 +72,6 @@ setu = on_command("识图", aliases={"search"}, block=True, priority=5) async def handle_first_receive(bot: Bot, event: MessageEvent, state: T_State): msg = get_message_text(event.json()) imgs = get_message_imgs(event.json()) - if msg in ["帮助"]: - await setu.finish("示例:\n\t识图 (图片)\n\t识图asc (图片)") if imgs: state["setu"] = imgs[0] if msg: @@ -94,13 +107,16 @@ async def get_setu(bot: Bot, event: MessageEvent, state: T_State): await bot.send(event=event, message="正在处理图片") idx = 1 async for msg in get_des(url, mod, event.user_id): - await bot.send(event=event, message=msg) - if idx == MAX_FIND_IMG_COUNT: - break - idx += 1 + if msg: + await bot.send(event=event, message=msg) + if idx == MAX_FIND_IMG_COUNT: + break + idx += 1 + if id == 1: + await bot.send(event=event, message='没找着.') logger.info( f"(USER {event.user_id}, GROUP " - f"{event.group_id if event.message_type != 'private' else 'private'}) 识图:{url}" + f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 识图:{url}" ) # image_data: List[Tuple] = await get_pic_from_url(url) # await setu.finish("hso") diff --git a/plugins/nonebot_plugin_picsearcher/saucenao.py b/plugins/nonebot_plugin_picsearcher/saucenao.py index 58ebbe61..8b60838a 100644 --- a/plugins/nonebot_plugin_picsearcher/saucenao.py +++ b/plugins/nonebot_plugin_picsearcher/saucenao.py @@ -93,12 +93,13 @@ async def get_des(url: str, user_id: int): return for pic in image_data: # print(pic) - msg = await download_img(pic[0], user_id) \ - + f"\n相似度:{pic[1]}" \ - f"\n标题:{pic[2] if (str(pic[2]).strip() != 'Creator:' and len(str(pic[2]).split('-')) < 3) else '未知'}" \ - f"\nPID:{pic[3]}" \ - f"\nmember:{pic[4]}\n" - yield msg + if int(str(pic[1]).split('.')[0]) > 80: + msg = await download_img(pic[0], user_id) \ + + f"\n相似度:{pic[1]}" \ + f"\n标题:{pic[2] if (str(pic[2]).strip() != 'Creator:' and len(str(pic[2]).split('-')) < 3) else '未知'}" \ + f"\nPID:{pic[3]}" \ + f"\nmember:{pic[4]}\n" + yield msg pass diff --git a/plugins/one_friend/__init__.py b/plugins/one_friend/__init__.py index 8f798f55..6e175b87 100644 --- a/plugins/one_friend/__init__.py +++ b/plugins/one_friend/__init__.py @@ -8,10 +8,25 @@ from utils.utils import get_message_text, get_message_at from utils.message_builder import image import re from utils.image_utils import CreateImg +from asyncio.exceptions import TimeoutError -__plugin_name__ = "我有一个朋友" - -__plugin_usage__ = "用法:我有一个朋友说/问 [消息] [at](不艾特则群员随机)" +__zx_plugin_name__ = "我有一个朋友" +__plugin_usage__ = """ +usage: + 我有一个朋友他...,不知道是不是你 + 指令: + 我有一个朋友想问问 [文本] ?[at]: 当at时你的朋友就是艾特对象 +""".strip() +__plugin_des__ = "我有一个朋友想问问..." +__plugin_cmd__ = ["我有一个朋友想问问[文本] ?[at]"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["我有一个朋友想问问", "我有一个朋友"], +} one_friend = on_regex( "^我.*?朋友.*?(想问问|说|让我问问|想问|让我问|想知道|让我帮他问问|让我帮他问|让我帮忙问|让我帮忙问问|问).*", @@ -23,8 +38,13 @@ one_friend = on_regex( async def get_pic(qq): url = f"http://q1.qlogo.cn/g?b=qq&nk={qq}&s=100" async with aiohttp.ClientSession() as session: - async with session.get(url, timeout=5) as response: - return await response.read() + for _ in range(3): + try: + async with session.get(url, timeout=5) as response: + return await response.read() + except TimeoutError: + pass + return None @one_friend.handle() @@ -40,11 +60,11 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): ) ] ) - user_name = '朋友' + 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'] + user_name = at_user["card"] if at_user["card"] else at_user["nickname"] msg = re.search( r"^我.*?朋友.*?(想问问|说|让我问问|想问|让我问|想知道|让我帮他问问|让我帮他问|让我帮忙问|让我帮忙问问|问)(.*)", msg ) @@ -52,7 +72,11 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): if not msg: msg = "都不知道问什么" msg = msg.replace("他", "我").replace("她", "我").replace("它", "我") - ava = CreateImg(100, 100, background=BytesIO(await get_pic(qq))) + x = await get_pic(qq) + if x: + ava = CreateImg(100, 100, background=BytesIO(await get_pic(qq))) + else: + ava = CreateImg(100, 100, color=(0, 0, 0)) ava.circle() text = CreateImg(300, 30, font_size=30) text.text((0, 0), user_name) diff --git a/plugins/open_cases/__init__.py b/plugins/open_cases/__init__.py index f3c1d083..b8ca3407 100644 --- a/plugins/open_cases/__init__.py +++ b/plugins/open_cases/__init__.py @@ -1,4 +1,6 @@ +from typing import Type from nonebot import on_command +from nonebot.matcher import Matcher from utils.utils import scheduler, get_message_text, is_number from nonebot.adapters.cqhttp.permission import GROUP from nonebot.typing import T_State @@ -15,23 +17,57 @@ 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__ = ( - "用法:\n" - "看看你的人品罢了\n" - "目前只支持\n\t" - "1.狂牙大行动武器箱\n\t" - "2.突围大行动武器箱\n\t" - "3.命悬一线武器箱\n\t" - "4.裂空武器箱\n\t" - "5.光谱武器箱\n" - f"示例:{NICKNAME}开箱 突围大行动(不输入指定武器箱则随机)\n" - "示例:我的开箱(开箱统计)\n" - "示例:群开箱统计\n" - "示例:我的金色" -) +__zx_plugin_name__ = "开箱" +__plugin_usage__ = """ +usage: + 看看你的人品罢了 + 模拟开箱,完美公布的真实概率,只想看看替你省了多少钱 + 指令: + 开箱 ?[武器箱] + [1-30]连开箱 ?[武器箱] + 我的开箱 + 我的金色 + 群开箱统计 + * 不包含[武器箱]时随机开箱 * + 目前支持的武器箱: + 1.狂牙大行动武器箱 + 2.突围大行动武器箱 + 3.命悬一线武器箱 + 4.裂空武器箱 + 5.光谱武器箱 + 示例:开箱 命悬一线 +""".strip() +__plugin_superuser_usage__ = """ +usage: + 更新皮肤指令 + 指令: + 更新开箱图片 ?[武器箱] + 更新开箱价格 ?[武器箱] + * 不指定武器箱时则全部更新 * + * 过多的爬取会导致账号API被封 * +""".strip() +__plugin_des__ = "csgo模拟开箱[戒赌]" +__plugin_cmd__ = [ + "开箱 ?[武器箱]", + "[1-30]连开箱 ?[武器箱]", + "我的开箱", + "我的金色", + "群开箱统计", + "更新开箱图片 ?[武器箱] [_superuser]", + "更新开箱价格 ?[武器箱] [_superuser]", +] +__plugin_type__ = ("抽卡相关", 1) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["csgo开箱", "开箱"], +} +__plugin_task__ = {"open_case_reset_remind": "每日开箱重置提醒"} +__plugin_cd_limit__ = {"rst": "着什么急啊,慢慢来!"} cases_name = ["狂牙大行动", "突围大行动", "命悬一线", "裂空", "光谱"] @@ -43,12 +79,8 @@ k_open_case = cases_matcher_group.on_command("开箱") @k_open_case.handle() async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - if str(event.get_message()).strip() in ["帮助"]: - await k_open_case.finish(__plugin_usage__) - # if not _flmt.check(event.user_id): - # await k_open_case.finish("着什么急啊,慢慢来!", at_sender=True) - # _flmt.start_cd(event.user_id) case_name = get_message_text(event.json()) + case_name = case_name.replace("武器箱", "").strip() if case_name: result = await open_case(event.user_id, event.group_id, case_name) else: @@ -89,7 +121,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): ) -open_shilian = cases_matcher_group.on_regex(".*连开箱") +open_shilian: Type[Matcher] = cases_matcher_group.on_regex(".*连开箱") @open_shilian.handle() @@ -108,11 +140,12 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): num = int(num) if num > 30: await open_shilian.finish("开箱次数不要超过30啊笨蛋!", at_sender=True) + if num < 0: + await open_shilian.finish("再负开箱就扣你明天开箱数了!", at_sender=True) else: await open_shilian.finish("必须要是数字切不要超过30啊笨蛋!中文也可!", at_sender=True) case_name = rs.group(2).strip() - if case_name.find("武器箱") != -1: - case_name = case_name.replace("武器箱", "").strip() + case_name = case_name.replace("武器箱", "").strip() if not case_name: case_name = random.choice(cases_name) elif case_name not in cases_name: @@ -157,7 +190,7 @@ num_dict = { } -update_price = on_command("更新价格", priority=1, permission=SUPERUSER, block=True) +update_price = on_command("更新开箱价格", priority=1, permission=SUPERUSER, block=True) @update_price.handle() @@ -165,7 +198,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): await update_price.send(await util_get_buff_price(str(event.get_message()))) -update_img = on_command("更新图片", priority=1, permission=SUPERUSER, block=True) +update_img = on_command("更新开箱图片", priority=1, permission=SUPERUSER, block=True) @update_img.handle() diff --git a/plugins/open_cases/utils.py b/plugins/open_cases/utils.py index 148bf6e2..be7db1d6 100644 --- a/plugins/open_cases/utils.py +++ b/plugins/open_cases/utils.py @@ -9,12 +9,12 @@ from models.open_cases_user import OpenCasesUser import os from services.log import logger from utils.utils import get_bot -from models.group_remind import GroupRemind from utils.utils import get_cookie_text from asyncio.exceptions import TimeoutError import pypinyin from nonebot.adapters.cqhttp.exception import ActionFailed from configs.config import BUFF_PROXY +from utils.manager import group_manager url = "https://buff.163.com/api/market/goods" # proxies = 'http://49.75.59.242:3128' @@ -264,10 +264,10 @@ async def update_count_daily(): today_open_total=0, ).apply() bot = get_bot() - gl = await bot.get_group_list(self_id=bot.self_id) + gl = await bot.get_group_list() gl = [g['group_id'] for g in gl] for g in gl: - if await GroupRemind.get_status(g, 'kxcz'): + if await group_manager.check_group_task_status(g, 'open_case_reset_remind'): try: await bot.send_group_msg(group_id=g, message="今日开箱次数重置成功") except ActionFailed: diff --git a/plugins/parse_bilibili_json.py b/plugins/parse_bilibili_json.py index f59ea9c7..34776f38 100644 --- a/plugins/parse_bilibili_json.py +++ b/plugins/parse_bilibili_json.py @@ -7,7 +7,6 @@ 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 @@ -16,8 +15,21 @@ import asyncio import time import aiohttp from bilibili_api import settings +from utils.manager import group_manager import ujson as json + +__zx_plugin_name__ = "B站转发解析" +__plugin_usage__ = """ +usage: + B站转发解析,解析b站分享信息,支持bv,bilibili链接,b站手机端转发卡片,cv,b23.tv,且5分钟内不解析相同url +""".strip() +__plugin_des__ = "B站转发解析" +__plugin_type__ = ("被动相关",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_task__ = {"bilibili_parse": "b站转发解析"} + if get_local_proxy(): settings.proxy = get_local_proxy() @@ -28,7 +40,7 @@ _tmp = {} @parse_bilibili_json.handle() async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - if await GroupRemind.get_status(event.group_id, "blpar"): + if await group_manager.check_group_task_status(event.group_id, "bilibili_parse"): vd_info = None url = None if get_message_json(event.json()): @@ -93,17 +105,17 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): if get_message_text(event.json()): msg = get_message_text(event.json()) if "BV" in msg: - index = msg.find('BV') - if len(msg[index + 2:]) >= 10: - msg = msg[index: index + 12] - url = f'https://www.bilibili.com/video/{msg}' + index = msg.find("BV") + if len(msg[index + 2 :]) >= 10: + msg = msg[index : index + 12] + url = f"https://www.bilibili.com/video/{msg}" vd_info = await video.Video(bvid=msg).get_info() - elif 'av' in msg: - index = msg.find('av') - if len(msg[index + 2:]) >= 9: - msg = msg[index + 2: index + 11] + elif "av" in msg: + index = msg.find("av") + if len(msg[index + 2 :]) >= 9: + msg = msg[index + 2 : index + 11] if is_number(msg): - url = f'https://www.bilibili.com/video/{msg}' + url = f"https://www.bilibili.com/video/{msg}" vd_info = await video.Video(aid=int(msg)).get_info() elif "https://b23.tv" in msg: url = "https://" + msg[msg.find("b23.tv") : msg.find("b23.tv") + 13] @@ -117,7 +129,9 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): bvid = url.split("/")[-1] vd_info = await video.Video(bvid=bvid).get_info() if vd_info: - if (url in _tmp.keys() and time.time() - _tmp[url] > 30) or url not in _tmp.keys(): + if ( + url in _tmp.keys() and time.time() - _tmp[url] > 30 + ) or url not in _tmp.keys(): _tmp[url] = time.time() aid = vd_info["aid"] title = vd_info["title"] diff --git a/plugins/pid_search.py b/plugins/pid_search.py index e73dff0e..85e694fb 100644 --- a/plugins/pid_search.py +++ b/plugins/pid_search.py @@ -1,22 +1,40 @@ +from asyncio.exceptions import TimeoutError + +import aiofiles +import aiohttp from nonebot import on_command from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent from nonebot.typing import T_State -from utils.utils import get_message_text, is_number -from utils.message_builder import image -import aiohttp -from services.log import logger -from asyncio.exceptions import TimeoutError -import asyncio -import aiofiles + from configs.path_config import IMAGE_PATH +from services.log import logger +from utils.message_builder import image +from utils.utils import get_message_text, is_number +from utils.manager import withdraw_message_manager try: import ujson as json except ModuleNotFoundError: import json -__plugin_name__ = "p搜" -__plugin_usage__ = "用法: 通过pid在Pixiv上搜索图片\n格式:p搜 [pid]\n\t示例:p搜 79520120" + +__zx_plugin_name__ = "pid搜索" +__plugin_usage__ = """ +usage: + 通过 pid 搜索图片 + 指令: + p搜 [pid] +""".strip() +__plugin_des__ = "通过 pid 搜索图片" +__plugin_cmd__ = ["p搜 [pid]"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["p搜"], +} pid_search = on_command("p搜", aliases={"pixiv搜", "P搜"}, priority=5, block=True) @@ -90,10 +108,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): f" 查询图片 PID:{pid}" ) if isinstance(event, GroupMessageEvent): - await asyncio.sleep(30) - await bot.delete_msg( - message_id=msg_id["message_id"], self_id=int(bot.self_id) - ) + withdraw_message_manager.append((msg_id, 30)) break else: await pid_search.finish("图片下载失败了....", at_sender=True) @@ -103,6 +118,6 @@ async def download_pic(img_url: str, user_id: int): async with aiohttp.ClientSession() as session: async with session.get(img_url, timeout=2) as res: async with aiofiles.open( - f"{IMAGE_PATH}/temp/pid_search_{user_id}.png", "wb" + f"{IMAGE_PATH}/temp/pid_search_{user_id}.png", "wb" ) as f: await f.write(await res.read()) diff --git a/plugins/pix_gallery/__init__.py b/plugins/pix_gallery/__init__.py index f38ef7ec..7d7f556c 100644 --- a/plugins/pix_gallery/__init__.py +++ b/plugins/pix_gallery/__init__.py @@ -9,8 +9,14 @@ import nonebot import asyncio import os -driver: Driver = nonebot.get_driver() +__zx_plugin_name__ = "更新扩展图库Omega [Hidden]" +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" + +nonebot.load_plugins("plugins/pix_gallery") + +driver: Driver = nonebot.get_driver() illust_url = f"{HIBIAPI}/api/pixiv/illust" @@ -27,11 +33,13 @@ async def _init_omega_pixiv_illusts(): length = len([x for x in lines if "INSERT INTO" in x.upper()]) all_pid = await OmegaPixivIllusts.get_all_pid() index = 0 - logger.info('检测到OmegaPixivIllusts数据库,准备开始更新....') + logger.info("检测到OmegaPixivIllusts数据库,准备开始更新....") for line in lines: if "INSERT INTO" in line.upper(): index += 1 - tasks.append(asyncio.ensure_future(_tasks(line, all_pid, length, index))) + tasks.append( + asyncio.ensure_future(_tasks(line, all_pid, length, index)) + ) await asyncio.gather(*tasks) omega_pixiv_illusts.unlink() @@ -45,12 +53,12 @@ async def _tasks(line: str, all_pid: List[int], length: int, index: int): x = data.split(maxsplit=3) pid = int(x[1][:-1].strip()) if pid in all_pid: - logger.info(f'添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}') + logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}") return uid = int(x[2][:-1].strip()) x = x[3].split(", '") title = x[0].strip()[1:-1] - tmp = x[1].split(', ') + tmp = x[1].split(", ") author = tmp[0].strip()[:-1] nsfw_tag = int(tmp[1]) width = int(tmp[2]) @@ -68,9 +76,10 @@ async def _tasks(line: str, all_pid: List[int], length: int, index: int): nsfw_tag, tags, datetime.min, - datetime.min + datetime.min, ): - logger.info(f"成功添加OmegaPixivIllusts图库数据 pid:{pid} 本次预计存储 {length} 张,已更新第 {index} 张") + logger.info( + f"成功添加OmegaPixivIllusts图库数据 pid:{pid} 本次预计存储 {length} 张,已更新第 {index} 张" + ) else: logger.info(f"添加OmegaPixivIllusts图库数据已存在 ---> pid:{pid}") - diff --git a/plugins/pix_gallery/pix.py b/plugins/pix_gallery/pix.py index 6d995c9f..755ecdb8 100644 --- a/plugins/pix_gallery/pix.py +++ b/plugins/pix_gallery/pix.py @@ -10,7 +10,7 @@ from nonebot.adapters.cqhttp import ( GroupMessageEvent, PrivateMessageEvent, ) -from utils.static_data import withdraw_message_id_manager +from utils.manager import withdraw_message_manager from nonebot.typing import T_State from .data_source import get_image from models.pixiv import Pixiv @@ -18,6 +18,40 @@ from nonebot import on_command import random +__zx_plugin_name__ = "PIX" +__plugin_usage__ = """ +usage: + 查看 pix 好康图库 + 指令: + pix ?*[tags]: 通过 tag 获取相似图片,不含tag时随机抽取 + pix pid[pid]: 查看图库中指定pid图片 +""".strip() +__plugin_superuser_usage__ = """ +usage: + 超级用户额外的 pix 指令 + 指令: + pix -s ?*[tags]: 通过tag获取色图,不含tag时随机 + pix -r ?*[tags]: 通过tag获取r18图,不含tag时随机 +""".strip() +__plugin_des__ = "这里是PIX图库!" +__plugin_cmd__ = [ + "pix ?*[tags]", + "pix pid [pid]", + "pix -s ?*[tags] [_superuser]", + "pix -r ?*[tags] [_superuser]", +] +__plugin_type__ = ("来点好康的",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["pix", "Pix", "PIX", "pIx"], +} +__plugin_block_limit__ = {"rst": "您有PIX图片正在处理,请稍等..."} + + pix = on_command("pix", aliases={"PIX", "Pix"}, priority=5, block=True) @@ -46,16 +80,16 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): ) else: x = keyword.split() - if '-s' in x: - x.remove('-s') + if "-s" in x: + x.remove("-s") nsfw_tag = 1 - elif '-r' in x: - x.remove('-r') + elif "-r" in x: + x.remove("-r") nsfw_tag = 2 else: nsfw_tag = 0 if nsfw_tag != 0 and str(event.user_id) not in bot.config.superusers: - await pix.finish('你不能看这些噢,这些都是是留给管理员看的...') + await pix.finish("你不能看这些噢,这些都是是留给管理员看的...") if len(x) > 1: if is_number(x[-1]): num = int(x[-1]) @@ -128,6 +162,4 @@ def withdraw_message(event: MessageEvent, id_: int): or (WITHDRAW_PIX_TIME[1] == 1 and isinstance(event, GroupMessageEvent)) or WITHDRAW_PIX_TIME[1] == 2 ): - withdraw_message_id_manager["message_id"].append( - (id_, WITHDRAW_PIX_TIME[0]) - ) + withdraw_message_manager.append((id_, WITHDRAW_PIX_TIME[0])) diff --git a/plugins/pix_gallery/pix_add_keyword.py b/plugins/pix_gallery/pix_add_keyword.py index 35f18a65..fd8c16fc 100644 --- a/plugins/pix_gallery/pix_add_keyword.py +++ b/plugins/pix_gallery/pix_add_keyword.py @@ -8,14 +8,19 @@ from models.pixiv_keyword_user import PixivKeywordUser from models.pixiv import Pixiv from nonebot.permission import SUPERUSER -__plugin_name__ = "添加PIX关键词/UID/PID | 添加PIX黑名单" - +__zx_plugin_name__ = "PIX关键词/UID/PID添加管理 [Superuser]" __plugin_usage__ = """ - 关键词:添加搜图的关键词(效果拉胯) - UID:搜集该画师的图片,可指定收藏数 - PID:收录单张图片 - PIX黑名单:可以是当个pid,也可以是pid_p0等 -""" +usage: + PIX关键词/UID/PID添加管理操作 + 指令: + 添加pix关键词 [Tag]: 添加一个pix搜索收录Tag + 添加pixuid [uid]: 添加一个pix搜索收录uid + 添加pixpid [pid]: 添加一个pix收录pid +""".strip() +__plugin_des__ = "PIX关键词/UID/PID添加管理" +__plugin_cmd__ = ["添加pix关键词 [Tag]", "添加pixuid [uid]", "添加pixpid [pid]"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" add_keyword = on_command("添加pix关键词", aliases={"添加pix关键字"}, priority=1, block=True) diff --git a/plugins/pix_gallery/pix_pass_del_keyword.py b/plugins/pix_gallery/pix_pass_del_keyword.py index ecdf1cd1..eed460aa 100644 --- a/plugins/pix_gallery/pix_pass_del_keyword.py +++ b/plugins/pix_gallery/pix_pass_del_keyword.py @@ -11,12 +11,29 @@ from models.pixiv_keyword_user import PixivKeywordUser from models.pixiv import Pixiv -__plugin_name__ = "通过/取消/删除pix关键词 | 删除pix图片" - +__zx_plugin_name__ = "PIX关键词/UID/PID删除管理 [Superuser]" __plugin_usage__ = """ - 通过/取消/删除pix关键词 [关键词/pid/uid] 示例:通过pix关键词萝莉,通过pix关键词uid:123456,通过pix关键词pid:123456 - 删除pix图片 *[pid] 示例:删除pix图片4223442 -""" +usage: + PIX关键词/UID/PID删除管理操作 + 指令: + 通过pix关键词 [关键词/pid/uid] + 取消pix关键词 [关键词/pid/uid] + 删除pix关键词 [关键词/pid/uid] + 删除pix图片 *[pid] + 示例:通过pix关键词萝莉 + 示例:通过pix关键词uid:123456 + 示例:通过pix关键词pid:123456 + 示例:删除pix图片4223442 +""".strip() +__plugin_des__ = "PIX关键词/UID/PID删除管理" +__plugin_cmd__ = [ + "通过pix关键词 [关键词/pid/uid]", + "取消pix关键词 [关键词/pid/uid]", + "删除pix关键词 [关键词/pid/uid]", + "删除pix图片 *[pid]", +] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" pass_keyword = on_command( @@ -31,9 +48,7 @@ del_keyword = on_command( "删除pix关键词", aliases={"删除pix关键字"}, permission=SUPERUSER, priority=1, block=True ) -del_pic = on_command( - "删除pix图片", permission=SUPERUSER, priority=1, block=True -) +del_pic = on_command("删除pix图片", permission=SUPERUSER, priority=1, block=True) @del_keyword.handle() diff --git a/plugins/pix_gallery/pix_show_info.py b/plugins/pix_gallery/pix_show_info.py index 9d9c537d..9463fd2b 100644 --- a/plugins/pix_gallery/pix_show_info.py +++ b/plugins/pix_gallery/pix_show_info.py @@ -7,11 +7,24 @@ from .data_source import gen_keyword_pic, get_keyword_num from models.pixiv_keyword_user import PixivKeywordUser import asyncio -__plugin_name__ = "查看pix图库" +__zx_plugin_name__ = "查看pix图库" __plugin_usage__ = """ - 查看pix图库 [keyword]:当keyword为空时检查所有图片 -""" +usage: + 查看pix图库 + 指令: + 查看pix图库 ?[tags]: 查看指定tag图片数量,为空时查看整个图库 +""".strip() +__plugin_des__ = "让我看看管理员私藏了多少货" +__plugin_cmd__ = ["查看pix图库 ?[tags]"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["查看pix图库"], +} my_keyword = on_command("我的pix关键词", aliases={"我的pix关键字"}, priority=1, block=True) diff --git a/plugins/pix_gallery/pix_update.py b/plugins/pix_gallery/pix_update.py index a4849b64..1dcc5006 100644 --- a/plugins/pix_gallery/pix_update.py +++ b/plugins/pix_gallery/pix_update.py @@ -9,14 +9,20 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent import time -__plugin_name__ = "更新pix关键字 | pix检查更新" - +__zx_plugin_name__ = "pix检查更新 [Superuser]" __plugin_usage__ = """ - 更新pix收录的所有或指定数量的关键词/uid/pid - 更新pix关键词 [keyword/uid/pid] [num]=all 示例:更新pix关键词uid 5 - pix检测更新:检测从未更新过的uid和pid -""" - +usage: + 更新pix收录的所有或指定数量的 关键词/uid/pid + 指令: + 更新pix关键词 *[keyword/uid/pid] [num=max]: 更新仅keyword/uid/pid或全部 + pix检测更新:检测从未更新过的uid和pid + 示例:更新pix关键词keyword + 示例:更新pix关键词uid 10 +""".strip() +__plugin_des__ = "pix图库收录数据检查更新" +__plugin_cmd__ = ["更新pix关键词 *[keyword/uid/pid] [num=max]", "pix检测更新"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" start_update = on_command( "更新pix关键词", aliases={"更新pix关键字"}, permission=SUPERUSER, priority=1, block=True diff --git a/plugins/pixiv/__init__.py b/plugins/pixiv/__init__.py index 556a7c42..af901a2d 100644 --- a/plugins/pixiv/__init__.py +++ b/plugins/pixiv/__init__.py @@ -13,38 +13,55 @@ from typing import Type from nonebot.rule import to_me import time -__plugin_name__ = "P站" +__zx_plugin_name__ = "P站排行/搜图" + +__plugin_usage__ = """ +usage: + P站排行: + 可选参数: + 类型: + 1. 日排行 + 2. 周排行 + 3. 月排行 + 4. 原创排行 + 5. 新人排行 + 6. R18日排行 + 7. R18周排行 + 8. R18受男性欢迎排行 + 9. R18重口排行【慎重!】 + 【使用时选择参数序号即可,R18仅可私聊】 + p站排行 ?[参数] ?[数量] ?[日期] + 示例: + p站排行榜 [无参数默认为日榜] + p站排行榜 1 + p站排行榜 1 5 + p站排行榜 1 5 2018-4-25 + 【注意空格!!】【在线搜索会较慢】 + --------------------------------- + P站搜图: + 搜图 [关键词] ?[数量] ?[页数=1] ?[r18](不屏蔽R-18) + 示例: + 搜图 樱岛麻衣 + 搜图 樱岛麻衣 5 + 搜图 樱岛麻衣 5 r18 + 【默认为 热度排序】 + 【注意空格!!】【在线搜索会较慢】【数量可能不符?可能该页数量不够,也可能被R-18屏蔽】 +""".strip() +__plugin_des__ = "P站排行榜直接冲,P站搜图跟着冲" +__plugin_cmd__ = ["p站排行 ?[参数] ?[数量] ?[日期]", "搜图 [关键词] ?[数量] ?[页数=1] ?[r18](不屏蔽R-18)"] +__plugin_type__ = ("来点好康的",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 9, + "default_status": True, + "limit_superuser": False, + "cmd": ["pixiv", "p站排行", "搜图", "p站搜图", "P站搜图"], +} +__plugin_block_limit__ = { + "rst": "P站排行榜或搜图正在搜索,请不要重复触发命令..." +} -__plugin_usage__ = """P站排行榜帮助: -可选参数: -类型: - 1. 日排行 - 2. 周排行 - 3. 月排行 - 4. 原创排行 - 5. 新人排行 - 6. R18日排行 - 7. R18周排行 - 8. R18受男性欢迎排行 - 9. R18重口排行【慎重!】 -【使用时选择参数序号即可,R18仅可私聊】 -p站排行榜 [参数] [数量](可选) [日期](可选) -示例: - p站排行榜 (无参数默认为日榜) - p站排行榜 1 - p站排行榜 1 5 - p站排行榜 1 5 2018-4-25 -【注意空格!!】【在线搜索会较慢】 ---------------------------------- -'P站搜图帮助: - 搜图 [关键词] [数量](可选) [页数](可选默认1) [r18](不屏蔽R-18,可选) - 示例: - 搜图 樱岛麻衣 - 搜图 樱岛麻衣 5 - 搜图 樱岛麻衣 5 r18 - 【默认为 热度排序】 - 【注意空格!!】【在线搜索会较慢】【数量可能不符?可能该页数量不够,也可能被R-18屏蔽】 -""" rank_dict = { "1": "day", @@ -60,7 +77,11 @@ rank_dict = { pixiv_rank = on_command( - "p站排行", aliases={"P站排行榜", "p站排行榜", "P站排行榜", "P站排行"}, priority=5, block=True, rule=to_me() + "p站排行", + aliases={"P站排行榜", "p站排行榜", "P站排行榜", "P站排行"}, + priority=5, + block=True, + rule=to_me(), ) pixiv_keyword = on_command("搜图", priority=5, block=True, rule=to_me()) @@ -108,9 +129,9 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): async def _(bot: Bot, event: MessageEvent, state: T_State): msg = get_message_text(event.json()) if isinstance(event, GroupMessageEvent): - if 'r18' in msg.lower(): + if "r18" in msg.lower(): await pixiv_keyword.finish("(脸红#) 你不会害羞的 八嘎!", at_sender=True) - r18 = 0 if 'r18' in msg else 1 + r18 = 0 if "r18" in msg else 1 msg = msg.replace("r18", "").strip().split() msg = [m.strip() for m in msg if m] keyword = None @@ -148,13 +169,18 @@ def check_date(date): return False -async def send_image(info_list: list, matcher: Type[Matcher], bot: Bot, event: MessageEvent): +async def send_image( + info_list: list, matcher: Type[Matcher], bot: Bot, event: MessageEvent +): if isinstance(event, GroupMessageEvent): - await pixiv_rank.send('开始下载整理数据...') + await pixiv_rank.send("开始下载整理数据...") idx = 0 mes_list = [] for title, author, urls in info_list: - _message = f'title: {title}\nauthor: {author}\n' + await download_pixiv_imgs(urls, event.user_id, idx) + _message = ( + f"title: {title}\nauthor: {author}\n" + + await download_pixiv_imgs(urls, event.user_id, idx) + ) data = { "type": "node", "data": { @@ -169,7 +195,10 @@ async def send_image(info_list: list, matcher: Type[Matcher], bot: Bot, event: M else: for title, author, urls in info_list: try: - await matcher.send(f'title: {title}\n' - f'author: {author}\n' + await download_pixiv_imgs(urls, event.user_id)) + await matcher.send( + f"title: {title}\n" + f"author: {author}\n" + + await download_pixiv_imgs(urls, event.user_id) + ) except (NetworkError, TimeoutError, ClientConnectorError): await matcher.send("这张图网络直接炸掉了!", at_sender=True) diff --git a/plugins/pixiv/data_source.py b/plugins/pixiv/data_source.py index ab295199..3909e544 100644 --- a/plugins/pixiv/data_source.py +++ b/plugins/pixiv/data_source.py @@ -84,6 +84,7 @@ async def download_pixiv_imgs( result = "" index = 0 for url in urls: + url = url.replace('_webp', '') async with aiohttp.ClientSession(headers=headers) as session: for _ in range(3): try: diff --git a/plugins/poke/__init__.py b/plugins/poke/__init__.py index d4ea7f70..393981eb 100644 --- a/plugins/poke/__init__.py +++ b/plugins/poke/__init__.py @@ -9,9 +9,22 @@ import random from utils.utils import CountLimiter from models.ban_user import BanUser -__plugin_name__ = "戳一戳 [Hidden]" +__zx_plugin_name__ = "戳一戳" -__plugin_usage__ = "用法:无" +__plugin_usage__ = """ +usage: + 戳一戳随机掉落语音或美图萝莉图 +""".strip() +__plugin_des__ = "戳一戳发送语音美图萝莉图不美哉?" +__plugin_type__ = ("被动相关",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["戳一戳"], +} poke__reply = [ "lsp你再戳?", diff --git a/plugins/quotations.py b/plugins/quotations.py index 6e4056c9..f3e98b90 100644 --- a/plugins/quotations.py +++ b/plugins/quotations.py @@ -6,8 +6,23 @@ import aiohttp from utils.utils import get_local_proxy -__plugin_name__ = "语录" -__plugin_usage__ = "用法: 二次元语录给你力量" +__zx_plugin_name__ = "一言二次元语录" +__plugin_usage__ = """ +usage: + 一言二次元语录 + 指令: + 语录/二次元 +""".strip() +__plugin_des__ = "二次元语录给你力量" +__plugin_cmd__ = ["语录/二次元"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["语录", "二次元"], +} quotations = on_command("语录", aliases={"二次元", "二次元语录"}, priority=5, block=True) diff --git a/plugins/reimu/__init__.py b/plugins/reimu/__init__.py index dad7b5e9..73b24a49 100644 --- a/plugins/reimu/__init__.py +++ b/plugins/reimu/__init__.py @@ -4,23 +4,35 @@ from .data_source import from_reimu_get_info from services.log import logger 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 utils.utils import is_number, get_message_text, UserBlockLimiter, scheduler from models.count_user import UserCount from configs.config import COUNT_PER_DAY_REIMU, NICKNAME -__plugin_name__ = "上车" -__plugin_usage__ = r""" -* 请各位使用后不要转发 * -* 大部分解压密码是⑨ * -/ 每人每天仅提供 5 次上车机会(只能私聊)更多次数请向管理员申请(用爱发电)限制小色批乱搜 / -/ 并不推荐小色批使用此功能(主要是不够色,目的不够明确) / -上车 [目的地] -上车 5 [目的地] 该目的地第5页停车场 -ps: 请尽量提供具体的目的地名称 +__zx_plugin_name__ = "上车" +__plugin_usage__ = """ +usage: + * 请各位使用后不要转发 * + * 大部分解压密码是⑨ * + / 并不推荐小色批使用此功能[主要是不够色,目的不够明确] / + 指令: + 上车 ?[page] [目的地] + 示例:上车 萝莉 + 示例:上车 5 萝莉: 该目的地第5页停车场 + ps: 请尽量提供具体的目的地名称 """.strip() +__plugin_des__ = "都坐稳了,老司机焊死了车门![仅限私聊]" +__plugin_cmd__ = ["上车 ?[page] [目的地]"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["上车"], +} -_ulmt = UserExistLimiter() +_ulmt = UserBlockLimiter() reimu = on_command("上车", permission=PRIVATE, block=True, priority=1) @@ -63,7 +75,9 @@ 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(f"已经帮你关好车门了,请等待发车(不加{NICKNAME}好友的话是欣赏不到旅途的风景的)", 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/roll.py b/plugins/roll.py index 14968aaa..b8fe723b 100644 --- a/plugins/roll.py +++ b/plugins/roll.py @@ -7,10 +7,26 @@ from configs.config import NICKNAME import random import asyncio -__plugin_name__ = "roll" -__plugin_usage__ = ( - "用法:\n" "\troll -> 随机数字\n" "\troll *[文本] -> 决定事件\n" "示例:roll 吃饭 睡觉 打游戏" -) + +__zx_plugin_name__ = "roll" +__plugin_usage__ = """ +usage: + 随机数字 或 随机选择事件 + 指令: + roll: 随机 0-100 的数字 + roll *[文本]: 随机事件 + 示例:roll 吃饭 睡觉 打游戏 +""".strip() +__plugin_des__ = "犹豫不决吗?那就让我帮你决定吧" +__plugin_cmd__ = ["roll", "roll *[文本]"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["roll"], +} roll = on_command("roll", priority=5, block=True) diff --git a/plugins/russian/__init__.py b/plugins/russian/__init__.py index d4ba9bed..791a7372 100644 --- a/plugins/russian/__init__.py +++ b/plugins/russian/__init__.py @@ -13,22 +13,44 @@ import time from .data_source import rank from configs.config import MAX_RUSSIAN_BET_GOLD, NICKNAME -__plugin_name__ = "俄罗斯轮盘" - -__plugin_usage__ = """俄罗斯轮盘帮助: - 开启游戏:装弹 [子弹数] [金额](默认200金币) [at](指定决斗对象,为空则所有群友都可接受决斗) - 示例:装弹 1 10 - 接受对决:接受对决/拒绝决斗 - 开始对决:开枪(轮流开枪,30秒未开枪另一方可使用‘结算’命令结束对决并胜利) - 结算:结算(当某一方30秒未开枪,可使用该命令强行结束对决并胜利) - 我的战绩:我的战绩 - 排行榜:胜场排行/败场排行/欧洲人排行/慈善家排行 - 【注:同一时间群内只能有一场对决】 -""" +__zx_plugin_name__ = "俄罗斯轮盘" +__plugin_usage__ = """ +usage: + 又到了决斗时刻 + 指令: + 装弹 [子弹数] ?[金额=200] ?[at]: 开启游戏,装填子弹,可选自定义金额,或邀请决斗对象 + 接受对决: 接受当前存在的对决 + 拒绝对决: 拒绝邀请的对决 + 开枪: 开出未知的一枪 + 结算: 强行结束当前比赛 (仅当一方未开枪超过30秒时可使用) + 我的战绩: 对,你的战绩 + 胜场排行/败场排行/欧洲人排行/慈善家排行/最高连胜排行/最高连败排行: 各种排行榜 + 示例:装弹 3 100 @sdd + * 注:同一时间群内只能有一场对决 * +""".strip() +__plugin_des__ = "虽然是运气游戏,但这可是战场啊少年" +__plugin_cmd__ = [ + "装弹 [子弹数] ?[金额=200] ?[at]", + "接受对决", + "拒绝对决", + "开枪", + "结算", + "我的战绩", + "胜场排行/败场排行/欧洲人排行/慈善家排行/最高连胜排行/最高连败排行", +] +__plugin_type__ = ("群内小游戏", 1) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["俄罗斯轮盘", "装弹"], +} rs_player = {} -rssian = on_command( +russian = on_command( "俄罗斯轮盘", aliases={"装弹", "俄罗斯转盘"}, permission=GROUP, priority=5, block=True ) @@ -48,7 +70,7 @@ settlement = on_command("结算", permission=GROUP, priority=5, block=True) record = on_command("我的战绩", permission=GROUP, priority=5, block=True) -rssian_rank = on_command( +russian_rank = on_command( "胜场排行", aliases={"胜利排行", "败场排行", "失败排行", "欧洲人排行", "慈善家排行", "最高连胜排行", "最高连败排行"}, permission=GROUP, @@ -160,36 +182,36 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): await end_game(bot, event) -@rssian.args_parser +@russian.args_parser async def _(bot: Bot, event: GroupMessageEvent, state: T_State): msg = get_message_text(event.json()) if msg in ["取消", "算了"]: - await rssian.finish("已取消操作...") + await russian.finish("已取消操作...") try: if rs_player[event.group_id][1] != 0: - await rssian.finish("决斗已开始...", at_sender=True) + await russian.finish("决斗已开始...", at_sender=True) except KeyError: pass if not is_number(msg): - await rssian.reject("输入子弹数量必须是数字啊喂!") + await russian.reject("输入子弹数量必须是数字啊喂!") if int(msg) < 1 or int(msg) > 6: - await rssian.reject("子弹数量必须大于0小于7!") + await russian.reject("子弹数量必须大于0小于7!") state["bullet_num"] = int(msg) -@rssian.handle() +@russian.handle() async def _(bot: Bot, event: GroupMessageEvent, state: T_State): global rs_player msg = get_message_text(event.json()) if msg == "帮助": - await rssian.finish(__plugin_usage__) + await russian.finish(__plugin_usage__) try: if ( rs_player[event.group_id][1] and not rs_player[event.group_id][2] and time.time() - rs_player[event.group_id]["time"] <= 30 ): - await rssian.finish( + await russian.finish( f'现在是 {rs_player[event.group_id]["player1"]} 发起的对决\n请等待比赛结束后再开始下一轮...' ) if ( @@ -197,7 +219,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): and rs_player[event.group_id][2] and time.time() - rs_player[event.group_id]["time"] <= 30 ): - await rssian.finish( + await russian.finish( f'{rs_player[event.group_id]["player1"]} 和' f' {rs_player[event.group_id]["player2"]}的对决还未结束!' ) @@ -232,11 +254,11 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): state["money"] = int(money) else: state["money"] = 200 - await rssian.send(f"赌注金额超过限制(MAX_RUSSIAN_BET_GOLD),已改为200(默认)") + await russian.send(f"赌注金额超过限制({MAX_RUSSIAN_BET_GOLD}),已改为200(默认)") state["at"] = get_message_at(event.json()) -@rssian.got("bullet_num", prompt="请输入装填子弹的数量!(最多6颗)") +@russian.got("bullet_num", prompt="请输入装填子弹的数量!(最多6颗)") async def _(bot: Bot, event: GroupMessageEvent, state: T_State): global rs_player bullet_num = state["bullet_num"] @@ -244,11 +266,11 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): money = state["money"] if state.get("money") else 200 user_money = await BagUser.get_gold(event.user_id, event.group_id) if bullet_num < 0 or bullet_num > 6: - await rssian.reject("子弹数量必须大于0小于7!速速重新装弹!") + await russian.reject("子弹数量必须大于0小于7!速速重新装弹!") if money > MAX_RUSSIAN_BET_GOLD: - await rssian.finish(f"太多了!单次金额不能超过{MAX_RUSSIAN_BET_GOLD}!", at_sender=True) + await russian.finish(f"太多了!单次金额不能超过{MAX_RUSSIAN_BET_GOLD}!", at_sender=True) if money > user_money: - await rssian.finish("你没有足够的钱支撑起这场挑战", at_sender=True) + await russian.finish("你没有足够的钱支撑起这场挑战", at_sender=True) player1_name = event.sender.card if event.sender.card else event.sender.nickname @@ -280,7 +302,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): "time": time.time(), } - await rssian.send( + await russian.send( Message( ("咔 " * bullet_num)[:-1] + f",装填完毕\n挑战金额:{money}\n" f"第一枪的概率为:{str(float(bullet_num) / 7.0 * 100)[:5]}%\n" @@ -447,20 +469,20 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): ) -@rssian_rank.handle() +@russian_rank.handle() async def _(bot: Bot, event: GroupMessageEvent, state: T_State): if state["_prefix"]["raw_command"] in ["胜场排行", "胜利排行"]: - await rssian_rank.finish(await rank(event.group_id, "win_rank")) + await russian_rank.finish(await rank(event.group_id, "win_rank")) if state["_prefix"]["raw_command"] in ["败场排行", "失败排行"]: - await rssian_rank.finish(await rank(event.group_id, "lose_rank")) + await russian_rank.finish(await rank(event.group_id, "lose_rank")) if state["_prefix"]["raw_command"] == "欧洲人排行": - await rssian_rank.finish(await rank(event.group_id, "make_money")) + await russian_rank.finish(await rank(event.group_id, "make_money")) if state["_prefix"]["raw_command"] == "慈善家排行": - await rssian_rank.finish(await rank(event.group_id, "spend_money")) + await russian_rank.finish(await rank(event.group_id, "spend_money")) if state["_prefix"]["raw_command"] == "最高连胜排行": - await rssian_rank.finish(await rank(event.group_id, "max_winning_streak")) + await russian_rank.finish(await rank(event.group_id, "max_winning_streak")) if state["_prefix"]["raw_command"] == "最高连败排行": - await rssian_rank.finish(await rank(event.group_id, "max_losing_streak")) + await russian_rank.finish(await rank(event.group_id, "max_losing_streak")) # 随机子弹排列 diff --git a/plugins/search_anime/__init__.py b/plugins/search_anime/__init__.py index 04aa0f4e..3bc06b46 100644 --- a/plugins/search_anime/__init__.py +++ b/plugins/search_anime/__init__.py @@ -4,17 +4,32 @@ from services.log import logger from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from nonebot.typing import T_State from configs.config import MAXINFO_GROUP_ANIME, MAXINFO_PRIVATE_ANIME -from utils.utils import get_message_text, UserExistLimiter +from utils.utils import get_message_text -__plugin_name__ = "搜番" -__plugin_usage__ = r""" -在群内使用此功能只返还5个结果,私聊返还 20 个结果(绝不能打扰老色批们看色图!) -搜索动漫资源 -搜番 [番剧名称或者关键词] -搜番 Aria +__zx_plugin_name__ = "搜番" +__plugin_usage__ = f""" +usage: + 搜索动漫资源 + 普通的搜番群内使用此功能只返还 {MAXINFO_GROUP_ANIME} 个结果,私聊返还 {MAXINFO_PRIVATE_ANIME} 个结果(绝不能打扰老色批们看色图!) + 指令: + 搜番 [番剧名称或者关键词] + 示例:搜番 刀剑神域 """.strip() -_ulmt = UserExistLimiter() +__plugin_des__ = "找不到想看的动漫吗?" +__plugin_cmd__ = ["搜番 [番剧名称或者关键词]"] +__plugin_type__ = ("一些工具",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["搜番"], +} +__plugin_block_limit__ = { + "rst": "搜索还未完成,不要重复触发!" +} search_anime = on_command("搜番", aliases={"搜动漫"}, priority=5, block=True) @@ -29,9 +44,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @search_anime.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): - if _ulmt.check(event.user_id): - await search_anime.finish("您有动漫正在搜索,请稍等...", at_sender=True) - _ulmt.set_true(event.user_id) if get_message_text(event.json()): state["anime"] = get_message_text(event.json()) @@ -55,4 +67,3 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): else: logger.warning(f"未找到番剧 {key_word}") await search_anime.send(f"未找到番剧 {key_word}(也有可能是超时,再尝试一下?)") - _ulmt.set_false(event.user_id) diff --git a/plugins/search_anime/data_source.py b/plugins/search_anime/data_source.py index d4498ac5..182e4f44 100644 --- a/plugins/search_anime/data_source.py +++ b/plugins/search_anime/data_source.py @@ -1,5 +1,4 @@ from lxml import etree -from lxml import etree import feedparser from urllib import parse from services.log import logger @@ -13,7 +12,6 @@ async def from_anime_get_info(key_word: str, max_: int) -> str: repass = "" url = "https://share.dmhy.org/topics/rss/rss.xml?keyword=" + parse.quote(key_word) try: - logger.debug("Now starting get the {}".format(url)) repass = await get_repass(url, max_) except Exception as e: logger.error("Timeout! {}".format(e)) @@ -28,7 +26,6 @@ async def get_repass(url: str, max_: int) -> str: d = feedparser.parse(await response.text()) url_list = [e.link for e in d.entries][:max_] for u in url_list: - print(u) try: async with session.get( u, proxy=get_local_proxy(), timeout=20 @@ -47,7 +44,6 @@ async def get_repass(url: str, max_: int) -> str: .replace("\t", "") ) size = item[3].xpath("string(.)")[5:].strip() - putline.append( "【{}】| {}\n【{}】| {}".format(class_a, title, size, magent) ) diff --git a/plugins/search_buff_skin_price/__init__.py b/plugins/search_buff_skin_price/__init__.py index aaa2291e..318a824c 100644 --- a/plugins/search_buff_skin_price/__init__.py +++ b/plugins/search_buff_skin_price/__init__.py @@ -5,15 +5,29 @@ from nonebot.typing import T_State 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 utils.utils import get_message_text from configs.config import NICKNAME -__plugin_name__ = "查询皮肤" -__plugin_usage__ = "查询皮肤帮助:\n\t" "查询皮肤 [枪械名] [皮肤]\n\t" "示例: 查询皮肤 awp 二西莫夫" - - -_ulmt = UserExistLimiter() +__zx_plugin_name__ = "BUFF查询皮肤" +__plugin_usage__ = """ +usage: + 在线实时获取BUFF指定皮肤所有磨损底价 + 指令: + 查询皮肤 [枪械名] [皮肤名称] + 示例:查询皮肤 ak47 二西莫夫 +""".strip() +__plugin_des__ = "BUFF皮肤底价查询" +__plugin_cmd__ = ["查询皮肤 [枪械名] [皮肤名称]"] +__plugin_type__ = ("一些工具",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["查询皮肤"], +} search_skin = on_command("查询皮肤", aliases={"皮肤查询"}, priority=5, block=True) @@ -51,7 +65,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(F'请先对{NICKNAME}说"设置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) @@ -74,7 +88,7 @@ async def arg_handle(bot: Bot, event: MessageEvent, state: T_State): update_buff_session = on_command( - "更新cookie", aliases={'设置cookie'}, rule=to_me(), permission=SUPERUSER, priority=1 + "更新cookie", aliases={"设置cookie"}, rule=to_me(), permission=SUPERUSER, priority=1 ) diff --git a/plugins/search_buff_skin_price/data_source.py b/plugins/search_buff_skin_price/data_source.py index 97c1c7b5..6d5032c7 100644 --- a/plugins/search_buff_skin_price/data_source.py +++ b/plugins/search_buff_skin_price/data_source.py @@ -1,7 +1,7 @@ from utils.user_agent import get_user_agent import aiohttp from utils.utils import get_cookie_text -from configs.path_config import TXT_PATH +from configs.path_config import TEXT_PATH from asyncio.exceptions import TimeoutError from configs.config import BUFF_PROXY from pathlib import Path @@ -50,7 +50,7 @@ async def get_price(dname): def update_buff_cookie(cookie: str): - _cookie = Path(TXT_PATH + "cookie/buff.txt") + _cookie = Path(TEXT_PATH + "cookie/buff.txt") try: _cookie.parent.mkdir(parents=True, exist_ok=True) with open(_cookie, "w") as f: diff --git a/plugins/send_dinggong_voice/__init__.py b/plugins/send_dinggong_voice/__init__.py index 3a012b6d..f547ff5f 100644 --- a/plugins/send_dinggong_voice/__init__.py +++ b/plugins/send_dinggong_voice/__init__.py @@ -9,8 +9,23 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from nonebot.rule import to_me import os -__plugin_name__ = "骂我" -__plugin_usage__ = '对我说 "骂我",我真的会骂你哦' +__zx_plugin_name__ = "骂我" +__plugin_usage__ = """ +usage: + 多骂我一点,球球了 + 指令: + 骂老子 +""".strip() +__plugin_des__ = "请狠狠的骂我一次!" +__plugin_cmd__ = ["骂老子/骂我"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["骂老子", "骂我"], +} _flmt = FreqLimiter(3) diff --git a/plugins/send_img/__init__.py b/plugins/send_img/__init__.py index 089aff9e..548b2984 100644 --- a/plugins/send_img/__init__.py +++ b/plugins/send_img/__init__.py @@ -6,30 +6,43 @@ import os import random from services.log import logger from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, MessageEvent, Message, GroupMessageEvent +from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from utils.utils import FreqLimiter, cn2py -from models.group_remind import GroupRemind -from asyncio.exceptions import TimeoutError from configs.config import IMAGE_DIR_LIST -import aiofiles -import aiohttp -import re +from utils.manager import group_manager try: import ujson as json except ModuleNotFoundError: import json -__plugin_name__ = "壁纸/萝莉/美图/在线搜图" -__plugin_usage__ = ( - "用法: \n" '\t1.发送"壁纸/萝莉/美图", 回复图片,后添加id获得指定图片 示例:萝莉 123\n' "\t2.在线搜图 示例:1张米浴的图" -) - -_flmt = FreqLimiter(1) - if "色图" in IMAGE_DIR_LIST: IMAGE_DIR_LIST.remove("色图") +__zx_plugin_name__ = "发送本地图库图片" +__plugin_usage__ = f""" +usage: + 发送指定图库下的随机或指定id图片 + 指令: + {IMAGE_DIR_LIST} ?[id] + 示例:美图 + 示例: 萝莉 2 +""".strip() +__plugin_des__ = "让看看我的私藏,指[图片]" +__plugin_cmd__ = IMAGE_DIR_LIST +__plugin_type__ = ("来点好康的",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["发送图片"] + IMAGE_DIR_LIST, +} +__plugin_task__ = {"pa": "丢人爬"} + +_flmt = FreqLimiter(1) + cmd = set(IMAGE_DIR_LIST) # print(cmd) @@ -61,21 +74,26 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): result = image(f"{index}.jpg", path) if result: logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送{path}:" + f"(USER {event.user_id}, GROUP " + f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送{path}:" + result ) await send_img.finish(f"id:{index}" + result) else: logger.info( - f"(USER {event.user_id}, GROUP {event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送 {path} 失败" + f"(USER {event.user_id}, GROUP " + f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'}) 发送 {path} 失败" ) await send_img.finish(f"不想给你看Ov|") @pa.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): - if isinstance(event, GroupMessageEvent) and not await GroupRemind.get_status( - event.group_id, "pa" + if ( + isinstance(event, GroupMessageEvent) + and not await group_manager.check_group_task_status(event.group_id, "pa") + or get_message_text(event.json()).startswith("开启") + or get_message_text(event.json()).startswith("关闭") ): return msg = get_message_text(event.json()) @@ -88,8 +106,13 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @pa_reg.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): - if isinstance(event, GroupMessageEvent) and not await GroupRemind.get_status( - event.group_id, "pa" + if ( + ( + isinstance(event, GroupMessageEvent) + and not await group_manager.check_group_task_status(event.group_id, "pa") + or get_message_text(event.json()).startswith("开启") + or get_message_text(event.json()).startswith("关闭") + ) ): return if _flmt.check(event.user_id): @@ -110,4 +133,3 @@ num_key = { "八": 8, "九": 9, } - diff --git a/plugins/send_setu/__init__.py b/plugins/send_setu/__init__.py index 3d1b2c09..05bed0c4 100644 --- a/plugins/send_setu/__init__.py +++ b/plugins/send_setu/__init__.py @@ -32,7 +32,7 @@ from .data_source import ( ) from nonebot.adapters.cqhttp.exception import ActionFailed from configs.config import ONLY_USE_LOCAL_SETU, WITHDRAW_SETU_TIME, NICKNAME -from utils.static_data import withdraw_message_id_manager +from utils.manager import withdraw_message_manager import re try: @@ -40,26 +40,38 @@ try: except ModuleNotFoundError: import json -__plugin_name__ = "色图" -__plugin_usage__ = f"""示例: - 1. 色图 (随机本地色图) - 2. 色图r (随机在线十张r18涩图) - 3. 色图 666 (本地色图id) - 4. 色图 xx xx (在线搜索xx xx色图) - 5. 色图r xx (搜索十张xx的r18涩图,注意空格)(仅私聊,每日限制5次) - 6. 来n张涩图 (本地涩图连发)(1<=n<=9) - 7. 来n张xx的涩图 (在线搜索xx涩图)(较慢,看网速) -注: - xx 为 tag,多余20取前20 示例:原神 黑丝 - 本地涩图没有r18! - 联网搜索会较慢! - 如果图片数量与数字不符, - 原因1:网络不好,网线被拔QAQ - 原因2:搜索到的总数小于数字 - 原因3:图太色或者小错误了】 -示例: - 色图 萝莉|少女 白丝|黑丝 - 色图 萝莉 猫娘""" +__zx_plugin_name__ = "色图" +__plugin_usage__ = f""" +usage: + 搜索 lolicon 图库,每日色图time... + 指令: + 色图: 随机本地色图 + 色图r: 随机在线十张r18涩图 + 色图 [id]: 本地指定id色图 + 色图 *[tags]: 在线搜索指定tag色图 + 色图r *[tags]: 同上 + [1-9]张涩图: 本地随机色图连发 + [1-9]张[tags]的涩图: 指定tag色图连发 + 示例:色图 萝莉|少女 白丝|黑丝 + 示例:色图 萝莉 猫娘 + 注: + tag至多取前20项,| 为或,萝莉|少女=萝莉或者少女 +""".strip() +__plugin_des__ = "不要小看涩图啊混蛋!" +__plugin_cmd__ = ["色图 ?[id]", "色图 ?[tags]", "色图r ?[tags]", "[1-9]张?[tags]色图"] +__plugin_type__ = ("来点好康的",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 9, + "default_status": True, + "limit_superuser": False, + "cmd": ["色图", "涩图", "瑟图"], +} +__plugin_block_limit__ = {} +__plugin_cd_limit__ = { + 'rst': '您冲的太快了,请稍后再冲.', +} setu_data_list = [] @@ -181,7 +193,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): num = 1 else: return - await send_setu_handle(setu_reg, event, '色图', tags, num, 0) + await send_setu_handle(setu_reg, event, "色图", tags, num, 0) @find_setu.args_parser @@ -210,7 +222,12 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): async def send_setu_handle( - matcher: Type[Matcher], event: MessageEvent, command: str, msg: str, num: int, r18: int + matcher: Type[Matcher], + event: MessageEvent, + command: str, + msg: str, + num: int, + r18: int, ): global setu_data_list # 非 id,在线搜索 @@ -223,7 +240,9 @@ async def send_setu_handle( msg_id = None if not ONLY_USE_LOCAL_SETU and tags: # 先尝试获取在线图片 - urls, text_list, add_databases_list, code = await get_setu_urls(tags, num, r18, command) + urls, text_list, add_databases_list, code = await get_setu_urls( + tags, num, r18, command + ) for x in add_databases_list: setu_data_list.append(x) # 未找到符合的色图,想来本地应该也没有 @@ -240,7 +259,9 @@ async def send_setu_handle( f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'})" f" 发送色图 {index}.png" ) - msg_id = await matcher.send(Message(f"{text_list[i]}\n{setu_img}")) + msg_id = await matcher.send( + Message(f"{text_list[i]}\n{setu_img}") + ) else: if setu_list is None: setu_list, _ = await get_setu_list(tags=tags, r18=r18) @@ -250,7 +271,9 @@ async def send_setu_handle( msg_id = await matcher.send( Message( gen_message(setu_image) - + (await check_local_exists_or_download(setu_image))[0] + + ( + await check_local_exists_or_download(setu_image) + )[0] ) ) logger.info( @@ -267,7 +290,7 @@ async def send_setu_handle( return # 本地无图 或 超过上下限 if code != 200: - await matcher.finish('网络连接失败...', at_sender=True) + await matcher.finish("网络连接失败...", at_sender=True) if setu_list is None: setu_list, code = await get_setu_list(tags=tags, r18=r18) if code != 200: @@ -303,4 +326,4 @@ def withdraw_message(event: MessageEvent, id_: int): or (WITHDRAW_SETU_TIME[1] == 1 and isinstance(event, GroupMessageEvent)) or WITHDRAW_SETU_TIME[1] == 2 ): - withdraw_message_id_manager['message_id'].append((id_, WITHDRAW_SETU_TIME[0])) + withdraw_message_manager.append((id_, WITHDRAW_SETU_TIME[0])) diff --git a/plugins/send_setu/data_source.py b/plugins/send_setu/data_source.py index 36712e66..2df67611 100644 --- a/plugins/send_setu/data_source.py +++ b/plugins/send_setu/data_source.py @@ -7,7 +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 configs.config import INITIAL_SETU_PROBABILITY, NICKNAME, DOWNLOAD_SETU from models.setu import Setu import aiohttp import aiofiles @@ -80,8 +80,14 @@ headers = { async def search_online_setu( - url_: str, id_: int = None, path_: str = None + url_: str, id_: Optional[int] = None, path_: Optional[str] = None ) -> "MessageSegment, int": + """ + 下载色图 + :param url_: 色图url + :param id_: 本地id + :param path_: 存储路径 + """ if "i.pixiv.cat" in url_: url_ = url_.replace("i.pixiv.cat", "i.pximg.net") async with aiohttp.ClientSession(headers=headers) as session: @@ -122,13 +128,17 @@ async def search_online_setu( # 检测本地是否有id涩图,无的话则下载 async def check_local_exists_or_download(setu_image: Setu) -> "MessageSegment, int": - if setu_image.is_r18: - path_ = "_r18" - else: - path_ = path - if os.path.exists(f"{IMAGE_PATH}/{path_}/{setu_image.local_id}.jpg"): - return image(f"{setu_image.local_id}.jpg", path_), 200 - return await search_online_setu(setu_image.img_url, setu_image.local_id, path_) + path_ = None + id_ = None + if DOWNLOAD_SETU: + id_ = setu_image.local_id + if setu_image.is_r18: + path_ = "_r18" + else: + path_ = path + if os.path.exists(f"{IMAGE_PATH}/{path_}/{setu_image.local_id}.jpg"): + return image(f"{setu_image.local_id}.jpg", path_), 200 + return await search_online_setu(setu_image.img_url, id_, path_) # 添加涩图数据到数据库 diff --git a/plugins/shop/__init__.py b/plugins/shop/__init__.py index e69de29b..e0fbec0a 100644 --- a/plugins/shop/__init__.py +++ b/plugins/shop/__init__.py @@ -0,0 +1,84 @@ +from pathlib import Path +from configs.path_config import DATA_PATH +import nonebot +try: + import ujson as json +except ModuleNotFoundError: + import json + +nonebot.load_plugins("plugins/shop") + +# 修改旧数据 + +statistics_group_file = Path(DATA_PATH) / "statistics" / "_prefix_count.json" +statistics_user_file = Path(DATA_PATH) / "statistics" / "_prefix_user_count.json" + +for file in [statistics_group_file, statistics_user_file]: + if file.exists(): + with open(file, 'r', encoding='utf8') as f: + data = json.load(f) + if not (statistics_group_file.parent / f"{file}.bak").exists(): + with open(f"{file}.bak", 'w', encoding='utf8') as wf: + json.dump(data, wf, ensure_ascii=False, indent=4) + for x in ['total_statistics', 'day_statistics']: + for key in data[x].keys(): + num = 0 + if data[x][key].get('我的道具') is not None: + num += data[x][key]['我的道具'] + del data[x][key]['我的道具'] + if data[x][key].get('使用道具') is not None: + num += data[x][key]['使用道具'] + del data[x][key]['使用道具'] + if data[x][key].get('我的金币') is not None: + num += data[x][key]['我的金币'] + del data[x][key]['我的金币'] + if data[x][key].get('购买') is not None: + num += data[x][key]['购买'] + del data[x][key]['购买'] + if data[x][key].get('商店') is not None: + data[x][key]['商店'] += num + else: + data[x][key]['商店'] = num + for x in ['week_statistics', 'month_statistics']: + for key in data[x].keys(): + if key == 'total': + if data[x][key].get('我的道具') is not None: + num += data[x][key]['我的道具'] + del data[x][key]['我的道具'] + if data[x][key].get('使用道具') is not None: + num += data[x][key]['使用道具'] + del data[x][key]['使用道具'] + if data[x][key].get('我的金币') is not None: + num += data[x][key]['我的金币'] + del data[x][key]['我的金币'] + if data[x][key].get('购买') is not None: + num += data[x][key]['购买'] + del data[x][key]['购买'] + if data[x][key].get('商店') is not None: + data[x][key]['商店'] += num + else: + data[x][key]['商店'] = num + else: + for day in data[x][key].keys(): + num = 0 + if data[x][key][day].get('我的道具') is not None: + num += data[x][key][day]['我的道具'] + del data[x][key][day]['我的道具'] + if data[x][key][day].get('使用道具') is not None: + num += data[x][key][day]['使用道具'] + del data[x][key][day]['使用道具'] + if data[x][key][day].get('我的金币') is not None: + num += data[x][key][day]['我的金币'] + del data[x][key][day]['我的金币'] + if data[x][key][day].get('购买') is not None: + num += data[x][key][day]['购买'] + del data[x][key][day]['购买'] + if data[x][key][day].get('商店') is not None: + data[x][key][day]['商店'] += num + else: + data[x][key][day]['商店'] = num + with open(file, 'w', encoding='utf8') as f: + json.dump(data, f, ensure_ascii=False, indent=4) + + + diff --git a/plugins/shop/buy.py b/plugins/shop/buy.py index 04946866..5968360c 100644 --- a/plugins/shop/buy.py +++ b/plugins/shop/buy.py @@ -9,8 +9,26 @@ from nonebot.adapters.cqhttp.permission import GROUP from models.goods_info import GoodsInfo -__plugin_name__ = "商店购买" -__plugin_usage__ = "格式:购买 [名称或序号] [数量](默认1)\n\t示例:购买 好感双倍加持卡Ⅰ\n\t示例:购买 1 4" +__zx_plugin_name__ = "商店 - 购买道具" +__plugin_usage__ = """ +usage: + 购买道具 + 指令: + 购买 [序号或名称] ?[数量=1] + 示例:购买 好感双倍加持卡Ⅰ + 示例:购买 1 4 +""".strip() +__plugin_des__ = "商店 - 购买道具" +__plugin_cmd__ = ["购买 [序号或名称] ?[数量=1]"] +__plugin_type__ = ('商店',) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["商店", "购买道具"], +} buy = on_command("购买", aliases={"购买道具"}, priority=5, block=True, permission=GROUP) diff --git a/plugins/shop/gold.py b/plugins/shop/gold.py index 2dba4ab0..e139a23c 100644 --- a/plugins/shop/gold.py +++ b/plugins/shop/gold.py @@ -5,6 +5,25 @@ from nonebot.adapters.cqhttp.permission import GROUP from utils.data_utils import init_rank from models.bag_user import BagUser +__zx_plugin_name__ = "商店 - 我的金币" +__plugin_usage__ = """ +usage: + 我的金币 + 指令: + 我的金币 +""".strip() +__plugin_des__ = "商店 - 我的金币" +__plugin_cmd__ = ["我的金币"] +__plugin_type__ = ('商店',) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["商店", "我的金币"], +} + my_gold = on_command("我的金币", priority=5, block=True, permission=GROUP) diff --git a/plugins/shop/gold_redbag/__init__.py b/plugins/shop/gold_redbag/__init__.py index 7f9de5c1..a7be458e 100644 --- a/plugins/shop/gold_redbag/__init__.py +++ b/plugins/shop/gold_redbag/__init__.py @@ -23,21 +23,32 @@ from nonebot.permission import SUPERUSER from nonebot.rule import to_me from datetime import datetime, timedelta from configs.config import NICKNAME -from apscheduler.jobstores.base import ConflictingIdError +from apscheduler.jobstores.base import JobLookupError import random import time -__plugin_name__ = "金币红包" - -__plugin_usage__ = ( - "金币红包帮助:\n" - "\t塞红包 [金币数] [红包个数](默认5)\n" - "示例:\n" - "\t塞红包 500 5\n" - "抢红包 --> 戳一戳,开\n" - "退还剩余红包 --> 退还" -) +__zx_plugin_name__ = "金币红包" +__plugin_usage__ = """ +usage: + 在群内发送指定金额的红包,拼手气项目 + 指令: + 塞红包 [金币数] ?[红包数=5]: 塞入红包 + 开/抢/*戳一戳*: 打开红包 + 退回: 退回未开完的红包,必须在一分钟后使用 + 示例:塞红包 1000 + 示例:塞红包 1000 10 +""".strip() +__plugin_des__ = "运气项目又来了" +__plugin_cmd__ = ["塞红包 [金币数] ?[红包数=5]", "开/抢", "退回"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["金币红包", "塞红包"], +} gold_redbag = on_command( "塞红包", aliases={"金币红包"}, priority=5, block=True, permission=GROUP @@ -112,7 +123,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): except KeyError: pass msg = get_message_text(event.json()) - msg = msg.split(" ") + msg = msg.split() if len(msg) == 1: flag, amount = await check_gold(event.user_id, event.group_id, msg[0]) if not flag: @@ -124,9 +135,13 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): flag, amount = await check_gold(event.user_id, event.group_id, amount) if not flag: await gold_redbag.finish(amount, at_sender=True) - if not is_number(num): + if not is_number(num) or int(num) < 1: await gold_redbag.finish("红包个数给我输正确啊!", at_sender=True) + group_member_num = (await bot.get_group_info(group_id=event.group_id))['member_count'] num = int(num) + if num > group_member_num: + await gold_redbag.send('你发的红包数量也太多了,已经为你修改成与本群人数相同的红包数量...') + num = group_member_num nickname = event.sender.card if event.sender.card else event.sender.nickname flag, result = init_redbag( event.user_id, event.group_id, nickname, amount, num, int(bot.self_id) @@ -160,7 +175,7 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): .replace("。", "") ) if msg: - if msg.find("红包") == -1: + if '红包' not in msg: return flag1 = True flag2 = True @@ -280,6 +295,11 @@ 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: + try: + scheduler.remove_job(f"festive_redbag_{g}") + await end_festive_redbag(bot, g) + except JobLookupError: + pass init_redbag(int(bot.self_id), g, f"{NICKNAME}", amount, num, int(bot.self_id), 1) scheduler.add_job( end_festive_redbag, diff --git a/plugins/shop/my_props.py b/plugins/shop/my_props.py index 138ff7e3..8474463b 100644 --- a/plugins/shop/my_props.py +++ b/plugins/shop/my_props.py @@ -6,7 +6,24 @@ from models.bag_user import BagUser from nonebot.adapters.cqhttp.permission import GROUP -__plugin_name__ = "商店基础显示" +__zx_plugin_name__ = "商店 - 我的道具" +__plugin_usage__ = """ +usage: + 我的道具 + 指令: + 我的道具 +""".strip() +__plugin_des__ = "商店 - 我的道具" +__plugin_cmd__ = ["我的道具"] +__plugin_type__ = ('商店',) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["商店", "我的道具"], +} my_props = on_command("我的道具", priority=5, block=True, permission=GROUP) diff --git a/plugins/shop/reset_today_gold.py b/plugins/shop/reset_today_gold.py index 14e77e1a..bdb896e0 100644 --- a/plugins/shop/reset_today_gold.py +++ b/plugins/shop/reset_today_gold.py @@ -3,6 +3,11 @@ from models.bag_user import BagUser from services.log import logger +__zx_plugin_name__ = "每日金币重置 [Hidden]" +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" + + # 重置每日金币 @scheduler.scheduled_job( "cron", diff --git a/plugins/shop/shop_handle/__init__.py b/plugins/shop/shop_handle/__init__.py index abe73ebd..20150853 100644 --- a/plugins/shop/shop_handle/__init__.py +++ b/plugins/shop/shop_handle/__init__.py @@ -11,7 +11,41 @@ import os import time -__plugin_name__ = "商店" +__zx_plugin_name__ = "商店" +__plugin_usage__ = """ +usage: + 商店项目,这可不是奸商 + 指令: + 商店 +""".strip() +__plugin_superuser_usage__ = """ +usage: + 商品操作 + 指令: + 添加商品 [名称]-[价格]-[描述]-?[折扣](小数)-?[限时时间](分钟) + 删除商品 [名称或序号] + 修改商品 -name [名称或序号] -price [价格] -des [描述] -discount [折扣] -time [限时] + 示例:添加商品-昏睡红茶-300-一杯上好的奇怪红茶-0.9-60 + 示例:删除商品 2 + 示例:修改商品 -name 1 -price 900: 修改序号为1的商品的价格为900 + * 修改商品只需添加需要值即可 * +""".strip() +__plugin_des__ = "商店系统[金币回收计划]" +__plugin_cmd__ = [ + "商店", + "添加商品 [名称]-[价格]-[描述]-?[折扣](小数)-?[限时时间](分钟) [_superuser]", + "删除商品 [名称或序号] [_superuser]", + "修改商品 -name [名称或序号] -price [价格] -des [描述] -discount [折扣] -time [限时] [_superuser]", +] +__plugin_type__ = ('商店',) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["商店"], +} shop_help = on_command("商店", priority=5, block=True) diff --git a/plugins/shop/shop_handle/data_source.py b/plugins/shop/shop_handle/data_source.py index 2a3a745e..b9b5d479 100644 --- a/plugins/shop/shop_handle/data_source.py +++ b/plugins/shop/shop_handle/data_source.py @@ -6,14 +6,17 @@ from configs.config import IMPORT_DEFAULT_SHOP_GOODS from nonebot import Driver import nonebot import time +import os driver: Driver = nonebot.get_driver() -# 导入内置商品 +# 导入内置商品 | 重新生成商店图片 @driver.on_startup async def init_default_shop_goods(): + if os.path.exists(f"{IMAGE_PATH}/shop_help.png"): + os.remove(f"{IMAGE_PATH}/shop_help.png") if IMPORT_DEFAULT_SHOP_GOODS: await add_goods(["好感度双倍加持卡Ⅰ", 30, "下次签到双倍好感度概率 + 10%(谁才是真命天子?)(同类商品将覆盖)"]) await add_goods(["好感度双倍加持卡Ⅱ", 150, "下次签到双倍好感度概率 + 20%(平平庸庸)(同类商品将覆盖)"]) diff --git a/plugins/shop/use/__init__.py b/plugins/shop/use/__init__.py index b31b6469..875afd40 100644 --- a/plugins/shop/use/__init__.py +++ b/plugins/shop/use/__init__.py @@ -9,9 +9,25 @@ from services.db_context import db from .data_source import effect -__plugin_name__ = "使用道具" -__plugin_usage__ = "输入 “使用道具 xxx(序号 或 道具名称)“ 即可使用道具\n【注】序号以我的道具序号为准,更推荐使用道具名称使用道具(怕出错)" - +__zx_plugin_name__ = "商店 - 使用道具" +__plugin_usage__ = """ +usage: + 普通的使用道具 + 指令: + 使用道具 [序号或道具名称] + * 序号以 ”我的道具“ 为准 * +""".strip() +__plugin_des__ = "商店 - 使用道具" +__plugin_cmd__ = ["使用道具 [序号或道具名称]"] +__plugin_type__ = ('商店',) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["商店", "使用道具"], +} use_props = on_command("使用道具", priority=5, block=True, permission=GROUP) diff --git a/plugins/sign_in/__init__.py b/plugins/sign_in/__init__.py index 6ff29d26..d0df66f1 100644 --- a/plugins/sign_in/__init__.py +++ b/plugins/sign_in/__init__.py @@ -6,6 +6,7 @@ from .group_user_checkin import ( ) from nonebot.typing import T_State from nonebot.adapters.cqhttp import Bot, GroupMessageEvent +from utils.manager import plugins2cd_manager from nonebot.adapters.cqhttp.permission import GROUP from utils.message_builder import image from nonebot import on_command @@ -20,13 +21,30 @@ try: except ModuleNotFoundError: import json -__plugin_name__ = "签到" -__plugin_usage__ = ( - "用法:\n" - "对我说 “签到” 来签到\n" - "“我的签到” 来获取历史签到信息\n" - "“好感度排行” 来查看当前好感度前十的伙伴\n" - "/ 签到时有 3% 概率 * 2 /" +__zx_plugin_name__ = "签到" +__plugin_usage__ = """ +usage: + 每日签到 + 会影响色图概率和开箱次数,以及签到的随机道具获取 + 指令: + 签到 + 我的签到 + 好感度排行 + 好感度总排行 + * 签到时有 3% 概率 * 2 * +""".strip() +__plugin_des__ = "每日签到,证明你在这里" +__plugin_cmd__ = ["签到", "我的签到", "好感度排行", "好感度总排行"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["签到"], +} +plugins2cd_manager.add_cd_limit( + 'sign_in', ) _file = Path(f"{DATA_PATH}/not_show_sign_rank_user.json") diff --git a/plugins/sign_in/config.py b/plugins/sign_in/config.py index 5c062d1e..1e662bcb 100644 --- a/plugins/sign_in/config.py +++ b/plugins/sign_in/config.py @@ -7,7 +7,6 @@ SIGN_TODAY_CARD_PATH = Path(IMAGE_PATH) / 'sign' / 'today_card' SIGN_BORDER_PATH = Path(SIGN_RESOURCE_PATH) / 'border' SIGN_BACKGROUND_PATH = Path(SIGN_RESOURCE_PATH) / 'background' -SIGN_TODAY_CARD_PATH.mkdir(exist_ok=True, parents=True) SIGN_BORDER_PATH.mkdir(exist_ok=True, parents=True) SIGN_BACKGROUND_PATH.mkdir(exist_ok=True, parents=True) diff --git a/plugins/sign_in/group_user_checkin.py b/plugins/sign_in/group_user_checkin.py index 91683c2c..a7a10863 100644 --- a/plugins/sign_in/group_user_checkin.py +++ b/plugins/sign_in/group_user_checkin.py @@ -15,8 +15,8 @@ import random import aiohttp import math import asyncio -import os import secrets +import os async def group_user_check_in( @@ -183,9 +183,6 @@ async def _pst(users: list, impressions: list, groups: list): except AttributeError: user_name = f"我名字呢?" user_name = user_name if len(user_name) < 11 else user_name[:10] + "..." - impression = ( - str(impression)[:4] if len(str(impression)) > 4 else impression - ) try: async with session.get( f"http://q1.qlogo.cn/g?b=qq&nk={user}&s=160", timeout=5 @@ -201,7 +198,7 @@ async def _pst(users: list, impressions: list, groups: list): bk.text((5, int((100 - font_h) / 2)), f"{idx}.") bk.paste(ava, (55, int((100 - 50) / 2)), True) bk.text((120, int((100 - font_h) / 2)), f"{user_name}") - bk.text((460, int((100 - font_h) / 2)), f"[{impression}]") + bk.text((460, int((100 - font_h) / 2)), f"[{impression:.2f}]") col_img.paste(bk) A.paste(col_img, (width, 0)) lens -= 33 diff --git a/plugins/sign_in/utils.py b/plugins/sign_in/utils.py index be93cde3..34092e9b 100644 --- a/plugins/sign_in/utils.py +++ b/plugins/sign_in/utils.py @@ -20,6 +20,7 @@ from typing import Optional, List from nonebot import Driver from io import BytesIO import asyncio +import random import nonebot import aiohttp import os @@ -31,6 +32,7 @@ driver: Driver = nonebot.get_driver() @driver.on_startup async def init_image(): SIGN_RESOURCE_PATH.mkdir(parents=True, exist_ok=True) + SIGN_TODAY_CARD_PATH.mkdir(exist_ok=True, parents=True) await GroupInfoUser.add_member_info(114514, 114514, "", datetime.min, 0) _u = await GroupInfoUser.get_member_info(114514, 114514) if _u.uid is None: @@ -57,15 +59,26 @@ async def get_card( ) -> MessageSegment: user_id = user.user_qq date = datetime.now().date() - _type = 'view' if is_card_view else 'sign' - card_file = Path(SIGN_TODAY_CARD_PATH) / f"{user_id}_{user.belonging_group}_{_type}_{date}.png" + _type = "view" if is_card_view else "sign" + card_file = ( + Path(SIGN_TODAY_CARD_PATH) + / f"{user_id}_{user.belonging_group}_{_type}_{date}.png" + ) if card_file.exists(): - return image(f"{user_id}_{user.belonging_group}_{_type}_{date}.png", "sign/today_card") + return image( + f"{user_id}_{user.belonging_group}_{_type}_{date}.png", "sign/today_card" + ) else: if add_impression == -1: - card_file = Path(SIGN_TODAY_CARD_PATH) / f"{user_id}_{user.belonging_group}_view_{date}.png" + card_file = ( + Path(SIGN_TODAY_CARD_PATH) + / f"{user_id}_{user.belonging_group}_view_{date}.png" + ) if card_file.exists(): - return image(f"{user_id}_{user.belonging_group}_view_{date}.png", "sign/today_card") + return image( + f"{user_id}_{user.belonging_group}_view_{date}.png", + "sign/today_card", + ) is_card_view = True ava = BytesIO(await _get_pic(user_id)) uid = await GroupInfoUser.get_group_member_uid( @@ -110,7 +123,7 @@ def _generate_card( ava_border = CreateImg( 140, 140, - background=SIGN_BORDER_PATH / 'ava_border_01.png', + background=SIGN_BORDER_PATH / "ava_border_01.png", ) ava = CreateImg(102, 102, background=ava_bytes) ava.circle() @@ -142,15 +155,22 @@ def _generate_card( True, ) font_size = 30 - if '好感度双倍加持卡' in gift: + if "好感度双倍加持卡" in gift: font_size = 20 gift_border = CreateImg( - 270, 100, background=SIGN_BORDER_PATH / "gift_border_02.png", font_size=font_size + 270, + 100, + background=SIGN_BORDER_PATH / "gift_border_02.png", + font_size=font_size, ) gift_border.text((0, 0), gift, center_type="center") bk = CreateImg( - 876, 424, background=SIGN_BACKGROUND_PATH / "background_01.jpg", font_size=25 + 876, + 424, + background=SIGN_BACKGROUND_PATH + / random.choice(os.listdir(SIGN_BACKGROUND_PATH)), + font_size=25, ) A = CreateImg(876, 274, background=SIGN_RESOURCE_PATH / "white.png") line = CreateImg(2, 180, color="black") @@ -226,8 +246,11 @@ def _generate_card( f"上次签到日期:{'从未' if user.checkin_time_last == datetime.min else user.checkin_time_last.date()}", ) today_data.text((0, 25), f"总金币:{gold}") - today_data.text((0, 50), f'色图概率:{(70 + user.impression if user.impression < 100 else 100):.2f}%') - today_data.text((0, 75), f'开箱次数:{(20 + int(user.impression / 3))}') + today_data.text( + (0, 50), + f"色图概率:{(70 + user.impression if user.impression < 100 else 100):.2f}%", + ) + today_data.text((0, 75), f"开箱次数:{(20 + int(user.impression / 3))}") _type = "view" else: A.paste(gift_border, (570, 140), True) @@ -268,8 +291,12 @@ def _generate_card( bk.paste(today_sign_text_img, (550, 180), True) bk.paste(today_data, (580, 220), True) bk.paste(watermark, (15, 400), True) - bk.save(SIGN_TODAY_CARD_PATH / f"{user_id}_{user.belonging_group}_{_type}_{data}.png") - return image(f"{user_id}_{user.belonging_group}_{_type}_{data}.png", "sign/today_card") + bk.save( + SIGN_TODAY_CARD_PATH / f"{user_id}_{user.belonging_group}_{_type}_{data}.png" + ) + return image( + f"{user_id}_{user.belonging_group}_{_type}_{data}.png", "sign/today_card" + ) def generate_progress_bar_pic(): @@ -330,4 +357,3 @@ def clear_sign_data_pic(): for file in os.listdir(SIGN_TODAY_CARD_PATH): if str(date) not in file: os.remove(SIGN_TODAY_CARD_PATH / file) - diff --git a/plugins/songpicker2/__init__.py b/plugins/songpicker2/__init__.py deleted file mode 100644 index 50a8f4ea..00000000 --- a/plugins/songpicker2/__init__.py +++ /dev/null @@ -1,42 +0,0 @@ -from .music_163 import dataGet, dataProcess, get_music_id -from nonebot.adapters import Bot, Event -from nonebot.typing import T_State -from nonebot import on_command - -__plugin_name__ = "点歌" - -__plugin_usage__ = "用法:点歌 [歌名]" - -dataget = dataGet() - -songpicker = on_command("点歌", priority=5, block=True) - - -@songpicker.handle() -async def handle_first_receive(bot: Bot, event: Event, state: T_State): - args = str(event.get_message()).strip() - if args: - state["songName"] = args - - -@songpicker.got("songName", prompt="歌名是?") -async def handle_songName(bot: Bot, event: Event, state: T_State): - songName = state["songName"] - songIdList = await dataget.songIds(songName=songName) - if not songIdList: - await songpicker.finish("没有找到这首歌!", at_sender=True) - for _ in range(3): - songInfoDict = await dataget.songInfo(songIdList[0]) - if songInfoDict != "网易云网络繁忙!": - break - else: - await songpicker.finish("网易云繁忙...") - state["songIdList"] = songIdList - - -@songpicker.got("songName") -async def handle_songNum(bot: Bot, event: Event, state: T_State): - songIdList = state["songIdList"] - selectedSongId = songIdList[0] - songContent = [{"type": "music", "data": {"type": 163, "id": selectedSongId}}] - await songpicker.send(songContent) diff --git a/plugins/songpicker2/music_163.py b/plugins/songpicker2/music_163.py deleted file mode 100644 index 65586cdc..00000000 --- a/plugins/songpicker2/music_163.py +++ /dev/null @@ -1,155 +0,0 @@ -import aiohttp -import json -from utils.utils import get_local_proxy -from configs.config import ALAPI_TOKEN -from asyncio.exceptions import TimeoutError - - -class dataApi: - """ - 从网易云音乐接口直接获取数据(实验性) - """ - - headers = {"referer": "http://music.163.com"} - cookies = {"appver": "2.0.2"} - - async def search(self, songName: str): - """ - 搜索接口,用于由歌曲名查找id - """ - async with aiohttp.ClientSession( - headers=self.headers, cookies=self.cookies - ) as session: - async with session.post( - f"http://music.163.com/api/search/get/", - data={"s": songName, "limit": 5, "type": 1, "offset": 0}, - ) as r: - if r.status != 200: - return None - r = await r.text() - return json.loads(r) - - async def getSongInfo(self, songId: int): - """ - 获取歌曲信息 - """ - async with aiohttp.ClientSession( - headers=self.headers, cookies=self.cookies - ) as session: - async with session.post( - f"http://music.163.com/api/song/detail/?id={songId}&ids=%5B{songId}%5D", - ) as r: - if r.status != 200: - return None - r = await r.text() - return json.loads(r) - - -class dataGet(dataApi): - """ - 从dataApi获取数据,并做简单处理 - """ - - api = dataApi() - - async def songIds(self, songName: str, amount=5) -> list: - """ - 根据用户输入的songName 获取候选songId列表 [默认songId数量:5] - """ - songIds = list() - r = await self.api.search(songName=songName) - if r is None: - raise WrongDataError - idRange = ( - amount if amount < len(r["result"]["songs"]) else len(r["result"]["songs"]) - ) - for i in range(idRange): - songIds.append(r["result"]["songs"][i]["id"]) - return songIds - - async def songInfo(self, songId: int): - """ - 根据传递的songId,获取歌曲名、歌手、专辑等信息,作为dict返回 - """ - songInfo = dict() - r = await self.api.getSongInfo(songId) - if r is None: - raise WrongDataError - if r["code"] == -460: - return "网易云网络繁忙!" - songInfo["songName"] = r["songs"][0]["name"] - - songArtists = list() - for ars in r["songs"][0]["artists"]: - songArtists.append(ars["name"]) - songArtistsStr = "、".join(songArtists) - songInfo["songArtists"] = songArtistsStr - - songInfo["songAlbum"] = r["songs"][0]["album"]["name"] - - return songInfo - - -class dataProcess: - """ - 将获取的数据处理为用户能看懂的形式 - """ - - @staticmethod - async def mergeSongInfo(songInfos: list) -> str: - """ - 将歌曲信息list处理为字符串,供用户点歌 - 传递进的歌曲信息list含有多个歌曲信息dict - """ - songInfoMessage = "请输入欲点播歌曲的序号:\n" - numId = 0 - for songInfo in songInfos: - songInfoMessage += f"{numId}:" - songInfoMessage += songInfo["songName"] - songInfoMessage += "-" - songInfoMessage += songInfo["songArtists"] - songInfoMessage += " 专辑:" - songInfoMessage += songInfo["songAlbum"] - songInfoMessage += "\n" - numId += 1 - return songInfoMessage - - @staticmethod - async def mergeSongComments(songComments: dict) -> str: - songCommentsMessage = "\n".join( - ["%s: %s" % (key, value) for (key, value) in songComments.items()] - ) - return songCommentsMessage - - -class Error(Exception): - """ - 谁知道网易的接口会出什么幺蛾子 - """ - - pass - - -class WrongDataError(Error): - def __init__(self, expression, message): - self.expression = expression - self.message = message - self.message += "\n未从网易接口获取到有效的数据!" - - -async def get_music_id(keyword: str): - url = f"https://v2.alapi.cn/api/music/search" - params = {"token": ALAPI_TOKEN, "keyword": keyword} - 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: - data = data["data"]["songs"] - return data["id"], 200 - else: - return f'访问失败...code:{data["code"]}', 999 - except TimeoutError: - return "超时了...", 999 diff --git a/plugins/statistics/__init__.py b/plugins/statistics/__init__.py new file mode 100644 index 00000000..6b1c8b3c --- /dev/null +++ b/plugins/statistics/__init__.py @@ -0,0 +1,15 @@ +from pathlib import Path +from configs.path_config import DATA_PATH +import nonebot +import os + +nonebot.load_plugins("plugins/statistics") + +old_file1 = Path(DATA_PATH) / "_prefix_count.json" +old_file2 = Path(DATA_PATH) / "_prefix_user_count.json" +new_path = Path(DATA_PATH) / "statistics" +new_path.mkdir(parents=True, exist_ok=True) +if old_file1.exists(): + os.rename(old_file1, new_path / "_prefix_count.json") +if old_file2.exists(): + os.rename(old_file2, new_path / "_prefix_user_count.json") diff --git a/plugins/statistics/statistics_handle.py b/plugins/statistics/statistics_handle.py new file mode 100644 index 00000000..9c119d8b --- /dev/null +++ b/plugins/statistics/statistics_handle.py @@ -0,0 +1,262 @@ +from nonebot import on_command +from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent +from models.group_info import GroupInfo +from nonebot.typing import T_State +from pathlib import Path +from configs.path_config import DATA_PATH, IMAGE_PATH +from utils.utils import get_message_text +from utils.image_utils import CreateMat +from utils.message_builder import image +from utils.manager import plugins2settings_manager +import asyncio +import os + +try: + import ujson as json +except ModuleNotFoundError: + import json + + +__zx_plugin_name__ = "功能调用统计可视化" +__plugin_usage__ = """ +usage: + 功能调用统计可视化 + 指令: + 功能调用统计 + 日功能调用统计 + 周功能调用统计 ?[功能] + 月功能调用统计 ?[功能] + 我的功能调用统计 + 我的日功能调用统计 ?[功能] + 我的周功能调用统计 ?[功能] + 我的月功能调用统计 ?[功能] +""".strip() +__plugin_superuser_usage__ = """ +usage: + 功能调用统计可视化 + 指令: + 全局功能调用统计 + 全局日功能调用统计 + 全局周功能调用统计 ?[功能] + 全局月功能调用统计 ?[功能] +""".strip() +__plugin_des__ = "功能调用统计可视化" +__plugin_cmd__ = [ + "功能调用统计", + "全局功能调用统计 [_superuser]", + "全局日功能调用统计 [_superuser]", + "全局周功能调用统计 ?[功能] [_superuser]", + "全局月功能调用统计 ?[功能] [_superuser]", + "周功能调用统计 ?[功能]", + "月功能调用统计 ?[功能]", + "我的功能调用统计", + "我的日功能调用统计 ?[功能]", + "我的周功能调用统计 ?[功能]", + "我的月功能调用统计 ?[功能]", +] +__plugin_type__ = ("功能调用统计可视化", 1) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["功能调用统计"], +} + + +statistics = on_command( + "功能调用统计", + aliases={ + "全局功能调用统计", + "全局日功能调用统计", + "全局周功能调用统计", + "全局月功能调用统计", + "日功能调用统计", + "周功能调用统计", + "月功能调用统计", + "我的功能调用统计", + "我的日功能调用统计", + "我的周功能调用统计", + "我的月功能调用统计", + }, + priority=5, + block=True, +) + + +statistics_group_file = Path(DATA_PATH) / "statistics" / "_prefix_count.json" +statistics_user_file = Path(DATA_PATH) / "statistics" / "_prefix_user_count.json" + + +@statistics.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State): + msg = get_message_text(event.json()) + if state["_prefix"]["raw_command"][:2] == "全局": + if str(event.user_id) in bot.config.superusers: + data: dict = json.load(open(statistics_group_file, "r", encoding="utf8")) + if state["_prefix"]["raw_command"][2] == '日': + itype = 'day_statistics' + elif state["_prefix"]["raw_command"][2] == '周': + itype = 'week_statistics' + elif state["_prefix"]["raw_command"][2] == '月': + itype = 'month_statistics' + else: + itype = 'total_statistics' + data = data[itype]["total"] + bar_graph = await init_bar_graph(data, state["_prefix"]["raw_command"]) + await asyncio.get_event_loop().run_in_executor(None, bar_graph.gen_graph) + await statistics.finish(image(b64=bar_graph.pic2bs4())) + return + if state["_prefix"]["raw_command"][:2] == "我的": + itype = "user" + key = str(event.user_id) + state["_prefix"]["raw_command"] = state["_prefix"]["raw_command"][2:] + if not statistics_user_file.exists(): + await statistics.finish("统计文件不存在...", at_sender=True) + else: + if not isinstance(event, GroupMessageEvent): + await statistics.finish("请在群内调用此功能...") + itype = "group" + key = str(event.group_id) + if not statistics_group_file.exists(): + await statistics.finish("统计文件不存在...", at_sender=True) + plugin = "" + if state["_prefix"]["raw_command"][0] == "日": + arg = "day_statistics" + elif state["_prefix"]["raw_command"][0] == "周": + arg = "week_statistics" + elif state["_prefix"]["raw_command"][0] == "月": + arg = "month_statistics" + else: + arg = "total_statistics" + if msg: + plugin = plugins2settings_manager.get_plugin_module(msg) + if not plugin: + if arg not in ["day_statistics", "total_statistics"]: + await statistics.finish("未找到此功能的调用...", at_sender=True) + if itype == "group": + data: dict = json.load(open(statistics_group_file, "r", encoding="utf8")) + if not data[arg].get(str(event.group_id)): + await statistics.finish("该群统计数据不存在...", at_sender=True) + else: + data: dict = json.load(open(statistics_user_file, "r", encoding="utf8")) + if not data[arg].get(str(event.user_id)): + await statistics.finish("该用户统计数据不存在...", at_sender=True) + day_index = data["day_index"] + data = data[arg][key] + if itype == "group": + name = await GroupInfo.get_group_info(event.group_id) + name = name.group_name if name else str(event.group_id) + else: + name = event.sender.card if event.sender.card else event.sender.nickname + img = await generate_statistics_img(data, arg, name, plugin, day_index) + await statistics.send(image(b64=img)) + + +async def generate_statistics_img( + data: dict, arg: str, name: str, plugin: str, day_index: int +): + bar_graph = None + if arg == "day_statistics": + bar_graph = await init_bar_graph(data, f"{name} 日功能调用统计") + elif arg == "week_statistics": + if plugin: + current_week = day_index % 7 + week_lst = [] + if current_week == 0: + week_lst = [1, 2, 3, 4, 5, 6, 7] + else: + for i in range(current_week + 1, 7): + week_lst.append(str(i)) + for i in range(current_week + 1): + week_lst.append(str(i)) + count = [] + for i in range(7): + if int(week_lst[i]) == 7: + try: + count.append(data[str(0)][plugin]) + except KeyError: + count.append(0) + else: + try: + print(data[str(week_lst[i])][plugin]) + count.append(data[str(week_lst[i])][plugin]) + except KeyError: + count.append(0) + week_lst = ["7" if i == "0" else i for i in week_lst] + bar_graph = CreateMat( + y=count, + mat_type="line", + title=f"{name} 周 {plugin} 功能调用统计【为7天统计】", + x_index=week_lst, + display_num=True, + background=[ + f"{IMAGE_PATH}/background/create_mat/{x}" + for x in os.listdir(f"{IMAGE_PATH}/background/create_mat") + ], + bar_color=["*"], + ) + else: + bar_graph = await init_bar_graph(update_data(data), f"{name} 周功能调用统计【为7天统计】") + elif arg == "month_statistics": + if plugin: + day_index = day_index % 30 + day_lst = [] + for i in range(day_index + 1, 30): + day_lst.append(i) + for i in range(day_index + 1): + day_lst.append(i) + count = [data[str(day_lst[i])][plugin] for i in range(30)] + day_lst = [str(x + 1) for x in day_lst] + bar_graph = CreateMat( + y=count, + mat_type="line", + title=f"{name} 月 {plugin} 功能调用统计【为30天统计】", + x_index=day_lst, + display_num=True, + background=[ + f"{IMAGE_PATH}/background/create_mat/{x}" + for x in os.listdir(f"{IMAGE_PATH}/background/create_mat") + ], + bar_color=["*"], + ) + else: + bar_graph = await init_bar_graph(update_data(data), f"{name} 月功能调用统计【为30天统计】") + elif arg == "total_statistics": + bar_graph = await init_bar_graph(data, f"{name} 功能调用统计") + await asyncio.get_event_loop().run_in_executor(None, bar_graph.gen_graph) + return bar_graph.pic2bs4() + + +async def init_bar_graph(data: dict, title: str) -> CreateMat: + return await asyncio.get_event_loop().run_in_executor(None, _init_bar_graph, data, title) + + +def _init_bar_graph(data: dict, title: str) -> CreateMat: + bar_graph = CreateMat( + y=[data[x] for x in data.keys() if data[x] != 0], + mat_type="barh", + title=title, + x_index=[x for x in data.keys() if data[x] != 0], + display_num=True, + background=[ + f"{IMAGE_PATH}/background/create_mat/{x}" + for x in os.listdir(f"{IMAGE_PATH}/background/create_mat") + ], + bar_color=["*"], + ) + return bar_graph + + +def update_data(data: dict): + tmp_dict = {} + for day in data.keys(): + for plugin_name in data[day].keys(): + # print(f'{day}:{plugin_name} = {data[day][plugin_name]}') + if data[day][plugin_name] is not None: + if tmp_dict.get(plugin_name) is None: + tmp_dict[plugin_name] = 1 + else: + tmp_dict[plugin_name] += data[day][plugin_name] + return tmp_dict diff --git a/plugins/statistics_hook.py b/plugins/statistics/statistics_hook.py similarity index 60% rename from plugins/statistics_hook.py rename to plugins/statistics/statistics_hook.py index 1371ee85..e5bc57d1 100644 --- a/plugins/statistics_hook.py +++ b/plugins/statistics/statistics_hook.py @@ -1,194 +1,215 @@ -from configs.path_config import DATA_PATH -from nonebot.matcher import Matcher -from nonebot.message import run_postprocessor -from nonebot.typing import T_State -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from datetime import datetime -from configs.config import plugins2info_dict -from utils.utils import scheduler -from nonebot.typing import Optional - -try: - import ujson as json -except ModuleNotFoundError: - import json - - -try: - with open(DATA_PATH + "_prefix_count.json", "r", encoding="utf8") as f: - _prefix_count_dict = json.load(f) -except (FileNotFoundError, ValueError): - _prefix_count_dict = { - "total_statistics": { - "total": {}, - }, - "day_statistics": { - "total": {}, - }, - "week_statistics": { - "total": {}, - }, - "month_statistics": { - "total": {}, - }, - "start_time": str(datetime.now().date()), - "day_index": 0, - } - -try: - with open(DATA_PATH + "_prefix_user_count.json", "r", encoding="utf8") as f: - _prefix_user_count_dict = json.load(f) -except (FileNotFoundError, ValueError): - _prefix_user_count_dict = { - "total_statistics": { - "total": {}, - }, - "day_statistics": { - "total": {}, - }, - "week_statistics": { - "total": {}, - }, - "month_statistics": { - "total": {}, - }, - "start_time": str(datetime.now().date()), - "day_index": 0, - } - - -# 以前版本转换 -if not _prefix_count_dict.get("day_index"): - tmp = _prefix_count_dict.copy() - _prefix_count_dict = { - "total_statistics": tmp["total_statistics"], - "day_statistics": { - "total": {}, - }, - "week_statistics": { - "total": {}, - }, - "month_statistics": { - "total": {}, - }, - "start_time": tmp["start_time"], - "day_index": 0, - } - - -# 添加命令次数 -@run_postprocessor -async def _( - matcher: Matcher, - exception: Optional[Exception], - bot: Bot, - event: GroupMessageEvent, - state: T_State, -): - global _prefix_count_dict - 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}') - for plugin in plugins2info_dict: - if plugin == model: - # print(f'plugin --> {plugin}') - try: - group_id = str(event.group_id) - except AttributeError: - group_id = "total" - user_id = str(event.user_id) - plugin_name = plugins2info_dict[plugin]["cmd"][0] - check_exists_key(group_id, user_id, plugin_name) - for data in [_prefix_count_dict, _prefix_user_count_dict]: - data["total_statistics"]["total"][plugin_name] += 1 - data["day_statistics"]["total"][plugin_name] += 1 - data["week_statistics"]["total"][plugin_name] += 1 - data["month_statistics"]["total"][plugin_name] += 1 - # print(_prefix_count_dict) - if group_id != "total": - for data in [_prefix_count_dict, _prefix_user_count_dict]: - if data == _prefix_count_dict: - key = group_id - else: - key = user_id - data["total_statistics"][key][plugin_name] += 1 - data["day_statistics"][key][plugin_name] += 1 - data["week_statistics"][key][str(day_index % 7)][ - plugin_name - ] += 1 - data["month_statistics"][key][str(day_index % 30)][ - plugin_name - ] += 1 - with open(DATA_PATH + "_prefix_count.json", "w", encoding="utf8") as f: - json.dump(_prefix_count_dict, f, indent=4, ensure_ascii=False) - with open( - DATA_PATH + "_prefix_user_count.json", "w", encoding="utf8" - ) as f: - json.dump(_prefix_user_count_dict, f, ensure_ascii=False, indent=4) - break - - -def check_exists_key(group_id: str, user_id: str, plugin_name: str): - global _prefix_count_dict, _prefix_user_count_dict - for data in [_prefix_count_dict, _prefix_user_count_dict]: - if data == _prefix_count_dict: - key = group_id - else: - key = user_id - if not data["total_statistics"]["total"].get(plugin_name): - data["total_statistics"]["total"][plugin_name] = 0 - if not data["day_statistics"]["total"].get(plugin_name): - data["day_statistics"]["total"][plugin_name] = 0 - if not data["week_statistics"]["total"].get(plugin_name): - data["week_statistics"]["total"][plugin_name] = 0 - if not data["month_statistics"]["total"].get(plugin_name): - data["month_statistics"]["total"][plugin_name] = 0 - - if not data["total_statistics"].get(key): - data["total_statistics"][key] = {} - if not data["total_statistics"][key].get(plugin_name): - data["total_statistics"][key][plugin_name] = 0 - if not data["day_statistics"].get(key): - data["day_statistics"][key] = {} - if not data["day_statistics"][key].get(plugin_name): - data["day_statistics"][key][plugin_name] = 0 - - if not data["week_statistics"].get(key): - data["week_statistics"][key] = {} - if data["week_statistics"][key].get("0") is None: - for i in range(7): - data["week_statistics"][key][str(i)] = {} - if data["week_statistics"][key]["0"].get(plugin_name) is None: - for i in range(7): - data["week_statistics"][key][str(i)][plugin_name] = 0 - - if not data["month_statistics"].get(key): - data["month_statistics"][key] = {} - if data["month_statistics"][key].get("0") is None: - for i in range(30): - data["month_statistics"][key][str(i)] = {} - if data["month_statistics"][key]["0"].get(plugin_name) is None: - for i in range(30): - data["month_statistics"][key][str(i)][plugin_name] = 0 - - -# 天 -@scheduler.scheduled_job( - "cron", - hour=0, - minute=1, -) -async def _(): - for data in [_prefix_count_dict, _prefix_user_count_dict]: - for x in _prefix_count_dict["day_statistics"].keys(): - for key in _prefix_count_dict["day_statistics"][x].keys(): - try: - data["day_statistics"][x][key] = 0 - except KeyError: - pass - data["day_index"] += 1 - with open(DATA_PATH + "_prefix_count.json", "w", encoding="utf8") as f: - json.dump(_prefix_count_dict, f, indent=4, ensure_ascii=False) - with open(DATA_PATH + "_prefix_user_count.json", "w", encoding="utf8") as f: - json.dump(_prefix_user_count_dict, f, indent=4, ensure_ascii=False) +from configs.path_config import DATA_PATH +from nonebot.matcher import Matcher +from nonebot.message import run_postprocessor +from nonebot.typing import T_State +from nonebot.adapters.cqhttp import Bot, GroupMessageEvent +from datetime import datetime +from utils.manager import plugins2settings_manager +from utils.utils import scheduler +from nonebot.typing import Optional +from pathlib import Path + +try: + import ujson as json +except ModuleNotFoundError: + import json + + +__zx_plugin_name__ = "功能调用统计 [Hidden]" +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" + +statistics_group_file = Path(DATA_PATH) / "statistics" / "_prefix_count.json" +statistics_user_file = Path(DATA_PATH) / "statistics" / "_prefix_user_count.json" + +try: + with open(statistics_group_file, "r", encoding="utf8") as f: + _prefix_count_dict = json.load(f) +except (FileNotFoundError, ValueError): + _prefix_count_dict = { + "total_statistics": { + "total": {}, + }, + "day_statistics": { + "total": {}, + }, + "week_statistics": { + "total": {}, + }, + "month_statistics": { + "total": {}, + }, + "start_time": str(datetime.now().date()), + "day_index": 0, + } + +try: + with open(statistics_user_file, "r", encoding="utf8") as f: + _prefix_user_count_dict = json.load(f) +except (FileNotFoundError, ValueError): + _prefix_user_count_dict = { + "total_statistics": { + "total": {}, + }, + "day_statistics": { + "total": {}, + }, + "week_statistics": { + "total": {}, + }, + "month_statistics": { + "total": {}, + }, + "start_time": str(datetime.now().date()), + "day_index": 0, + } + + +# 以前版本转换 +if _prefix_count_dict.get("day_index") is None: + tmp = _prefix_count_dict.copy() + _prefix_count_dict = { + "total_statistics": tmp["total_statistics"], + "day_statistics": { + "total": {}, + }, + "week_statistics": { + "total": {}, + }, + "month_statistics": { + "total": {}, + }, + "start_time": tmp["start_time"], + "day_index": 0, + } + + +# 添加命令次数 +@run_postprocessor +async def _( + matcher: Matcher, + exception: Optional[Exception], + bot: Bot, + event: GroupMessageEvent, + state: T_State, +): + global _prefix_count_dict + if ( + matcher.type == "message" + and matcher.priority not in [1, 9] + and matcher.module not in ["update_info"] + ): + module = matcher.module + day_index = _prefix_count_dict["day_index"] + try: + group_id = str(event.group_id) + except AttributeError: + group_id = "total" + user_id = str(event.user_id) + plugin_name = plugins2settings_manager.get_plugin_data(module) + if plugin_name and plugin_name.get('cmd'): + plugin_name = plugin_name.get('cmd')[0] + check_exists_key(group_id, user_id, plugin_name) + for data in [_prefix_count_dict, _prefix_user_count_dict]: + data["total_statistics"]["total"][plugin_name] += 1 + data["day_statistics"]["total"][plugin_name] += 1 + data["week_statistics"]["total"][plugin_name] += 1 + data["month_statistics"]["total"][plugin_name] += 1 + # print(_prefix_count_dict) + if group_id != "total": + for data in [_prefix_count_dict, _prefix_user_count_dict]: + if data == _prefix_count_dict: + key = group_id + else: + key = user_id + data["total_statistics"][key][plugin_name] += 1 + data["day_statistics"][key][plugin_name] += 1 + data["week_statistics"][key][str(day_index % 7)][ + plugin_name + ] += 1 + data["month_statistics"][key][str(day_index % 30)][ + plugin_name + ] += 1 + with open(statistics_group_file, "w", encoding="utf8") as f: + json.dump(_prefix_count_dict, f, indent=4, ensure_ascii=False) + with open( + statistics_user_file, "w", encoding="utf8" + ) as f: + json.dump(_prefix_user_count_dict, f, ensure_ascii=False, indent=4) + + +def check_exists_key(group_id: str, user_id: str, plugin_name: str): + global _prefix_count_dict, _prefix_user_count_dict + for data in [_prefix_count_dict, _prefix_user_count_dict]: + if data == _prefix_count_dict: + key = group_id + else: + key = user_id + if not data["total_statistics"]["total"].get(plugin_name): + data["total_statistics"]["total"][plugin_name] = 0 + if not data["day_statistics"]["total"].get(plugin_name): + data["day_statistics"]["total"][plugin_name] = 0 + if not data["week_statistics"]["total"].get(plugin_name): + data["week_statistics"]["total"][plugin_name] = 0 + if not data["month_statistics"]["total"].get(plugin_name): + data["month_statistics"]["total"][plugin_name] = 0 + + if not data["total_statistics"].get(key): + data["total_statistics"][key] = {} + if not data["total_statistics"][key].get(plugin_name): + data["total_statistics"][key][plugin_name] = 0 + if not data["day_statistics"].get(key): + data["day_statistics"][key] = {} + if not data["day_statistics"][key].get(plugin_name): + data["day_statistics"][key][plugin_name] = 0 + + if not data["week_statistics"].get(key): + data["week_statistics"][key] = {} + if data["week_statistics"][key].get("0") is None: + for i in range(7): + data["week_statistics"][key][str(i)] = {} + if data["week_statistics"][key]["0"].get(plugin_name) is None: + for i in range(7): + data["week_statistics"][key][str(i)][plugin_name] = 0 + + if not data["month_statistics"].get(key): + data["month_statistics"][key] = {} + if data["month_statistics"][key].get("0") is None: + for i in range(30): + data["month_statistics"][key][str(i)] = {} + if data["month_statistics"][key]["0"].get(plugin_name) is None: + for i in range(30): + data["month_statistics"][key][str(i)][plugin_name] = 0 + + +# 天 +@scheduler.scheduled_job( + "cron", + hour=0, + minute=1, +) +async def _(): + for data in [_prefix_count_dict, _prefix_user_count_dict]: + data["day_index"] += 1 + for x in data["day_statistics"].keys(): + for key in data["day_statistics"][x].keys(): + try: + data["day_statistics"][x][key] = 0 + except KeyError: + pass + for type_ in ["week_statistics", "month_statistics"]: + index = str( + data["day_index"] % 7 + if type_ == "week_statistics" + else data["day_index"] % 30 + ) + for x in data[type_].keys(): + try: + for key in data[type_][x][index].keys(): + data[type_][x][index][key] = 0 + except KeyError: + pass + with open(statistics_group_file, "w", encoding="utf8") as f: + json.dump(_prefix_count_dict, f, indent=4, ensure_ascii=False) + with open(statistics_user_file, "w", encoding="utf8") as f: + json.dump(_prefix_user_count_dict, f, indent=4, ensure_ascii=False) diff --git a/plugins/statistics_handle.py b/plugins/statistics_handle.py deleted file mode 100644 index 9acfb2d1..00000000 --- a/plugins/statistics_handle.py +++ /dev/null @@ -1,176 +0,0 @@ -from nonebot import on_command -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent -from models.group_info import GroupInfo -from nonebot.typing import T_State -from pathlib import Path -from configs.path_config import DATA_PATH, TTF_PATH -import matplotlib.pyplot as plt -from utils.utils import get_message_text -from utils.image_utils import fig2b64 -from utils.message_builder import image -from configs.config import plugins2info_dict -from matplotlib.font_manager import FontProperties - -plt.rcParams["font.family"] = ["SimHei", "FangSong", "KaiTi"] -plt.rcParams["font.sans-serif"] = ["SimHei", "FangSong", "KaiTi"] -plt.rcParams["axes.unicode_minus"] = False - -font = FontProperties(fname=f"{TTF_PATH}/yz.ttf", size=10) - -try: - import ujson as json -except ModuleNotFoundError: - import json - -__plugin_name__ = "功能调用统计" -__plugin_usage__ = "用法: 无" - -statistics = on_command( - "功能调用统计", - aliases={ - "日功能调用统计", - "周功能调用统计", - "月功能调用统计", - "我的功能调用统计", - "我的日功能调用统计", - "我的周功能调用统计", - "我的月功能调用统计", - }, - priority=5, - block=True, -) - - -statistics_group_file = Path(f"{DATA_PATH}/_prefix_count.json") -statistics_user_file = Path(f"{DATA_PATH}/_prefix_user_count.json") - - -@statistics.handle() -async def _(bot: Bot, event: MessageEvent, state: T_State): - msg = get_message_text(event.json()) - if state["_prefix"]["raw_command"][:2] == "我的": - itype = "user" - key = str(event.user_id) - state["_prefix"]["raw_command"] = state["_prefix"]["raw_command"][2:] - if not statistics_user_file.exists(): - await statistics.finish("统计文件不存在...", at_sender=True) - else: - if not isinstance(event, GroupMessageEvent): - await statistics.finish("请在群内调用此功能...") - itype = "group" - key = str(event.group_id) - if not statistics_group_file.exists(): - await statistics.finish("统计文件不存在...", at_sender=True) - plugin = "" - if state["_prefix"]["raw_command"][0] == "日": - arg = "day_statistics" - elif state["_prefix"]["raw_command"][0] == "周": - arg = "week_statistics" - elif state["_prefix"]["raw_command"][0] == "月": - arg = "month_statistics" - else: - arg = "total_statistics" - if msg: - for x in plugins2info_dict.keys(): - if msg in plugins2info_dict[x]["cmd"]: - plugin = plugins2info_dict[x]["cmd"][0] - break - else: - if arg not in ["day_statistics", "total_statistics"]: - await statistics.finish("未找到此功能的调用...", at_sender=True) - if itype == "group": - data: dict = json.load(open(statistics_group_file, "r", encoding="utf8")) - if not data[arg].get(str(event.group_id)): - await statistics.finish("该群统计数据不存在...", at_sender=True) - else: - data: dict = json.load(open(statistics_user_file, "r", encoding="utf8")) - if not data[arg].get(str(event.user_id)): - await statistics.finish("该用户统计数据不存在...", at_sender=True) - day_index = data["day_index"] - data = data[arg][key] - if itype == "group": - name = await GroupInfo.get_group_info(event.group_id) - name = name.group_name if name else str(event.group_id) - else: - name = event.sender.card if event.sender.card else event.sender.nickname - img = generate_statistics_img(data, arg, name, plugin, day_index) - await statistics.send(image(b64=img)) - plt.cla() - - -def generate_statistics_img( - data: dict, arg: str, name: str, plugin: str, day_index: int -): - if arg == "day_statistics": - init_bar_graph(data, f"{name} 日功能调用统计") - elif arg == "week_statistics": - if plugin: - current_week = day_index % 7 - week_lst = [] - if current_week == 0: - week_lst = [1, 2, 3, 4, 5, 6, 7] - else: - for i in range(current_week + 1, 7): - week_lst.append(str(i)) - for i in range(current_week + 1): - week_lst.append(str(i)) - count = [] - for i in range(7): - if int(week_lst[i]) == 7: - try: - count.append(data[str(0)][plugin]) - except KeyError: - count.append(0) - else: - try: - count.append(data[str(week_lst[i])][plugin]) - except KeyError: - count.append(0) - week_lst = ["7" if i == "0" else i for i in week_lst] - plt.plot(week_lst, count) - plt.title(f"{name} 周 {plugin} 功能调用统计【为7天统计】", FontProperties=font) - else: - init_bar_graph(update_data(data), f"{name} 周功能调用统计【为7天统计】") - elif arg == "month_statistics": - if plugin: - day_index = day_index % 30 - day_lst = [] - for i in range(day_index + 1, 30): - day_lst.append(i) - for i in range(day_index + 1): - day_lst.append(i) - count = [data[str(day_lst[i])][plugin] for i in range(30)] - day_lst = [str(x + 1) for x in day_lst] - plt.title(f"{name} 月 {plugin} 功能调用统计【为30天统计】", FontProperties=font) - plt.plot(day_lst, count) - else: - init_bar_graph(update_data(data), f"{name} 月功能调用统计【为30天统计】") - elif arg == "total_statistics": - init_bar_graph(data, f"{name} 功能调用统计") - - return fig2b64(plt) - - -def init_bar_graph(data: dict, title: str, ha: str = "left", va: str = "center"): - plt.tick_params(axis="y", labelsize=7) - tmp_x = list(data.keys()) - tmp_y = list(data.values()) - x = [tmp_x[i] for i in range(len(tmp_y)) if tmp_y[i]] - y = [tmp_y[i] for i in range(len(tmp_y)) if tmp_y[i]] - plt.barh(x, y) - plt.title(f"{title}", FontProperties=font) - for y, x in zip(y, x): - plt.text(y, x, s=str(y), ha=ha, va=va, fontsize=8) - - -def update_data(data: dict): - tmp_dict = {} - for day in data.keys(): - for plugin_name in data[day].keys(): - # print(f'{day}:{plugin_name} = {data[day][plugin_name]}') - if data[day][plugin_name] is not None: - if tmp_dict.get(plugin_name) is None: - tmp_dict[plugin_name] = 1 - else: - tmp_dict[plugin_name] += data[day][plugin_name] - return tmp_dict diff --git a/plugins/super_cmd/__init__.py b/plugins/super_cmd/__init__.py index 0081e936..781ddcbb 100644 --- a/plugins/super_cmd/__init__.py +++ b/plugins/super_cmd/__init__.py @@ -5,18 +5,46 @@ from nonebot.typing import T_State from nonebot.adapters.cqhttp import Bot, MessageEvent, Message from nonebot.rule import to_me from utils.utils import get_message_at, get_message_text, is_number, get_bot, scheduler +from pathlib import Path from services.log import logger -from .data_source import open_remind, close_remind from models.group_info import GroupInfo from models.friend_user import FriendUser from utils.message_builder import at from configs.path_config import IMAGE_PATH +from utils.manager import plugins2cd_manager, plugins2settings_manager, plugins2block_manager, group_manager import asyncio import os -__plugin_name__ = "超级用户指令 [Hidden]" -__plugin_usage__ = "用法" +__zx_plugin_name__ = "超级用户指令 [Superuser]" +__plugin_usage__ = """ +usage: + 超级用户集成指令 + 指令: + 添加权限 [at] [权限] + 删除权限 [at] + 开启/关闭广播通知 [group] + 查看所有好友/查看所有群组 + 退群 [group] + 更新群信息 + 更新好友信息 + 清理临时数据 + 重载插件配置 +""".strip() +__plugin_des__ = "超级用户集成指令" +__plugin_cmd__ = [ + "添加权限 [at] [权限]", + "删除权限 [at]", + "开启/关闭广播通知 [group]", + "查看所有好友/查看所有群组", + "退群 [group]", + "更新群信息", + "更新好友信息", + "清理临时数据", + "重载插件配置" +] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" super_cmd = on_command( @@ -36,10 +64,10 @@ oc_gb = on_command( block=True, ) cls_group = on_command( - "所有群组", rule=to_me(), permission=SUPERUSER, priority=1, block=True + "查看所有群组", rule=to_me(), permission=SUPERUSER, priority=1, block=True ) cls_friend = on_command( - "所有好友", rule=to_me(), permission=SUPERUSER, priority=1, block=True + "查看所有好友", rule=to_me(), permission=SUPERUSER, priority=1, block=True ) del_group = on_command("退群", rule=to_me(), permission=SUPERUSER, priority=1, block=True) update_group_info = on_command( @@ -49,8 +77,9 @@ update_friend_info = on_command( "更新好友信息", rule=to_me(), permission=SUPERUSER, priority=1, block=True ) clear_data = on_command( - "清理数据", rule=to_me(), permission=SUPERUSER, priority=1, block=True + "清理临时数据", rule=to_me(), permission=SUPERUSER, priority=1, block=True ) +reload_plugins_manager = on_command('重载插件配置', rule=to_me(), permission=SUPERUSER, priority=1, block=True) @super_cmd.handle() @@ -119,10 +148,10 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): # try: if state["_prefix"]["raw_command"] == "开启广播通知": logger.info(f"USER {event.user_id} 开启了 GROUP {group} 的广播") - await oc_gb.finish(await open_remind(group, "gb"), at_sender=True) + await oc_gb.finish(await group_manager.open_group_task(group, "broadcast",), at_sender=True) else: logger.info(f"USER {event.user_id} 关闭了 GROUP {group} 的广播") - await oc_gb.finish(await close_remind(group, "gb"), at_sender=True) + await oc_gb.finish(await group_manager.close_group_task(group, "broadcast"), at_sender=True) # except Exception as e: # await oc_gb.finish(f'关闭 {group} 的广播失败', at_sender=True) else: @@ -177,7 +206,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @update_group_info.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): bot = get_bot() - gl = await bot.get_group_list(self_id=bot.self_id) + gl = await bot.get_group_list() gl = [g["group_id"] for g in gl] num = 0 rst = "" @@ -201,7 +230,7 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): async def _(bot: Bot, event: MessageEvent, state: T_State): num = 0 rst = "" - fl = await get_bot().get_friend_list(self_id=bot.self_id) + fl = await get_bot().get_friend_list() for f in fl: if await FriendUser.add_friend_info(f["user_id"], f["nickname"]): logger.info(f'自动更新好友 {f["user_id"]} 信息成功') @@ -215,16 +244,29 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @clear_data.handle() async def _(bot: Bot, event: MessageEvent, state: T_State): await clear_data.send("开始清理临时数据....") - size = await asyncio.get_event_loop().run_in_executor( - None, _clear_data - ) + size = await asyncio.get_event_loop().run_in_executor(None, _clear_data) await clear_data.send("共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024)) +@reload_plugins_manager.handle() +async def _(bot: Bot, event: MessageEvent, state: T_State): + plugins2settings_manager.reload() + plugins2cd_manager.reload() + plugins2block_manager.reload() + try: + (Path(IMAGE_PATH) / "help.png").unlink() + except FileNotFoundError: + pass + await reload_plugins_manager.send(f'重载插件配置完成...\n' + f'已加载 {len(plugins2settings_manager.get_data())} 个非限制插件\n' + f'已加载 {len(plugins2cd_manager.get_data())} 个Cd限制\n' + f'已加载 {len(plugins2block_manager.get_data())} 个Block限制') + + def _clear_data() -> float: size = 0 - for dir_name in ['temp', 'rar', 'r18_rar']: - dir_name = f'{IMAGE_PATH}/{dir_name}' + for dir_name in ["temp", "rar", "r18_rar"]: + dir_name = f"{IMAGE_PATH}/{dir_name}" if os.path.exists(dir_name): for file in os.listdir(dir_name): try: @@ -237,15 +279,11 @@ def _clear_data() -> float: return float(size) -# 早上好 @scheduler.scheduled_job( "cron", hour=1, minute=1, ) async def _(): - size = await asyncio.get_event_loop().run_in_executor( - None, _clear_data - ) - logger.info('自动清理临时数据完成,' + "共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024)) - + size = await asyncio.get_event_loop().run_in_executor(None, _clear_data) + logger.info("自动清理临时数据完成," + "共清理了 {:.2f}MB 的数据...".format(size / 1024 / 1024)) diff --git a/plugins/super_cmd/data_source.py b/plugins/super_cmd/data_source.py index 6b6eb783..53244823 100644 --- a/plugins/super_cmd/data_source.py +++ b/plugins/super_cmd/data_source.py @@ -1,44 +1,43 @@ -from models.group_remind import GroupRemind -async def open_remind(group: int, name: str) -> str: - _name = "" - if name == "zwa": - _name = "早晚安" - if name == "dz": - _name = "地震播报" - if name == "hy": - _name = "群欢迎" - if name == "kxcz": - _name = "开箱重置提醒" - if name == "gb": - _name = "广播" - if await GroupRemind.get_status(group, name): - return f"该群已经开启过 {_name} 通知,请勿重复开启!" - if await GroupRemind.set_status(group, name, True): - return f"成功开启 {_name} 通知!0v0" - else: - return f"开启 {_name} 通知失败了..." - - -async def close_remind(group: int, name: str) -> str: - _name = "" - if name == "zwa": - _name = "早晚安" - if name == "dz": - _name = "地震播报" - if name == "hy": - _name = "群欢迎" - if name == "kxcz": - _name = "开箱重置提醒" - if name == "gb": - _name = "广播" - if not await GroupRemind.get_status(group, name): - return f"该群已经取消过 {_name} 通知,请勿重复取消!" - if await GroupRemind.set_status(group, name, False): - return f"成功关闭 {_name} 通知!0v0" - else: - return f"关闭 {_name} 通知失败了..." +# async def open_remind(group: int, name: str) -> str: +# _name = "" +# if name == "zwa": +# _name = "早晚安" +# if name == "dz": +# _name = "地震播报" +# if name == "hy": +# _name = "群欢迎" +# if name == "kxcz": +# _name = "开箱重置提醒" +# if name == "gb": +# _name = "广播" +# if await GroupRemind.get_status(group, name): +# return f"该群已经开启过 {_name} 通知,请勿重复开启!" +# if await GroupRemind.set_status(group, name, True): +# return f"成功开启 {_name} 通知!0v0" +# else: +# return f"开启 {_name} 通知失败了..." +# +# +# async def close_remind(group: int, name: str) -> str: +# _name = "" +# if name == "zwa": +# _name = "早晚安" +# if name == "dz": +# _name = "地震播报" +# if name == "hy": +# _name = "群欢迎" +# if name == "kxcz": +# _name = "开箱重置提醒" +# if name == "gb": +# _name = "广播" +# if not await GroupRemind.get_status(group, name): +# return f"该群已经取消过 {_name} 通知,请勿重复取消!" +# if await GroupRemind.set_status(group, name, False): +# return f"成功关闭 {_name} 通知!0v0" +# else: +# return f"关闭 {_name} 通知失败了..." # cmd_list = ['总开关', '签到', '发送图片', '色图', '黑白草图', 'coser', '鸡汤/语录', '骂我', '开箱', '鲁迅说', '假消息', '商店系统', diff --git a/plugins/super_help/__init__.py b/plugins/super_help/__init__.py index f8d7d644..1bdbaf69 100644 --- a/plugins/super_help/__init__.py +++ b/plugins/super_help/__init__.py @@ -3,51 +3,19 @@ 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 +from .data_source import create_help_image +from pathlib import Path -result = """超级用户帮助: -*:可多个类型参数 ?:可省略参数 - 1.添加/删除管理 [at] [level] - 2.所有群组/好友 - 3.广播- [msg] - 4.更新色图 - 5./t命令帮助 - 6.更新/设置cookie [cookie] - 7.开启/关闭广播通知 [群号] - 8.退群 [群号] - 9.自检 - 10.更新价格/更加图片 ?[武器箱] - 11.更新好友信息 - 12.更新群群信息 - 13.重载原神/方舟/赛马娘/坎公骑冠剑卡池 - 14.添加商品 [名称]-[价格]-[描述]-[折扣]-[限时时间] - 15.删除商品 [名称(序号)] - 16.修改商品 -name [名称(序号)] -price [价格] -des [描述] -discount [折扣] -time [限时] - 17.节日红包 [金额] [数量] ?[祝福语] *?[指定群] - 18.更新原神今日素材 - 19.更新原神资源信息 - 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](同时加入黑名单) - 25.查看pix图库 [keyword] - 26.pix检测更新 [update] - 27.pix [-s/-r] ?[tag] - 28.检查更新真寻 - 29.真寻重启 - 30.添加/删除群白名单 *[群号] - 31.关闭[功能] ?[群号/private/group](有群号时禁用指定群) - 32.功能状态 - 33.查看群白名单""" +__zx_plugin_name__ = '超级用户帮助 [Superuser]' -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') + +superuser_help_image = Path(IMAGE_PATH) / 'superuser_help.png' + +if superuser_help_image.exists(): + superuser_help_image.unlink() super_help = on_command( "超级用户帮助", rule=to_me(), priority=1, permission=SUPERUSER, block=True @@ -56,4 +24,7 @@ super_help = on_command( @super_help.handle() async def _(bot: Bot, event: Event, state: T_State): - await super_help.finish(image('super_help.png'), at_sender=True) + if not superuser_help_image.exists(): + await create_help_image() + x = image(superuser_help_image) + await super_help.finish(x) diff --git a/plugins/super_help/data_source.py b/plugins/super_help/data_source.py new file mode 100644 index 00000000..c0c98448 --- /dev/null +++ b/plugins/super_help/data_source.py @@ -0,0 +1,80 @@ +from utils.image_utils import CreateImg +from configs.path_config import IMAGE_PATH +from services.log import logger +from utils.utils import get_matchers +from nonebot.adapters.cqhttp import Bot +from pathlib import Path +from nonebot import Driver +import asyncio +import nonebot + + +driver: Driver = nonebot.get_driver() + +background = Path(IMAGE_PATH) / "background" / "0.png" + +superuser_help_image = Path(IMAGE_PATH) / "superuser_help.png" + + +@driver.on_bot_connect +async def create_help_image(bot: Bot = None): + """ + 创建超级用户帮助图片 + """ + await asyncio.get_event_loop().run_in_executor(None, _create_help_image) + + +def _create_help_image(): + """ + 创建管理员帮助图片 + """ + _matchers = get_matchers() + _plugin_name_list = [] + width = 0 + help_str = "超级用户帮助\n\n* 注: ‘*’ 代表可有多个相同参数 ‘?’ 代表可省略该参数 *\n\n" + tmp_img = CreateImg(0, 0, plain_text='1', font_size=24) + plugin_name = "" + for matcher in _matchers: + try: + _plugin = nonebot.plugin.get_plugin(matcher.module) + _module = _plugin.module + try: + plugin_name = _module.__getattribute__("__zx_plugin_name__") + except AttributeError: + continue + is_superuser_usage = False + try: + _ = _module.__getattribute__("__plugin_superuser_usage__") + is_superuser_usage = True + except AttributeError: + pass + if ( + ("[superuser]" in plugin_name.lower() or is_superuser_usage) + and plugin_name != "超级用户帮助 [Superuser]" + and plugin_name not in _plugin_name_list + and "[hidden]" not in plugin_name.lower() + ): + _plugin_name_list.append(plugin_name) + try: + plugin_des = _module.__getattribute__("__plugin_des__") + except AttributeError: + plugin_des = '_' + plugin_cmd = _module.__getattribute__("__plugin_cmd__") + if is_superuser_usage: + plugin_cmd = [x for x in plugin_cmd if "[_superuser]" in x] + plugin_cmd = " / ".join(plugin_cmd).replace('[_superuser]', '').strip() + help_str += f"{plugin_des} -> {plugin_cmd}\n\n" + x = tmp_img.getsize(f"{plugin_des} -> {plugin_cmd}")[0] + width = width if width > x else x + except Exception as e: + logger.warning( + f"获取超级用户插件 {matcher.module}: {plugin_name} 设置失败... {type(e)}:{e}" + ) + height = len(help_str.split("\n")) * 33 + width += 500 + A = CreateImg(width, height, font_size=24) + _background = CreateImg(width, height, background=background) + A.text((300, 140), help_str) + A.paste(_background, alpha=True) + A.save(superuser_help_image) + logger.info(f"已成功加载 {len(_plugin_name_list)} 条超级用户命令") diff --git a/plugins/translate/__init__.py b/plugins/translate/__init__.py index 4d57abe6..d29189f3 100644 --- a/plugins/translate/__init__.py +++ b/plugins/translate/__init__.py @@ -6,9 +6,29 @@ from nonebot.typing import T_State from .data_source import translate_msg -__plugin_name__ = "翻译" - -__plugin_usage__ = "用法:\n" "英翻 [英文] 翻英 [中文]\n" "日翻 [日文] 翻日 [中文]\n" "韩翻 [韩文] 翻韩 [中文]" +__zx_plugin_name__ = "翻译" +__plugin_usage__ = """ +usage: + 出国旅游小助手 + 指令: + 英翻 [英文] + 翻英 [中文] + 日翻 [日文] + 翻日 [中文] + 韩翻 [韩文] + 翻韩 [中文] +""".strip() +__plugin_des__ = "出国旅游好助手" +__plugin_cmd__ = ["英翻 [英文]", "翻英 [中文]", "日翻 [日文]", "翻日 [中文]", "韩翻 [韩文]", "翻韩 [中文]"] +__plugin_type__ = ("一些工具",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["翻译"], +} translate = on_command( diff --git a/plugins/update_gocqhttp/__init__.py b/plugins/update_gocqhttp/__init__.py index 5a21a83f..6a088d3b 100644 --- a/plugins/update_gocqhttp/__init__.py +++ b/plugins/update_gocqhttp/__init__.py @@ -3,22 +3,28 @@ from nonebot.typing import T_State from nonebot.adapters.cqhttp import Bot, GroupMessageEvent from .data_source import download_gocq_lasted, upload_gocq_lasted import os -from nonebot.adapters.cqhttp.permission import GROUP from services.log import logger -from utils.utils import scheduler, get_bot, UserExistLimiter +from utils.utils import scheduler, get_bot +from nonebot.permission import SUPERUSER from configs.config import UPDATE_GOCQ_GROUP from pathlib import Path -__plugin_name__ = "更新gocq" -__plugin_usage__ = "用法:发送’更新gocq‘,指定群 自动检测最新版gocq下载并上传" +__zx_plugin_name__ = "更新gocq [Superuser]" +__plugin_usage__ = """ +usage: + 下载最新版gocq并上传至群文件 + 指令: + 更新gocq +""".strip() +__plugin_cmd__ = ["更新gocq"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" + path = str((Path() / "resources" / "gocqhttp_file").absolute()) + "/" -lasted_gocqhttp = on_command("更新gocq", permission=GROUP, priority=5, block=True) - - -_ulmt = UserExistLimiter() +lasted_gocqhttp = on_command("更新gocq", permission=SUPERUSER, priority=5, block=True) @lasted_gocqhttp.handle() @@ -29,9 +35,6 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): info = await download_gocq_lasted(path) if info == "gocqhttp没有更新!": await lasted_gocqhttp.finish("gocqhttp没有更新!") - if _ulmt.check(event.group_id): - await lasted_gocqhttp.finish("gocqhttp正在更新,请勿重复使用该命令", at_sender=True) - _ulmt.set_true(event.group_id) try: for file in os.listdir(path): await upload_gocq_lasted(path, file, event.group_id) @@ -39,7 +42,6 @@ async def _(bot: Bot, event: GroupMessageEvent, state: T_State): await lasted_gocqhttp.send(f"gocqhttp更新了,已上传成功!\n更新内容:\n{info}") except Exception as e: logger.error(f"更新gocq错误 e:{e}") - _ulmt.set_false(event.group_id) # 更新gocq diff --git a/plugins/update_info.py b/plugins/update_info.py index f31b37d1..8d11d144 100644 --- a/plugins/update_info.py +++ b/plugins/update_info.py @@ -3,23 +3,33 @@ from nonebot.adapters.cqhttp import Bot, Event from nonebot.typing import T_State from utils.message_builder import image -__plugin_name__ = '更新信息' -__plugin_usage__ = '无' +__zx_plugin_name__ = "更新信息" +__plugin_usage__ = """ +usage: + 更新信息 + 指令: + 更新信息 +""".strip() +__plugin_des__ = "当前版本的更新信息" +__plugin_cmd__ = ["更新信息"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["更新信息"], +} -update_info = on_command("更新信息", aliases={'更新日志'}, priority=5, block=True) +update_info = on_command("更新信息", aliases={"更新日志"}, priority=5, block=True) @update_info.handle() async def _(bot: Bot, event: Event, state: T_State): - img = image('update_info.png') + img = image("update_info.png") if img: - await update_info.finish(image('update_info.png')) + await update_info.finish(image("update_info.png")) else: - await update_info.finish('目前没有更新信息哦') - - - - - + await update_info.finish("目前没有更新信息哦") diff --git a/plugins/update_pic.py b/plugins/update_pic.py index b6c92b21..15511fdb 100644 --- a/plugins/update_pic.py +++ b/plugins/update_pic.py @@ -16,35 +16,52 @@ import cv2 import numpy as np -__plugin_name__ = "图片" -__plugin_usage__ = f"""图片用法(目前): -可以输入 指定操作 或 序号 来进行选择 - 1.修改尺寸 宽(x) 高(y) 图片(在文字后跟图片即可) - 示例:{NICKNAME}修改图片 修改尺寸 200 300 图片(在文字后跟图片即可) - 2.等比压缩 比例(x) 图片(在文字后跟图片即可) - 示例:{NICKNAME}修改图片 等比压缩 2 图片(在文字后跟图片即可) - 3.旋转图片 角度(x) 图片(在文字后跟图片即可) - 示例:{NICKNAME}修改图片 旋转图片 45 图片(在文字后跟图片即可) - 4.水平翻转 - 示例:{NICKNAME}修改图片 水平翻转 图片 - 5.铅笔滤镜 - 示例:{NICKNAME}修改图片 铅笔滤镜 图片 - 6.模糊效果 - 示例:{NICKNAME}修改图片 模糊效果 图片 - 7.锐化效果 - 示例:{NICKNAME}修改图片 锐化效果 图片 - 8.高斯模糊 - 示例:{NICKNAME}修改图片 高斯模糊 图片 - 9.边缘检测 - 示例:{NICKNAME}修改图片 边缘检测 图片 - 10.底色替换 颜色 颜色 图片 (不专业)支持:(红,蓝)->(红,蓝,白,绿,黄) - 示例:{NICKNAME}修改图片 底色替换 蓝色 红色 图片""" +__zx_plugin_name__ = "各种图片简易操作" +__plugin_usage__ = """ +usage: + 简易的基础图片操作,输入 指定操作 或 序号 来进行选择 + 指令: + 1.修改尺寸 [宽] [高] [图片] + 2.等比压缩 [比例] [图片] + 3.旋转图片 [角度] [图片] + 4.水平翻转 [图片] + 5.铅笔滤镜 [图片] + 6.模糊效果 [图片] + 7.锐化效果 [图片] + 8.高斯模糊 [图片] + 9.边缘检测 [图片] + 10.底色替换 [红/蓝] [红/蓝/白/绿/黄] [图片] + 示例:图片修改尺寸 100 200 [图片] + 示例:图片 2 0.3 [图片] +""".strip() +__plugin_des__ = "10种快捷的图片简易操作" +__plugin_cmd__ = [ + "改图 修改尺寸 [宽] [高] [图片]", + "改图 等比压缩 [比例] [图片]", + "改图 旋转图片 [角度] [图片]", + "改图 水平翻转 [图片]", + "改图 铅笔滤镜 [图片]", + "改图 模糊效果 [图片]", + "改图 锐化效果 [图片]", + "改图 高斯模糊 [图片]", + "改图 边缘检测 [图片]", + "改图 底色替换 [红/蓝] [红/蓝/白/绿/黄] [图片]", +] +__plugin_type__ = ("一些工具", 1) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["修改图片", "改图", "操作图片"], +} # IMAGE_LOCAL = IMAGE_PATH + "temp/{}_update.png" method_flag = "" update_img = on_command( - "修改图片", aliases={"图片", "操作图片", "改图"}, priority=5, rule=to_me(), block=True + "修改图片", aliases={"操作图片", "改图"}, priority=5, rule=to_me(), block=True ) method_list = [ diff --git a/plugins/update_setu/__init__.py b/plugins/update_setu/__init__.py index e41622c3..48d86b75 100644 --- a/plugins/update_setu/__init__.py +++ b/plugins/update_setu/__init__.py @@ -8,37 +8,41 @@ from .data_source import update_setu_img from configs.config import DOWNLOAD_SETU -__plugin_name__ = "更新色图 [Hidden]" +__zx_plugin_name__ = "更新色图 [Superuser]" +__plugin_usage__ = """ +usage: + 更新数据库内存在的色图 + 指令: + 更新色图 +""".strip() +__plugin_cmd__ = ["更新色图"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_block_limit__ = { + "rst": "色图正在更新..." +} -__plugin_usage__ = '无' -exists_flag = False - -update_setu = on_command("更新色图", rule=to_me(), permission=SUPERUSER, priority=1, block=True) +update_setu = on_command( + "更新色图", rule=to_me(), permission=SUPERUSER, priority=1, block=True +) @update_setu.handle() async def _(bot: Bot, event: Event, state: T_State): - global exists_flag if DOWNLOAD_SETU: - if not exists_flag: - exists_flag = True - await update_setu.send("开始更新色图...", at_sender=True) - await update_setu.send(await update_setu_img(), at_sender=True) - exists_flag = False - else: - await update_setu.finish("色图正在更新....") + await update_setu.send("开始更新色图...", at_sender=True) + await update_setu.send(await update_setu_img(), at_sender=True) else: - await update_setu.finish('更新色图配置未开启') + await update_setu.finish("更新色图配置未开启") # 更新色图 @scheduler.scheduled_job( - 'cron', + "cron", hour=4, minute=30, ) async def _(): - global exists_flag - if DOWNLOAD_SETU and not exists_flag: + if DOWNLOAD_SETU: await update_setu_img() diff --git a/plugins/update_setu/data_source.py b/plugins/update_setu/data_source.py index fcc776a8..d50f852a 100644 --- a/plugins/update_setu/data_source.py +++ b/plugins/update_setu/data_source.py @@ -1,4 +1,4 @@ -from configs.path_config import IMAGE_PATH, TXT_PATH +from configs.path_config import IMAGE_PATH, TEXT_PATH from services.log import logger from datetime import datetime from utils.image_utils import compressed_image, get_img_hash @@ -20,9 +20,10 @@ driver: Driver = nonebot.get_driver() _path = Path(IMAGE_PATH) +# 替换旧色图数据,修复local_id一直是50的问题 @driver.on_startup async def update_old_setu_data(): - path = Path(TXT_PATH) + path = Path(TEXT_PATH) setu_data_file = path / "setu_data.json" r18_data_file = path / "r18_setu_data.json" if setu_data_file.exists() or r18_data_file.exists(): diff --git a/plugins/weather/__init__.py b/plugins/weather/__init__.py index f48c891b..075d9df6 100644 --- a/plugins/weather/__init__.py +++ b/plugins/weather/__init__.py @@ -7,8 +7,25 @@ from nonebot.typing import T_State import re from utils.utils import get_message_text -__plugin_name__ = "天气查询" -__plugin_usage__ = "普普通通的查天气吧\n示例:北京天气" + +__zx_plugin_name__ = "天气查询" +__plugin_usage__ = """ +usage: + 普普通通的查天气吧 + 指令: + [城市]天气/天气[城市] +""".strip() +__plugin_des__ = "出门要看看天气,不要忘了带伞" +__plugin_cmd__ = ["[城市]天气/天气[城市]"] +__plugin_type__ = ("一些工具",) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["查询天气", "天气", "天气查询", "查天气"], +} weather = on_regex(r".*?(.*)市?的?天气.*?", priority=5, block=True) diff --git a/plugins/weather/data_source.py b/plugins/weather/data_source.py index bb7806d4..0fd8bf27 100644 --- a/plugins/weather/data_source.py +++ b/plugins/weather/data_source.py @@ -1,7 +1,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.path_config import TEXT_PATH from configs.config import NICKNAME from asyncio.exceptions import TimeoutError from typing import List @@ -13,13 +13,9 @@ import nonebot driver: Driver = nonebot.get_driver() -china_city = Path(TXT_PATH) / "china_city.json" +china_city = Path(TEXT_PATH) / "china_city.json" -try: - with open(china_city, "r", encoding="utf8") as f: - data = json.load(f) -except FileNotFoundError: - data = {} +data = {} async def get_weather_of_city(city: str) -> str: @@ -93,6 +89,12 @@ def _check_exists_city(city: str) -> int: def get_city_list() -> List[str]: global data + if not data: + try: + with open(china_city, "r", encoding="utf8") as f: + data = json.load(f) + except FileNotFoundError: + data = {} city_list = [] for p in data.keys(): for c in data[p]: diff --git a/plugins/what_anime/__init__.py b/plugins/what_anime/__init__.py index 2758699f..b3f09e84 100644 --- a/plugins/what_anime/__init__.py +++ b/plugins/what_anime/__init__.py @@ -4,16 +4,26 @@ from nonebot.typing import T_State from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from utils.utils import get_message_imgs from services.log import logger -from utils.utils import UserExistLimiter -__plugin_name__ = "识番" -__plugin_usage__ = r""" -以图识番 -识番 [图片] +__zx_plugin_name__ = "识番" +__plugin_usage__ = """ +usage: + api.trace.moe 以图识番 + 指令: + 识番 [图片] """.strip() +__plugin_des__ = "以图识番" +__plugin_cmd__ = ["识番 [图片]"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["识番"], +} -_ulmt = UserExistLimiter() what_anime = on_command("识番", priority=5, block=True) @@ -32,8 +42,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): async def _(bot: Bot, event: MessageEvent, state: T_State): if str(event.get_message()) in ["帮助"]: await what_anime.finish(__plugin_usage__) - if _ulmt.check(event.user_id): - await what_anime.finish("您有识番任务正在进行,请稍等...", at_sender=True) img_url = get_message_imgs(event.json()) if img_url: state["img_url"] = img_url @@ -42,7 +50,6 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): @what_anime.got("img_url", prompt="虚空识番?来图来图GKD") async def _(bot: Bot, event: MessageEvent, state: T_State): img_url = state["img_url"][0] - _ulmt.set_true(event.user_id) await what_anime.send("开始识别.....") anime_data_report = await get_anime(img_url) if anime_data_report: @@ -58,4 +65,3 @@ async def _(bot: Bot, event: MessageEvent, state: T_State): f"{event.group_id if isinstance(event, GroupMessageEvent) else 'private'} 识番 {img_url} 未找到!!" ) await what_anime.send(f"没有寻找到该番剧,果咩..", at_sender=True) - _ulmt.set_false(event.user_id) diff --git a/plugins/white2black_img.py b/plugins/white2black_img.py index f56d304e..3519948b 100644 --- a/plugins/white2black_img.py +++ b/plugins/white2black_img.py @@ -23,9 +23,24 @@ from services.log import logger # RU2ZH_CN 俄语 » 中文 # SP2ZH_CN 西语 » 中文 -__plugin_name__ = "黑白草图" -__plugin_usage__ = "用法: \n\t黑白图 [文字] [图片]\n示例:黑白草图 没有人不喜欢萝莉 [图片]" +__zx_plugin_name__ = "黑白草图" +__plugin_usage__ = """ +usage: + 将图片黑白化并配上中文与日语 + 指令: + 黑白图 [文本] [图片] +""".strip() +__plugin_des__ = "为设想过得黑白草图" +__plugin_cmd__ = ["黑白图"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["黑白图", "黑白草图"], +} w2b_img = on_command("黑白草图", aliases={"黑白图"}, priority=5, block=True) diff --git a/plugins/withdraw.py b/plugins/withdraw.py index bc35b4c8..534f9adb 100644 --- a/plugins/withdraw.py +++ b/plugins/withdraw.py @@ -4,12 +4,27 @@ from nonebot.typing import T_State import re -withdraw_msg = on_command('撤回', priority=5, block=True) +__zx_plugin_name__ = "消息撤回 [Admin]" +__plugin_usage__ = """ +usage: + 简易的消息撤回机制 + 指令: + [回复]撤回 +""".strip() +__plugin_des__ = "消息撤回机制" +__plugin_cmd__ = ["[回复]撤回"] +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "admin_level": 0, +} + + +withdraw_msg = on_command("撤回", priority=5, block=True) @withdraw_msg.handle() async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - r = re.search(r'\[CQ:reply,id=(-?\d*)]', event.raw_message) + r = re.search(r"\[CQ:reply,id=(-?\d*)]", event.raw_message) if r: await bot.delete_msg(message_id=int(r.group(1)), self_id=int(bot.self_id)) - diff --git a/plugins/yiqing/__init__.py b/plugins/yiqing/__init__.py index e6cd27dc..760babb3 100644 --- a/plugins/yiqing/__init__.py +++ b/plugins/yiqing/__init__.py @@ -5,8 +5,29 @@ from nonebot.adapters.cqhttp import Bot, MessageEvent, GroupMessageEvent from nonebot.typing import T_State from utils.utils import get_message_text -__plugin_name__ = "疫情查询" -__plugin_usage__ = "查询疫情帮助:\n\t对我说 查询疫情 省份/城市,我会回复疫情的实时数据\n\t示例: 查询疫情 温州" + +__zx_plugin_name__ = "疫情查询" +__plugin_usage__ = """ +usage: + 全国疫情查询 + 指令: + 疫情 中国 + 疫情 [省份/城市] + * 当省份与城市重名时,可在后添加 “市” * + 示例:疫情 吉林 <- [省] + 示例:疫情 吉林市 <- [市] +""".strip() +__plugin_des__ = "实时疫情数据查询" +__plugin_cmd__ = ["疫情 [省份/城市]", "疫情 中国"] +__plugin_type__ = ('一些工具',) +__plugin_version__ = 0.1 +__plugin_author__ = "HibiKier" +__plugin_settings__ = { + "level": 5, + "default_status": True, + "limit_superuser": False, + "cmd": ["查询疫情", "疫情", "疫情查询"], +} yiqing = on_command("疫情", aliases={"查询疫情", "疫情查询"}, priority=5, block=True) diff --git a/plugins/yiqing/data_source.py b/plugins/yiqing/data_source.py index c3aed80a..ebb9a0b5 100644 --- a/plugins/yiqing/data_source.py +++ b/plugins/yiqing/data_source.py @@ -1,18 +1,14 @@ from utils.user_agent import get_user_agent -from configs.path_config import TXT_PATH +from configs.path_config import TEXT_PATH from configs.config import NICKNAME from typing import List from pathlib import Path import ujson as json import aiohttp -china_city = Path(TXT_PATH) / "china_city.json" +china_city = Path(TEXT_PATH) / "china_city.json" -try: - with open(china_city, "r", encoding="utf8") as f: - data = json.load(f) -except FileNotFoundError: - data = {} +data = {} url = "https://view.inews.qq.com/g2/getOnsInfo?name=disease_h5" @@ -23,16 +19,16 @@ async def get_yiqing_data(area: str): province = None city = None province_type = "省" - if area == '中国': + if area == "中国": province = area province_type = "" - elif area in data.keys() and area[-1] != '市': - province = area if area[-1] != '省' else area[:-1] + elif area in data.keys() and area[-1] != "市": + province = area if area[-1] != "省" else area[:-1] if len(data[province]) == 1: province_type = "市" city = "" else: - area = area[:-1] if area[-1] == '市' else area + area = area[:-1] if area[-1] == "市" else area for p in data.keys(): if area in data[p]: province = p @@ -55,7 +51,7 @@ async def get_yiqing_data(area: str): try: data_ = [x for x in data_["children"] if x["name"] == city][0] except IndexError: - return '未查询到...' + return "未查询到..." confirm = data_["total"]["confirm"] # 累计确诊 heal = data_["total"]["heal"] # 累计治愈 dead = data_["total"]["dead"] # 累计死亡 @@ -64,7 +60,7 @@ async def get_yiqing_data(area: str): now_confirm = data_["total"]["nowConfirm"] # 目前确诊 suspect = data_["total"]["suspect"] # 疑似 add_confirm = data_["today"]["confirm"] # 新增确诊 - x = f"{city}市" if city else f'{province}{province_type}' + x = f"{city}市" if city else f"{province}{province_type}" return ( f"{x} 疫情数据:\n" f"\t目前确诊:\n" @@ -83,6 +79,12 @@ async def get_yiqing_data(area: str): def get_city_list() -> List[str]: global data + if not data: + try: + with open(china_city, "r", encoding="utf8") as f: + data = json.load(f) + except FileNotFoundError: + data = {} city_list = [] for p in data.keys(): for c in data[p]: diff --git a/resources/img/background/0.png b/resources/img/background/0.png new file mode 100644 index 00000000..495111d4 Binary files /dev/null and b/resources/img/background/0.png differ diff --git a/resources/img/background/1.png b/resources/img/background/1.png new file mode 100644 index 00000000..21533f21 Binary files /dev/null and b/resources/img/background/1.png differ diff --git a/resources/img/background/create_mat/0.jpg b/resources/img/background/create_mat/0.jpg new file mode 100644 index 00000000..42d8be37 Binary files /dev/null and b/resources/img/background/create_mat/0.jpg differ diff --git a/resources/img/background/create_mat/1.jpg b/resources/img/background/create_mat/1.jpg new file mode 100644 index 00000000..72e1c661 Binary files /dev/null and b/resources/img/background/create_mat/1.jpg differ diff --git a/resources/img/background/create_mat/10.jpg b/resources/img/background/create_mat/10.jpg new file mode 100644 index 00000000..418ed808 Binary files /dev/null and b/resources/img/background/create_mat/10.jpg differ diff --git a/resources/img/background/create_mat/11.jpg b/resources/img/background/create_mat/11.jpg new file mode 100644 index 00000000..22535d58 Binary files /dev/null and b/resources/img/background/create_mat/11.jpg differ diff --git a/resources/img/background/create_mat/2.jpg b/resources/img/background/create_mat/2.jpg new file mode 100644 index 00000000..e970b9dc Binary files /dev/null and b/resources/img/background/create_mat/2.jpg differ diff --git a/resources/img/background/create_mat/3.jpg b/resources/img/background/create_mat/3.jpg new file mode 100644 index 00000000..924abb4d Binary files /dev/null and b/resources/img/background/create_mat/3.jpg differ diff --git a/resources/img/background/create_mat/4.jpg b/resources/img/background/create_mat/4.jpg new file mode 100644 index 00000000..639f5a86 Binary files /dev/null and b/resources/img/background/create_mat/4.jpg differ diff --git a/resources/img/background/create_mat/5.jpg b/resources/img/background/create_mat/5.jpg new file mode 100644 index 00000000..cb881c2f Binary files /dev/null and b/resources/img/background/create_mat/5.jpg differ diff --git a/resources/img/background/create_mat/6.jpg b/resources/img/background/create_mat/6.jpg new file mode 100644 index 00000000..aa33cc8d Binary files /dev/null and b/resources/img/background/create_mat/6.jpg differ diff --git a/resources/img/background/create_mat/7.jpg b/resources/img/background/create_mat/7.jpg new file mode 100644 index 00000000..0ae2766c Binary files /dev/null and b/resources/img/background/create_mat/7.jpg differ diff --git a/resources/img/background/create_mat/8.jpg b/resources/img/background/create_mat/8.jpg new file mode 100644 index 00000000..12b49fa7 Binary files /dev/null and b/resources/img/background/create_mat/8.jpg differ diff --git a/resources/img/background/create_mat/9.jpg b/resources/img/background/create_mat/9.jpg new file mode 100644 index 00000000..b6daafc0 Binary files /dev/null and b/resources/img/background/create_mat/9.jpg differ diff --git a/resources/img/background/help/simple_help/11.jpg b/resources/img/background/help/simple_help/11.jpg new file mode 100644 index 00000000..22535d58 Binary files /dev/null and b/resources/img/background/help/simple_help/11.jpg differ diff --git a/resources/img/background/help/simple_help/3.jpg b/resources/img/background/help/simple_help/3.jpg new file mode 100644 index 00000000..924abb4d Binary files /dev/null and b/resources/img/background/help/simple_help/3.jpg differ diff --git a/resources/img/background/help/simple_help/8.jpg b/resources/img/background/help/simple_help/8.jpg new file mode 100644 index 00000000..12b49fa7 Binary files /dev/null and b/resources/img/background/help/simple_help/8.jpg differ diff --git a/resources/ttf/HWXingKai.ttf b/resources/ttf/HWXingKai.ttf new file mode 100644 index 00000000..353ba6a9 Binary files /dev/null and b/resources/ttf/HWXingKai.ttf differ diff --git a/plugins/genshin/almanac/汉仪文黑.ttf b/resources/ttf/HWZhongSong.ttf similarity index 55% rename from plugins/genshin/almanac/汉仪文黑.ttf rename to resources/ttf/HWZhongSong.ttf index 891435dc..0f167cbd 100644 Binary files a/plugins/genshin/almanac/汉仪文黑.ttf and b/resources/ttf/HWZhongSong.ttf differ diff --git a/resources/ttf/HYWenHei-85W.ttf b/resources/ttf/HYWenHei-85W.ttf new file mode 100644 index 00000000..1ea57000 Binary files /dev/null and b/resources/ttf/HYWenHei-85W.ttf differ diff --git a/services/log.py b/services/log.py index fa2443ad..d870e320 100644 --- a/services/log.py +++ b/services/log.py @@ -21,6 +21,4 @@ logger.add( rotation='00:00', format=default_format, filter=default_filter, - retention=timedelta(days=30)) - - + retention=timedelta(days=30)) \ No newline at end of file diff --git a/update_info.json b/update_info.json index 4a729c57..560ff4dd 100644 --- a/update_info.json +++ b/update_info.json @@ -1,83 +1,12 @@ { "update_file": [ - "README.md", - "configs/config.py", - "configs/utils/init_config.py", - "models/ban_user.py", - "models/group_member_info.py", - "models/pixiv.py", - "models/russian_user.py", - "models/setu.py", - "models/omega_pixiv_illusts.py", - "plugins/admin_bot_manage", - "plugins/admin_help/__init__.py", - "plugins/ai/__init__.py", - "plugins/ai/data_source.py", - "plugins/alapi/wbtop.py", - "plugins/ban/__init__.py", - "plugins/bt/__init__.py", - "plugins/check_zhenxun_update/__init__.py", - "plugins/check_zhenxun_update/data_source.py", - "plugins/coser/__init__.py", - "plugins/draw_card/announcement.py", - "plugins/fudu.py", - "plugins/genshin/query_resource_points", - "plugins/group_handle/__init__.py", - "plugins/group_manager/__init__.py", - "plugins/help/config.py", - "plugins/help/data_source.py", - "plugins/hook.py", - "plugins/luxun/__init__.py", - "plugins/mute.py", - "plugins/one_friend/__init__.py", - "plugins/open_cases/__init__.py", - "plugins/open_cases/open_cases_c.py", - "plugins/parse_bilibili_json.py", - "plugins/pix_gallery/__init__.py", - "plugins/pix_gallery/data_source.py", - "plugins/pix_gallery/pix.py", - "plugins/pix_gallery/pix_show_info.py", - "plugins/pixiv/__init__.py", - "plugins/pixiv/data_source.py", - "plugins/reimu/__init__.py", - "plugins/russian/__init__.py", - "plugins/russian/data_source.py", - "plugins/search_anime/__init__.py", - "plugins/search_buff_skin_price/__init__.py", - "plugins/send_img/__init__.py", - "plugins/send_setu/__init__.py", - "plugins/send_setu/data_source.py", - "plugins/shop/gold_redbag/__init__.py", - "plugins/shop/use/data_source.py", - "plugins/sign_in/__init__.py", - "plugins/sign_in/group_user_checkin.py", - "plugins/statistics_hook.py", - "plugins/super_cmd/__init__.py", - "plugins/super_help/__init__.py", - "plugins/update_gocqhttp/__init__.py", - "plugins/what_anime/__init__.py", - "plugins/bilibili_sub", - "models/bilibili_sub.py", - "services/log.py", - "update_info.json", - "utils/browser.py", - "utils/image_utils.py", - "utils/message_builder.py", - "utils/static_data/__init__.py", - "utils/static_data/data_class.py", - "utils/static_data/group_manager.py", - "utils/utils.py", - "models/omega_pixiv_illusts.py", - "models/sign_group_user.py", - "plugins/bilibili_sub", - "models/bilibili_sub.py", - "plugins/database_scripts.py", - "plugins/sign_in/config.py", - "plugins/sign_in/random_event.py", - "plugins/sign_in/utils.py", - "plugins/withdraw.py", - "resources/img/sign" + "plugins", + "configs", + "models", + "services", + "utils", + "resources/ttf" ], - "add_file": [], - "delete_file": ["plugins/nonebot_plugin_withdraw", "models/sigin_group_user.py"] + "add_file": ["resources/img/background"], + "delete_file": [] } diff --git a/utils/image_utils.py b/utils/image_utils.py index 65208af4..fb4945eb 100644 --- a/utils/image_utils.py +++ b/utils/image_utils.py @@ -1,13 +1,16 @@ -from configs.path_config import IMAGE_PATH, TTF_PATH -from PIL import Image, ImageFile, ImageDraw, ImageFont +from configs.path_config import IMAGE_PATH, FONT_PATH +from PIL import Image, ImageFile, ImageDraw, ImageFont, ImageFilter from imagehash import ImageHash from io import BytesIO from matplotlib import pyplot as plt -from typing import Tuple, Optional, Union +from typing import Tuple, Optional, Union, List from pathlib import Path +from math import ceil +import random import cv2 import base64 import imagehash + ImageFile.LOAD_TRUNCATED_IMAGES = True Image.MAX_IMAGE_PIXELS = None @@ -143,11 +146,11 @@ class CreateImg: h: int, paste_image_width: int = 0, paste_image_height: int = 0, - color: Union[str, Tuple[int, int, int], Tuple[int, int, int, int]] = "white", + color: Union[str, Tuple[int, int, int], Tuple[int, int, int, int]] = None, image_mode: str = "RGBA", font_size: int = 10, - background: Union[Optional[str], BytesIO] = None, - ttf: str = "yz.ttf", + background: Union[Optional[str], BytesIO, Path] = None, + font: str = "yz.ttf", ratio: float = 1, is_alpha: bool = False, plain_text: Optional[str] = None, @@ -174,9 +177,13 @@ class CreateImg: self.paste_image_height = int(paste_image_height) self.current_w = 0 self.current_h = 0 - self.font = ImageFont.truetype(TTF_PATH + ttf, int(font_size)) + self.font = ImageFont.truetype(FONT_PATH + font, int(font_size)) + if not plain_text and not color: + color = (255, 255, 255) if not background: if plain_text: + if not color: + color = (255, 255, 255, 0) ttf_w, ttf_h = self.getsize(plain_text) self.w = self.w if self.w > ttf_w else ttf_w self.h = self.h if self.h > ttf_h else ttf_h @@ -204,7 +211,7 @@ class CreateImg: for i in range(w): for j in range(h): pos = array[i, j] - is_edit = (sum([1 for x in pos[0:3] if x > 240]) == 3) + is_edit = sum([1 for x in pos[0:3] if x > 240]) == 3 if is_edit: array[i, j] = (255, 255, 255, 0) self.draw = ImageDraw.Draw(self.markImg) @@ -302,7 +309,11 @@ class CreateImg: self.draw.ellipse(pos, fill, outline, width) def text( - self, pos: Tuple[int, int], text: str, fill: Tuple[int, int, int] = (0, 0, 0), center_type: Optional[str] = None + self, + pos: Tuple[int, int], + text: str, + fill: Tuple[int, int, int] = (0, 0, 0), + center_type: Optional[str] = None, ): """ 说明: @@ -320,23 +331,27 @@ class CreateImg: ) w, h = self.w, self.h ttf_w, ttf_h = self.getsize(text) - if center_type == 'center': + if center_type == "center": w = int((w - ttf_w) / 2) h = int((h - ttf_h) / 2) - elif center_type == 'by_width': + elif center_type == "by_width": w = int((w - ttf_w) / 2) - elif center_type == 'by_height': + h = pos[1] + elif center_type == "by_height": h = int((h - ttf_h) / 2) + w = pos[0] pos = (w, h) self.draw.text(pos, text, fill=fill, font=self.font) - def save(self, path: str): + def save(self, path: Union[str, Path]): """ 说明: 保存图片 参数: :param path: 图片路径 """ + if isinstance(path, Path): + path = path.absolute() self.markImg.save(path) def show(self): @@ -478,9 +493,519 @@ class CreateImg: pim_b[i - (r - r3), j - (r - r3)] = pim_a[i, j] self.markImg = imb + def circle_corner(self, radii: int = 30): + """ + 说明: + 矩形四角变圆 + 参数: + :param radii: 半径 + """ + # 画圆(用于分离4个角) + circle = Image.new('L', (radii * 2, radii * 2), 0) + draw = ImageDraw.Draw(circle) + draw.ellipse((0, 0, radii * 2, radii * 2), fill=255) + self.markImg = self.markImg.convert("RGBA") + w, h = self.markImg.size + alpha = Image.new('L', self.markImg.size, 255) + alpha.paste(circle.crop((0, 0, radii, radii)), (0, 0)) + alpha.paste(circle.crop((radii, 0, radii * 2, radii)), (w - radii, 0)) + alpha.paste(circle.crop((radii, radii, radii * 2, radii * 2)), (w - radii, h - radii)) + alpha.paste(circle.crop((0, radii, radii, radii * 2)), (0, h - radii)) + self.markImg.putalpha(alpha) + + def rotate(self, angle: int): + """ + 说明: + 旋转图片 + 参数: + :param angle: 角度 + """ + self.markImg = self.markImg.rotate(angle) + + def filter(self, filter_: str, aud: int = None): + """ + 图片变化 + :param filter_: 变化效果 + :param aud: 利率 + """ + _x = None + if filter_ == 'GaussianBlur': # 高斯模糊 + _x = ImageFilter.GaussianBlur + elif filter_ == 'EDGE_ENHANCE': # 锐化效果 + _x = ImageFilter.EDGE_ENHANCE + elif filter_ == 'BLUR': # 模糊效果 + _x = ImageFilter.BLUR + elif filter_ == 'CONTOUR': # 铅笔滤镜 + _x = ImageFilter.CONTOUR + elif filter_ == 'FIND_EDGES': # 边缘检测 + _x = ImageFilter.FIND_EDGES + if _x: + if aud: + self.markImg = self.markImg.filter(_x(aud)) + else: + self.markImg = self.markImg.filter(_x) + # - def getchannel(self, itype): - self.markImg = self.markImg.getchannel(itype) + def getchannel(self, type_): + self.markImg = self.markImg.getchannel(type_) + + +class CreateMat: + """ + 针对 折线图/柱状图,基于 CreateImg 编写的 非常难用的 自定义画图工具 + 目前仅支持 正整数 + """ + + def __init__( + self, + y: List[int], + mat_type: str = "line", + *, + x_name: Optional[str] = None, + y_name: Optional[str] = None, + x_index: List[Union[str, int, float]] = None, + y_index: List[Union[str, int, float]] = None, + title: Optional[str] = None, + size: Tuple[int, int] = (1000, 1000), + font_size: int = 20, + display_num: bool = False, + is_grid: bool = False, + background: Optional[List[str]] = None, + background_filler_type: Optional[str] = "center", + bar_color: Optional[List[Union[str, Tuple[int, int, int]]]] = None, + ): + """ + 说明: + 初始化 CreateMat + 参数: + :param y: 坐标值 + :param mat_type: 图像类型 可能的值:[line]: 折线图,[bar]: 柱状图,[barh]: 横向柱状图 + :param x_name: 横坐标名称 + :param y_name: 纵坐标名称 + :param x_index: 横坐标值 + :param y_index: 纵坐标值 + :param title: 标题 + :param size: 图像大小,建议默认 + :param font_size: 字体大小,建议默认 + :param display_num: 是否显示数值 + :param is_grid: 是否添加栅格 + :param background: 背景图片 + :param background_filler_type: 图像填充类型 + :param bar_color: 柱状图颜色,位 ['*'] 时替换位彩虹随机色 + """ + self.mat_type = mat_type + self.markImg = None + self._check_value(y, y_index) + self.w = size[0] + self.h = size[1] + self.y = y + self.x_name = x_name + self.y_name = y_name + self.x_index = x_index + self.y_index = y_index + self.title = title + self.font_size = font_size + self.display_num = display_num + self.is_grid = is_grid + self.background = background + self.background_filler_type = background_filler_type + self.bar_color = bar_color if bar_color else [(0, 0, 0)] + self.size = size + self.padding_w = 120 + self.padding_h = 120 + self.line_length = 760 + self._deviation = 0.905 + self._color = {} + if self.bar_color == ["*"]: + self.bar_color = [ + "#FF0000", + "#FF7F00", + "#FFFF00", + "#00FF00", + "#00FFFF", + "#0000FF", + "#8B00FF", + ] + if not x_index: + raise ValueError("缺少 x_index [横坐标值]...") + self._x_interval = int((self.line_length - 70) / len(x_index)) + self._bar_width = int( + (self.line_length - (len(x_index) * (10 if len(x_index) >= 18 else 25))) + / len(x_index) + ) + # 没有 y_index 时自动生成 + if not y_index: + _y_index = [] + _max_value = max(y) + _max_value = ceil( + _max_value / eval("1" + "0" * (len(str(_max_value)) - 1)) + ) * eval("1" + "0" * (len(str(_max_value)) - 1)) + _step = int(_max_value / 10) + for i in range(_step, _max_value + _step, _step): + _y_index.append(i) + self.y_index = _y_index + self._p = self.line_length / max(self.y_index) + self._y_interval = int((self.line_length - 70) / len(self.y_index)) + + def gen_graph(self): + """ + 说明: + 生成图像 + """ + self.markImg = self._init_graph( + x_name=self.x_name, + y_name=self.y_name, + x_index=self.x_index, + y_index=self.y_index, + font_size=self.font_size, + is_grid=self.is_grid, + ) + if self.mat_type == "line": + self._gen_line_graph(y=self.y, display_num=self.display_num) + elif self.mat_type == "bar": + self._gen_bar_graph(y=self.y, display_num=self.display_num) + elif self.mat_type == "barh": + self._gen_bar_graph(y=self.y, display_num=self.display_num, is_barh=True) + + def set_y(self, y: List[int]): + """ + 说明: + 给坐标点设置新值 + 参数: + :param y: 坐标点 + """ + self._check_value(y, self.y_index) + self.y = y + + def set_y_index(self, y_index: List[Union[str, int, float]]): + """ + 说明: + 设置y轴坐标值 + 参数: + :param y_index: y轴坐标值 + """ + self._check_value(self.y, y_index) + self.y_index = y_index + + def set_title(self, title: str, color: Optional[Union[str, Tuple[int, int, int]]]): + """ + 说明: + 设置标题 + 参数: + :param title: 标题 + :param color: 字体颜色 + """ + self.title = title + if color: + self._color["title"] = color + + def set_background( + self, background: Optional[List[str]], type_: Optional[str] = None + ): + """ + 说明: + 设置背景图片 + 参数: + :param background: 图片路径列表 + :param type_: 填充类型 + """ + self.background = background + self.background_filler_type = type_ if type_ else self.background_filler_type + + def show(self): + """ + 说明: + 展示图像 + """ + self.markImg.show() + + def pic2bs4(self) -> str: + """ + 说明: + 转base64 + """ + return self.markImg.pic2bs4() + + def resize(self, ratio: float = 0.9): + """ + 说明: + 调整图像大小 + 参数: + :param ratio: 比例 + """ + self.markImg.resize(ratio) + + def save(self, path: Union[str, Path]): + """ + 说明: + 保存图片 + 参数: + :param path: 路径 + """ + self.markImg.save(path) + + def _check_value( + self, + y: List[int], + y_index: List[Union[str, int, float]] = None, + x_index: List[Union[str, int, float]] = None, + ): + """ + 说明: + 检查值合法性 + 参数: + :param y: 坐标值 + :param y_index: y轴坐标值 + :param x_index: x轴坐标值 + """ + if y_index: + _value = x_index if self.mat_type == "barh" else y_index + if max(y) > max(y_index): + raise ValueError("坐标点的值必须小于y轴坐标的最大值...") + i = -9999999999 + for y in y_index: + if y > i: + i = y + else: + raise ValueError("y轴坐标值必须有序...") + + def _gen_line_graph( + self, + y: List[Union[int, float]], + display_num: bool = False, + ): + """ + 说明: + 生成折线图 + 参数: + :param y: 坐标点 + :param display_num: 显示该点的值 + """ + _black_point = CreateImg(7, 7, color=random.choice(self.bar_color)) + _black_point.circle() + x_interval = self._x_interval + current_w = self.padding_w + x_interval + current_h = self.padding_h + self.line_length + for i in range(len(y)): + if display_num: + w = int(self.markImg.getsize(str(y[i]))[0] / 2) + self.markImg.text( + ( + current_w - w, + current_h - int(y[i] * self._p * self._deviation) - 25, + ), + str(y[i]), + ) + self.markImg.paste( + _black_point, + ( + current_w - 3, + current_h - int(y[i] * self._p * self._deviation) - 3, + ), + True, + ) + if i != len(y) - 1: + self.markImg.line( + ( + current_w, + current_h - int(y[i] * self._p * self._deviation), + current_w + x_interval, + current_h - int(y[i + 1] * self._p * self._deviation), + ), + fill=(0, 0, 0), + width=2, + ) + current_w += x_interval + + def _gen_bar_graph( + self, + y: List[Union[int, float]], + display_num: bool = False, + is_barh: bool = False, + ): + """ + 说明: + 生成柱状图 + 参数: + :param y: 坐标值 + :param display_num: 是否显示数值 + :param is_barh: 横柱状图 + """ + _interval = self._x_interval + if is_barh: + current_h = self.padding_h + self.line_length - _interval + current_w = self.padding_w + else: + current_w = self.padding_w + _interval + current_h = self.padding_h + self.line_length + for i in range(len(y)): + if display_num: + if is_barh: + font_h = self.markImg.getsize(str(y[i]))[1] + self.markImg.text( + ( + self.padding_w + int(y[i] * self._p * self._deviation) + 2, + current_h - int(font_h / 2), + ), + str(y[i]), + ) + else: + w = int(self.markImg.getsize(str(y[i]))[0] / 2) + self.markImg.text( + ( + current_w - w, + current_h - int(y[i] * self._p * self._deviation) - 25, + ), + str(y[i]), + ) + if i != len(y): + bar_color = random.choice(self.bar_color) + if is_barh: + A = CreateImg( + int(y[i] * self._p * self._deviation), + self._bar_width, + color=bar_color, + ) + self.markImg.paste( + A, + ( + current_w + 2, + current_h - int(self._bar_width / 2), + ), + ) + else: + A = CreateImg( + self._bar_width, + int(y[i] * self._p * self._deviation), + color=bar_color, + ) + self.markImg.paste( + A, + ( + current_w - int(self._bar_width / 2), + current_h - int(y[i] * self._p * self._deviation), + ), + ) + if is_barh: + current_h -= _interval + else: + current_w += _interval + + def _init_graph( + self, + x_name: Optional[str] = None, + y_name: Optional[str] = None, + x_index: List[Union[str, int, float]] = None, + y_index: List[Union[str, int, float]] = None, + font_size: Optional[int] = None, + is_grid: bool = False, + ) -> CreateImg: + """ + 说明: + 初始化图像,生成xy轴 + 参数: + :param x_name: x轴名称 + :param y_name: y轴名称 + :param x_index: x轴坐标值 + :param y_index: y轴坐标值 + :param is_grid: 添加栅格 + """ + padding_w = self.padding_w + padding_h = self.padding_h + line_length = self.line_length + background = random.choice(self.background) if self.background else None + A = CreateImg(self.w, self.h, font_size=font_size, background=background) + if background: + _tmp = CreateImg(self.w, self.h) + _tmp.transparent(2) + A.paste(_tmp, alpha=True) + if self.title: + title = CreateImg( + 0, + 0, + plain_text=self.title, + color=(255, 255, 255, 0), + font_size=35, + font_color=self._color.get("title"), + ) + A.paste(title, (0, 25), True, "by_width") + A.line( + ( + padding_w, + padding_h + line_length, + padding_w + line_length, + padding_h + line_length, + ), + (0, 0, 0), + 2, + ) + A.line( + ( + padding_w, + padding_h, + padding_w, + padding_h + line_length, + ), + (0, 0, 0), + 2, + ) + _interval = self._x_interval + if self.mat_type == "barh": + tmp = x_index + x_index = y_index + y_index = tmp + _interval = self._y_interval + current_w = padding_w + _interval + _text_font = CreateImg(0, 0, font_size=self.font_size) + _grid = self.line_length if is_grid else 10 + for _x in x_index: + _p = CreateImg(1, _grid, color="#a9a9a9") + A.paste(_p, (current_w, padding_h + line_length - _grid)) + w = int(_text_font.getsize(f"{_x}")[0] / 2) + text = CreateImg( + 0, + 0, + plain_text=f"{_x}", + font_size=self.font_size, + color=(255, 255, 255, 0), + ) + A.paste(text, (current_w - w, padding_h + line_length + 10), alpha=True) + current_w += _interval + _interval = self._x_interval if self.mat_type == "barh" else self._y_interval + current_h = padding_h + line_length - _interval + _text_font = CreateImg(0, 0, font_size=self.font_size) + for _y in y_index: + _p = CreateImg(_grid, 1, color="#a9a9a9") + A.paste(_p, (padding_w, current_h)) + w, h = _text_font.getsize(f"{_y}") + h = int(h / 2) + text = CreateImg( + 0, + 0, + plain_text=f"{_y}", + font_size=self.font_size, + color=(255, 255, 255, 0), + ) + while text.size[0] > self.padding_w - 10: + text = CreateImg( + 0, + 0, + plain_text=f"{_y}", + font_size=int(self.font_size * 0.9), + color=(255, 255, 255, 0), + ) + w, _ = text.getsize(f"{_y}") + A.paste(text, (padding_w - w - 10, current_h - h), alpha=True) + current_h -= _interval + if x_name: + A.text((int(padding_w / 2), int(padding_w / 2)), x_name) + if y_name: + A.text( + (int(padding_w + line_length + 50), int(padding_h + line_length + 50)), + y_name, + ) + # A.show() + return A if __name__ == "__main__": diff --git a/utils/manager/__init__.py b/utils/manager/__init__.py new file mode 100644 index 00000000..f1db432d --- /dev/null +++ b/utils/manager/__init__.py @@ -0,0 +1,35 @@ +from typing import Optional +from .group_manager import GroupManager +from pathlib import Path +from .withdraw_message_manager import WithdrawMessageManager +from .plugins2cd_manager import Plugins2cdManager +from .plugins2block_manager import Plugins2blockManager +from .plugins2settings_manager import Plugins2settingsManager +from configs.path_config import DATA_PATH +from nonebot import Driver +import nonebot + +driver: Driver = nonebot.get_driver() + +# 群功能开关 | 群被动技能 | 群权限 管理 +group_manager: Optional[GroupManager] = GroupManager( + Path(DATA_PATH) / "manager" / "group_manager.json" +) +# 撤回消息管理 +withdraw_message_manager: Optional[WithdrawMessageManager] = WithdrawMessageManager() + +# 插件基本设置管理 +plugins2settings_manager: Optional[Plugins2settingsManager] = Plugins2settingsManager( + Path(DATA_PATH) / "configs" / "plugins2settings.yaml" +) + +# 插件命令 cd 管理 +plugins2cd_manager: Optional[Plugins2cdManager] = Plugins2cdManager( + Path(DATA_PATH) / "configs" / "plugins2cd.yaml" +) + +# 插件命令 阻塞 管理 +plugins2block_manager: Optional[Plugins2blockManager] = Plugins2blockManager( + Path(DATA_PATH) / "configs" / "plugins2block.yaml" +) + diff --git a/utils/manager/data_class.py b/utils/manager/data_class.py new file mode 100644 index 00000000..4c55a234 --- /dev/null +++ b/utils/manager/data_class.py @@ -0,0 +1,64 @@ +from typing import Union, Optional +from pathlib import Path +from ruamel.yaml import YAML +import ujson as json + +yaml = YAML(typ="safe") + + +class StaticData: + """ + 静态数据共享类 + """ + + def __init__(self, file: Optional[Path]): + self._data = {} + if file: + file.parent.mkdir(exist_ok=True, parents=True) + self.file = file + 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 keys(self): + return self._data.keys() + + def delete(self, key): + if self._data.get(key) is not None: + del self._data[key] + + def get_data(self): + return self._data + + 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(): + if self.file.name.endswith('json'): + self._data: dict = json.load(open(self.file, "r", encoding="utf8")) + elif self.file.name.endswith('yaml'): + self._data: dict = yaml.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/manager/group_manager.py b/utils/manager/group_manager.py new file mode 100644 index 00000000..f973b452 --- /dev/null +++ b/utils/manager/group_manager.py @@ -0,0 +1,319 @@ +from configs.config import DEFAULT_GROUP_LEVEL +from typing import Optional, List, Union, Dict +from pathlib import Path +from .data_class import StaticData +from utils.utils import get_matchers, get_bot +import nonebot + + +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": {}, + } + self._task = {} + + def block_plugin( + self, plugin_cmd: str, group_id: Optional[int] = 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[int] = None): + """ + 说明: + 解锁插件 + 参数: + :param plugin_cmd: 功能模块名 + :param group_id: 群组 + """ + self._set_plugin_status(plugin_cmd, "unblock", group_id) + + def set_group_level(self, group_id: int, level: int): + """ + 说明: + 设置群权限 + 参数: + :param group_id: 群组 + :param level: 权限等级 + """ + group_id = str(group_id) + 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[int] = None, block_type: str = "all" + ) -> bool: + """ + 说明: + 获取插件状态 + 参数: + :param plugin_cmd: 功能模块名 + :param group_id: 群组 + :param block_type: 限制类型 + """ + group_id = str(group_id) if group_id else group_id + 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: int) -> int: + """ + 说明: + 获取群等级 + 参数: + :param group_id: 群号 + """ + group_id = str(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 get_group_white_list(self) -> List[str]: + """ + 说明: + 获取所有群白名单 + """ + return self._data["super"]["white_group_list"] + + async def open_group_task(self, group_id: int, task: str): + """ + 开启群被动技能 + :param group_id: 群号 + :param task: 被动技能名称 + """ + await self._set_group_task_status(group_id, task, True) + + async def close_group_task(self, group_id: int, task: str): + """ + 关闭群被动技能 + :param group_id: 群号 + :param task: 被动技能名称 + """ + await self._set_group_task_status(group_id, task, False) + + async def check_group_task_status(self, group_id: int, task: str) -> bool: + """ + 查看群被动技能状态 + :param group_id: 群号 + :param task: 被动技能名称 + """ + group_id = str(group_id) + if ( + not self._data["group_manager"][group_id].get("group_task_status") + or self._data["group_manager"][group_id]["group_task_status"].get(task) + is None + ): + await self.init_group_task(group_id) + return self._data["group_manager"][group_id]["group_task_status"][task] + + def get_task_data(self) -> Dict[str, str]: + return self._task + + async def group_task_status(self, group_id: int) -> str: + """ + 查看群被全部动技能状态 + :param group_id: 群号 + """ + x = '[群被动技能]:\n' + group_id = str(group_id) + if not self._data["group_manager"][group_id].get("group_task_status"): + await self.init_group_task(group_id) + for key in self._data["group_manager"][group_id]["group_task_status"].keys(): + x += f'{self._task[key]}:{"√" if await self.check_group_task_status(int(group_id), key) else "×"}\n' + return x[:-1] + + async def _set_group_task_status(self, group_id: int, task: str, status: bool): + """ + 管理群被动技能状态 + :param group_id: 群号 + :param task: 被动技能 + :param status: 状态 + """ + group_id = str(group_id) + if not self._data["group_manager"].get(group_id): + self._init_group(group_id) + if ( + not self._data["group_manager"][group_id].get("group_task_status") + or self._data["group_manager"][group_id]["group_task_status"].get(task) + is None + ): + await self.init_group_task(group_id) + self._data["group_manager"][group_id]["group_task_status"][task] = status + self.save() + + async def init_group_task(self, group_id: Optional[Union[int, str]] = None): + """ + 初始化群聊 被动技能 状态 + """ + if not self._task: + for matcher in get_matchers(): + _plugin = nonebot.plugin.get_plugin(matcher.module) + _module = _plugin.module + try: + plugin_task = _module.__getattribute__("__plugin_task__") + for key in plugin_task.keys(): + self._task[key] = plugin_task[key] + except AttributeError: + pass + bot = get_bot() + if bot or group_id: + if group_id: + _group_list = [group_id] + else: + _group_list = [x["group_id"] for x in await bot.get_group_list()] + for group_id in _group_list: + group_id = str(group_id) + if not self._data["group_manager"].get(group_id): + self._init_group(group_id) + if not self._data["group_manager"][group_id].get("group_task_status"): + self._data["group_manager"][group_id]['group_task_status'] = {} + for task in self._task: + if ( + self._data["group_manager"][group_id][ + "group_task_status" + ].get(task) + is None + ): + self._data["group_manager"][group_id]["group_task_status"][ + task + ] = True + for task in self._data["group_manager"][group_id]["group_task_status"]: + if task not in self._task: + del self._data["group_manager"][group_id]["group_task_status"][ + task + ] + self.save() + + 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: 限制类型 + """ + group_id = str(group_id) if group_id else group_id + if plugin_cmd: + 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: 群号 + """ + if not self._data["group_manager"].get(group_id): + self._data["group_manager"][group_id] = { + "level": DEFAULT_GROUP_LEVEL, + "close_plugins": [], + "group_task_status": {}, + } diff --git a/utils/manager/plugins2block_manager.py b/utils/manager/plugins2block_manager.py new file mode 100644 index 00000000..f97cbf1a --- /dev/null +++ b/utils/manager/plugins2block_manager.py @@ -0,0 +1,132 @@ +from typing import Optional, Dict +from .data_class import StaticData +from services.log import logger +from utils.utils import UserBlockLimiter +from pathlib import Path +from ruamel.yaml import YAML + +yaml = YAML(typ="safe") + + +class Plugins2blockManager(StaticData): + """ + 插件命令阻塞 管理器 + """ + def __init__(self, file: Path): + self.file = file + super().__init__(None) + self._block_limiter: Dict[str, UserBlockLimiter] = {} + + def add_block_limit( + self, + plugin: str, + status: Optional[bool] = True, + check_type: Optional[str] = "all", + limit_type: Optional[str] = "user", + rst: Optional[str] = None, + data_dict: Optional[dict] = None, + ): + """ + 添加插件调用 block 限制 + :param plugin: 插件模块名称 + :param status: 默认开关状态 + :param check_type: 检查类型 'private'/'group'/'all',限制私聊/群聊/全部 + :param limit_type: 限制类型 监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id + :param rst: 回复的话,为空则不回复 + :param data_dict: 封装好的字典数据 + """ + if data_dict: + status = data_dict.get('status') + check_type = data_dict.get('check_type') + limit_type = data_dict.get('limit_type') + rst = data_dict.get('rst') + status = status if status is not None else True + check_type = check_type if check_type else 'all' + limit_type = limit_type if limit_type else 'user' + if check_type not in ["all", "group", "private"]: + raise ValueError( + f"{plugin} 添加block限制错误,‘check_type‘ 必须为 'private'/'group'/'all'" + ) + if limit_type not in ["user", "group"]: + raise ValueError(f"{plugin} 添加block限制错误,‘limit_type‘ 必须为 'user'/'group'") + self._data[plugin] = { + "status": status, + "check_type": check_type, + "limit_type": limit_type, + "rst": rst, + } + + def remove_block_limit(self, plugin: str): + """ + 删除一个插件 block 限制 + :param plugin: 插件模块名称 + """ + if self._data.get(plugin): + del self._data[plugin] + + def get_plugin_block_data(self, plugin: str) -> Optional[dict]: + """ + 获取插件block数据 + :param plugin: 模块名 + """ + if self.check_plugin_block_status(plugin): + return self._data[plugin] + return None + + def check_plugin_block_status(self, plugin: str) -> bool: + """ + 检测插件是否有 block + :param plugin: 模块名 + """ + return ( + plugin in self._data.keys() + and self._data[plugin]["status"] + ) + + def check(self, id_: int, plugin: str) -> bool: + """ + 检查 block + :param plugin: 模块名 + :param id_: 限制 id + """ + if self._block_limiter.get(plugin): + return self._block_limiter[plugin].check(id_) + return False + + def set_true(self, id_: int, plugin: str): + """ + 对插件 block + :param plugin: 模块名 + :param id_: 限制 id + """ + if self._block_limiter.get(plugin): + self._block_limiter[plugin].set_true(id_) + + def set_false(self, id_: int, plugin: str): + """ + 对插件 unblock + :param plugin: 模块名 + :param id_: 限制 id + """ + if self._block_limiter.get(plugin): + self._block_limiter[plugin].set_false(id_) + + def reload_block_limit(self): + """ + 加载 block 限制器 + :return: + """ + for plugin in self._data: + if self.check_plugin_block_status(plugin): + self._block_limiter[plugin] = UserBlockLimiter() + logger.info(f'已成功加载 {len(self._block_limiter)} 个Block限制.') + + def reload(self): + """ + 重载本地数据 + """ + if self.file.exists(): + with open(self.file, "r", encoding="utf8") as f: + self._data: dict = yaml.load(f) + self._data = self._data['PluginBlockLimit'] + self.reload_block_limit() diff --git a/utils/manager/plugins2cd_manager.py b/utils/manager/plugins2cd_manager.py new file mode 100644 index 00000000..8f557757 --- /dev/null +++ b/utils/manager/plugins2cd_manager.py @@ -0,0 +1,144 @@ +from typing import Optional, Dict +from .data_class import StaticData +from utils.utils import FreqLimiter +from services.log import logger +from pathlib import Path +from ruamel.yaml import YAML + +yaml = YAML(typ="safe") + + +class Plugins2cdManager(StaticData): + """ + 插件命令 cd 管理器 + """ + + def __init__(self, file: Path): + self.file = file + super().__init__(None) + self._freq_limiter: Dict[str, FreqLimiter] = {} + + def add_cd_limit( + self, + plugin: str, + *, + cd: Optional[int] = 5, + status: Optional[bool] = True, + check_type: Optional[str] = "all", + limit_type: Optional[str] = "user", + rst: Optional[str] = None, + data_dict: Optional[dict] = None, + ): + """ + 添加插件调用 cd 限制 + :param plugin: 插件模块名称 + :param cd: cd 时长 + :param status: 默认开关状态 + :param check_type: 检查类型 'private'/'group'/'all',限制私聊/群聊/全部 + :param limit_type: 限制类型 监听对象,以user_id或group_id作为键来限制,'user':用户id,'group':群id + :param rst: 回复的话,为空则不回复 + :param data_dict: 封装好的字典数据 + """ + if data_dict: + cd = data_dict.get('cd') + status = data_dict.get('status') + check_type = data_dict.get('check_type') + limit_type = data_dict.get('limit_type') + rst = data_dict.get('rst') + cd = cd if cd is not None else 5 + status = status if status is not None else True + check_type = check_type if check_type else 'all' + limit_type = limit_type if limit_type else 'user' + if check_type not in ["all", "group", "private"]: + raise ValueError( + f"{plugin} 添加cd限制错误,‘check_type‘ 必须为 'private'/'group'/'all'" + ) + if limit_type not in ["user", "group"]: + raise ValueError(f"{plugin} 添加cd限制错误,‘limit_type‘ 必须为 'user'/'group'") + self._data[plugin] = { + "cd": cd, + "status": status, + "check_type": check_type, + "limit_type": limit_type, + "rst": rst, + } + + def remove_cd_limit(self, plugin: str): + """ + 删除一个插件 cd 限制 + :param plugin: 插件模块名称 + """ + if self._data.get(plugin): + del self._data[plugin] + + def get_plugin_cd_data(self, plugin: str) -> Optional[dict]: + """ + 获取插件cd数据 + :param plugin: 模块名 + """ + if self.check_plugin_cd_status(plugin): + return self._data[plugin] + return None + + def check_plugin_cd_status(self, plugin: str) -> bool: + """ + 检测插件是否有 cd + :param plugin: 模块名 + """ + return ( + plugin in self._data.keys() + and self._data[plugin]["cd"] > 0 + and self._data[plugin]["status"] + ) + + def check(self, plugin: str, id_: int) -> bool: + """ + 检查 cd + :param plugin: 模块名 + :param id_: 限制 id + """ + if self._freq_limiter.get(plugin): + return self._freq_limiter[plugin].check(id_) + return False + + def start_cd(self, plugin: str, id_: int, cd: int = 0): + """ + 开始cd + :param plugin: 模块名 + :param id_: cd 限制类型 + :param cd: cd 时长 + :return: + """ + if self._freq_limiter.get(plugin): + self._freq_limiter[plugin].start_cd(id_, cd) + + def get_plugin_data(self, plugin: str) -> dict: + """ + 获取单个模块限制数据 + :param plugin: 模块名 + """ + if self._data.get(plugin) is not None: + return self._data.get(plugin) + return {} + + def reload_cd_limit(self): + """ + 加载 cd 限制器 + :return: + """ + for plugin in self._data: + if self.check_plugin_cd_status(plugin): + self._freq_limiter[plugin] = FreqLimiter(self.get_plugin_cd_data(plugin)['cd']) + logger.info(f'已成功加载 {len(self._freq_limiter)} 个Cd限制.') + + def reload(self): + """ + 重载本地数据 + """ + if self.file.exists(): + with open(self.file, "r", encoding="utf8") as f: + self._data: dict = yaml.load(f) + self._data = self._data['PluginCdLimit'] + self.reload_cd_limit() + + diff --git a/utils/manager/plugins2settings_manager.py b/utils/manager/plugins2settings_manager.py new file mode 100644 index 00000000..d4183b40 --- /dev/null +++ b/utils/manager/plugins2settings_manager.py @@ -0,0 +1,102 @@ +from typing import List, Optional, Union, Tuple +from .data_class import StaticData +from pathlib import Path +from ruamel.yaml import YAML + +yaml = YAML(typ="safe") + + +class Plugins2settingsManager(StaticData): + """ + 插件命令阻塞 管理器 + """ + + def __init__(self, file: Path): + self.file = file + super().__init__(None) + + def add_plugin_settings( + self, + plugin: str, + cmd: Optional[List[str]] = None, + default_status: Optional[bool] = True, + level: Optional[int] = 5, + limit_superuser: Optional[bool] = False, + plugin_type: Tuple[Union[str, int]] = ("normal",), + data_dict: Optional[dict] = None, + ): + """ + 添加一个插件设置 + :param plugin: 插件模块名称 + :param cmd: 命令 或 命令别名 + :param default_status: 默认开关状态 + :param level: 功能权限等级 + :param limit_superuser: 功能状态是否限制超级用户 + :param plugin_type: 插件类型 + :param data_dict: 封装好的字典数据 + """ + if data_dict: + level = data_dict.get("level") if data_dict.get("level") is not None else 5 + default_status = ( + data_dict.get("default_status") + if data_dict.get("default_status") is not None + else True + ) + limit_superuser = ( + data_dict.get("limit_superuser") + if data_dict.get("limit_superuser") is not None + else False + ) + cmd = data_dict.get("cmd") if data_dict.get("cmd") is not None else [] + self._data[plugin] = { + "level": level if level is not None else 5, + "default_status": default_status if default_status is not None else True, + "limit_superuser": limit_superuser + if limit_superuser is not None + else False, + "cmd": cmd, + "plugin_type": list(plugin_type if plugin_type is not None else ("normal",)) + } + + def remove_plugin_settings(self, plugin: str): + """ + 删除一个插件设置 + :param plugin: 插件模块名称 + """ + if self._data.get(plugin): + del self._data[plugin] + + def get_plugin_data(self, module: str) -> dict: + """ + 通过模块名获取数据 + :param module: 模块名称 + """ + if self._data.get(module) is not None: + return self._data.get(module) + return {} + + def get_plugin_module( + self, cmd: str, is_all: bool = False + ) -> Union[str, List[str]]: + """ + 根据 cmd 获取功能 module + :param cmd: 命令 + :param is_all: 获取全部包含cmd的模块 + """ + keys = [] + for key in self._data.keys(): + if cmd in self._data[key]["cmd"]: + if is_all: + keys.append(key) + else: + return key + return keys + + def reload(self): + """ + 重载本地数据 + """ + if self.file.exists(): + with open(self.file, "r", encoding="utf8") as f: + self._data: dict = yaml.load(f) + self._data = self._data['PluginSettings'] diff --git a/utils/manager/withdraw_message_manager.py b/utils/manager/withdraw_message_manager.py new file mode 100644 index 00000000..fa7482cc --- /dev/null +++ b/utils/manager/withdraw_message_manager.py @@ -0,0 +1,28 @@ +from typing import Tuple, Union, Dict + + +class WithdrawMessageManager: + + def __init__(self): + self.data = [] + + def append(self, message_data: Tuple[Union[int, Dict[str, int]], int]): + """ + 说明: + 添加一个撤回消息id和时间 + 参数: + :param message_data: 撤回消息id和时间 + """ + if isinstance(message_data[0], dict): + message_data = (message_data[0]['message_id'], message_data[1]) + self.data.append(message_data) + + def remove(self, message_data: Tuple[int, int]): + """ + 说明: + 删除一个数据 + 参数: + :param message_data: 消息id和时间 + """ + self.data.remove(message_data) + diff --git a/utils/message_builder.py b/utils/message_builder.py index f6135741..c66230bf 100644 --- a/utils/message_builder.py +++ b/utils/message_builder.py @@ -8,7 +8,7 @@ import os def image( img_name: Union[str, Path] = None, path: str = None, abspath: str = None, b64: str = None -) -> MessageSegment or str: +) -> Union[MessageSegment, str]: """ 说明: 生成一个 MessageSegment.image 消息 @@ -25,11 +25,14 @@ def image( if os.path.exists(abspath) else "" ) + elif isinstance(img_name, Path): + if img_name.exists(): + return MessageSegment.image(f"file:///{img_name.absolute()}") + logger.warning(f"图片 {img_name.absolute()}缺失...") + return "" elif b64: return MessageSegment.image(b64 if "base64://" in b64 else "base64://" + b64) else: - # if isinstance(img_name, Path): - # return MessageSegment.image(img_name) if "http" in img_name: return MessageSegment.image(img_name) if len(img_name.split(".")) == 1: diff --git a/utils/static_data/__init__.py b/utils/static_data/__init__.py deleted file mode 100644 index c400aadf..00000000 --- a/utils/static_data/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -from typing import Optional -from .group_manager import GroupManager -from pathlib import Path -from .data_source import init -from .data_class import StaticData - -# 群管理 -group_manager: Optional[GroupManager] = GroupManager( - Path() / "data" / "manager" / "group_manager.json" -) - -withdraw_message_id_manager: Optional[StaticData] = StaticData(None) - -init(group_manager) diff --git a/utils/static_data/data_class.py b/utils/static_data/data_class.py deleted file mode 100644 index 0915b788..00000000 --- a/utils/static_data/data_class.py +++ /dev/null @@ -1,52 +0,0 @@ -from typing import Union, Optional -from pathlib import Path -import ujson as json - - -class StaticData: - """ - 静态数据共享类 - """ - - def __init__(self, file: Optional[Path]): - self.data = {} - if file: - file.parent.mkdir(exist_ok=True, parents=True) - self.file = file - 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 deleted file mode 100644 index 75ce71cc..00000000 --- a/utils/static_data/data_source.py +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index 6f16744e..00000000 --- a/utils/static_data/group_manager.py +++ /dev/null @@ -1,196 +0,0 @@ -from configs.config import DEFAULT_GROUP_LEVEL -from typing import Optional, List -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 get_group_white_list(self) -> List[str]: - """ - 说明: - 获取所有群白名单 - """ - return self.data['super']['white_group_list'] - - 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": DEFAULT_GROUP_LEVEL, "close_plugins": []} - - diff --git a/utils/utils.py b/utils/utils.py index 51d082fb..6d6d32ce 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -1,10 +1,11 @@ from datetime import datetime, timedelta from collections import defaultdict from nonebot import require -from configs.path_config import TXT_PATH +from configs.path_config import TEXT_PATH from configs.config import SYSTEM_PROXY -from typing import List, Union, Optional -from nonebot.adapters import Bot +from typing import List, Union, Optional, Type +from nonebot.adapters.cqhttp import Bot +from nonebot.matcher import matchers, Matcher import nonebot import pytz import pypinyin @@ -39,7 +40,7 @@ class CountLimiter: return False -class UserExistLimiter: +class UserBlockLimiter: """ 检测用户是否正在调用命令 """ @@ -180,6 +181,17 @@ def get_bot() -> Optional[Bot]: return None +def get_matchers() -> List[Type[Matcher]]: + """ + 获取所有插件 + """ + _matchers = [] + for i in matchers.keys(): + for matcher in matchers[i]: + _matchers.append(matcher) + return _matchers + + def get_message_at(data: str) -> List[int]: """ 说明: @@ -187,12 +199,15 @@ def get_message_at(data: str) -> List[int]: 参数: :param data: event.json() """ - qq_list = [] - data = json.loads(data) - for msg in data["message"]: - if msg["type"] == "at": - qq_list.append(int(msg["data"]["qq"])) - return qq_list + try: + qq_list = [] + data = json.loads(data) + for msg in data["message"]: + if msg["type"] == "at": + qq_list.append(int(msg["data"]["qq"])) + return qq_list + except KeyError: + return [] def get_message_imgs(data: str) -> List[str]: @@ -202,12 +217,15 @@ def get_message_imgs(data: str) -> List[str]: 参数: :param data: event.json() """ - img_list = [] - data = json.loads(data) - for msg in data["message"]: - if msg["type"] == "image": - img_list.append(msg["data"]["url"]) - return img_list + try: + img_list = [] + data = json.loads(data) + for msg in data["message"]: + if msg["type"] == "image": + img_list.append(msg["data"]["url"]) + return img_list + except KeyError: + return [] def get_message_text(data: str) -> str: @@ -217,12 +235,15 @@ def get_message_text(data: str) -> str: 参数: :param data: event.json() """ - data = json.loads(data) - result = "" - for msg in data["message"]: - if msg["type"] == "text": - result += msg["data"]["text"].strip() + " " - return result.strip() + try: + data = json.loads(data) + result = "" + for msg in data["message"]: + if msg["type"] == "text": + result += msg["data"]["text"].strip() + " " + return result.strip() + except KeyError: + return "" def get_message_record(data: str) -> List[str]: @@ -232,12 +253,15 @@ def get_message_record(data: str) -> List[str]: 参数: :param data: event.json() """ - record_list = [] - data = json.loads(data) - for msg in data["message"]: - if msg["type"] == "record": - record_list.append(msg["data"]["url"]) - return record_list + try: + record_list = [] + data = json.loads(data) + for msg in data["message"]: + if msg["type"] == "record": + record_list.append(msg["data"]["url"]) + return record_list + except KeyError: + return [] def get_message_json(data: str) -> List[dict]: @@ -247,12 +271,15 @@ def get_message_json(data: str) -> List[dict]: 参数: :param data: event.json() """ - json_list = [] - data = json.loads(data) - for msg in data["message"]: - if msg["type"] == "json": - json_list.append(msg["data"]) - return json_list + try: + json_list = [] + data = json.loads(data) + for msg in data["message"]: + if msg["type"] == "json": + json_list.append(msg["data"]) + return json_list + except KeyError: + return [] # 获取文本加密后的cookie @@ -263,7 +290,7 @@ def get_cookie_text(cookie_name: str) -> str: 参数: :param cookie_name: cookie文件名称 """ - with open(TXT_PATH + "cookie/" + cookie_name + ".txt", "r") as f: + with open(TEXT_PATH + "cookie/" + cookie_name + ".txt", "r") as f: return f.read() @@ -335,11 +362,9 @@ def change_picture_links(url: str, mode: str): :param url: 图片原图链接 :param mode: 模式 """ - if mode == 'master': - img_sp = url.rsplit('.', maxsplit=1) + if mode == "master": + img_sp = url.rsplit(".", maxsplit=1) url = img_sp[0] img_type = img_sp[1] - url = url.replace('original', 'master') + f'_master1200.{img_type}' + url = url.replace("original", "master") + f"_master1200.{img_type}" return url - -