39a5c0ca67
Using the ogg container allows to also embed cover images while still using the opus codec. Also fixed an edge case that would make the script fail if the first thing it iterated on was a regular file which didn't require conversion if the parent directory wasn't already created.
199 lines
5.8 KiB
Bash
Executable file
199 lines
5.8 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
# This code is thrown together lazily to just work and never be touched again.
|
|
# Do NOT try to learn from this piece of shit
|
|
|
|
check_dep() {
|
|
if [ -z "$(command -v "$1")" ]; then
|
|
echo "'$1' is required but not installed."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_deps() {
|
|
deps=("ffmpeg" "opusinfo" "xargs")
|
|
for dep in "${deps[@]}"; do
|
|
check_dep "$dep"
|
|
done
|
|
}
|
|
|
|
args() {
|
|
while [ -n "$1" ];do
|
|
case "$1" in
|
|
"help")
|
|
printf "\n\
|
|
arguments:\n\
|
|
in [input directory] (required) <The flac directory> {default: none}\n\
|
|
out [output directory] (required) <The opus directory> {default: none}\n\
|
|
verify [on/off] (optional) <Check converted files for corruption> {default: on}
|
|
vbr [on/off] (optional) <Toggle variable bit rate> {default: on}
|
|
bitrate [{bitrate}k] (optional) <Set the bitrate to be passed to ffmpeg> {default: 128k}\n\n"
|
|
exit 0
|
|
;;
|
|
"in")
|
|
if [ -z "$2" ]; then
|
|
echo "option '$1' requires an additional argument."
|
|
exit 1
|
|
fi
|
|
|
|
INPUT_DIR="$(realpath "$2")"
|
|
shift
|
|
;;
|
|
"out")
|
|
if [ -z "$2" ]; then
|
|
echo "option '$1' requires an additional argument."
|
|
exit 1
|
|
fi
|
|
|
|
OUTPUT_DIR="$(realpath "$2")"
|
|
shift
|
|
;;
|
|
"vbr")
|
|
if [ -z "$2" ]; then
|
|
echo "option '$1' requires an additional argument."
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$2" != "on" ] && [ "$2" != "off" ]; then
|
|
echo "Invalid option '$2' for $1. Only accepted options are 'on' or 'off'."
|
|
exit 1
|
|
fi
|
|
VBR="$2"
|
|
shift
|
|
;;
|
|
"verify")
|
|
if [ -z "$2" ]; then
|
|
echo "option '$1' requires an additional argument."
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$2" != "on" ] && [ "$2" != "off" ]; then
|
|
echo "Invalid option '$2' for $1. Only accepted options are 'on' or 'off'."
|
|
exit 1
|
|
fi
|
|
VERIFY="$2"
|
|
shift
|
|
;;
|
|
"bitrate")
|
|
if [ -z "$2" ]; then
|
|
echo "option '$1' requires an additional argument."
|
|
exit 1
|
|
fi
|
|
|
|
BITRATE="$2"
|
|
if [[ ! $2 =~ ^[0-9]+k$ ]]; then
|
|
echo "Invalid bitrate '$2', only accepts string matching pattern '[0-9]\\+k'"
|
|
fi
|
|
|
|
shift
|
|
;;
|
|
*)
|
|
echo "Invalid argument '$1', skipping"
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if [ -z "$INPUT_DIR" ]; then
|
|
echo "Missing input directory"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "$OUTPUT_DIR" ]; then
|
|
echo "Missing input directory"
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "$BITRATE" ]; then
|
|
BITRATE="128k"
|
|
fi
|
|
|
|
if [ -z "$VBR" ]; then
|
|
VBR="on"
|
|
fi
|
|
|
|
if [ -z "$VERIFY" ]; then
|
|
VERIFY="on"
|
|
fi
|
|
}
|
|
|
|
get_total_count() {
|
|
local -n ref_total_count="$2"
|
|
total_count="$ref_total_count"
|
|
|
|
local dir="$1"
|
|
for item in "$dir"/*; do
|
|
if [ -f "$item" ]; then
|
|
new_file="${item/"$INPUT_DIR"/"$OUTPUT_DIR"}"
|
|
new_file="${new_file/".flac"/".ogg"}"
|
|
if [ ! -f "$new_file" ] && [[ "$item" == *".flac" ]]; then
|
|
((total_count+=1))
|
|
elif [[ "$item" == *".flac" ]]; then
|
|
if [ "$VERIFY" = "on" ]; then
|
|
printf "Checking \e[93m'%s'\e[0m: " "$(basename "$new_file")"
|
|
if ! opusinfo "$new_file" > /dev/null 2>&1; then
|
|
((total_count+=1))
|
|
printf "\e[31mbad\e[0m\n"
|
|
rm "$new_file"
|
|
else
|
|
printf "\e[32mgood\e[0m\n"
|
|
fi
|
|
fi
|
|
fi
|
|
elif [ -d "$item" ]; then
|
|
get_total_count "$item" "total_count"
|
|
fi
|
|
done
|
|
}
|
|
|
|
iterate_dirs() {
|
|
local dir="$1"
|
|
local conversions=()
|
|
local -n ref_count="$2"
|
|
local total_count="$3"
|
|
count="$ref_count"
|
|
for item in "$dir"/*; do
|
|
item="${item/\$/"\\$"}"
|
|
if [ -f "$item" ]; then
|
|
new_file="${item/"$INPUT_DIR"/"$OUTPUT_DIR"}"
|
|
new_file="${new_file/".flac"/".ogg"}"
|
|
if [ ! -f "$new_file" ]; then
|
|
if [[ "$item" == *".flac" ]]; then
|
|
((count+=1))
|
|
conversions+=("printf '[%s/%s] \e[92m%s\e[0m -> \e[93m%s\e[0m\n' $count $total_count \
|
|
\"$item\" \"$new_file\" && ffmpeg -hide_banner -loglevel error -i \"$item\" -c:a libopus -vbr \"$VBR\" -b:a \"$BITRATE\" \"$new_file\" > /dev/null")
|
|
else
|
|
new_dir=$(dirname "${item/"$INPUT_DIR"/"$OUTPUT_DIR"}")
|
|
if [ ! -d "$new_dir" ]; then
|
|
mkdir -p "$new_dir"
|
|
fi
|
|
echo "Copied $(basename "$item")"
|
|
cp -f "$item" "$new_file"
|
|
fi
|
|
fi
|
|
elif [ -d "$item" ]; then
|
|
new_dir="${item/"$INPUT_DIR"/"$OUTPUT_DIR"}"
|
|
mkdir -p "$new_dir"
|
|
iterate_dirs "$item" "count" "$total_count"
|
|
fi
|
|
done
|
|
|
|
if [ ${#conversions[@]} -gt 0 ]; then
|
|
printf '%s\0' "${conversions[@]}" | xargs -0 -P "$(nproc)" -I {} bash -c '{}'
|
|
fi
|
|
}
|
|
|
|
main () {
|
|
check_deps
|
|
|
|
args "$@"
|
|
|
|
count="0"
|
|
total_count="0"
|
|
get_total_count "$INPUT_DIR" "total_count"
|
|
iterate_dirs "$INPUT_DIR" "count" "$total_count"
|
|
}
|
|
|
|
set -e
|
|
main "$@"
|
|
|