#!/usr/local/bin/perl -w
# Ian Beckwith <ianb@nessie.mcc.ac.uk> 20030423
# $Id: mp3lint,v 1.20 2003/12/14 09:43:56 ianb Exp $

use strict;

use Config;

use MP3::Archive::Lint;
use MP3::Archive::Lint::Tool ':all';
use MP3::Archive::Lint::Conf;
# For makemaker
use vars qw($VERSION);
$VERSION="0.9";

my @tools=();
my $me=($0=~/(?:.*\/)?(.*)/)[0];
use vars qw($archive);
if($#ARGV<0) { usage(); }

my %opts=();

$opts{fix}            =0;
$opts{debug}          =0;
$opts{quickscan}      =0;
$opts{ignoreskip}     =0;
$opts{skipnametests}  =0;

while( ($#ARGV>-1) && ($ARGV[0]=~/^-/) && ($_=shift))
{
	   if (/-f/) { $opts{fix}           = 1; }
	elsif (/-d/) { $opts{debug}         = 1; }
	elsif (/-n/) { $opts{skipnametests} = 1; }
	elsif (/-i/) { $opts{ignoreskip}    = 1; }
	elsif (/-q/) { $opts{quickscan}     = 1; }
	elsif (/-a/) { $opts{format_default} = "album"; }
	elsif (/-t/) { $opts{format_default} = "track";  }
	elsif (/-s/) { $opts{format_default} = "skip";   }
	elsif (/-T/) { $opts{tools}          = shift;    }
	elsif (/-X/) { $opts{skiptools}      = shift;    }
	elsif (/-c/) { checktools(); }
	elsif (/-h/) { usage();      }
	else { usage(); }
}

if($#ARGV<0) { usage(); } 

my $cfg=new MP3::Archive::Lint::Conf(\%opts);
$archive=new MP3::Archive($cfg);
my $lint=new MP3::Archive::Lint($cfg,$archive,\@ARGV);

exit($lint->lint);

sub checktools
{
	# we can assume at this point they have perl :)
	my %need=( mp3info => ["mp3info"],
			   ogg => ["ogginfo"],
			   flac => [qw(metaflac flac md5sum)]);

	use vars qw($tool $program $path);

	format STDOUT_TOP =
Program          Tool            Location
---------------------------------------------------------------------------
.

	format STDOUT =
@<<<<<<<<<<<<<<< @<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$program,              $tool,          $path
.

	for $tool (keys(%need))
	{
		for $program (@{$need{$tool}})
		{
			$path=findprogram($program);
			unless(defined($path))
			{
				$path="not found\n";
			}
			write;
		}
	}
	
	# handle mp3check specially because of alternate names 
	$tool="mp3check";
	$program="mp3check";
	$path=findprogram($program);
	unless(defined($path))
	{
		$program="checkmp3";
		$path=findprogram($program);
	}
	unless(defined($path))
	{
		$path="not found";
	}
	write;

	# check for MP3::Tag
	$tool="id3";
	$program="MP3::Tag";
	$path="not found";
	if(eval("require MP3::Tag;"))
	{
		$path=$INC{'MP3/Tag.pm'};
	}
	write;
	exit;

}

sub usage
{
	my $toolspath="/MP3/Archive/Lint/Tools/";
	my %tools=();

	# ensure .mp3lintrc gets created
	unless(defined($archive))
	{
		$archive=MP3::Archive->new(MP3::Archive::Lint::Conf->new);
	}
	foreach my $prefix (@INC)
	{
		my $toolsdir=$prefix.$toolspath;
		if(-d $toolsdir)
		{
			if(opendir(D,$toolsdir))
			{
				while($_=readdir(D))
				{
					if(/^([A-Z].*)\.pm$/)
					{
#						my $name=MP3::Archive::Lint::Tool::module2tool($1);
						my $name=module2tool($1);
						$tools{$name}++;
					}
				}
				closedir(D);
			}
		}
	}

	my $toolstr;
	if(keys(%tools))
	{
		$toolstr="Tools: ".join(',',sort keys %tools)."\n";
	}
	else
	{
		$toolstr="No tools found, check PERLLIB environment variable\n";
	}


	die( "$me [-natsfiqdc] [-T tool] [-X tool] (file.mp3|dir)...\n" .
		 " -n\t\tSkip filename related tests\n" .
		 " -a\t\tDefault to treating unknown files as album tracks.\n" .
		 " -t\t\tDefault to treating unknown files as non-album tracks.\n" .
		 " -s\t\tDefault to skipping name tests on unknown files.\n" .
		 " -f\t\tFix problems (where possible).\n" .
		 " -i\t\tIgnore .mp3lintskip files.\n" .
		 " -q\t\tQuick scan (avoid timeconsuming tests).\n" .
		 " -d\t\tDebug mp3lint.\n" .
		 " -T tool1,tool2\tJust run named tools (default: run all tools).\n".
		 " -X tool1,tool2\tSkip named tools.\n".
		 " -c\t\tCheck for needed support software.\n".
		 " -h\t\tThis help.\n".
		 $toolstr
		 );
}

__END__

=head1 NAME

mp3lint - checks directories of audio files for problems

=head1 SYNOPSIS

B<mp3lint> [I<-natsfiqdch>] [I<-T tool>] [I<-X tool>] (I<file.mp3>|I<dir>)...

=head1 DESCRIPTION

mp3lint is a tool to check collections of audio files for various
problems. It is highly configurable, allowing you to specify your
preferred format for filenames, minimum bitrate, tests to ignore,
etc. Formats checked are currently mp3, ogg, wav, flac, au, and m3u
playlists.  mp3lint is implemented as seperate tools (perl modules),
each of which implements a set of tests.

To see which tools and tests are available, see L<mp3lint-tools(3)>.

To find out about configuring mp3lint, see L<mp3lintrc(5)>.

To find out about suppressing messages you don't care about, see
L<mp3lintskip(1)>.

To find out about summarising the messages from mp3lint, see
L<mp3lintsum(1)>

=head1 QUICKSTART

For a first run, try B<mp3lint -n musicdir/>

To check for supplementary programs used by mp3lint, use
B<mp3lint -c>

If the number of messages from mp3lint is overwhelming, use
L<mp3lintsum(1)> to summarise them.

Later, you will want to configure your B<.mp3lintrc> to specify your
filename formats, etc. (See L<mp3lintrc(5)>) When you have done that,
you can try again without the B<-n> flag to run the filename tests
too.

When you have fixed all the problems you can/want to fix, run
B<mp3lint musicdir/ |mp3lintskip -v> which will tell mp3lint
to ignore all current warnings in future, and only tell you
about new ones.

=head1 OPTIONS

=over 4

=item B<-n>

Skip filename related tests

=item B<-a>

If it cannot work out from a files location whether to treat it as an
album track or non-album track, it defaults to album track.

This is the same as setting the B<$format_default> configuration
variable (see L<mp3lintrc(5)>) to B<"album">, and overrides that
setting.

=item B<-t>

If it cannot work out from a files location whether to treat it as an
album track or non-album track, it defaults to non-album (standalone)
track.

This is the same as setting the B<$format_default> configuration
variable to B<"track">, and overrides that setting.

=item B<-s>

If it cannot work out from a files location whether to treat it as an
album track or non-album track, it defaults to skipping all name-related tests.

This is the same as setting the B<$format_default> configuration
variable to B<"album">, and overrides that setting.

=item B<-f>

Fix problems, where possible. Currently it only fixes permissions
(filesys:perms) and various filename formatting problems
(filename:caps, filename:ext, filename:disc, filename:the and
filename:paren).

B<WARNING:> All the code for skipping messages (see L<mp3lintskip(1)>)
works by postprocessing the output, which means you cannot use it to disable
particular fixes. Use B<-f> with care, and make sure you are happy with
your configuration (see L<mp3lintrc(5)>) first.	

=item B<-i> 

Ignore .mp3lintskip files

=item B<-q>

Quick scan (avoid timeconsuming tests)

=item B<-d> 

Debug mp3lint

=item B<-T> I<tool1,tool2> 

Just run named tools (default: run all tools)

=item B<-X> I<tool1,tool2>

Skip named tools

=item B<-c>

Report on which of the supplementary programs used by mp3lint are
installed.  mp3lint will still work without them, but some tests will
be disabled.

=item B<-h>

Brief usage summary

=item B<file.mp3E<verbar>dir>

Files and/or directories to check. If given a directory, mp3lint
checks all files and dirs in it recursively.

=back

=head1 OUTPUT

All warnings display a single line message in a common format.  This
consists of either 4 or 5 fields, separated by colons ('B<:>').

The fields are as follows:

B<toolname>:B<test>:B<description>:B<details>:B<filename>

The first 3 fields contain constant text, suitable for filtering. See
L<mp3lintskip(1)> and B<$lint_skip> in L<mp3lintrc(5)> for more information.

The B<details> field is optional and does not appear in all messages.

=head2 Examples

With the details field:

B<wav:samplerate:S<low samplerate>:S<8000 Hz (should be 44100Hz)>:S<./skipname/u-law.wav>>

without the details field:

B<filename:ext:uppercase extension:./skipname/mp3.WAV>

Different tools have the same name for common tests, for instance the
B<mp3info>, B<flac>, B<ogg>, and B<wav> tools all implement a
B<samplerate> test.


=head1 SOFTWARE NEEDED

To make full use of mp3lint, a number of pieces of software written by
other people are needed. If something isn't installed, the relevant
tests will silently be skipped (unless debug mode (B<-d>) is on, in
which case you will be warned).

To see which programs are installed, type B<mp3lint -c>.

For debian, all needed software is listed as dependencies, so should
be installed automatically. See below for more details

=head2 What you need and where to get it

=over 4

=item B<perl>

mp3lint was written using perl v5.6.1, but I've tried to avoid the
latest features so it should hopefully run on any moderately recent
perl 5. If perl isn't installed, look for a package from your OS
vendor, or failing that, shake your head sadly and go to
L<http:E<sol>E<sol>www.cpan.orgE<sol>srcE<sol>>. Perl is not optional.

=item B<MP3::Archive>

Available from http://nessie.mcc.ac.uk/~ianb/projects/libmp3-archive-perl/
Unlike the software that follows, MP3::Archive is required for
mp3lint to work.	

=item B<MP3::Tag> (needed for C<id3> tool)

This is a suite of perl modules for handling id3V1/2 tags. Hopefully
it can be installed by typing (as root):

	# perl -MCPAN -e shell
	cpan> install MP3::Tag
	cpan> quit

If you have problems with the CPAN client, download MP3::Tag from
L<http:E<sol>E<sol>www.cpan.orgE<sol>modulesE<sol>by-moduleE<sol>MP3E<sol>tagged-0.40.tar.gz>
(or any later version).

This follows the standard perl installation procedure as used by
mp3lint, ie unpack,  C<perl Makefile.PL>, C<make>, C<make install>. You will
need to be root for C<make install>.

The I<tagged> package has a web page at L<http:E<sol>E<sol>tagged.sourceforge.netE<sol>>

=item B<Text::Autoformat> (needed for C<filename> tool)

This is Damian Conway's incredibly smart text formatting module.
If installed, it is used for working out filename capitalisation.
If not, a crude internal version is used.

It is available on CPAN, and can be downloaded and installed using the
same methods as MP3::Tag, above. 

If you have problems with the CPAN client, download Text::Autoformat from
L<http:E<sol>E<sol>www.cpan.orgE<sol>modulesE<sol>by-moduleE<sol>TextE<sol>Text-Autoformat-1.12.tar.gz>
(or any later version).

=item B<mp3info> (needed for tool C<mp3info>)

There are two programs called mp3info available on the net. This
expects the one that is at L<http:E<sol>E<sol>ibiblio.orgE<sol>mp3info> It is also
the version that Debian users get if they type C<apt-get install
mp3info>

=item B<mp3_check> (needed for tool C<mp3check>)

mp3_check is available from sourceforge, see
L<http:E<sol>E<sol>sourceforge.netE<sol>projectE<sol>?group_id=6126>

On debian systems, it is known as C<checkmp3> and can be installed by
typing C<apt-get install checkmp3> as root. The C<mp3check> tool
searches for either name.

=item B<ogginfo> (needed for tool C<ogg>)

Available from L<http:E<sol>E<sol>www.vorbis.comE<sol>download_unix.psp>

=item B<flac>, B<metaflac> (needed for tool C<flac>)

Available from L<http:E<sol>E<sol>flac.sourceforge.netE<sol>download.html>

=back

=head2 Other Required software you probably have

=over 4

=item B<File::Find>, B<File::stat>, B<Cwd>

These perl modules are a part of the standard distributions

=item B<md5sum> (needed for tool C<flac>)

If you don't already have it installed, look for a C<coreutils> or
C<textutils> package from your OS vendor, or see
L<http:E<sol>E<sol>www.gnu.orgE<sol>coreutilsE<sol>>

=item B<sort> (needed for test suite)

Any self-respecting unix box has this. If not, look in the same places
as for C<md5sum>, above.

=item B<diff> (needed for test suite)

Unless your vendor hates you, you should have this too. If not, go to 
L<http:E<sol>E<sol>www.gnu.orgE<sol>softwareE<sol>diffutilsE<sol>>. On debian systems, type
C<apt-get install diff> as root.

=back

=head2 Debian users

If mp3lint was installed using a tool like L<apt-get(1)>, all needed
software will have been installed via dependencies. If not (eg, you
downloaded the .deb and used dpkg):

	# apt-get install libmp3-tag-perl mp3info checkmp3 vorbis-tools flac diff

You will also need to install libmp3-archive-perl, available from the same
place you got mp3lint (see AVAILABILITY, below).

=head1 FILES

=over 4	

=item B<.mp3lintrc>, B</etc/mp3lintrc>

Configuration files, see L<mp3lintrc(5)> for details.	

=item B<.mp3lintskip>, B<$HOME/.mp3lintskip-global>

Warnings to skip. See L<mp3lintskip(1)> for details.

=back	

=head1 ENVIRONMENT

=over 4

=item  B<$MP3LINTRC>

If set, uses this instead of $HOME/.mp3lintrc

=item  B<$HOME>

Used to find .mp3lintrc and .mp3lintskip-global	

=item  B<$PATH>

Used to find auxillary programs needed by various tools.

=back

=head1 PORTABILITY

mp3lint was developed in perl under linux. It should be trivial to get
it working on any POSIX based system. If you get it working with
windows, let me know.

=head1 BUGS

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

I am especially interested in how well the code for filename formats
works for other people's naming styles. 

=head1 SEE ALSO    

L<mp3lint-tools(3)>, L<mp3lintskip(1)>, L<mp3lintsum(1)>,
L<mp3lintrc(5)>, L<MP3::Archive(3)>, L<MP3::Archive::Config(3)>,
L<mp3-archive-tools(1)>

L<perl(1)>, L<MP3::Tag(3)>, L<mp3info(1)>, L<mp3_check(1)>,
L<checkmp3(1)>, L<ogginfo(1)>, L<flac(1)>, L<metaflac(1)>,
L<md5sum(1)>, L<sort(1)>, L<diff(1)>

=head1 AUTHOR

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

=head1 AVAILABILITY

The latest version can be found at:

B<http://nessie.mcc.ac.uk/~ianb/projects/mp3lint/>

=head1 COPYRIGHT

Copyright 2003 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


