-
Notifications
You must be signed in to change notification settings - Fork 0
/
musicbase.sh
228 lines (207 loc) · 6.71 KB
/
musicbase.sh
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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#!/bin/bash
set -e
print_help(){
cat << 'EOF'
A kid3-based utility to build a complete music library database. Requires kid3-common and kid3-qt. The non-qt version of kid3 does not work with this, AFAIK.
Usage: musicbase.sh DIRPATH [option]
options:
-h display this help file
-k user-defined header string with delimiters
-l user-defined format codes with delimiters
-m minimum subdirectory depth from top directory of music library to music files (default: 1)
-n no database header
-o specify output file name and path (default: $HOME/.musiclib.dsv)
-q quiet - hide terminal output
-s sort database output by specified column number
Generates a music library database using music file tag data with kid3-cli/kid3-qt export tools.
Processes data from music files at the DIRPATH specified. Default output filetype is data separated
values (DSV) with carat (^) as the delimiter. Database records include the path to each music file.
Default header and format codes can be overridden using -k and -l options.
Defaults:
"Artist^Album^AlbumArtist^SongTitle^SongPath^Genre^SongLength^Rating"
"%{artist}^%{album}^%{albumartist}^%{title}^%{filepath}^%{genre}^%{seconds}000^%{popm}"
Time to complete varies by processor and can take >10 minutes for large libraries. Check output
quality more quickly by testing on a subdirectory.
EOF
}
kid3qtrunning(){
# Determine whether kid3-qt is running, prompt user to close and continue processing
local kidrunning="$(pgrep "kid3-qt")"
if [ -n "$kidrunning" ]
then
# prompt user to kill kid3-qt or exit program
echo -n "Kid3-qt cannot be running for this utility to work. Close kid3-qt now ([Y]/n)?"
read -r proceed
if [ "$proceed" == "${proceed#[Yn]}" ]
then
#local PID="$(pidof kid3-qt)"
kill -s HUP "$kidrunning"
else
printf 'Goodbye, then.\n'
exit 0
fi
fi
}
# Verify user provided required, valid path
if [ -z "$1" ]
then
printf '%s\n' "Missing required argument: path to music directory."
print_help
exit 1
fi
if [ -d "$1" ]; then
libpath=$1
shift
else
if [ "$1" == "-h" ]; then
print_help
exit 1
fi
printf 'This directory does not exist: '
printf '%s\n' "$1"
exit 1
fi
# Set default variables
kid3confpath=$"$HOME/.config/Kid3/Kid3.conf"
dirdepth=1
outpath=$"$HOME/.musiclib.dsv"
showdisplay=1
inclheader=1
defheader="Artist^Album^AlbumArtist^SongTitle^SongPath^Genre^SongLength^Rating"
exportcodes="%{artist}^%{album}^%{albumartist}^%{title}^%{filepath}^%{genre}^%{seconds}000^%{popm}"
sortcolumn=""
# Use getops to set any user-assigned options
while getopts ":hk:l:m:no:qs:" opt; do
case $opt in
h) # display Help
print_help
exit 0;;
k)
defheader=$OPTARG
;;
l)
exportcodes=$OPTARG
;;
m)
dirdepth=$OPTARG
shift
;;
n)
inclheader=0 >&2
;;
o)
outpath=$OPTARG
;;
q)
showdisplay=0 >&2
;;
s)
sortcolumn=$OPTARG
;;
\?)
printf 'Invalid option: -%s\n' "$OPTARG"
exit 1
;;
:)
printf 'Option requires an argument: %s\n' "$OPTARG"
exit 1
;;
esac
done
shift $((OPTIND-1))
# Verify kid3-qt is not running
kid3qtrunning
# Get list of music subdirectories, using first variable $libpath for library folder, e.g. /mnt/vboxfiles/music
find "$libpath" -mindepth "$dirdepth" -type d > /tmp/albumdirs;
if [ $showdisplay == 0 ]
then
printf '%s\n' "Locating all subdirectories under this path..." > /dev/null 2>&1
else
printf '%s\n' "Locating all subdirectories under this path..."
fi
# Backup kid3-qt config-> $HOME/.config/Kid3/Kid3.conf to /tmp
cp "$HOME/.config/Kid3/Kid3.conf" /tmp
# Add musicbase export format to $HOME/.config/Kid3/Kid3.conf
exportformatidx="$(grep -oP '(?<=ExportFormatIdx=)[0-9]+' "$kid3confpath")"
# add comma and space to end of ExportFormatHeaders string
sed -in '/^ExportFormatHeaders/ s/$/, /' "$kid3confpath"
# add count of 1 to existing value of ExportFormatIdx
(( exportformatidx++ ))
sed -i '/ExportFormatIdx.*/c\ExportFormatIdx='"$exportformatidx" "$kid3confpath"
# add comma, space and value 'musicbase' to end of ExportFormatNames string
sed -in '/^ExportFormatNames/ s/$/, musicbase/' "$kid3confpath"
# add comma, space and format string to end of ExportFormatTracks string
sed -in '/^ExportFormatTracks/ s/$/, '"$exportcodes"'/' "$kid3confpath"
# add comma and space to the end of ExportFormatTrailers string
sed -in '/^ExportFormatTrailers/ s/$/, /' "$kid3confpath"
# Build music library database
if [ $showdisplay == 0 ]
then
printf '%s\n' "Building database. This can take time for kid3-cli to process, especially for large music libraries..." > /dev/null 2>&1
else
printf '%s\n' "Building database. This can take time for kid3-cli to process, especially for large music libraries..."
fi
# This is for the spinner, to show the program is working
if [ $showdisplay == 1 ]
then
i=1
sp="/-\|"
echo -n ' '
else
printf ''
fi
# Add header to the database file
if [ $inclheader == 1 ]
then
echo "$defheader" > "$outpath"
else
rm "$outpath"
fi
# Loop through the albumdirs file using kid3-cli to read the tag info and add it to the database file,
# while running the spinner to show operation
while IFS= read -r line; do
kid3-cli -c "export /tmp/musiclib.dsv musicbase "$exportcodes"" "$line"
if [ $showdisplay = 0 ]
then
cat /tmp/musiclib.dsv >> "$outpath"
else
tee -a "$outpath" < /tmp/musiclib.dsv
fi
if [ $showdisplay == 0 ]
then
printf '' > /dev/null 2>&1
else
printf '\b%s' "${sp:i++%${#sp}:1}"
fi
done < /tmp/albumdirs
# Sort library order using file path column, preserving position of header, and replace library file
# First, check whether a sort order is specified, then whether a header is specified.
if [ -n "${sortcolumn}" ]
then
if [ $inclheader == 1 ]
then
(head -n 1 "$outpath" && tail -n +2 "$outpath" | sort -k"$sortcolumn" -t '^') > /tmp/musiclib.dsv
else # do not preserve header, not used
(tail -n +2 "$outpath" | sort -k"$sortcolumn" -t '^') > /tmp/musiclib.dsv
fi
else
if [ $inclheader == 1 ]
then
(head -n 1 "$outpath" && tail -n +2 "$outpath") > /tmp/musiclib.dsv
else # do not preserve header, not used
(tail -n +2 "$outpath") > /tmp/musiclib.dsv
fi
fi
cp /tmp/musiclib.dsv "$outpath"
if [ $showdisplay == 0 ]
then
printf '%s\n' "Finished! Output: $outpath" > /dev/null 2>&1
else
printf '%s\n' "Finished! Output: $outpath"
fi
rm /tmp/musiclib.dsv
# Replace $HOME/.config/Kid3/Kid3.conf with backed up tmp copy
rm "$HOME/.config/Kid3/Kid3.conf"
cp /tmp/Kid3.conf "$HOME/.config/Kid3"
#EOF
exportformatidx=$((exportformatidx+1))