from __future__ import annotations import discord from fastapi import APIRouter, Depends, HTTPException, Request from zyrarbot.music.music_player import MusicPlayer from zyrarbot.music.notification_channel_resolver import NotificationChannelResolver from zyrarbot.storage.ports.guild_config import GuildConfigRepository from zyrarbot.ui.api.dependencies import ( get_active_guild, get_broadcaster, get_config, get_guilds, get_player, ) from zyrarbot.ui.api.requests.connect_request import ConnectRequest from zyrarbot.ui.api.requests.notification_channel_request import NotificationChannelRequest from zyrarbot.ui.api.status_broadcaster import StatusBroadcaster from zyrarbot.ui.api.auth import current_user from zyrarbot.ui.bot.guild_resolver import GuildResolver router = APIRouter(prefix="/api", tags=["voice"]) @router.post("/notification_channel") async def set_notification_channel( request: NotificationChannelRequest, guild: discord.Guild = Depends(get_active_guild), guilds: GuildResolver = Depends(get_guilds), player: MusicPlayer = Depends(get_player), config: GuildConfigRepository = Depends(get_config), broadcaster: StatusBroadcaster = Depends(get_broadcaster), ) -> dict[str, str]: try: channel_id = int(request.channel_id) except ValueError as error: raise HTTPException(status_code=400, detail="Invalid text channel ID") from error channel = guilds.channel(channel_id) if not isinstance(channel, discord.TextChannel) or channel.guild.id != guild.id: raise HTTPException(status_code=404, detail="Text channel not found on this server") if channel not in NotificationChannelResolver.writable_channels(guild): raise HTTPException(status_code=403, detail="Bot cannot send messages to this channel") player.set_notification_channel(guild.id, channel) config.set_notification_channel_id(guild.id, channel.id) await broadcaster.broadcast() return {"status": "success", "channel_id": str(channel.id)} @router.post("/connect") async def connect( request: ConnectRequest, http_request: Request, user: dict = Depends(current_user), guilds: GuildResolver = Depends(get_guilds), player: MusicPlayer = Depends(get_player), broadcaster: StatusBroadcaster = Depends(get_broadcaster), ) -> dict[str, str]: try: channel_id = int(request.channel_id) except ValueError as error: raise HTTPException(status_code=400, detail="Invalid channel ID") from error channel = guilds.channel(channel_id) if not isinstance(channel, discord.VoiceChannel): raise HTTPException(status_code=404, detail="Voice channel not found") allowed = http_request.app.state.auth.guild_ids( user, [item.id for item in guilds.guilds()] ) if channel.guild.id not in allowed: raise HTTPException(status_code=403, detail="Brak dostępu do tego serwera") if channel.guild.me and not channel.permissions_for(channel.guild.me).connect: raise HTTPException( status_code=403, detail=f"Bot nie ma uprawnień do połączenia z kanałem {channel.name}", ) guild_id = channel.guild.id # Rozłączamy wyłącznie na tym samym serwerze - inne serwery grają dalej. existing = guilds.voice_client(guild_id) if existing: await existing.disconnect() await channel.connect() if not player.notification_channel(guild_id): player.set_notification_channel( guild_id, NotificationChannelResolver.first_writable(channel.guild) ) await broadcaster.broadcast() return {"status": "connected", "channel": channel.name} @router.post("/disconnect") async def disconnect( guild: discord.Guild = Depends(get_active_guild), player: MusicPlayer = Depends(get_player), broadcaster: StatusBroadcaster = Depends(get_broadcaster), ) -> dict[str, str]: voice_client = player.voice_client(guild.id) if not voice_client: raise HTTPException(status_code=400, detail="Bot not connected to voice on this server") player.save_queue(guild.id) await voice_client.disconnect() player.clear(guild.id) await broadcaster.broadcast() return {"status": "disconnected"}