From f6a371b9fc2e039cd191f8056fef1cbe8f0f5b91 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 9 Jun 2026 17:07:58 +0000 Subject: [PATCH] docs: add Polish project documentation for school submission https://claude.ai/code/session_01SbQjQEK1pbi3XkF48We2zG --- dokumentacja_FFQueue_konrad_12.md | 112 ++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 dokumentacja_FFQueue_konrad_12.md diff --git a/dokumentacja_FFQueue_konrad_12.md b/dokumentacja_FFQueue_konrad_12.md new file mode 100644 index 0000000..24a273c --- /dev/null +++ b/dokumentacja_FFQueue_konrad_12.md @@ -0,0 +1,112 @@ +# Dokumentacja projektu FFQueue + +**Autor:** Konrad +**Data:** 2026-06-09 + +--- + +## 1. Nazwa i opis projektu + +**FFQueue** to desktopowa aplikacja dla systemu Windows służąca do seryjnego konwertowania plików wideo do formatu HEVC (H.265) przy użyciu akceleracji sprzętowej karty graficznej NVIDIA. Nazwa pochodzi od połączenia nazwy narzędzia FFmpeg oraz angielskiego słowa "queue" (kolejka). + +Problem, który projekt rozwiązuje, jest praktyczny: mam duże kolekcje plików wideo w starszych formatach (np. H.264), które zajmują dużo miejsca na dysku. Ręczne konwertowanie każdego pliku z osobna jest żmudne i wymaga ciągłego nadzoru. FFQueue automatyzuje ten proces, przetwarzając pliki jeden po drugim bez ingerencji użytkownika, z możliwością dodawania nowych plików do kolejki w dowolnym momencie przez przeglądarkę lub inny komputer przez sieć. + +Aplikacja działa w tle, wyświetla postęp w interfejsie graficznym i udostępnia REST API, dzięki któremu można nią sterować zdalnie przez Tailscale (sieć VPN). W praktyce znaczy to, że mogę uruchomić kolejkę wieczorem i kontrolować jej stan z telefonu przez przeglądarkę. + +--- + +## 2. Co zrobiłem + +Zaimplementowałem kompletną aplikację desktopową składającą się z czterech niezależnych warstw działających równolegle w osobnych wątkach. + +**Warstwa kolejki** odpowiada za przechowywanie listy plików do przetworzenia. Kolejka jest utrwalana w pliku JSON po każdej zmianie, dzięki czemu przeżywa restarty programu. Przy każdym uruchomieniu aplikacja sprawdza, czy jakiś plik nie utknął w stanie "encoding" (co mogło zdarzyć się przy awarii) i automatycznie resetuje go do "pending". + +**Warstwa enkodera** to właściwy silnik aplikacji. Dla każdego pliku z kolejki najpierw sprawdzam przy pomocy FFprobe, czy plik nie jest już w formacie HEVC (wtedy nie ma sensu go ponownie kodować). Następnie analizuję ścieżki audio pod kątem ciszy, przeprowadzam kodowanie przez FFmpeg i na bieżąco parsują postęp, żeby można było wyświetlać procent ukończenia i szacowany czas zakończenia. + +**Warstwa API** to serwer REST napisany w FastAPI. Udostępnia endpointy do zarządzania kolejką, monitorowania stanu enkodera i pobierania logów. Każde żądanie musi zawierać klucz API w nagłówku HTTP. + +**Warstwa GUI** to dwuzakładkowy interfejs w Tkinter. Pierwsza zakładka pokazuje aktualną kolejkę i pozwala dodawać pliki. Druga zakładka wyświetla historię ukończonych i nieudanych enkodowań ze statystykami: rozmiar wejściowy i wyjściowy, procent zaoszczędzonego miejsca, czas kodowania i użyty koder. + +Zaimplementowałem też automatyczny wybór między koderem sprzętowym NVENC a programowym libx265, jeśli karta graficzna nie obsługuje NVENC lub go nie ma. + +--- + +## 3. Technologie i narzędzia + +| Technologia | Zastosowanie | +|---|---| +| Python 3.11 | Główny język programowania | +| FastAPI | Framework REST API serwujący endpointy do zdalnego sterowania | +| Uvicorn | Serwer ASGI uruchamiający FastAPI w osobnym wątku | +| Tkinter | Biblioteka do interfejsu graficznego (wbudowana w Python) | +| FFmpeg | Zewnętrzne narzędzie CLI do kodowania wideo | +| FFprobe | Narzędzie do analizy metadanych plików multimedialnych | +| NVIDIA NVENC | Sprzętowy koder HEVC w kartach graficznych NVIDIA | +| libx265 | Programowy koder HEVC jako fallback gdy GPU jest niedostępne | +| threading | Moduł do równoległego uruchamiania wątków (GUI, API, enkoder) | +| JSON | Format persystencji kolejki i konfiguracji | +| CSV | Format logowania statystyk enkodowań | +| Tailscale | Sieć VPN umożliwiająca zdalny dostęp do API | + +--- + +## 4. Ciekawe rzeczy techniczne + +### 4.1. Parsowanie postępu FFmpeg w czasie rzeczywistym + +FFmpeg normalnie nie raportuje postępu w sposób, który łatwo przetworzyć maszynowo. Użyłem flagi `-progress pipe:1`, która kieruje dane o postępie na standardowe wyjście w formacie klucz-wartość. Odczytuję te dane w osobnym wątku linia po linii i wyciągam pole `out_time_us` (czas wyjściowy w mikrosekundach). Dzieląc go przez całkowity czas trwania pliku, otrzymuję procent ukończenia, a na jego podstawie liczę szacowany czas zakończenia. Bez tej techniki jedyne co mógłbym pokazać to "kodowanie trwa". + +### 4.2. Automatyczne wykrywanie i usuwanie cichych ścieżek audio + +Niektóre pliki wideo mają wiele ścieżek audio, z których część to puste lub praktycznie nieużywane kanały. Zamiast ślepo kopiować je wszystkie do pliku wyjściowego, analizuję każdą ścieżkę przy pomocy filtra `volumedetect` w FFmpeg. Uruchamiają FFmpeg z flagą `-t 60` (analizuję tylko pierwszą minutę, żeby było szybko), parsując z wyjścia wartość `max_volume`. Ścieżki o głośności maksymalnej poniżej lub równej -90 dB uznaję za ciche i pomijam przy kodowaniu. Wbudowany jest mechanizm bezpieczeństwa: jeśli wszystkie ścieżki są "ciche", zachowuję pierwszą z nich, bo plik wideo bez żadnego dźwięku byłby bezużyteczny. + +### 4.3. Odporność na awarie przez plik tymczasowy i atomiczną zamianę + +Enkoder nigdy nie nadpisuje bezpośrednio oryginalnego pliku podczas kodowania. Zamiast tego FFmpeg zapisuje wynik do pliku tymczasowego o nazwie kończącej się na `_temp.mkv`. Dopiero gdy FFmpeg zakończy działanie z kodem wyjścia 0 (sukces), wywołuję `os.replace()`, które na systemie Windows jest operacją atomiczną na poziomie systemu plików. Jeśli aplikacja ulegnie awarii podczas kodowania, oryginalny plik jest nienaruszony, a przy ponownym uruchomieniu stary plik tymczasowy zostaje usunięty przed ponowną próbą. Dodałem też walidację rozmiaru: jeśli zakodowany plik jest większy od oryginału, uznaję kodowanie za niepowodzenie i usuwam go. + +### 4.4. Wielowątkowa architektura z kontrolowanym dostępem do zasobów wspólnych + +Aplikacja uruchamia trzy równoległe wątki: wątek główny z GUI Tkinter, wątek serwera API i wątek enkodera. Wszystkie trzy korzystają z tych samych obiektów (kolejka, stan enkodera), co mogłoby prowadzić do błędów wyścigowych. Rozwiązałem to przez owinięcie każdego obiektu współdzielonego własnym lockiem z modułu `threading`. Klasa `QueueManager` blokuje mutexa przy każdej operacji odczytu i zapisu na liście plików. Klasa `EncoderState` podobnie chroni dane o bieżącym postępie. GUI odświeża swój stan co kilkaset milisekund przez odpytywanie tych obiektów, bez konieczności przesyłania zdarzeń między wątkami. + +### 4.5. Automatyczne odtwarzanie klucza API i bezpieczeństwo zdalnego dostępu + +Przy pierwszym uruchomieniu aplikacja generuje 48-znakowy klucz w formacie szesnastkowym przy pomocy modułu `secrets` i zapisuje go do pliku `config.json`. Każde żądanie do API musi zawierać ten klucz w nagłówku `X-API-KEY`. Jeśli klucz się nie zgadza, serwer odpowiada kodem 403. Plik `config.json` jest wpisany do `.gitignore`, więc klucz nie trafia przypadkowo do repozytorium. Dzięki temu API dostępne przez Tailscale jest zabezpieczone przed nieautoryzowanym dostępem nawet z innych urządzeń w tej samej sieci VPN. + +--- + +## 5. Czego się nauczyłem + +Ten projekt był dla mnie pierwszym poważniejszym projektem łączącym wiele różnych warstw w jednej aplikacji. Wcześniej pisałem albo prosty skrypt, albo prosty interfejs, ale nie obie rzeczy jednocześnie. + +Największą lekcją była architektura wielowątkowa. Zrozumiałem praktycznie, dlaczego locki są potrzebne i co się dzieje, kiedy ich nie ma (sporadyczne błędy, które trudno odtworzyć). Nauczyłem się też, że wątek GUI musi działać w wątku głównym, bo Tkinter nie jest "thread-safe", co wymusiło konkretny układ kodu. + +FastAPI okazało się bardzo ergonomicznym narzędziem. Szczególnie doceniłem automatyczną dokumentację Swagger, którą framework generuje bez żadnej dodatkowej konfiguracji, co pozwoliło mi testować API wprost z przeglądarki podczas programowania. + +Praca z procesami zewnętrznymi przez `subprocess` była ciekawą lekcją o komunikacji z narzędziami CLI. Parsowanie wyjścia FFmpeg wymagało dokładnego przeczytania dokumentacji i kilku prób zanim zrozumiałem, jakie flagi generują maszynowo czytelny output. + +Na poziomie projektowania nauczyłem się, że "crash safety" trzeba zaprojektować od początku. Dopisanie obsługi błędów do gotowego kodu, który zakłada że wszystko działa, jest znacznie trudniejsze niż zaprojektowanie od razu mechanizmu tymczasowych plików i odtwarzania po restarcie. + +--- + +## 6. Jak uruchomić + +Aplikacja wymaga systemu Windows, zainstalowanego Pythona 3.11 lub nowszego oraz FFmpeg dostępnego w zmiennej PATH (lub skonfigurowanego w `config.json`). + +```bash +pip install -r requirements.txt +python main.py +``` + +Przy pierwszym uruchomieniu w konsoli pojawi się automatycznie wygenerowany klucz API oraz otworzy się okno graficzne aplikacji. Plik `config.json` zostanie utworzony automatycznie w katalogu głównym projektu. + +Żeby dodać pliki do kolejki, można użyć przycisku "Select Files" w GUI lub wysłać żądanie POST do API: + +``` +POST http://localhost:8000/add +X-API-KEY: +Content-Type: application/json + +{"paths": ["C:/Videos/film.mkv"]} +``` + +Enkoder uruchamia się automatycznie po starcie aplikacji i przetwarza kolejkę bez ingerencji użytkownika.