summaryrefslogtreecommitdiff
path: root/rmpc/utils/fetch_album_lyrics.sh
blob: cfc0d901c8790755d8210af751f409bc2f12a77f (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
#!/usr/bin/env bash
set -euo pipefail

# Usage: fetch_album_lyrics_simple.sh "/path/to/Artist/Album"
# Example: fetch_album_lyrics_simple.sh "$HOME/Music/mpd/Anderson .Paak/Ventura"

LRCLIB_API="https://lrclib.net/api/get"

if [ $# -ne 1 ]; then
    echo "Usage: $0 \"/path/to/Artist/Album\""
    exit 1
fi

ALBUM_DIR="$1"
if [ ! -d "$ALBUM_DIR" ]; then
    echo "Error: '$ALBUM_DIR' is not a directory."
    exit 1
fi

ARTIST="$(basename "$(dirname "$ALBUM_DIR")")"
ALBUM="$(basename "$ALBUM_DIR")"

# Try to fetch synced lyrics (only the [mm:ss.xx] lines) for a given title
# Arguments:
#   $1 = artist
#   $2 = album
#   $3 = title_to_try
# Returns stdout = JSON .syncedLyrics (or "null"/empty)
get_lyrics_for() {
    local artist="$1"
    local album="$2"
    local title_try="$3"

    curl -sG \
        --data-urlencode "artist_name=${artist}" \
        --data-urlencode "track_name=${title_try}" \
        --data-urlencode "album_name=${album}" \
        "$LRCLIB_API" \
        | jq -r '.syncedLyrics'
}

# Attempt a single fetch:
#   1) Try with TITLE_RAW (may include “(feat ...)”)
#   2) If that yields "" or "null", strip “(…)" and retry
#   3) If still no lyrics, give up
#   4) If we do get lyrics, write them verbatim to the .lrc file
#
# Arguments:
#   $1 = ARTIST
#   $2 = ALBUM
#   $3 = TITLE_RAW
#   $4 = OUTPUT_LRC_FILE (full path, e.g. /.../Song.lrc)
fetch_for_plain() {
    local artist="$1"
    local album="$2"
    local title_try="$3"
    local out_lrc="$4"

    # 1. First-pass lookup
    local lyrics
    lyrics="$(get_lyrics_for "$artist" "$album" "$title_try")"

    # 2. If empty or "null", try stripping "(...)" from title
    if [ -z "$lyrics" ] || [ "$lyrics" == "null" ]; then
        local stripped
        stripped="$(echo "$title_try" | sed -E 's/ *\([^)]*\)//g')"
        if [ "$stripped" != "$title_try" ]; then
            title_try="$stripped"
            lyrics="$(get_lyrics_for "$artist" "$album" "$title_try")"
        fi
    fi

    # 3. If still empty/null → skip
    if [ -z "$lyrics" ] || [ "$lyrics" == "null" ]; then
        echo "✗ No lyrics for: \"$title_try\""
        return 1
    fi

    # 4. Write only the synced‐lyrics lines (timestamps + text)
    #    We drop any existing [ar:], [al:], [ti:] lines from the API payload,
    #    but typically lrclib returns only timestamped lines anyway.
    echo "$lyrics" | sed -E '/^\[(ar|al|ti):/d' > "$out_lrc"
    echo "✔ Saved lyrics: $(basename "$out_lrc")"
    return 0
}

echo "▶ Fetching lyrics for all .mp3 in: $ALBUM_DIR"
echo "  Artist: $ARTIST"
echo "  Album:  $ALBUM"
echo

shopt -s nullglob
for mp3 in "$ALBUM_DIR"/*.mp3; do
    TITLE_RAW="$(basename "$mp3" .mp3)"
    LRC_FILE="${mp3%.mp3}.lrc"

    if [ -f "$LRC_FILE" ]; then
        echo "– Skipping \"$TITLE_RAW\" (already have .lrc)"
        continue
    fi

    if ! fetch_for_plain "$ARTIST" "$ALBUM" "$TITLE_RAW" "$LRC_FILE"; then
        # a failure just prints the “No lyrics for…” message and moves on
        continue
    fi
done

echo
echo "Done."