find-convert-move.sh 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. #!/usr/bin/env bash
  2. set -euo pipefail # bash strict mode
  3. IFS=$'\n\t'
  4. display_help(){
  5. echo "This script converts audio files of specified extensions to another specified extension and maintains directory structure."
  6. echo "Usage: ${0##*/} -p <output-path> -i <input-extensions> -o <output-extension> [music-path/s]"
  7. echo "Example: ${0##*/} -p /mnt/16gb_pendrive -i flac,wav,ogg -o mp3 ~/Music/Bjork\ Discography ~/Music/MikeOldfield Discography ..."
  8. echo "Options: "
  9. echo -e "\t -i -- Input extensions to search for (default: ${input_ext})"
  10. echo -e "\t -o -- Output extension to convert to (default: ${output_ext})"
  11. echo -e "\t -p -- Path to store converted files (default: ${output_path})"
  12. echo -e "\t -f -- Force overwrite existing files"
  13. echo -e "\t -h -- Display this help message"
  14. exit 2
  15. }
  16. extract_cover(){
  17. input_file_path="$1"
  18. output_file_path="$2"
  19. # ffmpeg -y -i "$1" -an -vcodec copy "${output_file_path}/cover.jpg"
  20. find "$input_file_path" -type f -iname "cover*" -exec cp {} "${output_file_path}/" \; || \
  21. ffmpeg -y -i "$1" -an -vcodec copy "${output_file_path}/cover.jpg"
  22. }
  23. cover_present_in(){
  24. path="$1"
  25. find "$path" -type f -iregex "\(folder\|cover\)\.\(png\|jpe?g\)"
  26. }
  27. ffmpeg_convert(){
  28. input_file="$1"
  29. output_file="$2"
  30. echo "Starting conversion..."
  31. ffmpeg "${force:--n}" -i "$input_file" \
  32. -vsync 2 -threads 4 \
  33. "$output_file" &>/dev/null
  34. if [[ $? -eq 0 ]]; then
  35. echo "Converted ${input_file} --> ${output_file}"
  36. else
  37. echo "Non zero exit code? Remove &/dev/null"
  38. fi
  39. }
  40. wait_on_max_bg_process(){
  41. if [[ $(pgrep ffmpeg | wc -w) -ge ${max_processes:-20} ]]; then
  42. wait $!
  43. fi
  44. }
  45. # default values
  46. output_path="."
  47. input_ext=".flac\|.wav\|.ogg\|.m4a"
  48. output_ext="opus"
  49. max_processes=10
  50. while getopts ':p:i:o:fDh' opt; do
  51. case "$opt" in
  52. p)output_path="${OPTARG%*/}" ;; # making sure to not end with /
  53. i)input_ext="${OPTARG//,/\\|}" ;; # substitute "," to "\|" for -regex
  54. o)output_ext="$OPTARG" ;;
  55. f)force="-y" ;;
  56. D)delete_source=1 ;;
  57. h|\?|:|*) display_help ;;
  58. esac
  59. done
  60. shift $((OPTIND-1)) # next parameters without flags
  61. # check if nessesary variables are correctly specified
  62. [[ ! -d $output_path || $# -lt 1 ]] && display_help
  63. for input_directory in "$@"; do
  64. [[ ! -d $input_directory ]] && echo "Not a directory: ${input_directory}" && continue
  65. mapfile -t input_files < <(find "$input_directory" -mount -type f -regex ".*\(${input_ext}\)$")
  66. for input_file in "${input_files[@]}"; do
  67. output_file="${output_path}/${input_file%.*}.${output_ext}"
  68. output_file_path="${output_file%/*}"
  69. [[ ! -d $output_file_path ]] && mkdir -p "${output_file_path}"
  70. input_file_path="${input_file%/*}"
  71. if [[ $output_file_path != "${old_path:-}" && ! $(cover_present_in "$input_file_path") ]]; then
  72. extract_cover "$input_file" "$output_file_path"
  73. old_path="$output_file_path"
  74. fi
  75. ffmpeg_convert "$input_file" "$output_file" &
  76. wait_on_max_bg_process
  77. [[ ${delete_source:-} -eq 1 ]] && rm "$input_file"
  78. done
  79. done
  80. wait
  81. echo "FINISHED"