misc-scripts/albumsetup

179 lines
5.9 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
set -euf
EXT="flac" # default
NL="
"
errecho() { echo "$*" >&2 ; }
die() { errecho "$*" && exit 1 ; }
clean() {
trap 'exit' INT HUP QUIT EXIT
[ -f "${DEFAULT_PICTURE:-}" ] && rm -f "$DEFAULT_PICTURE"
[ -f "${JSON:-}" ] && rm -f "$JSON"
}
# wrapper to grab a specific tag from flac/opus/mp3
grabtag() {
case ${1##*.} in
flac) metaflac --show-tag="$2" "$1" | cut -d '=' -f 2- ;;
opus) opusinfo "$1" | awk -v RS='\n' -v FS='=' -v OFS='' "/^\\t$2=/"'{$1=""; print $0}' ;;
mp3)
case "$2" in
ARTIST) id3 -q '%_a' "$1" ;;
ALBUM) id3 -q '%_A' "$1" ;;
TRACKNUMBER) id3 -q '%_###T' "$1" ;;
TITLE) id3 -q '%_t' "$1" ;;
ALBUMARTIST) id3 -2 -q "%|%{TPE2}||%{TXXX:ALBUM ARTIST}|?" "$1" ;;
*) printf 'unknown tag used for mp3' ;;
esac
;;
*) die 'unknown filetype'
esac
}
# grab track info, make tracknumber 3-padded just in case for long albums
# (no album has > 999 tracks. I think.)
grabinfo() {
set +e
DURATION="$(ffprobe -v quiet -of csv=p=0 -show_entries format=duration "$1")"
ARTIST="$(grabtag "$1" ARTIST)"
ALBUM="$(grabtag "$1" ALBUM)"
TITLE="$(grabtag "$1" TITLE)"
TRACKNUMBER="$(printf '%03g' "$(grabtag "$1" TRACKNUMBER)")"
set -e
}
ffconv() {
IFS=" "
ffmpeg ${VERBOSE--loglevel error} -y -loop 1 -framerate 4 -f image2 -i "$1" ${FULLALBUM:+-safe 0 -f concat} -i "$2" \
-t "${TOTALTIME:-$DURATION}" \
-pix_fmt yuv420p \
${acopy:--c:a libopus -b:a 256k} \
-r 4 \
-b:v 500k \
-c:v libvpx \
-cpu-used -5 \
-deadline realtime \
"$3"
errecho "Successfully converted $2"
}
extract_cover() {
set +e
_tmpimg="$(mktemp -u -t ALBUMSETUP_COVER.XXXX)"
{
case ${1##*.} in
flac) metaflac --export-picture-to="$tmpimg" -- "$1" ;;
opus) opustags --output-cover "$tmpimg" -- "$1" ;;
mp3) ffmpeg -i "$1" -map "0:v:0" -c:v copy "$tmpimg" ;;
*) die 'unknown filetype' ;;
esac
} >/dev/null
printf '%s' "$_tmpimg"
set -e
}
# GET OPTIONS #
SONG="" FULLALBUM="" BANDCAMP="" NO_CONVERT=""
OUTDIR="/tmp/albumsetup/${PWD##*/}"
while getopts :ovnd:e:p:s:b: OPT; do
case "$OPT" in
o) FULLALBUM=1 ;;
v) VERBOSE="" ;; # can use ${var-rep} for this
d) cd "$OPTARG" && OUTDIR="${OUTDIR%/*}/${PWD##*/}" ;;
e) EXT="$OPTARG" ;;
p) tmpimg="$OPTARG" ;;
s) SONG="$OPTARG" && OUTDIR="${OUTDIR%/*}" ;; # individual song
b) BANDCAMP="$OPTARG" ;; # bandcamp link to extract data
n) NO_CONVERT=1 ;; # don't convert, just get metadata.txt (only affects default albumsetup)
*) die "albumsetup: invalid option: -$OPTARG" ;;
esac
done
shift "$((OPTIND - 1))"
[ ! -f "$tmpimg" ] && die "Default image not specified!"
mkdir -p "$OUTDIR"
# convert cover image. it has to be wider than 1:1 so youtube doesn't convert it to a short
# if image is wider than 1:1, just resize height. if not, pad with black
DEFAULT_PICTURE="$OUTDIR/ALBUMSETUP_IMG.png"
magick convert "$tmpimg" -resize 1280x720 -background black -gravity center -extent 722x720 "$DEFAULT_PICTURE"
trap 'clean' INT HUP QUIT EXIT
[ "$EXT" = "opus" ] && acopy="-c:a copy" # copy audio codec if opus since output codec is opus
# INDIVIDUAL SONG #
if [ -n "$SONG" ]; then
grabinfo "$SONG"
ffconv "$DEFAULT_PICTURE" "$SONG" "$OUTDIR/SONG ${ARTIST%%/*} - ${TITLE%%/*}.webm" # substitution mods are to not create directories
# CONTINUOUS VIDEO OF WHOLE ALBUM #
elif [ -n "$FULLALBUM" ]; then
TOTALTIME=0 # keeping track of timestamps
IFS="$NL"
for f in $(fd -d 1 -e "$EXT"); do
grabinfo "$f"
# make timestamp
printf '%02d:%02d:%02d - %s\n' \
"$((${TOTALTIME%%.*} / 3600))" "$((${TOTALTIME%%.*} % 3600 / 60))" "$((${TOTALTIME%%.*} % 60))" \
"$ARTIST - $TITLE" >> "$OUTDIR/metadata.txt"
# add to total time, but this is as a float remember that
TOTALTIME="$(echo "$TOTALTIME + $DURATION" | bc)"
# build ffmpeg concat metadata
sf="$(printf '%s' "$f" | sed "s/'/'\\\\''/g")" # make safe filename for ffmpeg concat; replace all ' with '\''
echo "file '${PWD}/$sf'" >> "$OUTDIR/ffmpeg_tracklist.txt"
done
[ ! -f "$OUTDIR/ffmpeg_tracklist.txt" ] && die "No files found!"
ffconv "$DEFAULT_PICTURE" "$OUTDIR/tracklist.txt" "$OUTDIR/$ARTIST - $ALBUM.webm"
rm "$OUTDIR/ffmpeg_tracklist.txt"
# INDIVIDUAL TRACKS FOR FULL ALBUM (default) #
else
IFS="$NL"
for f in $(fd -d 1 -e "$EXT"); do
grabinfo "$f"
# metadata print
printf '%s %s - %s - %s\n' "${TRACKNUMBER:-000}" "${ARTIST:-unknown artist}" "${ALBUM:-unknown album}" "${TITLE:-unknown title}"
# try making auto pic
tmpimg="$(extract_cover "$f")"
PICTURE="$tmpimg"
[ ! -f "$PICTURE" ] && PICTURE="$(fd -e jpg -e png "^track$TRACKNUMBER")"
[ ! -f "$PICTURE" ] && PICTURE="$DEFAULT_PICTURE"
errecho "Converting $f"
[ -z "$NO_CONVERT" ] && ffconv "$PICTURE" "$f" "$OUTDIR/$TRACKNUMBER ${ARTIST%%/*} - ${TITLE%%/*}.webm"
[ -f "$tmpimg" ] && rm -f "$tmpimg"
done > "$OUTDIR/metadata.txt"
[ ! -f "$OUTDIR/metadata.txt" ] && die "No files found!"
# sort by correct track numbers then remove track numbers later
sort -o "$OUTDIR/metadata.txt.sorted" "$OUTDIR/metadata.txt"
while read -r line; do
echo "$line" | cut -d ' ' -f 2-
done <"$OUTDIR/metadata.txt.sorted" >"$OUTDIR/metadata.txt"
rm "$OUTDIR/metadata.txt.sorted"
# Bandcamp check and info retrieval
if [ -n "$BANDCAMP" ]; then
JSON="$(mktemp -t "ALBUMSETUP_JSON.XXXX")"
curl -L -s -o - "$BANDCAMP" | pup 'script[type="application/ld+json"]' 'text{}' > "$JSON"
albumartist="$(jq -r '.byArtist.name' < "$JSON")"
date="$(jq -r '.datePublished' < "$JSON")"
date="$(date -d "$date" -u +'%Y-%m-%d')"
desc="$(jq -r 'if (.description) then .description | gsub("[\\r]"; "") else empty end' <"$JSON")"
creds="$(jq -r 'if (.creditText) then .creditText | gsub("[\\r]"; "") else empty end' <"$JSON")"
{
printf '%s - %s\n\n' "$albumartist" "$ALBUM"
cat "$OUTDIR/metadata.txt"
printf '\nReleased %s\nDOWNLOAD: %s\n\n' "$date" "$BANDCAMP"
[ -n "$desc" ] || [ -n "$creds" ] && printf '%s\n' 'Release notes:'
printf '%s\n\n%s' "$desc" "$creds" | sed -e 's/<//g'
} > "$OUTDIR/metadata2.txt"
mv "$OUTDIR/metadata2.txt" "$OUTDIR/metadata.txt"
rm -f "$JSON"
fi
fi