# ŻyrarBOT Bot muzyczny Discord z panelem webowym: kolejka odtwarzania, historia, serwerowa baza plików i sterowanie na żywo przez WebSocket. ## Uruchomienie ```bash pip install -r requirements.txt python main.py # albo: python -m zyrarbot ``` Wymagane zmienne środowiskowe (plik `.env`): | Zmienna | Opis | | --------------- | ----------------------------------------------------------- | | `DISCORD_TOKEN` | Token bota Discord. | | `GUILD_ID` | Opcjonalnie - synchronizuje komendy tylko z jednym serwerem. | Panel działa pod `http://localhost:8000` podczas uruchomienia lokalnego. W Dockerze jest dostępny pod `http://localhost` po wykonaniu `docker compose up --build`. Panel obsługuje wiele serwerów Discorda. Wybór serwera w nagłówku przełącza jego osobną kolejkę, historię, bazę plików i ustawienia odtwarzania. Istniejące dane ze starego, wspólnego formatu są przypisywane do pierwszego użytego serwera. Historia jest zapisywana w osobnych plikach `config/history/.json`, a uploady w katalogach `uploads//`. ## Testy ```bash python -m unittest discover -s tests -t . ``` ## Struktura pakietu Każda klasa mieszka w osobnym pliku, a pliki są pogrupowane w przestrzenie nazw odpowiadające warstwom aplikacji: ``` zyrarbot/ ├── settings.py Settings - konfiguracja ze zmiennych środowiskowych ├── application.py Application - korzeń kompozycji, spina bota i API ├── storage/ Warstwa trwałości (pliki JSON, katalog uploadów) │ ├── json_file_store.py JsonFileStore │ ├── guild_config_repository.py GuildConfigRepository │ ├── history_repository.py HistoryRepository │ ├── uploads_repository.py UploadsRepository │ └── upload_file_info.py UploadFileInfo ├── audio/ Pozyskiwanie dźwięku │ ├── ytdl_options.py YtdlOptions │ ├── ytdl_source.py YTDLSource │ ├── media_probe.py MediaProbe │ └── track_factory.py TrackFactory ├── music/ Domena odtwarzania │ ├── loop_mode.py LoopMode │ ├── history_entry.py HistoryEntry │ ├── guild_music_state.py GuildMusicState │ ├── track_embed_factory.py TrackEmbedFactory │ ├── notification_channel_resolver.py NotificationChannelResolver │ └── music_player.py MusicPlayer └── ui/ Warstwa interfejsów użytkownika ├── api/ API panelu (FastAPI) │ ├── factory.py mount_api - konfiguracja i routery API │ ├── connection_manager.py ConnectionManager │ ├── status_service.py StatusService │ ├── status_broadcaster.py StatusBroadcaster │ ├── dependencies.py wstrzykiwanie zależności z app.state │ ├── requests/ modele żądań - jeden na plik │ └── routers/ trasy pogrupowane tematycznie └── bot/ Warstwa Discorda ├── client.py MusicBot ├── guild_resolver.py GuildResolver └── cogs/ komendy i listenery Discorda ├── common.py wspólne zależności i helpery ├── playback_cog.py PlaybackCog ├── queue_cog.py QueueCog ├── control_cog.py ControlCog ├── voice_cog.py VoiceCog └── settings_cog.py SettingsCog ``` ### Zasady - **`MusicPlayer` jest jedynym właścicielem stanu odtwarzania.** Zarówno komendy Discorda, jak i endpointy panelu operują wyłącznie przez niego - nie ma już dwóch niezależnych ścieżek modyfikujących kolejkę. - **Kolejka jest nieusuwalna, pozycję śledzi indeks** (`GuildMusicState.index`), dzięki czemu działa przeskakiwanie i przewijanie w tył. - **Zależności wędrują przez konstruktory**, a w API przez `app.state` i funkcje z `api/dependencies.py`. Nie ma globalnych singletonów.