YTDLSource powstaje z domyślną głośnością 0.5, a ustawienie głośności
zmieniało tylko źródło aktualnie odtwarzane. Nowy utwór startował więc
na 50%, podczas gdy panel i /api/status raportowały stan serwera - domyślnie
100%. Zmiana głośności "znikała" po przejściu do kolejnego utworu.
Teraz play_next ustawia na źródle głośność ze stanu serwera, zanim
przekaże je do odtworzenia.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Application składa wszystkie zależności w jednym miejscu i prowadzi bota
równolegle z serwerem web. Panel przeżywa awarię logowania do Discorda,
tak jak dotąd, ale komunikat idzie przez logging zamiast print.
- zyrarbot/__main__.py pozwala uruchomić pakiet przez python -m zyrarbot
i konfiguruje logowanie; main.py zostaje cienkim punktem wejścia.
- Usunięte bot.py, web.py i ytdl.py - ich zawartość rozeszła się po
pakiecie. Zniknął przy tym globalny obiekt bota tworzony przy imporcie
modułu, który wymuszał kolejność importów między bot.py a web.py.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
22 endpointy z jednego pliku rozdzielone na routery według obszaru:
status, playback, queue, voice, uploads, settings i websocket.
- Powtarzany w każdym endpoincie blok "pobierz cog, sprawdź czy istnieje,
ustal aktywny serwer, w razie czego rzuć 400" zastąpiony zależnościami
z dependencies.py. Zniknęło 22-krotne bot.get_cog("MusicBot").
- Zależności wędrują przez app.state zamiast importu globalnego obiektu
bota, więc warstwa web nie ma już zależności cyklicznej z modułem bota.
- create_app składa aplikację i montuje routery.
- Wycofane @app.on_event("startup") zastąpione lifespanem, który dodatkowo
sprząta po sobie: odpina hook i zatrzymuje pętlę rozgłaszania.
Kontrakt HTTP pozostaje bez zmian - te same ścieżki, metody, kody błędów
i kształt odpowiedzi.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- ConnectionManager - rejestr aktywnych połączeń (bez zmian poza typami).
- StatusService - budowanie obrazu stanu bota. Endpoint get_status miał
126 linii i składał odpowiedź w dwóch wariantach; teraz jest to zestaw
metod budujących poszczególne fragmenty payloadu.
- StatusBroadcaster - rozgłaszanie na żądanie oraz pętla cykliczna, wraz
z zatrzymywaniem zadania przy wyłączaniu aplikacji. Wcześniej zadanie
było tworzone w on_event("startup") i nigdy nie anulowane.
Wariant odpowiedzi dla bota bez serwerów zwraca teraz komplet kluczy
(dochodzi queue_index: -1), więc panel dostaje zawsze ten sam kształt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Jedenaście klas pydantic zadeklarowanych jednym blokiem na górze web.py
rozdzielone na pliki zgodnie z zasadą jedna klasa = jeden plik. Każdy
model dostaje docstring mówiący, do czego służy - z samych nazw pól
(np. channel_id akceptujące pusty string jako reset) nie wynikało to
w oczywisty sposób.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- ZyrarBot buduje intencje, rejestruje cog i synchronizuje drzewo komend.
- MusicCog zawiera już wyłącznie obsługę komend ukośnikowych: walidację
argumentów, komunikaty dla użytkownika i wywołania MusicPlayer. Cała
praca ze stanem zniknęła z tego pliku.
- GuildResolver ustala kontekst serwera dla panelu webowego, który nie ma
interakcji Discorda - wcześniej robiła to funkcja get_active_guild
w web.py, sięgająca po globalny obiekt bota.
- Powtarzana w czterech komendach odpowiedź "dodano do kolejki" albo
"teraz odtwarzane" zebrana w jednym helperze.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Logika odtwarzania wyprowadzona z coga Discorda do osobnej klasy. Dotąd
kolejkę modyfikowały dwie niezależne ścieżki: metody MusicBot oraz
endpointy w web.py sięgające po music_cog.queues[guild_id] i ustawiające
music_cog.jump_flag wprost. Teraz obie warstwy wołają MusicPlayer.
Przeniesione bez zmiany zachowania: enqueue, play_next wraz z arytmetyką
indeksu i limitem odtworzeń, remove, reorder, jump, sterowanie głośnością
oraz hook on_state_change rozgłaszający stan po WebSockecie.
Wybór kolejnego indeksu wydzielony do _next_index, dzięki czemu reguły
trybów zapętlania i przeskoku dają się czytać bez śledzenia całej metody.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- GuildMusicState zbiera stan jednego serwera w jedną strukturę. Dotąd
było to dziewięć równoległych słowników indeksowanych guild_id
(queues, currents, volumes, loop_currents, loop_playlists, last_channels,
history, queue_indices, jump_flag), co wymagało pamiętania, że przy
każdej zmianie trzeba ruszyć kilka z nich naraz.
- LoopMode zastępuje parę booleanów loop_current/loop_playlist, których
kombinacja "oba włączone" nie miała sensu, a mimo to była osiągalna.
Wartości enuma (off/playlist/single) odpowiadają kontraktowi API panelu.
- TrackEmbedFactory zbiera budowanie osadzeń Discorda, powielone dotąd
w enqueue_track i play_next.
- NotificationChannelResolver opisuje kolejność szukania kanału logów:
zapamiętany -> z konfiguracji -> pierwszy zapisywalny na serwerze.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ytdl.py rozbity na cztery pliki o rozłącznych rolach:
- YtdlOptions opcje yt-dlp i FFmpeg, wcześniej moduły-globalne
- MediaProbe odczyt długości pliku przez ffprobe
- YTDLSource samo źródło audio - dane utworu i zliczanie odtworzonego
czasu; dochodzą właściwości is_local, filepath, display_url
i has_web_link, które zastępują powtarzane w kilku miejscach
data.get("webpage_url") or url
- TrackFactory budowanie źródeł z zapytania, adresu lub pliku
Rozdzielenie źródła od sposobu jego tworzenia usuwa globalną instancję
YoutubeDL i pozwala podmienić fabrykę w testach. Metoda recreate zbiera
w jednym miejscu odtwarzanie utworu od nowa z zachowaniem jego tożsamości
i pozostałej liczby odtworzeń.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dostęp do danych trwałych schodzi za trzy repozytoria, zamiast być
rozsmarowany po metodach coga i endpointach:
- GuildConfigRepository - kanały powiadomień per serwer i domyślna liczba
odtworzeń.
- HistoryRepository - historia per serwer z buforem w pamięci i limitem
wpisów. Zasada odsiewania duplikatów (zgodny tytuł albo adres) siedzi
teraz w HistoryEntry.is_same_track_as zamiast w warunku wbudowanym
w listę składaną.
- UploadsRepository - katalog uploadów. Każda nazwa przechodzi przez
os.path.basename w jednym miejscu, co zamyka temat ścieżek względnych
przychodzących z API.
Wpisy historii i pliki opisują struktury HistoryEntry oraz UploadFileInfo
zamiast luźnych słowników z kluczami sprawdzanymi przez .get().
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Początek pakietu zyrarbot, budowanego wedle zasady jedna klasa = jeden plik.
- Settings zbiera konfigurację ze zmiennych środowiskowych oraz ścieżki
i limity, które dotąd były literałami rozsianymi po bot.py i web.py
("config/config.json", "uploads", zakres 1-999, domyślne 5 odtworzeń).
- JsonFileStore zastępuje sześć niemal identycznych bloków open/json.load
z ręcznym try/except. Brakujący lub uszkodzony plik daje pusty słownik
zamiast wyjątku, a zapis sam tworzy katalog.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replaced old commands-based approach with Discord app commands for slash command functionality. Simplified error handling, removed redundant code, and improved voice channel management. Updated bot's initialization and ensured proper command syncing for global or guild-specific contexts.
Introduce Dockerfile for containerizing the Discord bot, including required dependencies for audio handling. Add compose.yaml for simplified service orchestration. Update .gitignore to exclude compiled files and environment-specific artifacts.
Add music bot with YouTube integration and basic commands
Implemented a Discord bot with commands for playing, pausing, skipping, and managing a music queue utilizing yt_dlp and FFmpeg. Includes opus library loading fallback logic and gitignore entry for environment files.