#!/bin/bash

# Indexing system for files stored on CD/DVD, by teknohog of iki.fi

# This is not true production-quality software, it's more like a proof
# of concept: you can replace expensive, proprietary hardware and/or
# software for handling CD/DVD storage with a simple Bash script.

##################################################################

# LICENSE
 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

####################################################################

# PRINCIPLE OF OPERATION

# When you add a disc to the system, the full paths of all files on it
# are written to an index file. The files are named as integers,
# starting from 1, corresponding to the disc number. You can then
# search (grep) for these files to see which disc contains what,
# without having to handle the actual media.

# $ discindex.sh -a
# mounts the disc, writes a new index file,
# outputs the number of that index/disc, unmounts disc.

# There's also a simple search function that returns just the numbers
# of the discs, so you don't need to grep manually.

# $ discindex.sh foo
# searches all index files for paths containing the string foo, and
# returns the filenames (disc numbers).

# $ discindex.sh -s foo
# shows the full paths matching the search, in addition to disc numbers

# $ discindex.sh -d foo 
# shows directories only (crude hack, works by ignoring file
# extensions in EXT_PATTERN)

####################################################################

# NOTES

# This script should work with any removable media, not just CD/DVD,
# and with any kind of data stored in filesystems. Only file/path
# names are stored and searchable though, and the whole system is
# probably sensible with write-once storage only.

# FUTURE IDEAS

# Store the metadata of audio CDs and video discs. This needs an
# additional program to read the metadata. In the case of audio CDs
# the source of metadata is probably the freedb online database, and
# for video discs there should be programs for reading the info
# directly.

# Currently I use this system for music files, and I might want
# separate systems for, say, pictures and video files. This could be
# done via a commandline parameter to change INDEXDIR. Or you might
# just have different versions of the script, like musindex.sh,
# movindex.sh etc. This can be quite elegant if they're symbolic links
# to the same file, and the action is determined by the name
# (i.e. `basename $0`).

# In fact, the find function could also be called with a different $0,
# if you don't mind too many commands filling up your PATH.

CDROM=/mnt/cdrom
INDEXDIR=~/tracking/discindex
GREP_OPTS="-i"
EXT_PATTERN="\.\(aac\|asf\|avi\|bmp\|db\|doc\|flac\|gif\|html\?\|jpe\?g\|m3u\|m4a\|mov\|mp[234]\|mpc\|mpe\?g\|nfo\|ogg\|pdf\|png\|pp[st]\|ps\|rtf\|sfv\|shn\|sit\|swf\|tif\+\|txt\|wav\)$"

function disc_add {
    OLDDIR=`pwd`

    if [ "`mount | grep $CDROM`" ]; then
	MOUNTED=yes
    else
	mount $CDROM
    fi
    cd $CDROM

    # This way of finding the smallest available disc number may seem
    # rather inelegant, especially when the total number gets very
    # large. However, it works :) and it has one definite advantage:
    # if a disc is lost/destroyed etc, you can delete its index file,
    # and that number can be used again.

    i=1
    while true; do
	if [ -e $INDEXDIR/$i ]; then
	    i=$((++i))
	else
	    NUM=$i
	    break
	fi
    done

    INDEXFILE=$INDEXDIR/$NUM

    # Not sure if -noleaf is really necessary, but it seems advisable
    # from the find manpage
    find -noleaf > $INDEXFILE

    cd $OLDDIR

    # If the disc was already mounted, then don't unmount it now
    if [ "$MOUNTED" != "yes" ]; then
	umount $CDROM
    fi

    echo "Disc number is $NUM"
    echo "Path list saved to $INDEXFILE"
}

function disc_find {
    cd $INDEXDIR

    # Future idea: multiple search terms with piped grep
    # or with some other search software

    # there's probably a neater way with single grep only...
    #NUM=`grep -c $GREP_OPTS $@ * | grep -v "\:0" | cut -d":" -f1`

    #.. yes, there is.
    NUM=`grep $GREP_OPTS -l $@ *`

    if [ "$NUM" ]; then 
	echo "$1 found on disc(s):"
	echo $NUM
    else
	echo $1 not found.
    fi
}

case "$1" in 
   -a)
	disc_add
	;;

   -s)
	shift
	cd $INDEXDIR
	grep $GREP_OPTS $@ *
	;;
   -d)
	shift
	cd $INDEXDIR
	grep $GREP_OPTS $@ * | grep -iv "$EXT_PATTERN"
	;;
   *)
	if [ "$1" ]; then 
	    disc_find $@
	else
	    echo "Usage:"
	    echo `basename $0` -a "(add a new disc to the collection)"
	    echo `basename $0` -s foo "(find foo showing complete paths)"
	    echo `basename $0` -d foo "(find the directory foo)"
	    echo `basename $0` foo "(find foo, showing disc number only)"
	fi
	;;

esac
