async def bot_invited_join_group(app: GraiaMiraiApplication, event: BotInvitedJoinGroupRequestEvent): if event.supplicant != get_config("HostQQ"): await app.sendFriendMessage( get_config("HostQQ"), MessageChain.create([ Plain(text=f"主人主人,有个人拉我进群啦!\n"), Plain(text=f"ID:{event.supplicant}\n"), Plain(text=f"来自:{event.nickname}\n"), Plain(text=f"描述:{event.message}\n") ]))
async def handle(app: GraiaMiraiApplication, message: MessageChain, group: Group, member: Member): legal_type = ("setu", "setu18", "real", "realHighq", "wallpaper", "sketch") if re.match( r"添加(setu|setu18|real|realHighq|wallpaper|sketch)图片(\[图片])+", message.asDisplay()): if not user_permission_require(group, member, 2): return MessageItem( MessageChain.create([Plain(text="你没有权限,爬!")]), Normal(GroupStrategy())) image_type = re.findall(r"添加(.*?)图片(\[图片])+", message.asDisplay(), re.S)[0][0] if image_type not in legal_type: return MessageItem( MessageChain.create([ Plain( text=f"非法图片类型!\n合法image_type:{'、'.join(legal_type)}" ) ]), QuoteSource(GroupStrategy())) if path := get_config(f"{image_type}Path"): if os.path.exists(path): try: await ImageAdderHandler.add_image( path, message.get(Image)) except Exception as e: logger.error(traceback.format_exc()) return MessageItem( MessageChain.create( [Plain(text="出错了呐~请查看日志/控制台输出!")]), Normal(GroupStrategy())) return MessageItem( MessageChain.create([ Plain( text=f"保存成功!共保存了{len(message.get(Image))}张图片!") ]), Normal(GroupStrategy())) else: return MessageItem( MessageChain.create([ Image.fromLocalFile( f"{os.getcwd()}/statics/error/path_not_exists.png" ) ]), QuoteSource(GroupStrategy())) else: return MessageItem( MessageChain.create( [Plain(text=f"无{image_type}Path项!请检查配置!")]), QuoteSource(GroupStrategy()))
async def get_chat_reply(group_id: int, sender: int, text: str) -> str: if text.strip() == "": return "@纱雾干什么呐~是想找纱雾玩嘛~" url = "https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat" temp_list = re.findall(r"@(.*?) ", text, re.S) if temp_list: text = text.replace(f"@{temp_list[0]} ", "") text = text.strip() app_id = get_config("txAppId") t = time.time() time_stamp = str(int(t)) nonce_str = ''.join(random.sample(string.ascii_letters + string.digits, 10)) params = { 'app_id': app_id, 'question': text, 'time_stamp': time_stamp, 'nonce_str': nonce_str, 'session': await ChatReplyHandler.get_chat_session(group_id, sender) } sign = await ChatReplyHandler.get_tx_sign(params) params["sign"] = sign async with aiohttp.ClientSession() as session: async with session.get(url=url, params=params) as resp: res = await resp.json() if res["ret"] == 16394: return "抱歉呐~我不知道怎么回答呢~问我点别的吧~" if res["ret"] > 0: print(res) return f"Error:{res['msg']}" return res["data"]["answer"]
async def get_voice(text: str) -> Union[str, bytes]: url = "https://api.ai.qq.com/fcgi-bin/aai/aai_tts" text = text.strip() app_id = get_config("txAppId") t = time.time() time_stamp = str(int(t)) nonce_str = ''.join( random.sample(string.ascii_letters + string.digits, 10)) params = { 'app_id': app_id, 'time_stamp': time_stamp, 'nonce_str': nonce_str, "speaker": '7', "format": '3', "volume": '0', "speed": "100", "text": text, "aht": '0', "apc": "58" } sign = await get_tx_sign(params) params["sign"] = sign async with aiohttp.ClientSession() as session: async with session.get(url=url, params=params) as resp: res = await resp.json() if res["ret"] > 0: print(res) return f"Error:{res['msg']}" return base64.b64decode(res["data"]["speech"])
async def handle(self, app: GraiaMiraiApplication, message: MessageChain, group: Group, member: Member): if message.has(At) and message.get(At)[0].target == get_config("BotQQ"): await update_user_call_count_plus1(group, member, UserCalledCount.at, "at") content = "".join(plain.text for plain in message.get(Plain)).strip().replace(" ", ",") set_result(message, await self.get_reply(member.id, group.id, content)) else: return None
async def get_tx_sign(params: dict) -> str: """ Get sign of Tencent Ai Platform Args: params: Dict to send Examples: sign = await get_sign(params) Return: str """ app_key = get_config("txAppKey") params_keys = sorted(params.keys()) sign = "" for i in params_keys: if params[i] != '': sign += "%s=%s&" % (i, parse.quote(params[i], safe='')) sign += "app_key=%s" % app_key def curl_md5(src: str) -> str: m = hashlib.md5(src.encode('UTF-8')) return m.hexdigest().upper() sign = curl_md5(sign) # print("signMD5:", sign) return sign
async def new_friend_request(app: GraiaMiraiApplication, event: NewFriendRequestEvent): await app.sendFriendMessage( get_config("HostQQ"), MessageChain.create([ Plain(text=f"主人主人,有个人来加我好友啦!\n"), Plain(text=f"ID:{event.supplicant}\n"), Plain(text=f"来自:{event.nickname}\n"), Plain(text=f"描述:{event.message}\n"), Plain(text=f"source:{event.sourceGroup}") ]))
async def get_result(group: Group, member: Member, question: str) -> MessageItem: api_key = get_config("wolframAlphaKey") if api_key == "wolframAlphaKey": return MessageItem( MessageChain.create([Plain(text="尚未配置wolframAlphaKey!")]), QuoteSource(GroupStrategy())) url = f"https://api.wolframalpha.com/v1/simple?i={question.replace('+', '%2B')}&appid={api_key}" async with aiohttp.ClientSession() as session: async with session.get(url=url) as resp: if resp.status == 200: res = await resp.read() return MessageItem( MessageChain.create([Image.fromUnsafeBytes(res)]), QuoteSource(GroupStrategy())) else: return MessageItem( MessageChain.create([Plain(text=await resp.text())]), QuoteSource(GroupStrategy()))
async def anti_revoke(app: GraiaMiraiApplication, event: GroupRecallEvent): if await get_setting( event.group.id, Setting.anti_revoke) and event.authorId != get_config("BotQQ"): try: msg = await app.messageFromId(event.messageId) revoked_msg = msg.messageChain print(event.authorId) author_member = await app.getMember(event.group.id, event.authorId) author_name = "自己" if event.operator.id == event.authorId else author_member.name resended_msg = MessageChain.join( MessageChain.create([ Plain( text= f"{event.operator.name}偷偷撤回了{author_name}的一条消息哦:\n\n") ]), revoked_msg) print(msg) await app.sendGroupMessage(event.group, resended_msg.asSendable()) except (AccountMuted, UnknownTarget): pass
async def member_muted(app: GraiaMiraiApplication, event: MemberMuteEvent): if event.operator is not None: if event.member.id == get_config("HostQQ"): try: await app.unmute(event.member.group.id, event.member.id) await app.sendGroupMessage( event.member.group.id, MessageChain.create([Plain(text="保护!保护!")])) except PermissionError: pass else: try: m, s = divmod(event.durationSeconds, 60) h, m = divmod(m, 60) await app.sendGroupMessage( event.member.group.id, MessageChain.create([ Plain(text="哦~看看是谁被关进小黑屋了?\n"), Plain(text="哦我的上帝啊~是%s!他将在小黑屋里呆%s哦~" % (event.member.name, "%02d:%02d:%02d" % (h, m, s))) ])) except AccountMuted: pass
}) GlobalFrequencyLimitDict().add_group(group.id) await app.sendGroupMessage( group, MessageChain.create([Plain(text="欸嘿嘿~我来啦!宇宙无敌小可爱纱雾酱华丽登场!")])) except AccountMuted: pass except: logger.error(traceback.format_exc()) @logger.catch @bcc.receiver(ApplicationLaunched) async def init(): await core.bot_launch_init() await online_notice(app) def management_boot(): from WebManager.web_manager import run_api run_api() if get_config("webManagerApi"): threading.Thread(target=management_boot, args=()).start() if get_config("webManagerAutoBoot"): import webbrowser webbrowser.open(f"{os.getcwd()}/WebManager/index.html") core.launch()
async def sketch() -> str: base_path = get_config("sketchPath") return f"{os.getcwd()}/statics/error/path_not_exists.png" if not os.path.exists( base_path) else ImageSenderHandler.random_pic(base_path)
from graia.broadcast.interrupt import InterruptControl from graia.application.message.chain import MessageChain from graia.application.event.messages import GroupMessage, Group, Member from graia.application.message.elements.internal import Source, Plain, At, Image from SAGIRIBOT.Core.AppCore import AppCore from SAGIRIBOT.utils import get_setting, get_config from SAGIRIBOT.Handler.Handler import AbstractHandler from SAGIRIBOT.utils import update_user_call_count_plus1 from SAGIRIBOT.ORM.Tables import Setting, UserCalledCount from SAGIRIBOT.MessageSender.MessageItem import MessageItem from SAGIRIBOT.Core.Exceptions import AsyncioTasksGetResult from SAGIRIBOT.MessageSender.MessageSender import set_result from SAGIRIBOT.MessageSender.Strategy import GroupStrategy, Normal saucenao_cookie = get_config("saucenaoCookie") class ImageSearchHandler(AbstractHandler): """ 图片搜素Handler(saucenao) """ __name__ = "ImageSearchHandler" __description__ = "一个可以搜索Pixiv图片的Handler" __usage__ = "在群中发送 `搜图` 后,等待回应在30s内发送图片即可(多张图片只会搜索第一张)" async def handle(self, app: GraiaMiraiApplication, message: MessageChain, group: Group, member: Member): if message.asDisplay() == "搜图": await update_user_call_count_plus1(group, member, UserCalledCount.search, "search") if not await get_setting(group.id, Setting.img_search): set_result(message, MessageItem(MessageChain.create([Plain(text="搜图功能未开启呐~请联系管理员哦~")]), Normal(GroupStrategy()))) try: await app.sendGroupMessage(group, MessageChain.create([
async def get_image(group: Group, member: Member, keyword: str): apikey = get_config("loliconApiKey") if not apikey or apikey == "loliconApiKey": return MessageItem( MessageChain.create([Plain(text="loliconApiKey配置错误!")]), QuoteSource(GroupStrategy())) cache = get_config("loliconImageCache") r18 = await get_setting(group.id, Setting.r18) url = f"https://api.lolicon.app/setu/?r18=0&keyword={keyword}&apikey={apikey}&r18={1 if r18 else 0}" async with aiohttp.ClientSession() as session: async with session.get(url=url) as resp: result = await resp.json() if result["code"] == 401: return MessageItem( MessageChain.create([Plain(text="错误401:APIKEY 不存在或被封禁!")]), QuoteSource(GroupStrategy())) elif result["code"] == 403: return MessageItem( MessageChain.create([Plain(text="错误403:由于不规范的操作而被拒绝调用!")]), QuoteSource(GroupStrategy())) elif result["code"] == 404: return MessageItem( MessageChain.create([Plain(text="错误404:找不到符合关键字的色图!")]), QuoteSource(GroupStrategy())) elif result["code"] == 429: return MessageItem( MessageChain.create([Plain(text="错误429:达到调用额度限制!")]), QuoteSource(GroupStrategy())) elif result["code"] == -1: return MessageItem( MessageChain.create( [Plain(text="错误-1:API内部错误,请向 [email protected] 反馈!")]), QuoteSource(GroupStrategy())) result = result["data"][0] info = f"title: {result['title']}\nauthor: {result['author']}\nurl: {result['url']}" file_name = result["url"].split('/').pop() local_path = get_config("setu18Path" if r18 else "setuPath") file_path = os.path.join(local_path, file_name) if os.path.exists(file_path): return MessageItem( MessageChain.create([ Plain(text=f"你要的{keyword}涩图来辣!\n"), Image.fromLocalFile(file_path), Plain(text=f"\n{info}") ]), QuoteSource(GroupStrategy()) if not r18 else Revoke(GroupStrategy())) else: async with aiohttp.ClientSession() as session: async with session.get(url=result['url']) as resp: img_content = await resp.read() if cache: image = IMG.open(BytesIO(img_content)) image.save(file_path) return MessageItem( MessageChain.create([ Plain(text=f"你要的{keyword}涩图来辣!\n"), Image.fromUnsafeBytes(img_content), Plain(text=f"\n{info}") ]), QuoteSource(GroupStrategy()) if not r18 else Revoke(GroupStrategy()))
async def search_image(img: Image) -> MessageChain: # url for headers url = "https://saucenao.com/search.php" # picture url pic_url = img.url # json requesting url url2 = f"https://saucenao.com/search.php?db=999&output_type=2&testmode=1&numres=10&url={pic_url}" url3 = f"https://saucenao.com/search.php?api_key={get_config('saucenaoApiKey')}&db=999&output_type=2&testmode=1&numres=10&url={pic_url}" print(url3) # data for posting. payload = { "url": pic_url, "numres": 1, "testmode": 1, "db": 999, "output_type": 2, "api_key": get_config("saucenaoApiKey") } # header to fool the website. 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", # "cookie": saucenao_cookie } # , headers=headers, data=payload async with aiohttp.ClientSession() as session: async with session.get(url=url3) as resp: json_data = await resp.json() if json_data["header"]["status"] == -1: return MessageChain.create( [Plain(text=f"错误:{json_data['header']['message']}")]) if not json_data["results"]: return MessageChain.create([Plain(text="没有搜索到结果呐~")]) result = json_data["results"][0] header = result["header"] data = result["data"] async with aiohttp.ClientSession() as session: async with session.get(url=header["thumbnail"]) as resp: img_content = await resp.read() similarity = header["similarity"] data_str = f"搜索到如下结果:\n\n相似度:{similarity}%\n" for key in data.keys(): if isinstance(data[key], list): data_str += (f"\n{key}:\n " + "\n".join(data[key]) + "\n") else: data_str += f"\n{key}:\n {data[key]}\n" return MessageChain.create( [Image.fromUnsafeBytes(img_content), Plain(text=f"\n{data_str}")])
async def bot_leave_group(app: GraiaMiraiApplication, event: BotLeaveEventKick): print("bot has been kicked!") await app.sendFriendMessage( get_config("HostQQ"), MessageChain.create([Plain(text=f"呜呜呜主人我被踢出{event.group.name}群了")]))
async def sketch() -> str: base_path = get_config("sketchPath") pic_path = await ImageSenderHandler.random_pic(base_path) return pic_path
async def real_highq() -> str: base_path = get_config("realHighqPath") pic_path = await ImageSenderHandler.random_pic(base_path) return pic_path
async def color18() -> str: base_path = get_config("setu18Path") pic_path = await ImageSenderHandler.random_pic(base_path) return pic_path
async def wallpaper() -> str: base_path = get_config("wallpaperPath") pic_path = await ImageSenderHandler.random_pic(base_path) return pic_path
import asyncio import websockets from SAGIRIBOT.utils import get_config logs = [] async def set_log(log_str: str): logs.append(log_str.strip()) async def log_sender(websocket, path): while True: if logs: # print(logs[0]) await websocket.send(logs[0]) logs.pop(0) await asyncio.sleep(0.5) start_server = websockets.serve(log_sender, "127.0.0.1", 8001) if get_config("webManagerApi"): loop = asyncio.get_event_loop() loop.run_until_complete(start_server)