#!/usr/bin/env bash
input="${DIR_INPUT:-/mnt/elfstone2/syncthing/Music}";
output="${DIR_OUTPUT:-/mnt/elfstone2/auto/Music-Portable}";
export input;
export output;
temp_dir="$(mktemp --tmpdir -d "portable-music-copy-XXXXXXX")";
on_exit() {
rm -rf "${temp_dir}";
}
trap on_exit EXIT;
do_downmux() {
local source="${1}";
local target="${2}";
set +e;
ffmpeg -hide_banner -loglevel warning -nostats -i "${source}" -map_metadata 0 -id3v2_version 4 -c:v copy -disposition:v:0 attached_pic -ar 44100 -b:a 256k -f mp3 "${target}";
exit_code="${?}";
if [[ "${exit_code}" -ne 0 ]] && [[ -f "${target}" ]]; then
rm "${target}";
fi
return "${exit_code}";
}
do_copy() {
local source="${1}";
local target="${2}";
echo -n "cp ";
cp "${source}" "${target}";
}
compress_image() {
local source="${1}";
temp_file_png="$(mktemp --tmpdir="${temp_dir}" XXXXXXX.png)";
temp_file_jpeg="$(mktemp --tmpdir="${temp_dir}" XXXXXXX.jpeg)";
convert "${source}" -resize 256x256\> "${temp_file_jpeg}" >&2 &
convert "${source}" -resize 256x256\> "${temp_file_png}" >&2 &
wait
jpegoptim --quiet --all-progressive --preserve "${temp_file_jpeg}" >&2 &
optipng -quiet -fix -preserve "${temp_file_png}" >&2 &
wait
read -r size_png _ < <(wc --bytes "${temp_file_png}");
read -r size_jpeg _ < <(wc --bytes "${temp_file_jpeg}");
if [[ "${size_png}" -gt "${size_jpeg}" ]]; then
rm -rf "${temp_file_png}";
echo "${temp_file_jpeg}";
else
rm -rf "${temp_file_jpeg}";
echo "${temp_file_png}";
fi
}
process_file() {
local filename="${1}";
local extension="${filename##*.}";
local orig_destination="${output}/${filename}";
local destination="${orig_destination}";
echo -n "[file] ${filename}: ";
local do_downmux=false;
if [[ "${extension}" == "flac" ]] || [[ "${extension}" == "ogg" ]] || [[ "${extension}" == "mp3" ]] || [[ "${extension}" == "m4a" ]]; then
probejson="$(ffprobe -hide_banner -v quiet -show_format -print_format json "${filename}")";
is_above_256k="$(echo "${probejson}" | jq --raw-output '(.format.bit_rate | tonumber) > 256000')";
exit_code="${?}";
if [[ "${exit_code}" -ne 0 ]]; then
echo -n "ffprobe failed; falling back on ";
do_downmux=false;
elif [[ "${is_above_256k}" == "true" ]]; then
do_downmux=true;
fi
fi
if [[ "${do_downmux}" == "true" ]]; then
echo -n "downmuxing/";
destination="${orig_destination%.*}.mp3";
fi
case "${extension}" in
png|jpg|jpeg|JPG|JPEG )
local compressed_image; compressed_image="$(compress_image "${filename}")";
local compressed_extension="${compressed_image##*.}";
destination="${orig_destination%.*}.${compressed_extension}";
;;
esac
if [[ -f "${destination}" ]] || [[ -f "${orig_destination}" ]]; then
echo "exists in destination; skipping";
return 0;
fi
local destination_dir; destination_dir="$(dirname "${destination}")";
if [[ ! -d "${destination_dir}" ]]; then
mkdir -p "${destination_dir}";
fi
case "${extension}" in
flac|mp3|ogg )
if [[ "${do_downmux}" == "false" ]]; then
do_copy "${filename}" "${orig_destination}";
else
echo -n "ffmpeg ";
do_downmux "${filename}" "${destination}";
exit_code="$?";
if [[ "${exit_code}" -ne 0 ]]; then
echo "failed, exit code ${exit_code}: falling back on ";
do_copy "${filename}" "${orig_destination}";
fi
fi
;;
png|jpg|jpeg|JPG|JPEG )
mv "${compressed_image}" "${destination}";
;;
* )
do_copy "${filename}" "${destination}";
;;
esac
echo "done";
}
export temp_dir;
export -f process_file;
export -f compress_image;
export -f do_downmux;
export -f do_copy;
cd "${input}" || { echo "Error: Failed to cd to input directory"; exit 1; };
find -type f -not -path '*/.stversions/*' -print0 | nice -n20 xargs -P "$(nproc)" -0 -n1 -I{} bash -c 'process_file "{}"';
echo "[ ${SECONDS} ] Setting permissions";
chown -R root:root "${output}";
chmod -R 0644 "${output}";
chmod -R ugo+X "${output}";
echo "[ ${SECONDS} ] Portable music copy update complete";