#!/usr/bin/perl -w

eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}'
    if 0; # not running under some shell
# $Id$
# Ian Beckwith <ianb@nessie.mcc.ac.uk>

use strict;
use MP3::Info;

use vars qw($me);
$me=($0=~/(?:.*\/)?(.*)/)[0];

my @files=();
my $totalsecs=0;
my $totalsize=0;

my $cdlength=74 * 60; # seconds

my ($HOURS,$MINUTES,$SECONDS)=(0,1,2);
my ($NOSIZE,$MP3SIZE,$UNCSIZE)=(0,1,2);
my ($QUIET,$NORMAL,$VERBOSE)=(0,1,2);
my ($SPACEFREE,$JUSTFULL,$OVERFULL)=(0,1,2);

my $verbosity=$NORMAL;
my $cdspace=$SPACEFREE;
my $showcdleft=0;
my $tmformat=$MINUTES;
my $szformat=$NOSIZE;

my $doneargs=0;
my $donesomething=0;
my $gotfiles=0;

while($_=shift)
{
	if(/^-/ && !$doneargs)
	{
		if(/-s/)    { $tmformat=$SECONDS;     }
		elsif(/-m/) { $tmformat=$MINUTES;     }
		elsif(/-h/) { $tmformat=$HOURS;       }
		elsif(/-z/) { $szformat=$UNCSIZE;     }
		elsif(/-Z/) { $szformat=$MP3SIZE;     }
		elsif(/-c/) { $showcdleft=1;          }
		elsif(/-C/) { $cdlength=60 * shift;   }
		elsif(/-v/) { $verbosity=$VERBOSE;    }
		elsif(/-q/) { $verbosity=$QUIET;      }
		elsif(/-h/) { usage();                }
		elsif(/--/) { $doneargs=1;            }
		else        { usage();                }
		next;
	}
	$donesomething=1;
	my $file=$_;
	unless(-e $file)
	{
		warn("$me: $file: not found\n");
		next;
	}
	
	my $mp3=MP3::Info->new($file);
	my $size;
	(undef,undef,undef,undef,undef,undef,undef,$size)=stat($file);
	unless($mp3 && defined($size))
	{
		warn("$me: cannot open $file: $!\n");
		next;
	}
	$gotfiles=1;
	
	if($verbosity==$VERBOSE)
	{
		print("$file: ",fmttime($tmformat,$mp3->secs));
		if($szformat != $NOSIZE)
		{
			print(" (",fmtsize($szformat,$size,$mp3->secs),")");
		}
		print("\n");
	}
	
	$totalsecs += $mp3->secs;
	$totalsize += $size;
}

# abort if no non-option args or no valid files
usage() unless($donesomething);
exit(2) unless($gotfiles);

if($verbosity != $QUIET)
{
	print "Total: " if($verbosity == $VERBOSE);
	print(fmttime($tmformat,$totalsecs));
	if($szformat != $NOSIZE)
	{
		print(" (",fmtsize($szformat,$totalsize,$totalsecs),")");
	}
	print("\n");
	
	if($totalsecs == $cdlength)
	{
		$cdspace=$JUSTFULL;
	}
	elsif($totalsecs < $cdlength)
	{
		$cdspace=$SPACEFREE;
	}
	else
	{
		$cdspace=$OVERFULL;
	}
	
	if($showcdleft)
	{
		if($cdspace==$SPACEFREE)
		{
			print("CD has ",
				  fmttime($tmformat,($cdlength-$totalsecs))," left.\n");
		}
		elsif($cdspace==$JUSTFULL)
		{
			print("CD is exactly full!\n");
		}
		else # OVERFULL
		{
			print("CD is too long by ",
				  fmttime($tmformat,($totalsecs-$cdlength)),"\n");
		}
	}
}

if($cdspace==$OVERFULL)
{
	exit(1);
}
exit(0);


sub fmttime
{
	my($format,$secs)=@_;
	if($format == $SECONDS)
	{
		return(sprintf("%02d",$secs));
	}
	my $minutes=sprintf("%d",$secs/60);
	my $remsecs=sprintf("%02d",$secs%60);
	if($format == $MINUTES)
	{
		return "$minutes:$remsecs";
	}
	# must be HOURS
	my $hours=sprintf("%02d",$minutes/60);
	my $remmins=sprintf("%02d",$minutes%60);
	return "$hours:$remmins:$remsecs";
}


sub fmtsize
{
	my($format,$filesize,$secs)=@_;
	my $size;
	if($format == $NOSIZE)
	{
		return "";
	}
	if($format == $MP3SIZE)
	{
		$size=$filesize;
	}
	else
	{
		# format=$UNCSIZE
		# samplerate * channels * bytes
		my $multiplier=(44100 * 2 * 2);
		$size=$secs * $multiplier;
	}
	$size /= 1024; # now in kb
	if($size < 1024)
	{
		return(sprintf("%2.2fKb",$size));
	}
	else
	{
		$size /= 1024; # now in mb
		return(sprintf("%2.2f Mb",$size));
	}
}


sub usage
{
	print STDERR
		"Usage: $me [-csmhzZvqh] [-C cdlength] [--] file.mp3..\n".
		" -c\t\tShow space left/excess if mp3s burned to audio cd.\n".
		" -C cdlength\tSet audio CD length in minutes (default 74).\n".
		" -s\t\tShow time in seconds.\n".
		" -m\t\tShow time in minutes (mm:ss) (default).\n".
		" -h\t\tShow time in hours (hh:mm:ss).\n".
		" -z\t\tShow size as uncompressed audio.\n".
		" -Z\t\tShow actual (mp3) size.\n".
		" -v\t\tVerbose.\n".
		" -q\t\tQuiet (no output, just return exit code).\n".
		" -h\t\tThis help.\n".
		" --\t\tEnd of options.\n".
		"Return codes: 0=files fit on CD, 1=files too big, 2=error\n";
	exit(2);
}

		
__DATA__

=head1 NAME

mp3len - show length of mp3 files

=head1 SYNOPSIS

B<mp3len> [I<-c>] [I<-C cdlength>] [I<-s>] [I<-m>] [I<-h>] [I<-z>] [I<-Z>] [I<-v>] [I<-q>] [I<-h>] [I<-->] [I<file.mp3>...]

=head1 DESCRIPTION

mp3len calculates the total length of the mp3 files given on the
command line. It can also calculate whether the files will fit
on an audio CD and show the size the files will uncompress to.

=head1 OPTIONS

=over 4

=item B<-c>

Show space free or excess space used if these mp3 files were burned to
an audio CD.

=item B<-C cdlength>

Sets the length of the audio cd in minutes. Defaults to 74 minutes.

=item B<-s>

Show time in seconds.

=item B<-m>

Show time in minutes (as mm:ss). This is the default.

=item B<-h>

Show time in hours (as hh:mm:ss).

=item B<-z>

Show the size these mp3 files would expand to if they were written to
an audio CD (which requires uncompressed 16-bit stereo at 44100Hz
samplerate).

=item B<-Z>

Show the actual size of the mp3 files.

=item B<-v>

Verbose. Gives per-track details as well as a total.

=item B<-q>

Quiet. Give no output, just return an exit code.

=item B<-h>

Show a short help message.

=item B<-->

End of option arguments.

=back

=head1 RETURN VALUE

mp3len returns 0 if the files will fit on an audio CD, 1 if they are
too big, and 2 on errors.

=head1 BUGS

None known. Please report any found to ianb@nessie.mcc.ac.uk	

=head1 SEE ALSO    

L<mp3-archive-tools(1)>

=head1 AUTHOR

Ian Beckwith <ianb@nessie.mcc.ac.uk>

=head1 AVAILABILITY

mp3len is part of the mp3-archive-tools package.

The latest version can be found at:

B<http://nessie.mcc.ac.uk/~ianb/projects/mp3-archive-tools/>

=head1 COPYRIGHT

Copyright 2004 Ian Beckwith <ianb@nessie.mcc.ac.uk>

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., 675 Mass Ave, Cambridge, MA 02139, USA.

=cut


	
