source: flacrip/trunk/lib/MusicBrainz.pm @ 42

Last change on this file since 42 was 40, checked in by peter, 10 years ago

If given a barcode, get_musicbrainz_info() will attempt to match a release on
the DiscID and the barcode.

  • get_musicbrainz_info() and select_release() take a hashref with discid and barcode keys
  • mbz script takes a --barcode argument; however, if --flac is given, it dtermines the barcode from the BARCODE tag in the FLAC file
  • added a barcode method to the DiscFlacFile class
  • corrected the call to Audio::FLAC::Header::info to a call to tags for the Vorbis tags
  • removed the superfluous getprops script
File size: 5.2 KB
Line 
1package MusicBrainz;
2
3use strict;
4use warnings;
5
6our @ISA    = qw{Exporter};
7our @EXPORT = qw{get_musicbrainz_info lookup_release};
8
9#use WebService::MusicBrainz;
10use LWP;
11use XML::XPath;
12use XML::XPath::XMLParser;
13
14sub lookup_release {
15    my ($discid) = @_;
16    my $ua = LWP::UserAgent->new;
17
18    #my $uri = URI->new('http://musicbrainz.org/ws/1/release/');
19    #$uri->query_form(type => 'xml', discid => $discid);
20    my $uri = URI->new("http://musicbrainz.org/ws/2/discid/$discid");
21    $uri->query_form(inc => 'artists+labels+recordings+release-groups+artist-credits');
22
23    my $res = $ua->get($uri);
24    # pause for a second, so we don't run afoul of the MusicBrainz API TOS
25    sleep 1;
26
27    warn $res->status_line, "\n" if $res->code != 200;
28    return if $res->code >= 400;
29    #TODO: if we get a 5xx error, retry?
30
31    return $res->decoded_content;
32}
33
34sub select_release {
35    my ($xpath, $params) = @_;
36
37    my $discid = $params->{discid};
38    my $barcode = $params->{barcode};
39
40    if ($barcode) {
41        # try to pick the release automatically by the barcode
42        my @releases = $xpath->findnodes("//release[barcode='$barcode']");
43        die "Found no releases with discid $discid and barcode $barcode\n" unless @releases;
44        die "Found more than one release with discid $discid and barcode $barcode\n" if @releases > 1;
45        return $releases[0];
46    } else {
47        my $release_count = $xpath->findvalue('count(//release)');
48        my @releases = $xpath->findnodes('//release');
49        my $base = 'http://musicbrainz.org/release/';
50
51        my $i = 1;
52        # present the user with an interactive menu to pick/confirm the correct release ID
53        warn "$release_count release(s) found matching $discid\n";
54        for my $release (@releases) {
55            warn sprintf "%2d) $base%s %s %s (%s)\n", 
56            $i++,
57            $xpath->findvalue('@id', $release)->value,
58            $xpath->findvalue('.//label-info/label/name', $release)->value,
59            $xpath->findvalue('.//label-info/catalog-number', $release)->value,
60            $xpath->findvalue('barcode', $release)->value;
61        }
62
63        my $selection = 0;
64
65        while ($selection < 1 || $selection > $release_count) {
66            print STDERR "Select a release (1-$release_count): ";
67            $selection = <STDIN>;
68            chomp $selection;
69            return if $selection =~ /^q/i;
70        }
71
72        return $releases[$selection - 1];
73    }
74}
75
76sub get_musicbrainz_info {
77    my $params = shift;
78
79    my $discid = $params->{discid};
80    my %info;
81
82    $info{MUSICBRAINZ_DISCID} = $discid;
83
84    my $xpath = XML::XPath->new();
85    my $xml = lookup_release($discid) || return;
86   
87    $xpath->set_xml($xml);
88
89    # use the VorbisComment names from here http://musicbrainz.org/doc/MusicBrainz_Picard/Tags/Mapping
90
91    #my $release = $releases[0];
92    my $release = select_release($xpath, $params);
93    return unless $release;
94
95    $info{MUSICBRAINZ_ALBUMID} = $xpath->findvalue('@id', $release)->value;
96    $info{ALBUM}               = $xpath->findvalue('title', $release)->value;
97    @info{qw{ALBUMARTIST ALBUMARTISTSORT}} = get_artist_credits($xpath, $release);
98    $info{DATE}                = $xpath->findvalue('date', $release)->value;
99    $info{ORIGINALDATE}        = $xpath->findvalue('release-group/first-release-date', $release)->value;
100    $info{LANGUAGE}            = $xpath->findvalue('text-representation/language', $release)->value;
101    $info{SCRIPT}              = $xpath->findvalue('text-representation/script', $release)->value;
102
103    # select the proper medium (important for multidisc releases)
104    my ($medium) = $xpath->findnodes("medium-list/medium[disc-list/disc/\@id='$discid']", $release);
105
106    # disc position info
107    $info{DISCNUMBER} = $xpath->findvalue('position', $medium)->value;
108    $info{DISCTOTAL}  = $xpath->findvalue('../@count', $medium)->value;
109
110    #my $ua = LWP::UserAgent->new;
111    my $tracknum = 1;
112    for my $track_node ($xpath->findnodes('track-list/track', $medium)) {
113        my $prefix = sprintf('TRACK%02d', $tracknum);
114
115        $info{"$prefix.MUSICBRAINZ_TRACKID"} = $xpath->findvalue('@id', $track_node)->value;
116
117        my ($recording) = $xpath->findnodes('recording', $track_node);
118        $info{"$prefix.MUSICBRAINZ_RECORDINGID"} = $xpath->findvalue('@id', $recording)->value;
119        $info{"$prefix.TITLE"} = $xpath->findvalue('title', $recording)->value;
120        @info{"$prefix.ARTIST", "$prefix.ARTISTSORT"} = get_artist_credits($xpath, $recording);
121
122        #my $uri = URI->new("http://musicbrainz.org/ws/2/recording/$recording_mbid");
123        #$uri->query_form(inc => 'artists');
124        #my $res = $ua->get($uri);
125        #die $res->decoded_content;
126
127        #TODO: get track relations (Covers, etc.)
128
129        $tracknum++;
130    }
131
132    return \%info;
133}
134
135sub get_artist_credits {
136    my ($xpath, $context_node) = @_;
137
138    # use the MusicBrainz join phrase to build up the multiple artist credits
139    my ($credit, $sort_credit) = ('', '');
140    for my $credit_node ($xpath->findnodes('artist-credit/name-credit', $context_node)) {
141        $credit      .= $xpath->findvalue('concat(artist/name, @joinphrase)', $credit_node)->value;
142        $sort_credit .= $xpath->findvalue('concat(artist/sort-name, @joinphrase)', $credit_node)->value;
143    }
144
145    return ($credit, $sort_credit);
146}
147
148# module return
1491;
Note: See TracBrowser for help on using the repository browser.