#!/bin/bash # # 20081115 Jens Heine # # cdseek - a tiny medium database tool # # # DEBUG #set -x ############################################################################### # Check for needed binarys ############################################################################### test -x /bin/ls || { echo "/bin/ls not found."; exit 1; } test -x /bin/grep || { echo "/bin/grep not found."; exit 1; } test -x /usr/bin/find || { echo "/usr/bin/find not found."; exit 1; } test -x /usr/bin/vim || { echo "/usr/bin/vim not found."; exit 1; } test -x /usr/bin/sort || { echo "/usr/bin/sort not found."; exit 1; } ############################################################################### # CONSTANTS ############################################################################### USAGE_INFO_TEXT=" Description cdseek is a tiny tool for keeping track of all CD's, DVD's and other media you have (even filesystems are possible). After you have added your CD's to the cdseek database, you can search for file, view statistics and more. Obviously you can set various attributes for every CD you scan. This can be a title or a location for example. Usage cdseek -a [-A] [-b] [-D description] [-e] [-T mediumtype] [-P location] [-r scanpath] -n mediumnumber [-t title ] -c -d mediumnumber -E mediumnumber -l mediumnumber -L -m mediumnumber -M -R dbrootpath -s|-S searchstring Features -a Add/scan medium -A Automatic cd handling: mounts/umounts scanpath -b Backup the cdseek database -c Create cdseek database -d Delete medium -E Edit medium metadata file -e Eject medium after scanning -D Set medium description -l List medium contents -L List all medium titles in database -m Show medium metadata -n Set a logical medium number/id -M Show cdseek database metadata -r Set medium scan root path -P Set storage location of medium -R Set database root path -S Search file in database -s Search in medium title or description -T Set medium type -t Set medium title Files If the file ~/.cdseek.conf exist, it will be sourced. You can set default values here like: DBROOTPATH=\"/path/to/my/db\" M_TYPE=DVD M_LOCATION=\"My CD Box\" M_SCANPATH=\"/path/to/cdrom\" AUTO_MOUNT_UMOUNT_SCANPATH=1 AUTO_EJECT_SCANPATH=1 There are more values you can set here like M_TITLE and so on, but setting them to default values does not really make sense... Ok, have fun using this tool Write an email for comments or bug reports to Jens Heine Written by Jens Heine on 2008115 " ############################################################################### # VARIABLES ############################################################################### CDSEEKVERSION="7" CONFIGFILE=~/.cdseek.conf METADATAFILENAME="metadata" DBROOTPATH=~/cdseek/db TMPFOLDER="/tmp/cdseek" ACTION="" AUTO_MOUNT_UMOUNT_SCANPATH=0 AUTO_EJECT_SCANPATH=0 M_FILE_PLAINFILELIST="files.plain" M_FILE_FILETYPES="files.types" M_FILE_FILEDETAILS="files.detail" M_SCANPATH="" M_DESCRIPTION="" M_TYPE="" M_TITLE="" M_LOCATION="" M_NUMBER="" ############################################################################### # FUNCTIONS ############################################################################### function showHelptext() { echo "Wrong usage. Use -h for help." } function showVersion() { echo " Versioninfo: cdseek $CDSEEKVERSION" echo " Written by Jens Heine on 2008115" echo } function showUsage() { echo "$USAGE_INFO_TEXT" } function createFolder() { mkdir -pv "$1" } # Args: NAME VALUE FILE function setVariableInFile() { #sed -i 's/\$1=.*/\$1=\$2/' $3 grep -v -e "^${1}=" "$3" > $TMPFOLDER/cdseek.$$ echo "${1}=${2}" >> $TMPFOLDER/cdseek.$$ mv $TMPFOLDER/cdseek.$$ ${3} } # Args: NAME FILE # Returns: VALUE of VARIABLE_NAME or empty string function getVariableValueFromFile() { # NAME leer? [ -z "$1" ] && echo && return 1 # FILE nich lesbar? [ ! -r "$2" ] && echo && return 1 LINE=`grep "${1}=" "${2}" 2>/dev/null` # NAME nich in FILE? [ -z "$LINE" ] && echo && return 1 # auspacken und verschenken echo "${LINE#$1=}" && return 0 } function confirmAction() { echo -n "$1 (y/n): " read USERINPUT if [ "y" = "$USERINPUT" -o "Y" = "$USERINPUT" ];then return 0 else return 1 fi } # check if db manipulation operations can be done # if db does not exists - this program exits here function checkIfDatabaseExists() { if [ ! -d "${DBROOTPATH}/data" ];then echo " Error: Database datafolder not found: ${DBROOTPATH}/data" exit 1 elif [ ! -f "${DBROOTPATH}/${METADATAFILENAME}" ];then echo " Error: Database metadatafile is not a regular file: \ ${DBROOTPATH}/${METADATAFILENAME}" exit 1 elif [ ! -w "${DBROOTPATH}/${METADATAFILENAME}" ];then echo " Error: Database metadatafile is not writeable: \ ${DBROOTPATH}/${METADATAFILENAME}" elif [ ! -s "${DBROOTPATH}/${METADATAFILENAME}" ];then echo " Error: Database metadatafile is empty: \ ${DBROOTPATH}/${METADATAFILENAME}" fi } # all stuff will be read from exported variables function createDbMetadataFile() { DBMETAFILE="$DBROOTPATH"/"$METADATAFILENAME" echo "CDSEEKVERSION=$CDSEEKVERSION" > "$DBMETAFILE" echo "DBNAME=cdseekdb" >> "$DBMETAFILE" echo "DBCREATED=\"`date`\"" >> "$DBMETAFILE" echo "DBCREATEDSEC=`date +%s`" >> "$DBMETAFILE" echo "DBMEDIUMCOUNT=0" >> "$DBMETAFILE" echo "DBMEDIUMFILESCOUNT=0" >> "$DBMETAFILE" echo "DBMEDIUMTYPES=" >> "$DBMETAFILE" echo "DATABASESIZE=0" >> "$DBMETAFILE" echo "Database metafile created: $DBMETAFILE" } function updateDbMetadata() { echo -n " Updating database metadata... " DBMEDIUMCOUNT="`find $DBROOTPATH/data/ -type d | wc -l`" setVariableInFile DBMEDIUMCOUNT $DBMEDIUMCOUNT "$DBROOTPATH/$METADATAFILENAME" FILECOUNT=`countAllFilesInDatabase` setVariableInFile DBMEDIUMFILESCOUNT "$FILECOUNT" "$DBROOTPATH/$METADATAFILENAME" TYPES=`getAllMediumTypesInDatabase` setVariableInFile DBMEDIUMTYPES "$TYPES" "$DBROOTPATH/$METADATAFILENAME" DBSIZE=`du -sh $DBROOTPATH/data|cut -f1` setVariableInFile DATABASESIZE "$DBSIZE" "$DBROOTPATH/$METADATAFILENAME" echo "OK" } function showDbMetadata() { updateDbMetadata echo echo " cdseek Database Metadata:" echo echo " DBROOTPATH=${DBROOTPATH}" echo cat "$DBROOTPATH"/"$METADATAFILENAME" | sed 's/^/ /g' echo } function backupDatabase() { BACKUPFOLDER="${DBROOTPATH}/cdseekbackup/`date +%Y%m%d%H%M%S`" mkdir -p $BACKUPFOLDER || exit 1 echo -n " Backing up cdseek database... " && cp -a ${DBROOTPATH}/data $BACKUPFOLDER && cp -a ${DBROOTPATH}/metadata $BACKUPFOLDER && echo "OK" echo echo " The following cdseek backups exist:" echo du -sh ${DBROOTPATH}/cdseekbackup/* echo } function countAllFilesInDatabase() { ls -1 $DBROOTPATH/data/ | sort -n > $TMPFOLDER/cdseek.$$ SUMFILES=0 while read FOLDER;do FILECOUNT=`getVariableValueFromFile FILECOUNT $DBROOTPATH/data/$FOLDER/metadata` SUMFILES=`echo "$SUMFILES + $FILECOUNT"|bc` done < $TMPFOLDER/cdseek.$$ rm $TMPFOLDER/cdseek.$$ echo $SUMFILES } function getAllMediumTypesInDatabase() { ls -1 $DBROOTPATH/data/ | sort -n > $TMPFOLDER/cdseek.$$ touch $TMPFOLDER/cdseek.$$.2 while read FOLDER;do TYPE=`getVariableValueFromFile TYPE $DBROOTPATH/data/$FOLDER/metadata` echo "$TYPE" >> $TMPFOLDER/cdseek.$$.2 done < $TMPFOLDER/cdseek.$$ TYPES="`cat $TMPFOLDER/cdseek.$$.2 | sort -u`" rm $TMPFOLDER/cdseek.$$ rm $TMPFOLDER/cdseek.$$.2 echo $TYPES } function createDatabase() { confirmAction " Create new database in $DBROOTPATH ?" || return 1 if [ -d "$DBROOTPATH" ];then echo " Warning: $DBROOTPATH already exists!" confirmAction " Do you want to delete the existing database ?" || exit 0 rm -rvf $DBROOTPATH fi createFolder "$DBROOTPATH/data" createDbMetadataFile echo showDbMetadata } # Args: M_ID function showMediumMetadata() { echo " Medium number: $1" cat $DBROOTPATH/data/$1/metadata | sed 's/^/ /g' echo } # Args: Medium number function mediumNumberExists() { [ -z "$1" ] && return 1 [ ! -d $DBROOTPATH/data/"$1" ] && return 1 return 0 } function addMedium() { [ -z "$M_TITLE" ] && M_TITLE="Unknown title" [ -z "$M_NUMBER" ] && echo " Please add a number for the new medium." && exit 1 mediumNumberExists "$M_NUMBER" && echo "Medium number already exists." && exit 1 echo " Scanpath is : $M_SCANPATH" if [ ! -d "$M_SCANPATH" ];then echo " Scanpath \"$M_SCANPATH\" is not a valid directory." exit 1 fi [ 1 -eq "$AUTO_MOUNT_UMOUNT_SCANPATH" ] && mount "$M_SCANPATH" cd $M_SCANPATH find . > $TMPFOLDER/files.plain.$$ 2>/dev/null FILESTOSCAN=`cat $TMPFOLDER/files.plain.$$ | wc -l` if [ 0 -eq "$FILESTOSCAN" ];then echo " No files found in scanpath." rm $TMPFOLDER/files.plain.$$ exit 1 fi NEWFOLDER="$DBROOTPATH/data/$M_NUMBER" mkdir -p $DBROOTPATH/data/$M_NUMBER || exit 1 M_METAFILE=$NEWFOLDER/metadata echo "CDSEEKVERSION=$CDSEEKVERSION" > "$M_METAFILE" echo "SCANPATH=$M_SCANPATH" >> $M_METAFILE echo "DESCRIPTION=$M_DESCRIPTION" >> $M_METAFILE echo "TYPE=$M_TYPE" >> $M_METAFILE echo "TITLE=$M_TITLE" >> $M_METAFILE echo "LOCATION=$M_LOCATION" >> $M_METAFILE echo "FILECOUNT=$FILESTOSCAN" >> $M_METAFILE echo "MEDIUMSIZEBYTES=`du -sb $M_SCANPATH | cut -f1`" >> $M_METAFILE echo "MEDIUMSIZEHUMANREADABLE=`du -sh $M_SCANPATH | cut -f1`" >> $M_METAFILE echo "CREATEDATE=`date`" >> $M_METAFILE echo "CREATEDATESEC=`date +%s`" >> $M_METAFILE echo " Files to scan $FILESTOSCAN" # cd $M_SCANPATH echo -n " Creating plain file list... " # find . > $NEWFOLDER/$M_FILE_PLAINFILELIST mv $TMPFOLDER/files.plain.$$ $NEWFOLDER/$M_FILE_PLAINFILELIST echo "OK" echo -n " Creating detail file list" FILES_READY=0 FILES_SUM=$FILESTOSCAN P_MARK=26 while read FILENAME;do /bin/ls -dl "${FILENAME}" >> $NEWFOLDER/$M_FILE_FILEDETAILS let FILES_READY=$FILES_READY+1 P_DONE=`echo "$FILES_READY*100/$FILES_SUM"|bc` if [ $P_DONE -ge $P_MARK ];then echo -n "." let P_MARK=$P_MARK+25 fi done < $NEWFOLDER/$M_FILE_PLAINFILELIST echo " OK" echo -n " Creating file type list" FILES_READY=0 FILES_SUM=$FILESTOSCAN P_MARK=26 while read FILENAME;do /usr/bin/file "${FILENAME}" >> $NEWFOLDER/$M_FILE_FILETYPES let FILES_READY=$FILES_READY+1 P_DONE=`echo "$FILES_READY*100/$FILES_SUM"|bc` if [ $P_DONE -ge $P_MARK ];then echo -n "." let P_MARK=$P_MARK+25 fi done < $NEWFOLDER/$M_FILE_PLAINFILELIST echo " OK" cd - >/dev/null echo [ 1 -eq "$AUTO_MOUNT_UMOUNT_SCANPATH" ] && umount "$M_SCANPATH" [ 1 -eq "$AUTO_EJECT_SCANPATH" ] && eject "$M_SCANPATH" showMediumMetadata "$M_NUMBER" } function listAllMediumTitles() { ls -1 $DBROOTPATH/data/ | sort -n > $TMPFOLDER/cdseek.$$ while read FOLDER;do NUMBER=${FOLDER} TITLE=`getVariableValueFromFile TITLE $DBROOTPATH/data/$FOLDER/metadata` echo " [${NUMBER:-0}] $TITLE" # echo " Number : ${NUMBER:-0}" # echo " Title : $TITLE" # echo done < $TMPFOLDER/cdseek.$$ rm $TMPFOLDER/cdseek.$$ } # Args: Searchstring function searchInMediumTitles() { [ -z "$1" ] && return 1 SEARCHSTRING="`echo "$1"|tr [a-z] [A-Z]`" ls -1 $DBROOTPATH/*/ | sort -n > $TMPFOLDER/cdseek.$$ while read FOLDER;do TITLE=`getVariableValueFromFile TITLE $DBROOTPATH/data/$FOLDER/metadata` UPPER_TITLE=`echo $TITLE|tr [a-z] [A-Z]` [ 0 -eq "`expr match "$UPPER_TITLE" ".*${SEARCHSTRING}.*"`" ] && continue NUMBER=$FOLDER echo " [${NUMBER:-0}] $TITLE" # echo " Number : ${NUMBER:-0}" # echo " Title : $TITLE" # echo done < $TMPFOLDER/cdseek.$$ rm $TMPFOLDER/cdseek.$$ } # Args: Searchstring function searchInMediumFiles() { [ -z "$1" ] && return 1 ls -1 $DBROOTPATH/*/ | sort -n > $TMPFOLDER/cdseek.$$ while read FOLDER;do grep -iq "$1" $DBROOTPATH/data/$FOLDER/$M_FILE_PLAINFILELIST [ 0 -ne "$?" ] && continue NUMBER=$FOLDER TITLE=`getVariableValueFromFile TITLE $DBROOTPATH/data/$FOLDER/metadata` echo " Number : ${NUMBER:-0}" echo " Title : $TITLE" echo done < $TMPFOLDER/cdseek.$$ rm $TMPFOLDER/cdseek.$$ } # Args: Medium number function listMediumFilesPlain() { [ -z "$1" ] && { echo " Medium number must not be null"; exit 1; } cat $DBROOTPATH/data/$1/$M_FILE_PLAINFILELIST } # Args: Medium number function deleteMedium() { [ -z "$1" ] && { echo " Medium number must not be null"; exit 1; } echo " Do you want to delete this medium:" echo showMediumMetadata "$1" echo echo " Delete medium? (press strg-c to cancel)" && read XXX rm -rfv $DBROOTPATH/data/$1/ } function editMedium() { [ -z "$1" ] && { echo " Medium number must not be null"; exit 1; } mediumNumberExists "$1" || { echo "Medium $1 does not exist."; exit 1; } vim $DBROOTPATH/data/$1/metadata } ############################################################################### # MAIN PROGRAM ############################################################################### # load eventually existing config file: [ -r $CONFIGFILE ] && . "$CONFIGFILE" # create tmp folder if not existing and clean it up [ ! -d $TMPFOLDER ] && { createFolder $TMPFOLDER || exit 1; } [ ! -w $TMPFOLDER ] && echo " Unable to write in tmp folder $TMPFOLDER" && exit 1 rm -v $TMPFOLDER/* >/dev/null 2>&1 ARGUMENTS_EXIST=0 while getopts aAbcD:eE:T:t:r:R:P:d:l:Lm:n:Ms:S:Vh? options; do ARGUMENTS_EXIST=1 case $options in a) ACTION="ADD" ;; b) ACTION="BACKUP" ;; A) AUTO_MOUNT_UMOUNT_SCANPATH=1 ;; c) ACTION="CREATEDB" ;; D) M_DESCRIPTION="$OPTARG" ;; T) M_TYPE="$OPTARG" ;; t) M_TITLE="$OPTARG" ;; P) M_LOCATION="$OPTARG" ;; d) ACTION="DELETE" M_NUMBER="$OPTARG" ;; e) AUTO_EJECT_SCANPATH=1 ;; E) ACTION="EDITMEDIUM" M_NUMBER="$OPTARG" ;; l) ACTION="LIST" M_NUMBER="$OPTARG" ;; L) ACTION="LISTDB" ;; m) ACTION="MEDIUMMETADATA" M_NUMBER="$OPTARG" ;; n) M_NUMBER="$OPTARG" ;; M) ACTION="DBMETADATA" ;; r) M_SCANPATH="$OPTARG" ;; R) DBROOTPATH="$OPTARG" ;; S) ACTION="SEARCHFILES" SEARCHSTRING="$OPTARG" ;; s) ACTION="SEARCHMEDIUMS" SEARCHSTRING="$OPTARG" ;; V) ACTION="SHOWVERSION" ;; h) showUsage exit 0 ;; ?) showHelptext exit 1 ;; esac done if [ "1" != "$ARGUMENTS_EXIST" ];then showHelptext exit 1 fi # Check if we have a db rootpath for further operations: if [ -z "$DBROOTPATH" ];then echo " Error: DBROOTPATH not set." exit 1 fi echo case "$ACTION" in ADD) checkIfDatabaseExists addMedium exit 0 ;; BACKUP) checkIfDatabaseExists backupDatabase exit 0 ;; CREATEDB) createDatabase exit 0 ;; DBMETADATA) checkIfDatabaseExists showDbMetadata exit 0 ;; MEDIUMMETADATA) checkIfDatabaseExists showMediumMetadata $M_NUMBER exit 0 ;; LIST) checkIfDatabaseExists listMediumFilesPlain $M_NUMBER exit 0 ;; DELETE) checkIfDatabaseExists deleteMedium $M_NUMBER exit 0 ;; EDITMEDIUM) checkIfDatabaseExists editMedium $M_NUMBER exit 0 ;; LISTDB) checkIfDatabaseExists listAllMediumTitles exit 0 ;; SEARCHMEDIUMS) checkIfDatabaseExists searchInMediumTitles "$SEARCHSTRING" exit 0 ;; SEARCHFILES) checkIfDatabaseExists searchInMediumFiles "$SEARCHSTRING" exit 0 ;; SHOWVERSION) checkIfDatabaseExists showVersion exit 0 ;; esac exit 0