Version 7 of MusicBrainz

Updated 2019-08-19 02:26:42 by DG

Instruction how to get information from MusicBrainz database.

Script above shows how to get basic information about entered artist. Script returns list of albums with release date, title, and url to front and back cover (if exits)

Tutorial for MusicBrain is here

First of all we need to check artist id

http://www.musicbrainz.org/ws/2/artist/?query=<artist>

Next we can get xml contains release-list using following link:

http://www.musicbrainz.org/ws/2/release?artist=<artistID>

According to the wiki.musicbrainz.org : cover arts are available via coverartarchive.org

http://coverartarchive.org

 Discussion

bll 2018-11-8: To get information on a known recording, I am using:

http://musicbrainz.org/ws/2/recording/2409871f-6cde-42a1-a017-722b86f87e68?inc=artists%20releases%20media%20artist-credits

Let's try to get some basic info:

package require http
package require tdom

proc ___returnArtistID {artist} {
        set r [::http::geturl http://www.musicbrainz.org/ws/2/artist/?query=$artist]
        set data [::http::data $r]
        ::http::cleanup $r
        set doc [dom parse $data]
        set root [$doc documentElement]
        set ns {xmlns http://musicbrainz.org/ns/mmd-2.0#}
        set nodesList [$root selectNodes -namespaces $ns //xmlns:artist-list//xmlns:artist]
        return [[lindex $nodesList 0] getAttribute id]
}

proc ___coverURL {type id} {
        return "http://coverartarchive.org/release/$id/$type"
}

proc ___returnReleases {artistID} {
        set r [::http::geturl http://www.musicbrainz.org/ws/2/release?artist=$artistID]
        set data [::http::data $r]
        ::http::cleanup $r
        set doc [dom parse $data]
        set root [$doc documentElement]
        set ns {xmlns http://musicbrainz.org/ns/mmd-2.0#}
        set nodesList [$root selectNodes -namespaces $ns //xmlns:release-list//xmlns:release]
        #id used in the second query
        foreach node $nodesList {
                set date ""
                set id [$node getAttribute id]
                lappend ids $id
                set titleNode [$node selectNodes -namespaces $ns //xmlns:release-list//xmlns:release\[@id='$id'\]//xmlns:title]
                set dateNodes [$node selectNodes -namespaces $ns //xmlns:release-list//xmlns:release\[@id='$id'\]//xmlns:date]
                set coverFrontNode [$node selectNodes -namespaces $ns //xmlns:release-list//xmlns:release\[@id='$id'\]//xmlns:cover-art-archive//xmlns:front]
                set coverBackNode [$node selectNodes -namespaces $ns //xmlns:release-list//xmlns:release\[@id='$id'\]//xmlns:cover-art-archive//xmlns:back]
                set frontC [expr {[$coverFrontNode text] eq "true" ? [___coverURL "front" $id] : "false" }]
                set backC [expr {[$coverFrontNode text] eq "true" ? [___coverURL "back" $id] : "false" }]
                puts "##### Title: [$titleNode text] #####"
                puts "date: [[lindex $dateNodes 0] text]"
                puts "cover front: $frontC"
                puts "cover back: $backC"
                puts "##### #####"
        }
        return $ids
}


set artistID [___returnArtistID "portishead"]
set releaseIDs [___returnReleases $artistID]

puts [___returnArtistID "portishead"]

DG: I'm trying the JSON interface and prefer it so far. The code is much easier to get inside the data, IMO. JSON Web Service

package require http
package require uri  ;# in tcllib
package require json

http::config -useragent {example wiki.tcl-lang.org}

proc fetchJSON {uri {recurse_limit 4}} {
   http::config -accept "application/json"

   set token [http::geturl $uri]
   upvar #0 $token state
   if {[http::status $token] ne "ok" || [http::ncode $token] != 200} {
       # was the error a redirect?  If so, do it..
       if {[http::ncode $token] == 302 && [incr recurse_limit -1] > 0} {
           array set meta $state(meta)
           set result [fetchJSON $meta(Location) $recurse_limit]
           http::cleanup $token
           return $result
       }
       set err [http::code $token]
       http::cleanup $token
       return -code error $err
   }
   set json [http::data $token]
   array set meta $state(meta)
   http::cleanup $token

   # Do we need to do encoding conversions or was it already done
   # in transit?

   if {[info exist meta(Content-Type)] && \
           [regexp -nocase {charset\s*=\s*(\S+)} $meta(Content-Type)]} {

       # Socket channel encodings already performed!  No Work to do
       # here.  See section 5.2.2 of the html spec.  Server set
       # encodings win.

   }

   # Sloppy server.  Send them a bug report.
   set json [encoding convertfrom utf-8 $json]

   return [json::json2dict $json]
}

proc mblookup {entity mbid {inc {}} {method json}} {
    array set uri [list scheme http host musicbrainz.org path ws/2]

    set uri(path) [file join $uri(path) $entity]
    set uri(path) [file join $uri(path) $mbid]
    if {$inc ne ""} {
        set uri(query) "inc=$inc"
    }

    switch $method {
        json {
            return [fetchJSON [uri::join {*}[array get uri]]]
        }
        xml {
            return [[fetchXML [uri::join {*}[array get uri]]] documentElement]
        }
    }
}

# return bootleg show location and date
proc test2 {mbid} {
    array set recInfo [list]

    set query [mblookup release $mbid {place-rels+release-groups} json]

    set status  [dict get $query status]
    set primary [dict get $query release-group primary-type]
    set secondaries [dict get $query release-group secondary-types]

    # first check that this is a live, bootleg, single show recording
    if {$status ne "Bootleg"} {
        return -code error "not a bootleg"
    }
    if {[lsearch $secondaries "Compilation"] != -1} {
        return -code error "compilations are not a single show"
    }
    if {[lsearch $secondaries "Live"] == -1} {
        return -code error "not a live show"
    }
    foreach placerel [dict get $query relations] {
        if {[dict get $placerel type] eq "recorded at"} break
    }
    if {![info exist placerel] || [dict get $placerel type] ne "recorded at"} {
        return -code error "recording location not specified"
    }

    set recInfo(date)  [dict get $placerel begin]
    set recInfo(title) [dict get $query title]
    set recInfo(place) [dict get $placerel place name]

    return [array get recInfo]
}

% test2 817bfcee-a4ee-4afb-9314-9ae0e2885f57
place {Dallas Memorial Auditorium} title {Chasing the Dragon} date 1975-03-05