#!/usr/local/bin/perl -w
# $Id: id3tofilename,v 1.7 2003/12/12 06:30:10 ianb Exp $
# Ian Beckwith <ianb@nessie.mcc.ac.uk>
# v1 20030509
# v2 20031024 MP3::Archive support, more options.

use strict;
use MP3::Tag;
use Cwd;

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

my $archive=undef;
if(eval("require MP3::Archive;"))
{
	$archive=new MP3::Archive;
}
else
{
	warn("$me: cannot find MP3::Archive. Carrying on anyway...\n");
}

use vars qw($USEEITHER $USEONE $USETWO $ALBUM $TRACK $GUESS);
$USEEITHER=0;
$USEONE=1;
$USETWO=2;
my $use=$USEEITHER;

$ALBUM=0;
$TRACK=1;
$GUESS=2;
my $tracktype=$GUESS;
my $verbose=0;
my $dryrun=0;
my $doneargs=0;
my ($dotracknum,$doartist,$doalbum,$dotrack)=(0,0,0,0);
my $doall=1;
my $donesomething=0;

while($_=shift)
{
	if(/^-/ && !$doneargs)
	{
		if(/-1/)    { $use=$USEONE;      }
		elsif(/-2/) { $use=$USETWO;      }
		elsif(/-v/) { $verbose=1;        }
		elsif(/-q/) { $verbose=0;        }
		elsif(/-d/) { $dryrun=1;         }
		elsif(/-a/) { $tracktype=$ALBUM; }
		elsif(/-t/) { $tracktype=$TRACK; }
		elsif(/-g/) { $tracktype=$GUESS; }
		elsif(/-N/) { $dotracknum=1; $doall=0; }
		elsif(/-A/) { $doartist=1;   $doall=0; }
		elsif(/-L/) { $doalbum=1;    $doall=0; }
		elsif(/-T/) { $dotrack=1;    $doall=0; }
		elsif(/-h/) { usage();           }
		elsif(/--/) { $doneargs=1;       }
		else { usage(); }
		next;
	}
	$donesomething=1;
	my $file=$_;
	unless(-e $file)
	{
		warn("$me: $file: not found\n");
		next;
	}

	if($dotracknum && $doartist && $doalbum && $dotrack)
	{
		$doall=1;
	}

	if((!defined($archive)) && (!$doall))
	{
		die("$me: -N, -A, -L and -T only supported with MP3::Archive\n");
	}	

	my $mp3=MP3::Tag->new($file);
	unless($mp3)
	{
		warn("$me: cannot open $file: $!\n");
		next;
	}
	
	$mp3->get_tags;

	my $id3=undef;
	my $ver=undef;
	if(exists($mp3->{ID3v2}))
	{
		unless($use==$USEONE)
		{
			$ver="ID3v2";
			$id3=$mp3->{ID3v2};
		}
	}
	elsif(exists($mp3->{ID3v1}))
	{
		unless($use==$USETWO)
		{
			$ver="ID3v1";
			$id3=$mp3->{ID3v1};
		}
	}
	else
	{
		warn("$me: $file: no id3 tags found\n");
		next;
	}

	unless(defined $id3)
	{
		warn("$me:$file:cannot find requested ",
			 ("","ID3v1 ","ID3v2 ")[$use],
			 "tag\n");
		next;
	}
	my $id3tracknum=$id3->track;
	my $id3artist=$id3->artist;
	my $id3album=$id3->album;
	my $id3track=$id3->song;

	$mp3->close;
	
	unless(defined ($id3tracknum))
	{
		warn("$me:$file:no tracknumber defined in $ver tag\n");
		next;
	}

	unless(defined ($id3artist))
	{
		warn("$me:$file:no artist defined in $ver tag\n");
		next;
	}

	unless(defined ($id3album))
	{
		warn("$me:$file:no album defined in $ver tag\n");
		next;
	}

	unless(defined ($id3track))
	{
		warn("$me:$file:no track defined in $ver tag\n");
		next;
	}

	if($id3tracknum=~/^\d$/)
	{
		$id3tracknum="0$id3tracknum";
	}
	
	# default if MP3::Archive not installed
	my $newfile="$id3tracknum - $id3artist - $id3album - $id3track.mp3";
	
	if(defined($archive))
	{
		my ($ftracknum,$fartist,$falbum,$ftrack);
		if((!$dotracknum) && (!$doall))
		{
			$ftracknum=$archive->tracknum($file,$tracktype);
			unless(defined($ftracknum))
			{
				print("$me: $file: cannot extract tracknum, skipping.\n");
				next;
			}
			$id3tracknum=$ftracknum;
		}
		if((!$doartist) && (!$doall))
		{
			$fartist=$archive->artist($file,$tracktype);
			unless(defined($fartist))
			{
				print("$me: $file: cannot extract artist, skipping.\n");
				next;
			}
			$id3artist=$fartist;
		}
		if((!$doalbum) && (!$doall))
		{
			$falbum=$archive->album($file,$tracktype);
			unless(defined($falbum))
			{
				print("$me: $file: cannot extract album, skipping.\n");
				next;
			}
			$id3album=$falbum;
		}
		if((!$dotrack) && (!$doall))
		{
			$ftrack=$archive->track($file,$tracktype);
			unless(defined($ftrack))
			{
				print("$me: $file: cannot extract track, skipping.\n");
				next;
			}
			$id3track=$ftrack;
		}
		
		$newfile=$archive->makefilename($file,$id3tracknum,$id3artist,$id3album,$id3track,"mp3",$tracktype);
	}

	if($newfile eq $file)
	{
		next;
	}
	
	if(-e $newfile)
	{
		warn("$me:$file: cannot rename: file exists: $newfile\n");
		next;
	}
	
	my $skip=0;
	unless($dryrun)
	{
		unless(rename($file,$newfile))
		{
			$skip=1;
			warn("$me:$file: cannot rename to $newfile:$!\n");
		}
	}

	if((!$skip) && ($verbose || $dryrun))
	{
		print("$file -> $newfile\n");
	}
}

usage() unless($donesomething);

sub usage
{
	die("Usage: $me [-vqd12atgNALT] file.mp3..\n".
		" -v\tVerbose.\n".
		" -q\tQuiet (default).\n".
		" -d\tDry run (just show what it would do).\n".
		" -1\tRead ID3v1 tag only.\n".
		" -2\tRead ID3v2 tag only.\n".
		" -a\tTreat as album tracks.\n".
		" -t\tTreat as non-album tracks.\n".
		" -g\tGuess track type from file location (default).\n".
		" -N\tSet trackNumber.\n".
		" -A\tSet Artist.\n".
		" -L\tSet aLbum.\n".
		" -T\tSet Track.\n".
		" -h\tThis help.\n".
		" --\tEnd of options.\n".
		"Default: set all four data types.\n".
		"-N/-A/-L/-T require the current filename to be parsable.\n");
}

		
__DATA__

=head1 NAME

id3tofilename - renames mp3 files based on id3 metadata

=head1 SYNOPSIS

B<id3tofilename> [I<-v>] [I<-q>] [I<-d>] [I<-1>] [I<-2>] [I<-a>] [I<-t>] [I<-g>] [I<-N>] [I<-A>] [I<-L>] [I<-T>] [I<-h>] [I<file.mp3>...]

=head1 DESCRIPTION

id3tofilename renames mp3 files based on the metadata in id3 tags.
For details of how to specify the resulting filename formats, by
configuring F<.mp3archiverc>, see L<MP3::Archive::Config(3)>.

If any of the B<-N>/B<-A>/B<-L>/B<-T> options are set, it gets the
remaining data from the current filename, so the filename must already
be parsable by L<MP3::Archive(3)>. If none of those options are
supplied, it defaults to setting all data in the filename from the id3
tags, so the current filename does not have to be in any particular
format.

=head1 OPTIONS

=over 4

=item B<-v>

Verbose

=item B<-q>

Quiet (no output). This is the default.

=item B<-d>

Dry run. Just show what it would do.

=item B<-1>

Use ID3V1 tag only

=item B<-2>

Use ID3V2 tag only

=item B<-a>

Treat files as album tracks.

=item B<-t>

Treat files as non-album tracks.

=item B<-g>

Guess whether to treat files as album tracks or not, based on the
current directory of the file.

=item B<-N>

Only set the TRKNUM field from id3 tags.

=item B<-A>

Only set the ARTIST field from id3 tags.

=item B<-L>

Only set the ALBUM field from id3 tags.

=item B<-T>

Only set the TRACK field from id3 tags.

=item B<-h>

Show a short help message.

=back

=head1 BUGS

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

=head1 SEE ALSO    

L<filenametoid3(1)>, L<MP3::Archive(3)>, L<MP3::Archive::Config(3)>,
L<mp3-archive-tools(1)>, L<mp3lint(1)>

=head1 AUTHOR

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

=head1 AVAILABILITY

id3tofilename 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 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


	
