# Author: Theodore Zacharia
# V0.1: 07/10/2023 - Initial Release
# 
#
# Checks a file is valid for the format, and copies it to the destination if so,
# otherwise only copies a stub with specific name
# 
# I lost a hard disk with a LOT of files on it, some were good and some were not.
# This script checks each file and copies over the good ones to a new destination,
# creating a stub if the file is bad so we can re-get a good version of that file
# if required.
#

# *** Globals
TRACE=0
DELETEORIGINAL=0
MINFILESIZE=600
INPUTFILE=""
ERRCHECK=error.log
STARTORIGINALPATH=""
NEWDESTINATIONPATH=""
CHECKTIMEOUT=300
T1=$$.tmp


# *** Functions
_usage()
{
	echo "usage: $0 [-h] [-t] [-D] [-i inputfile] -s start_original_path -n new_destination_path [inputfiles...]"
	echo "where"
	cat <<- _EOF_
	  -h        Displays this help message
	  -t        Set trace on
	  -s        Start Original Path
	  -n        New Destination Path
	  -D        Delete the original file when done
	  -i file   takes the files to modify from the input file and not the args
	Example
	  ./copyifvalid.sh -s /mnt/Cerberus/MnS05/series/ -p series/ /mnt/Cerberus/MnS05/series/StrangeNewWorlds/S01E01_Strange_New_Worlds.mkv
	  will create the dir StrangeNewWorlds under series/ and copy the file S01E01_Strange_New_Worlds.mkv if it is valid or put a .error file if not
_EOF_
}


# *** Mainline

# process input parameters
while getopts thfFDs:i:p: AOPT
do
case $AOPT in
	t) TRACE=1 ;; # set TRACE mode
	i) INPUTFILE=$OPTARG ;;
	s) STARTORIGINALPATH=$OPTARG ;;
	p) NEWDESTINATIONPATH=$OPTARG ;;
	D) DELETEORIGINAL=1 ;;
	h) _usage
	   exit 1 ;;
	*) # echo "-$OPTARG is an invalid option" >&2 # start getopts string with :
	   exit 2 ;;
esac
done

shift $((OPTIND-1))

if [ $TRACE -gt 0 ]
then
	echo "Starting at $(date)"
	echo "TRACE=$TRACE" >&2
	echo "positional_args=$@" >&2
fi

if [ $# -lt 0 ] || [ ! -n "$NEWDESTINATIONPATH" ] || [ ! -n "$STARTORIGINALPATH" ]
then
	_usage
	exit 1
fi

# if we get this far, the filelist should be the files to shrink

if [ -n "$INPUTFILE" ]
then
	echo "Processing input file $INPUTFILE"
	cp $INPUTFILE $T1
else
	echo "Processing arguments"
	for AFILE in "$@"
	do
		echo "$AFILE" >> $T1
	done
fi

echo "Will check following files:"
cat $T1
echo " "

while read AFILE
do
	echo "--- Processing $AFILE at $(date)"

	ffprobe -v error "$AFILE" && echo "ffprobe OK => '$AFILE'" || echo "ffprobe ERROR => '$AFILE'"

	# maintain image size but reduce file size
	NEWPATH=$(echo "$AFILE" | sed "s#$STARTORIGINALPATH#$NEWDESTINATIONPATH#")
	echo "NEWPATH=$NEWPATH"
	BFILE="${NEWPATH%%.*}"
	BFILE="${NEWPATH}.error"
	mkdir -p "$(dirname "$NEWPATH")"
	if [ $TRACE -gt 0 ] ; then echo "checking $AFILE to $NEWPATH" ; fi

	# based on the size, if it cannot verify it after a specific time there is an issue, so skip
	timeout $CHECKTIMEOUT ffmpeg -v error -i "$AFILE" -map 0:1 -f null -  >$ERRCHECK 2>&1
	EL=$?

	if [ $EL -gt 0 ]
	then
		if [ $EL -eq 124 ]
		then
			echo "ffmpeg had an timeout ($EL) trying to verify $AFILE at $(date)" | tee "$BFILE"
		else
			echo "ffmpeg had an error ($EL) trying to verify $AFILE at $(date)" | tee "$BFILE"
		fi
		continue
	else
		ERRORLEVEL=$( wc -l $ERRCHECK | awk '{print $1}')
		if [ $TRACE -gt 0 ] ; then echo "ERRORLEVEL=$ERRORLEVEL" ; fi
	fi

	if [ $ERRORLEVEL -gt 0 ]
	then
		echo "Error ($ERRORLEVEL) found for $AFILE ..."
		cat $ERRCHECK
		cat $ERRCHECK > "$BFILE"
		echo "...skipping ($BFILE) at $(date)"
		continue
	fi

	# if we get this far then file should be ok, so copy it
	echo "copying $AFILE to $NEWPATH"
	#mkdir -p "$(dirname "$NEWPATH")" && cp "$AFILE" "$NEWPATH"
	cp "$AFILE" "$NEWPATH"
	EL=$?

	if [ $EL -eq 0 ]
	then
		if [ $DELETEORIGINAL -eq 1 ]
		then
			echo "Deleting Original"
			rm "$AFILE"
		fi
	fi

	if [ $TRACE -gt 0 ]
	then
		echo "done at $(date) for $AFILE"
	fi


done<$T1

rm -f $T1