Repository: beetbox/beets

Issue:
Use preferred country to select release event within each release
When manually selecting a release during import (e.g. by using the MusicBrainz ID or via search) that contains multiple countries, it seems like preferred countries are ignored in favor of the first country in the list.

For example, in [this release](https://musicbrainz.org/release/f7304df7-2e3d-461a-b05f-442d330c1bf6) there are multiple countries. With the following config the preferred countries are ignored and Canada is selected instead:

    match:
      preferred:
        countries: ['XW', 'US', 'GB', 'XE']

The same also happens if you call `mbsync` and the country has been updated.

Should the importer also handle selecting preferred metadata when multiple options are available? Does it handle this already and I'm just doing it wrong?


Discussion:
Hmm… I think I'm a little confused. The `preferred.countries` option (and all the `preferred` things) are ways to make beets choose *between* releases. They are powerless to help if you tell beets a *specific* release—then there's no ranking to be done. Did you mean to choose between the two releases in the relevant [release group](https://musicbrainz.org/release-group/5a35595d-05c5-48df-bbd1-777aac538ae2)?
That may have been a confusing explanation because I mentioned that it happens when manually selecting a release. It turns out that it doesn't matter how the release was selected.

I know (now) that beets only uses `preferred.countries` when selecting releases. It's surprising that it doesn't then use a preferred country for selecting a release event.

Imagine an album in MusicBrainz that has multiple release events for different countries each with a different release date. If your preferred country doesn't happen to come first alphabetically, the wrong release event will be chosen and your database will contain incorrect information (for both the country **and** the release date).

In my case `CA` is **not** in my `preferred.countries` but beets has chosen it to store in the DB over `US`:

    $ beet ls -a -f '$albumartist - $album - $country' Orphée
    Jóhann Jóhannsson - Orphée - CA

Is that slightly clearer?
Yeah, thanks! It looks like beets' module for interacting with MusicBrainz dates to a time when there was only one release country (and only one release event). We naively just get "the country" for a release, which turns out to be the first alphabetically. Clearly, we should be fetching the complete list of release countries for every release, and you're right that this setting should probably control that.

Resolving patch:
diff --git a/beets/autotag/mb.py b/beets/autotag/mb.py
--- a/beets/autotag/mb.py
+++ b/beets/autotag/mb.py
@@ -109,6 +109,21 @@ def _preferred_alias(aliases):
         return matches[0]
 
 
+def _preferred_release_event(release):
+    """Given a release, select and return the user's preferred release
+    event as a tuple of (country, release_date). Fall back to the
+    default release event if a preferred event is not found.
+    """
+    countries = config['match']['preferred']['countries'].as_str_seq()
+
+    for event in release.get('release-event-list', {}):
+        for country in countries:
+            if country in event['area']['iso-3166-1-code-list']:
+                return country, event['date']
+
+    return release.get('country'), release.get('date')
+
+
 def _flatten_artist_credit(credit):
     """Given a list representing an ``artist-credit`` block, flatten the
     data into a triple of joined artist name strings: canonical, sort, and
@@ -301,7 +316,6 @@ def album_info(release):
         info.artist = config['va_name'].as_str()
     info.asin = release.get('asin')
     info.releasegroup_id = release['release-group']['id']
-    info.country = release.get('country')
     info.albumstatus = release.get('status')
 
     # Build up the disambiguation string from the release group and release.
@@ -318,8 +332,8 @@ def album_info(release):
         if reltype:
             info.albumtype = reltype.lower()
 
-    # Release dates.
-    release_date = release.get('date')
+    # Release events.
+    info.country, release_date = _preferred_release_event(release)
     release_group_date = release['release-group'].get('first-release-date')
     if not release_date:
         # Fall back if release-specific date is not available.


Test patch: