167 lines
8.2 KiB
Python
167 lines
8.2 KiB
Python
import discord
|
||
from discord.ext import commands
|
||
from discord import app_commands
|
||
import asyncio
|
||
|
||
from cogs.player import (
|
||
YTDLSource, get_player,
|
||
now_playing_embed, fmt_duration
|
||
)
|
||
|
||
class Music(commands.Cog):
|
||
def __init__(self, bot: commands.Bot):
|
||
self.bot = bot
|
||
|
||
# ── Внутренний метод: следующий трек ──────
|
||
async def play_next(self, guild: discord.Guild, channel: discord.TextChannel):
|
||
player = get_player(guild.id)
|
||
vc: discord.VoiceClient = guild.voice_client
|
||
|
||
if not vc:
|
||
return
|
||
|
||
# Повтор текущего трека
|
||
if player.loop and player.current:
|
||
try:
|
||
source = await YTDLSource.from_url(player.current.url, loop=self.bot.loop)
|
||
source.volume = player.volume
|
||
player.current = source
|
||
vc.play(source, after=lambda e: asyncio.run_coroutine_threadsafe(
|
||
self.play_next(guild, channel), self.bot.loop))
|
||
await channel.send(embed=now_playing_embed(source))
|
||
except Exception as e:
|
||
await channel.send(f"❌ Ошибка повтора: {e}")
|
||
return
|
||
|
||
if player.queue:
|
||
url = player.queue.popleft()
|
||
try:
|
||
source = await YTDLSource.from_url(url, loop=self.bot.loop)
|
||
except Exception as e:
|
||
await channel.send(f"❌ Ошибка воспроизведения: {e}")
|
||
return
|
||
source.volume = player.volume
|
||
player.current = source
|
||
vc.play(source, after=lambda e: asyncio.run_coroutine_threadsafe(
|
||
self.play_next(guild, channel), self.bot.loop))
|
||
await channel.send(embed=now_playing_embed(source))
|
||
else:
|
||
player.current = None
|
||
await channel.send("✅ Очередь закончилась.")
|
||
|
||
# ── /play ─────────────────────────────────
|
||
@app_commands.command(name="play", description="Воспроизвести трек по названию или ссылке")
|
||
@app_commands.describe(query="Название песни или YouTube ссылка")
|
||
async def play(self, interaction: discord.Interaction, query: str):
|
||
await interaction.response.defer()
|
||
|
||
if not interaction.user.voice:
|
||
return await interaction.followup.send("❌ Сначала зайди в голосовой канал!")
|
||
|
||
vc: discord.VoiceClient = interaction.guild.voice_client
|
||
if not vc:
|
||
vc = await interaction.user.voice.channel.connect()
|
||
elif interaction.user.voice.channel != vc.channel:
|
||
await vc.move_to(interaction.user.voice.channel)
|
||
|
||
player = get_player(interaction.guild.id)
|
||
|
||
try:
|
||
source = await YTDLSource.from_url(query, loop=self.bot.loop)
|
||
except Exception as e:
|
||
return await interaction.followup.send(f"❌ Не удалось найти трек: {e}")
|
||
|
||
source.volume = player.volume
|
||
|
||
if vc.is_playing() or vc.is_paused():
|
||
player.queue.append(source.url)
|
||
embed = discord.Embed(
|
||
title="📥 Добавлено в очередь",
|
||
description=f"**{source.title}**",
|
||
color=0x5865F2
|
||
)
|
||
embed.add_field(name="Позиция", value=str(len(player.queue)))
|
||
return await interaction.followup.send(embed=embed)
|
||
|
||
player.current = source
|
||
vc.play(source, after=lambda e: asyncio.run_coroutine_threadsafe(
|
||
self.play_next(interaction.guild, interaction.channel), self.bot.loop))
|
||
await interaction.followup.send(embed=now_playing_embed(source))
|
||
|
||
# ── /skip ─────────────────────────────────
|
||
@app_commands.command(name="skip", description="Пропустить текущий трек")
|
||
async def skip(self, interaction: discord.Interaction):
|
||
vc = interaction.guild.voice_client
|
||
if vc and vc.is_playing():
|
||
vc.stop()
|
||
await interaction.response.send_message("⏭️ Трек пропущен.")
|
||
else:
|
||
await interaction.response.send_message("❌ Ничего не играет.")
|
||
|
||
# ── /pause ────────────────────────────────
|
||
@app_commands.command(name="pause", description="Пауза / продолжить")
|
||
async def pause(self, interaction: discord.Interaction):
|
||
vc = interaction.guild.voice_client
|
||
if vc and vc.is_playing():
|
||
vc.pause()
|
||
await interaction.response.send_message("⏸️ Пауза.")
|
||
elif vc and vc.is_paused():
|
||
vc.resume()
|
||
await interaction.response.send_message("▶️ Продолжаю.")
|
||
else:
|
||
await interaction.response.send_message("❌ Ничего не играет.")
|
||
|
||
# ── /stop ─────────────────────────────────
|
||
@app_commands.command(name="stop", description="Остановить музыку и очистить очередь")
|
||
async def stop(self, interaction: discord.Interaction):
|
||
player = get_player(interaction.guild.id)
|
||
player.queue.clear()
|
||
player.current = None
|
||
vc = interaction.guild.voice_client
|
||
if vc:
|
||
vc.stop()
|
||
await vc.disconnect()
|
||
await interaction.response.send_message("⏹️ Остановлено, очередь очищена.")
|
||
|
||
# ── /loop ─────────────────────────────────
|
||
@app_commands.command(name="loop", description="Включить/выключить повтор трека")
|
||
async def loop(self, interaction: discord.Interaction):
|
||
player = get_player(interaction.guild.id)
|
||
player.loop = not player.loop
|
||
status = "включён 🔁" if player.loop else "выключен ➡️"
|
||
await interaction.response.send_message(f"Повтор {status}")
|
||
|
||
# ── /nowplaying ───────────────────────────
|
||
@app_commands.command(name="nowplaying", description="Текущий трек")
|
||
async def nowplaying(self, interaction: discord.Interaction):
|
||
player = get_player(interaction.guild.id)
|
||
if player.current:
|
||
await interaction.response.send_message(embed=now_playing_embed(player.current))
|
||
else:
|
||
await interaction.response.send_message("❌ Ничего не играет.")
|
||
|
||
# ── /volume ───────────────────────────────
|
||
@app_commands.command(name="volume", description="Громкость от 1 до 100")
|
||
@app_commands.describe(level="Уровень громкости (1–100)")
|
||
async def volume(self, interaction: discord.Interaction, level: int):
|
||
if not 1 <= level <= 100:
|
||
return await interaction.response.send_message("❌ Укажи значение от 1 до 100.")
|
||
player = get_player(interaction.guild.id)
|
||
player.volume = level / 100
|
||
vc = interaction.guild.voice_client
|
||
if vc and vc.source:
|
||
vc.source.volume = player.volume
|
||
await interaction.response.send_message(f"🔊 Громкость: **{level}%**")
|
||
|
||
# ── /leave ────────────────────────────────
|
||
@app_commands.command(name="leave", description="Выгнать бота из канала")
|
||
async def leave(self, interaction: discord.Interaction):
|
||
vc = interaction.guild.voice_client
|
||
if vc:
|
||
await vc.disconnect()
|
||
await interaction.response.send_message("👋 Отключился.")
|
||
else:
|
||
await interaction.response.send_message("❌ Я не в канале.")
|
||
|
||
async def setup(bot: commands.Bot):
|
||
await bot.add_cog(Music(bot)) |