mbsync: Deal with albums that have multiple copies of the same recording
the current way mbsync plugin used to obtain track mapping list is to use the MusicBrainz recoding ID from each track, it's a workaround to handle "missing or extra tracks". This method is based on an assumption that for each MB release, there are no multiple tracks with same MB recording ID. It usually works, and in my case, only 4 out of 700+ albums disobey this assumption. But for this four albums, I have to fix them by tag track number by hand and re-import.

Considering it's called "mbsync", Why not make an assumption that track number in metadata is not corrupt and use it if possible, or fallback to MB recording ID way if it's corrupted(missing or extra track detected)

diff --git a/beetsplug/mbsync.py b/beetsplug/mbsync.py
index 76226f08c..1e5857bba 100644
--- a/beetsplug/mbsync.py
+++ b/beetsplug/mbsync.py
@@ -64,13 +64,29 @@ def mbsync_albums(lib, query, move, pretend, write):
             log.info(u'Release ID not found: {0}'.format(a.mb_albumid))
             continue
 
+        # Construct an hash mapping recording MBIDs to their information. A
+        # release can have recording MBIDs that appear multiple times in the
+        # same release.
+        track_index = {}
+        for track_info in album_info.tracks:
+            if track_info.track_id in track_index:
+                track_index[track_info.track_id].append(track_info)
+            else:
+                track_index[track_info.track_id] = [track_info]
+
         # Construct a track mapping according to MBIDs. This should work
-        # for albums that have missing or extra tracks.
+        # for albums that have missing or extra tracks. If a mapping is
+        # ambiguous, the items' disc and track number need to match in order
+        # for an item to be mapped.
         mapping = {}
         for item in items:
-            for track_info in album_info.tracks:
-                if item.mb_trackid == track_info.track_id:
-                    mapping[item] = track_info
+            candidates = track_index.get(item.mb_trackid, [])
+            if len(candidates) == 1:
+                mapping[item] = candidates[0]
+                continue
+            for c in candidates:
+                if c.medium_index == item.track and c.medium == item.disc:
+                    mapping[item] = c
                     break
 
         # Apply.
['beetsplug/mbsync.py']