feat: add country selection, cron automation, sparkle effects and layout fixes
This commit is contained in:
138
README.md
138
README.md
@@ -1,21 +1,24 @@
|
||||
# RadioPlayer
|
||||
|
||||
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.
|
||||
RadioPlayer is a Vite + React web app for browsing, playing, and casting radio stations.
|
||||
It uses a managed catalog from `public/stations.json`, exposes a same-origin managed endpoint at `/api/managed-stations.json`, supports user stations with local persistence, and includes scripts to refresh station data from Radio.si.
|
||||
|
||||
## Features
|
||||
|
||||
- Station browser with search, categories, favourites, and recent stations
|
||||
- Audio playback with previous/next station controls
|
||||
- Cast support
|
||||
- Production service worker for app-shell caching, offline launch support, and faster repeat visits
|
||||
- App install prompt for supported browsers
|
||||
- Custom station editor
|
||||
- Live station metadata and artwork rendering
|
||||
- Station library with search, category tabs, favorites, recents, sorting, and pagination.
|
||||
- Country filtering plus a country picker to choose which Radio Browser countries are synced and shown.
|
||||
- Audio playback with previous/next controls, volume/mute, and coverflow quick picks.
|
||||
- Google Cast and AirPlay output support.
|
||||
- User station management with local import/export/reset tooling.
|
||||
- Managed catalog fallback chain: remote endpoint -> cached remote -> bundled `stations.json`.
|
||||
- Production service worker with app shell caching, station sync cache, and periodic refresh registration.
|
||||
- PWA install prompt and offline-friendly launch behavior.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js 18 or newer
|
||||
- Node.js 18+
|
||||
- npm
|
||||
- For production managed endpoint: PHP-enabled web server with rewrite support (Apache + `.htaccess` in this repo)
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -25,7 +28,7 @@ Install dependencies:
|
||||
npm install
|
||||
```
|
||||
|
||||
Start the development server:
|
||||
Run development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
@@ -37,35 +40,32 @@ Build for production:
|
||||
npm run build
|
||||
```
|
||||
|
||||
Preview the production build:
|
||||
Preview production build locally:
|
||||
|
||||
```bash
|
||||
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:
|
||||
Deploy built assets with the included script:
|
||||
|
||||
```bash
|
||||
bash sync.sh
|
||||
```
|
||||
|
||||
## Station Data
|
||||
## Managed Catalog Endpoint
|
||||
|
||||
The app keeps the editorial managed list in `public/stations.json`.
|
||||
|
||||
At runtime, the frontend prefers the same-origin managed endpoint:
|
||||
Runtime managed endpoint path:
|
||||
|
||||
```text
|
||||
/api/managed-stations.json
|
||||
```
|
||||
|
||||
That endpoint returns:
|
||||
In production this is served by:
|
||||
|
||||
- `public/.htaccess` rewrite rule
|
||||
- `public/api/managed-stations.php`
|
||||
|
||||
Response shape:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -75,55 +75,107 @@ That endpoint returns:
|
||||
}
|
||||
```
|
||||
|
||||
If the backend endpoint is unavailable, the frontend and service worker fall back to the bundled `stations.json` file.
|
||||
In dev/preview, Vite middleware in `vite.config.js` serves the same envelope from `stations.json`.
|
||||
|
||||
To refresh the file from the remote source, run:
|
||||
If the endpoint is unavailable, frontend and service worker fall back to bundled `public/stations.json`.
|
||||
|
||||
## Station Data Refresh
|
||||
|
||||
Refresh managed stations from Radio.si:
|
||||
|
||||
```bash
|
||||
npm run update:stations
|
||||
```
|
||||
|
||||
That command fetches the latest station list from:
|
||||
Refresh and rebuild in one command:
|
||||
|
||||
```text
|
||||
https://data.radio.si/api/radiostations?857df78efd094abcb98c7bbb53303c3d
|
||||
```bash
|
||||
npm run update:stations:build
|
||||
```
|
||||
|
||||
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:
|
||||
Custom source and output:
|
||||
|
||||
```bash
|
||||
node scripts/update-stations.mjs <source-url> <output-path>
|
||||
```
|
||||
|
||||
## Cron Automation (Server)
|
||||
|
||||
Helper script:
|
||||
|
||||
```bash
|
||||
bash scripts/cron-refresh-stations.sh
|
||||
```
|
||||
|
||||
Update-only helper script:
|
||||
|
||||
```bash
|
||||
bash scripts/cron-update-stations.sh
|
||||
```
|
||||
|
||||
The script:
|
||||
|
||||
- acquires a lock file to prevent overlapping runs,
|
||||
- runs station refresh and build,
|
||||
- optionally runs `DEPLOY_CMD`,
|
||||
- writes logs to `/tmp/radioplayer-refresh-stations.log` by default,
|
||||
- rotates logs automatically when they exceed 1 MB, keeping 5 archives by default.
|
||||
|
||||
The update-only script:
|
||||
|
||||
- acquires its own lock file,
|
||||
- runs only `npm run update:stations`,
|
||||
- optionally runs `POST_UPDATE_CMD`,
|
||||
- writes logs to `/tmp/radioplayer-update-stations.log`,
|
||||
- uses the same log rotation behavior.
|
||||
|
||||
Example crontab (every 6 hours):
|
||||
|
||||
```cron
|
||||
0 */6 * * * REPO_DIR=/opt/www/virtual/RadioPlayer DEPLOY_CMD='rsync -av --delete /opt/www/virtual/RadioPlayer/dist/ /opt/www/virtual/RadioPlayer/' /opt/www/virtual/RadioPlayer/scripts/cron-refresh-stations.sh
|
||||
```
|
||||
|
||||
Example update-only crontab (every 2 hours):
|
||||
|
||||
```cron
|
||||
0 */2 * * * REPO_DIR=/opt/www/virtual/RadioPlayer /opt/www/virtual/RadioPlayer/scripts/cron-update-stations.sh
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
```text
|
||||
index.html
|
||||
privacy.html
|
||||
package.json
|
||||
public/
|
||||
.htaccess
|
||||
api/
|
||||
managed-stations.php
|
||||
data/
|
||||
radio-stations.json
|
||||
radio-stations-sync.json
|
||||
manifest.json
|
||||
stations.json
|
||||
sw.js
|
||||
server/
|
||||
index.mjs
|
||||
managedCatalogData.mjs
|
||||
scripts/
|
||||
bump-sw-cache-version.mjs
|
||||
cron-refresh-stations.sh
|
||||
cron-update-stations.sh
|
||||
import-radio-stations.ts
|
||||
update-stations.mjs
|
||||
src/
|
||||
App.jsx
|
||||
main.jsx
|
||||
player.js
|
||||
styles.css
|
||||
scripts/
|
||||
update-stations.mjs
|
||||
radio/
|
||||
storage/
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- 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`.
|
||||
- Service worker is only active in production builds. In dev, SW registrations and caches are cleared automatically.
|
||||
- `src/main.jsx` registers background sync / periodic sync where supported.
|
||||
- `src/player.js` also refreshes managed catalog on app focus after a timeout (fallback for browsers without periodic sync).
|
||||
- `sync.sh` deploys `dist/` only.
|
||||
- If you edit stations manually, rerun `npm run update:stations` to resync from upstream when needed.
|
||||
|
||||
Reference in New Issue
Block a user