Harden fix-genre, sync-bandcamp, upgrade-mp3-to-flac under strict mode (R1)

- fix-genre.sh: set -euo pipefail; guard the tag-remove metaflac calls and the
  'beet ls | head -5' verify (SIGPIPE) that would otherwise abort.
- sync-bandcamp.sh: set -euo pipefail; the destructive chain already used
  'if cmd; then..else WARN' (set -e exempt); guard the staging mv.
- upgrade-mp3-to-flac.sh: set -euo pipefail; capture sldl/replace-with-better
  exit codes without aborting (was 'cmd; RC=$?', which set -e breaks); read
  Soulseek creds from the first available .conf instead of a hardcoded y2k.conf,
  guarded; guard the xargs purge and a grep -c.
- pipeline-status.sh: deliberately kept at set -u (documented). It is read-only
  and assembles ~30 independent probes; set -e would abort the whole digest on
  one missing optional file, which is exactly how the 9am notification broke.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
andrew
2026-07-10 10:52:44 -06:00
parent 41ef26a40b
commit db13890fe1
4 changed files with 41 additions and 20 deletions
+22 -13
View File
@@ -19,16 +19,18 @@
# upgrade-mp3-to-flac.sh # run the scanner end-to-end
# upgrade-mp3-to-flac.sh --csv-only # just write the CSV; don't run sldl
set -u
set -euo pipefail
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export PATH
# These helpers are the same ones import-track.sh sources and runs under its
# own set -euo pipefail on every manual import, so they are already strict-safe.
# shellcheck source=${PIPELINE_DIR:-/app/pipeline}/lib/tag-guard.sh
source ${PIPELINE_DIR:-/app/pipeline}/lib/tag-guard.sh
source "${PIPELINE_DIR:-/app/pipeline}/lib/tag-guard.sh"
# shellcheck source=${PIPELINE_DIR:-/app/pipeline}/lib/prep-audio.sh
source ${PIPELINE_DIR:-/app/pipeline}/lib/prep-audio.sh
source "${PIPELINE_DIR:-/app/pipeline}/lib/prep-audio.sh"
# shellcheck source=${PIPELINE_DIR:-/app/pipeline}/lib/mb-tags.sh
source ${PIPELINE_DIR:-/app/pipeline}/lib/mb-tags.sh
source "${PIPELINE_DIR:-/app/pipeline}/lib/mb-tags.sh"
CSV_ONLY=0
[[ "${1:-}" == "--csv-only" ]] && CSV_ONLY=1
@@ -72,11 +74,19 @@ if [[ $CSV_ONLY -eq 1 ]]; then
exit 0
fi
# Pull credentials from any playlist conf (they're all the same)
SOULSEEK_USER=$(sed -n 's/^user *= *//p' ${ALEMBIC_CONFIG_DIR:-/config}/pipeline/y2k.conf | tr -d ' ')
SOULSEEK_PASS=$(sed -n 's/^pass *= *//p' ${ALEMBIC_CONFIG_DIR:-/config}/pipeline/y2k.conf | tr -d ' ')
# Pull Soulseek credentials from any rendered playlist conf (they all carry the
# same user/pass). Don't hardcode a specific playlist name: pick the first
# non-underscore .conf that exists. Guarded so a missing conf yields empty
# creds (sldl then fails and is handled) rather than aborting under set -e.
_CRED_CONF=$(ls "${ALEMBIC_CONFIG_DIR:-/config}"/pipeline/*.conf 2>/dev/null | grep -v '/_' | head -1 || true)
SOULSEEK_USER=$(sed -n 's/^user *= *//p' "${_CRED_CONF:-/nonexistent}" 2>/dev/null | tr -d ' ' || true)
SOULSEEK_PASS=$(sed -n 's/^pass *= *//p' "${_CRED_CONF:-/nonexistent}" 2>/dev/null | tr -d ' ' || true)
log "Running sldl with --format flac (HARD requirement, no MP3/WAV fallback)"
# sldl routinely exits non-zero (skipped/partial searches), which is normal
# here. Capture the code without letting set -e abort: init to 0, override in
# the || branch. (`cmd; RC=$?` would abort at cmd before RC=$? ran.)
SLDL_EXIT=0
"$SLDL_BIN" \
"$CSV_HOST" \
--input-type csv \
@@ -92,8 +102,7 @@ log "Running sldl with --format flac (HARD requirement, no MP3/WAV fallback)"
--no-browse-folder \
--no-skip-existing \
--verbose \
>> "$LOG" 2>&1
SLDL_EXIT=$?
>> "$LOG" 2>&1 || SLDL_EXIT=$?
log "sldl exit code: $SLDL_EXIT"
# Guard: this script is FLAC-upgrade-only. If sldl ever drops anything else
@@ -103,7 +112,7 @@ NON_FLAC=$(find "$STAGING_HOST" -type f ! -iname "*.flac" ! -name "*.incomplete"
if [[ -n "$NON_FLAC" ]]; then
log "Purging non-FLAC files from staging:"
echo "$NON_FLAC" | tee -a "$LOG"
echo "$NON_FLAC" | xargs -r rm -f
echo "$NON_FLAC" | xargs -r rm -f || true
fi
NEW_FLAC_COUNT=$(find "$STAGING_HOST" -type f -iname "*.flac" 2>/dev/null | wc -l)
@@ -149,8 +158,8 @@ log "Pre-tagged $PREPPED file(s)"
# the replacing FLAC before the swap, so playlist M3Us still resolve and the
# FLAC inherits spotify-retag's canonical metadata.
log "Running replace-with-better.sh on staging (--copy-tags-from-existing)"
${PIPELINE_DIR:-/app/pipeline}/lib/replace-with-better.sh --apply --copy-tags-from-existing "$STAGING_HOST" >> "$LOG" 2>&1
RBE_EXIT=$?
RBE_EXIT=0
${PIPELINE_DIR:-/app/pipeline}/lib/replace-with-better.sh --apply --copy-tags-from-existing "$STAGING_HOST" >> "$LOG" 2>&1 || RBE_EXIT=$?
log "replace-with-better exit: $RBE_EXIT"
# Regenerate playlist M3Us. Upgraded tracks have new paths (FLAC vs MP3) but
@@ -164,7 +173,7 @@ while IFS= read -r playlist; do
[[ -z "$playlist" ]] && continue
M3U_OUT="${PLAYLISTS_DIR}/${playlist}.m3u8"
BEET_OUTPUT=$(beet ls -f '$path' "grouping:${playlist}" 2>>"$LOG" || true)
TRACK_COUNT=$(echo -n "$BEET_OUTPUT" | grep -c '^')
TRACK_COUNT=$(echo -n "$BEET_OUTPUT" | grep -c '^' || true)
[[ "$TRACK_COUNT" -gt 0 ]] || continue
{ echo "#EXTM3U"; echo "$BEET_OUTPUT"; } > "$M3U_OUT"
log " $playlist.m3u8 — $TRACK_COUNT tracks"