Index: SQL/SQLite/dbcreate.sql =================================================================== --- SQL/SQLite/dbcreate.sql (revision 4110) +++ SQL/SQLite/dbcreate.sql (working copy) @@ -53,6 +53,7 @@ remote integer, -- boolean for remote moodlogic_mixable integer, musicmagic_mixable integer, + musicbrainz_id varchar, multialbumsortkey varchar -- used for sorting tracks in multi album lists ); @@ -103,6 +104,7 @@ artwork_path varchar, -- path to cover art disc integer, -- album number in set discc integer, -- number of albums in set + musicbrainz_id varchar, musicmagic_mixable integer ); @@ -121,6 +123,7 @@ namesearch varchar, -- version of name used for search matching moodlogic_id integer, -- these will eventually be dynamically created by the plugin moodlogic_mixable integer, + musicbrainz_id varchar, musicmagic_mixable integer ); Index: SQL/mysql/dbcreate.sql =================================================================== --- SQL/mysql/dbcreate.sql (revision 4110) +++ SQL/mysql/dbcreate.sql (working copy) @@ -61,6 +61,7 @@ moodlogic_id int(10) unsigned, moodlogic_mixable tinyint(1) unsigned, musicmagic_mixable tinyint(1) unsigned, + musicbrainz_id varchar(40), multialbumsortkey text, INDEX trackTitleIndex (title), INDEX trackAlbumIndex (album), @@ -116,6 +117,7 @@ artwork_path varchar(255), disc tinyint(1) unsigned, discc tinyint(1) unsigned, + musicbrainz_id varchar(40), musicmagic_mixable tinyint(1) unsigned, INDEX albumsTitleIndex (title), INDEX albumsSortIndex (titlesort), @@ -136,6 +138,7 @@ namesearch varchar(255), moodlogic_id int(10) unsigned, moodlogic_mixable tinyint(1) unsigned, + musicbrainz_id varchar(40), musicmagic_mixable tinyint(1) unsigned, INDEX contributorsNameIndex (name), INDEX contributorsSortIndex (namesort), Index: Slim/DataStores/DBI/Track.pm =================================================================== --- Slim/DataStores/DBI/Track.pm (revision 4110) +++ Slim/DataStores/DBI/Track.pm (working copy) @@ -52,6 +52,7 @@ 'moodlogic_id' => 'moodlogic_id', 'moodlogic_mixable' => 'moodlogic_mixable', 'musicmagic_mixable' => 'musicmagic_mixable', + 'musicbrainz_id' => 'musicbrainz_id', 'playCount' => 'playCount', 'lastPlayed' => 'lastPlayed', 'titlesearch' => 'titlesearch', Index: Slim/DataStores/DBI/Contributor.pm =================================================================== --- Slim/DataStores/DBI/Contributor.pm (revision 4110) +++ Slim/DataStores/DBI/Contributor.pm (working copy) @@ -14,7 +14,7 @@ $class->columns(Essential => qw/name namesort moodlogic_id moodlogic_mixable musicmagic_mixable/); - $class->columns(Others => qw/namesearch/); + $class->columns(Others => qw/namesearch musicbrainz_id/); $class->columns(Stringify => qw/name/); Index: Slim/DataStores/DBI/DBIStore.pm =================================================================== --- Slim/DataStores/DBI/DBIStore.pm (revision 4110) +++ Slim/DataStores/DBI/DBIStore.pm (working copy) @@ -1342,7 +1342,9 @@ # Push these back until we have a Track object. for my $tag (qw( COMMENT BAND COMPOSER CONDUCTOR GENRE ARTIST ARTISTSORT - PIC APIC ALBUM ALBUMSORT DISCC ALBUMARTIST COMPILATION)) { + PIC APIC ALBUM ALBUMSORT DISCC ALBUMARTIST COMPILATION + MUSICBRAINZ_ARTIST_ID MUSICBRAINZ_ALBUM_ARTIST_ID + MUSICBRAINZ_ALBUM_ID MUSICBRAINZ_ALBUM_TYPE MUSICBRAINZ_ALBUM_STATUS)) { next unless defined $attributes->{$tag}; @@ -1538,6 +1540,8 @@ $albumObj->compilation(1) if $attributes->{'COMPILATION'}; + $albumObj->musicbrainz_id($attributes->{'MUSICBRAINZ_ALBUM_ID'}); + $albumObj->disc($disc) if $disc; $albumObj->discc($discc) if $discc; $albumObj->year($track->year) if $track->year; @@ -1639,6 +1643,7 @@ for my $tag (@tags) { my $contributor = $attributes->{$tag} || next; + my $forceCreate = 0; # Bug 1955 - Previously 'last one in' would win for a @@ -1670,8 +1675,15 @@ # Is ARTISTSORT/TSOP always right for non-artist # contributors? I think so. ID3 doesn't have # "BANDSORT" or similar at any rate. + my $contributorMBId; + + $contributorMBId = $attributes->{'MUSICBRAINZ_ALBUM_ARTIST_ID'} if ($tag eq 'ALBUMARTIST'); + $contributorMBId = $attributes->{'MUSICBRAINZ_ARTIST_ID'} if ($tag eq 'ARTIST'); + $contributorMBId = $attributes->{'MUSICBRAINZ_ARTIST_ID'} if ($tag eq 'TRACKARTIST'); + push @contributors, Slim::DataStores::DBI::ContributorTrack->add( $contributor, + $contributorMBId, $Slim::DataStores::DBI::ContributorTrack::contributorToRoleMap{$tag}, $track, $tag eq 'ARTIST' ? $attributes->{'ARTISTSORT'} : undef, Index: Slim/DataStores/DBI/ContributorTrack.pm =================================================================== --- Slim/DataStores/DBI/ContributorTrack.pm (revision 4110) +++ Slim/DataStores/DBI/ContributorTrack.pm (working copy) @@ -43,6 +43,7 @@ sub add { my $class = shift; my $artist = shift; + my $artistMBId = shift; my $role = shift; my $track = shift; my $artistSort = shift || $artist; @@ -86,6 +87,7 @@ $artistObj->name($name); $artistObj->namesort($sort); + $artistObj->musicbrainz_id($artistMBId); $artistObj->update; push @contributors, $artistObj; Index: Slim/DataStores/DBI/Album.pm =================================================================== --- Slim/DataStores/DBI/Album.pm (revision 4110) +++ Slim/DataStores/DBI/Album.pm (working copy) @@ -14,7 +14,7 @@ $class->columns(Essential => qw/title titlesort contributor compilation year artwork_path disc discc musicmagic_mixable/); - $class->columns(Others => qw/titlesearch/); + $class->columns(Others => qw/titlesearch musicbrainz_id/); $class->columns(Stringify => qw/title/); Index: Slim/Formats/Ogg.pm =================================================================== --- Slim/Formats/Ogg.pm (revision 4112) +++ Slim/Formats/Ogg.pm (working copy) @@ -25,6 +25,11 @@ 'TRACKNUMBER' => 'TRACKNUM', 'DISCNUMBER' => 'DISC', 'URL' => 'URLTAG', + 'MUSICBRAINZ_TRACKID' => 'MUSICBRAINZ_ID', + 'MUSICBRAINZ_ALBUMID' => 'MUSICBRAINZ_ALBUM_ID', + 'MUSICBRAINZ_ALBUMSTATUS' => 'MUSICBRAINZ_ALBUM_STATUS', + 'MUSICBRAINZ_ALBUMTYPE' => 'MUSICBRAINZ_ALBUM_TYPE', + 'MUSICBRAINZ_ARTISTID' => 'MUSICBRAINZ_ARTIST_ID', ); # Given a file, return a hash of name value pairs, Index: Slim/Formats/MP3.pm =================================================================== --- Slim/Formats/MP3.pm (revision 4112) +++ Slim/Formats/MP3.pm (working copy) @@ -10,6 +10,7 @@ use strict; use IO::Seekable qw(SEEK_SET); use MP3::Info; +use MP3::Tag; use Slim::Utils::Misc; @@ -60,6 +61,69 @@ # bitrate is in bits per second, not kbits per second. $info->{'BITRATE'} = $info->{'BITRATE'} * 1000 if ($info->{'BITRATE'}); + my $mp3 = MP3::Tag->new($file); + $mp3->get_tags(); + + if (exists $mp3->{ID3v2}) + { + my $frames = $mp3->{ID3v2}->get_frame_ids(); + foreach my $frame (keys %$frames) + { + my ($tagInfo, $tagName) = $mp3->{ID3v2}->get_frame($frame); + next unless defined $tagInfo; + + if (ref $tagInfo) + { + my ($tagInfo, $tagName) = $mp3->{ID3v2}->get_frame($frame); + next unless defined $tagInfo; + + if (ref $tagInfo) + { + my $tagInfoKey; + my $tagInfoVal; + + # This is the unique file identifier (here, track ID) + if ($frame eq "UFID") + { + while (my ($key,$val) = each %$tagInfo) + { + if (($key eq "_Data") && ($frame eq "UFID")) + { + $tagInfoKey = "MUSICBRAINZ_ID"; + $tagInfoVal = $val; + + $::d_private && msg(" * I '$tagInfoKey' => '$tagInfoVal' in $file\n"); + $info->{$tagInfoKey} = $tagInfoVal; + } + } + } + elsif ($frame =~ /^TXXX/) + { + while (my ($key,$val) = each %$tagInfo) + { + if (($key eq "Description") && ($val =~ /^MusicBrainz/)) + { + $tagInfoKey = uc $val; + $tagInfoKey =~ s/\ /_/g; + } + + if (($key eq "Text") && (defined $val)) + { + $tagInfoVal = $val; + } + } + + if ((defined $tagInfoKey) && (defined $tagInfoVal)) + { + $::d_private && msg(" * I '$tagInfoKey' => '$tagInfoVal' in $file\n"); + $info->{$tagInfoKey} = $tagInfoVal; + } + } + } + } + } + } + close $fh; return $info;