misc-scripts/albumsetup

197 lines
6.2 KiB
Bash
Executable File
Raw Permalink 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 -eu
EXT="flac" # default
errecho() { echo "$*" >&2 ; }
die() { errecho "$*" && exit 1 ; }
clean() {
trap 'exit' INT HUP QUIT EXIT
[ -f "${DEFAULT_PICTURE:-}" ] && rm -f "$DEFAULT_PICTURE"
[ -f "${COVER_PICTURE:-}" ] && rm -f "$COVER_PICTURE"
[ -f "${JSON:-}" ] && rm -f "$JSON"
}
# wrapper to grab a specific tag from flac/opus/mp3
grab_tag() {
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.)
grab_info() {
set +e
DURATION="$(ffprobe -v quiet -of csv=p=0 -show_entries format=duration "$1")"
ARTIST="$(grab_tag "$1" ARTIST)"
ALBUM="$(grab_tag "$1" ALBUM)"
TITLE="$(grab_tag "$1" TITLE)"
ALBUMARTIST="$(grab_tag "$1" ALBUMARTIST)"
TRACKNUMBER="$(printf '%03g' "$(grab_tag "$1" TRACKNUMBER)")"
set -e
}
convert_vid() {
ffmpeg -nostdin ${VERBOSE--loglevel error} -y -loop 1 -framerate 4 -f image2 -i "$1" -i "$2" \
-t "$DURATION" \
-pix_fmt yuv420p \
${acopy:--c:a libopus -b:a 256k} \
-r 4 \
-b:v 500k \
-c:v libvpx \
-deadline realtime \
"$3"
errecho "Successfully converted $2"
}
# extracts cover from $1 to $2
# returns 0 if $2 (output) exists, 1 if not
extract_cover() {
set +e
{
case ${1##*.} in
flac) metaflac --export-picture-to="$2" -- "$1" ;;
opus) opustags --output-cover "$2" -- "$1" ;;
mp3) ffmpeg -nostdin -i "$1" -map "0:v:0" -c:v copy "$2" ;;
*) die 'unknown filetype' ;;
esac
} >/dev/null 2>&1
set -e
# resize within the bounds of 1280x720
# if it's square then make it 722x720 so youtube doesn't make it a short
[ -f "$2" ] && vipsthumbnail -o "$2" -s '722x720' -c "$2" || true
}
# sets COVER_PIC for use in convert_vid
set_cover() {
COVER_PICTURE="$(mktemp -u -t XXXXXX.png)"
extract_cover "$1" "$COVER_PICTURE"
if [ -f "$COVER_PICTURE" ]; then
:
elif [ -f "track$TRACKNUMBER.png" ]; then
cp "track$TRACKNUMBER.png" "$COVER_PICTURE"
else
cp "$DEFAULT_PICTURE" "$COVER_PICTURE"
fi
}
# SCRIPT START #
trap 'clean' INT HUP QUIT EXIT
SONG="" BANDCAMP="" NO_CONVERT=""
OUTDIR="/tmp/albumsetup/${PWD##*/}"
while getopts :vnd:e:p:s:b: OPT; do
case "$OPT" in
v) VERBOSE="" ;; # can use ${var-rep} for this
d) cd "$OPTARG" && OUTDIR="${OUTDIR%/*}/${PWD##*/}" ;;
e) EXT="$OPTARG" ;;
p) tmpcover="$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 "$tmpcover" ] && die "Default cover not specified! (-p IMG)"
mkdir -p "$OUTDIR"
# default cover image, fallback if tracks don't have embedded art
DEFAULT_PICTURE="$(mktemp -u -t XXXXXX.png)"
vipsthumbnail -o "$DEFAULT_PICTURE" -s '722x720' -c "$tmpcover"
# copy audio codec if opus since output codec is opus
[ "$EXT" = "opus" ] && acopy="-c:a copy"
# INDIVIDUAL SONG #
if [ -n "$SONG" ]; then
grab_info "$SONG"
set_cover "$SONG"
# lots of %%/* as to not accidentally create directories
convert_vid "$COVER_PICTURE" "$SONG" "$OUTDIR/SONG ${ARTIST%%/*} - ${TITLE%%/*}.webm"
# INDIVIDUAL TRACKS FOR FULL ALBUM + COMPLETE VID #
else
# make a sorted list of the files by tracknumber first
# so that we don't have to do it individually for everything later
for f in ./*."$EXT"; do
grab_info "$f"
printf '%s\t%s\n' "$TRACKNUMBER" "$f"
done | sort | cut -f 2- > "$OUTDIR/tmp_sorted_list"
total_time=0 # this var helps for more precise timestamps
while read -r f; do
grab_info "$f"
set_cover "$f"
output_file="$OUTDIR/$TRACKNUMBER ${ARTIST%%/*} - ${TITLE%%/*}.webm"
# STUFF FOR INDIVIDUAL VID #
errecho "Converting $f"
[ -z "$NO_CONVERT" ] && convert_vid "$COVER_PICTURE" "$f" "$output_file"
rm -f "$COVER_PICTURE"
# metadata print to send to metadata.txt
printf '%s - %s - %s\n' "${ARTIST:-unknown artist}" "${ALBUM:-unknown album}" "${TITLE:-unknown title}" \
>> "$OUTDIR/metadata.txt"
# build ffmpeg concat metadata
# make safe filename for ffmpeg concat; replace all ' with '\''
sf="$(printf '%s' "$output_file" | sed "s/'/'\\\\''/g")"
# tracklist
printf '%02d:%02d:%02d - %s\n' \
"$((${total_time%%.*} / 3600))" "$((${total_time%%.*} % 3600 / 60))" "$((${total_time%%.*} % 60))" \
"$ARTIST - $TITLE" >> "$OUTDIR/metadata_fullvid.txt"
total_time="$(printf '%s\n' "$total_time + $DURATION" | bc)"
printf "file '%s'\n" "$sf" >> "$OUTDIR/ffmpeg_tracklist.txt"
done < "$OUTDIR/tmp_sorted_list"
[ ! -f "$OUTDIR/metadata.txt" ] && die "No files found!"
if [ -z "$NO_CONVERT" ]; then
errecho "Building full video..."
ffmpeg -nostdin -safe 0 -f concat -i "$OUTDIR/ffmpeg_tracklist.txt" -c copy "$OUTDIR/${ALBUMARTIST%%/*} - ${ALBUM%%/*}.webm"
fi
rm "$OUTDIR/ffmpeg_tracklist.txt"
# 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
rm -f "$DEFAULT_PICTURE"
fi