Walk me thru writing a plugin

I want to write a plugin that provides variables for file naming scripts based on the ‘recorded at’ attributes of both releases and recordings, based somewhat from an XSL script i wrote.

I started playing at the python3 console and got something useful:

davygrvy@puukukui:~$ python3
Python 3.10.12 (main, Jan 26 2026, 14:55:28) [GCC 11.4.0] on linuxType “help”, “copyright”, “credits” or “license” for more information.
>>> import musicbrainzngs
>>> musicbrainzngs.set_useragent("perfvars.py", "0.1", "davygrvy@pobox.com")
>>> release_data = musicbrainzngs.get_release_by_id("63ad599f-ba01-41f2-b89a-1c3e6524cede", includes=["event-rels"])
>>> print(release_data)
{'release': {'id': '63ad599f-ba01-41f2-b89a-1c3e6524cede', 'title': 'Chicago Soundcheck', 'status': 'Bootleg', 'quality': 'normal', 'text-representation': {'language': 'eng', 'script': 'Latn'}, 'cover-art-archive': {'artwork': 'true', 'count': '1', 'front': 'true', 'back': 'false'}, 'event-relation-list': [{'type': 'recorded at', 'type-id': '4dda6e40-14af-46bb-bb78-ea22f4a99dfa', 'target': '8489a816-8242-4eae-a568-b6dca9d29f1f', 'direction': 'backward', 'event': {'id': '8489a816-8242-4eae-a568-b6dca9d29f1f', 'name': 'Met Center, Bloomington, MN', 'disambiguation': 'rehearsal, not performance', 'life-span': {'begin': '1975-01-17', 'end': '1975-01-17'}, 'setlist': '# rehersal'}}]}}

So I see the JSON for the release and all is great. The concert event is there, and I know I’ll have to follow into it to get the place, then backward unwind the area to make the proper “town,county,subdivision,country” form. I want to link these to variables for filenaming scripts.

I’m not sure what I’m really asking here, but I’ve looked at the API docs and the starter stuff, and I don’t know which way is up in Python as my scripting experience is in other langs. Here is my relatively blank start:

PLUGIN_NAME = "Performance Variables plugin"
PLUGIN_AUTHOR = "David Gravereaux <davygrvy@pobox.com>"
PLUGIN_DESCRIPTION = """
This plugin provides the 'recorded at' attributes for live releases
and recordings as variables for use in filenaming and tagger
scripts.  If the location is an event, 'held at' is used instead.
Two additional functions are provided that filter
Live-Bootleg-Style from release and recording disambig comments.

This plugin caches data requests, so it will be kind to our server ;)
"""
PLUGIN_VERSION = '0.1'
PLUGIN_API_VERSIONS = ['2.7', '2.8']
PLUGIN_LICENSE = "0BSD aka Public Domain"
PLUGIN_LICENSE_URL = "https://spdx.org/licenses/0BSD.html"
PLUGIN_USER_GUIDE_URL = "https://github.com/davygrvy/perfvars/wiki"

import re
import json
from picard import config, log
from picard.metadata import (register_album_metadata_processor,
                           register_track_metadata_processor)
from picard.plugin import PluginPriority
from picard.script import register_script_function


def filter_disambig(parser, disambig):
    return disambig


register_script_function(filter_disambig)

You might want to look at GitHub - avh4/picard-recordingdate: MusicBrainz Picard plugin for recording date metadata

That plugin might already do what you need, but it can also serve as an example.

Getting the data is not super efficient, as the plugin needs an extra request per recording. If we integrate this into Picard we could maybe already include the required relationships in the original release query.

2 Likes

That’s really close to my goals, thanks

Yes, I understand why. I’ll be needing the full *-rels Chicago Soundcheck

I’ll try to do my best to cache the JSON data to eliminate the network requests