diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..82d674a --- /dev/null +++ b/.env.example @@ -0,0 +1,11 @@ +# Copy to .env and fill in your values + +MUSIC_PATH=/path/to/your/navidrome/music + +AUDIO_FMT=mp3 # mp3 | flac | opus | best +AUDIO_QUALITY=0 # 0 = best quality +MAX_PARALLEL=2 + +NAVIDROME_URL=http://navidrome:4533 +NAVIDROME_USER=admin +NAVIDROME_PASS=yourpassword diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e058366 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +FROM nginx:alpine +COPY index.html styles.css app.js sw.js /usr/share/nginx/html/ +COPY nginx.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..260076e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,46 @@ +services: + + # ── Frontend (nginx) ────────────────────────────────────────────────────────── + novasonic-frontend: + build: . + container_name: novasonic-frontend + restart: unless-stopped + ports: + - "8080:80" # change left side to your desired host port + labels: + - "traefik.enable=true" + - "traefik.http.routers.novasonic.rule=Host(`novasonic.yourdomain.com`)" + - "traefik.http.routers.novasonic.entrypoints=websecure" + - "traefik.http.routers.novasonic.tls.certresolver=letsencrypt" + + # ── Backend (yt-dlp download server) ───────────────────────────────────────── + novasonic-backend: + image: node:20-alpine + container_name: novasonic-backend + restart: unless-stopped + working_dir: /app + volumes: + - ./backend/novasonic-server.js:/app/novasonic-server.js:ro + - ${MUSIC_PATH:-/music}:/music # your Navidrome music library + ports: + - "3700:3700" + environment: + - PORT=3700 + - MUSIC_PATH=/music + - AUDIO_FMT=${AUDIO_FMT:-mp3} + - AUDIO_QUALITY=${AUDIO_QUALITY:-0} + - MAX_PARALLEL=${MAX_PARALLEL:-2} + - NAVIDROME_URL=${NAVIDROME_URL:-} + - NAVIDROME_USER=${NAVIDROME_USER:-} + - NAVIDROME_PASS=${NAVIDROME_PASS:-} + command: > + sh -c " + apk add --no-cache yt-dlp ffmpeg python3 && + npm install express cors && + node novasonic-server.js + " + labels: + - "traefik.enable=true" + - "traefik.http.routers.novasonic-api.rule=Host(`novasonic-api.yourdomain.com`)" + - "traefik.http.routers.novasonic-api.entrypoints=websecure" + - "traefik.http.routers.novasonic-api.tls.certresolver=letsencrypt" diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..8753cdd --- /dev/null +++ b/nginx.conf @@ -0,0 +1,31 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + gzip on; + gzip_types text/css application/javascript application/json image/svg+xml; + gzip_min_length 1024; + + # index.html – never cache so SW updates are picked up immediately + location = /index.html { + add_header Cache-Control "no-cache, no-store, must-revalidate"; + } + + # Static assets – long-term cache (cache busted by SW version) + location ~* \.(css|js)$ { + add_header Cache-Control "public, max-age=31536000, immutable"; + } + + # Service worker – no cache so browser always gets the latest version + location = /sw.js { + add_header Cache-Control "no-cache, no-store, must-revalidate"; + add_header Service-Worker-Allowed "/"; + } + + # SPA fallback + location / { + try_files $uri $uri/ /index.html; + } +}