diff options
Diffstat (limited to 'import_music.sh')
| -rwxr-xr-x | import_music.sh | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/import_music.sh b/import_music.sh new file mode 100755 index 0000000..bf6c1aa --- /dev/null +++ b/import_music.sh @@ -0,0 +1,131 @@ +#!/bin/bash +# Import, transcode, and organize music from slskd downloads +# Usage: ./import_music.sh [--dry-run] [--keep-flac] + +INGEST_DIR="/disks/Plex/Music/_ingest" +LIBRARY_DIR="/disks/Plex/Music" +GROUP="mediaserver" +BITRATE="128k" + +DRY_RUN=false +KEEP_FLAC=false + +for arg in "$@"; do + case $arg in + --dry-run) DRY_RUN=true ;; + --keep-flac) KEEP_FLAC=true ;; + esac +done + +echo "=== Music Import Started ===" +$DRY_RUN && echo "DRY RUN MODE" + +# Skip these directories +shopt -s extglob + +cd "$INGEST_DIR" || exit 1 + +for album_dir in */; do + [[ ! -d "$album_dir" ]] && continue + dir_name="${album_dir%/}" + + # Skip special dirs + [[ "$dir_name" == "incomplete" ]] && continue + [[ "$dir_name" == "downloads" ]] && continue + + # Count audio files + audio_count=$(ls -1 "$album_dir"*.flac "$album_dir"*.mp3 "$album_dir"*.opus 2>/dev/null | wc -l) + [[ $audio_count -lt 2 ]] && continue + + echo "" + echo "Processing: $dir_name ($audio_count files)" + + # Get first audio file for metadata + first_file=$(ls "$album_dir"*.flac "$album_dir"*.mp3 2>/dev/null | head -1) + [[ -z "$first_file" ]] && continue + + # Extract metadata + artist=$(ffprobe -v quiet -show_entries format_tags=artist -of default=noprint_wrappers=1:nokey=1 "$first_file" 2>/dev/null) + album_artist=$(ffprobe -v quiet -show_entries format_tags=album_artist -of default=noprint_wrappers=1:nokey=1 "$first_file" 2>/dev/null) + album=$(ffprobe -v quiet -show_entries format_tags=album -of default=noprint_wrappers=1:nokey=1 "$first_file" 2>/dev/null) + + # Prefer album_artist over artist + [[ -n "$album_artist" ]] && artist="$album_artist" + + # Clean for filesystem + artist=$(echo "$artist" | tr -d '<>:"/\\|?*' | sed 's/\.$//') + album=$(echo "$album" | tr -d '<>:"/\\|?*' | sed 's/\.$//') + + if [[ -z "$artist" ]] || [[ -z "$album" ]]; then + echo " ⚠ Missing metadata, skipping" + continue + fi + + dest_dir="$LIBRARY_DIR/$artist/$album" + echo " → $artist / $album" + + if $DRY_RUN; then + echo " [DRY RUN] Would transcode to $dest_dir" + continue + fi + + mkdir -p "$dest_dir" + + # Transcode FLACs + for flac in "$album_dir"*.flac "$album_dir"*.FLAC; do + [[ ! -f "$flac" ]] && continue + + base=$(basename "$flac") + # Remove .flac extension properly + name="${base%.[Ff][Ll][Aa][Cc]}" + opus_out="$dest_dir/${name}.opus" + + echo " Transcoding: $name" + ffmpeg -hide_banner -loglevel error -i "$flac" \ + -c:a libopus -b:a "$BITRATE" -vbr on \ + -map_metadata 0 -y "$opus_out" + + [[ -f "$opus_out" ]] && chgrp "$GROUP" "$opus_out" 2>/dev/null + done + + # Remove any FLACs from destination (we only want Opus there) + for flac in "$dest_dir"/*.flac "$dest_dir"/*.FLAC; do + [[ -f "$flac" ]] && rm "$flac" + done + + # Copy non-FLAC audio + for audio in "$album_dir"*.mp3 "$album_dir"*.m4a "$album_dir"*.ogg; do + [[ -f "$audio" ]] && cp "$audio" "$dest_dir/" + done + + # Copy artwork + for art in "$album_dir"*.jpg "$album_dir"*.png "$album_dir"cover.* "$album_dir"folder.*; do + [[ -f "$art" ]] && cp "$art" "$dest_dir/" + done + + # Fix permissions + chgrp -R "$GROUP" "$dest_dir" 2>/dev/null + chmod -R g+rw "$dest_dir" 2>/dev/null + + # Run beets for tagging + echo " Running beets..." + beet import -q "$dest_dir" 2>/dev/null + if [[ $? -eq 0 ]]; then + echo " ✓ Beets tagging complete" + else + echo " ⚠ Beets tagging skipped or failed (check manually)" + fi + + # Verify + new_count=$(ls -1 "$dest_dir"/*.opus "$dest_dir"/*.mp3 2>/dev/null | wc -l) + if [[ $new_count -ge 3 ]]; then + echo " ✓ Imported $new_count files" + rm -rf "$INGEST_DIR/$dir_name" + echo " ✓ Cleaned source" + else + echo " ✗ Verification failed" + fi +done + +echo "" +echo "=== Done ===" |
