mirror of
https://github.com/deadcxap/YandexMusicDiscordBot.git
synced 2026-01-10 12:31:46 +03:00
feat: Add "My Vibe" button to menu and enhance interactions.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import logging
|
||||
from typing import Literal, cast
|
||||
from typing import Any, Literal, cast
|
||||
|
||||
import discord
|
||||
from yandex_music import Track, Album, Artist, Playlist
|
||||
@@ -19,11 +19,11 @@ class PlayButton(Button, VoiceExtension):
|
||||
logging.debug(f"Callback triggered for type: '{type(self.item).__name__}'")
|
||||
|
||||
if not interaction.guild:
|
||||
logging.warning("No guild found in context.")
|
||||
logging.warning("No guild found in PlayButton callback")
|
||||
return
|
||||
|
||||
if not await self.voice_check(interaction):
|
||||
logging.debug("Voice check failed")
|
||||
logging.debug("Voice check failed in PlayButton callback")
|
||||
return
|
||||
|
||||
gid = interaction.guild.id
|
||||
@@ -41,7 +41,7 @@ class PlayButton(Button, VoiceExtension):
|
||||
elif isinstance(self.item, Album):
|
||||
album = await self.item.with_tracks_async()
|
||||
if not album or not album.volumes:
|
||||
logging.debug("Failed to fetch album tracks")
|
||||
logging.debug("Failed to fetch album tracks in PlayButton callback")
|
||||
await interaction.respond("Не удалось получить треки альбома.", ephemeral=True)
|
||||
return
|
||||
|
||||
@@ -53,7 +53,7 @@ class PlayButton(Button, VoiceExtension):
|
||||
elif isinstance(self.item, Artist):
|
||||
artist_tracks = await self.item.get_tracks_async()
|
||||
if not artist_tracks:
|
||||
logging.debug("Failed to fetch artist tracks")
|
||||
logging.debug("Failed to fetch artist tracks in PlayButton callback")
|
||||
await interaction.respond("Не удалось получить треки артиста.", ephemeral=True)
|
||||
return
|
||||
|
||||
@@ -65,7 +65,7 @@ class PlayButton(Button, VoiceExtension):
|
||||
elif isinstance(self.item, Playlist):
|
||||
short_tracks = await self.item.fetch_tracks_async()
|
||||
if not short_tracks:
|
||||
logging.debug("Failed to fetch playlist tracks")
|
||||
logging.debug("Failed to fetch playlist tracks in PlayButton callback")
|
||||
await interaction.respond("❌ Не удалось получить треки из плейлиста.", delete_after=15)
|
||||
return
|
||||
|
||||
@@ -77,7 +77,7 @@ class PlayButton(Button, VoiceExtension):
|
||||
elif isinstance(self.item, list):
|
||||
tracks = self.item.copy()
|
||||
if not tracks:
|
||||
logging.debug("Empty tracks list")
|
||||
logging.debug("Empty tracks list in PlayButton callback")
|
||||
await interaction.respond("❌ Не удалось получить треки.", delete_after=15)
|
||||
return
|
||||
|
||||
@@ -89,7 +89,7 @@ class PlayButton(Button, VoiceExtension):
|
||||
raise ValueError(f"Unknown item type: '{type(self.item).__name__}'")
|
||||
|
||||
if guild.get(f'vote_{action}') and len(channel.members) > 2 and not member.guild_permissions.manage_channels:
|
||||
logging.debug(f"Starting vote for '{action}'")
|
||||
logging.debug(f"Starting vote for '{action}' (from PlayButton callback)")
|
||||
|
||||
message = cast(discord.Interaction, await interaction.respond(vote_message, delete_after=30))
|
||||
response = await message.original_response()
|
||||
@@ -109,7 +109,7 @@ class PlayButton(Button, VoiceExtension):
|
||||
}
|
||||
)
|
||||
else:
|
||||
logging.debug(f"Skipping vote for '{action}'")
|
||||
logging.debug(f"Skipping vote for '{action}' (from PlayButton callback)")
|
||||
|
||||
if guild['current_track'] is not None:
|
||||
self.db.modify_track(gid, tracks, 'next', 'extend')
|
||||
@@ -129,6 +129,41 @@ class PlayButton(Button, VoiceExtension):
|
||||
else:
|
||||
await interaction.respond(response_message, delete_after=15)
|
||||
|
||||
class MyVibeButton(Button, VoiceExtension):
|
||||
def __init__(self, item: Track | Album | Artist | Playlist | list[Track], *args, **kwargs):
|
||||
Button.__init__(self, *args, **kwargs)
|
||||
VoiceExtension.__init__(self, None)
|
||||
self.item = item
|
||||
|
||||
async def callback(self, interaction: discord.Interaction):
|
||||
logging.debug(f"[VIBE] Button callback for '{type(self.item).__name__}'")
|
||||
if not await self.voice_check(interaction):
|
||||
return
|
||||
|
||||
gid = interaction.guild_id
|
||||
if not gid:
|
||||
logging.warning(f"[VIBE] Guild ID is None in button callback")
|
||||
return
|
||||
|
||||
guild = self.db.get_guild(gid)
|
||||
channel = cast(discord.VoiceChannel, interaction.channel)
|
||||
|
||||
if len(channel.members) > 2 and not guild['always_allow_menu']:
|
||||
logging.info(f"[VIBE] Button callback declined: other members are present in the voice channel")
|
||||
await interaction.respond("❌ Вы не единственный в голосовом канале.", ephemeral=True)
|
||||
return
|
||||
|
||||
track_type_map: dict[Any, Literal['track', 'album', 'artist', 'playlist', 'user']] = {
|
||||
Track: 'track', Album: 'album', Artist: 'artist', Playlist: 'playlist', list: 'user'
|
||||
} # NOTE: Likes playlist should have its own entry instead of 'user:onyourwave'
|
||||
|
||||
await self.send_menu_message(interaction)
|
||||
await self.update_vibe(
|
||||
interaction,
|
||||
track_type_map[type(self.item)],
|
||||
cast(int, self.item.uid) if isinstance(self.item, Playlist) else cast(int | str, self.item.id) if not isinstance(self.item, list) else 'onyourwave'
|
||||
)
|
||||
|
||||
class ListenView(View):
|
||||
def __init__(self, item: Track | Album | Artist | Playlist | list[Track], *items: Item, timeout: float | None = 3600, disable_on_timeout: bool = False):
|
||||
super().__init__(*items, timeout=timeout, disable_on_timeout=disable_on_timeout)
|
||||
@@ -150,11 +185,13 @@ class ListenView(View):
|
||||
self.add_item(PlayButton(item, label="Слушать в голосовом канале", style=ButtonStyle.gray))
|
||||
return
|
||||
|
||||
self.button1: Button = Button(label="Слушать в приложении", style=ButtonStyle.gray, url=link_app)
|
||||
self.button2: Button = Button(label="Слушать в браузере", style=ButtonStyle.gray, url=link_web)
|
||||
self.button3: PlayButton = PlayButton(item, label="Слушать в голосовом канале", style=ButtonStyle.gray)
|
||||
self.button1: Button = Button(label="Слушать в приложении", style=ButtonStyle.gray, url=link_app, row=0)
|
||||
self.button2: Button = Button(label="Слушать в браузере", style=ButtonStyle.gray, url=link_web, row=0)
|
||||
self.button3: PlayButton = PlayButton(item, label="Слушать в голосовом канале", style=ButtonStyle.gray, row=0)
|
||||
self.button4: MyVibeButton = MyVibeButton(item, label="Моя Волна", style=ButtonStyle.gray, emoji="🌊", row=1)
|
||||
|
||||
if item.available:
|
||||
# self.add_item(self.button1) # Discord doesn't allow well formed URLs in buttons for some reason.
|
||||
self.add_item(self.button2)
|
||||
self.add_item(self.button3)
|
||||
self.add_item(self.button3)
|
||||
self.add_item(self.button4)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import logging
|
||||
from typing import Self, cast
|
||||
|
||||
from discord.ui import View, Button, Item
|
||||
from discord import VoiceChannel, ButtonStyle, Interaction, ApplicationContext, RawReactionActionEvent, Embed
|
||||
from discord.ui import View, Button, Item, Modal, Select
|
||||
from discord import VoiceChannel, ButtonStyle, Interaction, ApplicationContext, RawReactionActionEvent, Embed, ComponentType, SelectOption
|
||||
|
||||
import yandex_music.exceptions
|
||||
from yandex_music import Track, ClientAsync
|
||||
from MusicBot.cogs.utils.voice_extension import VoiceExtension
|
||||
|
||||
@@ -123,8 +124,15 @@ class LyricsButton(Button, VoiceExtension):
|
||||
ClientAsync(ym_token), # type: ignore # Async client can be used here
|
||||
))
|
||||
|
||||
lyrics = await track.get_lyrics_async()
|
||||
try:
|
||||
lyrics = await track.get_lyrics_async()
|
||||
except yandex_music.exceptions.NotFoundError:
|
||||
logging.debug('Lyrics not found')
|
||||
await interaction.respond("❌ Текст песни не найден. Яндекс нам соврал (опять)!", delete_after=15, ephemeral=True)
|
||||
return
|
||||
|
||||
if not lyrics:
|
||||
logging.debug('Lyrics not found')
|
||||
return
|
||||
|
||||
embed = Embed(
|
||||
@@ -137,6 +145,36 @@ class LyricsButton(Button, VoiceExtension):
|
||||
embed.add_field(name='', value=subtext, inline=False)
|
||||
await interaction.respond(embed=embed, ephemeral=True)
|
||||
|
||||
class MyVibeButton(Button, VoiceExtension):
|
||||
def __init__(self, **kwargs):
|
||||
Button.__init__(self, **kwargs)
|
||||
VoiceExtension.__init__(self, None)
|
||||
|
||||
async def callback(self, interaction: Interaction) -> None:
|
||||
logging.info('[VIBE] My vibe button callback')
|
||||
if not await self.voice_check(interaction):
|
||||
return
|
||||
if not interaction.guild_id:
|
||||
logging.warning('[VIBE] No guild id in button callback')
|
||||
return
|
||||
|
||||
track = self.db.get_track(interaction.guild_id, 'current')
|
||||
if track:
|
||||
logging.info(f"[VIBE] Playing vibe for track '{track["id"]}'")
|
||||
await self.update_vibe(
|
||||
interaction,
|
||||
'track',
|
||||
track['id'],
|
||||
button_callback=True
|
||||
)
|
||||
else:
|
||||
logging.info('[VIBE] Playing on your wave')
|
||||
await self.update_vibe(
|
||||
interaction,
|
||||
'user',
|
||||
'onyourwave',
|
||||
button_callback=True
|
||||
)
|
||||
|
||||
class MenuView(View, VoiceExtension):
|
||||
|
||||
@@ -156,8 +194,9 @@ class MenuView(View, VoiceExtension):
|
||||
|
||||
self.like_button = LikeButton(style=ButtonStyle.secondary, emoji='❤️', row=1)
|
||||
self.lyrics_button = LyricsButton(style=ButtonStyle.secondary, emoji='📋', row=1)
|
||||
self.vibe_button = MyVibeButton(style=ButtonStyle.secondary, emoji='🌊', row=1)
|
||||
|
||||
async def init(self) -> Self:
|
||||
async def init(self, *, disable: bool = False) -> Self:
|
||||
current_track = self.guild['current_track']
|
||||
likes = await self.get_likes(self.ctx)
|
||||
|
||||
@@ -177,6 +216,10 @@ class MenuView(View, VoiceExtension):
|
||||
|
||||
self.add_item(self.like_button)
|
||||
self.add_item(self.lyrics_button)
|
||||
self.add_item(self.vibe_button)
|
||||
|
||||
if disable:
|
||||
self.disable_all_items()
|
||||
|
||||
return self
|
||||
|
||||
@@ -186,7 +229,7 @@ class MenuView(View, VoiceExtension):
|
||||
return
|
||||
|
||||
if self.guild['current_menu']:
|
||||
self.db.update(self.ctx.guild_id, {'current_menu': None, 'previous_tracks': []})
|
||||
self.db.update(self.ctx.guild_id, {'current_menu': None, 'previous_tracks': [], 'vibing': False})
|
||||
message = await self.get_menu_message(self.ctx, self.guild['current_menu'])
|
||||
if message:
|
||||
await message.delete()
|
||||
|
||||
Reference in New Issue
Block a user