- 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>
README opisuje pracę lokalną (npm run dev z proxy na backend), budowanie,
uruchomienie kontenera oraz strukturę katalogu src z rolą każdego pliku.
Spisane też zasady, które utrzymują panel spójnym: stan płynie z serwera,
zero innerHTML, ikony jako komponenty zamiast skryptu z CDN.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ładuje artefakt z dist/ w jsdom, podstawiając atrapy WebSocketu i fetcha,
a następnie sprawdza dwie rzeczy naraz:
- czy dane z serwera faktycznie renderują się w interfejsie (aktualny utwór,
kolejka, historia, baza plików, głośność, tryb zapętlania, odmiana
liczebników, formatowanie czasu)
- czy kliknięcia trafiają we właściwe endpointy - każdy przycisk sterujący
porównywany jest z oczekiwaną parą metoda + ścieżka
Razem 31 sprawdzeń, uruchamiane przez npm run smoke po npm run build.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Rozdzielenie na dwie niezależne usługi:
- frontend/Dockerfile buduje panel w etapie node:22-alpine, a artefakt
serwuje nginx:1.27-alpine. Obraz nie zawiera Node'a ani źródeł.
- frontend/nginx.conf serwuje aplikację jednostronicową (nieznane ścieżki
wracają jako index.html), cache'uje /assets z sumą kontrolną w nazwie,
a /api i /ws przekazuje do usługi discord-bot. Przeglądarka widzi jedno
źródło, więc backend nie potrzebuje CORS-u.
Adres backendu siedzi w zmiennej nginxa, więc nazwa jest rozwiązywana
przy żądaniu i panel wstaje niezależnie od kolejności startu kontenerów.
- Proxy nie limituje rozmiaru ciała żądania i nie buforuje go, żeby
wysyłka dużych plików wideo/audio przechodziła bez zmian w backendzie.
Timeouty podniesione, bo panel trzyma WebSocket otwarty na stałe.
- Root Dockerfile wraca do samego Pythona i wystawia port 8000.
- compose.yaml uruchamia obie usługi we wspólnej sieci: panel na :80,
API na :8000 (wystawione do diagnostyki).
- Katalog static/ znika z repozytorium - nie ma już czego serwować.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Panel działa w osobnym kontenerze, więc serwis Pythona przestaje serwować
pliki statyczne:
- usunięty mount StaticFiles na "/" wraz z importem
- tytuł aplikacji zmieniony na "ŻyrarBOT API"
- GET / zwraca opis usługi zamiast panelu, żeby wejście pod adres backendu
nie kończyło się nic niemówiącym 404
- GET /api/health informuje, czy bot zdążył połączyć się z Discordem;
przydaje się jako healthcheck kontenera i przy diagnozie proxy
Pozostałe endpointy oraz WebSocket pozostają bez zmian.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
static/app.js (1196 linii imperatywnego JS operującego na getElementById)
oraz static/index.html zastąpione w całości aplikacją z frontend/.
Arkusz stylów został wcześniej przeniesiony, nie usuwamy go ponownie.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Widok rozbity na komponenty odpowiadające kafelkom pulpitu:
- AppHeader, VoiceChannelPanel, PlayerPanel, AddTrackPanel
- UploadsPanel wraz z UploadedFileRow współdzielonym z oknem modalnym
- QueuePanel i QueueItem - przeciąganie, zmiana kolejności, limit odtworzeń
- HistoryPanel, ModalShell, SettingsModal, UploadsLibraryModal, ToastHost
Arkusz stylów przeniesiony ze static/style.css bez zmian w wyglądzie.
Style, które app.js wstrzykiwał inline przy budowaniu HTML-a, przeniesione
do klas współdzielonych i bloków scoped w komponentach.
Poprawki bezpieczeństwa wynikające z przepisania:
- Tytuły utworów i nazwy plików nie trafiają już do innerHTML. Poprzednia
wersja składała wiersze kolejki, historii i listy plików ze stringów,
więc tytuł zawierający znaczniki HTML był wstawiany do DOM bez escapowania.
- Nazwy plików nie są już wklejane do atrybutów onclick z ręcznym
escapowaniem apostrofu, które i tak nie obejmowało cudzysłowu. Zdarzenia
podpina Vue, bez generowania kodu w stringach.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Logika, która w app.js żyła w zmiennych globalnych, trafia do czterech
composables o wyraźnym zakresie odpowiedzialności:
- useBotStatus jedno połączenie WebSocket na aplikację, z licznikiem
subskrybentów i ponawianiem po zerwaniu. Flaga paused
wstrzymuje aktualizacje na czas przeciągania utworów.
- useToasts kolejka powiadomień wraz z helperem run(), który
opakowuje wywołanie API w parę komunikatów sukces/błąd.
- useTrackProgress płynny pasek postępu - między pakietami z serwera czas
dopisujemy lokalnie, a każdy pakiet resynchronizuje licznik.
- useUploads serwerowa baza plików, współdzielona przez kafelek na
pulpicie i okno z pełną listą.
Dochodzi też utils/plural.ts z polską odmianą liczebników, zamiast
powtarzanego w kilku miejscach warunku count < 5.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- types/status.ts spisuje kształt odpowiedzi /api/status oraz pakietów
rozgłaszanych po WebSockecie. Dotąd struktura tych danych istniała
wyłącznie w głowie autora i w rozsianych po kodzie odwołaniach.
- api/client.ts zbiera wszystkie adresy endpointów w jednym miejscu i
ujednolica obsługę błędów: pole "detail" z odpowiedzi FastAPI trafia do
wyjątku ApiError, więc warstwa widoku dostaje gotowy komunikat.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Panel przestaje być zestawem plików statycznych serwowanych przez backend
i staje się osobnym projektem w katalogu frontend/.
- Vue 3 z Composition API jako framework - szablony komponentów są bliskie
dotychczasowemu HTML-owi, więc migracja nie wymaga przepisywania widoków
na inny model mentalny.
- TypeScript w trybie strict; kontrakt danych z API będzie opisany typami.
- Vite jako bundler, z aliasem @ na src/ i budowaniem do dist/.
- Serwer deweloperski przekierowuje /api i /ws na backend; adres można
nadpisać zmienną VITE_BACKEND_URL.
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.