UPnP MediaServer udostępniający lokalne pliki audio, internetowe strumienie radiowe oraz archiwum audycji Polskiego Radia Trójka wzmacniaczom sieciowym (rendererom). Korzysta z Kestrel do serwowania plików i ohNet jako stosu UPnP.
Główna cecha: biblioteka oparta na strukturze katalogów — SoundBridge nie czyta metadanych plików (ID3 tagów). Zamiast tego odwzorowuje strukturę folderów 1:1. Jeśli masz dobrze zorganizowaną kolekcję (Muzyka/Artysta/Album/utwór.mp3), renderer zobaczy ją dokładnie w tej hierarchii. Żadnego skanowania, żadnych tagów — tylko to, co na dysku.
SoundBridge działa w trzech trybach:
| Tryb | Komenda |
|---|---|
| Konsola | dotnet run --project src/SoundBridge.App |
| Windows Service | dotnet run --project src/SoundBridge.App -- --service (wymaga administratora do instalacji: sc create SoundBridge binPath=...) |
| Docker | docker run -d soundbridge |
Zaleca się ustawienie konkretnego adresu IP w WebServerHost zamiast domyślnego 0.0.0.0 — zapewnia to poprawne działanie UPnP (SSDP, PresentationURL, ikony) w sieci lokalnej.
# Zbuduj
dotnet build
# Uruchom (przed uruchomieniem ustaw WebServerHost w appsettings.json na adres IP swojej maszyny)
dotnet run --project src/SoundBridge.AppUstawienia pochodzą z dwóch źródeł — zmienne środowiskowe mają priorytet nad appsettings.json.
{
"SoundBridge": {
"FriendlyName": "SoundBridge",
"UdnFilePath": "data/device.udn",
"WebServerHost": "192.168.1.100",
"WebServerPort": 5000
}
}Uwaga:
WebServerHostustaw na rzeczywisty adres IP maszyny w sieci lokalnej.0.0.0.0spowoduje, że PresentationURL, ikony i SSDP nie będą działać poprawnie.
Te same klucze, prefiks SoundBridge__:
# Linux / Docker
export SoundBridge__FriendlyName="MojaMuzyka"
export SoundBridge__WebServerPort=8080# Windows PowerShell
$env:SoundBridge__FriendlyName = "MojaMuzyka"
$env:SoundBridge__WebServerPort = 8080| Klucz | Domyślnie | Opis |
|---|---|---|
FriendlyName |
SoundBridge |
Nazwa wyświetlana w rendererze |
UdnFilePath |
data/device.udn |
Ścieżka pliku UDN |
WebServerHost |
0.0.0.0 |
Adres IP maszyny — zaleca się ustawienie konkretnego IP |
WebServerPort |
5000 |
Port nasłuchiwania Kestrel |
Biblioteki (Local Libraries) to ścieżki w systemie plików widoczne jako główne kontenery w ContentDirectory. Konfiguruje się je wyłącznie przez REST API — nie ma ich w appsettings.json.
| Metoda | Ścieżka | Opis |
|---|---|---|
GET |
/api/local-libraries |
Lista wszystkich bibliotek |
GET |
/api/local-libraries/{name} |
Pojedyncza biblioteka |
POST |
/api/local-libraries |
Dodaj nową bibliotekę |
DELETE |
/api/local-libraries/{name} |
Usuń bibliotekę |
# Pobierz listę
curl http://{WebServerHost}:{WebServerPort}/api/local-libraries
# Dodaj bibliotekę
curl -X POST http://{WebServerHost}:{WebServerPort}/api/local-libraries \
-H "Content-Type: application/json" \
-d '{"name": "Muzyka", "path": "I:\\music"}'
# Usuń bibliotekę
curl -X DELETE http://{WebServerHost}:{WebServerPort}/api/local-libraries/MuzykaBiblioteki zapisywane są w LiteDB (data/soundbridge.db). Renderery UPnP widzą je przy Browse z ObjectID=0.
Wirtualna biblioteka strumieni radiowych. Zawsze obecna jako kontener najwyższego poziomu (domyślnie "Radio Online"), nie wymaga jawnego tworzenia. Nazwę roota można zmienić przez API.
Każda stacja radiowa to kontener, który zawiera jeden lub więcej Streamów — każdy z własną nazwą, URL-em i MIME type. Dzięki temu jedna stacja może oferować kilka wariantów jakości/kodeka (np. MP3 128kbps, FLAC lossless).
| Metoda | Ścieżka | Opis |
|---|---|---|
GET |
/api/radio-online |
Nazwa roota |
PUT |
/api/radio-online |
Zmień nazwę roota |
| Metoda | Ścieżka | Opis |
|---|---|---|
GET |
/api/radio-online/stations |
Lista wszystkich stacji |
GET |
/api/radio-online/stations/{name} |
Pojedyncza stacja |
POST |
/api/radio-online/stations |
Dodaj stację (tylko nazwa) |
PUT |
/api/radio-online/stations/{name} |
Zmień nazwę stacji |
DELETE |
/api/radio-online/stations/{name} |
Usuń stację wraz ze streamami |
| Metoda | Ścieżka | Opis |
|---|---|---|
GET |
.../streams |
Lista streamów stacji |
GET |
.../streams/{streamName} |
Pojedynczy stream |
POST |
.../streams |
Dodaj stream |
PUT |
.../streams/{streamName} |
Edytuj stream (nazwa, URL, MIME) |
DELETE |
.../streams/{streamName} |
Usuń stream |
audio/mpeg (MP3), audio/aac, audio/flac, audio/x-mpegurl (M3U playlisty)
# Zmień nazwę roota
curl -X PUT http://{host}:{port}/api/radio-online \
-H "Content-Type: application/json" \
-d '{"name": "Internet Radio"}'
# Dodaj stację
curl -X POST http://{host}:{port}/api/radio-online/stations \
-H "Content-Type: application/json" \
-d '{"name": "Radio Paradise"}'
# Zmień nazwę stacji
curl -X PUT http://{host}:{port}/api/radio-online/stations/Radio%20Paradise \
-H "Content-Type: application/json" \
-d '{"name": "RP"}'
# Dodaj stream MP3
curl -X POST http://{host}:{port}/api/radio-online/stations/Radio%20Paradise/streams \
-H "Content-Type: application/json" \
-d '{"name": "Mellow Mix - MP3", "url": "https://stream.example.com/mellow.mp3", "mimeType": "audio/mpeg"}'
# Dodaj stream FLAC
curl -X POST http://{host}:{port}/api/radio-online/stations/Radio%20Paradise/streams \
-H "Content-Type: application/json" \
-d '{"name": "World Mix - FLAC", "url": "https://stream.example.com/world.flac", "mimeType": "audio/flac"}'
# Edytuj URL streama
curl -X PUT http://{host}:{port}/api/radio-online/stations/Radio%20Paradise/streams/Mellow%20Mix%20-%20MP3 \
-H "Content-Type: application/json" \
-d '{"url": "https://new-stream.example.com/mellow.mp3"}'
# Usuń stream
curl -X DELETE http://{host}:{port}/api/radio-online/stations/Radio%20Paradise/streams/Mellow%20Mix%20-%20MP3
# Usuń stację (kasuje też wszystkie jej streamy)
curl -X DELETE http://{host}:{port}/api/radio-online/stations/Radio%20ParadiseKażdy stream pojawia się jako item UPnP audioBroadcast — renderer odtwarza go bezpośrednio z zewnętrznego URL-a.
Wirtualna biblioteka archiwum audycji Polskiego Radia Trójka. Zawsze obecna jako kontener najwyższego poziomu (domyślnie "Trójka Archiwum"). Pobiera dane na żywo z API Polskiego Radia — lista audycji i odcinków nie jest persistowana lokalnie.
Audycje są pogrupowane w wirtualne foldery #, A–Z według pierwszej litery nazwy. Polskie znaki diakrytyczne są normalizowane (np. Ł → L, Ż → Z). Każda audycja wyświetla odcinki stronicowane po 10, z nawigacją Nast. > / < Poprz..
Klucz API wymagany przez api-gateway.polskieradio.pl konfiguruje się w appsettings.json:
{
"SoundBridge": {
"PrThreeArchive": {
"ApiKey": "twój-klucz-api"
}
}
}Lub przez zmienną środowiskową: SoundBridge__PrThreeArchive__ApiKey.
| Metoda | Ścieżka | Opis |
|---|---|---|
GET |
/api/pr-three-archive |
Nazwa roota |
PUT |
/api/pr-three-archive |
Zmień nazwę roota |
# Zmień nazwę roota
curl -X PUT http://{host}:{port}/api/pr-three-archive \
-H "Content-Type: application/json" \
-d '{"name": "Trójka"}'Odcinki są serwowane jako itemy UPnP audioBroadcast z bezpośrednim URL-em do strumienia na serwerach Polskiego Radia (MIME audio/mpeg).
Dokumentacja OpenAPI dostępna zawsze pod /scalar/v1 — interaktywne UI do testowania endpointów API.
Pliki serwowane są przez Kestrel pod trasą /media/{**path} z obsługą range requests (niezbędne do przewijania w rendererze). Dozwolone rozszerzenia: .mp3, .wav, .flac, .aac.
# Budowa
docker build -t soundbridge .
# Uruchomienie z mapowaniem portów i wolumenem
docker run -d \
-p 5000:5000 \
-p 1900:1900/udp \
-v /host/data:/app/data \
-e SoundBridge__WebServerHost={WebServerHost} \
-e SoundBridge__FriendlyName="SoundBridge-Docker" \
soundbridgePorty:
5000— HTTP (Kestrel: API + media)1900/udp— SSDP (wykrywanie UPnP)
Wolumen /app/data przechowuje device.udn, soundbridge.db i logi.
src/
├── SoundBridge.Abstractions/ # IContentResolver, BrowseResult, SoundBridgeOptions
├── SoundBridge.Shared/ # DidlLiteBuilder, PathValidator
├── SoundBridge.Libraries.LocalLibrary/ # Lokalne biblioteki plików
│ ├── Models/ # LocalLibrary
│ └── Controllers/ # LocalLibrariesController
├── SoundBridge.Libraries.RadioOnline/ # Strumienie radiowe
│ ├── Models/ # RadioRoot, RadioStation, Stream
│ └── Controllers/ # RadioOnlineController
├── SoundBridge.Libraries.PrThreeArchive/ # Archiwum Trójki
│ ├── Models/ # PrThreeRoot
│ ├── ApiModels/ # PrShowDto, PrEpisodeDto
│ └── Controllers/ # PrThreeArchiveController
└── SoundBridge.App/ # Host ASP.NET + UPnP
├── Controllers/ # MediaController
├── Core/ # UdnManager
├── Providers/ # SoundBridgeContentDirectory, SoundBridgeConnectionManager
├── Services/ # UpnpDeviceService, ContentDirectoryService
└── CompositeResolver.cs # Dyspozytor sub-resolverów
