Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash
- #######
- #
- # NAME:
- # reflacker-threaded.sh - A Bash script for re-encoding FLAC files with ReplayGain
- #
- # SYNOPSIS:
- # reflacker-threaded.sh ROOT_OF_SOURCE_TREE
- #
- # DESCRIPTION:
- # Re-encode a single folder or an entire folder tree of FLAC files, add ReplayGain,
- # detect and remove ID3 tags while preserving any existing VORBIS comment tags, export
- # and purge embedded album art, with per-folder multithreading.
- #
- # DEPENDS:
- # file, flac, (GNU) parallel
- #
- # RECOMMENDS:
- # metaflac, id3v2, date
- #
- # VERSION: 01
- #
- #######
- flac_options="-V8 --force --totally-silent --padding=4096" #
- parallel_jobs="0" # "0" - Run as many jobs as possible (or 1 job per CPU core anyway)
- # "N" - Run up to N jobs in parallel
- # 'parallel -j' # "-N" - Subtract N from number of CPU cores, run this many jobs in parallel
- # "+N" - Add N to number of CPU cores, run this many jobs in parallel
- # enable the following options with "1", any other value disables them
- 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
- check_for_id3_tags="1" # NB: currently, after removing id3 tags there's no padding in output, using --padding in $flac_options is advised
- add_replay_gain="1" # attempts to only add replaygain tags to files that don't already have them
- command -v file >/dev/null 2>&1 || { printf '\nfile (the program) not found, aborting.\n\n' ;exit 1 ; }
- [[ "$( file -b "$( command -v parallel )" )" == "Perl"* ]] || { printf '\nGNU Parallel not found, aborting.\n\n' ;exit 1 ; }
- command -v flac >/dev/null 2>&1 || { printf '\nflac not found, aborting.\n\n' ;exit 1 ; }
- if [[ "$unembed_artwork" == "1" || "$check_for_id3_tags" == "1" || "$add_replay_gain" == "1" ]] ;then
- if ! command -v metaflac >/dev/null 2>&1 ;then
- printf '\nmetaflac not found, disabling _EVERY_FEATURE_ except threaded flac tree re-encoding.\n\n'
- unembed_artwork="0" ;check_for_id3_tags="0" ;add_replay_gain="0"
- fi
- fi
- if [[ "$check_for_id3_tags" == "1" ]] ;then
- if ! command -v id3v2 >/dev/null 2>&1 ;then
- printf '\nid3v2 (the program) not found. Checking for and removing ID3 tags is disabled.\n\n'
- check_for_id3_tags="0"
- fi
- fi
- [[ "$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'
- 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
- 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
- fail_message() { printf ' ______ _____ _ ______ _____ _
- | ____/\ |_ _| | | ____| __ \| |
- | |__ / \ | | | | | |__ | | | | |
- | __/ /\ \ | | | | | __| | | | | |
- | | / ____ \ _| |_| |____| |____| |__| |_|
- |_|/_/ \_\_____|______|______|_____/(_)
- '
- }
- actions() {
- [[ ! -d "$1" ]] && exit
- 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.
- exit
- else
- shopt -s nocaseglob
- flacfiles+=( "$1"/*.flac )
- shopt -u nocaseglob
- printf '\n'
- fi
- # embedded artwork? make a copy before we CURSE IT! TAKE BACK THOSE 2 MEGABYTES!
- [[ "$unembed_artwork" == "1" ]] && {
- if metaflac --list "${flacfiles[0]}" |grep -A 1 "METADATA block" |grep -q PICTURE ;then
- printf 'Exporting embedded artwork... '
- if metaflac --export-picture-to="$1"/embed_art.unk "${flacfiles[0]}" ;then
- if grep -q JPEG <<< "$( file -b "$1"/embed_art.unk )" ;then
- printf 'JPEG format detected.\n'
- mv "$1"/embed_art.unk "$1"/embed_art.jpg
- elif grep -q PNG <<< "$( file -b "$1"/embed_art.unk )" ;then
- printf 'PNG format detected.\n'
- mv "$1"/embed_art.unk "$1"/embed_art.png
- elif grep -q GIF <<< "$( file -b "$1"/embed_art.unk )" ;then
- printf 'GIF format detected.\n'
- mv "$1"/embed_art.unk "$1"/embed_art.gif
- else
- printf 'unable to determine filetype, saved as '\''embed_art.unk'\''.\n'
- fi
- metaflac --dont-use-padding --remove --block-type=PICTURE,PADDING "${flacfiles[@]}"
- # use this one instead I guess, if you aren't adding padding in $flac_options:
- #metaflac --dont-use-padding --remove --block-type=PICTURE "${flacfiles[@]}"
- # probably not needed at all, definitely not if all padding is removed in previous command:
- #metaflac --list --block-type=PADDING "${flacfiles[@]}" |grep -q "is last: false" && metaflac --sort-padding "${flacfiles[@]}"
- else
- printf 'FAILED!\n'
- fi
- fi
- }
- # ID3 tags? CURSE THEM!
- [[ "$check_for_id3_tags" == "1" ]] && {
- if grep -q ID3 <<< "$( file -b "${flacfiles[@]}" )" ;then
- for id3flac in "${flacfiles[@]}" ;do
- id3temp="$(basename "$id3flac")"
- if metaflac --export-tags-to="$1/$id3temp".metaflac "$id3flac" ;then
- id3v2 -D "$id3flac"
- metaflac --dont-use-padding --remove-all "$id3flac"
- metaflac --import-tags-from="$1/$id3temp".metaflac "$id3flac" && rm "$1/$id3temp".metaflac
- else
- printf 'Tag export failed, aborting ID3 tag removal for %s.\n' "$id3flac"
- fi
- done
- fi
- }
- if [[ "$add_replay_gain" == "1" && "$( metaflac --list --block-type=VORBIS_COMMENT "${flacfiles[0]}" |grep -c REPLAYGAIN )" -ne "5" ]] ;then
- printf 'Re-encoding FLAC file(s) with Replay Gain.\n'
- if flac $flac_options --replay-gain "${flacfiles[@]}" ;then
- printf 'Success! @ %s.\n\n' "$( date +%_I:%M%P 2>/dev/null || printf 'timestamp failure! ...meh' )"
- else
- fail_message
- fi
- else
- printf 'Re-encoding FLAC file(s). 5 Replay Gain tags already exist.\n'
- if flac $flac_options "${flacfiles[@]}" ;then
- printf 'Success! @ %s.\n\n' "$( date +%_I:%M%P 2>/dev/null || printf 'timestamp failure! ...meh' )"
- else
- fail_message
- fi
- fi
- }
- SHELL="$( type -p bash )" # https://stackoverflow.com/a/23815646
- export SHELL # SC2155: Declare and assign separately to avoid masking return values
- export -f fail_message actions
- 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!
- parallel --will-cite --bar --tag -j "$parallel_jobs" actions ::: "${dirs_in_tree[@]}"
- # TODO/IDEAS/PONDERINGS
- # how can we tell when a folder has failed and needs re-doing?
- # or tell which folders have been done already if we stop in the middle and start again?
- # can we "mkfifo failed_folders" and "printf '%s\n' "$1" >> failed_folders" ??
- # if potentially thousands of iterations of the script are being run, seems pretty clear mkfifo shouldn't run in every one
- # can all the iterations even write to the same fifo? _without_ breaking somehow??
- # 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?
- # does flac do the same as "metaflac --sort-padding" to any existing padding (or even just
- # replace any existing padding when re-encoding a flac file and using the -P/--padding option ??
- # flac --force leaves behind source files when their extension includes uppercase characters
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement