Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 84 additions & 19 deletions src/tux/modules/features/bookmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@

from __future__ import annotations

import asyncio
import io
from collections.abc import Sequence

import aiohttp
import discord
from discord import StandardSticker, StickerFormatType, StickerItem
from discord.abc import Messageable
from discord.ext import commands
from loguru import logger
Expand Down Expand Up @@ -130,7 +133,7 @@ async def add_bookmark(self, user: discord.User, message: discord.Message) -> No
message : discord.Message
The message to be bookmarked.
"""
embed = self._create_bookmark_embed(message)
embed = await self._create_bookmark_embed(message)
files = await self._get_files_from_message(message)

try:
Expand Down Expand Up @@ -212,8 +215,8 @@ async def _get_files_from_stickers(
break

if sticker.format in {
discord.StickerFormatType.png,
discord.StickerFormatType.apng,
StickerFormatType.png,
StickerFormatType.apng,
}:
try:
sticker_bytes = await sticker.read()
Expand Down Expand Up @@ -287,7 +290,49 @@ async def _get_files_from_message(

return files

def _create_bookmark_embed(self, message: discord.Message) -> discord.Embed:
async def _format_sticker_bullets(
self,
stickers: Sequence[StickerItem],
) -> str:
"""Build sticker lines for the embed: link guild stickers; name-only for standard.

Fetches full sticker metadata so :class:`StandardSticker` can be detected;
uses :attr:`StickerItem.url` for links (correct CDN for png/apng/gif).

Parameters
----------
stickers : Sequence[StickerItem]
Sticker items from the message.

Returns
-------
str
Newline-separated bullet lines, or empty string.
"""
if not stickers:
return ""

results = await asyncio.gather(
*[s.fetch() for s in stickers],
return_exceptions=True,
)
lines: list[str] = []
for sticker, full in zip(stickers, results, strict=True):
if isinstance(full, Exception):
logger.debug(
"Could not fetch sticker {} for bookmark embed: {}",
sticker.id,
full,
)
lines.append(f"• {sticker.name}")
continue
if isinstance(full, StandardSticker):
lines.append(f"• {sticker.name}")
else:
lines.append(f"• [{sticker.name}]({sticker.url})")
return "\n".join(lines)

async def _create_bookmark_embed(self, message: discord.Message) -> discord.Embed:
"""
Create an embed for a bookmarked message.

Expand All @@ -311,13 +356,45 @@ def _create_bookmark_embed(self, message: discord.Message) -> discord.Embed:
if len(content) > EMBED_MAX_DESC_LENGTH:
content = f"{content[: EMBED_MAX_DESC_LENGTH - 4]}..."

# Prepare attachment bullets
attachment_list = ""
if message.attachments:
attachment_list = "\n".join(
f"• [{att.filename}]({att.url})" for att in message.attachments
)

stickers: Sequence[StickerItem] = message.stickers
Comment thread
meatsnails marked this conversation as resolved.
sticker_list = await self._format_sticker_bullets(stickers)

# Combine everything into the embed description and enforce the max length

parts: list[str] = []
if content:
parts.append(content)
else:
parts.append("> No content available to display")
if attachment_list:
parts.append(f"**Attachments:**\n{attachment_list}")
if sticker_list:
parts.append(f"**Stickers:**\n{sticker_list}")
description = "\n\n".join(parts)

limit_warning = "\n\n*(Message cut off due to character limit.)*"
# Ensure we never exceed Discord's embed description limit
if len(description) > EMBED_MAX_DESC_LENGTH:
# reserve space for the notice
cutoff = EMBED_MAX_DESC_LENGTH - len(limit_warning)

# avoid negative slice sizes in extreme cases
cutoff = max(0, cutoff)

description = description[:cutoff].rstrip() + limit_warning

embed = EmbedCreator.create_embed(
bot=self.bot,
embed_type=EmbedCreator.INFO,
title="Message Bookmarked",
description=f"{content}"
if content
else "> No content available to display",
description=description,
)

# Add author to the embed
Expand All @@ -341,18 +418,6 @@ def _create_bookmark_embed(self, message: discord.Message) -> discord.Embed:
value=f"[Click Here]({message.jump_url})",
)

# Add attachments to the embed
if message.attachments:
Comment thread
meatsnails marked this conversation as resolved.
attachments = "\n".join(
f"[{a.filename}]({a.url})" for a in message.attachments
)
embed.add_field(name="Attachments", value=attachments, inline=False)

# Add stickers to the embed
if message.stickers:
stickers = "\n".join(f"[{s.name}]({s.url})" for s in message.stickers)
embed.add_field(name="Stickers", value=stickers, inline=False)

# Handle embeds
if message.embeds:
embed.add_field(
Expand Down
Loading