コード例 #1
0
ファイル: server.py プロジェクト: MeetWq/mybot
async def blrec_handler(
    event: Union[LiveBeganEvent, LiveEndedEvent, RecordingStartedEvent]
):
    logger.info(str(event))
    room_info = event.data.room_info
    uid = str(room_info.uid)

    if isinstance(event, RecordingStartedEvent):

        key = f"{uid}_record"
        if key in uid_cache:
            logger.warning(f"skip send msg for {key}")
            return

        info = get_sub_info_by_uid(uid)
        if info:
            await send_record_msg(uid, f"{info['up_name']} 录播启动...")
            uid_cache[key] = True
    else:

        key = f"{uid}_live"
        if key in uid_cache:
            logger.warning(f"skip send msg for {key}")
            return

        user_info = event.data.user_info
        live_info = LiveInfo(user_info, room_info)
        live_msg = await live_info.format_msg()
        if live_msg:
            await send_live_msg(uid, live_msg)
            uid_cache[key] = True
コード例 #2
0
    async def _handle_http(self, adapter: str):
        request: Request = _request

        try:
            data: Dict[str, Any] = await request.get_json()
        except Exception as e:
            raise exceptions.BadRequest()

        if adapter not in self._adapters:
            logger.warning(f'Unknown adapter {adapter}. '
                           'Please register the adapter before use.')
            raise exceptions.NotFound()

        BotClass = self._adapters[adapter]
        headers = {k: v for k, v in request.headers.items(lower=True)}

        try:
            self_id = await BotClass.check_permission(self, 'http', headers,
                                                      data)
        except RequestDenied as e:
            raise exceptions.HTTPException(status_code=e.status_code,
                                           description=e.reason,
                                           name='Request Denied')
        if self_id in self._clients:
            logger.warning("There's already a reverse websocket connection,"
                           "so the event may be handled twice.")
        bot = BotClass('http', self_id)
        asyncio.create_task(bot.handle_message(data))
        return Response('', 204)
コード例 #3
0
ファイル: comic.py プロジェクト: zangxx66/cheruBot
async def comic_scheduler():
    if nonebot.get_bots():
        bot = list(nonebot.get_bots().values())[0]
    else:
        logger.warning('未连接任何ws对象')
        return
    index_api = 'https://comic.priconne-redive.jp/api/index'
    index = load_index()

    resp = await aiorequests.get(index_api, timeout=10)
    data = await resp.json()
    id_ = data['latest_cartoon']['id']
    episode = data['latest_cartoon']['episode_num']
    title = data['latest_cartoon']['title']

    if episode in index:
        qs = urlparse(index[episode]['link']).query
        old_id = parse_qs(qs)['id'][0]
        if id_ == old_id:
            logger.info('未检测到官漫更新')
            return

    await download_comic(id_)
    pic = res.img('priconne/comic', get_pic_name(episode)).cqcode
    msg = f'プリンセスコネクト!Re:Dive公式4コマ更新!\n第{episode}話 {title}\n{pic}'
    await helper.broadcast(bot, msg, '官漫', 0.5)
コード例 #4
0
ファイル: news.py プロジェクト: zangxx66/cheruBot
async def news_scheduler():
    if nonebot.get_bots():
        bot = list(nonebot.get_bots().values())[0]
    else:
        logger.warning('未连接任何ws对象')
        return
    await news_poller(bot, BiliSpider, 'B服新闻')
コード例 #5
0
ファイル: little_helper.py プロジェクト: muguangAA/qqBot
async def jp_to_jp_dict(session: nonebot.CommandSession):
    ctx = session.ctx.copy()
    if user_control_module.get_user_privilege(ctx['user_id'], perm.BANNED):
        await session.finish('略略略,我主人把你拉黑了。哈↑哈↑哈')

    key_word = session.get('key_word', prompt='请输入一个关键字!')
    goo_api = None
    try:
        goo_api = youdao.Goodict(keyWord=key_word)
    except Exception as e:
        logger.warning('something went wrong in jptojpdict %s' % e)
        await session.finish('悲!连接出错惹')

    result, okay_or_not = goo_api.get_title_string()
    if okay_or_not:
        number = session.get('number', prompt='%s\n请输入要查询的部分的序号!' % result)
        try:
            number = int(number)
        except ValueError:
            await session.send('序号出错!')
            return

        goo_api.get_list(index=number)
        result = goo_api.get_explaination()
        await session.send('你查询的关键字%s的结果如下:\n%s' % (key_word, result))

    else:
        await session.send('出大错惹!!尝试新算法中……')
        goo_api.get_list(index=0, page='exception')
        result = goo_api.get_explaination()
        await session.send('你查询的关键字%s的结果如下:\n%s' % (key_word, result))
コード例 #6
0
ファイル: youdao.py プロジェクト: muguangAA/qqBot
 def _getPage(self):
     try:
         page = requests.get(self.baseUrl, headers=headers, timeout=10)
     except Exception as e:
         logger.warning('出问题啦!%s' % e)
         return ''
     return page.text
コード例 #7
0
    def _load_plugin(module_info) -> Optional[Plugin]:
        _tmp_matchers.set(set())
        _export.set(Export())
        name = module_info.name
        if name.startswith("_"):
            return None

        spec = module_info.module_finder.find_spec(name, None)
        if not spec:
            logger.warning(
                f"Module {name} cannot be loaded! Check module name first.")
        elif spec.name in plugins:
            return None
        elif spec.name in sys.modules:
            logger.warning(
                f"Module {spec.name} has been loaded by other plugin! Ignored")
            return None

        try:
            module = _load(spec)

            for m in _tmp_matchers.get():
                m.module = name
            plugin = Plugin(name, module, _tmp_matchers.get(), _export.get())
            plugins[name] = plugin
            logger.opt(
                colors=True).info(f'Succeeded to import "<y>{name}</y>"')
            return plugin
        except Exception as e:
            logger.opt(colors=True, exception=e).error(
                f'<r><bg #f8bbd0>Failed to import "{name}"</bg #f8bbd0></r>')
            return None
コード例 #8
0
async def get_dynamic_screenshot(url: str) -> Optional[bytes]:
    try:
        async with get_new_page(
            viewport={"width": 392, "height": 30},
            user_agent="Mozilla/5.0 (Linux; Android 11; Redmi K20 Pro Premium Edition) "
            "AppleWebKit/537.36 (KHTML, like Gecko) "
            "Chrome/96.0.4664.55 Mobile Safari/537.36 EdgA/96.0.1054.41",
            device_scale_factor=2.75,
        ) as page:
            await page.goto(url, wait_until="networkidle", timeout=10000)
            content = await page.content()
            content = content.replace(
                '<div class="dyn-header__right">'
                '<div data-pos="follow" class="dyn-header__following">'
                '<span class="dyn-header__following__icon"></span>'
                '<span class="dyn-header__following__text">关注</span></div></div>',
                "",
            )
            await page.set_content(content)
            card = await page.query_selector(".dyn-card")
            if card:
                clip = await card.bounding_box()
                if clip:
                    img = await page.screenshot(clip=clip, full_page=True)
                    return img
    except Exception as e:
        logger.warning(f"Error in get_dynamic_screenshot({url}): {e}")
        return None
コード例 #9
0
async def handle_image(bot: Bot, event: Event, state: dict):
    message = str(event.get_message())

    images = await get_data(message)
    # TODO 使用抛出异常的方式统一处理,避免使用独立的异常处理逻辑
    if type(images) is list and len(images):
        logger.info(f'[{message}] images count: {len(images)}')
        reply_image = random.choice(images)
        # logger.info(f'reply_image: {reply_image}')
        # 使用 objURL 时,图片可能会不存在,不知道百度搜图这个操作啥意思 _(:3J∠)_
        # 可能是由于百度会从源地址去下载原图,但是原图不存在的问题
        obj_url = reply_image['objURL']
        middle_url = reply_image['middleURL']
        logger.info(f'obj_url: {obj_url}')
        logger.info(f'middle_url: {middle_url}')
        try:
            # await image.finish(f'[CQ:image,file={escape(reply_image)}]') # 通过字符串暂时无法发送带有特殊符号的图片链接
            await image.finish(get_message(event, obj_url))
            logger.info(f'reply obj_url: {obj_url}')
        except exception.ActionFailed:
            logger.warning(f'reply obj_url failed, retry by middle_url')
            await image.finish(get_message(event, middle_url))
    else:
        logger.info(f'[{message}] no images')
        await image.finish(f'未找到 [{message}] 相关图片 _(:3J∠)_')
コード例 #10
0
ファイル: bilibili_live.py プロジェクト: muguangAA/qqBot
    def _get_live_info(self) -> (bool, dict):
        live_temp_dict = {}
        try:
            page = requests.get(self.api_url, timeout=5)
        except HTTPSConnectionPool as err:
            logging.warning(
                f'Uncaught error while fetching bilibili live for {self.ch_name}: {err}'
            )
            return False, {}

        if not page.status_code == 200:
            logging.warning(
                f'API connection failed to bilibili live room update for {self.ch_name}'
            )
            return False, {}

        json_result = page.json()
        live_stat = json_result['data']['live_status']
        if live_stat == 1:
            info = get_info_in_json(json_result, self.ch_name)
            live_temp_dict[self.ch_name] = info
            return True, live_temp_dict

        else:
            return False, {}
コード例 #11
0
async def get_mcmodel(uuid: str) -> Optional[BytesIO]:
    skin_bytes = await get_crafatar("skin", uuid)
    cape_bytes = await get_crafatar("cape", uuid)
    if not skin_bytes:
        return None
    skin = f"data:image/png;base64,{base64.b64encode(skin_bytes).decode()}"
    cape = (
        f"data:image/png;base64,{base64.b64encode(cape_bytes).decode()}"
        if cape_bytes
        else ""
    )

    try:
        template = env.get_template("skin.html")
        html = await template.render_async(skin=skin, cape=cape)

        images = []
        async with get_new_page(viewport={"width": 200, "height": 400}) as page:
            await page.set_content(html)
            await asyncio.sleep(0.1)
            for i in range(60):
                image = await page.screenshot(full_page=True)
                images.append(Image.open(BytesIO(image)))

        output = BytesIO()
        imageio.mimsave(output, images, format="gif", duration=0.05)
        return output
    except:
        logger.warning(traceback.format_exc())
        return None
コード例 #12
0
ファイル: plugin.py プロジェクト: ffreemt/nonebot2
def load_plugin(module_path: str) -> Optional[Plugin]:
    """
    :说明:
      使用 ``importlib`` 加载单个插件,可以是本地插件或是通过 ``pip`` 安装的插件。
    :参数:
      * ``module_path: str``: 插件名称 ``path.to.your.plugin``
    :返回:
      - ``Optional[Plugin]``
    """
    try:
        _tmp_matchers.clear()
        if module_path in plugins:
            return plugins[module_path]
        elif module_path in sys.modules:
            logger.warning(
                f"Module {module_path} has been loaded by other plugins! Ignored"
            )
            return
        module = importlib.import_module(module_path)
        for m in _tmp_matchers:
            m.module = module_path
        plugin = Plugin(module_path, module, _tmp_matchers.copy())
        plugins[module_path] = plugin
        logger.opt(
            colors=True).info(f'Succeeded to import "<y>{module_path}</y>"')
        return plugin
    except Exception as e:
        logger.opt(colors=True, exception=e).error(
            f'<r><bg #f8bbd0>Failed to import "{module_path}"</bg #f8bbd0></r>')
        return None
コード例 #13
0
async def get_voice(text: str) -> Optional[Union[str, BytesIO]]:
    url = (
        f"http://{mb_config.mockingbird_ip}:{mb_config.mockingbird_port}/api/synthesize"
    )
    files = {"file": recoder}
    try:
        texts = split_text(cn2an.transform(text, "an2cn"))
        sound = AudioSegment.silent(10)
        for t in texts:
            if len(t) > 50:
                return "连续文字过长,请用标点符号分割"
            data = {"text": t, "vocoder": "HifiGAN"}
            async with httpx.AsyncClient() as client:
                resp = await client.post(url,
                                         data=data,
                                         files=files,
                                         timeout=20)
                result = resp.content
            sound += AudioSegment.from_file(
                BytesIO(result)) + AudioSegment.silent(200)
        output = BytesIO()
        sound.export(output, format="wav")
        return output
    except:
        logger.warning(traceback.format_exc())
        return None
コード例 #14
0
async def search_by_image(img_url) -> Optional[Union[str, Message]]:
    url = "https://saucenao.com/search.php"
    params = {
        "url": img_url,
        "numres": 1,
        "testmode": 1,
        "db": 5,
        "output_type": 2,
        "api_key": pixiv_config.saucenao_apikey,
    }
    headers = {
        "User-Agent":
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "none",
        "Sec-Fetch-User": "******",
        "Referer": url,
        "Origin": "https://saucenao.com",
        "Host": "saucenao.com",
    }
    try:
        async with httpx.AsyncClient() as client:
            resp = await client.post(url,
                                     params=params,
                                     headers=headers,
                                     timeout=20)
            result = resp.json()

        if result["header"]["status"] == -1:
            logger.warning(
                f"post saucenao failed:{result['header']['message']}")
            return None

        if result["header"]["status"] == -2:
            return "24小时内搜索次数到达上限!"

        if "results" not in result or not result["results"]:
            return "找不到相似的图片"

        res = result["results"][0]
        header = res["header"]
        data = res["data"]
        thumb_url = header["thumbnail"]

        msg = (f"搜索到如下结果:\n"
               f"相似度:{header['similarity']}%\n"
               f"题目:{data['title']}\n"
               f"pixiv id:{data['pixiv_id']}\n"
               f"作者:{data['member_name']}\n"
               f"作者id:{data['member_id']}\n"
               f"链接:{', '.join(data['ext_urls'])}")
    except Exception as e:
        logger.warning(f"Error in search_by_image({url}): {e}")
        return None

    msgs = Message()
    msgs.append(msg)
    msgs.append(MessageSegment.image(thumb_url))
    return msgs
コード例 #15
0
    async def _handle_http(self, adapter: str, request: Request):
        data = await request.body()

        if adapter not in self._adapters:
            logger.warning(
                f"Unknown adapter {adapter}. Please register the adapter before use."
            )
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
                                detail="adapter not found")

        # 创建 Bot 对象
        BotClass = self._adapters[adapter]
        http_request = HTTPRequest(request.scope["http_version"],
                                   request.url.scheme, request.url.path,
                                   request.scope["query_string"],
                                   dict(request.headers), request.method, data)
        x_self_id, response = await BotClass.check_permission(
            self, http_request)

        if not x_self_id:
            raise HTTPException(
                response and response.status or 401, response and response.body
                and response.body.decode("utf-8"))

        if x_self_id in self._clients:
            logger.warning("There's already a reverse websocket connection,"
                           "so the event may be handled twice.")

        bot = BotClass(x_self_id, http_request)

        asyncio.create_task(bot.handle_message(data))
        return Response(response and response.body,
                        response and response.status or 200)
コード例 #16
0
def load_plugins(*plugin_dir: str) -> Set[Plugin]:
    loaded_plugins = set()
    for module_info in pkgutil.iter_modules(plugin_dir):
        _tmp_matchers.clear()
        name = module_info.name
        if name.startswith("_"):
            continue

        spec = module_info.module_finder.find_spec(name)
        if spec.name in plugins:
            continue
        elif spec.name in sys.modules:
            logger.warning(
                f"Module {spec.name} has been loaded by other plugin! Ignored")
            continue

        try:
            module = _load(spec)

            for m in _tmp_matchers:
                m.module = name
            plugin = Plugin(name, module, _tmp_matchers.copy())
            plugins[name] = plugin
            loaded_plugins.add(plugin)
            logger.opt(colors=True).info(f'Succeeded to import "<y>{name}</y>"')
        except Exception as e:
            logger.opt(colors=True, exception=e).error(
                f'<r><bg #f8bbd0>Failed to import "{name}"</bg #f8bbd0></r>')
    return loaded_plugins
コード例 #17
0
async def baidu_tl(rss_str_tl: str):
    appid = cf.appid
    secretKey = cf.secretKey
    url = f'https://api.fanyi.baidu.com/api/trans/vip/translate'
    salt = str(random.randint(32768, 65536))
    sign = hashlib.md5(
        (appid + rss_str_tl + salt + secretKey).encode()).hexdigest()
    params = {
        "q": rss_str_tl,
        "from": "auto",
        "to": "zh",
        "appid": appid,
        "salt": salt,
        "sign": sign
    }
    r = requests.get(url, params=params)
    try:
        i = 0
        text = ''
        while i < len(r.json()["trans_result"]):
            text += r.json()["trans_result"][i]["dst"] + "\n"
            i += 1
        text = "\n百度翻译:\n" + text
    except:
        if r.json()["error_code"] == "52003":
            logger.warning("无效的appid,尝试使用谷歌翻译,错误信息:" +
                           str(r.json()["error_msg"]))
            text = await google_tl(rss_str_tl)
        else:
            logger.warning("使用百度翻译错误:" + str(r.json()["error_msg"]) +
                           ",开始尝试使用谷歌翻译")
            text = await google_tl(rss_str_tl)
    return text
コード例 #18
0
async def get_mcstatus(addr: str) -> Optional[Message]:
    try:
        server = MinecraftServer.lookup(addr)
        status = await server.async_status()
        version = status.version.name
        protocol = status.version.protocol
        players_online = status.players.online
        players_max = status.players.max
        players = status.players.sample
        player_names = [player.name for player in players] if players else []
        description = status.description
        latency = status.latency
        favicon = status.favicon
    except:
        logger.warning(traceback.format_exc())
        return None

    msg = Message()
    if favicon:
        msg.append(
            MessageSegment.image(
                "base64://" + favicon.replace("data:image/png;base64,", "")
            )
        )
    msg.append(
        f"服务端版本:{version}\n"
        f"协议版本:{protocol}\n"
        f"当前人数:{players_online}/{players_max}\n"
        f"在线玩家:{'、'.join(player_names)}\n"
        f"描述文本:{description}\n"
        f"游戏延迟:{latency}ms"
    )
    return msg
コード例 #19
0
async def get_essay(type: str, texts: List[str]) -> str:
    try:
        func = commands[type]["func"]
        return await func(*texts)
    except:
        logger.warning(traceback.format_exc())
        return "出错了,请稍后再试"
コード例 #20
0
async def get_text(type: str, text: str) -> str:
    try:
        func = commands[type]["func"]
        return await func(text)
    except Exception as e:
        logger.warning(f"Error in get_text({text}, {type}): {e}")
        return ""
コード例 #21
0
ファイル: quart.py プロジェクト: SK-415/nonebot2
    async def _handle_http(self, adapter: str):
        request: Request = _request
        data: bytes = await request.get_data()  # type: ignore

        if adapter not in self._adapters:
            logger.warning(f'Unknown adapter {adapter}. '
                           'Please register the adapter before use.')
            raise exceptions.NotFound()

        BotClass = self._adapters[adapter]
        http_request = HTTPRequest(request.http_version, request.scheme,
                                   request.path, request.query_string,
                                   dict(request.headers), request.method, data)

        self_id, response = await BotClass.check_permission(self, http_request)

        if not self_id:
            raise exceptions.Unauthorized(
                description=(response and response.body or b"").decode())
        if self_id in self._clients:
            logger.warning("There's already a reverse websocket connection,"
                           "so the event may be handled twice.")
        bot = BotClass(self_id, http_request)
        asyncio.create_task(bot.handle_message(data))
        return Response(response and response.body or "",
                        response and response.status or 200)
コード例 #22
0
 def _load_plugin(module_path: str) -> Optional[Plugin]:
     try:
         _tmp_matchers.set(set())
         _export.set(Export())
         if module_path in plugins:
             return plugins[module_path]
         elif module_path in sys.modules:
             logger.warning(
                 f"Module {module_path} has been loaded by other plugins! Ignored"
             )
             return None
         module = importlib.import_module(module_path)
         for m in _tmp_matchers.get():
             m.module = module_path
         plugin = Plugin(module_path, module, _tmp_matchers.get(),
                         _export.get())
         plugins[module_path] = plugin
         logger.opt(colors=True).info(
             f'Succeeded to import "<y>{module_path}</y>"')
         return plugin
     except Exception as e:
         logger.opt(colors=True, exception=e).error(
             f'<r><bg #f8bbd0>Failed to import "{module_path}"</bg #f8bbd0></r>'
         )
         return None
コード例 #23
0
async def get_fortune(user_id, username) -> Optional[Union[str, bytes]]:
    try:
        log_path = data_path / (datetime.now().strftime("%Y%m%d") + ".json")
        if log_path.exists():
            log = json.load(log_path.open("r", encoding="utf-8"))
        else:
            log = {}

        if user_id not in log:
            copywriting = get_copywriting()
            luck = copywriting["luck"]
            content = copywriting["content"]
            fortune = get_type(luck)
            face = get_face(luck)
            image = await create_image(username, luck, fortune, content, face)
            if image:
                log[user_id] = fortune
                json.dump(log, log_path.open("w", encoding="utf-8"), ensure_ascii=False)
                return image
        else:
            fortune = log[user_id]
            return "你今天已经抽过签了,你的今日运势是:" + fortune
    except:
        logger.warning(traceback.format_exc())
        return None
コード例 #24
0
ファイル: utils.py プロジェクト: nightingu/damebot
        async def help(bot: Bot, event: Event, state: T_State, matcher: Matcher):
            # get real command content
            logger.debug(f"event: {event}")
            logger.debug(f"state: {state}")
            msg = event.get_message().extract_plain_text()
            logger.debug(f"got message '{msg}'")
            _, origin_command, command_text = re.match(regex, msg, flags=re.MULTILINE).groups()
            logger.debug(f"got command text '{command_text}'")
            extra_prompt = ""
            if not command_text.startswith(" ") and command_text != "":
                extra_prompt += f"treat '{origin_command + command_text}' as '{origin_command}'\n"
                logger.warning(extra_prompt)
                command_text = ""
            else:
                command_text = command_text.strip()
            command_without_help = origin_command.split()[-1]
            logger.debug(f"{command_without_help} => {self.cmd}")
            logger.debug(f"planning to call with '{self.cmd}', '{command_text}', '{self.help_long}'")
            help_long_text = await self.help_long_async_factory(self.cmd, command_text, self.help_long)
            
            sub_commands_texts = await asyncio.gather(*[command.help_short_async_factory(command.cmd, command_text, command.help_short) for command in self.sub_commands])
            newline = '\n'
            output = \
f"""
{extra_prompt}{help_long_text.strip()}

sub-commands:
{newline.join(f'{k}[{u}]:{v.strip()}' for k,u,v in zip(
    ('|'.join(comm.cmd_in_dice) for comm in self.sub_commands), 
    (f'{comm.run_as}' for comm in self.sub_commands), 
    sub_commands_texts
    )
).strip()}
""".strip()
            await matcher.finish(output)
コード例 #25
0
async def send_superuser_msg(msg: Union[str, Message]):
    try:
        bot = nonebot.get_bot()
        assert isinstance(bot, Bot)
        user_id = list(bot.config.superusers)[0]
        await bot.send_private_msg(user_id=int(user_id), message=msg)
    except:
        logger.warning(f"send superuser msg failed, msg: {msg}")
コード例 #26
0
async def beici():
    if nonebot.get_bots():
        bot = list(nonebot.get_bots().values())[0]
    else:
        logger.warning('未连接任何ws对象')
        return
    msg = '骑士君、准备好背刺了吗?'
    await helper.broadcast(bot, msg, 'arena_reminder')
コード例 #27
0
 async def execute(self, query: str, param: list = None):
     try:
         await self.cur.execute(query, param)
     except RuntimeError:
         logger.warning("数据库连接超时,重新建立连接!")
         await self.close()
         await self.connect()
         await self.cur.execute(query, param)
コード例 #28
0
async def get_wolframalpha_text(input, params=(), **kwargs):
    try:
        client = wolframalpha.Client(wolframalpha_config.wolframalpha_appid)
        res = client.query(input, params, **kwargs)
        return next(res.results).text
    except Exception as e:
        logger.warning(f"Error in get_wolframalpha_text({input}): {e}")
        return ""
コード例 #29
0
ファイル: youdao.py プロジェクト: muguangAA/qqBot
 def getContentList(self):
     e = etree.HTML(self.Page)
     try:
         contentList = e.xpath('//*[@id="article"]/p//text()')
     except Exception as e:
         logger.warning('getContentList wrong %s' % e)
         return []
     return contentList
コード例 #30
0
 def deco(func) -> Callable:
     for n in names:
         if n in _registry:
             logger.warning(
                 f'出现重名命令:{func.__name__} 与 {_registry[n].__name__}命令名冲突')
         else:
             _registry[n] = (func, parser)
     return func