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:
andrew
2026-07-08 13:10:55 -06:00
commit 68cb007e4c
48 changed files with 9261 additions and 0 deletions
+99
View File
@@ -0,0 +1,99 @@
#!/bin/bash
# ${PIPELINE_DIR:-/app/pipeline}/lib/tag-guard.sh
#
# Shared helper sourced by run-playlist.sh and import-track.sh.
# Moves audio files with missing ARTIST or TITLE tags into a quarantine dir,
# so they never reach beets and rot the library as "[Unknown Album]".
#
# Usage: quarantine_untagged <scan_dir> <quarantine_dir> <log_file>
# Returns: number of files moved (via stdout)
# Separator pattern matching Navidrome's artist split list in navidrome.toml.
# Used by set_albumartist_fallback to extract the primary artist from a multi-
# artist string. Keep these two lists in sync.
#
# Only unambiguous separators here. ", " and " & " are NOT included because they
# appear inside real band names ("Tyler, The Creator", "Simon & Garfunkel",
# "piri & tommy"). For collab strings using those separators, ALBUMARTIST falls
# back to the full string — Navidrome will show one combined artist for the album,
# which is the lesser of two evils vs. corrupting real band names.
_PRIMARY_ARTIST_SEP_PATTERN=' / | feat\. | feat | ft\. | ft |; '
# For each audio file under $scan_dir that has no ALBUMARTIST tag, set
# ALBUMARTIST to the primary artist (everything before the first separator
# in the ARTIST tag). Prevents Navidrome from coining ghost album-artists
# like "Fred Again, The Blessed Madonna" when a track is a collab.
#
# Usage: set_albumartist_fallback <scan_dir> <log_file>
# Returns: number of files updated (via stdout)
set_albumartist_fallback() {
local scan_dir="$1"
local logfile="$2"
local count=0
while IFS= read -r -d '' file; do
case "${file##*.}" in
flac|FLAC)
local cur_aa artist primary
cur_aa=$(metaflac --show-tag=ALBUMARTIST "$file" 2>/dev/null | sed -n 's/^[^=]*=//p' | head -1)
[[ -n "$cur_aa" ]] && continue
artist=$(metaflac --show-tag=ARTIST "$file" 2>/dev/null | sed -n 's/^[^=]*=//p' | head -1)
[[ -z "$artist" ]] && continue
primary=$(echo "$artist" | sed -E "s#(${_PRIMARY_ARTIST_SEP_PATTERN}).*##")
metaflac --set-tag="ALBUMARTIST=${primary}" "$file" 2>>"$logfile"
count=$((count + 1))
;;
mp3|MP3)
local cur_aa artist primary
cur_aa=$(id3v2 -l "$file" 2>/dev/null | sed -n 's/^TPE2[^:]*: //p' | head -1)
[[ -n "$cur_aa" ]] && continue
artist=$(id3v2 -l "$file" 2>/dev/null | sed -n 's/^TPE1[^:]*: //p' | head -1)
[[ -z "$artist" ]] && continue
primary=$(echo "$artist" | sed -E "s#(${_PRIMARY_ARTIST_SEP_PATTERN}).*##")
id3v2 --TPE2 "$primary" "$file" 2>>"$logfile"
count=$((count + 1))
;;
esac
done < <(find "$scan_dir" -type f \( -iname "*.flac" -o -iname "*.mp3" \) -print0 2>/dev/null)
echo "$count"
}
quarantine_untagged() {
local scan_dir="$1"
local quarantine_dir="$2"
local logfile="$3"
local moved=0
mkdir -p "$quarantine_dir"
_has_flac_tags() {
local artist title
artist=$(metaflac --show-tag=ARTIST "$1" 2>/dev/null | sed -n 's/^[^=]*=//p' | head -1)
title=$(metaflac --show-tag=TITLE "$1" 2>/dev/null | sed -n 's/^[^=]*=//p' | head -1)
[[ -n "$artist" && -n "$title" ]]
}
_has_mp3_tags() {
local artist title
artist=$(id3v2 -l "$1" 2>/dev/null | sed -n 's/^TPE1[^:]*: //p' | head -1)
title=$(id3v2 -l "$1" 2>/dev/null | sed -n 's/^TIT2[^:]*: //p' | head -1)
[[ -n "$artist" && -n "$title" ]]
}
while IFS= read -r -d '' file; do
local ok=1
case "${file##*.}" in
flac|FLAC) _has_flac_tags "$file" || ok=0 ;;
mp3|MP3) _has_mp3_tags "$file" || ok=0 ;;
*) ok=0 ;; # unknown format — beets can't handle it anyway
esac
if [[ $ok -eq 0 ]]; then
echo "[$(date -Iseconds)] QUARANTINE: missing artist/title — $(basename "$file")" >> "$logfile"
mv -n "$file" "$quarantine_dir/" 2>>"$logfile"
moved=$((moved + 1))
fi
done < <(find "$scan_dir" -type f \( -iname "*.flac" -o -iname "*.mp3" -o -iname "*.m4a" \) -print0 2>/dev/null)
echo "$moved"
}