Novice scripting - updating info from Musicbrainz

This forum is for questions / discussions regarding development of addons / tweaks for MediaMonkey.

Moderator: Gurus

Novice scripting - updating info from Musicbrainz

Postby mhendu » Thu Oct 26, 2017 8:11 am

I'm a complete novice at writing code and not sure what I'm doing. Am hoping that one or more folks here with more experience might be willing to point me in the right direction, maybe review the script as I'm writing it and provide feedback.

Thanks to the efforts of other users we have scripts that will find an AcoustID for a given track. We also have a script that will search Musicbrainz to find the earliest release date for a given track (which I would use if the below lookups don't return results). I'd like to build a script that will do the following:

1. Search AcoustID metadata to find a Musicbrainz recording ID (e.g., http://api.acoustid.org/v2/lookup?clien ... ee12d5718c)
2. For a given recording ID, store the Work ID (if available) in a custom field - this is both for the classical lookup mentioned below, as well as to allow me to find covers of tracks in my library
3. If the track is a classical work, find the composition date and store it in the year (if available, assuming work ID returned a result)
4. If the track is not a classical work, find the recording date and store it in the year (if available)

This query at Musicbrainz will return the recording date, work ID and composition date if they're accessible:

http://musicbrainz.org/ws/2/recording/3 ... place-rels

I'm looking at borrowing some code from either the MusicIP tagger (which was based on the now-deprecated PUID) or the MusicBrainz NGS tagger, or maybe both, but again, not really sure what I'm doing.

*******

First issue I'm looking to tackle is how to load the currently selected song list and, for each track in the list, query AcoustID to find the recording ID. I store the AcoustID in Custom5 but if the script is to be more broadly applicable I'd have to incorporate either fpcalc or allow a user to specify which field the AcoustID is stored in to perform the lookup.

I could use some pointers on how to do the above so I can get started - also not sure how to integrate debugging into the code to identify any problems that might come up.

*******

Next issue would be querying to find the Work ID (I'm not sure how to get this data from the query I posted above). Then storing that ID in a custom field (I use custom 4 but again, might need to make this user-defined).

I use the Grouping field to specify whether a track is classical, although others may use the newer functionality in MediaMonkey 4 to separate classical tracks from other tracks. That would be my next problem to solve, figuring out whether a track is classical and, if so, looking up and storing the composition date.

Final issue would be looking up and storing the recorded date if the track is not classical.

Thanks in advance for any help!
mhendu
 
Posts: 79
Joined: Thu Jan 12, 2006 11:18 am

Re: Novice scripting - updating info from Musicbrainz

Postby mhendu » Fri Oct 27, 2017 1:18 am

Shockingly, I actually was able to make this work, more or less. Biggest problem is that the script will effectively freeze MediaMonkey if run against a large number of tracks, but otherwise seems to work OK. Would appreciate if anyone happens to look to see what could be improved here. For simplicity, I just built it for myself, but could be extended to allow for user inputs if someone has the knowledge to do that.

Code: Select all
Sub SearchAcoustID
  ' Define variables
  Dim list, itm, i
  Dim APIKey : APIKey = "[insert your API key here]"
  Dim Grouping
  Dim AcoustID
  Dim Worktemp
  Dim WorkID
  Dim RecordingID
  Dim acoustidurl
  Dim mbrainzurl
  Dim xml : Set xml = CreateObject("Microsoft.XMLDOM")
  xml.async = False
  xml.preserveWhiteSpace = True
  Dim mbrainz : Set mbrainz = CreateObject("Microsoft.XMLDOM")
  mbrainz.async = False
  mbrainz.preserveWhiteSpace = True
  Dim mbrainznode
  Dim recordingidtemp
  Dim mbrainztemp
  Dim workidtemp
  RecordingID = ""
  WorkID = ""

  ' Get list of selected tracks from MediaMonkey
  Set list = SDB.CurrentSongList
  If list.Count=0 Then
    Exit Sub
  End If
    ' Process all selected tracks
  For i=0 To list.count-1
    Do
      Set itm = list.Item(i)
       Grouping = itm.Grouping
     AcoustID = itm.Custom5
     acoustidurl = "http://api.acoustid.org/v2/lookup?format=xml&client=" & APIKey & "&meta=recordingids+recordings&trackid=" & AcoustID
     Call xml.Load(acoustidurl)
      Dim cnt : cnt = 0
      While (xml.readyState < 4 And cnt < 300)
        Call SDB.Tools.Sleep(100)
        SDB.ProcessMessages
        cnt = cnt+1
      WEnd
      If xml.readyState < 4 Then
        Exit Sub 
      End If
      Set recordingidtemp = xml.getElementsByTagName("id").Item(0)
      If recordingidtemp Is Nothing Then Exit Do
     RecordingID = xml.getElementsByTagName("id").Item(0).Text
     mbrainzurl = "http://musicbrainz.org/ws/2/recording/" & RecordingID & "?inc=place-rels+artist-rels+work-rels+work-level-rels"
     Call mbrainz.Load(mbrainzurl)
      Dim cnta : cnta = 0
      While (mbrainz.readyState < 4 And cnta < 300)
        Call SDB.Tools.Sleep(100)
        SDB.ProcessMessages
        cnta = cnta+1
      WEnd
      If mbrainz.readyState < 4 Then
        Exit Sub 
      End If
     If Grouping = "Classical" Then
       Set Worktemp = mbrainz.getElementsByTagName("work").Item(0)
      If Worktemp Is Nothing Then Exit Do
       WorkID = Worktemp.getAttribute("id")
       itm.Custom4 = WorkID
      Set mbrainztemp = mbrainz.SelectSingleNode("//recording/relation-list/relation/work/relation-list/relation/end")
      If mbrainztemp Is Nothing Then
        itm.UpdateDB
        itm.WriteTags
        Exit Do
      End If
       mbrainznode = mbrainz.SelectSingleNode("//recording/relation-list/relation/work/relation-list/relation/end").Text
         itm.Year = mbrainznode
     Else
        Set mbrainztemp = mbrainz.SelectSingleNode("//recording/relation-list/relation/end")
      If mbrainztemp Is Nothing Then
          Set Worktemp = mbrainz.getElementsByTagName("work").Item(0)
        If Worktemp Is Nothing Then Exit Do
         WorkID = Worktemp.getAttribute("id")
          itm.Custom4 = WorkID
        itm.UpdateDB
        itm.WriteTags
        Exit Do
      End If
          mbrainznode = mbrainz.SelectSingleNode("//recording/relation-list/relation/end").Text
       itm.Year = Left(mbrainznode,4)
        Set Worktemp = mbrainz.getElementsByTagName("work").Item(0)
      If Worktemp Is Nothing Then
        itm.UpdateDB
        itm.WriteTags
         Exit Do
      End If
       WorkID = Worktemp.getAttribute("id")
       itm.Custom4 = WorkID
     End If
   Loop While False
  Next
  list.UpdateAll
End Sub
mhendu
 
Posts: 79
Joined: Thu Jan 12, 2006 11:18 am

Re: Novice scripting - updating info from Musicbrainz

Postby mhendu » Fri Oct 27, 2017 1:31 am

Oh, just to set good expectations, the script won't commonly return results, unfortunately. I think this is because the fields I'm looking up are not often filled out and associated with an AcoustID fingerprint, so your mileage may vary. If I'm incorrect and this is due to a coding error would love to have some help to make this more productive.
mhendu
 
Posts: 79
Joined: Thu Jan 12, 2006 11:18 am

Re: Novice scripting - updating info from Musicbrainz

Postby mhendu » Fri Oct 27, 2017 8:29 am

Last post (I think) - made some improvements. Now the script will also search by Work ID for classical works, if that information is stored in Custom4. Also limited the loop to go once per second to avoid hitting Musicbrainz too often. I created a separate version of the script just to tag the Work ID from the AcoustID, which mostly involved stripping out a bunch of code. If anyone's interested in that I can post it separately.

Code: Select all
Sub SearchAcoustID
  ' Define variables
  Dim list, itm, i
  Dim APIKey : APIKey = "[REPLACE WITH ACOUSTID API KEY]"
  Dim Grouping
  Dim AcoustID
  Dim Worktemp
  Dim WorkID
  Dim RecordingID
  Dim acoustidurl
  Dim mbrainzurl
  Dim xml : Set xml = CreateObject("Microsoft.XMLDOM")
  xml.async = False
  xml.preserveWhiteSpace = True
  Dim mbrainz : Set mbrainz = CreateObject("Microsoft.XMLDOM")
  mbrainz.async = False
  mbrainz.preserveWhiteSpace = True
  Dim mbrainznode
  Dim recordingidtemp
  Dim mbrainztemp
  Dim workidtemp
  Dim workurl
  Dim workxml : Set workxml = CreateObject("Microsoft.XMLDOM")
  workxml.async = False
  workxml.preserveWhiteSpace = True
  Dim mbrainzlist
  RecordingID = ""
  WorkID = ""

  ' Get list of selected tracks from MediaMonkey
  Set list = SDB.CurrentSongList
  If list.Count=0 Then
    Exit Sub
  End If
    ' Process all selected tracks
  For i=0 To list.count-1
    Do
      Set itm = list.Item(i)
       Grouping = itm.Grouping
     AcoustID = itm.Custom5
     acoustidurl = "http://api.acoustid.org/v2/lookup?format=xml&client=" & APIKey & "&meta=recordingids+recordings&trackid=" & AcoustID
     Call xml.Load(acoustidurl)
      Dim cnt : cnt = 0
      While (xml.readyState < 4 And cnt < 300)
        Call SDB.Tools.Sleep(100)
        SDB.ProcessMessages
        cnt = cnt+1
      WEnd
      If xml.readyState < 4 Then
        Exit Sub 
      End If
      Set recordingidtemp = xml.getElementsByTagName("id").Item(0)
      If recordingidtemp Is Nothing Then
       If itm.Custom4 <> "" AND Grouping = "Classical" Then
     WorkID = itm.Custom4
      workurl = "http://musicbrainz.org/ws/2/work/" & WorkID & "?inc=artist-rels"
     Call workxml.Load(workurl)
      Dim cntb : cntb = 0
      While (workxml.readyState < 4 And cntb < 300)
        Call SDB.Tools.Sleep(100)
        SDB.ProcessMessages
        cntb = cntb+1
      WEnd
      If workxml.readyState < 4 Then
        Exit Sub 
      End If
      Set mbrainztemp = workxml.SelectSingleNode("//work/relation-list/relation/end")
      If mbrainztemp Is Nothing Then Exit Do
      mbrainznode = workxml.SelectSingleNode("//work/relation-list/relation/end").Text
         itm.Year = Left(mbrainznode,4)
        itm.UpdateDB
        itm.WriteTags
      End If
      Exit Do
     End If
     RecordingID = xml.getElementsByTagName("id").Item(0).Text
     mbrainzurl = "http://musicbrainz.org/ws/2/recording/" & RecordingID & "?inc=place-rels+artist-rels+work-rels+work-level-rels"
     Call mbrainz.Load(mbrainzurl)
      Dim cnta : cnta = 0
      While (mbrainz.readyState < 4 And cnta < 300)
        Call SDB.Tools.Sleep(100)
        SDB.ProcessMessages
        cnta = cnta+1
      WEnd
      If mbrainz.readyState < 4 Then
        Exit Sub 
      End If
     If Grouping = "Classical" Then
       Set Worktemp = mbrainz.getElementsByTagName("work").Item(0)
      If Worktemp Is Nothing Then Exit Do
       WorkID = Worktemp.getAttribute("id")
       itm.Custom4 = WorkID
      Set mbrainztemp = mbrainz.SelectSingleNode("//recording/relation-list/relation/work/relation-list/relation/end")
      If mbrainztemp Is Nothing Then
        itm.UpdateDB
        itm.WriteTags
        Exit Do
      End If
       mbrainznode = mbrainz.SelectSingleNode("//recording/relation-list/relation/work/relation-list/relation/end").Text
         itm.Year = Left(mbrainznode,4)
     Else
        Set mbrainztemp = mbrainz.SelectSingleNode("//recording/relation-list/relation/end")
      If mbrainztemp Is Nothing Then
          Set Worktemp = mbrainz.getElementsByTagName("work").Item(0)
        If Worktemp Is Nothing Then Exit Do
         WorkID = Worktemp.getAttribute("id")
          itm.Custom4 = WorkID
        itm.UpdateDB
        itm.WriteTags
        Exit Do
      End If
          mbrainznode = mbrainz.SelectSingleNode("//recording/relation-list/relation/end").Text
       itm.Year = Left(mbrainznode,4)
        Set Worktemp = mbrainz.getElementsByTagName("work").Item(0)
      If Worktemp Is Nothing Then
        itm.UpdateDB
        itm.WriteTags
         Exit Do
      End If
       WorkID = Worktemp.getAttribute("id")
       itm.Custom4 = WorkID
     End If
   Loop While False
   Call SDB.Tools.Sleep(1000)
  Next
  list.UpdateAll
End Sub
mhendu
 
Posts: 79
Joined: Thu Jan 12, 2006 11:18 am

Re: Novice scripting - updating info from Musicbrainz

Postby mhendu » Sat Oct 28, 2017 12:43 am

Found that there were some instances where the script would return the incorrect date or Work ID. Have adjusted accordingly.

Code: Select all
Sub SearchAcoustID
  ' Define variables
  Dim list, itm, i, j, jnum, jcnt, jmax, jpos
  Dim APIKey : APIKey = "[ENTER ACOUSTID API KEY HERE]"
  Dim Grouping
  Dim AcoustID
  Dim Worktemp
  Dim WorkID
  Dim RecordingID
  Dim acoustidurl
  Dim mbrainzurl
  Dim xml : Set xml = CreateObject("Microsoft.XMLDOM")
  xml.async = False
  xml.preserveWhiteSpace = True
  Dim mbrainz : Set mbrainz = CreateObject("Microsoft.XMLDOM")
  mbrainz.async = False
  mbrainz.preserveWhiteSpace = True
  Dim mbrainznode
  Dim recordingidtemp
  Dim recordingidtemp1
  Dim mbrainztemp
  Dim workidtemp
  Dim workurl
  Dim workxml : Set workxml = CreateObject("Microsoft.XMLDOM")
  workxml.async = False
  workxml.preserveWhiteSpace = True
  Dim mbrainzlist
  RecordingID = ""
  WorkID = ""

  ' Get list of selected tracks from MediaMonkey
  Set list = SDB.CurrentSongList
  If list.Count=0 Then
    Exit Sub
  End If
    ' Process all selected tracks
  For i=0 To list.count-1
    Do
      Set itm = list.Item(i)
       Grouping = itm.Grouping
     AcoustID = itm.Custom5
     acoustidurl = "http://api.acoustid.org/v2/lookup?format=xml&client=" & APIKey & "&meta=recordingids+sources&trackid=" & AcoustID
     Call xml.Load(acoustidurl)
      Dim cnt : cnt = 0
      While (xml.readyState < 4 And cnt < 300)
        Call SDB.Tools.Sleep(100)
        SDB.ProcessMessages
        cnt = cnt+1
      WEnd
      If xml.readyState < 4 Then
        Exit Sub 
      End If
     jnum = 0
     jcnt = -1
     jmax = 0
     jpos = 0
     For Each j In xml.selectNodes("//sources")
       jnum = CInt(j.Text)
      jcnt = jcnt + 1
      If jnum > jmax Then jpos = jcnt
      If jnum > jmax Then jmax = jnum
     Next
      Set recordingidtemp = xml.getElementsByTagName("id").Item(jpos)
      If recordingidtemp Is Nothing Then
       If itm.Custom4 <> "" AND Grouping = "Classical" Then
         WorkID = itm.Custom4
          workurl = "http://musicbrainz.org/ws/2/work/" & WorkID & "?inc=artist-rels"
         Call workxml.Load(workurl)
          Dim cntb : cntb = 0
          While (workxml.readyState < 4 And cntb < 300)
            Call SDB.Tools.Sleep(100)
            SDB.ProcessMessages
            cntb = cntb+1
          WEnd
          If workxml.readyState < 4 Then
          Exit Sub 
          End If
        xpath = "//relation[@type='composer']/end"
        Set mbrainztemp = workxml.SelectSingleNode(xpath)
        If mbrainztemp Is Nothing Then Exit Do
        mbrainznode = mbrainztemp.Text
           itm.Year = Left(mbrainznode,4)
        itm.UpdateDB
        itm.WriteTags
        End If
       Exit Do
     End If
     RecordingID = recordingidtemp.Text
     mbrainzurl = "http://musicbrainz.org/ws/2/recording/" & RecordingID & "?inc=place-rels+artist-rels+work-rels+work-level-rels"
      Call mbrainz.Load(mbrainzurl)
     Dim cnta : cnta = 0
      While (mbrainz.readyState < 4 And cnta < 300)
        Call SDB.Tools.Sleep(100)
        SDB.ProcessMessages
        cnta = cnta+1
      WEnd
      If mbrainz.readyState < 4 Then
        Exit Sub 
      End If
     If Grouping = "Classical" Then
       Set Worktemp = mbrainz.getElementsByTagName("work").Item(0)
      If Worktemp Is Nothing Then Exit Do
       WorkID = Worktemp.getAttribute("id")
       itm.Custom4 = WorkID
      xpath = "//relation[@type='composer']/end"
      Set mbrainztemp = mbrainz.SelectSingleNode(xpath)
      If mbrainztemp Is Nothing Then
        itm.UpdateDB
        itm.WriteTags
        Exit Do
      End If
       mbrainznode = mbrainztemp.Text
         itm.Year = Left(mbrainznode,4)
     Else
        xpath = "//relation-list[@target-type='place']/relation/end"
      Set mbrainztemp = mbrainz.SelectSingleNode(xpath)
      If mbrainztemp Is Nothing Then
          Set Worktemp = mbrainz.getElementsByTagName("work").Item(0)
        If Worktemp Is Nothing Then Exit Do
         WorkID = Worktemp.getAttribute("id")
          itm.Custom4 = WorkID
        itm.UpdateDB
        itm.WriteTags
        Exit Do
      End If
          mbrainznode = mbrainztemp.Text
       itm.Year = Left(mbrainznode,4)
        Set Worktemp = mbrainz.getElementsByTagName("work").Item(0)
      If Worktemp Is Nothing Then
        itm.UpdateDB
        itm.WriteTags
         Exit Do
      End If
       WorkID = Worktemp.getAttribute("id")
       itm.Custom4 = WorkID
     End If
   Loop While False
   Call SDB.Tools.Sleep(1000)
  Next
  list.UpdateAll
End Sub
mhendu
 
Posts: 79
Joined: Thu Jan 12, 2006 11:18 am

Re: Novice scripting - updating info from Musicbrainz

Postby mhendu » Mon Oct 30, 2017 9:40 pm

Err, OK, found instances where the AcoustID search returns no recording IDs but then the script still treats classical works like other works and doesn't search by work ID if present. Fixed in this version, so more results will be returned for classical works (assuming Grouping=Classical and the work ID is present and stored in Custom4).

Code: Select all
Sub SearchAcoustID
  ' Define variables
  Dim list, itm, i, j, jnum, jcnt, jmax, jpos
  Dim APIKey : APIKey = "[INSERT ACOUSTID API KEY HERE]"
  Dim Grouping
  Dim AcoustID
  Dim Worktemp
  Dim WorkID
  Dim RecordingID
  Dim acoustidurl
  Dim mbrainzurl
  Dim xml : Set xml = CreateObject("Microsoft.XMLDOM")
  xml.async = False
  xml.preserveWhiteSpace = True
  Dim mbrainz : Set mbrainz = CreateObject("Microsoft.XMLDOM")
  mbrainz.async = False
  mbrainz.preserveWhiteSpace = True
  Dim mbrainznode
  Dim recordingidtemp
  Dim recordingidtemp1
  Dim mbrainztemp
  Dim workidtemp
  Dim workurl
  Dim workxml : Set workxml = CreateObject("Microsoft.XMLDOM")
  workxml.async = False
  workxml.preserveWhiteSpace = True
  Dim mbrainzlist
  RecordingID = ""
  WorkID = ""

  ' Get list of selected tracks from MediaMonkey
  Set list = SDB.CurrentSongList
  If list.Count=0 Then
    Exit Sub
  End If
    ' Process all selected tracks
  For i=0 To list.count-1
    Do
      Set itm = list.Item(i)
       Grouping = itm.Grouping
     AcoustID = itm.Custom5
     acoustidurl = "http://api.acoustid.org/v2/lookup?format=xml&client=" & APIKey & "&meta=recordingids+sources&trackid=" & AcoustID
     Call xml.Load(acoustidurl)
      Dim cnt : cnt = 0
      While (xml.readyState < 4 And cnt < 300)
        Call SDB.Tools.Sleep(100)
        SDB.ProcessMessages
        cnt = cnt+1
      WEnd
      If xml.readyState < 4 Then
        Exit Sub 
      End If
     jnum = 0
     jcnt = -1
     jmax = 0
     jpos = 0
     For Each j In xml.selectNodes("//sources")
       jnum = CInt(j.Text)
      jcnt = jcnt + 1
      If jnum > jmax Then jpos = jcnt
      If jnum > jmax Then jmax = jnum
     Next
      Set recordingidtemp = xml.getElementsByTagName("id").Item(jpos)
      If recordingidtemp Is Nothing OR jmax = 0 Then
       If itm.Custom4 <> "" AND Grouping = "Classical" Then
         WorkID = itm.Custom4
          workurl = "http://musicbrainz.org/ws/2/work/" & WorkID & "?inc=artist-rels"
         Call workxml.Load(workurl)
          Dim cntb : cntb = 0
          While (workxml.readyState < 4 And cntb < 300)
            Call SDB.Tools.Sleep(100)
            SDB.ProcessMessages
            cntb = cntb+1
          WEnd
          If workxml.readyState < 4 Then
          Exit Sub 
          End If
        xpath = "//relation[@type='composer']/end"
        Set mbrainztemp = workxml.SelectSingleNode(xpath)
        If mbrainztemp Is Nothing Then Exit Do
        mbrainznode = mbrainztemp.Text
           itm.Year = Left(mbrainznode,4)
        itm.UpdateDB
        itm.WriteTags
        End If
       Exit Do
     End If
     RecordingID = recordingidtemp.Text
     mbrainzurl = "http://musicbrainz.org/ws/2/recording/" & RecordingID & "?inc=place-rels+artist-rels+work-rels+work-level-rels"
      Call mbrainz.Load(mbrainzurl)
     Dim cnta : cnta = 0
      While (mbrainz.readyState < 4 And cnta < 300)
        Call SDB.Tools.Sleep(100)
        SDB.ProcessMessages
        cnta = cnta+1
      WEnd
      If mbrainz.readyState < 4 Then
        Exit Sub 
      End If
     If Grouping = "Classical" Then
       Set Worktemp = mbrainz.getElementsByTagName("work").Item(0)
      If Worktemp Is Nothing Then Exit Do
       WorkID = Worktemp.getAttribute("id")
       itm.Custom4 = WorkID
      xpath = "//relation[@type='composer']/end"
      Set mbrainztemp = mbrainz.SelectSingleNode(xpath)
      If mbrainztemp Is Nothing Then
        itm.UpdateDB
        itm.WriteTags
        Exit Do
      End If
       mbrainznode = mbrainztemp.Text
         itm.Year = Left(mbrainznode,4)
     Else
        xpath = "//relation-list[@target-type='place']/relation/end"
      Set mbrainztemp = mbrainz.SelectSingleNode(xpath)
      If mbrainztemp Is Nothing Then
          Set Worktemp = mbrainz.getElementsByTagName("work").Item(0)
        If Worktemp Is Nothing Then Exit Do
         WorkID = Worktemp.getAttribute("id")
          itm.Custom4 = WorkID
        itm.UpdateDB
        itm.WriteTags
        Exit Do
      End If
          mbrainznode = mbrainztemp.Text
       itm.Year = Left(mbrainznode,4)
        Set Worktemp = mbrainz.getElementsByTagName("work").Item(0)
      If Worktemp Is Nothing Then
        itm.UpdateDB
        itm.WriteTags
         Exit Do
      End If
       WorkID = Worktemp.getAttribute("id")
       itm.Custom4 = WorkID
     End If
   Loop While False
   Call SDB.Tools.Sleep(1000)
  Next
  list.UpdateAll
End Sub
mhendu
 
Posts: 79
Joined: Thu Jan 12, 2006 11:18 am


Return to MediaMonkey 4 Addons developer forum

Who is online

Users browsing this forum: No registered users and 3 guests