Source code for pylav.extension.red.ui.menus.queue

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING, Any, Literal

import discord
from redbot.core.i18n import Translator

from pylav.core.context import PyLavContext
from pylav.extension.red.ui.buttons.generic import CloseButton, NavigateButton, RefreshButton
from pylav.extension.red.ui.buttons.player import DisconnectButton
from pylav.extension.red.ui.buttons.queue import (
    DecreaseVolumeButton,
    EmptyQueueButton,
    EnqueueButton,
    IncreaseVolumeButton,
    PauseTrackButton,
    PlayNowFromQueueButton,
    PreviousTrackButton,
    QueueHistoryButton,
    RemoveFromQueueButton,
    ResumeTrackButton,
    ShuffleButton,
    SkipTrackButton,
    StopTrackButton,
    ToggleRepeatButton,
    ToggleRepeatQueueButton,
)
from pylav.extension.red.ui.menus.generic import BaseMenu
from pylav.extension.red.ui.selectors.queue import QueueSelectTrack
from pylav.extension.red.ui.sources.queue import QueuePickerSource, QueueSource
from pylav.extension.red.utils.decorators import is_dj_logic
from pylav.type_hints.bot import DISCORD_BOT_TYPE, DISCORD_COG_TYPE, DISCORD_INTERACTION_TYPE

_ = Translator("PyLav", Path(__file__))

if TYPE_CHECKING:
    from pylav.players.player import Player


[docs] class QueueMenu(BaseMenu): _source: QueueSource def __init__( self, cog: DISCORD_COG_TYPE, bot: DISCORD_BOT_TYPE, source: QueueSource, original_author: discord.abc.User, *, delete_after_timeout: bool = True, timeout: int = 600, message: discord.Message = None, starting_page: int = 0, history: bool = False, **kwargs: Any, ) -> None: super().__init__( cog=cog, bot=bot, source=source, delete_after_timeout=delete_after_timeout, timeout=timeout, message=message, starting_page=starting_page, **kwargs, ) self.author = original_author self.is_history = history self.forward_button = NavigateButton( style=discord.ButtonStyle.grey, emoji="\N{BLACK RIGHT-POINTING TRIANGLE}\N{VARIATION SELECTOR-16}", direction=1, row=0, cog=cog, ) self.backward_button = NavigateButton( style=discord.ButtonStyle.grey, emoji="\N{BLACK LEFT-POINTING TRIANGLE}\N{VARIATION SELECTOR-16}", direction=-1, row=0, cog=cog, ) self.first_button = NavigateButton( style=discord.ButtonStyle.grey, emoji="\N{BLACK LEFT-POINTING DOUBLE TRIANGLE}", direction=0, row=0, cog=cog, ) self.last_button = NavigateButton( style=discord.ButtonStyle.grey, emoji="\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE}", direction=self.source.get_max_pages, row=0, cog=cog, ) self.refresh_button = RefreshButton( style=discord.ButtonStyle.grey, row=0, cog=cog, ) self.queue_disconnect = DisconnectButton( style=discord.ButtonStyle.red, row=1, cog=cog, ) self.repeat_queue_button_on = ToggleRepeatQueueButton( style=discord.ButtonStyle.blurple, row=1, cog=cog, ) self.repeat_button_on = ToggleRepeatButton( style=discord.ButtonStyle.blurple, row=1, cog=cog, ) self.repeat_button_off = ToggleRepeatButton( style=discord.ButtonStyle.grey, row=1, cog=cog, ) self.show_history_button = QueueHistoryButton( style=discord.ButtonStyle.grey, row=1, cog=cog, ) self.close_button = CloseButton( style=discord.ButtonStyle.red, row=1, cog=cog, ) self.clear_queue_button = EmptyQueueButton(style=discord.ButtonStyle.red, row=1, cog=cog) self.previous_track_button = PreviousTrackButton( style=discord.ButtonStyle.grey, row=2, cog=cog, ) self.stop_button = StopTrackButton( style=discord.ButtonStyle.grey, row=2, cog=cog, ) self.paused_button = PauseTrackButton( style=discord.ButtonStyle.blurple, row=2, cog=cog, ) self.resume_button = ResumeTrackButton( style=discord.ButtonStyle.blurple, row=2, cog=cog, ) self.skip_button = SkipTrackButton( style=discord.ButtonStyle.grey, row=2, cog=cog, ) self.shuffle_button = ShuffleButton( style=discord.ButtonStyle.grey, row=2, cog=cog, ) self.decrease_volume_button = DecreaseVolumeButton( style=discord.ButtonStyle.grey, row=3, cog=cog, ) self.increase_volume_button = IncreaseVolumeButton( style=discord.ButtonStyle.grey, row=3, cog=cog, ) self.enqueue_button = EnqueueButton( cog=cog, style=discord.ButtonStyle.green, row=3, ) self.remove_from_queue_button = RemoveFromQueueButton( cog=cog, style=discord.ButtonStyle.red, row=3, ) self.play_now_button = PlayNowFromQueueButton( cog=cog, style=discord.ButtonStyle.blurple, row=3, )
[docs] async def prepare(self): self.clear_items() max_pages = self.source.get_max_pages() is_dj = await is_dj_logic(self.ctx) if (not self.is_history) and is_dj is True: self.add_item(self.close_button) self.add_item(self.queue_disconnect) self.add_item(self.clear_queue_button) self.add_item(self.first_button) self.add_item(self.backward_button) self.add_item(self.forward_button) self.add_item(self.last_button) self.add_item(self.refresh_button) if not self.is_history: self.repeat_button_on.disabled = False self.repeat_button_off.disabled = False self.repeat_queue_button_on.disabled = False self.clear_queue_button.disabled = False self.show_history_button.disabled = False self.forward_button.disabled = False self.backward_button.disabled = False self.first_button.disabled = False self.last_button.disabled = False self.refresh_button.disabled = False if max_pages == 1: self.forward_button.disabled = True self.backward_button.disabled = True self.first_button.disabled = True self.last_button.disabled = True elif max_pages == 2: self.first_button.disabled = True self.last_button.disabled = True if self.is_history or is_dj is False: return self.previous_track_button.disabled = False self.paused_button.disabled = False self.resume_button.disabled = False self.stop_button.disabled = False self.skip_button.disabled = False self.shuffle_button.disabled = False self.decrease_volume_button.disabled = False self.increase_volume_button.disabled = False self.enqueue_button.disabled = False self.remove_from_queue_button.disabled = False self.play_now_button.disabled = False self.add_item(self.previous_track_button) self.add_item(self.stop_button) if (player := self.cog.pylav.get_player(self.source.guild_id)) and is_dj is not False: await self._player_and_dj(player) else: await self._no_player_or_no_dj() self.add_item(self.skip_button) self.add_item(self.shuffle_button) self.add_item(self.decrease_volume_button) self.add_item(self.increase_volume_button) self.add_item(self.enqueue_button) self.add_item(self.remove_from_queue_button) self.add_item(self.play_now_button)
async def _player_and_dj(self, player: Player): self.queue_disconnect.disabled = False if player.paused: self.add_item(self.resume_button) else: self.add_item(self.paused_button) if player.queue.empty(): self.shuffle_button.disabled = True self.remove_from_queue_button.disabled = True self.play_now_button.disabled = True self.clear_queue_button.disabled = True if not player.current: self.stop_button.disabled = True self.shuffle_button.disabled = True self.previous_track_button.disabled = True self.decrease_volume_button.disabled = True self.increase_volume_button.disabled = True if player.history.empty(): self.previous_track_button.disabled = True self.show_history_button.disabled = True else: self.add_item(self.show_history_button) if await player.config.fetch_repeat_current(): self.add_item(self.repeat_button_on) elif await player.config.fetch_repeat_queue(): self.add_item(self.repeat_queue_button_on) else: self.add_item(self.repeat_button_off) async def _no_player_or_no_dj(self): self.queue_disconnect.disabled = True self.forward_button.disabled = True self.backward_button.disabled = True self.first_button.disabled = True self.last_button.disabled = True self.stop_button.disabled = True self.skip_button.disabled = True self.previous_track_button.disabled = True self.repeat_button_off.disabled = True self.show_history_button.disabled = True self.shuffle_button.disabled = True self.decrease_volume_button.disabled = True self.increase_volume_button.disabled = True self.resume_button.disabled = True self.repeat_button_on.disabled = True self.enqueue_button.disabled = True self.remove_from_queue_button.disabled = True self.play_now_button.disabled = True self.repeat_queue_button_on.disabled = True self.clear_queue_button.disabled = True self.add_item(self.resume_button) self.add_item(self.repeat_button_off) @property def source(self) -> QueueSource: return self._source
[docs] async def start(self, ctx: PyLavContext | DISCORD_INTERACTION_TYPE): if isinstance(ctx, discord.Interaction): ctx = await self.cog.bot.get_context(ctx) if ctx.interaction and not ctx.interaction.response.is_done(): await ctx.defer(ephemeral=True) self.ctx = ctx await self.send_initial_message(ctx)
[docs] class QueuePickerMenu(BaseMenu): _source: QueuePickerSource def __init__( self, cog: DISCORD_COG_TYPE, bot: DISCORD_BOT_TYPE, source: QueuePickerSource, original_author: discord.abc.User, *, delete_after_timeout: bool = True, timeout: int = 120, message: discord.Message = None, starting_page: int = 0, menu_type: Literal["remove", "play"], **kwargs: Any, ) -> None: super().__init__( cog=cog, bot=bot, source=source, delete_after_timeout=delete_after_timeout, timeout=timeout, message=message, starting_page=starting_page, **kwargs, ) self.author = original_author self.menu_type = menu_type self.forward_button = NavigateButton( style=discord.ButtonStyle.grey, emoji="\N{BLACK RIGHT-POINTING TRIANGLE}\N{VARIATION SELECTOR-16}", direction=1, row=4, cog=cog, ) self.backward_button = NavigateButton( style=discord.ButtonStyle.grey, emoji="\N{BLACK LEFT-POINTING TRIANGLE}\N{VARIATION SELECTOR-16}", direction=-1, row=4, cog=cog, ) self.first_button = NavigateButton( style=discord.ButtonStyle.grey, emoji="\N{BLACK LEFT-POINTING DOUBLE TRIANGLE}", direction=0, row=4, cog=cog, ) self.last_button = NavigateButton( style=discord.ButtonStyle.grey, emoji="\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE}", direction=self.source.get_max_pages, row=4, cog=cog, ) self.close_button = CloseButton( style=discord.ButtonStyle.red, row=4, cog=cog, ) self.refresh_button = RefreshButton( style=discord.ButtonStyle.grey, row=4, cog=cog, ) self.select_view: QueueSelectTrack | None = None self.add_item(self.first_button) self.add_item(self.backward_button) self.add_item(self.forward_button) self.add_item(self.last_button) @property def source(self) -> QueuePickerSource: return self._source
[docs] async def start(self, ctx: PyLavContext | DISCORD_INTERACTION_TYPE): if isinstance(ctx, discord.Interaction): ctx = await self.cog.bot.get_context(ctx) if ctx.interaction and not ctx.interaction.response.is_done(): await ctx.defer(ephemeral=True) self.ctx = ctx await self.send_initial_message(ctx)
[docs] async def send_initial_message(self, ctx: PyLavContext | DISCORD_INTERACTION_TYPE): await self._source.get_page(0) self.ctx = ctx kwargs = await self.source.format_page(self, []) await self.prepare() self.message = await ctx.send(view=self, ephemeral=True, **kwargs) return self.message
[docs] async def show_page(self, page_number: int, interaction: DISCORD_INTERACTION_TYPE): await self._source.get_page(page_number) await self.prepare() self.current_page = page_number if self.message is not None: if not interaction.response.is_done(): await interaction.response.pong() await self.message.edit(view=self) elif not interaction.response.is_done(): await interaction.response.edit_message(view=self)
[docs] async def prepare(self): self.clear_items() max_pages = self.source.get_max_pages() self.forward_button.disabled = False self.backward_button.disabled = False self.first_button.disabled = False self.last_button.disabled = False if max_pages == 1: self.forward_button.disabled = True self.backward_button.disabled = True self.first_button.disabled = True self.last_button.disabled = True elif max_pages == 2: self.first_button.disabled = True self.last_button.disabled = True self.add_item(self.close_button) self.add_item(self.first_button) self.add_item(self.backward_button) self.add_item(self.forward_button) self.add_item(self.last_button) if self.source.select_options: options = self.source.select_options if self.menu_type == "remove": title = _("Select a track to remove.") else: title = _("Select a track to play now.") self.remove_item(self.select_view) self.select_view = QueueSelectTrack( options=options, cog=self.cog, placeholder=title, interaction_type=self.menu_type, mapping=self.source.select_mapping, ) self.add_item(self.select_view) if self.select_view and not self.source.select_options: self.remove_item(self.select_view) self.select_view = None