http://www.perlmonks.org?node_id=985820

This script will create a folder hierarchy based on the tags of an MP3 file. It creates the folders and puts the MP3s in their respective folder. The folder hierarchy is /artist/album/*.mp3.

#!/usr/bin/perl use strict; use warnings; use MP3::Tag; use File::Copy::Recursive qw(fmove); foreach my $file (<*.mp3>) { my $mp3 = MP3::Tag->new($file); my ($artist, $album) = $mp3->autoinfo()[2,3]; $mp3->close(); s/[\\\/:*?"<>|]//g for $artist, $album; fmove($file, "$artist/$album/$file") or die $!; }

I updated it, removing some unnecessary declarations that were pointed out to me. Thank you!

Re-updated. Got home and made sure the script worked, and it didn't. Now it does. :-) I am thinking of adding more functionality to this, like checking if an MP3's tags are set, and offering to let you set them if they aren't. Any other ideas are welcome!

Re-re-updated. Took CountZero's comments into consideration, and removed unnecessary delcaration of some tag information.

Replies are listed 'Best First'.
Re: Create folder hierarchy based on MP3 tags
by CountZero (Bishop) on Aug 08, 2012 at 06:37 UTC
    Rather than fcopy you can use the fmove function from File::Copy::Recursive and then you do not need to unlink the source file.

    You can also delete use File::Path qw(mkpath); since you do not use it in this script.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

    My blog: Imperial Deltronics
Re: Create folder hierarchy based on MP3 tags
by reisinge (Hermit) on Aug 08, 2012 at 14:22 UTC
    Handy script! I added some tag checking/customization:
    #!/usr/bin/perl use strict; use warnings; # Create folder hierarchy based on MP3 tags. # Based on: http://www.perlmonks.org/?node_id=985820 # To get mp3 files from directories # find /path/to/mp3_dirs/ -iname '*.mp3' -exec cp "{}" . \; use MP3::Tag; use File::Copy::Recursive qw(fmove); my $Debug = 1; # 1 - don't move files just print the new path foreach my $file (<*.mp3>) { my $mp3 = MP3::Tag->new($file); my ( $title, $track, $artist, $album ) = ( $mp3->autoinfo() )[ 0, +1, 2, 3 ]; $mp3->close(); # Check/customize tags $track = $track =~ /^([0-9]+)/ ? sprintf "%02d", $1 : undef; $title = $title eq '' ? 'uknown_title' : $title; $artist = $artist eq '' ? 'uknown_artist' : $artist; $album = $album eq '' ? 'uknown_album' : $album; s/[\\\/:*?"<>|]//g for $artist, $album; # Set the new path my $path = defined $track ? "$artist/$album/$track $title.mp3" : "$artist/$album/$title.mp3"; if ($Debug) { print "$path\n"; } else { fmove( $file, $path ) or warn "Can't fmove '$file': $!"; } }
    Update: Replaced path setting if structure with the ternary operator.

    Have a nice day, j

      Ternary is nice, but I'd check the tags this way, in case any is just whitespace:

      $title = 'unknown_title' if $title !~ /\S/; $artist = 'unknown_artist' if $artist !~ /\S/; $album = 'unknown_album' if $album !~ /\S/;

      Awesome, thanks for adding! Also, that debug thing you did there is pretty neat. I've never thought to do something like that.