Skip to content

feat: error visibility, already-downloaded status, PWA, mobile UI, and .env-based Docker setup#6

Open
QuantumFF wants to merge 10 commits into
AnOddName:mainfrom
QuantumFF:env-based-docker-setup
Open

feat: error visibility, already-downloaded status, PWA, mobile UI, and .env-based Docker setup#6
QuantumFF wants to merge 10 commits into
AnOddName:mainfrom
QuantumFF:env-based-docker-setup

Conversation

@QuantumFF

Copy link
Copy Markdown

Fix silent download failures, add already-downloaded detection, PWA support, mobile UI, and portable Docker configuration

Important

This PR is entirely written by claude code.

Summary

This PR fixes downloads failing silently when running outside Docker, surfaces rip errors that were previously swallowed, adds proper handling for music already in streamrip's database, makes the app installable as a PWA, optimises the UI for mobile viewports, and reworks the Docker configuration so one streamrip config (and one downloads database) works identically on the host and in the container.

Problem

Running python app.py directly on the host made every download fail instantly with no visible reason. Root cause: the default paths (/config/config.toml, /music) are Docker-internal — on a host, rip dies with PermissionError: Permission denied: '/music' before transferring a byte. The failure was invisible because the worker captured rip's output but never logged it server-side, and the UI discarded it.

Separately: re-downloading something already in streamrip's database silently fetched only the cover art but reported COMPLETED, and the Docker setup required hand-editing absolute paths inside the container's config.toml.

Changes

Fix: sensible local defaults + loud failures (app.py)

  • Default paths are now host-friendly: ~/.config/streamrip/config.toml and ~/Music (Docker still overrides both via environment variables)
  • Startup check: if DOWNLOAD_DIR can't be created or written, the app logs a prominent error at boot instead of failing per-download
  • The download worker now logs rip's exit code and last 30 lines of output on failure; worker exceptions are logged with tracebacks

Feature: already-downloaded detection (app.py, app.js, style.css)

  • When rip skips every track (Skipping track N. Marked as downloaded in the database.) and downloads nothing, the item is reported as skipped instead of completed
  • UI shows a cyan ALREADY DOWNLOADED badge and border; history shows it as a success-style entry
  • Partial downloads (album with some tracks new, some in DB) still correctly report completed

Feature: PWA support (manifest.json, sw.js, app.py, index.html, app.js)

  • Web app manifest with standalone display and 192/512 icons
  • Service worker: network-first with cache fallback for the app shell; never intercepts /api/* so the SSE event stream and POSTs always hit the network directly
  • Served from /sw.js via a new Flask route so its scope covers the whole app
  • iOS/Android install meta tags

Feature: mobile viewport support (style.css, index.html)

  • Responsive layout under 768px: stacked URL/search controls, evenly-spread tabs, full-width download buttons in search results, stacked file entries
  • 16px input font size on mobile to prevent iOS zoom-on-focus
  • Safe-area insets for notched phones in standalone PWA mode
  • Wide-desktop improvement: result/file panes use viewport height instead of fixed 500px

Fix: portable Docker configuration (docker-compose.yml, .env.example, .gitignore)

  • docker-compose.yml no longer contains machine-specific paths — all deployment values come from .env (CONFIG_DIR, MUSIC_DIR, PUID/PGID, PORT, MAX_CONCURRENT_DOWNLOADS)
  • Host directories are self-mounted at identical paths inside the container, so the absolute paths streamrip writes into config.toml (downloads database, folders) stay valid everywhere — no more in-container path surgery
  • Local runs, the rip CLI, and Docker now share one config and one downloads database, keeping already-downloaded detection consistent
  • docker-compose.yml is tracked again; .env is gitignored; .env.example documents the knobs

Docs (README.md)

  • Rewritten as a linear guide: how it works → streamrip setup → Docker via .env → local run → PWA install → usage → troubleshooting
  • Troubleshooting now maps to the actual error messages the app produces; removed the obsolete in-container sed path-fix recipe

Testing

  • Reproduced the original failure deterministically (rip -f /music ...PermissionError), then verified end-to-end through the running app: real Qobuz track download completes, SSE reports completed
  • Verified the startup check fires with an unusable DOWNLOAD_DIR
  • Verified status classification end-to-end via the API: an in-database track reports skipped, a fresh track reports completed, and skips are logged server-side
  • Verified all PWA endpoints (/sw.js, manifest, icons) serve with correct content types; JS/JSON syntax-checked
  • Verified docker compose config resolves all .env interpolations correctly
  • Manual testing of downloads and UI

Notes for reviewers

  • The repo has no test infrastructure, so there are no automated regression tests; the startup writability check is the practical guard for the original bug
  • PWA install requires localhost or HTTPS (browser secure-context rule) — documented in the README
  • The service worker uses network-first, so CSS/JS changes reach online clients without cache busting; bump CACHE_NAME only when changing SW logic itself

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant