diff --git a/beets/autotag/__init__.py b/beets/autotag/__init__.py index e62f492c6f..9169060293 100644 --- a/beets/autotag/__init__.py +++ b/beets/autotag/__init__.py @@ -27,7 +27,7 @@ TrackMatch, Distance, ) -from .match import tag_item, tag_album, Proposal # noqa +from .match import tag_item, tag_album, current_metadata, Proposal # noqa from .match import Recommendation # noqa # Global logger. diff --git a/beets/config_default.yaml b/beets/config_default.yaml index 74540891e6..b59ce3297d 100644 --- a/beets/config_default.yaml +++ b/beets/config_default.yaml @@ -27,6 +27,7 @@ import: group_albums: no pretend: false search_ids: [] + duplicate_keys: albumartist album duplicate_action: ask bell: no set_fields: {} diff --git a/beets/importer.py b/beets/importer.py index 561cedd2c6..76aa95fd8c 100644 --- a/beets/importer.py +++ b/beets/importer.py @@ -533,6 +533,17 @@ def chosen_ident(self): elif self.choice_flag is action.APPLY: return (self.match.info.artist, self.match.info.album) + def chosen_info(self): + """Returns a dictionnary of metadata about the current choice. + May only be called when the choice flag is ASIS or RETAG + (in which case the data comes from the files' current metadata) + or APPLY (in which case the data comes from the choice). + """ + if self.choice_flag in (action.ASIS, action.RETAG): + return self.cur_info + elif self.choice_flag is action.APPLY: + return self.match.info + def imported_items(self): """Return a list of Items that should be added to the library. @@ -656,6 +667,8 @@ def lookup_candidates(self): candidate IDs are stored in self.search_ids: if present, the initial lookup is restricted to only those IDs. """ + likelies, consensus = autotag.current_metadata(self.items) + self.cur_info = likelies artist, album, prop = \ autotag.tag_album(self.items, search_ids=self.search_ids) self.cur_artist = artist @@ -675,10 +688,11 @@ def find_duplicates(self, lib): duplicates = [] task_paths = {i.path for i in self.items if i} - duplicate_query = dbcore.AndQuery(( - dbcore.MatchQuery('albumartist', artist), - dbcore.MatchQuery('album', album), - )) + keys = config['import']['duplicate_keys'].as_str().split() + info = self.chosen_info().copy() + info['albumartist'] = artist + subqueries = [ dbcore.MatchQuery(k, info.get(k)) for k in keys ] + duplicate_query = dbcore.AndQuery(subqueries) for album in lib.albums(duplicate_query): # Check whether the album paths are all present in the task diff --git a/docs/changelog.rst b/docs/changelog.rst index e803b5bfa8..2ce0d35e8f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -11,6 +11,7 @@ New features: * :doc:`/plugins/kodiupdate`: Now supports multiple kodi instances :bug:`4101` * Add the item fields ``bitrate_mode``, ``encoder_info`` and ``encoder_settings``. +* Allow to configure which fields are used to find duplicates Bug fixes: diff --git a/docs/reference/config.rst b/docs/reference/config.rst index 642216c8f7..448eb8e60c 100644 --- a/docs/reference/config.rst +++ b/docs/reference/config.rst @@ -670,6 +670,16 @@ with the ``-a`` flag to the :ref:`import-cmd` command.) Default: ``yes``. +.. _duplicate_keys: + +duplicate_keys +~~~~~~~~~~~~~~ + +The fields used to find duplicates in import task. +If several items have the same value for each key, they will be considered duplicates. + +Default: ``albumartist album`` + .. _duplicate_action: duplicate_action