async def bap(self, ctx, *, user: discord.Member): """ Baps a user """ if user.id == ctx.bot.user.id: await ctx.send(":newspaper2: :newspaper2: :newspaper2: " + italics(ctx.message.author.display_name)) else: if ctx.guild.id == 508496957350608906: await ctx.send( italics(user.display_name) + " <:aureliabagu:678829441178271770>") else: await ctx.send(":newspaper2: " + italics(user.display_name))
async def send_to(self, ctx: Context, content=None): if await ctx.embed_requested(): return await ctx.send(content=content, embed=self) content = str(content) if content is not None else None if content: content = [content, ""] else: content = [] next_break = False title = self._("title") if title: content.append(CF.bold(title)) next_break = True name = self._("author.name") if name: content.append(CF.italics(name)) next_break = True url = self._("thumbnail.url") if url and not url.startswith("attachment://"): content.append(f"<{url}>") next_break = True description = self._("description") if description: content.append(CF.box(CF.escape(description, formatting=True))) next_break = False if next_break: content.append("") next_break = False for i in range(len(self.fields)): inline, name, value = ( self._("fields", i, "inline"), self._("fields", i, "name"), self._("fields", i, "value"), ) if not inline or len(name) + len( value) > 78 or "\n" in name or "\n" in value: content.append(name) content.append(CF.box(CF.escape(value, formatting=True))) next_break = False else: content.append(f"{name}: {value}") next_break = True if next_break: content.append("") next_break = False url = self._("image.url") if url and not url.startswith("attachment://"): content.append(f"<{url}>") url = self._("video.url") if url and not url.startswith("attachment://"): content.append(f"<{url}>") text, timestamp = self._("footer.text"), self._("timestamp") if text and timestamp: content.append(f"{text} | {timestamp}") elif text: content.append(text) elif timestamp: content.append(f"{timestamp} UTC") content = list(CF.pagify("\n".join(map(str, content)), shorten_by=0)) return await ctx.send_interactive(content)
async def grouphug(self, ctx, intensity: int, *users: discord.Member): """ Give a group hug to multiple users! If not pinging, you must put quotes around names with spaces Can also use user ids """ if not users: await self.bot.send_help_for(ctx, "grouphug") return names = [italics(user.display_name) for user in users] names = ", ".join(names) if intensity <= 0: msg = "(っ˘̩╭╮˘̩)っ {} ⊂(˘̩╭╮˘̩⊂)".format(names) elif intensity <= 3: msg = "(っ´▽`)っ {} ⊂( ̄▽ ̄⊂)".format(names) elif intensity <= 6: msg = "╰(*´︶`*)╯ {} ╰(*´︶`*)╯".format(names) elif intensity <= 9: msg = "(つ≧▽≦)つ {} ⊂(・▽・⊂)".format(names) elif intensity >= 10: msg = "(づ ̄ ³ ̄)づ {} ⊂(´・ω・`⊂)".format(names) await ctx.send(msg)
async def act(self, ctx, *, target: Union[discord.Member, str] = None): """ Acts on the specified user. """ if not target or isinstance(target, str): return # no help text action = inflection.humanize(ctx.invoked_with).split() iverb = -1 for cycle in range(2): if iverb > -1: break for i, act in enumerate(action): act = act.lower() if (act in NOLY_ADV or act in CONJ or (act.endswith("ly") and act not in LY_VERBS) or (not cycle and act in SOFT_VERBS)): continue action[i] = inflection.pluralize(action[i]) iverb = max(iverb, i) if iverb < 0: return action.insert(iverb + 1, target.mention) await ctx.send(italics(" ".join(action)))
async def desc_select( self, ctx: commands.Context, embed: Embed, message: discord.Message, do_once: bool = True, ) -> bool: """Requests information from the member about the description of the character being registered. Args: ctx (commands.Context): Same as `RegisterSession.ctx` embed (Embed): Same as `RegisterSession.embed` message (discord.Message): Same as `RegisterSession.message` do_once (bool): The parameter allows not to perform actions that are not needed during a recursive method call. Returns: bool: Whether the correct information is received or not. """ if do_once: embed.description = ( "**Опишите своего персонажа**\n\n" "В описании персонажа должно быть **не менее 50** и **не более 2000 символов**.\n" "Описание персонажа должно состоять из символов **латинского алфавита** или **кириллицы.**" ) await message.edit(embed=embed) do_once = False try: desc = await self.ctx.bot.wait_for( "message", timeout=600.0, check=MessagePredicate.same_context(ctx)) desc_content = desc.content await desc.delete() if not re.match( """[a-zа-яA-ZА-ЯёЁ\d\s!.,%*'";:()\[\]<>\-«»—]{50,2000}""", desc_content): incorrect = await ctx.send("Недопустимый ввод!") desc_select = await self.desc_select(ctx, embed, message, do_once) await incorrect.delete() if desc_select: return True else: await self.cancel(embed, message) return False self.char["desc"] = desc_content embed.description = italics(desc_content) await message.edit(embed=embed) return True except asyncio.TimeoutError: await self.cancel(embed, message) return False
async def rpsls(self, ctx, choice: ValidChoiceConverter): """Play rock, paper, scizzors, lizard, spock. Use `[p]rpsls help` for a diagram. """ human_choice, human_number = choice bot_choice, bot_number = generate_bot_rpsls() if bot_number == human_number: phrase = italics("It's a draw! We're fair and square.") bot_user = self.bot.user human_user = ctx.author elif bot_number in IntMapper[human_number]: phrase = italics("You won - nice job!") bot_user = self.bot.user human_user = bold(str(ctx.author)) else: phrase = italics("Damn, better luck next time...") bot_user = bold(str(self.bot.user)) human_user = ctx.author bot_emoji = get_emoji_from_name(bot_choice) human_emoji = get_emoji_from_name(human_choice) message = f"{human_user} {human_emoji} {VS} {bot_emoji} {bot_user}" f"\n> {phrase}" await ctx.maybe_send_embed(message)
async def theme_list(self, ctx, *, user: discord.User = None): """ Lists your currently set themes. """ if not user: user = ctx.author themes = await self.maybe_bot_themes(ctx, user) if themes: message = self.pretty_themes( bold(_("{}'s Themes")).format(user.name), themes) else: message = "{}\n\n{}".format( bold(_("{0}'s Themes")), italics(_("{0} has not set any themes."))).format(user.name) for msg in pagify(message): await ctx.maybe_send_embed(msg)
async def hug(self, ctx, user: discord.Member, intensity: int = 1): """Because everyone likes hugs Up to 10 intensity levels.""" name = italics(user.display_name) if intensity <= 0: msg = "(っ˘̩╭╮˘̩)っ" + name elif intensity <= 3: msg = "(っ´▽`)っ" + name elif intensity <= 6: msg = "╰(*´︶`*)╯" + name elif intensity <= 9: msg = "(つ≧▽≦)つ" + name elif intensity >= 10: msg = "(づ ̄ ³ ̄)づ{} ⊂(´・ω・`⊂)".format(name) await ctx.send(msg)
async def boop(self, ctx, *, boop_target: str): """ Boops a user. 10 intensity levels. """ user, intensity = self.get_user_and_intensity(ctx.guild, boop_target) if user is not None: name = italics(user.display_name) if intensity <= 3: msg = "/) {}".format(name) elif intensity <= 6: msg = "**/)** {}".format(name) elif intensity <= 9: msg = "**__/)__** {}".format(name) elif intensity >= 10: msg = "**__/)__** {} **__(\\\__**".format(name) await ctx.send(msg) else: await ctx.send("Can't boop what I can't see!")
async def hug(self, ctx, user: discord.Member, intensity: int = 1): """Because everyone likes hugs! Up to 10 intensity levels. """ name = italics(user.display_name) if intensity <= 0: msg = "(っ˘̩╭╮˘̩)っ" + name elif intensity <= 3: msg = "(っ´▽`)っ" + name elif intensity <= 6: msg = "╰(*´︶`*)╯" + name elif intensity <= 9: msg = "(つ≧▽≦)つ" + name elif intensity >= 10: msg = "(づ ̄ ³ ̄)づ{} ⊂(´・ω・`⊂)".format(name) else: # For the purposes of "msg might not be defined" linter errors raise RuntimeError await ctx.send(msg)
async def hug(self, ctx, user: discord.Member, intensity: int = 1): """Because everyone likes hugs! Up to 10 intensity levels. """ name = italics(user.display_name) if intensity <= 0: msg = "(っ˘̩╭╮˘̩)っ" + name elif intensity <= 3: msg = "(っ´▽`)っ" + name elif intensity <= 6: msg = "╰(*´︶`*)╯" + name elif intensity <= 9: msg = "(つ≧▽≦)つ" + name elif intensity >= 10: msg = "(づ ̄ ³ ̄)づ{} ⊂(´・ω・`⊂)".format(name) else: # For the purposes of "msg might not be defined" linter errors raise RuntimeError await ctx.send(msg)
async def hug(self, ctx, *, hug_target: str): """Hugs a user with optional intensity! Example: .hug *username* 4 Up to 10 intensity levels.""" user, intensity = self.get_user_and_intensity(ctx.guild, hug_target) if user is not None: name = italics(user.display_name) if intensity <= 0: msg = "(っ˘̩╭╮˘̩)っ" + name elif intensity <= 3: msg = "(っ´▽`)っ" + name elif intensity <= 6: msg = "╰(*´︶`*)╯" + name elif intensity <= 9: msg = "(つ≧▽≦)つ" + name elif intensity >= 10: msg = "(づ ̄ ³ ̄)づ {} ⊂(´・ω・`⊂)".format(name) await ctx.send(msg) else: await ctx.send("Member not found.")
async def pypi(self, ctx, project: str): """Get information about a project on PyPi.""" await ctx.trigger_typing() async with self.session.get( f"https://pypi.org/pypi/{project}/json") as request: if request.status != 200: embed = discord.Embed( description=f'There were no results for "{project}".') return await self.send_embed(ctx, embed) request = await request.json() info = request["info"] kwargs = {} embed = discord.Embed(title=f"{info['name']} {info['version']}", url=info["package_url"]) embed.description = info["summary"] or italics( "No description was provided for this project.") if (author := info["author"]) and author != " ": embed.add_field(name="Author", value=author)
async def act(self, ctx: commands.Context, *, target: Union[discord.Member, str] = None): """ Acts on the specified user. """ if not target or isinstance(target, str): return # no help text try: if not ctx.guild: raise KeyError() message = await self.config.guild(ctx.guild).get_raw("custom", ctx.invoked_with) except KeyError: try: message = await self.config.get_raw("custom", ctx.invoked_with) except KeyError: message = NotImplemented if message is None: # ignored command return elif message is NotImplemented: # default # humanize action text action = inflection.humanize(ctx.invoked_with).split() iverb = -1 for cycle in range(2): if iverb > -1: break for i, act in enumerate(action): act = act.lower() if ( act in NOLY_ADV or act in CONJ or (act.endswith("ly") and act not in LY_VERBS) or (not cycle and act in SOFT_VERBS) ): continue action[i] = inflection.pluralize(action[i]) iverb = max(iverb, i) if iverb < 0: return action.insert(iverb + 1, target.mention) message = italics(" ".join(action)) else: assert isinstance(message, str) message = fmt_re.sub(functools.partial(self.repl, target), message) # add reaction gif if self.try_after and ctx.message.created_at < self.try_after: return await ctx.send(message) if not await ctx.embed_requested(): return await ctx.send(message) key = (await ctx.bot.get_shared_api_tokens("tenor")).get("api_key") if not key: return await ctx.send(message) async with aiohttp.request( "GET", "https://api.tenor.com/v1/search", params={ "q": ctx.invoked_with, "key": key, "anon_id": str(ctx.author.id ^ ctx.me.id), "media_filter": "minimal", "contentfilter": "off" if getattr(ctx.channel, "nsfw", False) else "low", "ar_range": "wide", "limit": "8", "locale": get_locale(), }, ) as response: json: dict if response.status == 429: self.try_after = ctx.message.created_at + 30 json = {} elif response.status >= 400: json = {} else: json = await response.json() if not json.get("results"): return await ctx.send(message) message = f"{message}\n\n{random.choice(json['results'])['itemurl']}" await ctx.send( message, allowed_mentions=discord.AllowedMentions( users=False if target in ctx.message.mentions else [target] ), )
async def godville(self, ctx, *, godname: str): """Get data about godville's god by name""" async with self.session.get("{}/{}/{}".format( BASE_API, godname.casefold(), await self.api_by_god(godname.casefold(), "godville") or "")) as sg: if sg.status == 404: await ctx.send( chat.error( "404 — Sorry, but there is nothing here\nCheck god name and try again" )) return elif sg.status != 200: await ctx.send( chat.error( "Something went wrong. Server returned {}.".format( sg.status))) return profile = await sg.json() profile = GodvilleUser(profile) text_header = "{} и его {}\n{}\n" \ .format(chat.bold(profile.god), chat.bold(profile.name), chat.italics(chat.escape(profile.motto.strip(), formatting=True)) if profile.motto else chat.inline("Здесь ничего нет")) if profile.arena_is_in_fight: text_header += "В сражении: {}\n".format(profile.fight_type_rus) if profile.town: text_header += "В городе: {}\n".format(profile.town) if profile.need_update: text_header += chat.bold("! УСТАРЕВШАЯ ИНФОРМАЦИЯ !") + "\n" text = "" pet = "" times = "" if profile.gold_approximately: text += "Золота: {}\n".format(profile.gold_approximately) if profile.distance: text += "Столбов от столицы: {}\n".format(profile.distance) if profile.quest_progress: text += "Задание: {} ({}%)\n".format(profile.quest, profile.quest_progress) if profile.experience: text += "Опыта до следующего уровня: {}%\n".format( profile.experience) text += "Уровень: {}\n".format(profile.level) if profile.godpower: text += "Праны: {}/{}\n".format( profile.godpower, 200 if profile.savings_date else 100) text += "Характер: {}\n".format(profile.alignment) text += "Пол: {}\n".format(profile.gender) text += "Побед/Поражений: {}/{}\n".format(profile.arena_won, profile.arena_lost) text += "Гильдия: {} ({})\n".format(profile.clan, profile.clan_position) if profile.clan \ else "Гильдия: Не состоит\n" text += "Кирпичей: {} ({}%)\n".format(profile.bricks, profile.bricks / 10) if profile.inventory: text += "Инвентарь: {}/{} ({}%)\n".format( profile.inventory, profile.inventory_max, int(profile.inventory / profile.inventory_max * 100)) else: text += "Вместимость инвентаря: {}\n".format(profile.inventory_max) if profile.health: text += "Здоровье: {}/{} ({}%)\n".format( profile.health, profile.health_max, int(profile.health / profile.health_max * 100)) else: text += "Максимум здоровья: {}\n".format(profile.health_max) if profile.ark_male: text += "Тварей ♂: {} ({}%)\n".format(profile.ark_male, profile.ark_male / 10) if profile.ark_female: text += "Тварей ♀: {} ({}%)\n".format(profile.ark_female, profile.ark_female / 10) if profile.savings: text += "Сбережений: {}\n".format(profile.savings) if profile.trading_level: text += "Уровень торговли: {}\n".format(profile.trading_level) if profile.wood: text += "Поленьев: {} ({}%)\n".format(profile.wood, profile.wood / 10) # private (api only) if profile.diary_last: text += "Дневник: {}\n".format(profile.diary_last) if profile.activatables: text += "Активируемое в инвентаре: {}\n".format(", ".join( profile.activatables)) if profile.aura: text += "Аура: {}\n".format(profile.aura) # pet if profile.pet.name: pet += "Имя: {}\n".format(profile.pet.name) pet += "Уровень: {}\n".format(profile.pet.level or "Без уровня") if profile.pet.type: pet += "Тип: {}\n".format(profile.pet.type) if profile.pet.wounded: pet += "❌ — Контужен" # times if profile.temple_date: times += "Храм достроен: {}\n".format( profile.date_string("temple")) if profile.ark_date: times += "Ковчег достроен: {}\n".format(profile.date_string("ark")) if profile.savings_date: times += "Пенсия собрана: {}\n".format( profile.date_string("savings")) finaltext = "" finaltext += text_header finaltext += chat.box(text) if pet: finaltext += "Питомец:\n" finaltext += chat.box(pet) if times: finaltext += chat.box(times) await ctx.send(finaltext)
async def godvillegame(self, ctx, *, godname: str): """Get data about godville's god by name""" async with self.session.get("{}/{}".format(BASE_API_GLOBAL, godname.casefold())) as sg: if sg.status == 404: await ctx.send( chat.error( "404 — Sorry, but there is nothing here\nCheck god name and try again" )) return elif sg.status != 200: await ctx.send( chat.error( "Something went wrong. Server returned {}.".format( sg.status))) return profile = await sg.json() profile = GodvilleUser(profile) text_header = "{} and his {}\n{}\n" \ .format(chat.bold(profile.god), chat.bold(profile.name), chat.italics(chat.escape(profile.motto.strip(), formatting=True)) if profile.motto else chat.inline("Nothing here")) if profile.arena_is_in_fight: text_header += "In fight: {}\n".format(profile.fight_type_rus) if profile.town: text_header += "In city: {}\n".format(profile.town) if profile.need_update: text_header += chat.bold("! INFO OUTDATED !") + "\n" text = "" pet = "" times = "" if profile.gold_approximately: text += "Gold: {}\n".format(profile.gold_approximately) if profile.distance: text += "Milestone: {}\n".format(profile.distance) if profile.quest_progress: text += "Quest: {} ({}%)\n".format(profile.quest, profile.quest_progress) if profile.experience: text += "Exp for next level: {}%\n".format(profile.experience) text += "Level: {}\n".format(profile.level) if profile.godpower: text += "Godpower: {}/{}\n".format( profile.godpower, 200 if profile.savings_date else 100) text += "Personality: {}\n".format(profile.alignment) text += "Gender: {}\n".format(profile.gender) text += "Wins / Losses: {}/{}\n".format(profile.arena_won, profile.arena_lost) text += "Guild: {} ({})\n".format(profile.clan, profile.clan_position) if profile.clan \ else "Guild: Not in guild\n" text += "Bricks: {} ({}%)\n".format(profile.bricks, profile.bricks / 10) if profile.inventory: text += "Inventory: {}/{} ({}%)\n".format( profile.inventory, profile.inventory_max, int(profile.inventory / profile.inventory_max * 100)) else: text += "Inventory max: {}\n".format(profile.inventory_max) if profile.health: text += "Health: {}/{} ({}%)\n".format( profile.health, profile.health_max, int(profile.health / profile.health_max * 100)) else: text += "Health maximum: {}\n".format(profile.health_max) if profile.ark_male: text += "Manimals: {} ({}%)\n".format(profile.ark_male, profile.ark_male / 10) if profile.ark_female: text += "Fenimals: {} ({}%)\n".format(profile.ark_female, profile.ark_female / 10) if profile.savings: text += "Savings: {}\n".format(profile.savings) if profile.trading_level: text += "Trading Level: {}\n".format(profile.trading_level) if profile.wood: text += "Wood: {} ({}%)\n".format(profile.wood, profile.wood / 10) # private (api only) if profile.diary_last: text += "Diary: {}\n".format(profile.diary_last) if profile.activatables: text += "Activatables in inv: {}\n".format(", ".join( profile.activatables)) if profile.aura: text += "Aura: {}\n".format(profile.aura) # pet if profile.pet.name: pet += "Name: {}\n".format(profile.pet.name) pet += "Level: {}\n".format(profile.pet.level or "No level") if profile.pet.type: pet += "Type: {}\n".format(profile.pet.type) if profile.pet.wounded: pet += "❌ — Knocked out" # times if profile.temple_date: times += "Temple completed: {}\n".format( profile.date_string("temple")) if profile.ark_date: times += "Ark completed: {}\n".format(profile.date_string("ark")) if profile.savings_date: times += "Pension collected: {}\n".format( profile.date_string("savings")) # ? finaltext = "" finaltext += text_header finaltext += chat.box(text) if pet: finaltext += "Pet:\n" finaltext += chat.box(pet) if times: finaltext += chat.box(times) await ctx.send(finaltext)
async def act(self, ctx: commands.Context, *, target: Union[discord.Member, str] = None): if not target or isinstance(target, str): return # no help text try: if not ctx.guild: raise KeyError() message = await self.config.guild(ctx.guild).get_raw("custom", ctx.invoked_with) except KeyError: try: message = await self.config.get_raw("custom", ctx.invoked_with) except KeyError: message = NotImplemented humanized: Optional[str] = None if message is None: # ignored command return elif message is NotImplemented: # default # humanize action text humanized = inflection.humanize(ctx.invoked_with) action = humanized.split() iverb = -1 for cycle in range(2): if iverb > -1: break for i, act in enumerate(action): act = act.lower() if ( act in NOLY_ADV or act in CONJ or (act.endswith("ly") and act not in LY_VERBS) or (not cycle and act in SOFT_VERBS) ): continue action[i] = inflection.pluralize(action[i]) iverb = max(iverb, i) if iverb < 0: return action.insert(iverb + 1, target.mention) message = italics(" ".join(action)) else: assert isinstance(message, str) message = fmt_re.sub(functools.partial(self.repl, target), message) send = functools.partial( ctx.send, allowed_mentions=discord.AllowedMentions( users=False if target in ctx.message.mentions else [target] ), ) # add reaction gif if self.try_after and ctx.message.created_at < self.try_after: return await send(message) if not await ctx.embed_requested(): return await send(message) key = (await ctx.bot.get_shared_api_tokens("tenor")).get("api_key") if not key: return await send(message) if humanized is None: humanized = inflection.humanize(ctx.invoked_with) async with aiohttp.request( "GET", "https://g.tenor.com/v1/search", params={ "q": humanized, "key": key, "anon_id": str(ctx.author.id ^ ctx.me.id), "media_filter": "minimal", "contentfilter": "off" if getattr(ctx.channel, "nsfw", False) else "low", "ar_range": "wide", "limit": 20, "locale": i18n.get_locale(), }, ) as response: json: dict if response.status == 429: self.try_after = ctx.message.created_at + timedelta(seconds=30) json = {} elif response.status >= 400: json = {} else: json = await response.json() if not json.get("results"): return await send(message) # Try to keep gifs more relevant by only grabbing from the top 50% + 1 of results, # in case there are only a few results. # math.ceiling() is not used since it would be too limiting for smaller lists. choice = json["results"][random.randrange(len(json["results"]) // 2 + 1)] choice = random.choice(json["results"]) embed = discord.Embed( color=await ctx.embed_color(), timestamp=datetime.fromtimestamp(choice["created"], timezone.utc), url=choice["itemurl"], ) # This footer is required by Tenor's API: https://tenor.com/gifapi/documentation#attribution embed.set_footer(text="Via Tenor") embed.set_image(url=choice["media"][0]["gif"]["url"]) await send(message, embed=embed)
async def act(self, ctx, *, target: Union[discord.Member, str] = None): """ Acts on the specified user. """ if not target or isinstance(target, str): return # no help text try: if not ctx.guild: raise KeyError() message = await self.config.guild(ctx.guild).get_raw( "custom", ctx.invoked_with) except KeyError: try: message = await self.config.get_raw("custom", ctx.invoked_with) except KeyError: message = NotImplemented if message is None: # ignored command return elif message is NotImplemented: # default # humanize action text action = inflection.humanize(ctx.invoked_with).split() iverb = -1 for cycle in range(2): if iverb > -1: break for i, act in enumerate(action): act = act.lower() if (act in NOLY_ADV or act in CONJ or (act.endswith("ly") and act not in LY_VERBS) or (not cycle and act in SOFT_VERBS)): continue action[i] = inflection.pluralize(action[i]) iverb = max(iverb, i) if iverb < 0: return action.insert(iverb + 1, target.mention) message = italics(" ".join(action)) else: message = message.format(target, user=target) # add reaction gif if not ctx.channel.permissions_for(ctx.me).embed_links: return await ctx.send(message) key = (await get_shared_api_tokens(ctx.bot, "tenor")).get("api_key") if not key: return await ctx.send(message) async with aiohttp.request( "GET", "https://api.tenor.com/v1/search", params={ "q": ctx.invoked_with, "key": key, "anon_id": str(ctx.author.id ^ ctx.me.id), "media_filter": "minimal", "contentfilter": "low", "ar_range": "wide", "locale": get_locale(), }, ) as response: if response.status >= 400: json: dict = {} else: json = await response.json() if not json.get("results"): return await ctx.send(message) message = f"{message}\n\n{random.choice(json['results'])['itemurl']}" await ctx.send(message)
content = kwargs.pop("content") except KeyError: content = getattr(__dest, "content", None) content = str(content) if content is not None else None unwrapped = [] if content: unwrapped.extend([content, ""]) title = _("title") if title: unwrapped.append(bold(title)) url = _("url") if url: unwrapped.append(f"> <{url}>") name = _("author.name") if name: unwrapped.append(italics(name)) url = _("author.url") if url: unwrapped.append(f"<{url}>") if unwrapped and unwrapped[-1]: unwrapped.append("") url = _("thumbnail.url") if url and not url.startswith("attachment://"): unwrapped.append(f"<{url}>") description = _("description") if description: unwrapped.append(quote(description)) if unwrapped and unwrapped[-1]: unwrapped.append("") for i in range(len(getattr(self, "_fields", []))): inline, name, value = (