From 33b350a612aa80e1b2ab01e4f76cee6b76af66b1 Mon Sep 17 00:00:00 2001 From: Michael Krieger Date: Mon, 15 Sep 2025 18:50:47 -0400 Subject: [PATCH 1/5] Adds a zero_disc_if_single_disc to the zero plugin Adds a zero_disc_number_if_single_disc boolean to the zero plugin for writing to files. Adds the logic that, if disctotal is set and there is only one disc in disctotal, that the disc is not set. This keeps tags cleaner, only using disc on multi-disc albums. The disctotal is not touched, particularly as this is not usually displayed in most clients. The field is removed only for writing the tags, but the disc number is maintained in the database to avoid breaking anything that may depend on a disc number or avoid possible loops or failed logic. --- beetsplug/zero.py | 7 ++++++- docs/changelog.rst | 3 +++ docs/plugins/zero.rst | 2 ++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/beetsplug/zero.py b/beetsplug/zero.py index bce3b1a727..e65dd82864 100644 --- a/beetsplug/zero.py +++ b/beetsplug/zero.py @@ -41,6 +41,7 @@ def __init__(self): "fields": [], "keep_fields": [], "update_database": False, + "zero_disc_if_single_disc": False, } ) @@ -123,8 +124,12 @@ def set_fields(self, item, tags): """ fields_set = False + if "disc" in tags and self.config["zero_disc_if_single_disc"].get(bool) and item.disctotal == 1: + self._log.debug("disc: {.disc} -> None", item) + tags["disc"] = None + if not self.fields_to_progs: - self._log.warning("no fields, nothing to do") + self._log.warning("no fields list to remove") return False for field, progs in self.fields_to_progs.items(): diff --git a/docs/changelog.rst b/docs/changelog.rst index 4f32093fe6..f5109a9b44 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -8,6 +8,9 @@ Unreleased ---------- New features: +* :doc:`plugins/zero`: Add new configuration option, + ``zero_disc_if_single_disc``, to allow zeroing the disc number on + write for single-disc albums. Defaults to False. Bug fixes: diff --git a/docs/plugins/zero.rst b/docs/plugins/zero.rst index 6ed9427d94..88903a389b 100644 --- a/docs/plugins/zero.rst +++ b/docs/plugins/zero.rst @@ -31,6 +31,8 @@ to nullify and the conditions for nullifying them: ``keep_fields``---not both! - To conditionally filter a field, use ``field: [regexp, regexp]`` to specify regular expressions. +- Set ``zero_disc_if_single_disc`` to ``True`` to zero the disc number field + only if the album contains a disctotal count and is a single disc. - By default this plugin only affects files' tags; the beets database is left unchanged. To update the tags in the database, set the ``update_database`` option to true. From 5fc15bcfa4814418c2256e0db1b062b571ac9268 Mon Sep 17 00:00:00 2001 From: Michael Krieger Date: Mon, 15 Sep 2025 19:00:06 -0400 Subject: [PATCH 2/5] Misc formatting changes --- beetsplug/zero.py | 7 ++++--- docs/changelog.rst | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/beetsplug/zero.py b/beetsplug/zero.py index e65dd82864..c8ef9f855c 100644 --- a/beetsplug/zero.py +++ b/beetsplug/zero.py @@ -124,9 +124,10 @@ def set_fields(self, item, tags): """ fields_set = False - if "disc" in tags and self.config["zero_disc_if_single_disc"].get(bool) and item.disctotal == 1: - self._log.debug("disc: {.disc} -> None", item) - tags["disc"] = None + if "disc" in tags and self.config["zero_disc_if_single_disc"].get(bool): + if item.disctotal == 1: + self._log.debug("disc: {.disc} -> None", item) + tags["disc"] = None if not self.fields_to_progs: self._log.warning("no fields list to remove") diff --git a/docs/changelog.rst b/docs/changelog.rst index f5109a9b44..ac3af62578 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -8,9 +8,10 @@ Unreleased ---------- New features: -* :doc:`plugins/zero`: Add new configuration option, - ``zero_disc_if_single_disc``, to allow zeroing the disc number on - write for single-disc albums. Defaults to False. + +- :doc:`plugins/zero`: Add new configuration option, + ``zero_disc_if_single_disc``, to allow zeroing the disc number on write for + single-disc albums. Defaults to False. Bug fixes: From b1c87cd98c2f7287af40fee8560234b4d0adec4e Mon Sep 17 00:00:00 2001 From: Michael Krieger Date: Tue, 16 Sep 2025 10:04:24 -0400 Subject: [PATCH 3/5] Change parameter name, add return, add tests Change the parameter name to omit_single_disc (vs previously zero_disc_if_single_disc) Add return of 'fields_set' so that, if triggered by the command line `beets zero`, it will still effect the item.write. Added tests. --- beetsplug/zero.py | 7 +++--- docs/changelog.rst | 6 ++--- docs/plugins/zero.rst | 4 ++-- test/plugins/test_zero.py | 48 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 8 deletions(-) diff --git a/beetsplug/zero.py b/beetsplug/zero.py index c8ef9f855c..c957a27d36 100644 --- a/beetsplug/zero.py +++ b/beetsplug/zero.py @@ -41,7 +41,7 @@ def __init__(self): "fields": [], "keep_fields": [], "update_database": False, - "zero_disc_if_single_disc": False, + "omit_single_disc": False, } ) @@ -124,14 +124,15 @@ def set_fields(self, item, tags): """ fields_set = False - if "disc" in tags and self.config["zero_disc_if_single_disc"].get(bool): + if "disc" in tags and self.config["omit_single_disc"].get(bool): if item.disctotal == 1: + fields_set = True self._log.debug("disc: {.disc} -> None", item) tags["disc"] = None if not self.fields_to_progs: self._log.warning("no fields list to remove") - return False + return fields_set for field, progs in self.fields_to_progs.items(): if field in tags: diff --git a/docs/changelog.rst b/docs/changelog.rst index ac3af62578..773c6cc678 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -9,9 +9,9 @@ Unreleased New features: -- :doc:`plugins/zero`: Add new configuration option, - ``zero_disc_if_single_disc``, to allow zeroing the disc number on write for - single-disc albums. Defaults to False. +- :doc:`plugins/zero`: Add new configuration option, ``omit_single_disc``, to + allow zeroing the disc number on write for single-disc albums. Defaults to + False. Bug fixes: diff --git a/docs/plugins/zero.rst b/docs/plugins/zero.rst index 88903a389b..50b51797ee 100644 --- a/docs/plugins/zero.rst +++ b/docs/plugins/zero.rst @@ -31,8 +31,8 @@ to nullify and the conditions for nullifying them: ``keep_fields``---not both! - To conditionally filter a field, use ``field: [regexp, regexp]`` to specify regular expressions. -- Set ``zero_disc_if_single_disc`` to ``True`` to zero the disc number field - only if the album contains a disctotal count and is a single disc. +- Set ``omit_single_disc`` to ``True`` to zero the disc number field only if the + album contains a disctotal count and is a single disc. - By default this plugin only affects files' tags; the beets database is left unchanged. To update the tags in the database, set the ``update_database`` option to true. diff --git a/test/plugins/test_zero.py b/test/plugins/test_zero.py index 51913c8e05..b08bf0dcaf 100644 --- a/test/plugins/test_zero.py +++ b/test/plugins/test_zero.py @@ -249,6 +249,54 @@ def test_fields_removes_preserved_tags(self): assert "id" not in z.fields_to_progs + def test_omit_single_disc_with_tags_single(self): + item = self.add_item_fixture( + disctotal=1, disc=1, comments="test comment" + ) + item.write() + with self.configure_plugin( + {"omit_single_disc": True, "fields": ["comments"]} + ): + item.write() + + mf = MediaFile(syspath(item.path)) + assert mf.comments is None + assert mf.disc == 0 + + def test_omit_single_disc_with_tags_multi(self): + item = self.add_item_fixture( + disctotal=4, disc=1, comments="test comment" + ) + item.write() + with self.configure_plugin( + {"omit_single_disc": True, "fields": ["comments"]} + ): + item.write() + + mf = MediaFile(syspath(item.path)) + assert mf.comments is None + assert mf.disc == 1 + + def test_omit_single_disc_only_change_single(self): + item = self.add_item_fixture(disctotal=1, disc=1) + item.write() + + with self.configure_plugin({"omit_single_disc": True}): + item.write() + + mf = MediaFile(syspath(item.path)) + assert mf.disc == 0 + + def test_omit_single_disc_only_change_multi(self): + item = self.add_item_fixture(disctotal=4, disc=1) + item.write() + + with self.configure_plugin({"omit_single_disc": True}): + item.write() + + mf = MediaFile(syspath(item.path)) + assert mf.disc == 1 + def test_empty_query_n_response_no_changes(self): item = self.add_item_fixture( year=2016, day=13, month=3, comments="test comment" From dc133087847b676ed987a7ea8191ffe3b566af17 Mon Sep 17 00:00:00 2001 From: Michael Krieger Date: Tue, 16 Sep 2025 11:55:34 -0400 Subject: [PATCH 4/5] Remove tests. Update docs. Remove unnecessary return Remove tests. Update docs. Remove unnecessary return. --- beetsplug/zero.py | 1 - docs/plugins/zero.rst | 5 ++-- test/plugins/test_zero.py | 48 --------------------------------------- 3 files changed, 3 insertions(+), 51 deletions(-) diff --git a/beetsplug/zero.py b/beetsplug/zero.py index c957a27d36..ab1bfa5cab 100644 --- a/beetsplug/zero.py +++ b/beetsplug/zero.py @@ -132,7 +132,6 @@ def set_fields(self, item, tags): if not self.fields_to_progs: self._log.warning("no fields list to remove") - return fields_set for field, progs in self.fields_to_progs.items(): if field in tags: diff --git a/docs/plugins/zero.rst b/docs/plugins/zero.rst index 50b51797ee..bf134e6649 100644 --- a/docs/plugins/zero.rst +++ b/docs/plugins/zero.rst @@ -31,8 +31,9 @@ to nullify and the conditions for nullifying them: ``keep_fields``---not both! - To conditionally filter a field, use ``field: [regexp, regexp]`` to specify regular expressions. -- Set ``omit_single_disc`` to ``True`` to zero the disc number field only if the - album contains a disctotal count and is a single disc. +- Set ``omit_single_disc`` to ``True`` to omit writing the ``disc`` number for + albums with only a single disc (``disctotal == 1``). By default, beets will + number the disc even if the album contains only one disc in total. - By default this plugin only affects files' tags; the beets database is left unchanged. To update the tags in the database, set the ``update_database`` option to true. diff --git a/test/plugins/test_zero.py b/test/plugins/test_zero.py index b08bf0dcaf..51913c8e05 100644 --- a/test/plugins/test_zero.py +++ b/test/plugins/test_zero.py @@ -249,54 +249,6 @@ def test_fields_removes_preserved_tags(self): assert "id" not in z.fields_to_progs - def test_omit_single_disc_with_tags_single(self): - item = self.add_item_fixture( - disctotal=1, disc=1, comments="test comment" - ) - item.write() - with self.configure_plugin( - {"omit_single_disc": True, "fields": ["comments"]} - ): - item.write() - - mf = MediaFile(syspath(item.path)) - assert mf.comments is None - assert mf.disc == 0 - - def test_omit_single_disc_with_tags_multi(self): - item = self.add_item_fixture( - disctotal=4, disc=1, comments="test comment" - ) - item.write() - with self.configure_plugin( - {"omit_single_disc": True, "fields": ["comments"]} - ): - item.write() - - mf = MediaFile(syspath(item.path)) - assert mf.comments is None - assert mf.disc == 1 - - def test_omit_single_disc_only_change_single(self): - item = self.add_item_fixture(disctotal=1, disc=1) - item.write() - - with self.configure_plugin({"omit_single_disc": True}): - item.write() - - mf = MediaFile(syspath(item.path)) - assert mf.disc == 0 - - def test_omit_single_disc_only_change_multi(self): - item = self.add_item_fixture(disctotal=4, disc=1) - item.write() - - with self.configure_plugin({"omit_single_disc": True}): - item.write() - - mf = MediaFile(syspath(item.path)) - assert mf.disc == 1 - def test_empty_query_n_response_no_changes(self): item = self.add_item_fixture( year=2016, day=13, month=3, comments="test comment" From df8cd23ae7979a82fdcf8d0b31a2dec8676dc43b Mon Sep 17 00:00:00 2001 From: Michael Krieger Date: Tue, 16 Sep 2025 11:57:50 -0400 Subject: [PATCH 5/5] Add back tests as they were. Add back tests as they were. --- test/plugins/test_zero.py | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/test/plugins/test_zero.py b/test/plugins/test_zero.py index 51913c8e05..b08bf0dcaf 100644 --- a/test/plugins/test_zero.py +++ b/test/plugins/test_zero.py @@ -249,6 +249,54 @@ def test_fields_removes_preserved_tags(self): assert "id" not in z.fields_to_progs + def test_omit_single_disc_with_tags_single(self): + item = self.add_item_fixture( + disctotal=1, disc=1, comments="test comment" + ) + item.write() + with self.configure_plugin( + {"omit_single_disc": True, "fields": ["comments"]} + ): + item.write() + + mf = MediaFile(syspath(item.path)) + assert mf.comments is None + assert mf.disc == 0 + + def test_omit_single_disc_with_tags_multi(self): + item = self.add_item_fixture( + disctotal=4, disc=1, comments="test comment" + ) + item.write() + with self.configure_plugin( + {"omit_single_disc": True, "fields": ["comments"]} + ): + item.write() + + mf = MediaFile(syspath(item.path)) + assert mf.comments is None + assert mf.disc == 1 + + def test_omit_single_disc_only_change_single(self): + item = self.add_item_fixture(disctotal=1, disc=1) + item.write() + + with self.configure_plugin({"omit_single_disc": True}): + item.write() + + mf = MediaFile(syspath(item.path)) + assert mf.disc == 0 + + def test_omit_single_disc_only_change_multi(self): + item = self.add_item_fixture(disctotal=4, disc=1) + item.write() + + with self.configure_plugin({"omit_single_disc": True}): + item.write() + + mf = MediaFile(syspath(item.path)) + assert mf.disc == 1 + def test_empty_query_n_response_no_changes(self): item = self.add_item_fixture( year=2016, day=13, month=3, comments="test comment"