Radio Explorer je implementován jako čistě klientská webová aplikace, kde serverová část slouží pouze jako statický zdroj dat a vstupní konfigurace. Celá aplikační logika, řízení přehrávání, stavový management i nahrávání streamu probíhají výhradně na straně prohlížeče. Tento přístup je patrný již na úrovni zdrojového kódu, kde PHP vrstva obsahuje pouze definici seznamu stanic a několik pomocných funkcí, zatímco vlastní funkcionalita je realizována v JavaScriptu.
Serverová část je založena na statickém poli stanic, kde každá položka obsahuje identifikátor, název, URL streamu, typ formátu a volitelnou poznámku. Toto pole je následně použito k vygenerování seznamu stanic v HTML. PHP zde plní roli jednoduchého templatingu a zároveň poskytuje doplňkovou funkci pro získání bitrate streamu. Ta je realizována pomocí knihovny cURL, která provede HTTP požadavek na stream a z hlaviček extrahuje hodnotu icy-br. Výsledek je následně vrácen jako JSON odpověď na základě parametrů v URL, což představuje jediný dynamický endpoint celé aplikace.
Klientská část aplikace je postavena na HTMLMediaElement reprezentovaném elementem audio. Tento prvek slouží jako primární rozhraní pro přehrávání streamu. Při výběru stanice dochází k nastavení atributu src na URL streamu a k inicializaci přehrávání pomocí metody play. Součástí inicializace je také nastavení atributu crossOrigin na hodnotu anonymous, což je nutné pro další práci se streamem, zejména pro jeho zachycení pomocí MediaStream API.
Řízení aplikace je realizováno pomocí stavových proměnných, které reprezentují aktuální stanici, stav přehrávání, nahrávání a další parametry. Tyto proměnné jsou synchronizovány s DOM prvky prostřednictvím událostí. Audio element generuje události jako playing, pause nebo error, které jsou využívány pro aktualizaci stavového textu, kontrolky a dalších částí rozhraní. Aplikace tak funguje jako jednoduchý stavový automat, kde změny stavu vycházejí z událostí prohlížeče i uživatelských vstupů.
Významnou část logiky tvoří implementace nahrávání streamu. Ta je založena na metodě captureStream, která z audio elementu vytvoří MediaStream obsahující aktuálně přehrávaný audio tok. Tento stream je následně předán objektu MediaRecorder. Při inicializaci recorderu je detekován podporovaný MIME typ, přičemž aplikace postupně testuje několik variant, například audio/webm nebo audio/ogg, a vybírá první podporovanou kombinaci. Samotný MediaRecorder je spuštěn s intervalem segmentace, který zajišťuje pravidelné generování datových bloků.
Data záznamu jsou ukládána do pole nahravaneBloky, kde každý prvek představuje Blob získaný z události dataavailable. Po ukončení záznamu dochází ke sloučení těchto bloků do jednoho výsledného Blob objektu. Ten je následně zpřístupněn uživateli pomocí dočasného URL vytvořeného funkcí URL.createObjectURL a je iniciováno jeho stažení. Název souboru je generován dynamicky na základě názvu stanice a aktuálního času, přičemž jsou odstraněny diakritické znaky a neplatné znaky pro souborový systém.
Důležitým aspektem implementace je práce s chybovými stavy. Při pokusu o spuštění záznamu může dojít k výjimce způsobené bezpečnostní politikou prohlížeče, typicky v případě, kdy stream neumožňuje cross-origin přístup. Aplikace tento stav detekuje na základě textu chyby a reaguje odpovídajícím způsobem, například zobrazením chybového hlášení a ukončením pokusu o záznam. Tím je zajištěno, že uživatel dostane srozumitelnou informaci o důvodu selhání.
Další významnou částí aplikace je správa uživatelských preferencí. Oblíbené stanice jsou ukládány pomocí localStorage, kde je uchováván seznam identifikátorů. Při načtení aplikace jsou tyto hodnoty načteny a použity pro označení odpovídajících položek v seznamu. Filtrace stanic podle oblíbenosti je realizována jednoduchou manipulací s vlastností display jednotlivých prvků, což umožňuje dynamicky měnit obsah seznamu bez nutnosti jeho znovunačítání.
Aplikace obsahuje také implementaci časovače a funkce spánku. Časovač přehrávání je realizován pomocí ukládání časového razítka začátku přehrávání a jeho pravidelného porovnávání s aktuálním časem. Výsledkem je formátovaný řetězec zobrazující uplynulý čas. Funkce spánku je implementována pomocí setTimeout, který po uplynutí zvoleného intervalu zastaví přehrávání a resetuje stav aplikace. Paralelně je využíván interval pro aktualizaci zbývajícího času do ukončení.
Zajímavým prvkem je také implementace cyklického stavového řádku, který střídavě zobrazuje informace o aktuálním přehrávání a případně o aktivním režimu spánku. Tento mechanismus využívá periodický interval a index, který určuje, která zpráva má být aktuálně zobrazena. Tento přístup umožňuje zobrazit více informací v omezeném prostoru bez nutnosti rozšiřovat uživatelské rozhraní.
Vizuální indikace stavu je realizována kombinací CSS tříd a animací. Kontrolka přehrávání a nahrávání je reprezentována jedním DOM prvkem, jehož třídy jsou dynamicky měněny podle aktuálního stavu. CSS následně definuje animace pomocí keyframes, které vytvářejí efekt blikání nebo pulzování. Tento přístup minimalizuje potřebu JavaScriptových animací a přenáší zátěž na renderovací engine prohlížeče.
Z pohledu interakce s uživatelem je důležitá podpora klávesového ovládání. Globální listener na událost keydown interpretuje stisky kláves a mapuje je na jednotlivé funkce aplikace. Součástí implementace je kontrola, zda není aktivní vstupní prvek, aby nedocházelo k nechtěným zásahům při psaní. Tento mechanismus umožňuje rychlé a efektivní ovládání bez nutnosti práce s myší.
Radio Explorer tak z technického hlediska představuje konzistentní implementaci klientské aplikace, která využívá standardní webová API bez externích závislostí. Kombinuje HTMLMediaElement, MediaStream API, MediaRecorder API a Web Storage API do jednoho celku, který poskytuje funkcionalitu běžně spojovanou s desktopovými aplikacemi. Celé řešení je deterministické, transparentní a snadno analyzovatelné, což z něj činí zajímavý příklad moderního klientského přístupu k webovým aplikacím.
Aplikaci můžete navštívit na adrese https://fm.bedrunka.eu/
Napsat komentář