#!/bin/sh

# this script converts the output of calibre's 'Save to Disk' function to a format optimized for the PB-302 ereader. It also removes duplicate files, creating symlink-analogues as necessary to save memory on the device.

### brainycat Sat May 15 10:16:00 PDT 2010
### copyrighted under the terms of the GPLv3
### http://www.gnu.org/licenses/gpl-3.0.html

### VARIABLES
# this is where calibre saves 
# "Save to Disk" format should be: {tags}/{optional}-{optional}-...
calibreOutDir="/share/ebooks/calibre_out/"
#calibreOutDir="/home/$USER/calibre_out/"

# location of the local canonical library that should mirror the device library
# protip: backup /dir/to/calibre/database
# protip: backup /dir/to/pb302/library
#libraryDir="/home/$USER/pbtest"
libraryDir="/share/ebooks/pb302"

# find files changed less than this many minutes ago
myCtime=6000

# working directory separate form canonical library
outDir="/tmp/pbcategories-${USER}"

# this is where the PB-302 is mounted
pbMnt="/mnt/sdb"

### FUNCTIONS

f_setDefaults(){
echo "Location where calibre saves to disk:"
read calibreOutDir

echo "Search for books added less than ___ minutes ago to ${calibreOutDir}:"
read myCtime

echo "Where is the local copy of the PB-302 library?"
read libraryDir

echo "Where is PB-302 mounted?"
read pbMnt
}; # end f_setDefaults

f_createLink(){
flkName=`echo ${thisFile} | md5sum | cut -c -8`
echo "/mnt/ext1/${thisFile}" > ${flkName}.flk
}; # end f_createMatch

### MAIN

echo "Default behavior: search ${calibreOutDir} for ebooks added less than ${myCtime} minutes ago, sort by calibre's tag(s), replace duplicate files with symlink-analogues to the original file, update the local canonical library at ${libraryDir} then update the device library mounted at ${pbMnt}."
echo "Accept Defaults? [y/n]"
read answer
# while loop tests exactly ONE condition, so we normalize our var
answer=`echo ${answer} | tr [[:upper:]] [[:lower:]]`
while [[ "${answer}" != "y" ]]
	do
		f_setDefaults
		echo "Find calibre output in ${calibreOutDir}"
		echo "We will find updates no older than ${myCtime} minutes ago"
		echo "Local copy of the PB-302 Library is located at ${libraryDir}"
		echo "PB-302 is mounted at ${pbMnt}"
		echo "Accept these options? [y/n]"
		read answer
		# while loop tests exactly ONE condition, so we normalize our var
		answer=`echo ${answer} | tr [[:upper:]] [[:lower:]]`
	done

if [[ ! -d ${calibreOutDir} ]]
	then
		echo "${calibreOutDir} does not exist. Have you \"Save to Disk\" from calibre?"
		echo "\"Save to Disk\" format should be: {tags}/{option}-{option}-..."
		exit
	else
		:; # do nothing, successfully
fi

if [[ -d ${outDir} ]]
	then
		rm -rf ${outDir}-old
		mv ${outDir} ${outDir}-old
	else
		:; # do nothing, successfully
fi
mkdir -p ${outDir}

cd ${calibreOutDir}
echo "Searching ${calibreOutDir} for new books..."
# outside loop finds the dirs that calibre installed
for DIR in $(find . -maxdepth 1 -type d -ctime -${myCtime} | grep -ve "^\.$")
	do
		# find categories in dirnames
		echo $DIR | tr ',' '\n' | sed -e 's/^\.\///' | sed -e 's/^_*//' \
		| while read -r THISDIR
			do 
				thisOutDir="${outDir}/${THISDIR}"
				if [[ ! -d ${thisOutDir} ]]
					then
						mkdir -p ${thisOutDir}
					else
						:; # do nothing, successfully
				fi
				# copy the contents of the original dir into the new tmp category dirs
				cp ${DIR}/* ${thisOutDir}/
			done
	done

# overload a var with our category dirs for reuse later
cd ${outDir}
for DIR in $(find . -maxdepth 1 -type d | grep -ve "^\.$" | sed -e 's/^\.\///' | sort)
	do
		myDirList="${myDirList} ${DIR}"
	done

# brute force iteration
echo "Searching for duplicates (this may take a while for large libraries)"
for DIR in ${myDirList}
	do
		for thisFile in $(find ${DIR} -type f)
			do
				fileNoPath=`echo ${thisFile} | sed -e 's/^.*\///'`
				# search other directories for identical files
				for thisDir in ${myDirList}
					do
						if [[ ${thisDir} == ${DIR} ]]
							then
								# don't remove/replace the original file
								cd ${outDir}
							else
								# search for duplicates in all other dirs
								cd ./${thisDir}
								if (ls ${fileNoPath} &>/dev/null)
									then
										rm -f ./${fileNoPath}
										# don't link opf files, but other files are assumed to be books
										if (echo "${fileNoPath}" | grep -ve "opf$" &>/dev/null)
											then
												f_createLink
											else
												:; # do nothing, successfully
										fi
									else
										:; # do nothing, successfully
								fi
								cd ${outDir}
						fi
					done
			done
		# remove DIRs from list after all files in them have been compared already
		# this prevents each file from being compared twice, saving much time
		myDirList=`echo ${myDirList} | sed -e 's/'${DIR}'//'`
	done

# copy new changes into canonical local library
echo "Updating local canonical library"
if [[ ! -d ${libraryDir} ]]
	then
		echo "No library found at ${libraryDir}, creating" 
		mkdir -p ${libraryDir}
	else
		:; # do nothing, successfully
fi
if (rsync -ar ${outDir}/ ${libraryDir})
	then
		echo "Successfully updated, removing temporary files"
		rm -rf ${outDir}
	else
		echo "Unable to update files from ${outDir} to ${libraryDir}, aborting"
		exit
fi

echo "Would you like to remove the contents of ${calibreOutDir}? [y/n]"
read answer
if [[ ${answer} = "y" ]] || [[ ${answer} = "Y" ]]
	then
		echo "Removing files..."
		echo "rm -rf ${calibreOutDir}/*"
	else
		echo "Leaving ${calibreOutDir} intact"
fi
unset ${answer}

# sync books to device
echo "Is the PB-302 currently mounted at ${pbMnt}? [y/n]"
read answer
if [[ ${answer} = "y" ]] || [[ ${answer} = "Y" ]]
	then
		echo "Syncing files to device, this may take a while"
		rsync -av ${libraryDir}/* ${pbMnt}
	else
		echo "Not attempting to sync books to device"
fi
unset ${answer}


