bash-music-sync/music-sync.sh

253 lines
5.6 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
begin=$(date +"%s")
# saner programming env: these switches turn some bugs into errors
set -o errexit -o pipefail -o noclobber -o nounset
source="-"
dest="-"
verbose=2
help=false
CheckDeps() {
# Check getopt
! getopt --test > /dev/null
if [[ ${PIPESTATUS[0]} -ne 4 ]]; then
VerboseOutput 5 "\`getopt --test\` failed"
VerboseOutput 5 "Sorry, It seems that your shell is not supported"
VerboseOutput 5 "If you're using MacOS or another unix-like system, please install GNU getopt"
ExecTime
exit 1
fi
# Check lame
if [[ ! $(lame --version 2>/dev/null) ]]; then
VerboseOutput 5 "\`lame --version\` failed"
VerboseOutput 5 "Sorry, It seems that lame is not installed on your system"
VerboseOutput 5 "Please install lame from your repositories and make sure it is available in your \$PATH"
ExecTime
exit 1
fi
}
GetOptions() {
# https://stackoverflow.com/a/29754866
# Parsing style without -s or -d
source=${*: -2:1}
dest=${*: -1:1}
OPTIONS=s:d:v::h
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 getopts output this way to handle the quoting right:
eval set -- "$PARSED"
# now enjoy the options in order and nicely split until we see --
while true; do
case "$1" in
-v|--verbose)
verbose=2
if [[ $2 != "" ]]; then
verbose=${2}
shift
fi
shift
;;
-h|--help)
help=true
shift
;;
-s|--source)
source="$2"
shift 2
;;
-d|--dest)
dest="$2"
shift 2
;;
--)
shift
break
;;
*)
VerboseOutput 5 "Programming error"
return 3
;;
esac
done
if [[ $dest == "" ]] || [[ $source == "" ]]; then
help=true
fi
}
Usage() {
echo ""
echo "Usage:"
echo "music-sync <options> -s|--source <source> -d|--dest <destination>"
echo "music-sync <options> <source> <destination>"
echo ""
echo "Syncronises music from one folder to another."
echo ""
echo "Options:"
echo " -s, --source <source> The source folder of the music"
echo " -d, --dest <destination> The destionation folder of the music"
echo " -v, --verbose <0-6> Set log level"
echo " -h, --help Display this help text"
echo ""
echo "Log levels:"
echo " 0 | Verbose"
echo " 1 | Debug"
echo " 2 | Info (Default)"
echo " 3 | Warning"
echo " 4 | Error"
echo " 5 | Fatal"
echo " 6 | No logging"
echo ""
echo "Exit Codes:"
echo " 1 Dependencies not met"
echo " 2 Invalid Argument"
echo " 3 Source Unreachable"
echo " 4 Destination Unreachable"
echo ""
}
VerboseOutput() {
level=""
if [[ $verbose -le $1 ]]; then
case "$1" in
0)
level="\033[1;36mVerbose\033[0m"
;;
1)
level="\033[1;34m Debug \033[0m"
;;
2)
level="\033[1;37m Info \033[0m"
;;
3)
level="\033[1;33mWarning\033[0m"
;;
4)
level="\033[1;31m Error \033[0m"
;;
5)
level="\033[1;30m Fatal \033[0m"
;;
esac
echo -e "[$level] $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 1 "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 2 "Added: ${3}/${relfile}"
fi
done
}
ConvertFiles() {
mkdir -p /tmp/converted
while read -r line
do
if [[ ! -f "${source}/$file" ]]; then
VerboseOutput 5 "Source-file ${source}/$file Unreachable"
ExecTime
exit 3
fi
VerboseOutput 1 "Converting: $line"
if [[ "/tmp/converted/$line" = */* ]]; then
mkdir -p "/tmp/converted/${line%/*}";
fi;
if [[ ! -f "/tmp/converted/$line" || "${source}/$file" -nt "/tmp/converted/$line" ]]; then
lame -b 192 $source/$line /tmp/converted/$line 1>/dev/null 2>/dev/null
VerboseOutput 2 "Converted: $line"
else
VerboseOutput 3 "$line already converted"
fi;
done < "/tmp/music-sync-filelist"
}
CopyFiles() {
while read -r line
do
if [[ ! -f "$dest" ]]; then
VerboseOutput 5 "Destination unreachable"
ExecTime
exit 4
fi
if [[ ! -f "$line" ]]; then
VerboseOutput 5 "Source-file ${source}/$file Unreachable"
ExecTime
exit 3
fi
VerboseOutput 1 "Copying: $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 2 "Copied: $line"
}
CleanUp() {
VerboseOutput 1 "Cleaning Up"
rm "/tmp/music-sync-filelist"
rm -rf "/tmp/converted"
VerboseOutput 1 "Done"
}
ExecTime() {
termin=$(date +"%s")
difftimelps=$(($termin-$begin))
VerboseOutput 1 "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution."
}
CheckDeps
GetOptions $@
if [[ $help == true ]]; then
Usage
exit
fi
if [[ -f /tmp/music-sync-filelist ]]; then
rm /tmp/music-sync-filelist
fi
CreateFileList $source $dest ""
if [[ ! -f /tmp/music-sync-filelist ]]; then
VerboseOutput 2 "Nothing to do!"
exit 0
fi
ConvertFiles
CopyFiles
CleanUp
ExecTime