Source code for pylav.extension.red.ui.buttons.playlist

from __future__ import annotations

import itertools
from io import BytesIO
from pathlib import Path
from typing import TYPE_CHECKING, Literal

import discord
from discord import Emoji, PartialEmoji
from redbot.core.i18n import Translator

from pylav.extension.red.utils import rgetattr
from pylav.helpers import emojis
from pylav.helpers.format.strings import shorten_string
from pylav.storage.models.playlist import Playlist
from pylav.type_hints.bot import DISCORD_COG_TYPE, DISCORD_INTERACTION_TYPE

if TYPE_CHECKING:
    from pylav.extension.red.ui.menus.playlist import PlaylistCreationFlow, PlaylistManageFlow
_ = Translator("PyLav", Path(__file__))


[docs] class PlaylistDeleteButton(discord.ui.Button): view: PlaylistManageFlow def __init__(self, cog: DISCORD_COG_TYPE, style: discord.ButtonStyle, row: int = None): super().__init__( style=style, emoji=emojis.TRASH, row=row, ) self.cog = cog
[docs] async def callback(self, interaction: DISCORD_INTERACTION_TYPE): if not interaction.response.is_done(): await interaction.response.defer(ephemeral=True) context = await self.cog.bot.get_context(interaction) if self.view.author.id != interaction.user.id: return await context.send( embed=await self.cog.pylav.construct_embed( messageable=interaction, description=_("You are not authorized to interact with this option.") ), ephemeral=True, ) self.view.cancelled = False self.view.delete = not self.view.delete if self.view.delete: response = _("I will delete this playlist permanently once you select “done”.") else: response = _("I will no longer delete this playlist permanently once you select “done”.") await context.send( embed=await self.cog.pylav.construct_embed(messageable=interaction, description=response), ephemeral=True, )
[docs] class PlaylistClearButton(discord.ui.Button): view: PlaylistManageFlow def __init__(self, cog: DISCORD_COG_TYPE, style: discord.ButtonStyle, row: int = None): super().__init__( style=style, emoji=emojis.CLEAR, row=row, ) self.cog = cog
[docs] async def callback(self, interaction: DISCORD_INTERACTION_TYPE): if not interaction.response.is_done(): await interaction.response.defer(ephemeral=True) context = await self.cog.bot.get_context(interaction) if self.view.author.id != interaction.user.id: return await context.send( embed=await self.cog.pylav.construct_embed( messageable=interaction, description=_("You are not authorized to interact with this option.") ), ephemeral=True, ) self.view.cancelled = False self.view.clear = not self.view.clear if self.view.clear: response = _("I will remove all tracks from this playlist.") else: response = _("I will no longer remove all tracks from this playlist.") await context.send( embed=await self.cog.pylav.construct_embed(messageable=interaction, description=response), ephemeral=True, )
[docs] class PlaylistDownloadButton(discord.ui.Button): view: PlaylistManageFlow def __init__( self, cog: DISCORD_COG_TYPE, style: discord.ButtonStyle, emoji: str | Emoji | PartialEmoji, row: int = None, ): super().__init__( style=style, emoji=emoji, row=row, ) self.cog = cog
[docs] async def callback(self, interaction: DISCORD_INTERACTION_TYPE): if not interaction.response.is_done(): await interaction.response.defer(ephemeral=True, thinking=True) context = await self.cog.bot.get_context(interaction) if self.view.author.id != interaction.user.id: return await context.send( embed=await self.cog.pylav.construct_embed( messageable=interaction, description=_("You are not authorized to interact with this option.") ), ephemeral=True, ) async with self.view.playlist.to_yaml(guild=interaction.guild) as (yaml_file, compressed): yaml_file: BytesIO if compressed == "gzip": message = _( "Here is your playlist: {playlist_name_variable_do_not_translate}. " "This file is compressed using Gzip to make it possible to be sent via Discord. " "You can use {url_name_variable_do_not_translate} to decompress it." ).format( playlist_name_variable_do_not_translate=await self.view.playlist.get_name_formatted(with_url=True), url_name_variable_do_not_translate="<https://gzip.swimburger.net/>", ) elif compressed == "brotli": message = _( "Here is your playlist: {playlist_name_name_variable_do_not_translate}. " "This file is compressed using Brotli to make it possible to be sent via Discord." ).format( playlist_name_name_variable_do_not_translate=await self.view.playlist.get_name_formatted( with_url=True ) ) else: message = _("Here is your playlist: {playlist_name_name_variable_do_not_translate}.").format( playlist_name_name_variable_do_not_translate=await self.view.playlist.get_name_formatted( with_url=True ) ) await context.send( embed=await self.cog.pylav.construct_embed( messageable=interaction, description=message, ), file=discord.File( filename=f"{await self.view.playlist.fetch_name()}{'.gz' if compressed=='gzip' else '.br' if compressed=='brotli' else ''}.pylav", fp=yaml_file, ), ephemeral=True, )
[docs] class PlaylistUpdateButton(discord.ui.Button): view: PlaylistManageFlow def __init__(self, cog: DISCORD_COG_TYPE, style: discord.ButtonStyle, row: int = None): super().__init__( style=style, emoji=emojis.UPDATE, row=row, ) self.cog = cog
[docs] async def callback(self, interaction: DISCORD_INTERACTION_TYPE): if not interaction.response.is_done(): await interaction.response.defer(ephemeral=True, thinking=True) context = await self.cog.bot.get_context(interaction) if self.view.author.id != interaction.user.id: return await context.send( embed=await self.cog.pylav.construct_embed( messageable=interaction, description=_("You are not authorized to interact with this option.") ), ephemeral=True, ) self.view.cancelled = False self.view.update = not self.view.update if (await self.view.playlist.fetch_url() or self.view.url) and self.view.update: response = _("I will update this playlist with the latest tracks, press done to continue.") else: self.view.update = False response = _("I will no longer update this playlist with the latest tracks.") await context.send( embed=await self.cog.pylav.construct_embed(messageable=interaction, description=response), ephemeral=True, )
[docs] class PlaylistInfoButton(discord.ui.Button): view: PlaylistManageFlow def __init__( self, cog: DISCORD_COG_TYPE, style: discord.ButtonStyle, emoji: str | Emoji | PartialEmoji, playlist: Playlist, row: int = None, ): super().__init__( style=style, emoji=emoji, row=row, ) self.cog = cog self.playlist = playlist
[docs] async def callback(self, interaction: DISCORD_INTERACTION_TYPE): if not interaction.response.is_done(): await interaction.response.defer(ephemeral=True) context = await self.cog.bot.get_context(interaction) if self.view.author.id != interaction.user.id: return await context.send( embed=await self.cog.pylav.construct_embed( messageable=interaction, description=_("You are not authorized to interact with this option.") ), ephemeral=True, ) from pylav.extension.red.ui.menus.generic import PaginatingMenu from pylav.extension.red.ui.sources.playlist import TrackMappingSource tracks = await self.view.playlist.fetch_tracks() await PaginatingMenu( bot=self.cog.bot, cog=self.cog, source=TrackMappingSource( guild_id=interaction.guild.id, cog=self.cog, author=interaction.user, entries=tracks, playlist=self.playlist, ), delete_after_timeout=True, starting_page=0, original_author=interaction.user, ).start(context)
[docs] class PlaylistQueueButton(discord.ui.Button): view: PlaylistManageFlow def __init__( self, cog: DISCORD_COG_TYPE, style: discord.ButtonStyle, emoji: str | Emoji | PartialEmoji, row: int = None, ): super().__init__( style=style, emoji=emoji, row=row, ) self.cog = cog
[docs] async def callback(self, interaction: DISCORD_INTERACTION_TYPE): if not interaction.response.is_done(): await interaction.response.defer(ephemeral=True) context = await self.cog.bot.get_context(interaction) if self.view.author.id != interaction.user.id: return await context.send( embed=await self.cog.pylav.construct_embed( messageable=interaction, description=_("You are not authorized to interact with this option.") ), ephemeral=True, ) self.view.queue = not self.view.queue if self.view.queue: await context.send( embed=await self.cog.pylav.construct_embed( messageable=interaction, description=_("I will add the current queue this playlist.") ), ephemeral=True, ) else: await context.send( embed=await self.cog.pylav.construct_embed( messageable=interaction, description=_("I will no longer add the current queue to this playlist.") ), ephemeral=True, )
[docs] class PlaylistDedupeButton(discord.ui.Button): view: PlaylistManageFlow def __init__( self, cog: DISCORD_COG_TYPE, style: discord.ButtonStyle, emoji: str | Emoji | PartialEmoji, row: int = None, ): super().__init__( style=style, emoji=emoji, row=row, ) self.cog = cog
[docs] async def callback(self, interaction: DISCORD_INTERACTION_TYPE): if not interaction.response.is_done(): await interaction.response.defer(ephemeral=True) context = await self.cog.bot.get_context(interaction) if self.view.author.id != interaction.user.id: return await context.send( embed=await self.cog.pylav.construct_embed( messageable=interaction, description=_("You are not authorized to interact with this option.") ), ephemeral=True, ) self.view.dedupe = not self.view.dedupe if self.view.dedupe: await context.send( embed=await self.cog.pylav.construct_embed( messageable=interaction, description=_("I will remove all duplicate tracks from the queue.") ), ephemeral=True, ) else: await context.send( embed=await self.cog.pylav.construct_embed( messageable=interaction, description=_("I will no longer remove duplicate tracks from the queue.") ), ephemeral=True, )
[docs] class PlaylistUpsertButton(discord.ui.Button): view: PlaylistCreationFlow | PlaylistManageFlow def __init__( self, cog: DISCORD_COG_TYPE, style: discord.ButtonStyle, op: Literal["url", "name", "scope", "add", "remove"], label: str = None, emoji: str | Emoji | PartialEmoji = None, row: int = None, ): super().__init__( style=style, emoji=emoji, label=label, row=row, ) self.cog = cog self.op = op
[docs] async def callback(self, interaction: DISCORD_INTERACTION_TYPE): if self.view.author.id != interaction.user.id: return await interaction.response.send_message( embed=await self.cog.pylav.construct_embed( messageable=interaction, description=_("You are not authorized to interact with this option.") ), ephemeral=True, ) self.view.cancelled = False if self.op == "url": await self.view.prompt_url(interaction) elif self.op == "name": await self.view.prompt_name(interaction) elif self.op == "scope": await self.view.prompt_scope(interaction) elif self.op == "add": await self.view.prompt_add_tracks(interaction) elif self.op == "remove": await self.view.prompt_remove_tracks(interaction)
[docs] class EnqueuePlaylistButton(discord.ui.Button): def __init__( self, cog: DISCORD_COG_TYPE, style: discord.ButtonStyle, row: int = None, emoji: Emoji | PartialEmoji = emojis.PLAYLIST, playlist: Playlist = None, ): self.cog = cog super().__init__( style=style, emoji=emoji, row=row, ) self.playlist = playlist
[docs] async def callback(self, interaction: DISCORD_INTERACTION_TYPE): if not interaction.response.is_done(): await interaction.response.defer(ephemeral=True) context = await self.cog.bot.get_context(interaction) if not self.playlist: playlists = await self.cog.pylav.playlist_db_manager.get_all_for_user( requester=context.author.id, vc=rgetattr(context.author, "voice.channel", None), guild=context.guild, channel=context.channel, ) playlists = list(itertools.chain.from_iterable(playlists)) from pylav.extension.red.ui.menus.playlist import PlaylistPickerMenu from pylav.extension.red.ui.selectors.playlist import PlaylistPlaySelector from pylav.extension.red.ui.sources.playlist import PlaylistPickerSource await PlaylistPickerMenu( cog=self.cog, bot=self.cog.bot, selector_cls=PlaylistPlaySelector, source=PlaylistPickerSource( guild_id=context.guild.id, cog=self.cog, pages=playlists, message_str=_("Playlists you can currently play."), ), delete_after_timeout=True, clear_buttons_after=True, starting_page=0, original_author=context.author, selector_text=shorten_string(max_length=100, string=_("Pick a playlist.")), ).start(context) else: await self.cog.command_playlist_play.callback(self.cog, interaction, playlist=[self.playlist]) if hasattr(self.view, "prepare"): await self.view.prepare() kwargs = await self.view.get_page(self.view.current_page) attachments = [] if "file" in kwargs: attachments = [kwargs.pop("file")] elif "files" in kwargs: attachments = kwargs.pop("files") if attachments: kwargs["attachments"] = attachments await self.view.message.edit(view=self.view, **kwargs)
[docs] class SaveQueuePlaylistButton(discord.ui.Button): def __init__(self, cog: DISCORD_COG_TYPE, style: discord.ButtonStyle, row: int = None): super().__init__( style=style, emoji=emojis.QUEUE, row=row, ) self.cog = cog
[docs] async def callback(self, interaction: DISCORD_INTERACTION_TYPE): from pylav.extension.red.ui.modals.playlist import PlaylistSaveModal modal = PlaylistSaveModal(self.cog, self, _("What should the playlist name be?")) await interaction.response.send_modal(modal)