From 9f51e46baeec622d7d73d16390d34c40de4d5aa6 Mon Sep 17 00:00:00 2001 From: Adrian Kowalski Date: Fri, 9 Oct 2015 18:41:42 +0200 Subject: [PATCH 1/5] Add whitelist feature to zero plugin --- beetsplug/zero.py | 53 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/beetsplug/zero.py b/beetsplug/zero.py index abccde36f..9f56b1cac 100644 --- a/beetsplug/zero.py +++ b/beetsplug/zero.py @@ -41,26 +41,51 @@ class ZeroPlugin(BeetsPlugin): self.config.add({ 'fields': [], - 'update_database': False, + 'keep_fields': [], + 'update_database': False }) self.patterns = {} self.warned = False - for field in self.config['fields'].as_str_seq(): - if field in ('id', 'path', 'album_id'): - self._log.warn(u'field \'{0}\' ignored, zeroing ' - u'it would be dangerous', field) - continue - if field not in MediaFile.fields(): - self._log.error(u'invalid field: {0}', field) - continue + if self.config['fields'] and self.config['keep_fields']: + self._log.warn(u'cannot blacklist and whitelist at the same time') - try: - self.patterns[field] = self.config[field].as_str_seq() - except confit.NotFoundError: - # Matches everything - self.patterns[field] = True + if self.config['fields']: + for field in self.config['fields'].as_str_seq(): + if field in ('id', 'path', 'album_id'): + self._log.warn(u'field \'{0}\' ignored, zeroing ' + u'it would be dangerous', field) + continue + if field not in MediaFile.fields(): + self._log.error(u'invalid field: {0}', field) + continue + + try: + self.patterns[field] = self.config[field].as_str_seq() + except confit.NotFoundError: + # Matches everything + self.patterns[field] = True + + if self.config['keep_fields']: + for field in self.config['keep_fields'].as_str_seq(): + if field not in MediaFile.fields(): + self._log.error(u'invalid field: {0}', field) + continue + + for field in MediaFile.fields(): + if field in self.config['keep_fields'].as_str_seq(): + continue + + try: + self.patterns[field] = self.config[field].as_str_seq() + except: + self.patterns[field] = True + + # These fields should be preserved + if 'id' in self.patterns: del self.patterns['id'] + if 'path' in self.patterns: del self.patterns['path'] + if 'album_id' in self.patterns: del self.patterns['album_id'] def import_task_choice_event(self, session, task): """Listen for import_task_choice event.""" From 158486319fde3685fe097cecbc2e47ab4fbc5f97 Mon Sep 17 00:00:00 2001 From: Adrian Kowalski Date: Fri, 9 Oct 2015 21:23:59 +0200 Subject: [PATCH 2/5] Improve code quality, separate shared logic into functions --- beetsplug/zero.py | 57 +++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/beetsplug/zero.py b/beetsplug/zero.py index 9f56b1cac..b97c37bcd 100644 --- a/beetsplug/zero.py +++ b/beetsplug/zero.py @@ -48,44 +48,43 @@ class ZeroPlugin(BeetsPlugin): self.patterns = {} self.warned = False - if self.config['fields'] and self.config['keep_fields']: - self._log.warn(u'cannot blacklist and whitelist at the same time') - if self.config['fields']: + self.validate_config('fields') for field in self.config['fields'].as_str_seq(): - if field in ('id', 'path', 'album_id'): - self._log.warn(u'field \'{0}\' ignored, zeroing ' - u'it would be dangerous', field) - continue - if field not in MediaFile.fields(): - self._log.error(u'invalid field: {0}', field) - continue - - try: - self.patterns[field] = self.config[field].as_str_seq() - except confit.NotFoundError: - # Matches everything - self.patterns[field] = True + self.write_patterns(field) - if self.config['keep_fields']: - for field in self.config['keep_fields'].as_str_seq(): - if field not in MediaFile.fields(): - self._log.error(u'invalid field: {0}', field) - continue + elif self.config['keep_fields']: + self.validate_config('keep_fields') for field in MediaFile.fields(): if field in self.config['keep_fields'].as_str_seq(): continue - - try: - self.patterns[field] = self.config[field].as_str_seq() - except: - self.patterns[field] = True + self.write_patterns(field) # These fields should be preserved - if 'id' in self.patterns: del self.patterns['id'] - if 'path' in self.patterns: del self.patterns['path'] - if 'album_id' in self.patterns: del self.patterns['album_id'] + for key in ('id', 'path', 'album_id'): + if key in self.patterns: + del self.patterns[key] + + def validate_config(self, mode): + """Check if fields written in config are correct.""" + if self.config['fields'] and self.config['keep_fields']: + self._log.warn(u'cannot blacklist and whitelist at the same time') + for field in self.config[mode].as_str_seq(): + if field not in MediaFile.fields(): + self._log.error(u'invalid field: {0}', field) + continue + if mode == 'fields' and field in ('id', 'path', 'album_id'): + self._log.warn(u'field \'{0}\' ignored, zeroing ' + u'it would be dangerous', field) + continue + + def write_patterns(self, field): + try: + self.patterns[field] = self.config[field].as_str_seq() + except confit.NotFoundError: + # Matches everything + self.patterns[field] = True def import_task_choice_event(self, session, task): """Listen for import_task_choice event.""" From 84da4b89a53b092d48f756d932ef58578b717494 Mon Sep 17 00:00:00 2001 From: Adrian Kowalski Date: Fri, 9 Oct 2015 21:38:38 +0200 Subject: [PATCH 3/5] Update documentation for zero plugin --- docs/plugins/zero.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/plugins/zero.rst b/docs/plugins/zero.rst index 2682ee6ca..360c737a5 100644 --- a/docs/plugins/zero.rst +++ b/docs/plugins/zero.rst @@ -2,8 +2,10 @@ Zero Plugin =========== The ``zero`` plugin allows you to null fields in files' metadata tags. Fields -can be nulled unconditionally or conditioned on a pattern match. For example, -the plugin can strip useless comments like "ripped by MyGreatRipper." +can be nulled unconditionally or conditioned on a pattern match. It works in +two independent modes - blacklist and whitelist. You can only choose one option, +however blacklist is the default. For example, the plugin can strip useless +comments like "ripped by MyGreatRipper." To use the ``zero`` plugin, enable the plugin in your configuration (see :ref:`using-plugins`). @@ -18,6 +20,9 @@ fields to nullify and the conditions for nullifying them: get the list of all available fields by running ``beet fields``. In addition, the ``images`` field allows you to remove any images embedded in the media file. +* Set ``keep_fields`` respectively to list of fields that plugin should + preserve. That way ``zero`` cleans anything other than fields written in this + option. * To conditionally filter a field, use ``field: [regexp, regexp]`` to specify regular expressions. * By default this plugin only affects files' tags ; the beets database is left From da655534ae5f36defbc9c4eafe82e3e09b931ee6 Mon Sep 17 00:00:00 2001 From: Adrian Kowalski Date: Mon, 12 Oct 2015 09:39:20 +0200 Subject: [PATCH 4/5] Change function name and correct documentation style --- beetsplug/zero.py | 11 +++++++---- docs/plugins/zero.rst | 16 +++++++++------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/beetsplug/zero.py b/beetsplug/zero.py index b97c37bcd..561430ddc 100644 --- a/beetsplug/zero.py +++ b/beetsplug/zero.py @@ -42,7 +42,7 @@ class ZeroPlugin(BeetsPlugin): self.config.add({ 'fields': [], 'keep_fields': [], - 'update_database': False + 'update_database': False, }) self.patterns = {} @@ -51,7 +51,7 @@ class ZeroPlugin(BeetsPlugin): if self.config['fields']: self.validate_config('fields') for field in self.config['fields'].as_str_seq(): - self.write_patterns(field) + self.set_pattern(field) elif self.config['keep_fields']: self.validate_config('keep_fields') @@ -59,7 +59,7 @@ class ZeroPlugin(BeetsPlugin): for field in MediaFile.fields(): if field in self.config['keep_fields'].as_str_seq(): continue - self.write_patterns(field) + self.set_pattern(field) # These fields should be preserved for key in ('id', 'path', 'album_id'): @@ -79,7 +79,10 @@ class ZeroPlugin(BeetsPlugin): u'it would be dangerous', field) continue - def write_patterns(self, field): + def set_pattern(self, field): + """Set a field in `self.patterns` to a string list corresponding to + the configuration, or `True` if the field has no specific configuration. + """ try: self.patterns[field] = self.config[field].as_str_seq() except confit.NotFoundError: diff --git a/docs/plugins/zero.rst b/docs/plugins/zero.rst index 360c737a5..cc70e6675 100644 --- a/docs/plugins/zero.rst +++ b/docs/plugins/zero.rst @@ -2,10 +2,8 @@ Zero Plugin =========== The ``zero`` plugin allows you to null fields in files' metadata tags. Fields -can be nulled unconditionally or conditioned on a pattern match. It works in -two independent modes - blacklist and whitelist. You can only choose one option, -however blacklist is the default. For example, the plugin can strip useless -comments like "ripped by MyGreatRipper." +can be nulled unconditionally or conditioned on a pattern match. For example, +the plugin can strip useless comments like "ripped by MyGreatRipper." To use the ``zero`` plugin, enable the plugin in your configuration (see :ref:`using-plugins`). @@ -20,9 +18,9 @@ fields to nullify and the conditions for nullifying them: get the list of all available fields by running ``beet fields``. In addition, the ``images`` field allows you to remove any images embedded in the media file. -* Set ``keep_fields`` respectively to list of fields that plugin should - preserve. That way ``zero`` cleans anything other than fields written in this - option. +* Set ``keep_fields`` to *invert* the logic of the plugin. Only these fields + will be kept; other fields will be removed. Remember to set only + ``fields`` or ``keep_fields``, not both! * To conditionally filter a field, use ``field: [regexp, regexp]`` to specify regular expressions. * By default this plugin only affects files' tags ; the beets database is left @@ -36,6 +34,10 @@ For example:: genre: [rnb, 'power metal'] update_database: true +The plugin can work in one of two modes. The first mode, the default, +is a blacklist, where you choose the tags you want to remove. The second mode +is a whitelist where you instead specify the tags you want to keep. + If a custom pattern is not defined for a given field, the field will be nulled unconditionally. From d180d42ddb7658ee2a3d1f980c2c9c4e1bc563c4 Mon Sep 17 00:00:00 2001 From: Adrian Kowalski Date: Mon, 12 Oct 2015 09:50:12 +0200 Subject: [PATCH 5/5] Fix flake8 complaint about line length --- beetsplug/zero.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/beetsplug/zero.py b/beetsplug/zero.py index 561430ddc..b538d6167 100644 --- a/beetsplug/zero.py +++ b/beetsplug/zero.py @@ -81,7 +81,8 @@ class ZeroPlugin(BeetsPlugin): def set_pattern(self, field): """Set a field in `self.patterns` to a string list corresponding to - the configuration, or `True` if the field has no specific configuration. + the configuration, or `True` if the field has no specific + configuration. """ try: self.patterns[field] = self.config[field].as_str_seq()