chore(unitproc/bkt-checkInt):Use 'must' instead of 'try'
[BK-2020-03.git] / user / mp3s_to_opus.sh
1 #!/bin/bash
2 # Desc: Converts a directory of mp3s into a single opus file
3 # Usage: mp3s_to_opus.sh [DIR in] [DIR out] [BITRATE]
4 # Example: mp3s_to_opus.sh ./dir_source ./dir_output 48k
5 # Depends: GNU Coretils 8.32 (date)
6 # Version: 0.0.3
7
8 # plumbing
9 opus_bitrate="$3"; # e.g. "48k"
10 script_rundate="$(date +%s)";
11 dir_tmp="/dev/shm";
12 dir_in="$(readlink -f "$1")";
13 dir_out="$(readlink -f "$2")";
14 file_flist="$dir_tmp"/"$script_rundate"..flist.txt;
15 file_out_opus="$dir_out"/output.opus;
16 file_albumart="$dir_out"/albumart.png;
17
18 yell() { echo "$0: $*" >&2; } # print script path and all args to stderr
19 die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status
20 must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails
21 show_usage() {
22 # Desc: Display script usage information
23 # Usage: showUsage
24 # Version 0.0.2
25 # Input: none
26 # Output: stdout
27 # Depends: GNU-coreutils 8.30 (cat)
28 cat <<'EOF'
29 USAGE:
30 mp3s_to_opus.sh [DIR in] [DIR out] [BITRATE]
31
32 EXAMPLE:
33 mp3s_to_opus.sh ./source_dir ./out_dir 48k
34 EOF
35 } # Display information on how to use this script.
36 check_depends() {
37 if ! command -v ffmpeg; then show_usage; die "FATAL:Missing ffmpeg."; fi;
38 }; # check dependencies
39 check_plumbing() {
40 if [[ $# -ne 3 ]]; then show_usage; die "FATAL:Invalid arg count:$#"; fi;
41 if [[ ! -d "$dir_in" ]]; then show_usage; die "FATAL:Not a dir:$dir_in"; fi;
42 if [[ ! -d "$dir_out" ]]; then mkdir -p "$2"; fi;
43 }; # check arguments
44 build_filelist() {
45 # Depends: var dir_tmp temporary directory
46 # var dir_in input dir
47 # var file_flist path file list
48 # Output: file: $file_flist list of mp3 files for ffmpeg
49
50 # Change directory to input dir
51 pushd "$dir_in" || die "FATAL:Directory error:$(pwd)";
52
53 while read -r line; do
54 yell "$(printf "file '%s'\n" "${line#./}")";
55 printf "file '%s'\n" "${line#./}" >> "$file_flist";
56 done < <(find "$dir_in" -type f -iname "*.mp3" | sort);
57
58 # Return to original dir
59 popd || die "FATAL:Directory error:$(pwd)";
60
61 }; # build file list for ffmpeg
62 ffmpeg_convert() {
63 # Depends: var dir_tmp
64 # dir_in
65 # dir_out
66 # Input: file $file_flist list of mp3 files for ffmpeg
67
68 # Change directory to input dir
69 pushd "$dir_in" || die "FATAL:Directory error:$(pwd)";
70
71 # Concatenate mp3 files into a single WAV file
72 # # Convert WAV to 48 kbps opus file
73 ffmpeg -f concat -safe 0 -i "$file_flist" -c:a pcm_s24le -rf64 auto -f wav - | \
74 ffmpeg -i - -c:a libopus -b:a "$opus_bitrate" "$file_out_opus";
75
76 # Return to original dir
77 popd || die "FATAL:Directory error:$(pwd)";
78 }; # convert mp3s to opus via ffmpeg
79 save_albumart() {
80 local file
81 file="$(find "$dir_in" -type f -iname "*.mp3" | sort | head -n1)";
82 file="$(readlink -f "$file")";
83 ffmpeg -i "$file" -an -vcodec copy "$file_albumart";
84 }; # save album art from an mp3 to output dir
85 main() {
86 check_depends && yell "DEBUG:check_depends OK";
87 check_plumbing "$@" && yell "DEBUG:check_plumbing OK";
88 build_filelist "$@" && yell "DEBUG:build_filelist OK";
89 ffmpeg_convert "$@" && yell "DEBUG:ffmpeg_convert OK";
90 save_albumart "$@" && yell "DEBUG:save_albumart OK";
91 }; # main program
92
93 main "$@";
94