# 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 = ".";

# If someone gave us an argument then treat it as a 
# dirname to scan
$start_dir = $ARGV[0] if($#ARGV > -1);

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 = "Unknown";
      }
    # 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 = "Unknown";
      }
    $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");
        $count++;
        $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;
  }
