543f10e662
run-playlist.sh and import-track.sh had the same beets->#EXTM3U block, but import-track.sh wrote the file non-atomically. Move it to pipeline/lib/m3u.sh as regen_m3u <name> <out>, sourced by both. The helper always writes atomically (temp + rename), so a reader like Navidrome never sees a partial file and a stray wrong-owner leftover .m3u8 is replaced without a chown. Returns 0 always (empty result is a warning), so it's safe as a standalone call under set -e. Verified: tests/test_m3u.py (atomic write with tracks, no file when empty; 44 tests green) plus a live regen against the real library (techno -> 229 tracks, no temp leftover). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>