#!/usr/bin/env perl ############################################################################### # # shredder.pl - version 2.0 (everything is 2.0 nowadays) # # The original one got lost so here's another attempt in creating the # ultimate mp3 renaming lump of Perl code # # needs MP3::ID3v1Tag to work on ID3 tags ... # # TODO: # - File::Copy sucks big time. As we move files in a local directory only # I reverted to Perls internal rename with does NOT work across filesystems # - take longest title name (i.e. from filename) as some ID3 tags are truncated # # ChangeLog: # # 20070304: allow empty album name, CLI -c will reset album name # chmod files, rename only if names differ # # Hendrik Scholz # ############################################################################### use strict; use warnings; use Getopt::Std; use Class::Struct; use File::Copy; use MP3::Tag; use vars qw/%opt/; struct (finfostruct => { artist => '$', album => '$', title => '$', track => '$' }); ### emptytags ################################################################# # # zero a finfo struct # sub emptytags { my $finfo = shift; $finfo->artist(""); $finfo->album(""); $finfo->title(""); $finfo->track(""); } ### gettagsfromfile ########################################################### # # read track information from filename # sub getinfofromfilename { my $file = shift; my $finfo = shift; if (!$file || !$finfo) { return } my $f = $file; $f =~ s/_/\ /g; # replace spaces # differ between formats if ($f =~ /^(\d+)\s+(.+)\s+-\s+(.+)\.[mM][pP]3$/) { # i.e. 02 Lcd Soundsystem - Too Much Love.mp3 $finfo->track($1); $finfo->artist($2); $finfo->title($3); } elsif ($f =~ /^(.+)\s+-\s+(.+)\s+-\s+(.+)\.([mM][pP]3|[mM]4[aA])$/) { # i.e. LCD_Soundsystem_-_LCD_Soundsystem_-_On_Repeat.mp3 $finfo->artist($1); $finfo->album($2); $finfo->title($3); } elsif ($f =~ /^(\d+)\.\s+(.+)\s+-\s+(.+)\.([mM][pP]3|[mM]4[aA])$/) { # i.e. 17. JOHNY CROCKETT - E For Electro.mp3 $finfo->track($1); $finfo->artist($2); $finfo->title($3); } elsif ($f =~ /^(\d+)\s+-\s+(.+)\.[mM][pP]3$/) { # i.e. 08 - Valley Of Debris.mp3 $finfo->track($1); $finfo->title($2); } elsif ($f =~ /^(\d+)\s+(.+)\.[mM][pP]3$/) { # i.e. 08 Valley Of Debris.mp3 $finfo->track($1); $finfo->title($2); } elsif ($f =~ /(.+)\s+-\s+(.+)\.[mM][pP]3$/) { $finfo->artist($1); $finfo->title($2); } elsif ($f =~ /^\((\d+)\)\s+\[(.+)\]\s+(.+)\.([mM][pP]3|[mM]4[aA])$/) { # i.e. (21) [Mando Diao] Down In The Past (Moonbootica Remix).mp3 $finfo->track($1); $finfo->artist($2); $finfo->title($3); } else { print "NO MATCH: '$file' format is unknown\n"; return 0; } return 1; } ### gettagsfromid3 ############################################################ # # read id3 tags from mp3 meta information # sub getid3fromfile { my $file = shift; my $finfo = shift; if (!$file || !$finfo) { return } my $mp3 = MP3::Tag->new($file); $mp3->get_tags(); if (!exists $mp3->{ID3v1}) { return } if ($mp3->{ID3v1}->artist()) { $finfo->artist($mp3->{ID3v1}->artist()) } if ($mp3->{ID3v1}->album()) { $finfo->album($mp3->{ID3v1}->album()) } if ($mp3->{ID3v1}->track()) { $finfo->track($mp3->{ID3v1}->track()) } if ($mp3->{ID3v1}->title()) { $finfo->title($mp3->{ID3v1}->title()) } $mp3->close(); return; } ### getinfofromgetopt ######################################################### # # get file information from command line # sub getinfofromgetopt { my $finfo = shift; return if (!$finfo); $finfo->artist($opt{A}) if $opt{A}; $finfo->album($opt{C}) if $opt{C}; $finfo->title($opt{T}) if $opt{T}; $finfo->album("") if $opt{c}; return; } ### usage ##################################################################### # # print usage and die # sub usage { print "$0 [h] \n"; print "\t-A set artist name\n"; print "\t-C set album name\n"; print "\t-c reset albume name\n"; print "\t-s set ID3 tag and rename file\n"; print "\t-I ignore ID3 tags from file\n"; exit(0); } ### savefile ################################################################## # # write ID3tag and rename file # sub savefile { my $file = shift; my $finfo = shift; if (!$file || !$finfo) { return } # ID3 part my $mp3 = MP3::Tag->new($file); $mp3->get_tags(); $mp3->{ID3v1}->remove_tag() if exists($mp3->{ID3v1}); $mp3->{ID3v2}->remove_tag() if exists($mp3->{ID3v2}); my $id3v2 = $mp3->new_tag("ID3v2"); $id3v2->remove_tag(); $id3v2->artist($finfo->artist) if ($finfo->artist); $id3v2->album($finfo->album) if ($finfo->album); $id3v2->track($finfo->title) if ($finfo->title); $id3v2->title($finfo->title) if ($finfo->title); $id3v2->write_tag(); my $id3v1 = $mp3->new_tag("ID3v1"); $id3v1->remove_tag(); $id3v1->artist($finfo->artist) if ($finfo->artist); $id3v1->album($finfo->album) if ($finfo->album); $id3v1->track($finfo->title) if ($finfo->title); $id3v1->title($finfo->title) if ($finfo->title); $id3v1->write_tag(); $mp3->close(); # file name # you may want to define your own filename format here if (!$finfo->artist || !$finfo->title) { print "crucial MP3 information is missing ... not renaming\n"; return; } # prefix track with 0 if needed $finfo->track("0".$finfo->track) if ($finfo->track < 10); my $newname = $finfo->artist." - ". (($finfo->album) ? $finfo->album." - " : ""). (($finfo->track) ? $finfo->track." - " : ""). $finfo->title.".mp3"; $newname =~ s/\ /_/g; # replace spaces print "new name: $newname\n"; my $mode = 0644; chmod ($mode, $file); #system ("mv \"$file\" \"$newname\"") if ($newname ne $file); #move ($file, $newname); rename ($file, $newname) if ($newname ne $file); return; } ### finfodump ################################################################# # # print information in finfo structure # sub finfodump { my $finfo = shift; print " artist: ", $finfo->artist, "\n"; print " album: ", $finfo->album, "\n"; print " track: ", $finfo->track, "\n"; print " title: ", $finfo->title, "\n"; return; } ### main ###################################################################### getopts("hcsIA:C:T:", \%opt) or usage(); usage() if $opt{h}; opendir(FILES, ".") || die "opendir failed: $!"; my @files = grep {/\.([Mm][Pp]3|[mM]4[aA])$/ && -f $_} readdir (FILES); closedir(FILES); foreach my $file (@files) { print "_" x 79, "\n\n"; print "working on $file\n"; my $finfo = new finfostruct; emptytags($finfo); getinfofromfilename($file, $finfo); if (!$opt{I}) { getid3fromfile($file, $finfo); } getinfofromgetopt($finfo); finfodump($finfo); savefile($file, $finfo) if $opt{s}; my $newname = $finfo->artist." - ". (($finfo->album) ? $finfo->album." - " : ""). (($finfo->track) ? $finfo->track." - " : "") .$finfo->title.".mp3"; $newname =~ s/\ /_/g; # replace spaces } if ($opt{s}) { print "_" x 79, "\n\n"; opendir(FILES, ".") || die "opendir failed: $!"; @files = grep {/\.(m3u|pls|txt|sfv|url|nfo)$/ && -f $_} readdir (FILES); closedir(FILES); foreach my $file (@files) { print "removing $file\n"; unlink($file); } opendir(FILES, ".") || die "opendir failed: $!"; @files = grep {/\.(JPG|jpg|jpeg)$/ && -f $_} readdir (FILES); closedir(FILES); my $mode = 0644; foreach my $file (@files) { print "chmodding $file\n"; chmod($mode, $file); } } exit(0);