feat: --decorate-as
This commit is contained in:
16
src/main.sh
16
src/main.sh
@@ -360,6 +360,21 @@ case "${1:-}" in
|
|||||||
fi
|
fi
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
|
"--decorate-as")
|
||||||
|
# Decorate the specified directory as given MusicBrainz release
|
||||||
|
#
|
||||||
|
# @argument $2: path
|
||||||
|
# @argument $3: MusicBrainz release ID
|
||||||
|
[ ! "${2:-}" ] && err "You did not specify a directory." && exit 1
|
||||||
|
[ ! -d "$2" ] && err "Path $2 does not point to a directory." && exit 1
|
||||||
|
[ ! "${3:-}" ] && err "You did not specify a MusicBrainz release ID." && exit 1
|
||||||
|
[ ! "$(mb_release "$3" | $JQ '.title // ""')" ] && err "Did you specify a correct MusicBrainz release ID?" && exit 1
|
||||||
|
if ! decorate_as "$2" "$3"; then
|
||||||
|
err "Something went wrong."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
"--reload-database")
|
"--reload-database")
|
||||||
# Reload database of local music
|
# Reload database of local music
|
||||||
#
|
#
|
||||||
@@ -392,6 +407,7 @@ GENERAL OPTIONS:
|
|||||||
|
|
||||||
MANAGE LOCAL MUSIC:
|
MANAGE LOCAL MUSIC:
|
||||||
--decorate <path> Decorate directory containing a tagged release
|
--decorate <path> Decorate directory containing a tagged release
|
||||||
|
--decorate-as <path> <mbid> Decorate directory as the relase <mbid>
|
||||||
--reload-database <path> Populate database with decorated local music from <path>
|
--reload-database <path> Populate database with decorated local music from <path>
|
||||||
EOF
|
EOF
|
||||||
exit 0
|
exit 0
|
||||||
|
@@ -103,7 +103,8 @@ __api_mb() {
|
|||||||
errormsg=$($JQ -e '.error // ""' "$tmpout")
|
errormsg=$($JQ -e '.error // ""' "$tmpout")
|
||||||
if [ "$errormsg" ]; then
|
if [ "$errormsg" ]; then
|
||||||
err "Failed to fetch MusicBrainz data for $1 $2: $errormsg"
|
err "Failed to fetch MusicBrainz data for $1 $2: $errormsg"
|
||||||
[ "$errormsg" = "Not Found" ] && break
|
echo "$errormsg" | grep -q -i "not found" && break
|
||||||
|
echo "$errormsg" | grep -q -i "invalid" && break
|
||||||
sleep "$SLEEP_ON_ERROR"
|
sleep "$SLEEP_ON_ERROR"
|
||||||
else
|
else
|
||||||
cat "$tmpout"
|
cat "$tmpout"
|
||||||
|
@@ -83,6 +83,97 @@ decorate() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Decorate locally available music with specified MusicBrainz release
|
||||||
|
#
|
||||||
|
# @input $1: Path to directory with album
|
||||||
|
# @input $2: MusicBrainz release ID
|
||||||
|
#
|
||||||
|
# Similar as `decorate`, but the MusicBrainz IDs are not inferred from the
|
||||||
|
# tags, but passed as argument.
|
||||||
|
decorate_as() {
|
||||||
|
if [ -f "$1/$DECORATION_FILENAME" ]; then
|
||||||
|
rid="$($JQ '.releaseid' "$1/$DECORATION_FILENAME")"
|
||||||
|
title="$(mb_release "$rid" | $JQ '.title // ""')"
|
||||||
|
artist="$(mb_release "$rid" | $JQ '."artist-credit" | map([.name, .joinphrase] | join("")) | join("")')"
|
||||||
|
[ "$rid" = "$2" ] &&
|
||||||
|
info "Directory $1 has already been decorated as the release '$title' - '$artist' with the identical MusicBrainz release ID." ||
|
||||||
|
info "Directory $1 has already been decorated as the release '$title' - '$artist' with the MusicBrainz release ID $rid."
|
||||||
|
while true; do
|
||||||
|
infonn "Do you want to redecorate $1? (yes/no)"
|
||||||
|
read -r yn
|
||||||
|
case $yn in
|
||||||
|
"yes") break ;;
|
||||||
|
"no") return 0 ;;
|
||||||
|
*) info "Please answer \"yes\" or \"no\"." ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
# Print info
|
||||||
|
title="$(mb_release "$2" | $JQ '.title // ""')"
|
||||||
|
artist="$(mb_release "$2" | $JQ '."artist-credit" | map([.name, .joinphrase] | join("")) | join("")')"
|
||||||
|
info "Decorating $1 as the release $title by $artist"
|
||||||
|
# Start decoration
|
||||||
|
decoration=$($JQ -n '.tracks = {}')
|
||||||
|
tmpf=$(mktemp)
|
||||||
|
(cd "$1" && find . -type f -iname '*.mp3' -o -iname '*.mp4' -o -iname '*.flac' -o -iname '*.m4a' | sort) >"$tmpf"
|
||||||
|
# Compare number of tracks with release
|
||||||
|
rcnt="$(mb_release "$2" | $JQ '.media | map(."track-count") | add')"
|
||||||
|
dcnt="$(wc -l "$tmpf" | cut -d ' ' -f 1)"
|
||||||
|
if [ ! "$rcnt" -eq "$dcnt" ]; then
|
||||||
|
err "Number of tracks in directory ($dcnt) does not match number of tracks in release ($rcnt)."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
#
|
||||||
|
tmpj=$(mktemp)
|
||||||
|
mb_release "$2" |
|
||||||
|
$JQ '.media[] |
|
||||||
|
.position as $pos |
|
||||||
|
.tracks |
|
||||||
|
map({
|
||||||
|
$pos,
|
||||||
|
"id": .id,
|
||||||
|
"n": .number,
|
||||||
|
"t": .title
|
||||||
|
}) |
|
||||||
|
map(if(.n | type == "string" and test("^[0-9]+$")) then .n |= tonumber else . end) |
|
||||||
|
sort_by([.pos, .n])[] |
|
||||||
|
[.t, .id] |
|
||||||
|
join("\t")' >"$tmpj"
|
||||||
|
assocfile=$(mktemp)
|
||||||
|
awk -F '\t' '
|
||||||
|
BEGIN { OFS = "\t" }
|
||||||
|
FNR == NR { title[FNR] = $1; id[FNR] = $2 }
|
||||||
|
FNR != NR { fname[FNR] = $1 }
|
||||||
|
END { for (i in id) print title[i], id[i], fname[i] }
|
||||||
|
' "$tmpj" "$tmpf" >"$assocfile"
|
||||||
|
rm -f "$tmpj" "$tmpf"
|
||||||
|
# Ask user if this is ok
|
||||||
|
info "We discovered the following associatoin:"
|
||||||
|
while IFS= read -r line; do
|
||||||
|
t="$(echo "$line" | cut -d "$(printf '\t')" -f 1)"
|
||||||
|
f="$(echo "$line" | cut -d "$(printf '\t')" -f 3)"
|
||||||
|
printf "Track '%s'\tFile '%s'\n" "$t" "$f"
|
||||||
|
done <"$assocfile" | column -t -s "$(printf '\t')"
|
||||||
|
while true; do
|
||||||
|
infonn "Are the track correctly associated to the audio files? (yes/no)"
|
||||||
|
read -r yn
|
||||||
|
case $yn in
|
||||||
|
"yes") break ;;
|
||||||
|
"no") return 0 ;;
|
||||||
|
*) info "Please answer \"yes\" or \"no\"." ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
# Construct decoration
|
||||||
|
decoration=$($JQ -n '.tracks = {}')
|
||||||
|
while IFS= read -r line; do
|
||||||
|
i="$(echo "$line" | cut -d "$(printf '\t')" -f 2)"
|
||||||
|
f="$(echo "$line" | cut -d "$(printf '\t')" -f 3)"
|
||||||
|
decoration=$(echo "$decoration" | $JQ ".tracks += {\"$i\": \"$f\"}")
|
||||||
|
done <"$assocfile"
|
||||||
|
echo "$decoration" | $JQ ".releaseid = \"$2\"" >"$1/$DECORATION_FILENAME"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# Load missing cache entries (batch mode)
|
# Load missing cache entries (batch mode)
|
||||||
#
|
#
|
||||||
# argument $1: type
|
# argument $1: type
|
||||||
|
@@ -25,3 +25,8 @@ err() {
|
|||||||
info() {
|
info() {
|
||||||
echo "$(date) [$$]>${INFO}Info:${OFF} ${1:-}" | tee -a "$LOGFILE" | cut -d ">" -f 2- >/dev/stderr
|
echo "$(date) [$$]>${INFO}Info:${OFF} ${1:-}" | tee -a "$LOGFILE" | cut -d ">" -f 2- >/dev/stderr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Like `info` but without newlnes on stderr.
|
||||||
|
infonn() {
|
||||||
|
echo "$(date) [$$]>${INFO}Info:${OFF} ${1:-}" | tee -a "$LOGFILE" | cut -d ">" -f 2- | tr '\n' ' ' >/dev/stderr
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user