-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshazam
executable file
·165 lines (141 loc) · 4.91 KB
/
shazam
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#!/usr/bin/env bash
#
# Detect currently playing audio and optionally save it to a playlist file.
#
# Adapted from https://github.com/loiccoyle/shazam-cli/tree/main
#
# Changes:
# - Ported to macOS
# - Uses `pctl` script to save tracks to a playlist file with youtube links
#
# Requires curl, ffmpeg, jq
TMP_DIR="/tmp/shazam"
[ ! -d "$TMP_DIR" ] && mkdir "$TMP_DIR"
AUDIO_FILE="$TMP_DIR/recording.dat"
AUDIO_B64_FILE="$TMP_DIR/recording_b64.dat"
PID_FILE="$TMP_DIR/recordingpid"
API_KEY_FILE="${XDG_CONFIG_HOME:-$HOME/.config}/shazam-cli/key"
[ -f "$API_KEY_FILE" ] && API_KEY="$(<"$API_KEY_FILE")"
err_msg_exit() {
# Print an error to stderr and exit.
printf "%s\n" "$*" >&2
exit 1
}
usage() {
printf "Usage: shazam [OPTION]... [FILE]
Query the Shazam music recognition API.
Get free API access at: https://rapidapi.com/apidojo/api/shazam/
The API key can be read from file:
$ echo \"api-key\" > \"%s\"
If no FILE is provided, a recording is made using the AUDIO_SOURCE.
Usage:
-h Show this message and exit.
-a API_KEY API token.
-s AUDIO_SOURCE ffmpeg audio input source, (default: \"default\").
-t RECORDING_TIME Length of recording time, in seconds, (default: 5).
" "$API_KEY_FILE"
}
start_recording() {
# should be mono signed 16 bit little endian
ffmpeg \
-hide_banner \
-f avfoundation -i ":$AUDIO_SOURCE" \
-ac 1 -f s16le -acodec pcm_s16le -ar 44100 \
-y "$AUDIO_FILE" >/dev/null 2>&1 &
printf "%s\n" "$!" >"$PID_FILE"
}
kill_recording() {
# kill with SIGTERM, allowing finishing touches.
local pid
pid="$(<"$PID_FILE")"
kill "$pid"
rm -f "$PID_FILE"
# even after SIGTERM, ffmpeg may still run, so wait till it's done.
while kill -0 "$pid" 2>/dev/null; do
sleep 0.1
done
}
convert() {
# convert audio file to 44100 Hz 16 bit signed little endian mono
ffmpeg -i "$AUDIO_FILE" -ac 1 -f s16le -acodec pcm_s16le -ar 44100 -y "/tmp/shazam/converted.dat" >/dev/null 2>&1
AUDIO_FILE="/tmp/shazam/converted.dat"
}
record() {
start_recording && sleep "$RECORDING_TIME" && kill_recording
}
query() {
base64 < "$AUDIO_FILE" > "$AUDIO_B64_FILE"
response=$(curl --silent -X POST \
'https://shazam.p.rapidapi.com/songs/v2/detect' \
--header 'content-type: text/plain' \
--header 'x-rapidapi-host: shazam.p.rapidapi.com' \
--header "x-rapidapi-key: $API_KEY" \
--data "@$AUDIO_B64_FILE")
# Check if the response contains any matches
matches=$(echo "$response" | jq '.matches')
if [ "$matches" = "[]" ] || [ "$matches" = "null" ]; then
echo "No matches found. Shazam couldn't identify the song."
return
fi
# Extract and print the required information
artist=$(echo "$response" | jq -r '.track.subtitle // "Unknown artist"')
title=$(echo "$response" | jq -r '.track.title // "Unknown title"')
apple_music_url=$(echo "$response" | jq -r '.track.hub.options[] | select(.caption == "OPEN") | .actions[] | select(.type == "uri") | .uri // "Not available"')
# Extract Spotify and YouTube URLs (if available)
spotify_url=$(echo "$response" | jq -r '.track.hub.providers[] | select(.type == "SPOTIFY") | .actions[] | select(.name == "hub:spotify:searchdeeplink") | .uri // "Not available"')
youtube_url=$(echo "$response" | jq -r '.track.hub.providers[] | select(.type == "YOUTUBE") | .actions[] | select(.name == "hub:youtube:searchdeeplink") | .uri // "Not available"')
# Print the extracted information
echo "Artist: $artist"
echo "Title: $title"
echo "YouTube URL: $youtube_url"
echo "Apple Music URL: $apple_music_url"
echo "Spotify URL: $spotify_url"
# Prompt user to save the track
read -p "Do you want to save this track to a playlist? (y/n) " save_choice
if [[ $save_choice =~ ^[Yy]$ ]]; then
pctl ls
read -p "Enter the name of the playlist to save to: " playlist_name
pctl save "$artist" "$title" "$playlist_name"
fi
}
# Defaults
RECORDING_TIME=5 # in seconds
AUDIO_SOURCE="0"
# Parse options
while getopts ":ha:s:t:" opt; do
case $opt in
"h")
usage
exit 0
;;
"a")
API_KEY="$OPTARG"
;;
"s")
AUDIO_SOURCE="$OPTARG"
;;
"t")
RECORDING_TIME="$OPTARG"
;;
"?")
usage >&2
err_msg_exit "Invalid Option: -$OPTARG"
;;
esac
done
shift $((OPTIND - 1))
type curl >/dev/null || err_msg_exit "'curl' not found."
type ffmpeg >/dev/null || err_msg_exit "'ffmpeg' not found."
type jq >/dev/null || err_msg_exit "'jq' not found."
[ -z "$API_KEY" ] && err_msg_exit "shazam: No API_KEY provided. Use the -a option or write it to \"$API_KEY_FILE\""
if [ -z "$1" ]; then
record || exit
else
if [ -f "$1" ]; then
AUDIO_FILE="$1"
convert
else
err_msg_exit "shazam: File \"$1\" not found."
fi
fi
[ -f "$AUDIO_FILE" ] && query