0

I have been trying to write a Picard plugin. My idea is for it to automatically insert transliterated track listings as comments for releases with track titles written in non-Latin scripts. MusicBrainz contains these transliterations as pseudo-releases existing in parallel with the actual releases. For a given release, for example, I would have to first read the relation for the ID of the related release. I would then have to transfer the titles of those tracks into the comment field of my files. In pseudocode:

pseudo_release = actual_release.getTransliteration() # As indicated in a relationship
i = 1
while i <= actual_release.numTracks():
    actual_release.getTrack(i).setComment(pseudo_release.getTrack(i).getTitle())
    i++

The first line is what I'm not sure how to do. Since the relation is not available as a Picard variable, it can't be accessed by any way indicated in the API.

I've been looking through the source of Picard and also the standalone web service but haven't been able to find anything. Is this at all possible, and if so how do I do it?

August Janse
  • 290
  • 1
  • 6
  • 18

2 Answers2

2

The information about relationships, including transliterated tracklistings, is available in Picard if you write a metadata processor. A simple plugin iterating over all relationships of a release would look like this:

PLUGIN_NAME = "Find transliterated tracklisting relationships"
PLUGIN_AUTHOR = "Wieland Hoffmann"
PLUGIN_DESCRIPTION = "I'm too lazy"
PLUGIN_VERSION = "0.1"
PLUGIN_API_VERSIONS = ["1.0"]

from picard.metadata import register_album_metadata_processor
from picard import log


# The relationship type id for transliterations from
# https://musicbrainz.org/relationship/fc399d47-23a7-4c28-bfcf-0607a562b644
TRANS_REL_UUID = "fc399d47-23a7-4c28-bfcf-0607a562b644"


@register_album_metadata_processor
def find_transliteration_relationship(album, metadata, release):
    if "relation_list" in release.children:
        for rel in release.relation_list:
            if rel.relation[0].type_id == TRANS_REL_UUID:
                log.info("Found a transliterated tracklisting relationship")
                for release in rel.relation[0].release:
                    log.info("Its target is https://musicbrainz.org/release/%s",
                             release.id)

The release argument that gets passed to the processor is an instance of Picards XmlNode class and its structure (including its child objects) resembles the XML you get by asking the MusicBrainz server about this release via the web service (this is what it returns for your example release if you only ask it about relationships). Now that you have the MBID of the relationships target, you can use the get method of Picards webservice module (the albums tagger.xmlws attribute is an instance of the XmlWebService class) to send another request to the MusicBrainz website asking for data about that release (don't forget to in- and decrement the albums _requests attribute so it doesn't complete its loading steps until after you've changed its data).

Some other plugins that use this to request and process further data are the album artist website and Last.FM.Plus plugins.

/edit: I've just been informed that there's already a ticket for improving how Picard handles pseudoreleases which has a link to a plugin doing what you want to be doing.

Wieland
  • 1,663
  • 14
  • 23
0

In the MusicBrainz Web Service you can get the transliterated release like this: https://musicbrainz.org/ws/2/release/1492ce2b-a9ee-4aa3-b9e2-b18ad093bc51?inc=release-rels (note the inc=release-rels). You can also use the json web service.

With python-musicbrainzngs you would do something like musicbrainzngs.get_release_by_id("1492ce2b-a9ee-4aa3-b9e2-b18ad093bc51",includes=["release-rels"]).

However, Picard doesn't ship with musicbrainzngs. So you either have to install python-musicbrainzngs separately and your plugin won't work without it or you have to use the Picard provided modules. I am not sure what exactly is and isn't included in Picard metadata, but these modules probably help: picard.album, picard.webservice and picard.mbxml.

JonnyJD
  • 2,593
  • 1
  • 28
  • 44
  • Are you sure that it's at all possible to use non-standard libraries through Picard? I installed python-musicbrainzngs for 2.7.8 with pip-Win and it's functioning properly in the interactive interpreter, but gives an "ImportError: No module named musicbrainzngs" error when imported in a plugin. – August Janse Jul 08 '14 at 13:26
  • Yes, it should be possible, but you might have to fiddle with environment variables or put the module at a specific place where Picard finds it. Though I agree that it is probably more difficult to get this working on Windows than on Linux (where I am at). – JonnyJD Jul 08 '14 at 14:22
  • 1
    Using python-musicbrainzngs in Picard is not a great idea because Picard is built with (Py)Qt and uses its asynchronous primitives all over the place, so you'd most likely cause problems with libraries that make synchronous requests over the network. In addition to that, the Python interpreter that's bundled with Picard on Windows doesn't include the socket module (iirc), making it very hard to use the standard libraries networking modules on which python-musicbrainzngs is built. – Wieland Jul 08 '14 at 17:06