Refactor message dispatch and playlist view error handling

Updated dispatch_message to use discord.utils.MISSING and improved content formatting. Added error handling in PlaylistView for VoicelinkException and refactored on_timeout logic in PlaylistViewManager to avoid duplication. Minor improvements to playlist track rendering.
This commit is contained in:
Choco
2025-11-20 23:34:34 +08:00
parent e99aefefcf
commit e2ba8b472a
2 changed files with 25 additions and 21 deletions

View File

@@ -30,7 +30,6 @@ from itertools import zip_longest
from typing import Dict, Optional, Union from typing import Dict, Optional, Union
from timeit import default_timer as timer from timeit import default_timer as timer
from discord.ext import commands from discord.ext import commands
from discord.utils import MISSING
from .mongodb import MongoDBHandler from .mongodb import MongoDBHandler
from .language import LangHandler from .language import LangHandler
@@ -303,7 +302,7 @@ async def dispatch_message(
*params, *params,
view: Optional[discord.ui.View] = None, view: Optional[discord.ui.View] = None,
file: Optional[discord.File] = None, file: Optional[discord.File] = None,
delete_after: Optional[float] = MISSING, delete_after: Optional[float] = discord.utils.MISSING,
ephemeral: bool = False, ephemeral: bool = False,
requires_fetch: bool = False requires_fetch: bool = False
) -> Optional[discord.Message]: ) -> Optional[discord.Message]:
@@ -323,12 +322,12 @@ async def dispatch_message(
Returns: Returns:
The sent message object, or None. The sent message object, or None.
""" """
if content is None: if not content:
content = "No content provided." content = "No content provided."
# Determine the text to send # Determine the text to send
embed = content if isinstance(content, discord.Embed) else None embed = content if isinstance(content, discord.Embed) else None
text = None if embed else content.format(*params) text = None if embed else str(content).format(*params) if params else str(content)
# Determine the sending function # Determine the sending function
send_func = ( send_func = (
@@ -354,9 +353,9 @@ async def dispatch_message(
send_kwargs["view"] = view send_kwargs["view"] = view
if "delete_after" in send_func.__code__.co_varnames: if "delete_after" in send_func.__code__.co_varnames:
if delete_after is MISSING and settings and ctx.channel.id == settings.get("music_request_channel", {}).get("text_channel_id"): if delete_after is discord.utils.MISSING and settings and ctx.channel.id == settings.get("music_request_channel", {}).get("text_channel_id"):
delete_after = 10 delete_after = 10
send_kwargs["delete_after"] = delete_after if delete_after != MISSING else None send_kwargs["delete_after"] = delete_after if delete_after is not discord.utils.MISSING else None
if "ephemeral" in send_func.__code__.co_varnames: if "ephemeral" in send_func.__code__.co_varnames:
send_kwargs["ephemeral"] = ephemeral send_kwargs["ephemeral"] = ephemeral

View File

@@ -31,9 +31,10 @@ from typing import Any
from .utils import DynamicViewManager, Pagination from .utils import DynamicViewManager, Pagination
from .pagination import PaginationView from .pagination import PaginationView
from ..config import Config from ..config import Config
from ..utils import format_ms, truncate_string from ..utils import format_ms, truncate_string, dispatch_message
from ..mongodb import MongoDBHandler from ..mongodb import MongoDBHandler
from ..language import LangHandler from ..language import LangHandler
from ..exceptions import VoicelinkException
class PlaylistDropdown(discord.ui.Select): class PlaylistDropdown(discord.ui.Select):
def __init__(self, results: list[dict[str, Any]], lang: str) -> None: def __init__(self, results: list[dict[str, Any]], lang: str) -> None:
@@ -108,7 +109,7 @@ class PlaylistView(PaginationView):
embed.description += f"\n\n**{texts[5]}:**\n" embed.description += f"\n\n**{texts[5]}:**\n"
if tracks: if tracks:
for index, track in enumerate(tracks, start=self.pagination.start_index + 1): for index, track in enumerate(tracks, start=self.pagination.start_index + 1):
if self.type == "playlist": if isinstance(track, dict):
source_emoji = Config().get_source_config(track['sourceName'], 'emoji') source_emoji = Config().get_source_config(track['sourceName'], 'emoji')
track_info = f"{source_emoji} `{index:>2}.` `[{format_ms(track['length'])}]` [{truncate_string(track['title'])}]({track['uri']})" track_info = f"{source_emoji} `{index:>2}.` `[{format_ms(track['length'])}]` [{truncate_string(track['title'])}]({track['uri']})"
else: else:
@@ -140,6 +141,10 @@ class PlaylistView(PaginationView):
} }
return super().update_view(extra_states) return super().update_view(extra_states)
async def on_error(self, interaction: discord.Interaction, error: Exception, item: discord.ui.Item) -> None:
if isinstance(error, VoicelinkException):
return await dispatch_message(interaction, content=getattr(error, 'original', error), ephemeral=True)
async def update_message(self, interaction: discord.Interaction) -> None: async def update_message(self, interaction: discord.Interaction) -> None:
"""Update the view and edit the message with the new embed.""" """Update the view and edit the message with the new embed."""
self.update_view() self.update_view()
@@ -199,6 +204,18 @@ class PlaylistViewManager(DynamicViewManager):
self.response: discord.Message = None self.response: discord.Message = None
self.add_item(PlaylistDropdown(results, self.lang)) self.add_item(PlaylistDropdown(results, self.lang))
async def on_timeout(self) -> None:
for view in self._views.values():
view.stop()
for child in self.current_view.children:
child.disabled = True
try:
await self.response.edit(view=self)
except:
pass
def get_width(self, s): def get_width(self, s):
width = 0 width = 0
for char in str(s): for char in str(s):
@@ -214,18 +231,6 @@ class PlaylistViewManager(DynamicViewManager):
padding = width - current_width padding = width - current_width
return s + " " * padding return s + " " * padding
async def on_timeout(self) -> None:
for view in self._views.values():
view.stop()
for child in self.current_view.children:
child.disabled = True
try:
await self.response.edit(view=self)
except:
pass
def build_embed(self) -> discord.Embed: def build_embed(self) -> discord.Embed:
""" """
Build the embed for the playlist overview. Build the embed for the playlist overview.