diff --git a/beets/library.py b/beets/library.py index a05052427..d4ec63200 100644 --- a/beets/library.py +++ b/beets/library.py @@ -350,6 +350,10 @@ class LibModel(dbcore.Model["Library"]): # Config key that specifies how an instance should be formatted. _format_config_key: str + @cached_classproperty + def writable_media_fields(cls) -> set[str]: + return set(MediaFile.fields()) & cls._fields.keys() + def _template_funcs(self): funcs = DefaultTemplateFunctions(self, self._db).functions() funcs.update(plugins.template_funcs()) @@ -401,6 +405,13 @@ class LibModel(dbcore.Model["Library"]): [cls.field_query(f, *args, **kwargs) for f in cls._search_fields] ) + @classmethod + def any_writable_media_field_query(cls, *args, **kwargs) -> dbcore.OrQuery: + fields = cls.writable_media_fields + return dbcore.OrQuery( + [cls.field_query(f, *args, **kwargs) for f in fields] + ) + def duplicates_query(self, fields: list[str]) -> dbcore.AndQuery: """Return a query for entities with same values in the given fields.""" return dbcore.AndQuery( diff --git a/beetsplug/bpd/__init__.py b/beetsplug/bpd/__init__.py index da6c2eb46..7b01f52c5 100644 --- a/beetsplug/bpd/__init__.py +++ b/beetsplug/bpd/__init__.py @@ -27,8 +27,6 @@ import time import traceback from string import Template -from mediafile import MediaFile - import beets import beets.ui from beets import dbcore, vfs @@ -91,8 +89,6 @@ SUBSYSTEMS = [ "partition", ] -ITEM_KEYS_WRITABLE = set(MediaFile.fields()).intersection(Item._fields.keys()) - # Gstreamer import error. class NoGstreamerError(Exception): @@ -1399,7 +1395,7 @@ class Server(BaseServer): return test_tag, key raise BPDError(ERROR_UNKNOWN, "no such tagtype") - def _metadata_query(self, query_type, any_query_type, kv): + def _metadata_query(self, query_type, kv, allow_any_query: bool = False): """Helper function returns a query object that will find items according to the library query type provided and the key-value pairs specified. The any_query_type is used for queries of @@ -1411,10 +1407,10 @@ class Server(BaseServer): it = iter(kv) for tag, value in zip(it, it): if tag.lower() == "any": - if any_query_type: + if allow_any_query: queries.append( - any_query_type( - value, ITEM_KEYS_WRITABLE, query_type + Item.any_writable_media_field_query( + query_type, value ) ) else: @@ -1429,14 +1425,14 @@ class Server(BaseServer): def cmd_search(self, conn, *kv): """Perform a substring match for items.""" query = self._metadata_query( - dbcore.query.SubstringQuery, dbcore.query.AnyFieldQuery, kv + dbcore.query.SubstringQuery, kv, allow_any_query=True ) for item in self.lib.items(query): yield self._item_info(item) def cmd_find(self, conn, *kv): """Perform an exact match for items.""" - query = self._metadata_query(dbcore.query.MatchQuery, None, kv) + query = self._metadata_query(dbcore.query.MatchQuery, kv) for item in self.lib.items(query): yield self._item_info(item) @@ -1456,7 +1452,7 @@ class Server(BaseServer): raise BPDError(ERROR_ARG, 'should be "Album" for 3 arguments') elif len(kv) % 2 != 0: raise BPDError(ERROR_ARG, "Incorrect number of filter arguments") - query = self._metadata_query(dbcore.query.MatchQuery, None, kv) + query = self._metadata_query(dbcore.query.MatchQuery, kv) clause, subvals = query.clause() statement = (