Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses

Fixing mp3 tags for Android 2.0

by hawtin (Prior)
on Feb 17, 2010 at 17:59 UTC ( [id://823779]=CUFP: print w/replies, xml ) Need Help??

I recently purchased an Android 2.0 phone, I was shocked to find that none of my mp3 files worked correctly. This short script fixed the problem.

# Android 2.0 reads mp3 song information # from the ID3v1 tag. Most modern # systems use the more flexible ID3v2 tags. # This means that mp3 files that work perfectly # well on iTunes and other modern systems are # shown as being by "Unknown Artist". # # This script finds all the mp3 files within # a directory and makes sure that the ID3v1 tags # and the ID3v2 tags are both filled in. # # This fixes the issue on my Motorola Milestone # (that is the Motorola Droid in the US) # use strict; use warnings; use MP3::Tag; use Carp; # We parse the command line to pick a directory, # this is easier my $start_dir = "."; foreach my $file_name (list_mp3_files($start_dir)) { # No point in doing anything if we can't # write to the file if(!-w $file_name) { carp("Cannot write to $file_name"); next; } my $mp3 = MP3::Tag->new($file_name); if(!defined $mp3) { carp("Failed to read tags from $file_name"); next; } $mp3->get_tags(); # Do we have the two tag types? my($id3v1,$id3v2); if(defined $mp3->{ID3v1}) { $id3v1 = $mp3->{ID3v1}; } else { $id3v1 = $mp3->new_tag("ID3v1"); } if(defined $mp3->{ID3v2}) { $id3v2 = $mp3->{ID3v2}; } else { $id3v2 = $mp3->new_tag("ID3v2"); } # The ID3v1 tag just provides methods, # so rather than doing some Perlish magic # to have a single piece of code that # uses the ID3v2 flag ("TIT2" or whatever) # I take the simplest (but most long # winded) approach # Read the artist my $artist = $id3v2->artist(); $artist = $id3v1->artist() if(!defined $artist); if(!defined $artist) { carp("Cannot get artist for $file_name"); $artist = "Artist of $file_name"; } # Save the artist $id3v2->artist($artist); $id3v1->artist($artist); my $album = $id3v2->album(); $album = $id3v1->album() if(!defined $album); if(!defined $album) { carp("Cannot get album for $file_name"); $album = "Album of $file_name"; } $id3v2->album($album); $id3v1->album($album); my $track = $id3v2->track(); $track = $id3v1->track() if(!defined $track); if(!defined $track) { carp("Cannot get track for $file_name"); # Magic track num to tell us we had # unknown value $track = 99; } $id3v2->track($track); $id3v1->track($track); my $year = $id3v2->year(); $year = $id3v1->year() if(!defined $year); if(!defined $year) { carp("Cannot get year for $file_name"); # If we don't have a year just ignore } else { $id3v2->year($year); $id3v1->year($year); } # The song() method is depreciated, but works # for ID2v1 my $title = $id3v2->title(); $title = $id3v1->song() if(!defined $title); if(!defined $title) { carp("Cannot get title for $file_name"); $title = "Song: $file_name"; } $id3v2->title($title); $id3v1->song($title); # Finally save the tags $id3v1->write_tag(); $id3v2->write_tag(); } # All done exit 0; sub list_mp3_files { # List all the mp3 files my($dir) = @_; local(*DIR); my @results; # Make sure we complete the dir scan before # doing any recursive calls opendir(DIR,$dir); my @files = readdir(DIR); closedir(DIR); foreach my $file (@files) { # Ignore . and .. next if($file =~ /^\.\.?$/); if(-d "$dir/$file") { # If we encounter a subdir then scan it push @results,list_mp3_files("$dir/$file"); next; } # We just match files that have \.mp3 at the # end of the name if($file =~ /\.mp3$/i) { push @results,"$dir/$file"; } } return @results; }

Replies are listed 'Best First'.
Re: Fixing mp3 tags for Android 2.0
by hossman (Prior) on Feb 17, 2010 at 19:45 UTC
    Some comments on your code...
    1. # We parse the command line to pick a directory, # this is easier my $start_dir = ".";

      How is that easier then my $start_dir = shift; ???

    2. Since $id3v1 and $id3v2 are both going to be objects, the distinction between undef and 0 isn't really relevant, so you should be able to simplify about 20 lines of initialization with something like...
      $id3v1 = $mp3->{ID3v1} || $mp3->new_tag("ID3v1"); $id3v2 = $mp3->{ID3v2} || $mp3->new_tag("ID3v2");
    3. Assigning default values like this...
      $artist = "Artist of $file_name";
      ...seems like the worst possible behavior you could have as a fallback. If instead you leave the fields blank, you can at least easily identify them later and you leave it up to the application to decide what to do about it (ie: display some string like "Unknown Artist", or prompty you, or try to fetch the metadata from an external music identification site).
    4. File::Find is your friend. It's been a core module for a while now, so you don't even need to worry about installing it.

      1. ...How is that easier then...

      Writing the script is not much more complex but invoking it (on a Windows machine) is easier if you don't have to pass the extra argument.

      2. should be able to simplify about 20 lines of initialization with something like...

      True. I find mine easier to understand, but I can see yours has its benefits.

      3. ...seems like the worst possible behavior you could have as a fallback...

      You are right. In my case these sections are never invoked, so its not an issue.

      4. File::Find is your friend.

      Yes, OK. But I had the subroutine already written so rather than spend time looking at the existing package I just grabbed it. Pure lazyness I admit.

Re: Fixing mp3 tags for Android 2.0
by netrom (Acolyte) on Feb 18, 2010 at 08:48 UTC
    I believe it to be your id-tagging program to be in question. I have no problems reading my mp3s on my HTC Tatoo.

    I use amarok 1.4 and amarok 2.0 and I only convert to id3v2. it creates this tagversion as seen by Mp3::Info::get_mp3tag($mp3file):

    'TAGVERSION' => 'ID3v1.1 / ID3v2.4.0'

      I believe that the HTC Tatoo is Android 1.6 not Android 2.0.

      Without knowing anything about Amarok, it looks like your software is adding both ID3v1 and ID3v2 tags. Given the restrictions in ID3v1 (no selection of character sets, limited field sizes, very restricted set of tags) I know quite a few people avoid using them. For those people this is a useful script. If you have decided to live with the restrictions Amarok imposes then the script won't be useful for you, so just ignore it.

      Before writing the script I did look at the Android BBs, where there are a number of complaints about exactly this topic and no easy to apply fixes. So the fact that your combination of tagger and phone don't suffer from this particular issue means that this particular script is no use to you, it does not mean the script is no use at all.

Re: Fixing mp3 tags for Android 2.0
by WoogieNoogie (Initiate) on May 08, 2010 at 04:15 UTC
    Sorry, and please forgive a perl noob, but I was wondering if you could instruct me on how to use this fix on my Droid? It's frustrating me to no end, and this seems to be the only fix there is.

      It's fairly simple. The idea is that you do three steps:

      1. Copy all the mp3 files to a location on your PC
      2. Use this script to fill out the suitable tags
      3. Copy the fixed files to your Droid

      So lets go through those steps, I'm going to assume that you *really* don't know what you are doing, I apologise if I'm stating the obvious here.

      Copy MP3 files

      Pick a temporary directory that will mirror what you want on your Droid. Personally I have a directory on the SD card called "Albums" with a subdir for each album. So maybe, on Windows, you create a directory called "D:\temp\Albums". Then within that directory create directories called, for example, "The Beatles 1967_1970" and "American Idiot". Then copy the mp3 files you want from wherever you have them into the suitable album directories.

      If you are copying all your music that step should be quite simple, if you are selecting songs (for example from a play list) you can do that by hand, but you may find it easier to write a Perl script to do it for you.

      Use the script

      You will need to have Perl installed with all the necessary CPAN modules. Perl you can get from all sorts of places, on Windows you probably want Strawberry Perl or ActiveState. The modules can be more interesting, under ActiveState the PPM program will show you which modules you have installed, you need to make sure that "MP3::Tag" is present, if not install it. Under most other versions of Perl you will need to run a CPAN shell and install the module, there are plenty of places that tell you how to do that.

      Now lets assume that you have copied this script to "D:\bin\". You need to run up a shell (on Windows select "Run" on the Start menu and type in "command" or "cmd").

      > cd D:\temp\Albums > perl D:\bin\

      At this point three things could happen. You could get a message to the effect "Don't understand the command" in which case you didn't install Perl properly, maybe you need to set your PATH for example. Alternately you could get a message "Can't find the module MP3::Tag" in which case go back and install the module.

      In the best of worlds there is some activity, every mp3 file has its modification time changed and we get a files called "AlbumArt.jpg" added to each album directory. This means that the script has done its work

      Copy to your Droid

      So we now have a set of mp3 files that are ready to put on the Android device. There are a number of ways to get them there, I find the easiest is to use USB.

      Plug the USB cable into the Droid and the computer. This will cause various noises and a USB icon will appear in the top left corner of your phone.

      Open the notification bar by dragging this top line down with your finger, you will see an item "USB Connection". Select that and you will have four options, the bottom one will be something like "Charge Only" and will be selected, above that there will be "Memory Card Access", select that one.

      Now you have told the Droid to let the PC manage its SD card. If you use "Windows Explorer" on the PC you should be able to find the Droid's SD card (it will be listed as "Removable Disk E:" or something like that.

      Copy the directory "Albums" from your scratch area to the Droid's SD card. Once the copy is complete go back to the Droid and set its USB connection back to "Charge Only"

      Listen to music

      Now your music should be listed under the correct Artists, Albums and Song Titles, with the right artwork

      As I said this description is long winded, I don't know what it is you don't know. But the process takes a lot less time to do than it does to explain.

      Hope that works for you

        Alright, after much deliberation, I've finally got Perl installed (Strawberry), and I got the MP3::Tag Module installed. Last step seems to be...fixing this error message I'm getting.
        Global symbol "$count" requires explicit package name at [file] Execution of [file] aborted due to complication errors.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://823779]
Approved by toolic
Front-paged by Arunbear
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (2)
As of 2024-04-16 23:23 GMT
Find Nodes?
    Voting Booth?

    No recent polls found