summaryrefslogtreecommitdiff
path: root/import_music.sh
blob: bf6c1aa92ee6a8f6e22683908ca66aedf276b29b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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 ==="