Only one %catalognumber%

How to do it to generate only one or only the first catalog number in albums with several catalog numbers?

Example:

$if(%catalognumber%, [%catalognumber%])
Generates:
obraz
Desired effect:
obraz

Any ideas? I tried with &left / &right /&ne but it does not work as it should.

You can use the regex search to choose only the first value before a multi-value separator (the default is "; ").

$if(%catalognumber%,[$rsearch(%catalognumber%,\(.+?\)\(?:; |\$\))])

Here’s the plain regex without escape characters (and the same on regex101.com)

(.+?)(?:; |$)

This solution isn’t 100% perfect because if a catalog number itself includes the separator, the value gets split up like if it was two values: "c4t4; l0gnumb3r" would give us "c4t4" instead of the whole value.

The above restriction seems unavoidable with the default functions. I just happened to make a plugin which gets past the mentioned restriction but in practice, the regex method works almost as well. [.]

PLUGIN_NAME = "Get Multi-value Subset"
PLUGIN_AUTHOR = "Joel Lintunen"
PLUGIN_DESCRIPTION = """Returns a subset of values from a multi-value tag.
<br /><br />
Examples:
<ul>
  <li><i>$getmultirange(catalognumber,0)</i> returns the first value if it exists</li>
  <li><i>$getmultirange(writer,2:4,\, )</i> returns the third and fourth values if they exist, separated by a
      comma</li>
</ul>
Arguments:
<ol>
  <li>Multi-value tag.</li>
  <li>List index or slicer. For example <i>"0"</i>, <i>":2"</i>, <i>"::2"</i> or <i>"-1"</i>.</li>
  <li>Separator which will be used to divide the values. The default is <i>"; "</i>.</li>
</ol>
"""
PLUGIN_VERSION = "1.0.0"
PLUGIN_API_VERSIONS = ["2.0", "2.1", "2.2"]
PLUGIN_LICENSE = "GPL-2.0"
PLUGIN_LICENSE_URL = "https://www.gnu.org/licenses/gpl-2.0.html"

from picard.metadata import MULTI_VALUED_JOINER
from picard.script import (
    normalize_tagname,
    register_script_function)


def func_get_multi_range(parser, multi, range, separator=MULTI_VALUED_JOINER):
    # Check inputs to prevent crashes on the options page
    if not multi or not range or not all(x.isdigit() or x in [':', '-', '+'] for x in range):
        return ""

    multi_values = parser.context.getall(normalize_tagname(multi))
    try:
        # Check if range is an index instead of a slicer
        if len(range.split(':')) == 1:
                return multi_values[int(range)]
        return separator.join(eval("{0}[{1}]".format(multi_values, range)))
    except (IndexError, SyntaxError, ValueError):
        return ""


register_script_function(func_get_multi_range, "getmultirange")

6 Likes

Oh my… quick test and looks like that it wooooorks like a charm! @Harakku THANK YOU. Thanks to you, my script is finally completed.

2 Likes

That’s a really neat little plugin. :slight_smile: It would be great if you’d submit it to the picard-plugins repository for wider usage:

5 Likes