From 249b420b1982f8a3fc4dc35430e47280c7d81cc5 Mon Sep 17 00:00:00 2001 From: Daniele Ferone Date: Tue, 7 Feb 2023 15:34:50 +0100 Subject: [PATCH 01/12] Added plugin --- beetsplug/substitute.py | 40 +++++++++++++++++++++++++++++++++++++ docs/plugins/substitute.rst | 27 +++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 beetsplug/substitute.py create mode 100644 docs/plugins/substitute.rst diff --git a/beetsplug/substitute.py b/beetsplug/substitute.py new file mode 100644 index 000000000..9d6fc2d04 --- /dev/null +++ b/beetsplug/substitute.py @@ -0,0 +1,40 @@ +# This file is part of beets. +# Copyright 2016, Adrian Sampson. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. + +"""Uses user-specified substituting rules to canonicalize names for path +formats without modifying the tags of the songs. +""" +from beets.plugins import BeetsPlugin +import re + +_substitute_rules = [] + +class Substitute(BeetsPlugin): + def __init__(self): + super(Substitute, self).__init__() + self.template_funcs['substitute'] = _tmpl_substitute + + for key, view in self.config.items(): + value = view.as_str() + pattern = re.compile(key.lower()) + _substitute_rules.append((pattern, value)) + +def _tmpl_substitute(text): + if text: + for pattern, replacement in _substitute_rules: + if pattern.match(text.lower()): + return replacement + return text + else: + return u'' diff --git a/docs/plugins/substitute.rst b/docs/plugins/substitute.rst new file mode 100644 index 000000000..867a7b391 --- /dev/null +++ b/docs/plugins/substitute.rst @@ -0,0 +1,27 @@ +Substitute Plugin +============== + +The ``substitute`` plugin lets you easily substitute values in your templates and +path formats. Specifically, it is intended to let you *canonicalize* names +such as artists: for example, perhaps you want albums from The Jimi Hendrix +Experience to be sorted into the same folder as solo Hendrix albums. + +To use field substituting, first enable the ``substitute`` plugin +(see :ref:`using-plugins`). +Then, make a ``substitute:`` section in your config file to contain your rules. +Each rule consists of a a regular expression pattern, and a +replacement value. Rules are written ``regex: replacement``. +For example, this line implements the Jimi Hendrix example above:: + + rewrite: + The Jimi Hendrix Experience: Jimi Hendrix + +The pattern is a case-insensitive regular expression. This means you can use +ordinary regular expression syntax to match multiple artists. For example, you +might use:: + + rewrite: + .*jimi hendrix.*: Jimi Hendrix + +This plugin is intented as a replacement for the ``rewrite`` plugin. Indeed, while +the ``rewrite`` plugin modifies the metadata, this plugin does not. From 07c33756b755992dabf335ac84f52d80a7782e62 Mon Sep 17 00:00:00 2001 From: Daniele Ferone Date: Sat, 11 Mar 2023 12:28:37 +0100 Subject: [PATCH 02/12] _substitute_rules became a class field --- beetsplug/substitute.py | 42 +++++++++++++---------------------------- 1 file changed, 13 insertions(+), 29 deletions(-) diff --git a/beetsplug/substitute.py b/beetsplug/substitute.py index 9d6fc2d04..d8c0ecbdf 100644 --- a/beetsplug/substitute.py +++ b/beetsplug/substitute.py @@ -1,40 +1,24 @@ -# This file is part of beets. -# Copyright 2016, Adrian Sampson. -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. - -"""Uses user-specified substituting rules to canonicalize names for path -formats without modifying the tags of the songs. -""" from beets.plugins import BeetsPlugin import re -_substitute_rules = [] - class Substitute(BeetsPlugin): + def tmpl_substitute(self, text): + if text: + for pattern, replacement in self.substitute_rules: + if pattern.match(text.lower()): + return replacement + return text + else: + return u'' + + def __init__(self): super(Substitute, self).__init__() - self.template_funcs['substitute'] = _tmpl_substitute + self.substitute_rules = [] + self.template_funcs['substitute'] = self.tmpl_substitute for key, view in self.config.items(): value = view.as_str() pattern = re.compile(key.lower()) - _substitute_rules.append((pattern, value)) + self.substitute_rules.append((pattern, value)) -def _tmpl_substitute(text): - if text: - for pattern, replacement in _substitute_rules: - if pattern.match(text.lower()): - return replacement - return text - else: - return u'' From bd568ad81747925cde7a880b9f9e7a38ea1d3ded Mon Sep 17 00:00:00 2001 From: Daniele Ferone Date: Sat, 11 Mar 2023 12:28:52 +0100 Subject: [PATCH 03/12] Changed docs of substitute plugin --- docs/plugins/substitute.rst | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/docs/plugins/substitute.rst b/docs/plugins/substitute.rst index 867a7b391..ba1f8587b 100644 --- a/docs/plugins/substitute.rst +++ b/docs/plugins/substitute.rst @@ -6,22 +6,18 @@ path formats. Specifically, it is intended to let you *canonicalize* names such as artists: for example, perhaps you want albums from The Jimi Hendrix Experience to be sorted into the same folder as solo Hendrix albums. -To use field substituting, first enable the ``substitute`` plugin -(see :ref:`using-plugins`). -Then, make a ``substitute:`` section in your config file to contain your rules. -Each rule consists of a a regular expression pattern, and a -replacement value. Rules are written ``regex: replacement``. -For example, this line implements the Jimi Hendrix example above:: - - rewrite: - The Jimi Hendrix Experience: Jimi Hendrix - -The pattern is a case-insensitive regular expression. This means you can use -ordinary regular expression syntax to match multiple artists. For example, you -might use:: - - rewrite: - .*jimi hendrix.*: Jimi Hendrix - This plugin is intented as a replacement for the ``rewrite`` plugin. Indeed, while the ``rewrite`` plugin modifies the metadata, this plugin does not. + +Enable the ``substitute`` plugin (see :ref:`using-plugins`), then make a ``substitute:`` section in your config file to contain your rules. +Each rule consists of a case-insensitive regular expression pattern, and a +replacement value. For example, you might use: + + substitute: + .*jimi hendrix.*: Jimi Hendrix + + +To apply the substitution, you have to call the function ``%substitute{}`` in the paths section. For example: + + paths: + default: %substitute{$albumartist}/$year - $album%aunique{}/$track - $title \ No newline at end of file From 20c1a3e8a0846249b0fecd593abcd7df1c663e63 Mon Sep 17 00:00:00 2001 From: Daniele Ferone Date: Fri, 17 Mar 2023 09:22:14 +0100 Subject: [PATCH 04/12] Wording fix in substitute plugin docs --- docs/plugins/substitute.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/substitute.rst b/docs/plugins/substitute.rst index ba1f8587b..a899abf14 100644 --- a/docs/plugins/substitute.rst +++ b/docs/plugins/substitute.rst @@ -3,10 +3,10 @@ Substitute Plugin The ``substitute`` plugin lets you easily substitute values in your templates and path formats. Specifically, it is intended to let you *canonicalize* names -such as artists: for example, perhaps you want albums from The Jimi Hendrix +such as artists: For example, perhaps you want albums from The Jimi Hendrix Experience to be sorted into the same folder as solo Hendrix albums. -This plugin is intented as a replacement for the ``rewrite`` plugin. Indeed, while +This plugin is intented as a replacement for the ``rewrite`` plugin. While the ``rewrite`` plugin modifies the metadata, this plugin does not. Enable the ``substitute`` plugin (see :ref:`using-plugins`), then make a ``substitute:`` section in your config file to contain your rules. From a4363fb6808b8d5d3ecbc74c72eae464ddea5e62 Mon Sep 17 00:00:00 2001 From: Daniele Ferone Date: Tue, 16 May 2023 10:57:10 +0200 Subject: [PATCH 05/12] Fixes in substitute plugin docs --- beetsplug/substitute.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/beetsplug/substitute.py b/beetsplug/substitute.py index d8c0ecbdf..a3c59c4f0 100644 --- a/beetsplug/substitute.py +++ b/beetsplug/substitute.py @@ -1,7 +1,30 @@ +# This file is part of beets. +# Copyright 2023, Daniele Ferone. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. + +"""Uses user-specified substitution rules to canonicalize names for path +formats. +""" + from beets.plugins import BeetsPlugin import re + class Substitute(BeetsPlugin): + """Create a template field function that subsitute the given field + with the given substitution rules. ``rules`` must be a list of + (pattern, replacement) pairs. + """ def tmpl_substitute(self, text): if text: for pattern, replacement in self.substitute_rules: @@ -11,7 +34,6 @@ class Substitute(BeetsPlugin): else: return u'' - def __init__(self): super(Substitute, self).__init__() self.substitute_rules = [] @@ -21,4 +43,3 @@ class Substitute(BeetsPlugin): value = view.as_str() pattern = re.compile(key.lower()) self.substitute_rules.append((pattern, value)) - From f3f6118b8f28cca4368a853e782c385ba9e07806 Mon Sep 17 00:00:00 2001 From: Daniele Ferone Date: Sat, 20 May 2023 08:45:59 +0200 Subject: [PATCH 06/12] Linting fixes in substitute plugin --- beetsplug/substitute.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/beetsplug/substitute.py b/beetsplug/substitute.py index a3c59c4f0..56c06da90 100644 --- a/beetsplug/substitute.py +++ b/beetsplug/substitute.py @@ -12,12 +12,11 @@ # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. -"""Uses user-specified substitution rules to canonicalize names for path -formats. +"""Uses user-specified substitution rules to canonicalize names for path formats. """ -from beets.plugins import BeetsPlugin import re +from beets.plugins import BeetsPlugin class Substitute(BeetsPlugin): From a7e02461ee7b0ca5d3670fddc7b2827c4d032ff9 Mon Sep 17 00:00:00 2001 From: J0J0 Todos Date: Thu, 31 Aug 2023 07:39:03 +0200 Subject: [PATCH 07/12] Add changelog for substitute plugin While rebasing master into this feature branch I removed fdaniele85's original version(s) of the changelog to make conflict resolvement easier. This is a slightly extended version of the latest version I found in the original commits. --- docs/changelog.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 0aacbf03a..4ceeb1874 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -115,6 +115,10 @@ New features: * :doc:`/plugins/embyupdate`: Add handling for private users by adding ``userid`` config option. :bug:`4402` +* :doc:`/plugins/substitute`: Add the new plugin `substitute` as an alternative + to the `rewrite` plugin. The main difference between them being that + `rewrite` modifies files' metadata and `substitute` does not. + :bug:`2786` Bug fixes: From 442a535b3e1e2e8d08cb29a8109b86942e217cff Mon Sep 17 00:00:00 2001 From: J0J0 Todos Date: Thu, 31 Aug 2023 08:27:22 +0200 Subject: [PATCH 08/12] Add substitute plugin to the docs' plugins index --- docs/plugins/index.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/plugins/index.rst b/docs/plugins/index.rst index 96b0eb7a8..21e99e3dc 100644 --- a/docs/plugins/index.rst +++ b/docs/plugins/index.rst @@ -122,6 +122,7 @@ following to your configuration:: spotify subsonicplaylist subsonicupdate + substitute the thumbnails types @@ -240,6 +241,11 @@ Path Formats :doc:`rewrite ` Substitute values in path formats. +:doc:`substitute ` + As an alternative to :doc:`rewrite `, use this plugin. The main + difference between them is that this plugin never modifies the files + metadata. + :doc:`the ` Move patterns in path formats (i.e., move "a" and "the" to the end). From 54efb279ffdad95f197f1dac50f611e4c801e7a4 Mon Sep 17 00:00:00 2001 From: J0J0 Todos Date: Thu, 31 Aug 2023 08:45:02 +0200 Subject: [PATCH 09/12] Try to clarify the bevhavior of the rewrite plugin in the plugin docs as was discovered in #2786 (Metadata being modified). --- docs/plugins/rewrite.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/plugins/rewrite.rst b/docs/plugins/rewrite.rst index 3706d940a..5610408aa 100644 --- a/docs/plugins/rewrite.rst +++ b/docs/plugins/rewrite.rst @@ -30,5 +30,7 @@ As a convenience, the plugin applies patterns for the ``artist`` field to the ``albumartist`` field as well. (Otherwise, you would probably want to duplicate every rule for ``artist`` and ``albumartist``.) -Note that this plugin only applies to templating; it does not modify files' -metadata tags or the values tracked by beets' library database. +Note that this plugin basically only applies to templating; it initially does +not modify files' metadata tags or the values tracked by beets' library +database, but since it rewrites all field lookups, it also might modify file's +metadata. From 6e983d8615b83e391ef8d156d71ab829109c8339 Mon Sep 17 00:00:00 2001 From: J0J0 Todos Date: Thu, 31 Aug 2023 08:59:18 +0200 Subject: [PATCH 10/12] Fix title underline in substitute plugin docs --- docs/plugins/substitute.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/substitute.rst b/docs/plugins/substitute.rst index a899abf14..14f3cb025 100644 --- a/docs/plugins/substitute.rst +++ b/docs/plugins/substitute.rst @@ -1,5 +1,5 @@ Substitute Plugin -============== +================= The ``substitute`` plugin lets you easily substitute values in your templates and path formats. Specifically, it is intended to let you *canonicalize* names From 4f4e4cdc70f5a32e572e671db24df2deae85a401 Mon Sep 17 00:00:00 2001 From: J0J0 Todos Date: Thu, 31 Aug 2023 09:26:39 +0200 Subject: [PATCH 11/12] Fix docstring issues in substitute module to finally make linter happy. --- beetsplug/substitute.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/beetsplug/substitute.py b/beetsplug/substitute.py index 56c06da90..120e62dfc 100644 --- a/beetsplug/substitute.py +++ b/beetsplug/substitute.py @@ -12,7 +12,9 @@ # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. -"""Uses user-specified substitution rules to canonicalize names for path formats. +"""The substitute plugin module. + +Uses user-specified substitution rules to canonicalize names for path formats. """ import re @@ -20,11 +22,14 @@ from beets.plugins import BeetsPlugin class Substitute(BeetsPlugin): - """Create a template field function that subsitute the given field - with the given substitution rules. ``rules`` must be a list of - (pattern, replacement) pairs. + """The substitute plugin class. + + Create a template field function that subsitute the given field with the + given substitution rules. ``rules`` must be a list of (pattern, + replacement) pairs. """ def tmpl_substitute(self, text): + """Do the actual replacing.""" if text: for pattern, replacement in self.substitute_rules: if pattern.match(text.lower()): @@ -34,6 +39,11 @@ class Substitute(BeetsPlugin): return u'' def __init__(self): + """Initialize the substitute plugin. + + Get the configuration, register template function and create list of + substitute rules. + """ super(Substitute, self).__init__() self.substitute_rules = [] self.template_funcs['substitute'] = self.tmpl_substitute From c185b4fba5346b823abd17304456186238268f2f Mon Sep 17 00:00:00 2001 From: J0J0 Todos Date: Fri, 8 Sep 2023 19:19:06 +0200 Subject: [PATCH 12/12] Final take on rewording rewrite plugin docs on whether it modifies metadata or not. Let's also leave a link to the issue here to make it superclear and researchable for anyone stumbling across it. Also suggest the substitute plugin as an alternative. --- docs/plugins/rewrite.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/plugins/rewrite.rst b/docs/plugins/rewrite.rst index 5610408aa..41cd454bf 100644 --- a/docs/plugins/rewrite.rst +++ b/docs/plugins/rewrite.rst @@ -30,7 +30,9 @@ As a convenience, the plugin applies patterns for the ``artist`` field to the ``albumartist`` field as well. (Otherwise, you would probably want to duplicate every rule for ``artist`` and ``albumartist``.) -Note that this plugin basically only applies to templating; it initially does -not modify files' metadata tags or the values tracked by beets' library -database, but since it rewrites all field lookups, it also might modify file's -metadata. +A word of warning: This plugin theoretically only applies to templates and path +formats; it initially does not modify files' metadata tags or the values +tracked by beets' library database, but since it *rewrites all field lookups*, +it modifies the file's metadata anyway. See comments in issue :bug:`2786`. + +As an alternative to this plugin the :doc:`/plugins/substitute` could be used.