#!/bin/bash

# src/mp3toogg.  Generated from mp3toogg.sh by configure.
#
# Copyright 2004 Alfredo Pironti
# alfredio@ciaoweb.it
#
# 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

# Verbose mode, useful for debugging (comment out this line to avoid verbose bash)
#set -x

# Some useful and generic variables
version="2.0"
progname="`basename $0`"
progdir="$HOME/.$progname"	# Where to store the log file
logfile="$progdir/log"		# The name of the log file
prefix="/usr"		# needed for i18n stuff
datadir="/usr/share"		# needed for i18n stuff
mp3info="/usr/bin/mp3info-rmc"
mpg321="/usr/bin/mpg321"
oggenc="/usr/bin/oggenc"
vorbiscomment="/usr/bin/vorbiscomment"
required_progs="$mp3info $mpg321 $oggenc $vorbiscomment"
stderr=2
bugreport_email="alfredio@ciaoweb.it"

#i18n support
. gettext.sh

TEXTDOMAIN="mp3toogg"
export TEXTDOMAIN
TEXTDOMAINDIR="$datadir/locale"
export TEXTDOMAINDIR

usage() {
#i18n workaround: every line starting with `-' is being started with `\0'
#i18n we would call 'gettext -- "string"' if string begins with `-', but then
#i18n xgettext wouldn't extract the right string, it would extract "--"
echo "`eval_gettext 'Usage: $progname [OPTION] FILE... DIRECTORY...'`"
echo -e "`gettext \"Convert mp3 FILEs or mp3 files in DIRECTORY to the free ogg format.\"`"
echo ""
echo -e "`gettext \" -b VALUE  force output bitrate to VALUE instead of automatically choosing the best one\"`"
echo -e "`gettext \" -c        do not delete mp3 file after a correct conversion\"`"
echo -e "`gettext \" -f        try to convert mp3 files regardelss of their exstension\"`"
echo -e "`gettext \" -h        display this page and exit\"`"
echo -e "`gettext \" -l        write output to log file\"`"
echo -e "`gettext \" -n        do not follow symlinks\"`"
echo -e "`gettext \" -o        overwrite existing ogg file if needed\"`"
echo -e "`gettext \" -q        minimum verbosity level (display only fatal errors)\"`"
echo -e "`gettext \" -r        descend into subdirectories\"`"
echo -e "`gettext \" -V        output version information and exit\"`"
echo -e ""
echo -e "`gettext \"* * * -b option is only useful for downsampling. Oversampling is useless and\\n\
will not be performed. Not all numbers can be used as output bitrate, it depends\\n\
on the file you are going to convert. * * *\"`"
echo ""
echo -e "`eval_gettext 'Report bugs to <$bugreport_email>.'`"
return 0
}

version() {
echo -e "`eval_gettext '$progname $version'`"
echo -e "`gettext \"Written by Alfredo Pironti.\"`"
}

license() {
echo "`gettext \"Copyright (C) 2004 Alfredo Pironti.\"`"
echo -e "`gettext \"This program is free software; you can redistribute it and/or\\n\
modify it under the terms of the GNU General Public License\\n\
THIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY! USE AT YOUR OWN RISK!\"`"
}

check_progdir() {
if [ ! -d "$progdir" ]; then
	mkdir "$progdir"
fi
}

convert() {
# Check if the file has a reasonable extension
mp3_to_convert="$1"
if [ "`echo "$mp3_to_convert" | sed -n -r 's/.+\.mp3$/mp3/p'`" = "mp3" ]; then
	# This is the name we'll give to the new ogg file
	oggname="`echo "$mp3_to_convert" | sed 's/mp3$/ogg/'`"
else
	if [ $forcing -eq 0 ]; then
		# We append ogg exstension at the exisitng file name
		oggname="$mp3_to_convert.ogg"
	else
		test $quiet -eq 0 || echo "`eval_gettext '$progname: \"$mp3_to_convert\" does not have a valid mp3 extension.'`" >&$out_fd
		return 1;
	fi
fi

# If we are going to overwrite an existing ogg file and the user doesn't want this we have to skip this file
if [ $overwrite -ne 0 ]; then
	if [ -f "$oggname" ]; then
		test $quiet -eq 0 || echo "`eval_gettext '$progname: \"$oggname\" already exist. Skipping file.'`" >&$out_fd
		return 1;
	fi
fi		

# Next line tells us if the file is good and its bitrate
bitrate="`"$mp3info" -r m -p "%r" "$mp3_to_convert" 2> /dev/null`"
# This is the first time we can check if the mp3 is bad (mp3info is telling it)
if [ $? -ne 0 ]; then
	test $quiet -eq 0 || echo "`eval_gettext '$progname: \"$mp3_to_convert\" is not a valid mp3 file.'`" >&$out_fd
	return 1;
fi

# Now we have to choose the output bitrate
if [ "$bitrate_type" != "auto" ]; then #if the user doesn't want automatic bitrate selection
	# we give a warning if the user tries to oversample, because it's useless
	if [ "$bitrate_type" -gt "$bitrate" ]; then
		test $quiet -eq 0 || echo "`eval_gettext '$progname: trying to oversample \"$mp3_to_convert\". Using automatic bitrate selection.'`" >&$out_fd
	else		
		bitrate="$bitrate_type"
	fi
fi

# This is the name of the temporary file, needed to store the Id3 tag values
tmp="$mp3_to_convert.__attributes"

# Create the new ogg file, using the mean VBR upon the CBR of the original mp3 file, or upon user request
test $quiet -eq 0 || echo -n "`eval_gettext '$progname: converting \"$mp3_to_convert\" @ $bitrate kbit/s... '`" >&$out_fd
"$mpg321" "$mp3_to_convert" -w - 2> /dev/null | "$oggenc" -o "$oggname" -b "$bitrate" - 2> /dev/null
if [ $? -eq 0 ]; then
	test $quiet -eq 0 || echo "`gettext \"Done.\"`" >&$out_fd
	# Copy any existent id3 tag into the vorbis comments tag
	test $quiet -eq 0 || echo "`eval_gettext '$progname: copying Id3 tags...'`" >&$out_fd
	echo -n "" > "$tmp"
	# if the mp3 does not have an id3 tag it would be nice
	# to skip this piece of code. Nevertheless, mp3info does not return
	# a proper value in this case, so we can't skip... by now
	comment="`"$mp3info" -p "%t" "$mp3_to_convert" 2> /dev/null`"
	if [ -n "$comment" ]; then
		echo "TITLE="$comment"" 1>> "$tmp"
	fi
	comment="`"$mp3info" -p "%a" "$mp3_to_convert" 2> /dev/null`"
	if [ -n "$comment" ]; then
		echo "ARTIST="$comment"" 1>> "$tmp"
	fi
	comment="`"$mp3info" -p "%l" "$mp3_to_convert" 2> /dev/null`"
	if [ -n "$comment" ]; then
		echo "ALBUM="$comment"" 1>> "$tmp"
	fi
	comment="`"$mp3info" -p "%c" "$mp3_to_convert" 2> /dev/null`"
	if [ -n "$comment" ]; then
		echo "DESCRIPTION="$comment"" 1>> "$tmp"
	fi
	comment="`"$mp3info" -p "%y" "$mp3_to_convert" 2> /dev/null`"
	if [ -n "$comment" ]; then
		echo "DATE="$comment"" 1>> "$tmp"
	fi
	comment="`"$mp3info" -p "%n" "$mp3_to_convert" 2> /dev/null`"
	if [ -n "$comment" ]; then
		echo "TRACKNUMBER="$comment"" 1>> "$tmp"
	fi
	comment="`"$mp3info" -p "%g" "$mp3_to_convert" 2> /dev/null`"
	if [ -n "$comment" ]; then
		echo "GENRE="$comment"" 1>> "$tmp"
	fi

	# We do not copy the Id3 genre number because ogg comments don't have a standard genre number field
	if [ -s "$tmp" ]; then # if we have something to write
		"$vorbiscomment" -w -c "$tmp" "$oggname"
	fi
	rm -f "$tmp"
	
	if [ $delete -eq 0 ]; then
		rm -f "$mp3_to_convert"
	fi
	test $quiet -eq 0 || echo "`eval_gettext '$progname: done: \"$oggname\".'`" >&$out_fd

else
	rm -f "$oggname"
	test $quiet -eq 0 || echo "`gettext \"Not Done. Preserving existing mp3 file.\"`" >&$out_fd
fi
return 0
}

# exit code reminder:
not_found=63 # needed program not found
inv_par=64 # invalid parameter

# Let's set some variable upon user requset

exiting=1
bitrate_type="auto"
delete=0
overwrite=1
quiet=1
forcing=1
recursion=1
logging=1
dont_flw_link=1

while getopts ":b:cfhlnoqrV" Options
do
	case $Options in
		b ) bitrate_type="$OPTARG" ;;
		c ) delete=1 ;;
		f ) forcing=0 ;;
		h ) usage ; exit 0 ;;
		l ) logging=0 ;;
		n ) dont_flw_link=0;;
		o ) overwrite=0 ;;
		q ) quiet=0 ;;
		r ) recursion=0 ;;
		V ) version ; echo ""; license ; exit 0 ;;
		? ) echo "`eval_gettext '$progname: unknown option -- $OPTARG.'`" >&$stderr
			exiting=0;;
	esac
done

shift $(($OPTIND-1))

# Let's check if the bitrate_type is "auto" or a valid bitrate number
if [ "$bitrate_type" != "auto" ]; then # aut is a number aut we exit
	echo "$bitrate_type" | egrep '^[0-9]+$' > /dev/null || { echo "`eval_gettext '$progname: bitrate option requires a number or \"auto\".'`" >&$stderr; exiting=0; }
fi	

# Let's check the user specified at least one file
if [ $# -eq 0 ]; then
	echo "`eval_gettext '$progname: you must specify at least one file or directory.'`" >&$stderr
	exiting=0
fi

# We posticipated the exit so the user can know what are all him/her mistakes
if [ $exiting -eq 0 ]; then
	usage >&$stderr
        exit $inv_par
fi

# Let's check if all programs we need are installed, I still don't like abs path name. Assume basic programs already installed
for prog in $required_progs; do
	if [ ! -x "$prog" ]; then
		echo "`eval_gettext '$progname: needed $prog program not found.'`" >&$stderr
		exiting=0
	fi
done

# We posticipated the exit so the user can know what are all the programs he/she needs to install
if [ $exiting -eq 0 ]; then
	exit $not_found
fi
		
# Let's check some stuff, then do the work

if [ $logging -eq 0 ]; then
	if [ $quiet -ne 0 ]; then
		check_progdir;
		exec 3>>"$logfile"
		out_fd=3;
		date >&$out_fd;
	fi
else
	out_fd=2
fi

#We set find options based on command line options
#We set them here because once set they will ever be the same in all execution of the program
#It is useless to set them everytime we encounter a directory, since they will always be set at the same value
if [ $recursion -ne 0 ]; then
	recurse=" -maxdepth 1"
fi
if [ $forcing -ne 0 ]; then
	force=" -name '*.mp3'"
fi

if [ $dont_flw_link -eq 0 ]; then #note that find consider files differently from the shell, so '-type f' doesn't select a symlink
	file_type=" -type f"
else
	file_type=" -type f -follow"
fi

for mp3name in "$@"
	do

	if [ -f "$mp3name" ]; then # Note: this check is ok for files and links
		#MAYBE putting here checking for exstension, since when we have a dir we search for correct files 
		#anyway, it is a bit more efficient this way (I think)

		if [ $dont_flw_link -eq 0 ]; then
			if [ -L "$mp3name" ]; then #this is a link and we don't follow links, we skip the file
				test $quiet -eq 0 || echo "`eval_gettext '$progname: skipping symlink \"$mp3name\".'`" >&$out_fd
			else
				convert "$mp3name"
			fi
		else
			convert "$mp3name"
		fi

	elif [ -d "$mp3name" ]; then #we call the find command (options for the find command have already been set)
		#we are going to quote $mp3name, which is the file or dir to search for
		# but still we have to escape the quote character!
		mp3name=`echo $mp3name | sed 's/\"/\\\"/g'` #Warning, still broken if file has ``' character
		# We redirect find stderr output to /dev/null so find won't warn us about broken links or
		# not accessible files
		files=`eval "find "\"$mp3name\"""$recurse""$force""$file_type" -printf '%p|'" 2> /dev/null`
		
		# Now we parse the file variable, launching convert() for each file found
		# we'd like to do it with a for, or while, but it doesn't work with filenames with spaces
		fs=1 # This is needed for the workaround to work
		while [ $fs -ne 0 ] #this is the workaround
			do fs=`expr index "$files" \|`
			if [ $fs -ne 0 ]; then
				convert "${files:0:$fs-1}"
				files=${files:$fs}
			fi
		done
	else
		test $quiet -eq 0 || echo "`eval_gettext '$progname: skipping \"$mp3name\". It is not a file nor a directory.'`" >&$out_fd
	fi
done

if [ $logging -eq 0 ]; then
	if [ $quiet -ne 0 ]; then
		3>&-
	fi
fi

exit 0
