Add files via upload
This commit is contained in:
87
cogs/player.py
Normal file
87
cogs/player.py
Normal file
@@ -0,0 +1,87 @@
|
||||
import discord
|
||||
import yt_dlp
|
||||
import asyncio
|
||||
from collections import deque
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Конфиг yt-dlp
|
||||
# ─────────────────────────────────────────────
|
||||
YTDL_OPTIONS = {
|
||||
"format": "bestaudio/best",
|
||||
"noplaylist": True,
|
||||
"quiet": True,
|
||||
"no_warnings": True,
|
||||
"default_search": "ytsearch",
|
||||
"source_address": "0.0.0.0",
|
||||
}
|
||||
|
||||
FFMPEG_OPTIONS = {
|
||||
"before_options": "-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5",
|
||||
"options": "-vn -bufsize 512k",
|
||||
}
|
||||
|
||||
ytdl = yt_dlp.YoutubeDL(YTDL_OPTIONS)
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Источник аудио
|
||||
# ─────────────────────────────────────────────
|
||||
class YTDLSource(discord.PCMVolumeTransformer):
|
||||
def __init__(self, source, *, data, volume=0.5):
|
||||
super().__init__(source, volume)
|
||||
self.data = data
|
||||
self.title = data.get("title", "Неизвестно")
|
||||
self.url = data.get("webpage_url", "")
|
||||
self.duration = data.get("duration", 0)
|
||||
self.thumbnail = data.get("thumbnail", "")
|
||||
|
||||
@classmethod
|
||||
async def from_url(cls, url: str, *, loop=None):
|
||||
loop = loop or asyncio.get_event_loop()
|
||||
data = await loop.run_in_executor(
|
||||
None,
|
||||
lambda: ytdl.extract_info(url, download=False)
|
||||
)
|
||||
if "entries" in data:
|
||||
data = data["entries"][0]
|
||||
return cls(
|
||||
discord.FFmpegPCMAudio(data["url"], **FFMPEG_OPTIONS),
|
||||
data=data
|
||||
)
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Состояние плеера (на сервер)
|
||||
# ─────────────────────────────────────────────
|
||||
class GuildPlayer:
|
||||
def __init__(self):
|
||||
self.queue: deque = deque()
|
||||
self.current: YTDLSource | None = None
|
||||
self.volume: float = 0.5
|
||||
self.loop: bool = False
|
||||
|
||||
# Глобальный словарь плееров
|
||||
players: dict[int, GuildPlayer] = {}
|
||||
|
||||
def get_player(guild_id: int) -> GuildPlayer:
|
||||
if guild_id not in players:
|
||||
players[guild_id] = GuildPlayer()
|
||||
return players[guild_id]
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# Хелперы
|
||||
# ─────────────────────────────────────────────
|
||||
def fmt_duration(sec: int) -> str:
|
||||
m, s = divmod(sec, 60)
|
||||
h, m = divmod(m, 60)
|
||||
return f"{h}:{m:02d}:{s:02d}" if h else f"{m}:{s:02d}"
|
||||
|
||||
def now_playing_embed(source: YTDLSource) -> discord.Embed:
|
||||
embed = discord.Embed(
|
||||
title="🎵 Сейчас играет",
|
||||
description=f"**[{source.title}]({source.url})**",
|
||||
color=0x1DB954
|
||||
)
|
||||
if source.duration:
|
||||
embed.add_field(name="Длительность", value=fmt_duration(source.duration))
|
||||
if source.thumbnail:
|
||||
embed.set_thumbnail(url=source.thumbnail)
|
||||
return embed
|
||||
Reference in New Issue
Block a user