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
+122
@@ -0,0 +1,122 @@
|
||||
#!/bin/bash
|
||||
# Wrapper: sync new Bandcamp purchases, then push them through the standard
|
||||
# import-track.sh pipeline so they end up in the Navidrome library tagged
|
||||
# the same way as everything else.
|
||||
#
|
||||
# Reads $ALEMBIC_CONFIG_DIR/pipeline/bandcamp/config.env for username, format pref, etc.
|
||||
# Run as root (cron). Logs to ${ALEMBIC_CONFIG_DIR:-/config}/logs/bandcamp-YYYYMMDD.log.
|
||||
|
||||
set -u
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
export PATH
|
||||
|
||||
CONFIG="${ALEMBIC_CONFIG_DIR:-/config}/pipeline/bandcamp/config.env"
|
||||
LOG=${ALEMBIC_CONFIG_DIR:-/config}/logs/bandcamp-$(date +%Y%m%d).log
|
||||
SYNC_PY=${PIPELINE_DIR:-/app/pipeline}/lib/sync-bandcamp.py
|
||||
IMPORT_ME=${MUSIC_DATA_DIR:-/data/music}/import-me
|
||||
|
||||
mkdir -p "$(dirname "$LOG")"
|
||||
log() { echo "[$(date -Iseconds)] $*" | tee -a "$LOG"; }
|
||||
|
||||
if [[ ! -f "$CONFIG" ]]; then
|
||||
log "ERROR: $CONFIG not found"
|
||||
exit 1
|
||||
fi
|
||||
# shellcheck disable=SC1090
|
||||
source "$CONFIG"
|
||||
|
||||
if [[ ! -f "$BANDCAMP_COOKIES" ]]; then
|
||||
log "ERROR: cookies file missing at $BANDCAMP_COOKIES"
|
||||
log " Export Bandcamp cookies in Netscape format (Get cookies.txt LOCALLY"
|
||||
log " extension, while logged into bandcamp.com), save to that path."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Refuse to run against a dead/empty share: mkdir -p below would otherwise
|
||||
# silently create shadow directories inside the container, downloads would
|
||||
# land there invisibly, and state.json would mark those purchases as done —
|
||||
# permanently skipping them after the mount comes back. `mountpoint -q` (the
|
||||
# original host-side check) doesn't apply to a bind-mounted container path;
|
||||
# a canary file + minimum artist-dir count is the container-compatible
|
||||
# equivalent (same pattern as navidrome-scan.sh's share-health gate).
|
||||
LIB="${MUSIC_DATA_DIR:-/data/music}/Library"
|
||||
CANARY="$LIB/.navidrome-canary"
|
||||
MIN_ARTIST_DIRS=500
|
||||
if [[ ! -r "$CANARY" ]]; then
|
||||
log "ERROR: canary $CANARY missing/unreadable — share looks unhealthy — aborting sync"
|
||||
exit 1
|
||||
fi
|
||||
n=$(find "$LIB" -maxdepth 1 -mindepth 1 -type d 2>/dev/null | wc -l)
|
||||
if [[ "$n" -lt "$MIN_ARTIST_DIRS" ]]; then
|
||||
log "ERROR: only $n artist dirs under $LIB (< $MIN_ARTIST_DIRS) — library looks truncated — aborting sync"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$BANDCAMP_STAGING" "$IMPORT_ME"
|
||||
|
||||
log "=== Bandcamp sync starting ==="
|
||||
log "user=$BANDCAMP_USERNAME staging=$BANDCAMP_STAGING format=$BANDCAMP_FORMAT_PREF"
|
||||
|
||||
if ! python3 "$SYNC_PY" \
|
||||
"$BANDCAMP_USERNAME" \
|
||||
"$BANDCAMP_COOKIES" \
|
||||
"$BANDCAMP_STATE" \
|
||||
"$BANDCAMP_STAGING" \
|
||||
"$BANDCAMP_FORMAT_PREF" >> "$LOG" 2>&1; then
|
||||
log "WARN: sync-bandcamp.py exited non-zero (likely auth issue or network)"
|
||||
fi
|
||||
|
||||
# Anything new? If staging dir has audio, hand it off to import-track.sh.
|
||||
NEW_COUNT=$(find "$BANDCAMP_STAGING" -type f \( -iname "*.flac" -o -iname "*.mp3" -o -iname "*.wav" -o -iname "*.m4a" \) 2>/dev/null | wc -l)
|
||||
if [[ "$NEW_COUNT" -eq 0 ]]; then
|
||||
log "No new files to import"
|
||||
log "=== Bandcamp sync done (no-op) ==="
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "$NEW_COUNT new audio file(s) staged; moving to $IMPORT_ME for import"
|
||||
|
||||
# Move everything from staging into import-me. Preserve the band/album folder
|
||||
# structure since import-track.sh handles directories fine.
|
||||
shopt -s dotglob nullglob
|
||||
for entry in "$BANDCAMP_STAGING"/*; do
|
||||
[[ -e "$entry" ]] || continue
|
||||
mv "$entry" "$IMPORT_ME/" 2>>"$LOG"
|
||||
done
|
||||
shopt -u dotglob nullglob
|
||||
|
||||
# Hand off to the standard manual-import pipeline. No playlist tag — Bandcamp
|
||||
# purchases aren't part of any Spotify playlist. The import-track.sh guard,
|
||||
# albumartist fallback, beets import, and Navidrome scan all kick in normally.
|
||||
log "Calling import-track.sh"
|
||||
if ${PIPELINE_DIR:-/app/pipeline}/bin/import-track.sh >> "$LOG" 2>&1; then
|
||||
log "import-track.sh OK"
|
||||
else
|
||||
log "WARN: import-track.sh exited non-zero (exit $?)"
|
||||
fi
|
||||
|
||||
# Safety net: if anything is stranded in ${MUSIC_DATA_DIR:-/data/music}/downloads (rare with
|
||||
# duplicate_action=keep set in beets config, but possible for files beets
|
||||
# couldn't process), find each one's library counterpart and replace if the
|
||||
# new file is higher quality, OR import as new if there's no counterpart.
|
||||
log "Running replace-with-better safety pass on /downloads stragglers"
|
||||
if ${PIPELINE_DIR:-/app/pipeline}/lib/replace-with-better.sh --apply >> "$LOG" 2>&1; then
|
||||
log "replace-with-better OK"
|
||||
else
|
||||
log "WARN: replace-with-better.sh exited non-zero (exit $?)"
|
||||
fi
|
||||
|
||||
# Now dedupe across the library. With duplicate_action=keep beets imported
|
||||
# every Bandcamp file even when it conflicts with an existing track at the
|
||||
# same path (it creates `.1.ext` siblings). dedup-library.sh's policy is
|
||||
# "FLAC > MP3, then largest file" — Bandcamp version wins, soulseek version
|
||||
# is removed from both the beets DB and disk.
|
||||
log "Running dedup pass (Bandcamp FLAC wins over older Soulseek copies)"
|
||||
if ${PIPELINE_DIR:-/app/pipeline}/lib/dedup-library.sh --apply >> "$LOG" 2>&1; then
|
||||
log "dedup OK"
|
||||
else
|
||||
log "WARN: dedup-library.sh exited non-zero (exit $?)"
|
||||
fi
|
||||
|
||||
log "=== Bandcamp sync done ==="
|
||||
exit 0
|
||||
Reference in New Issue
Block a user