mirror of
https://github.com/deadcxap/YandexMusicDiscordBot.git
synced 2026-01-10 02:51:45 +03:00
impr: Add new votings.
This commit is contained in:
@@ -155,7 +155,7 @@ class General(Cog):
|
|||||||
"`Примечание`: Доступность меню и Моей Волны зависит от настроек сервера.\n\n"
|
"`Примечание`: Доступность меню и Моей Волны зависит от настроек сервера.\n\n"
|
||||||
"Присоединить бота в голосовой канал.\n```/voice join```\n"
|
"Присоединить бота в голосовой канал.\n```/voice join```\n"
|
||||||
"Заставить бота покинуть голосовой канал.\n ```/voice leave```\n"
|
"Заставить бота покинуть голосовой канал.\n ```/voice leave```\n"
|
||||||
"Прервать проигрывание, удалить историю, очередь и текущий плеер.\n ```/track stop```\n"
|
"Прервать проигрывание, удалить историю, очередь и текущий плеер.\n ```/voice stop```\n"
|
||||||
"Создать меню проигрывателя. \n```/voice menu```\n"
|
"Создать меню проигрывателя. \n```/voice menu```\n"
|
||||||
"Запустить станцию. Без уточнения станции, запускает Мою Волну.\n```/voice vibe <название станции>```"
|
"Запустить станцию. Без уточнения станции, запускает Мою Волну.\n```/voice vibe <название станции>```"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -259,10 +259,11 @@ class VoiceExtension:
|
|||||||
|
|
||||||
async def update_vibe(
|
async def update_vibe(
|
||||||
self,
|
self,
|
||||||
ctx: ApplicationContext | Interaction,
|
ctx: ApplicationContext | Interaction | RawReactionActionEvent,
|
||||||
type: str,
|
type: str,
|
||||||
id: str | int,
|
id: str | int,
|
||||||
*,
|
*,
|
||||||
|
viber_id: int | None = None,
|
||||||
update_settings: bool = False
|
update_settings: bool = False
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Update vibe state or initialize it if not `guild['vibing']` and replace queue with next tracks.
|
"""Update vibe state or initialize it if not `guild['vibing']` and replace queue with next tracks.
|
||||||
@@ -272,6 +273,7 @@ class VoiceExtension:
|
|||||||
ctx (ApplicationContext | Interaction): Context.
|
ctx (ApplicationContext | Interaction): Context.
|
||||||
type (str): Type of the item.
|
type (str): Type of the item.
|
||||||
id (str | int): ID of the item.
|
id (str | int): ID of the item.
|
||||||
|
viber_id (int | None, optional): ID of the user who started vibe. If None, uses user id in context. Defaults to None.
|
||||||
update_settings (bool, optional): Update vibe settings by sending feedack usind data from database. Defaults to False.
|
update_settings (bool, optional): Update vibe settings by sending feedack usind data from database. Defaults to False.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@@ -280,7 +282,7 @@ class VoiceExtension:
|
|||||||
logging.info(f"[VC_EXT] Updating vibe for guild {ctx.guild_id} with type '{type}' and id '{id}'")
|
logging.info(f"[VC_EXT] Updating vibe for guild {ctx.guild_id} with type '{type}' and id '{id}'")
|
||||||
|
|
||||||
gid = ctx.guild_id
|
gid = ctx.guild_id
|
||||||
uid = ctx.user_id if isinstance(ctx, discord.RawReactionActionEvent) else ctx.user.id if ctx.user else None
|
uid = viber_id if viber_id else ctx.user_id if isinstance(ctx, discord.RawReactionActionEvent) else ctx.user.id if ctx.user else None
|
||||||
|
|
||||||
if not uid or not gid:
|
if not uid or not gid:
|
||||||
logging.warning("[VC_EXT] Guild ID or User ID not found in context inside 'vibe_update'")
|
logging.warning("[VC_EXT] Guild ID or User ID not found in context inside 'vibe_update'")
|
||||||
@@ -385,8 +387,7 @@ class VoiceExtension:
|
|||||||
|
|
||||||
if check_vibe_privilage:
|
if check_vibe_privilage:
|
||||||
guild = await self.db.get_guild(ctx.guild.id, projection={'current_viber_id': 1, 'vibing': 1})
|
guild = await self.db.get_guild(ctx.guild.id, projection={'current_viber_id': 1, 'vibing': 1})
|
||||||
member = cast(discord.Member, ctx.user)
|
if guild['vibing'] and ctx.user.id != guild['current_viber_id']:
|
||||||
if guild['vibing'] and ctx.user.id != guild['current_viber_id'] and not member.guild_permissions.manage_channels:
|
|
||||||
logging.debug("[VIBE] Context user is not the current viber")
|
logging.debug("[VIBE] Context user is not the current viber")
|
||||||
await ctx.respond("❌ Вы не можете взаимодействовать с чужой волной!", delete_after=15, ephemeral=True)
|
await ctx.respond("❌ Вы не можете взаимодействовать с чужой волной!", delete_after=15, ephemeral=True)
|
||||||
return False
|
return False
|
||||||
@@ -826,23 +827,27 @@ class VoiceExtension:
|
|||||||
"""
|
"""
|
||||||
logging.info(f"[VOICE] Performing '{vote_data['action']}' action for message {ctx.message_id}")
|
logging.info(f"[VOICE] Performing '{vote_data['action']}' action for message {ctx.message_id}")
|
||||||
|
|
||||||
|
if not ctx.guild_id:
|
||||||
|
logging.warning("[VOICE] Guild not found")
|
||||||
|
return False
|
||||||
|
|
||||||
if not guild['current_menu']:
|
if not guild['current_menu']:
|
||||||
await self.send_menu_message(ctx)
|
await self.send_menu_message(ctx)
|
||||||
|
|
||||||
if vote_data['action'] in ('next', 'previous'):
|
if vote_data['action'] in ('next', 'previous'):
|
||||||
if not guild.get(f'{vote_data['action']}_tracks'):
|
if not guild.get(f'{vote_data['action']}_tracks'):
|
||||||
|
logging.info(f"[VOICE] No {vote_data['action']} tracks found for message {ctx.message_id}")
|
||||||
await channel.send(content=f"❌ Очередь пуста!", delete_after=15)
|
await channel.send(content=f"❌ Очередь пуста!", delete_after=15)
|
||||||
|
|
||||||
elif not (await self.next_track(ctx) if vote_data['action'] == 'next' else await self.previous_track(ctx)):
|
elif not (await self.next_track(ctx) if vote_data['action'] == 'next' else await self.previous_track(ctx)):
|
||||||
await channel.send(content=f"❌ Ошибка при смене трека! Попробуйте ещё раз.", delete_after=15)
|
await channel.send(content=f"❌ Ошибка при смене трека! Попробуйте ещё раз.", delete_after=15)
|
||||||
|
|
||||||
elif vote_data['action'] == 'add_track':
|
elif vote_data['action'] == 'add_track':
|
||||||
track = vote_data['vote_content']
|
if not vote_data['vote_content']:
|
||||||
if not track:
|
|
||||||
logging.info(f"[VOICE] Recieved empty vote context for message {ctx.message_id}")
|
logging.info(f"[VOICE] Recieved empty vote context for message {ctx.message_id}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
await self.db.modify_track(guild['_id'], track, 'next', 'append')
|
await self.db.modify_track(guild['_id'], vote_data['vote_content'], 'next', 'append')
|
||||||
|
|
||||||
if guild['current_track']:
|
if guild['current_track']:
|
||||||
await channel.send(content=f"✅ Трек был добавлен в очередь!", delete_after=15)
|
await channel.send(content=f"✅ Трек был добавлен в очередь!", delete_after=15)
|
||||||
@@ -851,13 +856,12 @@ class VoiceExtension:
|
|||||||
await channel.send(content=f"❌ Ошибка при воспроизведении! Попробуйте ещё раз.", delete_after=15)
|
await channel.send(content=f"❌ Ошибка при воспроизведении! Попробуйте ещё раз.", delete_after=15)
|
||||||
|
|
||||||
elif vote_data['action'] in ('add_album', 'add_artist', 'add_playlist'):
|
elif vote_data['action'] in ('add_album', 'add_artist', 'add_playlist'):
|
||||||
tracks = vote_data['vote_content']
|
if not vote_data['vote_content']:
|
||||||
if not tracks:
|
|
||||||
logging.info(f"[VOICE] Recieved empty vote context for message {ctx.message_id}")
|
logging.info(f"[VOICE] Recieved empty vote context for message {ctx.message_id}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
await self.db.update(guild['_id'], {'is_stopped': False})
|
await self.db.update(guild['_id'], {'is_stopped': False})
|
||||||
await self.db.modify_track(guild['_id'], tracks, 'next', 'extend')
|
await self.db.modify_track(guild['_id'], vote_data['vote_content'], 'next', 'extend')
|
||||||
|
|
||||||
if guild['current_track']:
|
if guild['current_track']:
|
||||||
await channel.send(content=f"✅ Контент был добавлен в очередь!", delete_after=15)
|
await channel.send(content=f"✅ Контент был добавлен в очередь!", delete_after=15)
|
||||||
@@ -866,8 +870,7 @@ class VoiceExtension:
|
|||||||
await channel.send(content=f"❌ Ошибка при воспроизведении! Попробуйте ещё раз.", delete_after=15)
|
await channel.send(content=f"❌ Ошибка при воспроизведении! Попробуйте ещё раз.", delete_after=15)
|
||||||
|
|
||||||
elif vote_data['action'] == 'play/pause':
|
elif vote_data['action'] == 'play/pause':
|
||||||
vc = await self.get_voice_client(ctx)
|
if not (vc := await self.get_voice_client(ctx)):
|
||||||
if not vc:
|
|
||||||
await channel.send(content=f"❌ Ошибка при изменении воспроизведения! Попробуйте ещё раз.", delete_after=15)
|
await channel.send(content=f"❌ Ошибка при изменении воспроизведения! Попробуйте ещё раз.", delete_after=15)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -882,8 +885,37 @@ class VoiceExtension:
|
|||||||
await self.db.update(guild['_id'], {vote_data['action']: not guild[vote_data['action']]})
|
await self.db.update(guild['_id'], {vote_data['action']: not guild[vote_data['action']]})
|
||||||
await self.update_menu_view(ctx)
|
await self.update_menu_view(ctx)
|
||||||
|
|
||||||
|
elif vote_data['action'] == 'clear_queue':
|
||||||
|
await self.db.update(ctx.guild_id, {'previous_tracks': [], 'next_tracks': []})
|
||||||
|
await channel.send("✅ Очередь и история сброшены.", delete_after=15)
|
||||||
|
|
||||||
|
elif vote_data['action'] == 'stop':
|
||||||
|
res = await self.stop_playing(ctx, full=True)
|
||||||
|
if res:
|
||||||
|
await channel.send("✅ Воспроизведение остановлено.", delete_after=15)
|
||||||
|
else:
|
||||||
|
await channel.send("❌ Произошла ошибка при остановке воспроизведения.", delete_after=15)
|
||||||
|
|
||||||
|
elif vote_data['action'] == 'vibe_station':
|
||||||
|
_type, _id, viber_id = vote_data['vote_content'] if isinstance(vote_data['vote_content'], list) else (None, None, None)
|
||||||
|
|
||||||
|
if not _type or not _id or not viber_id:
|
||||||
|
logging.warning(f"[VOICE] Recieved empty vote context for message {ctx.message_id}")
|
||||||
|
await channel.send("❌ Произошла ошибка при обновлении станции.", delete_after=15)
|
||||||
|
return False
|
||||||
|
|
||||||
|
feedback = await self.update_vibe(ctx, _type, _id, viber_id=viber_id)
|
||||||
|
|
||||||
|
if not feedback:
|
||||||
|
await channel.send("❌ Операция не удалась. Возможно, у вес нет подписки на Яндекс Музыку.", delete_after=15)
|
||||||
|
return False
|
||||||
|
|
||||||
|
next_track = await self.db.get_track(ctx.guild_id, 'next')
|
||||||
|
if next_track:
|
||||||
|
await self._play_track(ctx, next_track)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logging.warning(f"[VOICE] Unknown action '{vote_data['action']}' for message {ctx.message_id}")
|
logging.error(f"[VOICE] Unknown action '{vote_data['action']}' for message {ctx.message_id}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -260,16 +260,38 @@ class Voice(Cog, VoiceExtension):
|
|||||||
async def clear(self, ctx: discord.ApplicationContext) -> None:
|
async def clear(self, ctx: discord.ApplicationContext) -> None:
|
||||||
logging.info(f"[VOICE] Clear queue command invoked by user {ctx.author.id} in guild {ctx.guild.id}")
|
logging.info(f"[VOICE] Clear queue command invoked by user {ctx.author.id} in guild {ctx.guild.id}")
|
||||||
|
|
||||||
|
if not await self.voice_check(ctx):
|
||||||
|
return
|
||||||
|
|
||||||
member = cast(discord.Member, ctx.author)
|
member = cast(discord.Member, ctx.author)
|
||||||
channel = cast(discord.VoiceChannel, ctx.channel)
|
channel = cast(discord.VoiceChannel, ctx.channel)
|
||||||
|
|
||||||
if len(channel.members) > 2 and not member.guild_permissions.manage_channels:
|
if len(channel.members) > 2 and not member.guild_permissions.manage_channels:
|
||||||
logging.info(f"[VOICE] User {ctx.author.id} does not have permissions to execute leave command in guild {ctx.guild.id}")
|
logging.info(f"Starting vote for stopping playback in guild {ctx.guild.id}")
|
||||||
await ctx.respond("❌ У вас нет прав для выполнения этой команды.", delete_after=15, ephemeral=True)
|
|
||||||
elif await self.voice_check(ctx):
|
response_message = f"{member.mention} хочет очистить историю прослушивания и очередь треков.\n\n Выполнить действие?."
|
||||||
await self.db.update(ctx.guild.id, {'previous_tracks': [], 'next_tracks': []})
|
message = cast(discord.Interaction, await ctx.respond(response_message, delete_after=60))
|
||||||
await ctx.respond("✅ Очередь и история сброшены.", delete_after=15, ephemeral=True)
|
response = await message.original_response()
|
||||||
logging.info(f"[VOICE] Queue and history cleared in guild {ctx.guild.id}")
|
|
||||||
|
await response.add_reaction('✅')
|
||||||
|
await response.add_reaction('❌')
|
||||||
|
|
||||||
|
await self.db.update_vote(
|
||||||
|
ctx.guild_id,
|
||||||
|
response.id,
|
||||||
|
{
|
||||||
|
'positive_votes': list(),
|
||||||
|
'negative_votes': list(),
|
||||||
|
'total_members': len(channel.members),
|
||||||
|
'action': 'clear_queue',
|
||||||
|
'vote_content': None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
await self.db.update(ctx.guild.id, {'previous_tracks': [], 'next_tracks': []})
|
||||||
|
await ctx.respond("✅ Очередь и история сброшены.", delete_after=15, ephemeral=True)
|
||||||
|
logging.info(f"[VOICE] Queue and history cleared in guild {ctx.guild.id}")
|
||||||
|
|
||||||
@queue.command(description="Получить очередь треков.")
|
@queue.command(description="Получить очередь треков.")
|
||||||
async def get(self, ctx: discord.ApplicationContext) -> None:
|
async def get(self, ctx: discord.ApplicationContext) -> None:
|
||||||
@@ -289,19 +311,40 @@ class Voice(Cog, VoiceExtension):
|
|||||||
async def stop(self, ctx: discord.ApplicationContext) -> None:
|
async def stop(self, ctx: discord.ApplicationContext) -> None:
|
||||||
logging.info(f"[VOICE] Stop command invoked by user {ctx.author.id} in guild {ctx.guild.id}")
|
logging.info(f"[VOICE] Stop command invoked by user {ctx.author.id} in guild {ctx.guild.id}")
|
||||||
|
|
||||||
|
if not await self.voice_check(ctx):
|
||||||
|
return
|
||||||
|
|
||||||
member = cast(discord.Member, ctx.author)
|
member = cast(discord.Member, ctx.author)
|
||||||
channel = cast(discord.VoiceChannel, ctx.channel)
|
channel = cast(discord.VoiceChannel, ctx.channel)
|
||||||
|
|
||||||
if len(channel.members) > 2 and not member.guild_permissions.manage_channels:
|
if len(channel.members) > 2 and not member.guild_permissions.manage_channels:
|
||||||
logging.info(f"[VOICE] User {ctx.author.id} tried to stop playback in guild {ctx.guild.id} but there are other users in the channel")
|
logging.info(f"Starting vote for stopping playback in guild {ctx.guild.id}")
|
||||||
await ctx.respond("❌ Вы не можете остановить воспроизведение, пока в канале находятся другие пользователи.", delete_after=15, ephemeral=True)
|
|
||||||
|
|
||||||
elif await self.voice_check(ctx):
|
response_message = f"{member.mention} хочет полностью остановить проигрывание.\n\n Выполнить действие?."
|
||||||
res = await self.stop_playing(ctx, full=True)
|
message = cast(discord.Interaction, await ctx.respond(response_message, delete_after=60))
|
||||||
if res:
|
response = await message.original_response()
|
||||||
await ctx.respond("✅ Воспроизведение остановлено.", delete_after=15, ephemeral=True)
|
|
||||||
else:
|
await response.add_reaction('✅')
|
||||||
await ctx.respond("❌ Произошла ошибка при остановке воспроизведения.", delete_after=15, ephemeral=True)
|
await response.add_reaction('❌')
|
||||||
|
|
||||||
|
await self.db.update_vote(
|
||||||
|
ctx.guild_id,
|
||||||
|
response.id,
|
||||||
|
{
|
||||||
|
'positive_votes': list(),
|
||||||
|
'negative_votes': list(),
|
||||||
|
'total_members': len(channel.members),
|
||||||
|
'action': 'stop',
|
||||||
|
'vote_content': None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
res = await self.stop_playing(ctx, full=True)
|
||||||
|
if res:
|
||||||
|
await ctx.respond("✅ Воспроизведение остановлено.", delete_after=15, ephemeral=True)
|
||||||
|
else:
|
||||||
|
await ctx.respond("❌ Произошла ошибка при остановке воспроизведения.", delete_after=15, ephemeral=True)
|
||||||
|
|
||||||
@voice.command(name='vibe', description="Запустить Мою Волну.")
|
@voice.command(name='vibe', description="Запустить Мою Волну.")
|
||||||
@discord.option(
|
@discord.option(
|
||||||
@@ -321,7 +364,7 @@ class Voice(Cog, VoiceExtension):
|
|||||||
|
|
||||||
if guild['vibing']:
|
if guild['vibing']:
|
||||||
logging.info(f"[VOICE] Action declined: vibing is already enabled in guild {ctx.guild.id}")
|
logging.info(f"[VOICE] Action declined: vibing is already enabled in guild {ctx.guild.id}")
|
||||||
await ctx.respond("❌ Моя Волна уже включена. Используйте /track stop, чтобы остановить воспроизведение.", delete_after=15, ephemeral=True)
|
await ctx.respond("❌ Моя Волна уже включена. Используйте /voice stop, чтобы остановить воспроизведение.", delete_after=15, ephemeral=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
await ctx.defer(invisible=False)
|
await ctx.defer(invisible=False)
|
||||||
@@ -357,7 +400,42 @@ class Voice(Cog, VoiceExtension):
|
|||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
_type, _id = 'user', 'onyourwave'
|
_type, _id = 'user', 'onyourwave'
|
||||||
|
content = None
|
||||||
|
|
||||||
|
member = cast(discord.Member, ctx.author)
|
||||||
|
channel = cast(discord.VoiceChannel, ctx.channel)
|
||||||
|
|
||||||
|
if len(channel.members) > 2 and not member.guild_permissions.manage_channels:
|
||||||
|
logging.info(f"Starting vote for stopping playback in guild {ctx.guild.id}")
|
||||||
|
|
||||||
|
if _type == 'user' and _id == 'onyourwave':
|
||||||
|
station = "Моя Волна"
|
||||||
|
elif content and content.station:
|
||||||
|
station = content.station.name
|
||||||
|
else:
|
||||||
|
logging.warning(f"[VOICE] Station {name} not found")
|
||||||
|
await ctx.respond("❌ Станция не найдена.", delete_after=15, ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
response_message = f"{member.mention} хочет запустить станцию **{station}**.\n\n Выполнить действие?"
|
||||||
|
message = cast(discord.WebhookMessage, await ctx.respond(response_message, delete_after=60))
|
||||||
|
|
||||||
|
await message.add_reaction('✅')
|
||||||
|
await message.add_reaction('❌')
|
||||||
|
|
||||||
|
await self.db.update_vote(
|
||||||
|
ctx.guild_id,
|
||||||
|
message.id,
|
||||||
|
{
|
||||||
|
'positive_votes': list(),
|
||||||
|
'negative_votes': list(),
|
||||||
|
'total_members': len(channel.members),
|
||||||
|
'action': 'vibe_station',
|
||||||
|
'vote_content': [_type, _id, ctx.user.id]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
feedback = await self.update_vibe(ctx, _type, _id)
|
feedback = await self.update_vibe(ctx, _type, _id)
|
||||||
|
|
||||||
if not feedback:
|
if not feedback:
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ class MessageVotes(TypedDict):
|
|||||||
positive_votes: list[int]
|
positive_votes: list[int]
|
||||||
negative_votes: list[int]
|
negative_votes: list[int]
|
||||||
total_members: int
|
total_members: int
|
||||||
action: Literal['next', 'play/pause', 'repeat', 'shuffle', 'previous', 'add_track', 'add_album', 'add_artist', 'add_playlist']
|
action: Literal[
|
||||||
|
'next', 'play/pause', 'stop', 'repeat', 'shuffle', 'previous', 'add_track',
|
||||||
|
'add_album', 'add_artist', 'add_playlist', 'vibe_station', 'clear_queue'
|
||||||
|
]
|
||||||
vote_content: Any | None
|
vote_content: Any | None
|
||||||
|
|
||||||
class Guild(TypedDict, total=False):
|
class Guild(TypedDict, total=False):
|
||||||
|
|||||||
Reference in New Issue
Block a user