Wie ein Open-Source-Fork zur nativen Radio-App wurde
Teil 1 der Serie 'Behind the App' - Vom React-Kursprojekt über den Weihnachts-Fork zum ersten Commit der nativen App.
Teil 1 der Serie "Behind the App" — Die Entstehungsgeschichte von Radio Adfree
Es begann mit einem fremden Projekt
Im Dezember 2024 stolperte ich über ein Open-Source-Projekt: React Radio, ein Kursprojekt aus dem SoftUni ReactJS-Kurs (Februar 2023). Ein webbasierter Radio-Player, gebaut mit React und TypeScript, der die offene radio-browser.info API nutzt: über 40.000 Sender, kostenlos und ohne API-Key.
Für ein Kursprojekt war das erstaunlich rund. Es gab einen funktionierenden Player, Favoriten, Verlauf, Cover-Suche, Browser-Steuerung und sogar einen Audio-Visualizer. Unter der Haube war vieles sauber getrennt und gut nachvollziehbar. Man merkte: Da hatte sich jemand Gedanken gemacht.
Aber es war auch klar: So wie es war, passte es nicht ganz zu dem, was ich bauen wollte. Einige Dienste waren mir zu fest eingebaut, manche Grenzen wurden schnell sichtbar, und ich hatte eigene Ideen, wohin das Ganze gehen sollte.
Also forkte ich das Projekt. An Weihnachten 2024.
Weihnachten 2024: Eine Woche Umbau
Was folgte, war ein ziemlich intensives, verlängertes Wochenende. In wenigen Tagen baute ich die Basis um:
Supabase raus, SQLite rein. Weniger externe Abhängigkeiten, mehr Kontrolle über die Daten.
Netlify Edge Functions raus, Express rein. Die Abfragen für Songtitel und Metadaten sollten zuverlässiger laufen und nicht von Serverless-Limits abhängen.
Docker drumherum. Aus dem Serverless-Setup wurde ein selbst gehostetes Backend, sauber verpackt und einfacher zu betreiben.
Mehrsprachigkeit, Passwort-Recovery, API-Absicherung. Also die Dinge, die ein öffentliches Projekt irgendwann braucht, wenn es nicht nur ein Experiment bleiben soll.
Das erste Fazit nach diesen Tagen: Aus einem Kursprojekt war ein eigener Web-Player mit eigenem Backend geworden. Weihnachtsferien, gut investiert.
Die CORS-Hölle
Wer schon einmal versucht hat, einen Radio-Stream im Browser abzuspielen, kennt das Problem: Die meisten Icecast- und Shoutcast-Server senden keine CORS-Header. Der Browser blockiert den Zugriff, und das war's.
Für den reinen Audio-Stream ist das meist kein Problem. Ein <audio>-Element kann viele Streams einfach abspielen. Aber sobald man Metadaten will, also Songtitel und Künstler, muss man genauer in den Stream hineinschauen. Und genau da sagt der Browser oft: nein.
Das Original löste das mit einer Netlify Edge Function. Mein Fork nutzte jetzt Express. Die eigentliche Erkenntnis kam aber später: Bei zehntausenden Streams, zusammengetragen von vermutlich tausenden Nutzern, sind viele Datensätze nicht besonders sauber gepflegt. Alte URLs, fehlendes HTTPS, ungewöhnliche Ports, Session-IDs in der Adresse. Ein Proxy wurde dadurch immer wichtiger. Nicht als Selbstzweck, sondern als eine Art Vermittler, der Streams prüft, bereinigt und dem Player in einer verlässlicheren Form zur Verfügung stellt.
Dieses Muster sollte später die Architektur der nativen App stark prägen. Aber das wusste ich zu dem Zeitpunkt noch nicht.
Was der Browser nicht kann
Der Web-Player konnte mittlerweile ziemlich viel. Das Original brachte bereits Cover, YouTube-Links, Favoriten, Verlauf, Browser-Steuerung und einen Visualizer mit. Mein Fork ergänzte Mehrsprachigkeit, Song-Favoriten, ein eigenes Backend und den Proxy.
Aber es gab Grenzen, an die ein Browser einfach nicht vorbeikommt:
Kein wirklich zuverlässiges Background-Audio. Tab wechseln? Meistens okay. Browser minimieren? Kommt darauf an. Bildschirm sperren? Auf dem Handy wird es schnell schwierig.
Kein richtiges Lock-Screen-Erlebnis. Metadaten können zwar angezeigt werden, aber nur sehr begrenzt und kaum gestaltbar.
Kein CarPlay, kein Android Auto. Ein Web-Player läuft nicht auf dem Auto-Display.
Audio-Visualizer nur in manchen Browsern. In Chrome und Firefox sah der Visualizer gut aus. In Safari blieb er stumm, weil Safari bei fremden Audio-Streams keinen Zugriff auf die nötigen Audiodaten gibt. Das ist kein kleiner Bug, den man eben fixt, sondern eine grundsätzliche Browser-Grenze.
Dieser letzte Punkt war der Auslöser. Silvester 2024 versuchte ich, den Visualizer in Safari doch irgendwie zum Laufen zu bringen, notfalls mit künstlichen Daten als Fallback. Es fühlte sich aber nie richtig an. In Chrome bewegte sich alles schön zur Musik, in Safari war es letztlich nur eine Simulation.
Das war der Moment, in dem klar wurde: Wenn ich einen Visualizer will, der sich wirklich gut anfühlt, und wenn Dinge wie Background-Audio, Lock-Screen, CarPlay und Android Auto ernsthaft funktionieren sollen, brauche ich eine native App.
Auf den Schultern von Open Source
Was ich an dem Fork-Ansatz schätze: Ich musste nicht bei Null anfangen. Das Original hatte gute Grundideen, und einige davon wanderten direkt in die native App:
Getrennter Player- und Metadaten-State — Ein Teil kümmert sich um Wiedergabe, ein anderer um das, was gerade läuft. Diese Trennung lebt bis heute in der React-Native-App weiter.
Der Proxy-Ansatz — Was im Original als kleine Serverless-Lösung begann und in meinem Fork zum eigenen Backend wurde, bekam in der App später noch eine native Ergänzung. Dazu aber in einem späteren Teil mehr.
Wiederverwendbare Datenlogik — Sender laden, Verlauf verwalten, gespeicherte Songs abrufen: Diese Art, Logik sauber auszulagern, funktionierte im Web und wurde in der App fortgesetzt.
Anerkennung an den Original-Autor: Ohne sein sauber strukturiertes Kursprojekt hätte es diese App vermutlich nicht gegeben, zumindest nicht so schnell. Besonders die Song-Erkennung fand ich stark: sehen, was gerade läuft, und später nachvollziehen können, was man gehört hat. Dieses Gefühl wollte ich unbedingt behalten und weiter ausbauen. Dazu kam das Speichern von Lieblingssongs, das ich schon in der Web-Version ergänzt hatte.
Die Datenbank-Reise
Ein Nebenstrang, der gut zeigt, wie sich Anforderungen ändern, wenn ein Projekt wächst:
- Supabase (Original, 2023) — Schnell startklar, gehostet, perfekt für ein Kursprojekt.
- SQLite (mein Fork, 26. Dezember 2024) — Weniger externe Abhängigkeiten, alles näher am eigenen System.
- MariaDB (Januar 2025) — Besser passend für den Betrieb, die Pflege und meine gewohnten Werkzeuge.
Drei Datenbanken in drei Wochen. Nicht elegant, aber lehrreich. Und ehrlich gesagt: Mit KI-Unterstützung war so ein Umbau Anfang 2025 schon deutlich weniger abschreckend als noch ein paar Jahre zuvor.
Der Sprung: 7. Januar 2025
Am 7. Januar 2025, zwölf Tage nach dem Fork, entstand der erste Commit der nativen App. Expo, React Native, TypeScript, eine neue Oberfläche und dieselbe Grundidee: Radio hören, erkennen, merken, wiederfinden.
Was auffällt, wenn man die ersten Commits heute noch einmal anschaut: Es ging schnell. Nicht weil React Native automatisch einfach ist, sondern weil die Vorarbeit da war. Die Probleme waren verstanden, viele Lösungen im Web bereits ausprobiert, und die App musste nicht bei null anfangen.
Ein Commit aus den ersten Tagen verrät außerdem, was von Anfang an ein Ziel war: "Implement fake player visualization". Der Visualizer, der im Browser nur eingeschränkt funktionierte, sollte nativ auf jedem Gerät gut aussehen.
(Spoiler: Es hat noch Monate gedauert. Aber dazu mehr im nächsten Post.)
Warum Forken manchmal besser ist als bei Null anzufangen
Es gibt in der Entwickler-Community eine Tendenz, alles selbst von Grund auf zu bauen. Aber der Fork-Ansatz hat mir drei Dinge gegeben, die unglaublich wertvoll waren:
-
Eine erprobte Grundstruktur — Viele Ideen aus dem Original hatten bereits funktioniert. Ich musste nicht alles neu erfinden, sondern konnte die guten Teile übernehmen.
-
Radio-Wissen im Zeitraffer — Streams, Metadaten, Cover, Browser-Grenzen, komische Sender-URLs: Das Original und der Umbau haben mir in zwei Wochen Dinge beigebracht, für die ich sonst deutlich länger gebraucht hätte.
-
Ein laufendes Backend — Der Web-Player dient bis heute als Backend für die native App. Viele Schnittstellen, die im Fork entstanden sind, werden von der App direkt genutzt.
Die Evolution des Players
| Web-Version (Dez 2024) | App v1 - "Radio Hero" (Jan 2025) | App heute - "Radio AdFree" |
|---|---|---|
![]() |
![]() |
![]() |
Was kommt als Nächstes
In den folgenden Posts erzähle ich die Geschichte der nativen App: Wie aus dem ersten Commit ein Player mit Audio-Visualizer, Song-Erkennung, Stream-Aufnahme, CarPlay-Support und einigen überraschend hartnäckigen Dark-Mode-Problemen wurde. 720 Commits, verteilt über 15 Monate.
Radio Adfree ist eine werbefreie Radio-App für iOS und Android mit über 40.000 Sendern, Song-Erkennung, Podcasts und Stream-Aufnahme.


