ŻyrarBOT
Bot muzyczny Discord z panelem webowym: kolejka odtwarzania, historia, serwerowa baza plików i sterowanie na żywo przez WebSocket.
Uruchomienie
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. |
POSTGRES_PASSWORD |
Hasło użytkownika bazy; domyślnie zyrarbot, zalecana zmiana w .env. |
POSTGRES_DB / POSTGRES_USER |
Opcjonalna nazwa bazy i użytkownika; domyślnie zyrarbot. |
Panel działa pod http://localhost:8000 podczas uruchomienia lokalnego.
Docker: development i production
Środowisko deweloperskie uruchom poleceniem:
docker compose up --build
Kod Pythona jest montowany z katalogu projektu; po zmianach zrestartuj backend
poleceniem docker compose restart discord-bot. Frontend działa w osobnym
kontenerze i przebudowuje frontend/dist w trybie watch. Python serwuje ten sam
współdzielony katalog pod http://localhost. Port PostgreSQL 5432 jest
dostępny lokalnie. Obraz dev zawiera też Ruff, a kontener frontendu instaluje
narzędzia z package-lock.json (ESLint i vue-tsc).
Sprawdzenia uruchom w kontenerze backendu, np. docker compose exec discord-bot ruff check . i docker compose exec discord-bot pytest; dla frontendu użyj
docker compose exec frontend npm run lint lub npm run typecheck.
Production uruchom z pliku compose.prod.yaml:
docker compose -f compose.prod.yaml up --build -d
W tym wariancie frontend jest budowany podczas tworzenia obrazu, a port PostgreSQL nie jest publikowany na hoście.
Konta i dostępy panelu
Panel wymaga logowania. Utwórz pierwszego administratora przez Makefile:
make create-admin USERNAME=admin
Komenda poprosi o niepuste hasło. Domyślna nazwa użytkownika to admin, jeśli nie
podasz USERNAME. Administrator ma dostęp do wszystkich
serwerów i strony /admin, gdzie może tworzyć konta użytkowników, przypisywać im
dostęp do serwerów oraz restartować bota. Zwykły użytkownik widzi wyłącznie
przypisane mu serwery. Konta i sesje są przechowywane w PostgreSQL.
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. Ustawienia, historia
i migawki kolejek przechodzą przez porty persystencji, a PostgreSQL jest obecnym
adapterem wybranym w korzeniu aplikacji. Baza działa jako usługa Compose, a jej dane
trwale przechowuje wolumen postgres_data. Przy pierwszym uruchomieniu
bot importuje istniejące pliki JSON z config/ do bazy, a pliki źródłowe zostają
na miejscu jako kopia. Starsze wspólne dane są przypisywane do pierwszego serwera,
do którego bot należy. Historia jest zapisywana w kolumnach id, title, url,
duration i is_local, wraz z guild_id oraz pozycją. Uploady pozostają w
katalogach uploads/<guild_id>/.
Migracje bazy
Przy uruchomieniu bot automatycznie stosuje oczekujące migracje PostgreSQL.
Można je też uruchomić jawnie przez make migrate. Makefile korzysta wyłącznie
z Dockera i sprawdza, czy dostępne są Docker oraz docker compose.
Zastosowane wersje i ich nazwy są zapisywane w tabeli schema_migrations.
Każda migracja jest osobną klasą z metodami apply i rollback, w osobnym
pliku w zyrarbot/storage/adapters/postgres/migrations/. Pliki należy nazywać
numerami z zerami wiodącymi, aby porządek leksykograficzny pokrywał się z kolejnością,
na przykład 0001_initial_schema.py, 0002_add_something.py. Migrację trzeba
dodać także do krotki MIGRATIONS w migrations/__init__.py. Obecna migracja
0001_initial_schema tworzy początkowy schemat.
Rollback wszystkich wersji wykonaj poleceniem:
make migration-rollback
Aby cofnąć wersje nowsze niż wskazana, ustaw TO, na przykład
make migration-rollback TO=1 pozostawi migrację w wersji 1. Przed rollbackiem
zatrzymaj bota poleceniem docker compose stop discord-bot. Rollback wykonuje migracje w odwrotnej kolejności,
usuwa ich wpisy z schema_migrations i może trwale skasować dane z cofanych tabel.
Po rollbacku uruchomienie bota ponownie zastosuje brakujące migracje.
Komendy Discorda
Wszystkie komendy działają w kontekście bieżącego serwera. Discord pokazuje wybór utworów przez autocomplete, a kanały przez natywne selektory — nie trzeba wpisywać indeksów ręcznie.
| Komenda | Działanie |
|---|---|
/player |
Publiczny panel odtwarzacza z przyciskami sterowania |
/play query |
Dodaje utwór, link lub zapytanie wyszukiwania |
/playfile filename |
Odtwarza plik z biblioteki serwera |
/files |
Otwiera listę plików z natywnym wyborem Discorda |
/upload file |
Przesyła i waliduje plik audio/wideo do biblioteki |
/deletefile filename |
Usuwa wybrany plik z biblioteki |
/replay track_id |
Ponownie odtwarza utwór z historii |
/queue |
Pokazuje kolejkę w embedzie |
/history |
Pokazuje historię odtwarzania |
/restorequeue |
Przywraca ostatnią zapisaną kolejkę |
/jump track_id |
Rozpoczyna wybrany utwór z kolejki |
/remove track_id |
Usuwa wybrany utwór z kolejki |
/move track_id before_id |
Przenosi utwór przed wybrany utwór docelowy |
/trackplays track_id count |
Ustawia liczbę odtworzeń utworu |
/pause, /resume |
Wstrzymuje lub wznawia odtwarzanie |
/seek seconds |
Przewija bieżący utwór do wskazanej sekundy |
/skip |
Pomija bieżący utwór |
/stop |
Zatrzymuje odtwarzanie i czyści kolejkę |
/volume volume |
Ustawia głośność w zakresie 1–100 |
/nowplaying |
Pokazuje bieżący utwór |
/loop |
Przełącza tryb zapętlania |
/loopplaylist |
Włącza lub wyłącza zapętlanie kolejki |
/defaultplays count |
Ustawia domyślną liczbę odtworzeń dla nowych utworów |
/connect channel |
Łączy bota z wybranym kanałem głosowym |
/notificationchannel channel |
Ustawia kanał powiadomień |
/leave |
Rozłącza bota z kanału głosowego |
Testy
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/
│ ├── ports/ GuildConfigRepository, HistoryRepository,
│ │ QueueRepository, UploadsRepository, Persistence
│ ├── adapters/
│ │ ├── postgres/ adaptery PostgreSQL oraz migrations/ z runnerem
│ │ ├── filesystem/ Adapter plików uploadu
│ │ └── json/ Adapter plikowego magazynu JSON
│ └── 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
├── discord_theme.py wspólny styl embedów Discorda
├── 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
MusicPlayerjest 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.statei funkcje zapi/dependencies.py. Nie ma globalnych singletonów.