Advertisement
Guest User

reflacker-threaded.sh v01

a guest
Oct 16th, 2019
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 7.41 KB | None | 0 0
  1. #!/bin/bash
  2.  
  3. #######
  4. #
  5. # NAME:
  6. #      reflacker-threaded.sh - A Bash script for re-encoding FLAC files with ReplayGain
  7. #
  8. # SYNOPSIS:
  9. #      reflacker-threaded.sh ROOT_OF_SOURCE_TREE
  10. #
  11. # DESCRIPTION:
  12. #      Re-encode a single folder or an entire folder tree of FLAC files, add ReplayGain,
  13. #      detect and remove ID3 tags while preserving any existing VORBIS comment tags, export
  14. #      and purge embedded album art, with per-folder multithreading.
  15. #
  16. # DEPENDS:
  17. #      file, flac, (GNU) parallel
  18. #
  19. # RECOMMENDS:
  20. #      metaflac, id3v2, date
  21. #
  22. # VERSION: 01
  23. #
  24. #######
  25.  
  26. flac_options="-V8 --force --totally-silent --padding=4096" #
  27.  
  28. parallel_jobs="0" #  "0" - Run as many jobs as possible (or 1 job per CPU core anyway)
  29.                   #  "N" - Run up to N jobs in parallel
  30. #  'parallel -j'  # "-N" - Subtract N from number of CPU cores, run this many jobs in parallel
  31.                   # "+N" - Add N to number of CPU cores, run this many jobs in parallel
  32.  
  33. # enable the following options with "1", any other value disables them
  34.    unembed_artwork="1" # NB: only preserves art embedded in the _first_ flac in a given directory. see lines 93, 95, and 97 for how PADDING blocks are handled, or could be
  35. check_for_id3_tags="1" # NB: currently, after removing id3 tags there's no padding in output, using --padding in $flac_options is advised
  36.    add_replay_gain="1" # attempts to only add replaygain tags to files that don't already have them
  37.  
  38. command -v file >/dev/null 2>&1                             || { printf '\nfile (the program) not found, aborting.\n\n' ;exit 1 ; }
  39. [[ "$( file -b "$( command -v parallel )" )" == "Perl"* ]]  || { printf '\nGNU Parallel not found, aborting.\n\n' ;exit 1 ; }
  40. command -v flac >/dev/null 2>&1                             || { printf '\nflac not found, aborting.\n\n' ;exit 1 ; }
  41. if [[ "$unembed_artwork" == "1" || "$check_for_id3_tags" == "1" || "$add_replay_gain" == "1" ]] ;then
  42.     if ! command -v metaflac >/dev/null 2>&1 ;then
  43.         printf '\nmetaflac not found, disabling _EVERY_FEATURE_ except threaded flac tree re-encoding.\n\n'
  44.         unembed_artwork="0" ;check_for_id3_tags="0" ;add_replay_gain="0"
  45.     fi
  46. fi
  47. if [[ "$check_for_id3_tags" == "1" ]] ;then
  48.     if ! command -v id3v2 >/dev/null 2>&1 ;then
  49.         printf '\nid3v2 (the program) not found. Checking for and removing ID3 tags is disabled.\n\n'
  50.         check_for_id3_tags="0"
  51.     fi
  52. fi
  53.    
  54. [[ "$check_for_id3_tags" == "1" ]] || printf '\nDetection of ID3 tags currently disabled.\nflac will refuse to operate on any FLAC file with an ID3 tag.\n\n'
  55.  
  56. declare -x flac_options parallel_jobs unembed_artwork check_for_id3_tags add_replay_gain # how we get our opaque-as-fuck function to see these variables/values
  57.  
  58. readarray -t -d '' dirs_in_tree < <( find "$1" -type d -print0 ) # https://unix.stackexchange.com/questions/263883/bash-pipe-find-output-into-readarray/263885#263885
  59.  
  60. fail_message() { printf '  ______      _____ _      ______ _____  _
  61. |  ____/\   |_   _| |    |  ____|  __ \| |
  62. | |__ /  \    | | | |    | |__  | |  | | |
  63. |  __/ /\ \   | | | |    |  __| | |  | | |
  64. | | / ____ \ _| |_| |____| |____| |__| |_|
  65. |_|/_/    \_\_____|______|______|_____/(_)
  66.  
  67. '
  68. }
  69.  
  70. actions() {
  71.    
  72.     [[ ! -d "$1" ]] && exit
  73.  
  74.     if [[ "$( ls "$1" | grep -ic \\.flac )" -lt "1" ]] ;then # SC2010: Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.
  75.         exit
  76.     else
  77.         shopt -s nocaseglob
  78.         flacfiles+=( "$1"/*.flac )
  79.         shopt -u nocaseglob
  80.         printf '\n'
  81.     fi
  82.  
  83.     # embedded artwork? make a copy before we CURSE IT! TAKE BACK THOSE 2 MEGABYTES!
  84.     [[ "$unembed_artwork" == "1" ]] && {
  85.         if metaflac --list "${flacfiles[0]}" |grep -A 1 "METADATA block" |grep -q PICTURE ;then
  86.             printf 'Exporting embedded artwork... '
  87.             if metaflac --export-picture-to="$1"/embed_art.unk "${flacfiles[0]}" ;then
  88.                 if grep -q JPEG <<< "$( file -b "$1"/embed_art.unk )" ;then
  89.                     printf 'JPEG format detected.\n'
  90.                     mv "$1"/embed_art.unk "$1"/embed_art.jpg
  91.                 elif grep -q PNG <<< "$( file -b "$1"/embed_art.unk )" ;then
  92.                     printf 'PNG format detected.\n'
  93.                     mv "$1"/embed_art.unk "$1"/embed_art.png
  94.                 elif grep -q GIF <<< "$( file -b "$1"/embed_art.unk )" ;then
  95.                     printf 'GIF format detected.\n'
  96.                     mv "$1"/embed_art.unk "$1"/embed_art.gif
  97.                 else
  98.                     printf 'unable to determine filetype, saved as '\''embed_art.unk'\''.\n'
  99.                 fi
  100.                 metaflac --dont-use-padding --remove --block-type=PICTURE,PADDING "${flacfiles[@]}"
  101.                 # use this one instead I guess, if you aren't adding padding in $flac_options:
  102.                 #metaflac --dont-use-padding --remove --block-type=PICTURE "${flacfiles[@]}"
  103.                 # probably not needed at all, definitely not if all padding is removed in previous command:
  104.                 #metaflac --list --block-type=PADDING "${flacfiles[@]}" |grep -q "is last: false" && metaflac --sort-padding "${flacfiles[@]}"
  105.             else
  106.                 printf 'FAILED!\n'
  107.             fi
  108.         fi
  109.     }
  110.  
  111.     # ID3 tags? CURSE THEM!
  112.     [[ "$check_for_id3_tags" == "1" ]] && {
  113.         if grep -q ID3 <<< "$( file -b "${flacfiles[@]}" )" ;then
  114.             for id3flac in "${flacfiles[@]}" ;do
  115.                 id3temp="$(basename "$id3flac")"
  116.                 if metaflac --export-tags-to="$1/$id3temp".metaflac "$id3flac" ;then
  117.                     id3v2 -D "$id3flac"
  118.                     metaflac --dont-use-padding --remove-all "$id3flac"
  119.                     metaflac --import-tags-from="$1/$id3temp".metaflac "$id3flac" && rm "$1/$id3temp".metaflac
  120.                 else
  121.                     printf 'Tag export failed, aborting ID3 tag removal for %s.\n' "$id3flac"
  122.                 fi
  123.             done
  124.         fi
  125.     }
  126.  
  127.     if [[ "$add_replay_gain" == "1" && "$( metaflac --list --block-type=VORBIS_COMMENT "${flacfiles[0]}" |grep -c REPLAYGAIN )" -ne "5" ]] ;then
  128.         printf 'Re-encoding FLAC file(s) with Replay Gain.\n'
  129.         if flac $flac_options --replay-gain "${flacfiles[@]}" ;then
  130.             printf 'Success! @ %s.\n\n' "$( date +%_I:%M%P 2>/dev/null || printf 'timestamp failure! ...meh' )"
  131.         else
  132.             fail_message
  133.         fi
  134.     else
  135.         printf 'Re-encoding FLAC file(s). 5 Replay Gain tags already exist.\n'
  136.         if flac $flac_options "${flacfiles[@]}" ;then
  137.             printf 'Success! @ %s.\n\n' "$( date +%_I:%M%P 2>/dev/null || printf 'timestamp failure! ...meh' )"
  138.         else
  139.             fail_message
  140.         fi
  141.     fi
  142. }
  143.  
  144. SHELL="$( type -p bash )" # https://stackoverflow.com/a/23815646
  145. export SHELL              # SC2155: Declare and assign separately to avoid masking return values
  146. export -f fail_message actions
  147. trap "killall -HUP parallel" INT # supposed to complete any active jobs and not start any new ones, instead: "^Cparallel: no process found" -- functions are so not frustrating!
  148. parallel --will-cite --bar --tag -j "$parallel_jobs" actions ::: "${dirs_in_tree[@]}"
  149.  
  150.  
  151.  
  152. # TODO/IDEAS/PONDERINGS
  153. # how can we tell when a folder has failed and needs re-doing?
  154. # or tell which folders have been done already if we stop in the middle and start again?
  155.  
  156. # can we "mkfifo failed_folders" and "printf '%s\n' "$1" >> failed_folders" ??
  157. #     if potentially thousands of iterations of the script are being run, seems pretty clear mkfifo shouldn't run in every one
  158. #     can all the iterations even write to the same fifo? _without_ breaking somehow??
  159. # is a simple text file in /tmp easier? does that work when more than one iteration of the script tries to add a line at the same time?
  160.  
  161. # does flac do the same as "metaflac --sort-padding" to any existing padding (or even just
  162. # replace any existing padding when re-encoding a flac file and using the -P/--padding option ??
  163.  
  164. # flac --force leaves behind source files when their extension includes uppercase characters
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement