162 lines
8.0 KiB
Markdown
162 lines
8.0 KiB
Markdown
# Ż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. |
|
||
| `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. 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. 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:
|
||
|
||
```bash
|
||
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
|
||
|
||
```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/
|
||
│ ├── 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
|
||
|
||
- **`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.
|