diff --git a/README.md b/README.md index 9f3d15a..5f690b4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # RadioPlayer -RadioPlayer is a Vite + React web app for browsing, playing, and casting radio stations. It loads its station catalog from `public/stations.json`, supports custom stations, and includes a built-in updater for refreshing that list from the live Radio.si feed. +RadioPlayer is a Vite + React web app for browsing, playing, and casting radio stations. It loads its bundled managed catalog from `public/stations.json`, exposes that catalog through a same-origin backend endpoint at `/api/managed-stations.json`, supports custom stations, and includes a built-in updater for refreshing the managed list from the live Radio.si feed. ## Features @@ -43,9 +43,39 @@ Preview the production build: npm run preview ``` +Run the production build with the bundled same-origin backend endpoint: + +```bash +npm run serve:backend +``` + +Deploy the built frontend plus backend server files to the remote host: + +```bash +bash sync.sh +``` + ## Station Data -The app reads station data from `public/stations.json`. +The app keeps the editorial managed list in `public/stations.json`. + +At runtime, the frontend prefers the same-origin managed endpoint: + +```text +/api/managed-stations.json +``` + +That endpoint returns: + +```json +{ + "schemaVersion": 1, + "updatedAt": "2026-04-29T07:39:58.374Z", + "stations": [] +} +``` + +If the backend endpoint is unavailable, the frontend and service worker fall back to the bundled `stations.json` file. To refresh the file from the remote source, run: @@ -59,7 +89,7 @@ That command fetches the latest station list from: https://data.radio.si/api/radiostations?857df78efd094abcb98c7bbb53303c3d ``` -and rewrites `public/stations.json` while preserving the existing JSON structure used by the app. +and rewrites `public/stations.json` while preserving the existing JSON structure used by the app. The backend endpoint reads from that file and wraps it in the runtime envelope shown above. You can also pass a custom source URL or a custom output path if needed: @@ -76,6 +106,9 @@ public/ manifest.json stations.json sw.js +server/ + index.mjs + managedCatalogData.mjs src/ App.jsx main.jsx @@ -90,4 +123,7 @@ scripts/ - The app uses a module-based frontend build, so `src/main.jsx` is the browser entry point. - The service worker is registered only in production builds. During development, existing service workers and caches are cleared automatically to avoid stale assets while iterating. - The updater script uses the remote feed as the source of truth for the station list and writes the merged result into `public/stations.json`. +- Vite dev and preview both expose `/api/managed-stations.json` on the same origin via middleware, and `npm run serve:backend` serves the built app plus the same endpoint from Node. +- `sync.sh` now deploys both the built frontend files and the `server/` runtime so the same-origin backend can be started remotely with `node /opt/www/virtual/RadioPlayer/server/index.mjs`. - If you add or edit stations manually, re-run `npm run update:stations` when you want to sync back to the remote catalog. +- Static-only deployments still work because the frontend falls back to bundled `stations.json`, but a true same-origin backend endpoint requires deploying a server that answers `/api/managed-stations.json`. diff --git a/package-lock.json b/package-lock.json index 3c7fe42..790e6ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "radioplayer-web", "version": "0.1.0", "dependencies": { + "idb": "^8.0.3", "react": "^19.2.5", "react-dom": "^19.2.5" }, @@ -911,6 +912,12 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/idb": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/idb/-/idb-8.0.3.tgz", + "integrity": "sha512-LtwtVyVYO5BqRvcsKuB2iUMnHwPVByPCXFXOpuU96IZPPoPN6xjOGxZQ74pgSVVLQWtUOYgyeL4GE98BY5D3wg==", + "license": "ISC" + }, "node_modules/lightningcss": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", diff --git a/package.json b/package.json index 872e350..ce955d5 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,13 @@ "prebuild": "node scripts/bump-sw-cache-version.mjs", "build": "vite build", "preview": "vite preview", + "serve:backend": "node server/index.mjs", "update:stations": "node scripts/update-stations.mjs", "radio:import": "tsx scripts/import-radio-stations.ts", "typecheck": "tsc --noEmit" }, "dependencies": { + "idb": "^8.0.3", "react": "^19.2.5", "react-dom": "^19.2.5" }, diff --git a/privacy.html b/privacy.html index fe96663..403fd13 100644 --- a/privacy.html +++ b/privacy.html @@ -258,10 +258,10 @@
Pravilnik
- Ta stran pojasnjuje, katere podatke uporablja spletna aplikacija RadioPlayer, zakaj jih uporablja in - kje se ti podatki hranijo. Besedilo velja za uporabo spletne aplikacije in njene PWA namestitve. + Ta stran pojasnjuje, katere podatke RadioPlayer shrani samo v vašem brskalniku, zakaj jih uporablja in kako + jih lahko izbrišete. Besedilo velja za spletno uporabo aplikacije in za njeno PWA namestitev.
- +Zgoraj navedeni podatki se hranijo lokalno v vašem brskalniku oziroma v podatkih spletnega mesta na vaši - napravi. RadioPlayer teh nastavitev ne pošilja na lasten strežnik in jih brez vašega dejanja ne deli z - drugimi uporabniki. + napravi. Za trajnejše shranjevanje nastavitev in postaj aplikacija uporablja brskalnikovo lokalno bazo + IndexedDB. Ob prvi uporabi nove različice lahko prenese tudi stare lokalne nastavitve iz prejšnje lokalne + hrambe, da se vaši podatki ohranijo. RadioPlayer teh nastavitev ne pošilja na lasten strežnik in jih brez + vašega dejanja ne deli z drugimi uporabniki.
Aplikacija uporablja tudi predpomnjenje datotek aplikacije za hitrejši zagon in delovanje brez ponovnega @@ -304,14 +306,19 @@ Sender SDK. Pri tem lahko Google oziroma naprava za predvajanje obdelujeta podatke, potrebne za sejo oddajanja in usmerjanje medijev.
++ Na napravah Apple lahko aplikacija ponudi tudi AirPlay izbiro izhoda. V tem primeru se medijski tok + preusmeri na izbrano AirPlay napravo prek zmožnosti vašega brskalnika in operacijskega sistema, zato lahko + zunanja naprava ali Apple obdelujeta podatke, potrebne za vzpostavitev in upravljanje predvajanja. +
Trenutna različica aplikacije ne uporablja analitičnih skript za profiliranje uporabnikov in ne nastavlja - lastnih piškotkov za oglaševanje. Aplikacija za shranjevanje nastavitev uporablja lokalno hrambo brskalnika, - ne klasičnih piškotkov. + lastnih piškotkov za oglaševanje. Aplikacija za shranjevanje nastavitev uporablja lokalno hrambo brskalnika + in IndexedDB, ne klasičnih piškotkov.
- Če aplikacija v prihodnje doda prijavo, obrazce ali dodatne zunanje storitve, je treba ta pravilnik ustrezno - dopolniti. -