Category: Utility
Author/Contact Info vim@fubaria.net
Description: This started as a one-liner, grew into a sizeable snippet.. and eventually (after posting first few versions to snippets node) grew even larger.
It'll take (IMHO broken) filenames that include spaces, (') single quotes, and (\) slashes (possibly from really bad renaming mishaps), and replace them with command-line friendly undercarriages (_).
i'm certain it could be written better, or smaller, but i didn't want to use filename globbing (due to some systems failing on <*.pattern> and glob();)
#!/usr/bin/perl -w
#    mp3.pl v0.9 by strfry()  (vim@fubaria.net)    
#    filenames (eg. mp3's) that have silly characters in them, like   
+     #
#    \'s, single quotes ('), and spaces (" ").    
#
#    can now do recursive renames (be careful!) (8
#                    
############################################################








use strict;    # or die $!

use File::Find;            # for recursive capability.
use Getopt::Std;        # grab command-line switches.
use vars qw/$opt_h $opt_r/;    # make sure we have variables for getop
+t.
getopts('hr');            # grab 'em.


$0=~s|.*[/\\]||;        # remove trailing crap from $0 
my $bl = "\e[1;30m";        # $bl == black
my $red = "\e[0;31m";        # $red == duh!
my $cl = "\e[m";        #



### catch the command-line and switches here. ###

my($arg) = $ARGV[0] if ($ARGV[0]);
&usage if ((!$ARGV[0]) || ($opt_h));
&usage if($opt_h);

&simple_rename($arg) if (!$opt_r);
if ($opt_r){
find(\&wanted, $arg);
print "\n\tfinished recursing $arg\n\n";
}




####################################
#                   #    
# sub-routines go here.           # 
#                   #
####################################


sub usage {

die "usage\e[1m:\e[m $0 \e[1;30m/\e[mpath\e[1;30m/\e[mto\e[1;30m/\e[mm
+p3\e[1;30m/\e[mdirectory \n\n"," " x 7, "Get rid of annoying characte
+rs out of files (spaces and single quotes)\n", " " x 7,"you \e[31mmus
+t\e[m have read\e[1;30m/\e[mwrite permission to directory!\n", " " x 
+7, "eg. $0 \e[1;34m~\e[m\e[1;30m/\e[mmp3s\e[1;30m/\e[m\n";


}



sub simple_rename {


my($cwd) = $_[0];
opendir(DIR, "$cwd") or die "can't open $cwd: $! !\n";

my @mp3s = grep { /^[^\.].*\.mp3$/ && -f "$cwd/$_" } readdir(DIR);clos
+edir(DIR);

opendir(DIR, "$cwd") or die "can't open $cwd: $! !\n";
my @skipped = grep { /^[\.].*\.mp3$/ && -f "$cwd/$_" } readdir(DIR);cl
+osedir(DIR);
chdir "$cwd" or die "couldn't cd to $cwd: $!\n";

foreach (@mp3s) {

    if ((/ /) or (/'/) or (/\\/)){

    my $old = $_;
    s/ /_/g;
    s/'//g;
    s/\\//g;
    rename $old,$_;
    print "$cwd: $old \e[31m->\e[m $_ \n";
}
}

foreach (@skipped){ 

    print "skipped [\e[1;34m$_\e[m] due to leading dot. (\".\")\n";
}


}


sub wanted {
      return unless -d $_; 
      my $bwd = `pwd`; chomp($bwd);
      my $cwd = $_;
      opendir(DIR, "$cwd") or die "can't open $cwd: $! !\n";
      my @mp3s = grep { /^[^\.].*\.mp3$/ && -f "$cwd/$_" } readdir(DIR
+);closedir(DIR);
    opendir(DIR, "$cwd") or die "can't open $cwd: $! !\n";
    my @skipped = grep { /^[\.].*\.mp3$/ && -f "$cwd/$_" } readdir(DIR
+);closedir(DIR);
    chdir "$cwd" or die "couldn't cd to $cwd: $!\n";
    print "$bl\[$red", "recurse$bl($red$bwd$bl/$red$cwd$bl/$bl)]$cl\n"
+;

    foreach (@mp3s) {

            if ((/ /) or (/'/) or (/\\/)){

            my $old = $_;
            s/ /_/g;
            s/'//g;
            s/\\//g;
               rename $old,$_;
        print "$cwd\e[1m:\e[m $old \e[31m->\e[m $_ \n";
        }
    }
     chdir "$bwd" or print "couldn't chdir to $bwd: $!\n";
}
Replies are listed 'Best First'.
Re: mp3 filename fixer
by cforde (Monk) on Jul 19, 2001 at 21:41 UTC
    How 'bout using MPEG::MP3Info to obtain the song name stored in the MP3 tags, apply your transformation and use that as the file name?

    Have fun,
    Carl Forde