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
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)
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)
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服新闻')
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))
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
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
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
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∠)_')
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, {}
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
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
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
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
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)
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
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
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
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 "出错了,请稍后再试"
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 ""
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)
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
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
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)
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}")
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')
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)
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 ""
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
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