async def guilds_list(self, ctx: commands.Context): import datetime cmd_date: datetime.datetime = ctx.message.created_at embed_factory = EmbedFactory( title="[ 라떼봇 정보 ] 라떼봇이 참여한 서버 목록입니다.", description=f"[{cmd_date.tzinfo}] : {cmd_date} 에 측정한 데이터입니다.", color=EmbedFactory.default_color, author={ "name": EmbedFactory.get_user_info(self.bot.user, contain_id=False), "icon_url": self.bot.user.avatar_url }, footer=EmbedFactory.get_command_caller(ctx.author)) for guild in self.bot.guilds: join: datetime.datetime = guild.me.joined_at # await embed_factory.add_field( # { # "name": f"{guild.name}", # "value": f"주인 : {EmbedFactory.get_user_info(guild.owner)}\n봇 참여일자 : [{join.tzinfo}] {join}", # "inline": False # } # ) await embed_factory.add_field(( f"{guild.name}", f"주인 : {EmbedFactory.get_user_info(guild.owner)}\n봇 참여일자 : [{join.tzinfo}] {join}", False)) return await ctx.send(embed=await embed_factory.build())
async def on_guild_remove(self, guild: discord.Guild): owner_info = f"{guild.owner.name}#{guild.owner.discriminator}" if guild.owner is not None else "UNKNOWN" await self.bot.get_channel( self.bot.config.config["admin_log"] ).send(embed=await EmbedFactory( title="[EVENT] 라떼봇이 서버에서 떠났습니다!", description="event : on_guild_remove", author={ "name": EmbedFactory.get_user_info(user=self.bot.user, contain_id=True), "icon_url": self.bot.user.avatar_url }, footer=EmbedFactory.get_command_caller(guild.owner) if guild. owner is not None else { "text": "UNKNOWN", "icon_url": self.bot.user.avatar_url }, fields=[{ "name": "떠난 서버 정보", "value": f"이름 : {guild.name}\nid : {guild.id}\n주인 : {owner_info} ({guild.owner_id})" }]).build())
async def notice(self, ctx: commands.Context, title: str, desc: str, *, content: str): title = title.replace('_', ' ') desc = desc.replace('_', ' ') embed = await EmbedFactory( title=title, description=desc, author={ "name": EmbedFactory.get_user_info(self.bot.user, contain_id=False), "icon_url": self.bot.user.avatar_url }, footer=EmbedFactory.get_command_caller(ctx.author), color=EmbedFactory.default_color, fields=[{ "name": "상세한 내용", "value": content, "inline": False }]).build() for guild in self.bot.guilds: if guild.system_channel is not None: await guild.system_channel.send(embed=embed) else: target_channels: List[discord.TextChannel] = [ ch for ch in guild.text_channels if ch.topic is not None and "공지" in ch.topic ] if len(target_channels) > 0: await target_channels[0].send(embed=embed) else: from random import choice await choice(guild.text_channels).send(embed=embed)
async def unban(self, ctx: commands.Context, target_id: int, *, reason: str = ""): target_ban_entry: discord.guild.BanEntry = discord.utils.find( lambda be: be.user.id == target_id, await ctx.guild.bans()) if target_ban_entry is None: return await ctx.send("해당 유저는 차단되지 않았습니다!") await ctx.guild.unban(target_ban_entry.user, reason=reason) return await ctx.send(embed=await EmbedFactory( title="[ 관리 ] 멤버를 차단 해제했습니다!", footer=EmbedFactory.get_command_caller(ctx.author), color=EmbedFactory.default_color, fields=[{ "name": "차단한 멤버", "value": EmbedFactory.get_user_info(target_ban_entry.user), "inline": False }, { "name": "차단 해제 사유", "value": reason, "inline": False }, { "name": "이 유저가 차단되었던 사유", "value": target_ban_entry.reason, "inline": False }]).build())
async def roll_the_dice(self, ctx: commands.Context, start: int = 1, end: int = 6): if start > end: start, end = end, start if start < -128 or end > 127: return await ctx.send( embed=EmbedFactory.COMMAND_LOG_EMBED( title="주사위를 굴릴 수 없습니다!", description="숫자가 너무 큽니다! 범위는 -128 ~ 127 사이만 가능합니다.\n" "(과도하게 큰 수를 사용하는 몇몇 유저들을 위한 조치입니다.)", user=ctx.author ) ) import random result = random.randint(start, end) result_embed_factory = EmbedFactory( title="🎲 주사위를 던졌어요!", description=f"결과 : {result}", color=EmbedFactory.default_color, author={ "name": self.bot.user.display_name, "icon_url": self.bot.user.avatar_url }, footer={ "text": f"command executed by {EmbedFactory.get_user_info(user=ctx.author)}", "icon_url": ctx.author.avatar_url } ) await ctx.send(embed=await result_embed_factory.build())
async def get_server_info(self, ctx: commands.Context): # Create an Embed which contains member's information caller_info = EmbedFactory.get_command_caller(user=ctx.author) # Because discord.py does not provide region "south-korea" but discord api does, # we need to request to discord api directly to get proper region info. response = await self.bot.api_get(api_url=f"/guilds/{ctx.guild.id}", response_type="json") embed_factory = EmbedFactory( title=f"{ctx.guild.name} 서버 정보입니다!", color=EmbedFactory.default_color, author={ "name": f"{EmbedFactory.get_user_info(user=self.bot.user, contain_id=False)}", "icon_url": self.bot.user.avatar_url }, footer={ "text": f"{caller_info['text']}", "icon_url": f"{caller_info['icon_url']}" }, thumbnail_url=ctx.guild.icon_url, fields=[{ "name": "서버 주인", "value": ctx.guild.owner.mention, "inline": False }, { "name": "서버 생성 날짜", "value": str(ctx.guild.created_at), "inline": True }, { "name": "서버 지역", "value": response["region"], "inline": True }, { "name": "서버 멤버 수", "value": str(len(ctx.guild.members)), "inline": False }, { "name": "서버 채널 수", "value": f"total : {len(ctx.guild.channels)} | category : {len(ctx.guild.categories)} | text : {len(ctx.guild.text_channels)} | voice : {len(ctx.guild.voice_channels)}", "inline": True }, { "name": "서버 역할들", "value": str([role.mention for role in ctx.guild.roles]), "inline": False }]) await ctx.send(embed=await embed_factory.build(), allowed_mentions=discord.AllowedMentions(everyone=False, users=False, roles=False))
async def get_bot_info(self, ctx: commands.Context): # Create an Embed which contains member's information caller_info = EmbedFactory.get_command_caller(user=ctx.author) user_count = len(list(filter(lambda u: not u.bot, self.bot.users))) created = self.bot.user.created_at embed_factory = EmbedFactory( title="라떼봇 정보", description=f"현재 **`{len(self.bot.guilds)}`**개의 서버에서 사용중이며, **`{user_count}`**명의 유저들과 소통중입니다.", color=EmbedFactory.default_color, author={ "name": f"{EmbedFactory.get_user_info(user=self.bot.user, contain_id=True)}", "icon_url": self.bot.user.avatar_url }, footer={ "text": f"{caller_info['text']}", "icon_url": f"{caller_info['icon_url']}" }, thumbnail_url=self.bot.user.avatar_url, fields=[ { "name": "**개발자**", "value": "sleepylapis#1608", "inline": False }, { "name": "**봇 운영 기간**", "value": f"{created.year}년 {created.month}월 {created.day}일 ~ 현재", "inline": True }, { "name": "**라떼봇에 기여해주신 분들 - 코드 부분**", "value": "BGM (Github : khk4912) : 라떼봇의 로그 문제를 해결해 주셨습니다!\n" "라고솔로가말했습니다 (Github : SaidBySolo) : 라떼봇의 코드 안에 잔재하던 오타들을 수정해 주셨습니다!\n", "inline": False }, { "name": "**라떼봇에 기여해주신 분들 - 그래픽 부분**", "value": "Star_Pixeller : 라떼봇의 프로필 이미지를 만들어 주셨습니다!\n", "inline": False }, { "name": "**라떼봇에 기여해주신 분들 - 테스트 부분**", "value": "HOREON : 수많은 테스트를 통해 버그를 찾아내는걸 도와주셨습니다 :D", "inline": False } ] ) await ctx.send(embed=await embed_factory.build())
async def search_naver(self, ctx: commands.Context, category: str, count: int = 3, *, query: str): if count <= 0: count = 3 result: dict = await self.naverSearch.search(category=category, query=query, response_format="xml", count=count) search_embeds: List[discord.Embed] = [] for item in result.values(): fields: List[Dict[str, str]] = [{ "name": "글 제목", "value": item["title"] }, { "name": "글 내용", "value": item["description"] }, { "name": "글 바로가기", "value": f"[클릭]({item['link']})" }] if category == "blog": fields.extend([{ "name": "글 작성자", "value": item["author"] }, { "name": "글 작성 일자", "value": item["postdate"] }]) elif category == "cafearticle": fields.extend([{ "name": "카페 이름", "value": item["cafename"] }, { "name": "카페 바로가기", "value": f"[클릭]({item['cafeurl']})" }]) caller_info = EmbedFactory.get_command_caller(user=ctx.author) search_embeds.append(await EmbedFactory( title=f"네이버 검색 결과입니다!", description=f"검색어 : {query}", author={ "name": f"{EmbedFactory.get_user_info(user=self.bot.user, contain_id=True)}", "icon_url": self.bot.user.avatar_url }, footer={ "text": f"{caller_info['text']}", "icon_url": f"{caller_info['icon_url']}" }, thumbnail_url=item["link"], fields=fields).build()) if len(search_embeds) > 0: for embed in search_embeds: await ctx.send(embed=embed)
async def ext_reload(self, ctx: commands.Context, *, params_raw: str): if params_raw.startswith("all"): self.bot.ext.reload_all(self.bot) return await ctx.send(embed=EmbedFactory.COMMAND_LOG_EMBED( title="[ Successfully Reloaded Extension ]", description=f"ext_args : {params_raw}", user=ctx.author)) params = await self.parse_params(params_raw) category: str = params.pop( "category") if "category" in params.keys() else '' name: str = params.pop("name") if "name" in params.keys() else '' dir: str = params.pop("dir") if "dir" in params.keys() else '' if (dir == '' and (category == '' or name == '')) or ((category == '' and name == '') and dir == ''): await ctx.send(embed=EmbedFactory.WARN_EMBED( title="Invalid usage!", description= "Module commands must be used with cli-style arguments to define module to load!\n" "usage: `ext reload -c (category) -n (name)` or `ext reload -d (dir)`" )) else: try: self.bot.ext.reload_ext(bot=self.bot, ext_category=category, ext_name=name, ext_dir=dir) except BadExtArguments as e: error_embed = EmbedFactory.ERROR_EMBED(e) await ctx.send(embed=error_embed) else: result_embed = EmbedFactory.COMMAND_LOG_EMBED( title="[ Successfully Reloaded Extension ]", description=f"ext_args : {params_raw}", user=ctx.author) await ctx.send(embed=result_embed) if category == "Utility" and name == "invites": # During reloading / loading module again, InvitesExt extension lose it`s trackin data. # So we need to call update() method and re-track invites data. # But, discord.Guild.invites() method is a coroutine, # it can`t be called in __init__ method while bot is running. # So, we need to call update() method manually right after reloading/loading extension again. await self.bot.get_cog(name).update()
async def on_command(self, ctx: commands.Context): command_name: str = f"{ctx.cog.qualified_name if ctx.cog is not None else 'bot'}:{ctx.command.name if ctx.command is not None else 'UNKNOWN'}" self.bot.get_logger().info( msg= f"[AdminExt.on_command] User {EmbedFactory.get_user_info(user=ctx.author)} used `{command_name}` " f"command with following arguments : \n{ctx.args, json.dumps(ctx.kwargs, indent=4, ensure_ascii=False)} " ) if self.bot.config.is_loaded( ) and self.bot.config.config_type == Config.Types.JSON: log_channel: discord.TextChannel = self.bot.get_channel( self.bot.config["admin_log"]) print(log_channel) args = ('\n'.join([ f"{arg_num} : {arg}" for arg_num, arg in enumerate(ctx.args) ])) if len(ctx.args) > 0 else "[]" if log_channel is not None: owner_info = f"{ctx.guild.owner.name}#{ctx.guild.owner.discriminator}" if ctx.guild.owner is not None else "UNKNOWN" await log_channel.send(embed=await EmbedFactory( title="[AdminExt.on_command]", description=f"`{command_name}` 명령어가 사용되었습니다.", author={ "name": EmbedFactory.get_user_info(user=self.bot.user, contain_id=True), "icon_url": self.bot.user.avatar_url }, footer=EmbedFactory.get_command_caller(ctx.author), color=EmbedFactory.default_color, fields=[{ "name": "명령어 파라미터 - 위치 인자 (*args)", "value": args, "inline": False }, { "name": "명령어 파라미터 - 키워드 인자 (**kwargs)", "value": json.dumps(ctx.kwargs, indent=4, ensure_ascii=False), "inline": False }, { "name": "명령어가 사용된 서버 정보", "value": f"이름 : {ctx.guild.name}\nid : {ctx.guild.id}\n주인 : {owner_info} ({ctx.guild.owner_id})", "inline": False }]).build())
async def restart(self, ctx: commands.Context): embed = EmbedFactory.COMMAND_LOG_EMBED(title="[ Command Result ]", description="봇을 재시작합니다!", user=ctx.author) await ctx.send(embed=embed) self.bot.get_logger().info( "[AdminExt] bot restart command detected. stopping bot...") self.bot.do_reboot = True await self.bot.close()
async def clearchat(self, ctx: commands.Context, amount: int = 5): if amount < 1: return await ctx.send(f"{amount} 는 너무 적습니다!") deleted: List[discord.Message] = await ctx.channel.purge( limit=amount + 1 ) # Add 1 to :param amout: to delete command message. return await ctx.send(embed=EmbedFactory.COMMAND_LOG_EMBED( title="메세지 청소 결과", description=f"{len(deleted)-1}개의 메세지를 청소했습니다!", user=ctx.author))
async def ban(self, ctx: commands.Context, target_member: discord.Member, *, reason: str = ""): await target_member.ban(reason=reason) return await ctx.send(embed=await EmbedFactory( title="[ 관리 ] 멤버를 차단했습니다!", footer=EmbedFactory.get_command_caller(ctx.author), color=EmbedFactory.default_color, fields=[{ "name": "차단한 멤버", "value": EmbedFactory.get_user_info(target_member), "inline": False }, { "name": "차단 사유", "value": reason, "inline": False }]).build())
async def config_unload(self, ctx: commands.Context): description: str = "UNDEFINED" # Set some default text to prevent empty embed error. try: self.bot.config.unload() except ConfigNotLoaded as e: description = str(e) else: description = "Config successfully unloaded :D" await ctx.send(embed=EmbedFactory.LOG_EMBED( title="[ Admin Extension - Config Unload Result ]", description=description))
async def report(self, ctx: commands.Context, report_type='', *, report_content: str = ''): print(f"{ctx.message.content}") print(f"report_type == {report_type}") print(f"report_content == {report_content}") if report_type == '' and report_content == '': await ctx.send( content=f"> 봇 공식 커뮤니티에서 버그를 제보해주세요!\n" f"{self.bot.discord_base_invite + self.bot.bug_report_invite}" ) elif report_content != '' and report_type in ["건의", "버그"]: bug_embed_factory = EmbedFactory( title=f"[ 라떼봇 제보 ]!", color=EmbedFactory.error_color, author={ "name": f"{ctx.author} ({ctx.author.id})", "icon_url": ctx.author.avatar_url }, fields=[ { "name": "제보 유형", "value": report_type, "inline": False }, { "name": "제보 내용", "value": report_content, "inline": False }, { "name": "제보한 곳", "value": f"서버 : {ctx.guild.name}\n 서버 주인 : {ctx.guild.owner} ({ctx.guild.owner.id})\n채널 : {ctx.channel.name}", "inline": False } ] ) await bug_embed_factory.add_field(name="제보 유형", value=report_type, inline=False) await bug_embed_factory.add_field(name="제보 내용", value=report_content, inline=False) for dev_id in self.bot.owner_id: developer_user: discord.User = self.bot.get_user(dev_id) await developer_user.send(embed=await bug_embed_factory.build()) await ctx.send("> 개발자들에게 해당 사항을 제보했습니다!") await ctx.send( content=f"> 추가적인 버그 및 봇 업데이트는 봇 공식 커뮤니티에서 확인해주세요!\n" f"{self.bot.discord_base_invite + self.bot.official_community_invite}" ) else: await ctx.send("> 잘못된 양식입니다!")
async def ext_unload(self, ctx: commands.Context, *, params_raw: str): if params_raw.startswith("all"): self.bot.ext.unload_all(self.bot) return await ctx.send(embed=EmbedFactory.COMMAND_LOG_EMBED( title="[ Successfully Unloaded Extension ]", description=f"ext_args : {params_raw}", user=ctx.author)) params = await self.parse_params(params_raw) category: str = params.pop( "category") if "category" in params.keys() else '' name: str = params.pop("name") if "name" in params.keys() else '' dir: str = params.pop("dir") if "dir" in params.keys() else '' if (dir == '' and (category == '' or name == '')) or ((category == '' and name == '') and dir == ''): await ctx.send(embed=EmbedFactory.WARN_EMBED( title="Invalid usage!", description= "Module commands must be used with cli-style arguments to define module to load!\n" "usage: `ext unload -c (category) -n (name)` or `ext unload -d (dir)`" )) else: try: self.bot.ext.unload_ext(bot=self.bot, ext_category=category, ext_name=name, ext_dir=dir) except BadExtArguments as e: error_embed = EmbedFactory.ERROR_EMBED(e) await ctx.send(embed=error_embed) else: result_embed = EmbedFactory.COMMAND_LOG_EMBED( title="[ Successfully Unloaded Extension ]", description=f"ext_args : {params_raw}", user=ctx.author) await ctx.send(embed=result_embed)
async def evaluate_code(self, ctx: commands.Context, *, code_raw: str): # Assume that code starts with ```py and endes with ``` (code block) if not code_raw.startswith("```py") or not code_raw.endswith("```"): raise ValueError( "Code to evaluate must starts with ```py and endswith ```") code_content: str = code_raw.replace("```", '')[2:] try: result = eval(code_content) except Exception as e: result = e await ctx.send(embed=EmbedFactory.COMMAND_LOG_EMBED( title="[ ADMIN COMMAND : EVAL ] 실행 결과", description=str(result), user=ctx.author))
async def config(self, ctx: commands.Context): if ctx.invoked_subcommand is None: embedfactory = EmbedFactory( title="[ Admin Extension - Config Commands ]", description= "This is an admin-only extension to manage Latte`s config in discord chat.", color=EmbedFactory.default_color, author={ "name": f"라떼봇 v{self.bot.bot_version}", "icon_url": self.bot.user.avatar_url }, footer={ "text": f"command executed by {EmbedFactory.get_user_info(user=ctx.author)}", "icon_url": ctx.author.avatar_url }) await ctx.send(embed=await embedfactory.build())
async def on_member_join(self, member: discord.Member): """ Event listener for member_join event, which is dispatched when new member joins the server. :param member: a member who joined in the server. """ used_invite_code, used_count = await self.compare_invites(member.guild) msg = f"{member.display_name} 님은 {used_invite_code} 초대코드를 사용해 서버에 참여했습니다." log_embed: discord.Embed = EmbedFactory.LOG_EMBED( title="새로운 멤버 참가!", description= f"{member.display_name} 님은 {used_invite_code} 초대코드를 사용해 서버에 참여했습니다." ) log_embed.add_field(name=f"초대코드 `{used_invite_code}`의 현재 사용 횟수", value=f"{used_count}회") await member.guild.system_channel.send(embed=log_embed) self.bot.get_logger().info(msg=msg) await self.update()
async def on_command_error(self, ctx: commands.Context, error: Type[Exception]): command_name: str = f"{ctx.cog.qualified_name if ctx.cog is not None else 'bot'}:{ctx.command.name if ctx.command is not None else 'UNKNOWN'}" self.bot.get_logger().error( msg= f"[AdminExt.on_command] User {EmbedFactory.get_user_info(user=ctx.author)} used `{command_name}` " f"command with following arguments : \n{ctx.args, json.dumps(ctx.kwargs, indent=4, ensure_ascii=False)}\n" f", and error :\n{error}") self.bot.get_logger().error(msg=f"type of the error : {error}") await ctx.channel.send(embed=await EmbedFactory( title= f"[라떼봇 베타] An error occurred during executing command `{command_name}`\n> {error}" ).build()) if self.bot.config.is_loaded( ) and self.bot.config.config_type == Config.Types.JSON: log_channel: discord.TextChannel = self.bot.get_channel( self.bot.config["admin_log"]) if log_channel is not None: owner_info = f"{ctx.guild.owner.name}#{ctx.guild.owner.discriminator}" if ctx.guild.owner is not None else "UNKNOWN" tracebacks: list = traceback.format_exception( type(error.__cause__), error.__cause__, error.__cause__.__traceback__) await log_channel.send( content=f"{self.bot.get_user(self.bot.owner_id).mention}", embed=await EmbedFactory( title="[AdminExt.on_command] command error detected", description=f"`{command_name}` 명령어가 사용되었습니다.", color=EmbedFactory.error_color, author={ "name": EmbedFactory.get_user_info(user=self.bot.user, contain_id=True), "icon_url": self.bot.user.avatar_url }, footer=EmbedFactory.get_command_caller(ctx.author), fields=[ { "name": "오류가 발생한 서버 정보", "value": f"이름 : {ctx.guild.name}\nid : {ctx.guild.id}\n주인 : {owner_info} ({ctx.guild.owner_id})" }, { "name": "명령어 실행 도중 발생한 오류 정보", "value": "```css\n" f"{''.join(tracebacks)}\n```" }, { "name": "명령어 파라미터 - 위치 인자 (*args)", "value": '\n'.join([ f"{arg_num} : {arg}" for arg_num, arg in enumerate(ctx.args) ]) }, { "name": "명령어 파라미터 - 키워드 인자 (**kwargs)", "value": json.dumps(ctx.kwargs, indent=4, ensure_ascii=False) }, ]).build())
async def update(self): self.bot.get_logger().info( msg="[InvitesExt.update] Updating tracking invites data...") if self.bot.is_ready(): self.bot.get_logger().info( msg= "[InvitesExt.update] Bot`s internal cache is ready. Try to update tracking invites data ..." ) invite_tracks: Dict[str, Dict[str, int]] = {} for guild in self.bot.guilds: invite_tracks[str(guild.id)] = {} guild_invites = [] if guild.me.guild_permissions.manage_guild: try: guild_invites: List[ discord.Invite] = await guild.invites() for invite in guild_invites: invite_tracks[str(guild.id)].update( {invite.code: invite.uses}) except discord.HTTPException as e: await self.bot.get_channel( self.bot.config["admin_log"] ).send(embed=await EmbedFactory( title= "[InvitesExt.update] 서버의 초대 정보를 가져오는 도중 HTTP 오류가 발생했습니다!", color=EmbedFactory.error_color, author={ "name": EmbedFactory.get_user_info(self.bot.user, contain_id=False), "icon_url": self.bot.user.avatar_url }, footer={ "text": f"서버 주인 : {EmbedFactory.get_user_info(guild.owner if guild.owner is not None else self.bot.user, contain_id=True)}", "icon_url": guild.owner.avatar_url if guild. owner is not None else self.bot.user.avatar_url }, fields=[{ "name": "오류가 발생한 서버 정보", "value": f"이름 : {guild.name}\nid : {guild.id}\n " }]).build()) import json print( "[InvitesExt.update] Updated result (on update method, not assigned to class instance.) :\n", json.dumps(obj=invite_tracks, indent=4, ensure_ascii=False)) self.invite_tracks = invite_tracks else: self.bot.get_logger().error( msg= "[InvitesExt.update] Bot`s internal cache is not ready! Cannot load invites..." ) if type(self.invite_tracks) == dict and self.invite_tracks != {}: self.bot.get_logger().info( msg= "[InvitesExt.update] Keep previously updated invite_tracks for safety." ) elif type(self.invite_tracks) != dict: self.bot.get_logger().error( msg= "[InvitesExt.update] Find invalid data is assigned in invite_tracks. " "Assigning blank dictionary data ( {} )") self.invite_tracks = {}
async def test_intro(self, ctx: commands.Context): await ctx.send(embed=EmbedFactory.LOG_EMBED( title="Opened `docs/ko-kr/intro.md`", description="```md\n" f"{self.doc_package.get_doc('ko-kr/intro.md').get_content()}\n" "```"))
async def help(self, ctx: commands.Context): await ctx.send(embed=EmbedFactory.LOG_EMBED( title="도움말 명령어는 현재 준비중입니다!", description="조만간 업데이트 될 예정이니 조금만 기다려주세요 :D"))
async def get_user_info(self, ctx: commands.Context, member: discord.Member = None): if member is None: member = ctx.author # Create an Embed which contains member's information embed_factory = EmbedFactory( title= f"{EmbedFactory.get_user_info(user=member, contain_id=False)} 님의 정보입니다!", color=EmbedFactory.default_color, author={ "name": EmbedFactory.get_user_info(user=self.bot.user, contain_id=True), "icon_url": self.bot.user.avatar_url }, footer=EmbedFactory.get_command_caller(user=ctx.author), thumbnail_url=member.avatar_url, fields=[{ "name": "이름", "value": f"{EmbedFactory.get_user_info(user=member, contain_id=False)}", "inline": False }, { "name": "유저 상태", "value": self.status_dict[member.status], "inline": True }, { "name": "Discord 가입 연도", "value": member.created_at, "inline": False }, { "name": "서버 참여 날짜", "value": member.joined_at, "inline": True }, { "name": "모바일 여부", "value": str(member.is_on_mobile()), "inline": True }]) is_nitro: bool = bool(member.premium_since) await embed_factory.add_field(name="프리미엄(니트로) 여부", value=str(is_nitro), inline=False) if is_nitro: await embed_factory.add_field(name="프리미엄 사용 시작 날짜", value=str(member.premium_since), inline=True) """ info_embed.add_field('Hypesquad 여부', user_profile.hypesquad, False) if user_profile.hypesquad: info_embed.add_field('소속된 Hypesquad house', user_profile.hypesquad_houses, True) info_embed.add_field('메일 인증 사용여부', member.verified, False) info_embed.add_field('2단계 인증 사용여부', member.mfa_enabled, True) """ await ctx.send(embed=await embed_factory.build())
async def get_user_activity(self, ctx: commands.Context, member: discord.Member = None): # Create an Embed which contains member's information if member is None: member = ctx.author caller_info = EmbedFactory.get_command_caller(user=ctx.author) embed_factory = EmbedFactory( title=f"{member.display_name} 님의 활동 정보입니다!", color=EmbedFactory.default_color, author={ "name": f"{EmbedFactory.get_user_info(user=self.bot.user, contain_id=True)}", "icon_url": self.bot.user.avatar_url }, footer={ "text": f"{caller_info['text']}", "icon_url": f"{caller_info['icon_url']}" }, thumbnail_url=member.avatar_url) if len(member.activities) == 0: await embed_factory.add_field(name="활동 정보가 없습니다!", value="현재 진행중인 활동이 없습니다.", inline=False) return await ctx.send(embed=await embed_factory.build()) else: count: int = 1 for ac in member.activities: await embed_factory.add_field(name='\u200b', value='\u200b', inline=False) # 공백 개행을 만든다. self.bot.get_logger().info( msg= f"[UtilsExt.useractivity] 활동 {count} : {type(ac)}, .type = {ac.type}" ) try: await embed_factory.add_field(f"**활동 {count} 이름**", ac.name, False) if ac.type == discord.ActivityType.playing: await embed_factory.add_field(f"활동 {count} 유형", "플레이 중", False) if type( ac ) != discord.Game and ac.large_image_url is not None: await embed_factory.add_field( "활동 이미지", '\u200b', False) embed_factory.image_url = ac.large_image_url elif ac.type == discord.ActivityType.streaming: await embed_factory.add_field(f"활동 {count} 유형", "방송 중", False) if type(ac) == discord.Streaming: await embed_factory.add_field( f"**방송 정보**", '\u200b', False) await embed_factory.add_field( f"방송 플랫폼", ac.platform, False) if ac.twitch_name is not None: await embed_factory.add_field( f"트위치 이름", ac.twitch_name, True) await embed_factory.add_field( "방송 주소", ac.url, False) if ac.game is not None: await embed_factory.add_field( "방송중인 게임", ac.game, False) elif ac.type == discord.ActivityType.listening: await embed_factory.add_field(f"활동 {count} 이름", ac.name, False) await embed_factory.add_field(f"활동 {count} 유형", "듣는 중", False) elif ac.type == discord.ActivityType.watching: await embed_factory.add_field(f"활동 {count} 이름", ac.name, False) await embed_factory.add_field(f"활동 {count} 유형", "시청 중", False) elif ac.type == discord.ActivityType.custom: ac_extra = '' if ac.emoji is not None: ac_extra += ac.emoji.name await embed_factory.add_field(f"활동 {count} 이름", ac_extra + ac.name, False) await embed_factory.add_field(f"활동 {count} 유형", "사용자 지정 활동", False) elif ac.type == discord.ActivityType.unknown: await embed_factory.add_field(f"활동 {count} 이름", "알 수 없는 활동입니다!", False) else: await embed_factory.add_field( f"요청하신 사용자의 활동을 파악하지 못했습니다!", "유효한 활동 유형이 아닙니다 :(", False) except Exception as e: await embed_factory.add_field(f"오류 발생!", "활동 정보를 불러오지 못했습니다 :(", False) await embed_factory.add_field( f"오류 내용", str(e.with_traceback(e.__traceback__)), False) count += 1 await ctx.send(embed=await embed_factory.build())