MP3-Tag-Utils/lib/MP3/Tag/Utils.pm

627 lines
11 KiB
Perl

package MP3::Tag::Utils;
use warnings;
use strict;
use MP3::Tag;
use Text::NeatTemplate;
=head1 NAME
MP3::Tag::Utils - Assorted utilities for manipulating MP3 files via MP3::Tag.
=head1 VERSION
Version 0.0.0
=cut
our $VERSION = '0.0.0';
=head1 SYNOPSIS
use MP3::Tag::Utils;
my $foo = MP3::Tag::Utils->new();
...
=head1 METHODS
=head2 new
=cut
sub new{
my %args;
if (defined($_[1])) {
%args=%{$_[1]};
}
my $method='new';
my $self={
perror=>undef,
error=>undef,
errorString=>'',
module=>'MP3-Tag-Utils',
};
bless $self;
return $self;
}
=head2 change
Change the tags on a MP3 file.
=head3 args hash
=head4 file
The file to operate on.
=head4 album
If this is defined, the tag is set to it.
=head4 artist
If this is defined, the tag is set to it.
=head4 comment
If this is defined, the tag is set to it.
=head4 genre
If this is defined, the tag is set to it.
=head4 title
If this is defined, the tag is set to it.
=head4 track
If this is defined, the tag is set to it.
=head4 year
If this is defined, the tag is set to it.
$foo->change(\%args);
if($foo->error){
warn('Error '.$foo->error.': '.$foo->errorString);
}
=cut
sub change{
my $self=$_[0];
my %args;
if (defined($_[1])) {
%args=%{$_[1]};
}
my $method='rename';
#blanks any previous errors
if (!$self->errorblank) {
warn($self->{module}.' '.$method.': Unable to blank previous error');
return undef;
}
#makes sure some files are specified.
if (!defined($args{file})) {
$self->{error}=1;
$self->{errorString}='No file specified';
warn($self->{module}.' '.$method.':'.$self->error.': '.$self->{errorString});
return undef;
}
#make sure something to change is specified
if (
(!defined( $args{album} )) &&
(!defined( $args{artist} )) &&
(!defined( $args{comment} )) &&
(!defined( $args{genre} )) &&
(!defined( $args{title} )) &&
(!defined( $args{track} )) &&
(!defined( $args{year} ))
) {
$self->{error}=3;
$self->{errorString}='Nothing specified to change';
warn($self->{module}.' '.$method.':'.$self->error.': '.$self->{errorString});
return undef;
}
#makes sure it appears to be a MP3
if ($args{file} !~ /[Mm][Pp]3$/) {
$self->{error}=4;
$self->{errorString}='Not a MP3';
warn($self->{module}.' '.$method.':'.$self->error.': '.$self->{errorString});
return undef;
}
#makes sure the track is numeric
if (
defined($args{track}) &&
($args{track} !~ /^[0123456789]*$/)
) {
$self->{error}=5;
$self->{errorString}='Track is not numeric';
warn($self->{module}.' '.$method.':'.$self->error.': '.$self->{errorString});
return undef;
}
#makes sure the year is numeric
if (
defined($args{year}) &&
($args{year} !~ /^[0123456789]*$/)
) {
$self->{error}=5;
$self->{errorString}='Track is not numeric';
warn($self->{module}.' '.$method.':'.$self->error.': '.$self->{errorString});
return undef;
}
my $mp3=MP3::Tag->new($args{file});
delete($args{file});
$mp3->update_tags(\%args);
return 1;
}
=head2 rename
This renames files.
One argument is taken and it is a hash ref.
The returned argument is a hash ref.
=head3 args hash ref
=head4 files
This is a array of files to rename.
=head4 template
This is the template to use for renaming a file.
The template keys are listed below.
{$title}
{$track}
{$artist}
{$album}
{$comment}
{$year}
{$genre}
The default template is.
{$artist} - {$album} ({$year}) - {$track} - {$title}.mp3
=head3 return hash ref
=head4 failed
This is a array of failed files.
=head4 padto
This pads a the track out to be this wide with zeros. By default is is 2.
To disable this, set it to 0.
=head4 success
This is true if it succeeds.
If it any thing failed, this is set to false.
my $returned=$foo->rename(\%args);
if ( $foo->error || ){
}
=cut
sub rename{
my $self=$_[0];
my %args;
if (defined($_[1])) {
%args=%{$_[1]};
}
my $method='rename';
#blanks any previous errors
if (!$self->errorblank) {
warn($self->{module}.' '.$method.': Unable to blank previous error');
return undef;
}
if (!defined($args{padto})) {
$args{padto}=2;
}
#makes sure some files are specified.
if (!defined($args{files})) {
$self->{error}=1;
$self->{errorString}='No files specified';
warn($self->{module}.' '.$method.':'.$self->error.': '.$self->{errorString});
return undef;
}
if (ref($args{files}) ne 'ARRAY') {
$self->{error}=2;
$self->{errorString}='The key files is not a array.';
warn($self->{module}.' '.$method.':'.$self->error.': '.$self->{errorString});
return undef;
}
if (!defined($args{files}[0])) {
$self->{error}=1;
$self->{errorString}='No files specified';
warn($self->{module}.' '.$method.':'.$self->error.': '.$self->{errorString});
return undef;
}
my $template='{$artist} - {$album} ({$year}) - {$track} - {$title}.mp3';
if (defined($args{template})) {
$template=$args{template};
}
#this will be returned
my $toreturn={failed=>[], success=>1,};
#declare it here so it does not have to be constantly recreated
my $tobj = Text::NeatTemplate->new();
my $int=0;
while (defined( $args{files}[$int] )) {
if (
(! -r $args{files}[$int] ) ||
( $args{files}[$int] !~ /\.[Mm][Pp]3$/ )
) {
$toreturn->{success}=0;
push( @{ $self->{failed} }, $args{file}[$int] );
}else {
my $mp3=MP3::Tag->new( $args{files}[$int] );
my ($title, $track, $artist, $album, $comment, $year, $genre) = $mp3->autoinfo();
my $int2=length($track);
while ($int2 < $args{padto}) {
$track='0'.$track;
$int2++;
}
my %data=(
title=>$title,
track=>$track,
artist=>$artist,
album=>$album,
comment=>$comment,
year=>$year,
genre=>$genre,
);
my $newfilename=$tobj->fill_in(
data_hash=>\%data,
template=>$template,
);
rename($args{files}[$int], $newfilename);
}
$int++;
}
return $toreturn;
}
=head2 show
This returns a string containing a description of all the specified MP3s.
One argument is taken and it is a hash ref.
The returned argument is a hash ref.
=head3 args hash ref
=head4 files
This is a array of files to rename.
=head4 template
This is the template to use for renaming a file.
The template keys are listed below.
{$file}
{$title}
{$track}
{$artist}
{$album}
{$comment}
{$year}
{$genre}
The default template is.
File: {$file}
Artist: {$artist}
Album: {$album}
Year: {$year}
Track: {$track}
Title: {$title}
=head3 return hash ref
=head4 failed
This is a array of failed files.
=head4 padto
This pads a the track out to be this wide with zeros. By default is is 2.
To disable this, set it to 0.
=head4 success
This is true if it succeeds.
If it any thing failed, this is set to false.
my $returned=$foo->rename(\%args);
if ( $foo->error || ){
}
=cut
sub show{
my $self=$_[0];
my %args;
if (defined($_[1])) {
%args=%{$_[1]};
}
my $method='rename';
#blanks any previous errors
if (!$self->errorblank) {
warn($self->{module}.' '.$method.': Unable to blank previous error');
return undef;
}
if (!defined($args{padto})) {
$args{padto}=2;
}
#makes sure some files are specified.
if (!defined($args{files})) {
$self->{error}=1;
$self->{errorString}='No files specified';
warn($self->{module}.' '.$method.':'.$self->error.': '.$self->{errorString});
return undef;
}
if (ref($args{files}) ne 'ARRAY') {
$self->{error}=2;
$self->{errorString}='The key files is not a array.';
warn($self->{module}.' '.$method.':'.$self->error.': '.$self->{errorString});
return undef;
}
if (!defined($args{files}[0])) {
$self->{error}=1;
$self->{errorString}='No files specified';
warn($self->{module}.' '.$method.':'.$self->error.': '.$self->{errorString});
return undef;
}
my $template="File: {\$file}\n".
"Artist: {\$artist}\n".
"Album: {\$album}\n".
"Year: {\$year}\n".
"Track: {\$track}\n".
"Title: {\$title}\n\n";
if (defined($args{template})) {
$template=$args{template};
}
#this will be returned
my $toreturn={failed=>[], success=>1, show=>''};
#declare it here so it does not have to be constantly recreated
my $tobj = Text::NeatTemplate->new();
my $int=0;
while (defined( $args{files}[$int] )) {
if (
(! -r $args{files}[$int] ) ||
( $args{files}[$int] !~ /\.[Mm][Pp]3$/ )
) {
$toreturn->{success}=0;
push( @{ $self->{failed} }, $args{file}[$int] );
}else {
my $mp3=MP3::Tag->new( $args{files}[$int] );
my ($title, $track, $artist, $album, $comment, $year, $genre) = $mp3->autoinfo();
my $int2=length($track);
while ($int2 < $args{padto}) {
$track='0'.$track;
$int2++;
}
my %data=(
file=>$args{files}[$int],
title=>$title,
track=>$track,
artist=>$artist,
album=>$album,
comment=>$comment,
year=>$year,
genre=>$genre,
);
$toreturn->{show}=$toreturn->{show}.$tobj->fill_in(
data_hash=>\%data,
template=>$template,
);
}
$int++;
}
return $toreturn;
}
=head1 ERROR RELATED METHODS
=head2 error
This returns the current error value.
This returns a integer or undefined, Perl boolean value, indicating if
a error is present or not and if it is which.
if($foo->error){
print "Error Code: ".$foo->error."\n";
}
=cut
sub error{
return $_[0]->{error};
}
=head2 errorString
This turns the current error string.
if($foo->errorString ne ''){
print "Error String: ".$foo->errorString."\n";
}
=cut
sub errorString{
return $_[0]->{errorString};
}
=head2 errorblank
This blanks a error, if a permanent error is not set.
This is a internal method and there is no good reason to call it.
=cut
sub errorblank{
if ($_[0]->{perror}) {
warn($_[0]->{module}.' errorblank: Unable to blank error. A permanent one is set');
return undef;
}
$_[0]->{error}=undef;
$_[0]->{errorString}='';
return 1;
}
=head1 ERROR CODES
=head2 1
No files specified.
=head2 2
The files key does not contain a array.
=head2 3
No changes specified.
=head2 4
Does not appear to be a MP3.
=head2 5
Track is not numeric.
=head2 6
Year is not numeric.
=head1 AUTHOR
Zane C. Bowers, C<< <vvelox at vvelox.net> >>
=head1 BUGS
Please report any bugs or feature requests to C<bug-mp3-tag-utils at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=MP3-Tag-Utils>. I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.
=head1 SUPPORT
You can find documentation for this module with the perldoc command.
perldoc MP3::Tag::Utils
You can also look for information at:
=over 4
=item * RT: CPAN's request tracker
L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=MP3-Tag-Utils>
=item * AnnoCPAN: Annotated CPAN documentation
L<http://annocpan.org/dist/MP3-Tag-Utils>
=item * CPAN Ratings
L<http://cpanratings.perl.org/d/MP3-Tag-Utils>
=item * Search CPAN
L<http://search.cpan.org/dist/MP3-Tag-Utils/>
=back
=head1 ACKNOWLEDGEMENTS
=head1 LICENSE AND COPYRIGHT
Copyright 2010 Zane C. Bowers.
This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation; or the Artistic License.
See http://dev.perl.org/licenses/ for more information.
=cut
1; # End of MP3::Tag::Utils