Stage 0: migrate pipeline scripts from /opt/sldl, scaffold repo
Moves all ~30 pipeline scripts, configs, and the vendored sldl binary into this repo (source /opt/sldl left untouched). Removes all docker exec/docker compose dependencies now that beets and sldl run in-process/as a subprocess of this container instead of via soulbeet/on-demand sldl containers. Replaces hardcoded host paths, Navidrome credentials, and Spotify credential sourcing with env-var-driven paths and shared credential loaders. Adds Dockerfile, entrypoint.sh, requirements.txt, docker-compose.snippet.yml, and the initial app DB schema.
This commit is contained in:
Executable
+60
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
# navidrome-scan.sh — trigger a Navidrome full scan ONLY if the music library
|
||||
# share is healthy.
|
||||
#
|
||||
# Why this exists: with ND_SCANNER_PURGEMISSING=always (which we keep, so
|
||||
# on-disk deletions propagate to playlists and out to Traktor), a full scan
|
||||
# that runs while the QNAP NFS share is unavailable makes Navidrome see the
|
||||
# entire library as "missing" and purge it — wiping every playlist. That is
|
||||
# exactly what happened on 2026-06-01 and lost the manual dj-* playlists.
|
||||
#
|
||||
# This wrapper refuses to trigger the scan unless the share is mounted, a
|
||||
# canary file is readable, and the library has a sane number of artist dirs.
|
||||
# Skipping a scan is harmless (the next healthy run picks up changes); running
|
||||
# one against a dead mount is catastrophic.
|
||||
set -euo pipefail
|
||||
|
||||
: "${MUSIC_DATA_DIR:=/data/music}"
|
||||
: "${ALEMBIC_CONFIG_DIR:=/config}"
|
||||
NAVIDROME_ENV="$ALEMBIC_CONFIG_DIR/pipeline/navidrome/admin.env"
|
||||
[ -f "$NAVIDROME_ENV" ] && source "$NAVIDROME_ENV"
|
||||
|
||||
LIB="$MUSIC_DATA_DIR/Library"
|
||||
CANARY="$LIB/.navidrome-canary"
|
||||
MIN_ARTIST_DIRS=500 # library has ~1500; 500 is "clearly not wiped"
|
||||
ND="${ND_BASE:-http://navidrome:4533}"
|
||||
ND_USER="${ND_USER:-andrew}"
|
||||
ND_PASS="${ND_PASS:-}"
|
||||
|
||||
log() { echo "[$(date -Iseconds)] navidrome-scan: $*"; }
|
||||
|
||||
# `mountpoint -q` on the host detected an unmounted/dead NFS share directly.
|
||||
# Running inside a container against a bind-mounted view, that check doesn't
|
||||
# apply (a bind mount has no distinct device number to detect) — the canary
|
||||
# file + artist-dir-count checks below are what actually carry the
|
||||
# 2026-06-01 protection now: an unhealthy/empty share fails both of them.
|
||||
# (Confirmed as an intentional adaptation, not a silent drop — see alembic
|
||||
# migration plan / MIGRATION.md.)
|
||||
if [ ! -r "$CANARY" ]; then
|
||||
log "ABORT: canary $CANARY missing/unreadable — share degraded — skipping scan"
|
||||
exit 0
|
||||
fi
|
||||
n=$(find "$LIB" -maxdepth 1 -mindepth 1 -type d 2>/dev/null | wc -l)
|
||||
if [ "$n" -lt "$MIN_ARTIST_DIRS" ]; then
|
||||
log "ABORT: only $n artist dirs under $LIB (< $MIN_ARTIST_DIRS) — library looks truncated — skipping scan"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "library healthy ($n artist dirs) — triggering full scan"
|
||||
resp=$(curl -s -G "$ND/rest/startScan.view" \
|
||||
--data-urlencode "u=$ND_USER" --data-urlencode "p=$ND_PASS" \
|
||||
--data-urlencode 'v=1.16.0' --data-urlencode 'c=cron' \
|
||||
--data-urlencode 'f=json' --data-urlencode 'fullScan=true' || true)
|
||||
# Don't log "scan triggered" on faith: a rotated password or Navidrome error
|
||||
# would otherwise report success forever while no scan ever runs.
|
||||
if echo "$resp" | grep -q '"status":"ok"'; then
|
||||
log "scan triggered"
|
||||
else
|
||||
log "ERROR: scan trigger failed — response: ${resp:-<empty/no response>}"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user