From 472aa12767340eb4e079213f5bae4001034ba5a6 Mon Sep 17 00:00:00 2001 From: Ember Light Date: Thu, 16 Oct 2025 18:49:14 +0200 Subject: [PATCH 1/9] Add main functionality --- beetsplug/ftintitle.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/beetsplug/ftintitle.py b/beetsplug/ftintitle.py index ef9b763cf..c10fdada5 100644 --- a/beetsplug/ftintitle.py +++ b/beetsplug/ftintitle.py @@ -108,6 +108,7 @@ class FtInTitlePlugin(plugins.BeetsPlugin): "drop": False, "format": "feat. {}", "keep_in_artist": False, + "skip_if_artist_and_album_artists_is_the_same": True, "custom_words": [], } ) @@ -133,12 +134,19 @@ class FtInTitlePlugin(plugins.BeetsPlugin): self.config.set_args(opts) drop_feat = self.config["drop"].get(bool) keep_in_artist_field = self.config["keep_in_artist"].get(bool) + skip_if_artist_and_album_artists_is_the_same = self.config[ + "skip_if_artist_and_album_artists_is_the_same" + ].get(bool) custom_words = self.config["custom_words"].get(list) write = ui.should_write() for item in lib.items(args): if self.ft_in_title( - item, drop_feat, keep_in_artist_field, custom_words + item, + drop_feat, + keep_in_artist_field, + skip_if_artist_and_album_artists_is_the_same, + custom_words, ): item.store() if write: @@ -151,11 +159,18 @@ class FtInTitlePlugin(plugins.BeetsPlugin): """Import hook for moving featuring artist automatically.""" drop_feat = self.config["drop"].get(bool) keep_in_artist_field = self.config["keep_in_artist"].get(bool) + skip_if_artist_and_album_artists_is_the_same = self.config[ + "skip_if_artist_and_album_artists_is_the_same" + ].get(bool) custom_words = self.config["custom_words"].get(list) for item in task.imported_items(): if self.ft_in_title( - item, drop_feat, keep_in_artist_field, custom_words + item, + drop_feat, + keep_in_artist_field, + skip_if_artist_and_album_artists_is_the_same, + custom_words, ): item.store() @@ -204,6 +219,7 @@ class FtInTitlePlugin(plugins.BeetsPlugin): item: Item, drop_feat: bool, keep_in_artist_field: bool, + skip_if_artist_and_album_artists_is_the_same: bool, custom_words: list[str], ) -> bool: """Look for featured artists in the item's artist fields and move @@ -218,7 +234,11 @@ class FtInTitlePlugin(plugins.BeetsPlugin): # Check whether there is a featured artist on this track and the # artist field does not exactly match the album artist field. In # that case, we attempt to move the featured artist to the title. - if albumartist and artist == albumartist: + if ( + skip_if_artist_and_album_artists_is_the_same + and albumartist + and artist == albumartist + ): return False _, featured = split_on_feat(artist, custom_words=custom_words) From f275835cd374d3f4e2759bc392fec41d4797100d Mon Sep 17 00:00:00 2001 From: Ember Light Date: Thu, 16 Oct 2025 18:49:24 +0200 Subject: [PATCH 2/9] Add test --- test/plugins/test_ftintitle.py | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/plugins/test_ftintitle.py b/test/plugins/test_ftintitle.py index 30b414948..f4fb898ac 100644 --- a/test/plugins/test_ftintitle.py +++ b/test/plugins/test_ftintitle.py @@ -205,6 +205,46 @@ def add_item( ("Alice med Bob", "Song 1"), id="custom-feat-words-keep-in-artists-drop-from-title", ), + # ---- skip_if_artist_and_album_artists_is_the_same variants ---- + pytest.param( + { + "format": "feat. {}", + "skip_if_artist_and_album_artists_is_the_same": True, + }, + ("ftintitle",), + ("Alice feat. Bob", "Song 1", "Alice"), + ("Alice", "Song 1 feat. Bob"), + id="skip-if-artist-and-album-artists-is-the-same-different-match", + ), + pytest.param( + { + "format": "feat. {}", + "skip_if_artist_and_album_artists_is_the_same": False, + }, + ("ftintitle",), + ("Alice feat. Bob", "Song 1", "Alice"), + ("Alice", "Song 1 feat. Bob"), + id="skip-if-artist-and-album-artists-is-the-same-different-match-b", + ), + pytest.param( + { + "format": "feat. {}", + "skip_if_artist_and_album_artists_is_the_same": True, + }, + ("ftintitle",), + ("Alice feat. Bob", "Song 1", "Alice feat. Bob"), + ("Alice feat. Bob", "Song 1"), + id="skip-if-artist-and-album-artists-is-the-same-matching-match", + ), + pytest.param( + { + "format": "feat. {}", + }, + ("ftintitle",), + ("Alice feat. Bob", "Song 1", "Alice feat. Bob"), + ("Alice", "Song 1 feat. Bob"), + id="skip-if-artist-and-album-artists-is-the-same-matching-match-b", + ), ], ) def test_ftintitle_functional( From 6d2d663d3e3c3ab119b39eda7fae418715e47b12 Mon Sep 17 00:00:00 2001 From: Ember Light Date: Thu, 16 Oct 2025 18:49:32 +0200 Subject: [PATCH 3/9] Add documentation --- docs/plugins/ftintitle.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/plugins/ftintitle.rst b/docs/plugins/ftintitle.rst index 1a95d03a8..7da56fbc7 100644 --- a/docs/plugins/ftintitle.rst +++ b/docs/plugins/ftintitle.rst @@ -28,6 +28,8 @@ file. The available options are: - **keep_in_artist**: Keep the featuring X part in the artist field. This can be useful if you still want to be able to search for features in the artist field. Default: ``no``. +- **skip_if_artist_and_album_artists_is_the_same**: If the artist and the album + artist is the same, skip the ftintitle processing. Default: ``yes``. - **custom_words**: List of additional words that will be treated as a marker for artist features. Default: ``[]``. From 022d7625d2e5cf6639acced28a37ef5fc0611aa2 Mon Sep 17 00:00:00 2001 From: Ember Light Date: Thu, 16 Oct 2025 18:49:39 +0200 Subject: [PATCH 4/9] Add changelog --- docs/changelog.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 9a8fc539b..00460e8ea 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -10,6 +10,8 @@ Unreleased New features: - :doc:`plugins/ftintitle`: Added argument for custom feat. words in ftintitle. +- :doc:`plugins/ftintitle`: Added argument to skip the processing of artist and + album artist is the same in ftintitle. Bug fixes: From 9b33575a70c68b99de8ca618cf800f3d5112f141 Mon Sep 17 00:00:00 2001 From: Ember Light <49758407+EmberLightVFX@users.noreply.github.com> Date: Thu, 16 Oct 2025 19:01:17 +0200 Subject: [PATCH 5/9] Update docs/changelog.rst Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --- docs/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 00460e8ea..c6fbf098b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -11,7 +11,7 @@ New features: - :doc:`plugins/ftintitle`: Added argument for custom feat. words in ftintitle. - :doc:`plugins/ftintitle`: Added argument to skip the processing of artist and - album artist is the same in ftintitle. + album artist are the same in ftintitle. Bug fixes: From adb5b293f047f6924699c7a3aa2e0af44da8ff09 Mon Sep 17 00:00:00 2001 From: Ember Light <49758407+EmberLightVFX@users.noreply.github.com> Date: Thu, 16 Oct 2025 19:01:29 +0200 Subject: [PATCH 6/9] Update docs/plugins/ftintitle.rst Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --- docs/plugins/ftintitle.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/ftintitle.rst b/docs/plugins/ftintitle.rst index 7da56fbc7..3b5d3ca85 100644 --- a/docs/plugins/ftintitle.rst +++ b/docs/plugins/ftintitle.rst @@ -29,7 +29,7 @@ file. The available options are: useful if you still want to be able to search for features in the artist field. Default: ``no``. - **skip_if_artist_and_album_artists_is_the_same**: If the artist and the album - artist is the same, skip the ftintitle processing. Default: ``yes``. + artist are the same, skip the ftintitle processing. Default: ``yes``. - **custom_words**: List of additional words that will be treated as a marker for artist features. Default: ``[]``. From ca8df30ec36124f17413eb44609362769aace693 Mon Sep 17 00:00:00 2001 From: Ember Light Date: Thu, 16 Oct 2025 19:06:56 +0200 Subject: [PATCH 7/9] Add missing test parameter --- test/plugins/test_ftintitle.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/plugins/test_ftintitle.py b/test/plugins/test_ftintitle.py index f4fb898ac..9fc771e89 100644 --- a/test/plugins/test_ftintitle.py +++ b/test/plugins/test_ftintitle.py @@ -239,6 +239,7 @@ def add_item( pytest.param( { "format": "feat. {}", + "skip_if_artist_and_album_artists_is_the_same": False, }, ("ftintitle",), ("Alice feat. Bob", "Song 1", "Alice feat. Bob"), From 027b775fcd802e3011366434812353ed5d2bdee6 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Mon, 20 Oct 2025 15:22:27 +0200 Subject: [PATCH 8/9] Change arg name --- beetsplug/ftintitle.py | 24 +++++++++--------------- docs/plugins/ftintitle.rst | 2 +- test/plugins/test_ftintitle.py | 10 +++++----- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/beetsplug/ftintitle.py b/beetsplug/ftintitle.py index c10fdada5..dd681a972 100644 --- a/beetsplug/ftintitle.py +++ b/beetsplug/ftintitle.py @@ -108,7 +108,7 @@ class FtInTitlePlugin(plugins.BeetsPlugin): "drop": False, "format": "feat. {}", "keep_in_artist": False, - "skip_if_artist_and_album_artists_is_the_same": True, + "preserve_album_artist": True, "custom_words": [], } ) @@ -134,9 +134,9 @@ class FtInTitlePlugin(plugins.BeetsPlugin): self.config.set_args(opts) drop_feat = self.config["drop"].get(bool) keep_in_artist_field = self.config["keep_in_artist"].get(bool) - skip_if_artist_and_album_artists_is_the_same = self.config[ - "skip_if_artist_and_album_artists_is_the_same" - ].get(bool) + preserve_album_artist = self.config["preserve_album_artist"].get( + bool + ) custom_words = self.config["custom_words"].get(list) write = ui.should_write() @@ -145,7 +145,7 @@ class FtInTitlePlugin(plugins.BeetsPlugin): item, drop_feat, keep_in_artist_field, - skip_if_artist_and_album_artists_is_the_same, + preserve_album_artist, custom_words, ): item.store() @@ -159,9 +159,7 @@ class FtInTitlePlugin(plugins.BeetsPlugin): """Import hook for moving featuring artist automatically.""" drop_feat = self.config["drop"].get(bool) keep_in_artist_field = self.config["keep_in_artist"].get(bool) - skip_if_artist_and_album_artists_is_the_same = self.config[ - "skip_if_artist_and_album_artists_is_the_same" - ].get(bool) + preserve_album_artist = self.config["preserve_album_artist"].get(bool) custom_words = self.config["custom_words"].get(list) for item in task.imported_items(): @@ -169,7 +167,7 @@ class FtInTitlePlugin(plugins.BeetsPlugin): item, drop_feat, keep_in_artist_field, - skip_if_artist_and_album_artists_is_the_same, + preserve_album_artist, custom_words, ): item.store() @@ -219,7 +217,7 @@ class FtInTitlePlugin(plugins.BeetsPlugin): item: Item, drop_feat: bool, keep_in_artist_field: bool, - skip_if_artist_and_album_artists_is_the_same: bool, + preserve_album_artist: bool, custom_words: list[str], ) -> bool: """Look for featured artists in the item's artist fields and move @@ -234,11 +232,7 @@ class FtInTitlePlugin(plugins.BeetsPlugin): # Check whether there is a featured artist on this track and the # artist field does not exactly match the album artist field. In # that case, we attempt to move the featured artist to the title. - if ( - skip_if_artist_and_album_artists_is_the_same - and albumartist - and artist == albumartist - ): + if preserve_album_artist and albumartist and artist == albumartist: return False _, featured = split_on_feat(artist, custom_words=custom_words) diff --git a/docs/plugins/ftintitle.rst b/docs/plugins/ftintitle.rst index 3b5d3ca85..b0e69af88 100644 --- a/docs/plugins/ftintitle.rst +++ b/docs/plugins/ftintitle.rst @@ -28,7 +28,7 @@ file. The available options are: - **keep_in_artist**: Keep the featuring X part in the artist field. This can be useful if you still want to be able to search for features in the artist field. Default: ``no``. -- **skip_if_artist_and_album_artists_is_the_same**: If the artist and the album +- **preserve_album_artist**: If the artist and the album artist are the same, skip the ftintitle processing. Default: ``yes``. - **custom_words**: List of additional words that will be treated as a marker for artist features. Default: ``[]``. diff --git a/test/plugins/test_ftintitle.py b/test/plugins/test_ftintitle.py index 9fc771e89..56c82b9d2 100644 --- a/test/plugins/test_ftintitle.py +++ b/test/plugins/test_ftintitle.py @@ -205,11 +205,11 @@ def add_item( ("Alice med Bob", "Song 1"), id="custom-feat-words-keep-in-artists-drop-from-title", ), - # ---- skip_if_artist_and_album_artists_is_the_same variants ---- + # ---- preserve_album_artist variants ---- pytest.param( { "format": "feat. {}", - "skip_if_artist_and_album_artists_is_the_same": True, + "preserve_album_artist": True, }, ("ftintitle",), ("Alice feat. Bob", "Song 1", "Alice"), @@ -219,7 +219,7 @@ def add_item( pytest.param( { "format": "feat. {}", - "skip_if_artist_and_album_artists_is_the_same": False, + "preserve_album_artist": False, }, ("ftintitle",), ("Alice feat. Bob", "Song 1", "Alice"), @@ -229,7 +229,7 @@ def add_item( pytest.param( { "format": "feat. {}", - "skip_if_artist_and_album_artists_is_the_same": True, + "preserve_album_artist": True, }, ("ftintitle",), ("Alice feat. Bob", "Song 1", "Alice feat. Bob"), @@ -239,7 +239,7 @@ def add_item( pytest.param( { "format": "feat. {}", - "skip_if_artist_and_album_artists_is_the_same": False, + "preserve_album_artist": False, }, ("ftintitle",), ("Alice feat. Bob", "Song 1", "Alice feat. Bob"), From bb541e22c3d0c7d736066fa71b8ef2cf67a8e830 Mon Sep 17 00:00:00 2001 From: Jacob Danell Date: Mon, 20 Oct 2025 15:28:33 +0200 Subject: [PATCH 9/9] Lint the docs --- docs/plugins/ftintitle.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/ftintitle.rst b/docs/plugins/ftintitle.rst index b0e69af88..1d2ec5c20 100644 --- a/docs/plugins/ftintitle.rst +++ b/docs/plugins/ftintitle.rst @@ -28,8 +28,8 @@ file. The available options are: - **keep_in_artist**: Keep the featuring X part in the artist field. This can be useful if you still want to be able to search for features in the artist field. Default: ``no``. -- **preserve_album_artist**: If the artist and the album - artist are the same, skip the ftintitle processing. Default: ``yes``. +- **preserve_album_artist**: If the artist and the album artist are the same, + skip the ftintitle processing. Default: ``yes``. - **custom_words**: List of additional words that will be treated as a marker for artist features. Default: ``[]``.