Minimal web audio player for ntfy-audio-daemon output (playlist + listened state)
  • HTML 72%
  • Python 28%
Find a file
raf fd9bea86c7 bind 127.0.0.1:5155 (host nginx now terminates TLS on :5055)
Loop task 262: https://ps1raf:5055/ was unavailable because the Flask
app served plaintext HTTP on 0.0.0.0:5055. Host nginx now fronts
:5055 with the shared step-CA cert (SAN audio-player + audio-player.ps1.at)
and proxies to the new internal bind 127.0.0.1:5155. Public URL is
https now.
2026-05-17 08:44:36 +02:00
templates loop tasks 197+198: pretty filename display + auto-cleanup of listened files >7d 2026-04-29 22:18:19 +02:00
.gitignore initial audio-player flask app (loop task 88) 2026-04-18 21:14:01 +02:00
app.py bind 127.0.0.1:5155 (host nginx now terminates TLS on :5055) 2026-05-17 08:44:36 +02:00
README.md initial audio-player flask app (loop task 88) 2026-04-18 21:14:01 +02:00

audio-player

Simple web audio player for the audio files created by ntfy-audio-daemon (files under /var/www/html/downloads/ntfy-audio-*.wav).

  • Playlist view with new / listened badges.
  • Per-file mark listened / unlistened and delete.
  • Continue with next unlistened automatically checkbox (persisted in localStorage).
  • Light polling every 15s so newly-synthesized files appear without a refresh.
  • Auto-marks listened once playback passes 50 % of a track's duration.

Endpoints

Method Path Purpose
GET / UI
GET /api/tracks list files + state
POST /api/tracks/<name>/listened body {"listened": true/false}
DELETE /api/tracks/<name> delete file (via sudo -n rm)
GET /health simple OK + track count

Run

systemctl --user start audio-player.service
# UI: http://ps1raf:5055/
# Logs: journalctl --user -u audio-player -f

Files

  • app.py — Flask app (python 3, stdlib + flask)
  • templates/index.html — single-page UI
  • data/state.json — listened-state persistence (JSON, live-edited)
  • .venv/ — venv with flask

Why no container?

The app needs sudo -n rm to delete root-owned audio files under /var/www/html/downloads/. Running as host user raf via a systemd user service keeps that simple. Packaging it into a podman container would require either mounting the downloads dir read-write (host UID mismatch) or exposing a privileged helper inside the container.

Security posture

  • Bound on 0.0.0.0:5055 — LAN / tailnet only; no auth. Don't expose publicly without adding a reverse proxy + basic auth.
  • File names are validated against a strict ntfy-audio-*.wav|mp3|ogg|m4a regex before any filesystem op (no path traversal).
  • DELETE shells out to sudo rm -- with explicit----terminated args — no shell interpolation.