async def flash_image_catcher(app: Ariadne, message: MessageChain, group: Group): if message.has(FlashImage) and await group_setting.get_setting(group.id, Setting.anti_flash_image): await app.sendGroupMessage( group, MessageChain([Plain(text="FlashImage => Image\n"), message[FlashImage][0].toImage()]) )
async def main(app: Ariadne, group: Group): await app.sendMessage(group, MessageChain([Image(data_bytes=await get_image())]))
async def nudge_event(app: Ariadne, event: NudgeEvent): if event.group_id and not await group_setting.get_setting( event.group_id, Setting.switch): return None if event.target == config.bot_qq: if event.context_type == "group": if member := await app.getMember(event.group_id, event.supplicant): logger.info( f"机器人被群 <{member.group.name}> 中用户 <{member.name}> 戳了戳。") if member.group.id in nudge_info.keys(): if member.id in nudge_info[member.group.id].keys(): period = nudge_info[member.group.id][ member.id]["time"] + relativedelta(minutes=1) if datetime.now() >= period: nudge_info[member.group.id][member.id] = { "count": 0, "time": datetime.now() } count = nudge_info[member.group.id][ member.id]["count"] + 1 if count == 1: try: await app.sendNudge(member) except: pass nudge_info[member.group.id][member.id] = { "count": count, "time": datetime.now() } elif count == 2: try: await app.sendNudge(member) await app.sendMessage( member.group, MessageChain.create([Plain(text=f"不许戳了!") ])) except: pass nudge_info[member.group.id][member.id] = { "count": count, "time": datetime.now() } elif count == 3: try: await app.sendNudge(member) await app.sendMessage( member.group, MessageChain.create( [Plain(text=f"说了不许再戳了!")])) except: pass nudge_info[member.group.id][member.id] = { "count": count, "time": datetime.now() } elif count == 4: try: await app.sendNudge(member) except: pass nudge_info[member.group.id][member.id] = { "count": count, "time": datetime.now() } elif count == 5: try: await app.sendNudge(member) await app.sendMessage( member.group, MessageChain.create( [Plain(text=f"呜呜呜你欺负我,不理你了!")])) except: pass nudge_info[member.group.id][member.id] = { "count": count, "time": datetime.now() } elif 6 <= count <= 9: nudge_info[member.group.id][member.id] = { "count": count, "time": datetime.now() } elif count == 10: try: await app.sendNudge(member) await app.sendMessage( member.group, MessageChain.create( [Plain(text="你真的很有耐心欸。")])) except: pass else: nudge_info[member.group.id][member.id] = { "count": 1, "time": datetime.now() } await app.sendNudge(member) else: nudge_info[member.group.id] = { member.id: { "count": 1, "time": datetime.now() } } await app.sendNudge(member) else: if friend := await app.getFriend(event.supplicant): logger.info(f"机器人被好友 <{friend.nickname}> 戳了戳。")
async def disable(self, **kwargs): self.__status = False return MessageChain.create([Plain(text="已关闭 Github 仓库订阅")])
class GithubWatcher(object): __name__ = "GithubWatcher" __description__ = "Github 订阅 Handler" __usage__ = "None" __cached = {} if config.functions['github'][ 'username'] != "username" and config.functions['github'][ 'token'] != 'token': __auth = True __session = aiohttp.ClientSession( auth=BasicAuth(login=config.functions['github']['username'], password=config.functions['github']['token'])) else: __auth = False __session = aiohttp.ClientSession() __first_warned = False __status = True __base_url = "https://api.github.com" __events_url = "/repos/{owner}/{repo}/events" __is_running = False initialize = False @switch() @blacklist() async def real_handle(self, app: Ariadne, message: MessageChain, group: Group = None, member: Member = None, friend: Friend = None) -> MessageItem: commands = { "enable": { "permission": [3, []], "permission_nl": "3 级权限", "manual": "/github-watch enable", "description": "启用 Github 订阅功能", "func": self.enable }, "disable": { "permission": [3, []], "permission_nl": "3 级权限", "manual": "/github-watch disable", "description": "禁用 Github 订阅功能", "func": self.disable }, "add": { "permission": [2, (MemberPerm.Administrator, MemberPerm.Owner)], "permission_nl": "2 级或群管理员及以上权限", "manual": "/github-watch add {repo} [repo]+", "description": "订阅仓库变动,可同时订阅多个仓库", "func": self.add }, "remove": { "permission": [2, (MemberPerm.Administrator, MemberPerm.Owner)], "permission_nl": "2 级或群管理员及以上权限", "manual": "/github-watch remove {repo} [repo]+", "description": "取消订阅仓库变动,可同时取消订阅多个仓库", "func": self.remove }, "check": { "permission": [ 1, (MemberPerm.Member, MemberPerm.Administrator, MemberPerm.Owner) ], "permission_nl": "任何人", "manual": "/github-watch check", "description": "手动查看仓库订阅列表", "func": self.check }, "cache": { "permission": [2, (MemberPerm.Administrator, MemberPerm.Owner)], "permission_nl": "2 级或群管理员及以上权限", "manual": "/github-watch cache {update/store}", "description": "更新/储存缓存", "func": self.cache } } if message.asDisplay().startswith("/github-watch"): if not self.initialize: self.update_cache() for repo in self.__cached.keys(): self.__cached[repo]['enabled'] = True self.store_cache() self.initialize = True args = message.asDisplay().split(" ", maxsplit=1) if len(args) == 1: msg = [Plain(text="缺少参数\n\n")] for func in commands.keys(): msg.append( Plain(text=( f"/github-watch {func}\n" f" 描述:{commands[func]['description']}\n" f" 用法:{commands[func]['manual']}\n" f" 权限:{commands[func]['permission_nl']}\n"))) return MessageItem( await MessageChainUtils.messagechain_to_img( MessageChain.create(msg)), QuoteSource()) _, args = args name = args.split(" ", maxsplit=1)[0] arg = ''.join(args.split(" ", maxsplit=1)[1:]) if name not in commands.keys(): return MessageItem( MessageChain.create([Plain(text=f"未知指令:{arg}")]), QuoteSource()) if member and group: permission = commands[name]['permission'] if not await user_permission_require(group, member, permission[0]) \ and not (member.permission in permission[1]): return MessageItem( MessageChain.create([ Plain( text=f"权限不足,你需要 {permission[0]} 级权限" f"{('或来自 ' + str(permission[1][0]) + ' 的权限') if permission[1] else ''}" ) ]), QuoteSource()) arg = arg.strip() return MessageItem( await commands[name]['func'](app=app, group=group, friend=friend, arg=arg), QuoteSource()) async def enable(self, **kwargs): self.__status = True return MessageChain.create([Plain(text="已开启 Github 仓库订阅")]) async def disable(self, **kwargs): self.__status = False return MessageChain.create([Plain(text="已关闭 Github 仓库订阅")]) async def add(self, **kwargs): if not self.__status: return MessageChain.create([Plain(text="Github 仓库订阅功能已关闭")]) repos = None group = None friend = None app = None for name, arg in kwargs.items(): if name == "arg" and isinstance(arg, str): repos = arg if isinstance(arg, Group): group = arg if isinstance(arg, Friend): friend = arg if isinstance(arg, Ariadne): app = arg err = [] if not group and not friend: err = err.extend([Plain(text="无法获取 Group 或 Friend 实例")]) if not app: err = err.extend([Plain(text="无法获取 Ariadne 实例")]) if not repos: err = err.extend([Plain(text="未填写需要订阅的仓库")]) if err: return MessageChain.create(err) repos = repos.split(" ") failed = [] duplicated = [] success_count = 0 for repo in repos: url = f"https://api.github.com/search/repositories?q={repo}" async with self.__session.get(url=url, proxy=proxy) as resp: try: resp.raise_for_status() except aiohttp.ClientError as e: logger.error(e) logger.error(f"暂时无法取得仓库 {repo} 的更新(状态码 {resp.status})") continue result = (await resp.json())["items"] if not result: failed.append(repo) continue repo = result[0]['full_name'] repo = repo.split("/") repo = (repo[0], repo[1]) if repo not in self.__cached.keys(): self.__cached[repo] = { "group": [], "friend": [], "last_id": -1, "enabled": True } if group: if group.id in self.__cached[repo]['group']: duplicated.append(f"{repo[0]}/{repo[1]}") else: self.__cached[repo][ 'group'] = self.__cached[repo]['group'] + [group.id] if friend: if friend.id in self.__cached[repo]['friend']: duplicated.append(f"{repo[0]}/{repo[1]}") else: self.__cached[repo]['friend'] = self.__cached[repo][ 'friend'] + [friend.id] if self.__cached[repo]['last_id'] == -1: await self.github_schedule(app=app, manuel=True, per_page=1, page=1, repo=repo) success_count += 1 res = [Plain(text=f"{success_count} 个仓库订阅成功")] if failed: res.append( Plain(text=f"\n{len(failed)} 个仓库订阅失败" f"\n失败的仓库有:{' '.join(failed)}")) if duplicated: res.append( Plain(text=f"\n{len(duplicated)} 个仓库已在订阅列表中" f"\n重复的仓库有:{' '.join(duplicated)}")) try: self.store_cache(manual=False) self.update_cache(manual=False) return MessageChain.create(res) except Exception as e: logger.error(e) res.append(Plain(text="\n\n刷新缓存失败")) return MessageChain.create(res) async def remove(self, **kwargs): if not self.__status: return MessageChain.create([Plain(text=f"Github 仓库订阅功能已关闭")]) repos = None group = None friend = None err = [] for name, arg in kwargs.items(): if name == "arg" and isinstance(arg, str): repos = arg if isinstance(arg, Group): group = arg if isinstance(arg, Friend): friend = arg if not group and not friend: err = err.extend([Plain(text=f"无法获取 Group 或 Friend 实例")]) if not repos: err = err.extend([Plain(text="未填写需要取消订阅的仓库")]) if err: return MessageChain.create(err) repos = repos.split(" ") failed = [] success_count = 0 for repo in repos: repo = repo.split("/") if len(repo) != 2: failed.append("/".join(repo)) continue repo = (repo[0], repo[1]) if repo not in self.__cached.keys(): failed.append("/".join(repo)) continue if group: self.__cached[repo]['group'] = [ group_id for group_id in self.__cached[repo]['group'] if group_id != group.id ] if friend: self.__cached[repo]['friend'] = [ friend_id for friend_id in self.__cached[repo]['group'] if friend_id != friend.id ] if not (self.__cached[repo]['group'] and self.__cached[repo]['friend']): self.__cached.pop(repo) success_count += 1 res = [Plain(text=f"{success_count} 个仓库取消订阅成功")] if failed: res.append( Plain(text=f"\n{len(failed)} 个仓库取消订阅失败" f"\n失败的仓库有:{' '.join(failed)}")) try: self.store_cache(manual=False) self.update_cache(manual=False) return MessageChain.create(res) except Exception as e: logger.error(e) res.append(Plain(text="\n\n刷新缓存失败")) return MessageChain.create(res) async def cache(self, **kwargs): accepted = ['update', 'store'] command = None for name, arg in kwargs.items(): if name == "arg" and isinstance(arg, str): command = arg if not command: return MessageChain.create([Plain(text=f"未填写参数")]) if command not in accepted: return MessageChain.create([Plain(text=f"未知参数:{command}")]) if command == 'update': return self.update_cache(manual=True) if command == 'store': return self.store_cache(manual=True) def update_cache(self, manual: bool = False): try: with open(str(Path(__file__).parent.joinpath("watcher_data.json")), "r") as r: data = json.loads(r.read()) cache = {} for key in data.keys(): owner, repo = key.split("/") cache[(owner, repo)] = data[key] self.__cached = cache return MessageChain.create([Plain( text="更新缓存成功")]) if manual else None except (FileNotFoundError, JSONDecodeError): return MessageChain.create( [Plain(text="无法更新缓存,请检查是否删除了缓存文件并重新储存缓存")]) def store_cache(self, manual: bool = False): with open(str(Path(__file__).parent.joinpath("watcher_data.json")), "w") as w: cache = {} for key in self.__cached.keys(): new_key = f"{key[0]}/{key[1]}" cache[new_key] = self.__cached[key] w.write(json.dumps(cache, indent=4)) return MessageChain.create([Plain(text="写入缓存成功")]) if manual else None async def check(self, **kwargs) -> MessageChain: group = None friend = None for name, arg in kwargs.items(): if isinstance(arg, Group): group = arg if isinstance(arg, Friend): friend = arg if not group and not friend: return MessageChain.create([Plain(text=f"无法获取 Group 或 Friend 实例")]) watched = [] target = group if group else friend field = 'group' if group else 'friend' for repo in self.__cached.keys(): if target.id in self.__cached[repo][field]: watched.append(f"{repo[0]}/{repo[1]}") res = [ Plain(text=f"{'本群' if group else '你'}订阅的仓库有:\n" f"{' '.join(watched)}") ] return MessageChain.create(res) async def get_repo_event(self, repo: tuple, per_page: int = 30, page: int = 1): url = self.__base_url \ + self.__events_url.replace('{owner}', repo[0]).replace('{repo}', repo[1]) \ + f'?per_page={per_page}&page={page}' res = None try: res = await self.__session.get(url=url, proxy=proxy) res.raise_for_status() res = await res.json() if isinstance(res, list): return res elif isinstance(res, dict): if "message" in res.keys(): if "API rate limit exceeded" in res["message"]: logger.error("GitHub API 超出速率限制") if not self.__auth: logger.error("请设置 GitHub 用户名和 OAuth Token 以提高限制") self.__first_warned = True elif res["message"] == "Not Found": logger.error(f"无法找到仓库 {repo[0]}/{repo[1]}") self.__cached[repo]['enabled'] = False return res except aiohttp.ClientError as e: logger.error(e) logger.error( f"暂时无法取得仓库 {repo[0]}/{repo[1]} 的更新" f"{'' if not res else '(状态码 ' + str(res.status) + ')'}") return None except Exception as e: logger.error(e) return None async def a_generate_plain(self, event: dict): return await asyncio.get_event_loop().run_in_executor( None, self.generate_plain, event) @staticmethod def generate_plain(event: dict): actor = event['actor']['display_login'] event_time = (datetime.strptime(event['created_at'], '%Y-%m-%dT%H:%M:%SZ') + timedelta(hours=8)) \ .strftime('%Y-%m-%d %H:%M:%S') resp = None if event['type'] == 'IssuesEvent': if event['payload']['action'] == 'opened': title = event['payload']['issue']['title'] number = event['payload']['issue']['number'] body = event['payload']['issue']['body'] if body: if len(body) > 100: body = body[:100] + "......" body = body + "\n" link = event['payload']['issue']['html_url'] resp = Plain(text=f"----------\n" f"[新 Issue]\n" f"#{number} {title}\n" f"{body}\n" f"\n" f"发布人:{actor}\n" f"时间:{event_time}\n" f"链接:{link}\n") elif event['type'] == 'IssueCommentEvent': if event['payload']['action'] == 'created': title = event['payload']['issue']['title'] number = event['payload']['issue']['number'] body = event['payload']['comment']['body'] if body: if len(body) > 100: body = body[:100] + "......" body = body + "\n" link = event['payload']['comment']['html_url'] resp = Plain(text=f"----------\n" f"[新 Comment]\n" f"#{number} {title}\n" f"{body}" f"\n" f"发布人:{actor}\n" f"时间:{event_time}\n" f"链接:{link}\n") elif event['type'] == 'PullRequestEvent': if event['payload']['action'] == 'opened': title = event['payload']['pull_request']['title'] number = event['payload']['pull_request']['number'] body = event['payload']['pull_request']['body'] if body: if len(body) > 100: body = body[:100] + "......" body = body + "\n" head = event['payload']['pull_request']['head']['label'] base = event['payload']['pull_request']['base']['label'] commits = event['payload']['pull_request']['commits'] link = event['payload']['pull_request']['html_url'] resp = Plain(text=f"----------\n" f"[新 PR]\n" f"#{number} {title}\n" f"{body}" f"\n" f"{head} → {base}\n" f"提交数:{commits}\n" f"发布人:{actor}\n" f"时间:{event_time}\n" f"链接:{link}\n") elif event['type'] == 'PushEvent': commits = [] for commit in event['payload']['commits']: commits.append( f"· [{commit['author']['name']}] {commit['message']}") resp = Plain(text=f"----------\n" f"[新 Push]\n" + "\n".join(commits) + f"\n" f"提交数:{len(commits)}\n" f"发布人:{actor}\n" f"时间:{event_time}\n") elif event['type'] == 'CommitCommentEvent': body = event['payload']['comment']['body'] if body: if len(body) > 100: body = body[:100] + "......" body = body + "\n" link = event['payload']['comment']['html_url'] resp = Plain(text=f"----------\n" f"[新 Comment]\n" f"{body}" f"\n" f"发布人:{actor}\n" f"时间:{event_time}\n" f"链接:{link}\n") return resp if resp else None async def github_schedule(self, **kwargs): if not self.initialize: self.update_cache() self.initialize = True try: app = None manual = False repo = None per_page = 30 page = 1 for name, arg in kwargs.items(): if name == "manual" and isinstance(arg, bool): manual = arg if name == "repo" and isinstance(arg, tuple): repo = arg if name == "per_page" and isinstance(arg, int): per_page = arg if name == "page" and isinstance(arg, int): page = arg if isinstance(arg, Ariadne): app = arg if not app: logger.error("无法获得 Ariadne 实例") return None if self.__is_running: if manual: return MessageItem( MessageChain.create( [Plain(text="Github 订阅插件正在进行其他操作,请稍后再试。")]), QuoteSource()) return None if self.__status and repo: res = [] if events := await self.get_repo_event(repo, per_page, page): if isinstance(events, list): self.__cached[repo]['last_id'] = int(events[0]['id']) if resp := await self.a_generate_plain(events[0]): res.append(resp) else: res.append(Plain(text=events["message"])) if not res: return None res.insert(0, Plain(text=f"仓库:{repo[0]}/{repo[1]}\n")) res.append( Plain( text= f"----------\n获取时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" )) return MessageChain.create(res) if self.__status: self.__is_running = True for repo in self.__cached.keys(): if not self.__cached[repo]['enabled']: continue res = [] if events := await self.get_repo_event( repo, per_page, page): if isinstance(events, list): last_id = self.__cached[repo]['last_id'] new_last_id = last_id for index, event in enumerate(events): if index == 0: new_last_id = int(event['id']) if int(event['id']) <= last_id: break if resp := await self.a_generate_plain(event): res.append(resp) else: continue self.__cached[repo]['last_id'] = new_last_id self.store_cache() else: res.append(Plain(text=events["message"])) if res: if res[0].asDisplay() == "Bad credentials": self.__is_running = False self.__status = False await app.sendFriendMessage( config.host_qq, MessageChain.create([ Plain( text="凭据无效,请检查是否已更改或吊销 Github Token\n" "已自动关闭 Github Watcher") ])) raise Exception("凭据无效,请检查是否已更改或吊销 Github Token") res.insert(0, Plain(text=f"仓库:{repo[0]}/{repo[1]}\n")) res.append( Plain( text= f"----------\n获取时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" )) res = MessageChain.create(res) # fwd_nodes = [ # ForwardNode( # senderId=config.bot_qq, # time=datetime.now(), # senderName="Github 订阅", # messageChain=MessageChain.create(Plain(text=f"仓库:{repo[0]}/{repo[1]}\n")), # ) # ] # for index, element in enumerate(res): # fwd_nodes.append( # ForwardNode( # senderId=config.bot_qq, # time=datetime.now() + timedelta(minutes=index + 1), # senderName="Github 订阅", # messageChain=MessageChain.create(element), # ) # ) # fwd_nodes.append( # ForwardNode( # senderId=config.bot_qq, # time=datetime.now(), # senderName="Github 订阅", # messageChain=MessageChain.create(Plain( # text=f"获取时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") # ), # ) # ) # res = MessageChain.create(Forward(nodeList=fwd_nodes)) if manual: self.__is_running = False return MessageItem(res, Normal()) for group in self.__cached[repo]['group']: try: await app.sendGroupMessage(group, res) except (AccountMuted, UnknownTarget): pass for friend in self.__cached[repo]['friend']: try: await app.sendFriendMessage(friend, res) except UnknownTarget: pass
async def get_image(group: Group, keyword: str) -> MessageChain: word_filter = ("&", "r18", "&r18", "%26r18") r18 = await group_setting.get_setting(group.id, Setting.r18) if any([i in keyword for i in word_filter]): return MessageChain("你注个寄吧") url = f"https://api.lolicon.app/setu/v2?r18={1 if r18 else 0}&keyword={keyword}" async with aiohttp.ClientSession( connector=TCPConnector(verify_ssl=False) ) as session: async with session.get(url=url, proxy=proxy) as resp: result = await resp.json() logger.info(result) if result["error"]: return MessageChain(result["error"]) if result["data"]: result = result["data"][0] else: return MessageChain(f"没有搜到有关{keyword}的图哦~有没有一种可能,你的xp太怪了?") if data_cache: await orm.insert_or_update( LoliconData, [LoliconData.pid == result["pid"], LoliconData.p == result["p"]], { "pid": result["pid"], "p": result["p"], "uid": result["uid"], "title": result["title"], "author": result["author"], "r18": result["r18"], "width": result["width"], "height": result["height"], "tags": "|".join(result["tags"]), "ext": result["ext"], "upload_date": datetime.utcfromtimestamp( int(result["uploadDate"]) / 1000 ), "original_url": result["urls"]["original"], }, ) info = f"title: {result['title']}\nauthor: {result['author']}\nurl: {result['urls']['original']}" file_name = result["urls"]["original"].split("/").pop() local_path = ( config.image_path.get("setu18") if r18 else config.image_path.get("setu") ) file_path = os.path.join(local_path, file_name) if os.path.exists(file_path): return MessageChain( [ Plain(text=f"你要的{keyword}涩图来辣!\n"), Image(path=file_path), Plain(text=f"\n{info}"), ] ) else: async with aiohttp.ClientSession( connector=TCPConnector(verify_ssl=False) ) as session: async with session.get(url=result["urls"]["original"], proxy=proxy) as resp: img_content = await resp.read() if image_cache: image = PIL.Image.open(BytesIO(img_content)) image.save(file_path) return MessageChain( [ Plain(text=f"你要的{keyword}涩图来辣!\n"), Image(data_bytes=img_content), Plain(text=f"\n{info}"), ] )
return MessageItem(res, Normal()) for group in self.__cached[repo]['group']: try: await app.sendGroupMessage(group, res) except (AccountMuted, UnknownTarget): pass for friend in self.__cached[repo]['friend']: try: await app.sendFriendMessage(friend, res) except UnknownTarget: pass self.__is_running = False else: if manual: return MessageItem( MessageChain.create([Plain(text="Github 订阅插件已关闭。")]), QuoteSource()) except Exception as e: logger.error(e) self.__is_running = False gw = GithubWatcher() @channel.use(SchedulerSchema(timer=timers.every_minute())) async def github_schedule(app: Ariadne): try: await gw.github_schedule(app=app, manual=False) except: pass
async def memberjoinevent_listener(app: Ariadne, event: MemberJoinEvent): member = event.member group = member.group if group.id == qq.littleskin_main: await app.sendGroupMessage(group, MessageChain.create( [At(member.id), Plain(' '), Plain(tF.join_welcome)]))
for element in message: if element["type"] == "plain": if content := element.get("content"): elements.append(Plain(content)) else: exceptions.append((element, "missing parameter: content")) elif element["type"] == "image": if content := element.get("content"): elements.append(Image(data_bytes=content)) elif url := element.get("url"): elements.append(Image(url=url)) elif path := element.get("path"): elements.append(Image(path=path)) else: exceptions.append((element, "missing parameter: content(bytes) / url(str) / path(str)")) return MessageChain(elements) if not exceptions else exceptions class UserData: _instance = None _data = {} _path: str = f"{os.path.dirname(__file__)}/data.json" def __new__(cls, path: str = f"{os.path.dirname(__file__)}/data.json"): if cls._instance is None: cls._instance = object.__new__(cls) return cls._instance def __init__(self, path: str = f"{os.path.dirname(__file__)}/data.json"): if not os.path.exists(path): if platform.system() != "Windows":
async def wrong_usage_tips(app: Ariadne, group: Group, messagechain: MessageChain): msg_text = messagechain.asDisplay() if msg_text.startswith(('&mute ', '&unmute')) and msg_text.endswith(' '): await app.sendGroupMessage(group, MessageChain.create([Plain('请删除末尾空格后重试')]))
async def srr_wrapper(app: Ariadne, group: Group): await app.sendGroupMessage(group, MessageChain.create(reply_content))
async def grass_spammer(app: Ariadne, group: Group, msg: MessageChain): disable_in_groups: List[int] = [qq.littleskin_main, qq.csl_group] if not group.id in disable_in_groups: await app.sendGroupMessage(group, MessageChain.create( [Plain('\u202e草')]))
async def command_handler(app: Ariadne, group: Group): infos = await apis.AuthlibInjectorLatest.get() _message = f'authlib-injector 最新版本:{infos.version}\n{infos.download_url}' await app.sendGroupMessage(group, MessageChain.create([Plain(_message)]))
async def wrapper(*args, **kwargs): try: return await func(*args, **kwargs) except Exception as e: return MessageChain(f"{func.__name__}运行出错:{str(e)}")
async def hot_words_explainer(app: Ariadne, message: MessageChain, group: Group, keyword: RegexResult): await app.sendGroupMessage(group, await get_result(keyword.result.asDisplay()), quote=message.getFirst(Source))
async def tarot(app: Ariadne, message: MessageChain, group: Group): await app.sendGroupMessage(group, Tarot.get_tarot(), quote=message.getFirst(Source))
async def handle(app: Ariadne, message: MessageChain, group: Group, member: Member) -> MessageItem: # global saya_data if message.asDisplay().strip() == "已加载插件": loaded_channels = SayaManager.get_loaded_channels() keys = list(loaded_channels.keys()) keys.sort() return MessageItem( await MessageChainUtils.messagechain_to_img( MessageChain.create([Plain(text="目前加载插件:\n")] + [ Plain( text=f"{i + 1}. {loaded_channels[keys[i]]._name}\n" ) for i in range(len(keys)) ] + [Plain(text="发送 `插件详情 [编号|名称]` 可查看插件详情")])), QuoteSource()) elif re.match(r"插件详情 .+", message.asDisplay()): target = message.asDisplay()[5:].strip() loaded_channels = SayaManager.get_loaded_channels() keys = list(loaded_channels.keys()) if target.isdigit(): keys.sort() if not 0 <= int(target) - 1 < len(keys): return MessageItem( MessageChain.create([Plain(text="错误的编号!请检查后再发送!")]), QuoteSource()) channel = loaded_channels[keys[int(target) - 1]] channel_path = keys[int(target) - 1] else: for lchannel in loaded_channels.keys(): if loaded_channels[lchannel]._name == target: channel = loaded_channels[lchannel] channel_path = lchannel break else: return MessageItem( MessageChain.create([Plain(text="错误的名称!请检查后再发送!")]), QuoteSource()) return MessageItem( MessageChain.create([ Plain(text=f"插件名称:{channel._name}\n"), Plain(text=f"插件作者:{'、'.join(channel._author)}\n"), Plain(text=f"插件描述:{channel._description}\n"), Plain(text=f"插件包名:{channel_path}") ]), QuoteSource()) elif message.asDisplay() == "未加载插件": if not await user_permission_require(group, member, 3): return MessageItem(MessageChain.create([Plain(text="爬,权限不足")]), QuoteSource()) unloaded_channels = SayaManager.get_unloaded_channels() unloaded_channels.sort() return MessageItem( MessageChain.create([Plain(text="目前未加载插件:\n")] + [ Plain(text=f"{i + 1}. {unloaded_channels[i]}\n") for i in range(len(unloaded_channels)) ] + [Plain(text="发送 `[加载|卸载|重载]插件 [编号|名称]` 可加载/卸载/重载插件\n")]), QuoteSource()) elif re.match(r"加载插件 .+", message.asDisplay()): if not await user_permission_require(group, member, 3): return MessageItem(MessageChain.create([Plain(text="爬,权限不足")]), QuoteSource()) target = message.asDisplay()[5:].strip() unloaded_channels = SayaManager.get_unloaded_channels() if target.isdigit(): unloaded_channels.sort() if not 0 <= int(target) - 1 < len(unloaded_channels): return MessageItem( MessageChain.create([Plain(text="错误的编号!请检查后再发送!")]), QuoteSource()) channel = unloaded_channels[int(target) - 1] else: for ulchannel in unloaded_channels: if ulchannel == target: channel = ulchannel break else: return MessageItem( MessageChain.create([Plain(text="错误的名称!请检查后再发送!")]), QuoteSource()) await app.sendMessage( group, MessageChain.create( [Plain(text=f"你确定要加载插件 `{channel}` 吗?(是/否)")])) @Waiter.create_using_function([GroupMessage]) def confirm_waiter(waiter_group: Group, waiter_member: Member, waiter_message: MessageChain): if all([ waiter_group.id == group.id, waiter_member.id == member.id ]): if re.match(r"[是否]", waiter_message.asDisplay()): return waiter_message.asDisplay() else: return "" result = await inc.wait(confirm_waiter) if not result: return MessageItem( MessageChain.create([Plain(text="非预期回复,进程退出")]), QuoteSource()) elif result == "是": result = SayaManager.load_channel(channel) if result: return MessageItem( MessageChain.create( [Plain(text=f"发生错误:{result[channel]}")]), QuoteSource()) else: return MessageItem( MessageChain.create([Plain(text="加载成功")]), QuoteSource()) else: return MessageItem(MessageChain.create([Plain(text="进程退出")]), QuoteSource()) elif re.match(r"[卸重]载插件 .+", message.asDisplay()): if not await user_permission_require(group, member, 3): return MessageItem(MessageChain.create([Plain(text="爬,权限不足")]), QuoteSource()) load_type = "reload" if message.asDisplay()[0] == "重" else "unload" target = message.asDisplay()[5:].strip() loaded_channels = SayaManager.get_loaded_channels() keys = list(loaded_channels.keys()) keys.sort() if target.isdigit(): if not 0 <= int(target) - 1 < len(keys): return MessageItem( MessageChain.create([Plain(text="错误的编号!请检查后再发送!")]), QuoteSource()) channel = loaded_channels[keys[int(target) - 1]] channel_path = keys[int(target) - 1] else: for lchannel in loaded_channels.keys(): if loaded_channels[lchannel]._name == target: channel = loaded_channels[lchannel] channel_path = lchannel break else: return MessageItem( MessageChain.create([Plain(text="错误的名称!请检查后再发送!")]), QuoteSource()) await app.sendMessage( group, MessageChain.create([ Plain( text= f"你确定要{message.asDisplay()[0]}载插件 `{channel._name}` 吗?(是/否)" ) ])) @Waiter.create_using_function([GroupMessage]) def confirm_waiter(waiter_group: Group, waiter_member: Member, waiter_message: MessageChain): if all([ waiter_group.id == group.id, waiter_member.id == member.id ]): if re.match(r"[是否]", waiter_message.asDisplay()): return waiter_message.asDisplay() else: return "" result = await inc.wait(confirm_waiter) if not result: return MessageItem( MessageChain.create([Plain(text="非预期回复,进程退出")]), QuoteSource()) elif result == "是": result = SayaManager.unload_channel( channel_path ) if load_type == "unload" else SayaManager.reload_channel( channel_path) if result: return MessageItem( MessageChain.create( [Plain(text=f"发生错误:{result[channel_path]}")]), QuoteSource()) else: return MessageItem( MessageChain.create( [Plain(text=f"{message.asDisplay()[0]}载成功")]), QuoteSource()) else: return MessageItem(MessageChain.create([Plain(text="进程退出")]), QuoteSource()) elif re.match(r"(打开|关闭)插件 .+", message.asDisplay()): if not await user_permission_require(group, member, 3): return MessageItem(MessageChain.create([Plain(text="爬,权限不足")]), QuoteSource()) switch_type = "on" if message.asDisplay()[:2] == "打开" else "off" target = message.asDisplay()[5:].strip() loaded_channels = SayaManager.get_loaded_channels() keys = list(loaded_channels.keys()) keys.sort() channel_path = "" if target.isdigit(): if not 0 <= int(target) - 1 < len(keys): return MessageItem( MessageChain.create([Plain(text="错误的编号!请检查后再发送!")]), QuoteSource()) channel_path = keys[int(target) - 1] else: for lchannel in loaded_channels.keys(): if loaded_channels[lchannel]._name == target: channel_path = lchannel break saya_data.switch_on( channel_path, group) if switch_type == "on" else saya_data.switch_off( channel_path, group) return MessageItem( MessageChain.create([ Plain(text=f"插件{channel_path}已{message.asDisplay()[:2]}!") ]), QuoteSource())
async def pica_function(app: Ariadne, message: MessageChain, group: Group, member: Member, operation: RegexResult, message_type: ArgResult, forward_type: ArgResult, rank_time: RegexResult, content: RegexResult): if not pica.init: await app.sendGroupMessage(group, MessageChain("pica实例初始化失败,请重启机器人或重载插件!")) return if any([ operation.result.asDisplay() == "download" and not DAILY_DOWNLOAD_LIMITER.check(member.id), operation.result.asDisplay() == "search" and not DAILY_SEARCH_LIMITER.check(member.id), operation.result.asDisplay() == "random" and not DAILY_RANDOM_LIMITER.check(member.id), operation.result.asDisplay() == "rank" and not DAILY_RANK_LIMITER.check(member.id) ]): await app.sendGroupMessage(group, MessageChain(limit_text[str( operation.result.asDisplay())]), quote=message.getFirst(Source)) return if operation.result.asDisplay() == "download": DAILY_DOWNLOAD_LIMITER.increase(member.id) elif operation.result.asDisplay() == "search": DAILY_SEARCH_LIMITER.increase(member.id) elif operation.result.asDisplay() == "random": DAILY_RANDOM_LIMITER.increase(member.id) elif operation.result.asDisplay() == "rank": DAILY_RANK_LIMITER.increase(member.id) if operation.result.asDisplay() == "init": if pica.init: await app.sendGroupMessage(group, MessageChain("pica已初始化")) return try: await pica.check() await app.sendGroupMessage(group, MessageChain("pica初始化成功")) except aiohttp.ClientConnectorError: await app.sendGroupMessage(group, MessageChain("pica初始化失败,请检查代理")) except KeyError: await app.sendGroupMessage(group, MessageChain("pica初始化失败,请检查账号密码是否配置正确")) elif operation.result.asDisplay( ) == "download" and forward_type.matched and content.matched: comic_id = content.result.asDisplay() await app.sendMessage(group, MessageChain(f"收到请求,正在下载{comic_id}...")) info = await pica.download_comic(comic_id, False) image_list = [] for root, _, files in os.walk(info[0]): for file in files: if file[-4:] in (".jpg", ".png"): image_list.append(os.path.join(root, file)) node_count = 0 time_count = 0 time_base = datetime.now() - timedelta(seconds=len(image_list)) forward_nodes = [ ForwardNode( senderId=bot_qq, time=time_base + timedelta(seconds=time_count), senderName="纱雾酱", messageChain=MessageChain("IOS系统可能会乱序,请参照下方文件名和发送时间顺序自行排序!")) ] for path in image_list: node_count += 1 time_count += 1 forward_nodes.append( ForwardNode( senderId=bot_qq, time=time_base + timedelta(seconds=time_count), senderName="纱雾酱", messageChain=MessageChain([ Image(path=path), Plain( f"\n{path.replace(info[0], '')}\n{time_base + timedelta(seconds=time_count)}" ) ]))) if node_count == 20: await app.sendMessage( group, MessageChain([Forward(nodeList=forward_nodes)])) forward_nodes = [ ForwardNode(senderId=bot_qq, time=time_base + timedelta(seconds=time_count), senderName="纱雾酱", messageChain=MessageChain( "IOS系统可能会乱序,请参照下方文件名和发送时间顺序自行排序!")) ] node_count = 0 await app.sendGroupMessage( group, MessageChain([Forward(nodeList=forward_nodes)])) elif operation.result.asDisplay( ) == "download" and message_type.matched and content.matched: comic_id = content.result.asDisplay() await app.sendMessage(group, MessageChain(f"收到请求,正在下载{comic_id}...")) info = await pica.download_comic(comic_id, False) image_list = [] for root, _, files in os.walk(info[0]): for file in files: if not file[-3:] == "zip": image_list.append(os.path.join(root, file)) await app.sendGroupMessage( group, MessageChain([Image(path=path) for path in image_list])) elif operation.result.asDisplay() == "download" and content.matched: comic_id = message.asDisplay()[14:] await app.sendMessage(group, MessageChain(f"收到请求,正在下载{comic_id}...")) info = await pica.download_comic(comic_id) try: await app.uploadFile(data=info[1], method=UploadMethod.Group, target=group, name=f"{info[0].replace(' ', '')}.zip") except RemoteException: await app.uploadFile(data=info[1], method=UploadMethod.Group, target=group, name=f"pica_{comic_id}.zip") return None elif operation.result.asDisplay() in ("search", "random"): search = operation.result.asDisplay() == "search" keyword = content.result.asDisplay() if content.matched else '' if search and content.matched: await app.sendMessage(group, MessageChain(f"收到请求,正在搜索{keyword}...")) data = (await pica.search(keyword))[:10] \ if search else (await pica.random())[:10] forward_nodes = [] for comic in data: comic_info = await pica.comic_info( comic["id"] ) if operation.result.asDisplay() == "search" else comic try: forward_nodes.append( ForwardNode( senderId=bot_qq, time=datetime.now(), senderName="纱雾酱", messageChain=MessageChain([ Image(data_bytes=TextEngine([ GraiaAdapter( MessageChain([ await get_thumb(comic_info), Plain( text=f"\n名称:{comic_info['title']}\n" ), Plain( text=f"作者:{comic_info['author']}\n" ), Plain( text= f"描述:{comic_info['description']}\n" ) if search else Plain(text=''), Plain( text= f"分类:{'、'.join(comic_info['categories'])}\n" ), Plain( text= f"标签:{'、'.join(comic_info['tags'])}\n" ) if search else Plain(text=''), Plain( text= f"页数:{comic_info['pagesCount']}\n" ), Plain( text= f"章节数:{comic_info['epsCount']}\n"), Plain( text= f"完结状态:{'已完结' if comic_info['finished'] else '未完结'}\n" ), Plain( text= f"喜欢: {comic_info['totalLikes']} " ), Plain( text= f"浏览次数: {comic_info['totalViews']} " ) ])) ], max_width=2160).draw()) ]).extend([ Plain(text="\n发送下列命令下载:\n"), Plain( text= f"转发消息形式:pica download -forward {comic_info['_id']}\n" ), Plain( text= f"消息图片形式:pica download -message {comic_info['_id']}\n" ), Plain( text=f"压缩包形式:pica download {comic_info['_id']}" ) ]))) except Exception as e: logger.error(e) continue await app.sendGroupMessage( group, MessageChain([Forward(nodeList=forward_nodes)])) elif operation.result.asDisplay() == "rank": rank_time = rank_time.result.asDisplay( ) if rank_time.matched else "-H24" if rank_time not in ("-H24", "-D7", "-D30"): await app.sendGroupMessage( group, MessageChain([ Plain(text="错误的时间!支持的选项:\n"), Plain(text="H24:24小时排行榜\n"), Plain(text="D7:一周排行榜\n"), Plain(text="D30:一月排行榜\n"), Plain(text="命令格式:pica random -{time}") ])) return data = (await pica.rank(rank_time[1:]))[:10] forward_nodes = [] rank = 0 for comic_info in data: rank += 1 try: forward_nodes.append( ForwardNode( senderId=bot_qq, time=datetime.now(), senderName="纱雾酱", messageChain=MessageChain([ Image(data_bytes=TextEngine([ GraiaAdapter( MessageChain([ await get_thumb(comic_info), Plain(text=f"\n排名:{rank}\n"), Plain( text=f"名称:{comic_info['title']}\n" ), Plain( text=f"作者:{comic_info['author']}\n" ), Plain( text= f"分类:{'、'.join(comic_info['categories'])}\n" ), Plain( text= f"页数:{comic_info['pagesCount']}\n" ), Plain( text= f"章节数:{comic_info['epsCount']}\n"), Plain( text= f"完结状态:{'已完结' if comic_info['finished'] else '未完结'}\n" ), Plain( text= f"喜欢: {comic_info['totalLikes']} " ), Plain( text= f"浏览次数: {comic_info['totalViews']} " ) ])) ], max_width=2160).draw()) ]).extend([ Plain(text="\n发送下列命令下载:\n"), Plain( text= f"转发消息形式:pica download -forward {comic_info['_id']}\n" ), Plain( text= f"消息图片形式:pica download -message {comic_info['_id']}\n" ), Plain( text=f"压缩包形式:pica download {comic_info['_id']}" ) ]))) except Exception as e: logger.error(e) continue await app.sendGroupMessage( group, MessageChain([Forward(nodeList=forward_nodes)]))
async def pero_dog(app: Ariadne, group: Group): await app.sendGroupMessage(group, MessageChain(random.choice(pero_dog_contents).replace('*', '')))
question_slug_data = await get_daily_question_json() question_slug = question_slug_data["data"]["todayRecord"][0]["question"][ "questionTitleSlug"] content = await get_question_content(question_slug, language) content = image_in_html_to_text(content) message_list = [] for i in content: if i: if re.match(r"img\[[0-9]+]:", i): if url := i.replace( re.findall(r"img\[[0-9]+]:", i, re.S)[0], ''): message_list.append(Image(url=url)) else: message_list.append(Plain(text=i)) return MessageChain( [Image(data_bytes=TextEngine([GraiaAdapter(message_list)]).draw())]) async def get_leetcode_user_statics(account_name: str) -> MessageChain: url = "https://leetcode-cn.com/graphql/" headers = { "origin": "https://leetcode-cn.com", "referer": "https://leetcode-cn.com/u/%s/" % account_name, "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/80.0.3987.100 Safari/537.36", "x-definition-name": "userProfilePublicProfile", "x-operation-name":
async def enable(self, **kwargs): self.__status = True return MessageChain.create([Plain(text="已开启 Github 仓库订阅")])
async def get_leetcode_user_statics(account_name: str) -> MessageChain: url = "https://leetcode-cn.com/graphql/" headers = { "origin": "https://leetcode-cn.com", "referer": "https://leetcode-cn.com/u/%s/" % account_name, "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/80.0.3987.100 Safari/537.36", "x-definition-name": "userProfilePublicProfile", "x-operation-name": "userPublicProfile", "content-type": "application/json" } payload = { 'operationName': "userPublicProfile", "query": "query userPublicProfile($userSlug: String!) {\n userProfilePublicProfile(userSlug: $userSlug) {\n " " username,\n haveFollowed,\n siteRanking,\n profile {\n userSlug,\n realName," "\n aboutMe,\n userAvatar,\n location,\n gender,\n websites," "\n skillTags,\n contestCount,\n asciiCode,\n medals {\n name," "\n year,\n month,\n category,\n __typename,\n }\n ranking {\n " " rating,\n ranking,\n currentLocalRanking,\n currentGlobalRanking," "\n currentRating,\n ratingProgress,\n totalLocalUsers,\n " "totalGlobalUsers,\n __typename,\n }\n skillSet {\n langLevels {\n " "langName,\n langVerboseName,\n level,\n __typename,\n }\n " "topics {\n slug,\n name,\n translatedName,\n __typename," "\n }\n topicAreaScores {\n score,\n topicArea {\n name," "\n slug,\n __typename,\n }\n __typename,\n }\n " " __typename,\n }\n socialAccounts {\n provider,\n profileUrl," "\n __typename,\n }\n __typename,\n }\n educationRecordList {\n " "unverifiedOrganizationName,\n __typename,\n }\n occupationRecordList {\n " "unverifiedOrganizationName,\n jobTitle,\n __typename,\n }\n submissionProgress {\n " " totalSubmissions,\n waSubmissions,\n acSubmissions,\n reSubmissions," "\n otherSubmissions,\n acTotal,\n questionTotal,\n __typename\n }\n " "__typename\n }\n}", 'variables': '{"userSlug": "%s"}' % account_name } async with get_running(Adapter).session.post( url=url, headers=headers, data=json.dumps(payload)) as resp: data_json = await resp.json() if 'userProfilePublicProfile' in data_json["data"].keys() \ and data_json["data"]['userProfilePublicProfile'] is None: return MessageChain(f"未找到 userSlug: {account_name}!") data_json = data_json['data']['userProfilePublicProfile'] profile = data_json['profile'] user_slug = profile['userSlug'] user_name = profile['realName'] ranking = data_json['siteRanking'] if ranking == 100000: ranking = "%s+" % ranking websites_list = profile['websites'] websites = [] for i in websites_list: websites.append("\n %s" % i) skills_list = profile['skillTags'] skills = [] for i in skills_list: skills.append("\n %s" % i) architecture = profile['skillSet']['topicAreaScores'][0]['score'] data_structures = profile['skillSet']['topicAreaScores'][1]['score'] algorithms = profile['skillSet']['topicAreaScores'][2]['score'] design = profile['skillSet']['topicAreaScores'][3]['score'] solved_problems = data_json['submissionProgress']['acTotal'] ac_submissions = data_json['submissionProgress']['acSubmissions'] total_question = data_json['submissionProgress']['questionTotal'] total_submissions = data_json['submissionProgress']['totalSubmissions'] submission_pass_rate = float(100 * ac_submissions / total_submissions) return MessageChain([ f"userSlug: {user_slug}\n", f" userName: {user_name}\n", f" ranking: {ranking}\n", f" websites: {''.join(websites)}\n", f" skills: {''.join(skills)}\n", " score:\n", f" architecture: {architecture}%\n", f" data-structures: {data_structures}%\n", f" algorithms: {algorithms}%\n", f" design: {design}%\n", f" solvedProblems: {solved_problems}/{total_question}\n", f" acSubmissions: {ac_submissions}\n", f" submissionPassRate: {submission_pass_rate}%", ])
async def add(self, **kwargs): if not self.__status: return MessageChain.create([Plain(text="Github 仓库订阅功能已关闭")]) repos = None group = None friend = None app = None for name, arg in kwargs.items(): if name == "arg" and isinstance(arg, str): repos = arg if isinstance(arg, Group): group = arg if isinstance(arg, Friend): friend = arg if isinstance(arg, Ariadne): app = arg err = [] if not group and not friend: err = err.extend([Plain(text="无法获取 Group 或 Friend 实例")]) if not app: err = err.extend([Plain(text="无法获取 Ariadne 实例")]) if not repos: err = err.extend([Plain(text="未填写需要订阅的仓库")]) if err: return MessageChain.create(err) repos = repos.split(" ") failed = [] duplicated = [] success_count = 0 for repo in repos: url = f"https://api.github.com/search/repositories?q={repo}" async with self.__session.get(url=url, proxy=proxy) as resp: try: resp.raise_for_status() except aiohttp.ClientError as e: logger.error(e) logger.error(f"暂时无法取得仓库 {repo} 的更新(状态码 {resp.status})") continue result = (await resp.json())["items"] if not result: failed.append(repo) continue repo = result[0]['full_name'] repo = repo.split("/") repo = (repo[0], repo[1]) if repo not in self.__cached.keys(): self.__cached[repo] = { "group": [], "friend": [], "last_id": -1, "enabled": True } if group: if group.id in self.__cached[repo]['group']: duplicated.append(f"{repo[0]}/{repo[1]}") else: self.__cached[repo][ 'group'] = self.__cached[repo]['group'] + [group.id] if friend: if friend.id in self.__cached[repo]['friend']: duplicated.append(f"{repo[0]}/{repo[1]}") else: self.__cached[repo]['friend'] = self.__cached[repo][ 'friend'] + [friend.id] if self.__cached[repo]['last_id'] == -1: await self.github_schedule(app=app, manuel=True, per_page=1, page=1, repo=repo) success_count += 1 res = [Plain(text=f"{success_count} 个仓库订阅成功")] if failed: res.append( Plain(text=f"\n{len(failed)} 个仓库订阅失败" f"\n失败的仓库有:{' '.join(failed)}")) if duplicated: res.append( Plain(text=f"\n{len(duplicated)} 个仓库已在订阅列表中" f"\n重复的仓库有:{' '.join(duplicated)}")) try: self.store_cache(manual=False) self.update_cache(manual=False) return MessageChain.create(res) except Exception as e: logger.error(e) res.append(Plain(text="\n\n刷新缓存失败")) return MessageChain.create(res)
return else: target = member if avatar := await get_avatar(target, 160): avatar = BuildImage(200, 100, background=BytesIO(avatar)) else: avatar = BuildImage(200, 100, color=(0, 0, 0)) avatar.circle_new() text = BuildImage(300, 30, font_size=30, color="white" if not dark.matched else "black") text.text((0, 0), member.name, (0, 0, 0) if not dark.matched else (141, 141, 146)) A = BuildImage(700, 150, font_size=25, color="white" if not dark.matched else "black") A.paste(avatar, (30, 25), True) A.paste(text, (150, 38)) A.text((150, 85), content.strip(), (125, 125, 125) if not dark.matched else (255, 255, 255)) await app.sendGroupMessage(group, MessageChain( [Image(data_bytes=A.pic2bytes())]), quote=message.getFirst(Source)) else: await app.sendGroupMessage(group, MessageChain("都不知道问什么"), quote=message.getFirst(Source))
async def real_handle(self, app: Ariadne, message: MessageChain, group: Group = None, member: Member = None, friend: Friend = None) -> MessageItem: commands = { "enable": { "permission": [3, []], "permission_nl": "3 级权限", "manual": "/github-watch enable", "description": "启用 Github 订阅功能", "func": self.enable }, "disable": { "permission": [3, []], "permission_nl": "3 级权限", "manual": "/github-watch disable", "description": "禁用 Github 订阅功能", "func": self.disable }, "add": { "permission": [2, (MemberPerm.Administrator, MemberPerm.Owner)], "permission_nl": "2 级或群管理员及以上权限", "manual": "/github-watch add {repo} [repo]+", "description": "订阅仓库变动,可同时订阅多个仓库", "func": self.add }, "remove": { "permission": [2, (MemberPerm.Administrator, MemberPerm.Owner)], "permission_nl": "2 级或群管理员及以上权限", "manual": "/github-watch remove {repo} [repo]+", "description": "取消订阅仓库变动,可同时取消订阅多个仓库", "func": self.remove }, "check": { "permission": [ 1, (MemberPerm.Member, MemberPerm.Administrator, MemberPerm.Owner) ], "permission_nl": "任何人", "manual": "/github-watch check", "description": "手动查看仓库订阅列表", "func": self.check }, "cache": { "permission": [2, (MemberPerm.Administrator, MemberPerm.Owner)], "permission_nl": "2 级或群管理员及以上权限", "manual": "/github-watch cache {update/store}", "description": "更新/储存缓存", "func": self.cache } } if message.asDisplay().startswith("/github-watch"): if not self.initialize: self.update_cache() for repo in self.__cached.keys(): self.__cached[repo]['enabled'] = True self.store_cache() self.initialize = True args = message.asDisplay().split(" ", maxsplit=1) if len(args) == 1: msg = [Plain(text="缺少参数\n\n")] for func in commands.keys(): msg.append( Plain(text=( f"/github-watch {func}\n" f" 描述:{commands[func]['description']}\n" f" 用法:{commands[func]['manual']}\n" f" 权限:{commands[func]['permission_nl']}\n"))) return MessageItem( await MessageChainUtils.messagechain_to_img( MessageChain.create(msg)), QuoteSource()) _, args = args name = args.split(" ", maxsplit=1)[0] arg = ''.join(args.split(" ", maxsplit=1)[1:]) if name not in commands.keys(): return MessageItem( MessageChain.create([Plain(text=f"未知指令:{arg}")]), QuoteSource()) if member and group: permission = commands[name]['permission'] if not await user_permission_require(group, member, permission[0]) \ and not (member.permission in permission[1]): return MessageItem( MessageChain.create([ Plain( text=f"权限不足,你需要 {permission[0]} 级权限" f"{('或来自 ' + str(permission[1][0]) + ' 的权限') if permission[1] else ''}" ) ]), QuoteSource()) arg = arg.strip() return MessageItem( await commands[name]['func'](app=app, group=group, friend=friend, arg=arg), QuoteSource())
async def wordle(app: Ariadne, message: MessageChain, group: Group, member: Member, single_game: ArgResult, dic: RegexResult, length: ArgResult, get_help: ArgResult, give_up: ArgResult, statistic: ArgResult) -> NoReturn: if get_help.matched: await app.sendGroupMessage( group, MessageChain( "Wordle文字游戏\n" "答案为指定长度单词,发送对应长度单词即可\n" "灰色块代表此单词中没有此字母\n" "黄色块代表此单词中有此字母,但该字母所处位置不对\n" "绿色块代表此单词中有此字母且位置正确\n" "猜出单词或用光次数则游戏结束\n" "发起游戏:/wordle -l=5 -d=SAT,其中-l/-length为单词长度,-d/-dic为指定词典,默认为5和CET4\n" "中途放弃:/wordle -g 或 /wordle -giveup\n" "查看数据统计:/wordle -s 或 /wordle -statistic\n" "查看提示:/wordle -hint\n" f"注:目前包含词典:{'、'.join(word_dics)}")) return None if statistic.matched: data = await get_member_statistic(group, member) await app.sendGroupMessage( group, MessageChain( f"用户 {member.name}\n" f"共参与{data[4]}场游戏,其中胜利{data[0]}场,失败{data[1]}场\n" f"一共猜对{data[2]}次,猜错{data[3]}次,共使用过{data[5]}次提示,再接再厉哦~"), quote=message.getFirst(Source)) return None if give_up.matched: return None await mutex.acquire() if group.id in group_running and group_running[group.id]: await app.sendGroupMessage(group, MessageChain("本群已有正在运行中的游戏实例,请等待本局游戏结束!")) mutex.release() return None else: if dic.matched: dic = dic.result.asDisplay().split('=')[1].strip() if dic not in word_dics: await app.sendGroupMessage( group, MessageChain(f"没有找到名为{dic}的字典!已有字典:{'、'.join(word_dics)}")) mutex.release() return None else: group_word_dic[group.id] = dic elif group.id not in group_word_dic: group_word_dic[group.id] = DEFAULT_DIC group_running[group.id] = True mutex.release() single = single_game.matched length = int(length.result.asDisplay().split('=') [1].strip()) if length.matched else 5 if length not in word_list[group_word_dic[group.id]].keys(): await app.sendGroupMessage( group, MessageChain( f"单词长度错误,词库中没有长度为{length}的单词=!" f"目前词库({group_word_dic[group.id]})中" f"只有长度为{'、'.join([str(i) for i in sorted(word_list[group_word_dic[group.id]].keys())])}的单词!" )) await mutex.acquire() group_running[group.id] = False mutex.release() return None wordle_instance = Wordle(length, dic=group_word_dic[group.id]) logger.success(f"成功创建 Wordle 实例,单词为:{wordle_instance.word}") await app.sendGroupMessage( group, MessageChain([ Image(data_bytes=wordle_instance.get_board_bytes()), Plain( f"\n你有{wordle_instance.row}次机会猜出单词,单词长度为{wordle_instance.length},请发送单词" ) ]), quote=message.getFirst(Source)) game_end = False try: while not game_end: game_end = await inc.wait(WordleWaiter(wordle_instance, group, member if single else None), timeout=300) except asyncio.exceptions.TimeoutError: await app.sendGroupMessage(group, MessageChain("游戏超时,进程结束"), quote=message.getFirst(Source)) await mutex.acquire() group_running[group.id] = False mutex.release()
async def bot_leave_event_kick(app: Ariadne, event: BotLeaveEventKick): logger.warning("bot has been kicked!") await app.sendFriendMessage( config.host_qq, MessageChain.create([Plain(text=f"呜呜呜主人我被踢出{event.group.name}群了")]))
async def detected_event(self, app: Ariadne, group: Group, member: Member, message: MessageChain): word = message.asDisplay().strip() message_source = message.getFirst(Source) if self.group == group.id and (self.member == member.id or not self.member): if message.asDisplay().strip() in ("/wordle -giveup", "/wordle -g"): dic = group_word_dic[group.id] word_data = word_list[dic][len( self.wordle.word)][self.wordle.word] explain = '\n'.join( [f"【{key}】:{word_data[key]}" for key in word_data]) await app.sendGroupMessage( group, MessageChain([ Image(data_bytes=self.wordle.get_board_bytes()), Plain("很遗憾,没有人猜出来呢" f"单词:{self.wordle.word}\n{explain}") ]), quote=message_source) await self.member_list_mutex.acquire() for member in self.member_list: await update_member_statistic(group, member, StatisticType.lose) await update_member_statistic(group, member, StatisticType.game) self.member_list_mutex.release() await mutex.acquire() group_running[group.id] = False mutex.release() return True if message.asDisplay().strip() == "/wordle -hint": await update_member_statistic(group, member, StatisticType.hint) hint = self.wordle.get_hint() if not hint: await app.sendGroupMessage( group, MessageChain("你还没有猜对过一个字母哦~再猜猜吧~"), quote=message.getFirst(Source)) else: await app.sendGroupMessage( group, MessageChain( [Image(data_bytes=self.wordle.draw_hint())]), quote=message.getFirst(Source)) return False if len(word) == self.wordle.length and word.encode( 'utf-8').isalpha(): await self.member_list_mutex.acquire() self.member_list.add(member.id) self.member_list_mutex.release() await self.wordle.draw_mutex.acquire() print("required") result = self.wordle.guess(word) print(result) print("released") self.wordle.draw_mutex.release() if not result: return True if result[0]: await update_member_statistic( group, member, StatisticType.correct if result[1] else StatisticType.wrong) await self.member_list_mutex.acquire() for member in self.member_list: await update_member_statistic( group, member, StatisticType.win if result[1] else StatisticType.lose) await update_member_statistic(group, member, StatisticType.game) self.member_list_mutex.release() dic = group_word_dic[group.id] word_data = word_list[dic][len( self.wordle.word)][self.wordle.word] explain = '\n'.join( [f"【{key}】:{word_data[key]}" for key in word_data]) await app.sendGroupMessage( group, MessageChain([ Image(data_bytes=self.wordle.get_board_bytes()), Plain( f"\n{'恭喜你猜出了单词!' if result[1] else '很遗憾,没有人猜出来呢'}\n" f"【单词】:{self.wordle.word}\n{explain}") ]), quote=message_source) await mutex.acquire() group_running[group.id] = False mutex.release() return True elif not result[2]: await app.sendGroupMessage( group, MessageChain(f"你确定 {word} 是一个合法的单词吗?"), quote=message_source) elif result[3]: await app.sendGroupMessage(group, MessageChain("你已经猜过这个单词了呢"), quote=message_source) else: await update_member_statistic(group, member, StatisticType.wrong) await app.sendGroupMessage( group, MessageChain( [Image(data_bytes=self.wordle.get_board_bytes())]), quote=message_source) return False
async def handle( app: Ariadne, message: MessageChain, group: Group, member: Member, cmd: RegexResult, at1: ElementResult, at2: ElementResult, qq1: RegexResult, qq2: RegexResult, img1: ElementResult, img2: ElementResult ): if not any([at1.matched, at2.matched, qq1.matched, qq2.matched, img1.matched, img2.matched]): return None await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") message_text = message.asDisplay() if message_text.startswith("摸"): match_elements = AvatarFunPic.get_match_element(message) if len(match_elements) >= 1: await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") element = match_elements[0] return await AvatarFunPic.petpet(element.target if isinstance(element, At) else element.url) elif re.match(r"摸 [0-9]+", message_text): await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") return await AvatarFunPic.petpet(int(message_text[2:])) elif message_text.startswith("亲"): match_elements = AvatarFunPic.get_match_element(message) if len(match_elements) == 1: await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") element = match_elements[0] return await AvatarFunPic.kiss( member.id, element.target if isinstance(element, At) else element.url ) elif len(match_elements) > 1: await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") element1 = match_elements[0] element2 = match_elements[1] return await AvatarFunPic.kiss( element1.target if isinstance(element1, At) else element1.url, element2.target if isinstance(element2, At) else element2.url ) elif re.match(r"亲 [0-9]+ [0-9]+", message_text): await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") operator, target = message_text[2:].split(" ") return await AvatarFunPic.kiss(int(operator), int(target)) elif re.match(r"亲 [0-9]+", message_text): await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") return await AvatarFunPic.kiss(member.id, int(message_text[2:])) elif message_text.startswith("贴"): match_elements = AvatarFunPic.get_match_element(message) if len(match_elements) == 1: await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") element = match_elements[0] return await AvatarFunPic.rub( member.id, element.target if isinstance(element, At) else element.url ) elif len(match_elements) > 1: await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") element1 = match_elements[0] element2 = match_elements[1] return await AvatarFunPic.rub( element1.target if isinstance(element1, At) else element1.url, element2.target if isinstance(element2, At) else element2.url ) elif re.match(r"贴 [0-9]+ [0-9]+", message_text): await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") operator, target = message_text[2:].split(" ") return await AvatarFunPic.rub(int(operator), int(target)) elif re.match(r"贴 [0-9]+", message_text): await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") return await AvatarFunPic.rub(member.id, int(message_text[2:])) elif message_text.startswith("撕"): match_elements = AvatarFunPic.get_match_element(message) if len(match_elements) >= 1: await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") element = match_elements[0] return await AvatarFunPic.ripped(element.target if isinstance(element, At) else element.url) elif re.match(r"撕 [0-9]+", message_text): await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") return await AvatarFunPic.ripped(int(message_text[2:])) elif message_text.startswith("丢"): match_elements = AvatarFunPic.get_match_element(message) if len(match_elements) >= 1: await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") element = match_elements[0] return await AvatarFunPic.throw(element.target if isinstance(element, At) else element.url) elif re.match(r"丢 [0-9]+", message_text): await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") return await AvatarFunPic.throw(int(message_text[2:])) elif message_text.startswith("爬"): match_elements = AvatarFunPic.get_match_element(message) if len(match_elements) >= 1: await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") element = match_elements[0] return await AvatarFunPic.crawl(element.target if isinstance(element, At) else element.url) elif re.match(r"爬 [0-9]+", message_text): await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") return await AvatarFunPic.crawl(int(message_text[2:])) elif message_text.startswith("精神支柱"): match_elements = AvatarFunPic.get_match_element(message) if len(match_elements) >= 1: await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") element = match_elements[0] return await AvatarFunPic.support(element.target if isinstance(element, At) else element.url) elif re.match(r"精神支柱 [0-9]+", message_text): await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") return await AvatarFunPic.support(int(message_text[5:])) elif message_text.startswith("吞"): match_elements = AvatarFunPic.get_match_element(message) if len(match_elements) >= 1: await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") element = match_elements[0] return await AvatarFunPic.swallowed(element.target if isinstance(element, At) else element.url) elif re.match(r"吞 [0-9]+", message_text): await update_user_call_count_plus(group, member, UserCalledCount.functions, "functions") return await AvatarFunPic.swallowed(int(message_text[2:])) else: return None
group.id, target, level) elif level == 3: if await user_permission_require(group, member, 4): return await grant_permission_process( group.id, target, level) else: return MessageChain( "格式错误!权限不足,你必须达到权限等级4(master level)才可对超级管理员进行授权!") else: return MessageChain( "level值非法!合法level值:1-3\n1: user\n2: administrator\n3: super administrator" ) else: return MessageChain("格式错误!使用方法:user -grant @user level[1-3]") else: return MessageChain("权限不足,爬!") async def grant_permission_process(group_id: int, member_id: int, new_level: int) -> MessageChain: if await grant_permission(group_id, member_id, new_level): return MessageChain( f"修改成功!\n{member_id} permission level: {new_level}") else: return MessageChain("出现错误,请查看日志!") async def grant_permission(group_id: int, member_id: int, new_level: int) -> bool: try: await orm.insert_or_update(UserPermission, [