#!/bin/bash # saner programming env: these switches turn some bugs into errors set -o errexit -o pipefail -o noclobber -o nounset source="-" dest="-" verbose=true help=false GetOptions() { # https://stackoverflow.com/a/29754866 ! getopt --test > /dev/null if [[ ${PIPESTATUS[0]} -ne 4 ]]; then VerboseOutput "Fatal" "\`getopt --test\` failed" echo "Sorry, It seems that your shell is not supported" echo "If you're using mac or another unix-like system, please install GNU getopt" exit 1 fi # Parsing style without -s or -d source=${*: -2:1} dest=${*: -1:1} OPTIONS=s:d:vh LONGOPTS=source:,dest:,verbose,help # -use ! and PIPESTATUS to get exit code with errexit set # -temporarily store output to be able to check for errors # -activate quoting/enhanced mode (e.g. by writing out “--options”) # -pass arguments only via -- "$@" to separate them correctly ! PARSED=$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@") if [[ ${PIPESTATUS[0]} -ne 0 ]]; then # e.g. return value is 1 # then getopt has complained about wrong arguments to stdout Usage exit 2 fi # read getopt’s output this way to handle the quoting right: eval set -- "$PARSED" verbose=false # now enjoy the options in order and nicely split until we see -- while true; do case "$1" in -v|--verbose) verbose=true shift ;; -h|--help) help=true shift ;; -s|--source) source="$2" shift 2 ;; -d|--dest) dest="$2" shift 2 ;; --) shift break ;; *) echo "Programming error" return 3 ;; esac done if [[ $dest == "" ]] || [[ $source == "" ]]; then help=true fi } Usage() { echo "" echo "Usage:" echo "music-sync -s|--source -d|--dest " echo "music-sync " echo "" echo "Syncronises music from one folder to another." echo "" echo "Options:" echo " -s, --source The source folder of the music" echo " -d, --dest The destionation folder of the music" echo " -v, --verbose Enable verbose output" echo " -h, --help Display this help text" echo "" } VerboseOutput() { if [[ "$verbose" = true ]]; then echo "[$1] $2" >&2 fi } CreateFileList() { # ${1} /mnt/hdd/Example-Artist/Example-Album # ${2} /mnt/mtp/Example-Artist/Example-Album # ${3} Example-Artist/Example-Album/ IFS="" sourcepath="${1}/*" for file in $sourcepath; do relfile="${file#"$1/"}" if [[ -d "${1}/$relfile" ]]; then newdir="${3}/$relfile" newdir=${newdir#"/"} VerboseOutput "Info" "Entering $newdir" CreateFileList "${1}/$relfile" "${2}/$relfile" "$newdir" elif [[ ! -f "${2}/$relfile" || "${1}/$relfile" -nt "${2}/$relfile" ]]; then echo ${3}/$relfile >> /tmp/music-sync-filelist VerboseOutput "Info" "Added: ${3}/${relfile}" fi done } ConvertFiles() { mkdir -p /tmp/converted while read -r line do VerboseOutput "Info" "Converting $line" if [[ "/tmp/converted/$line" = */* ]]; then mkdir -p "/tmp/converted/${line%/*}"; fi; lame -b 192 $source/$line /tmp/converted/$line 1>/dev/null 2>/dev/null VerboseOutput "Info" "Converted $line" done < "/tmp/music-sync-filelist" } CopyFiles() { while read -r line do VerboseOutput "Info" "Copy $line" if [[ "$dest/$line" = */* ]]; then mkdir -p "$dest/${line%/*}"; fi; cp -f $source/$line $dest/$line 1>/dev/null 2>/dev/null done < "/tmp/music-sync-filelist" VerboseOutput "Info" "Copied $line" } CleanUp() { VerboseOutput "Info" "Cleaning Up" rm "/tmp/music-sync-filelist" rm -rf "/tmp/converted" VerboseOutput "Info" "Done" } GetOptions $@ if [[ $help == true ]]; then Usage exit fi CreateFileList $source $dest "" if [[ ! -f /tmp/music-sync-filelist ]]; then VerboseOutput "Info" "Nothing to do!" exit 0 fi ConvertFiles CopyFiles CleanUp