diff --git a/beetsplug/importsource.py b/beetsplug/importsource.py index 19b2530ba..e42be3f1f 100644 --- a/beetsplug/importsource.py +++ b/beetsplug/importsource.py @@ -39,6 +39,8 @@ class ImportSourcePlugin(BeetsPlugin): ) def prevent_suggest_removal(self, session, task): + if task.skip: + return for item in task.imported_items(): if "mb_albumid" in item: self.stop_suggestions_for_albums.add(item.mb_albumid) diff --git a/docs/changelog.rst b/docs/changelog.rst index 6d37a64a4..d37c0c802 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -24,6 +24,9 @@ New features: to receive extra verbose logging around last.fm results and how they are resolved. The ``extended_debug`` config setting and ``--debug`` option have been removed. +- :doc:`plugins/importsource`: Added new plugin that tracks original import + paths and optionally suggests removing source files when items are removed + from the library. - :doc:`plugins/mbpseudo`: Add a new `mbpseudo` plugin to proactively receive MusicBrainz pseudo-releases as recommendations during import. - Added support for Python 3.13. @@ -491,7 +494,6 @@ New features: ``beet list -a title:something`` or ``beet list artpath:cover``. Consequently album queries involving ``path`` field have been sped up, like ``beet list -a path:/path/``. -- :doc:`plugins/importsource`: Added plugin - :doc:`plugins/ftintitle`: New ``keep_in_artist`` option for the plugin, which allows keeping the "feat." part in the artist metadata while still changing the title. diff --git a/test/plugins/test_importsource.py b/test/plugins/test_importsource.py index e05a8f177..a4f498181 100644 --- a/test/plugins/test_importsource.py +++ b/test/plugins/test_importsource.py @@ -18,7 +18,7 @@ import os import time -from beets import importer +from beets import importer, plugins from beets.test.helper import AutotagImportTestCase, PluginMixin, control_stdin from beets.util import syspath from beetsplug.importsource import ImportSourcePlugin @@ -113,3 +113,34 @@ class ImportSourceTest(PluginMixin, AutotagImportTestCase): assert current_mtime == original_mtime, ( f"Source file timestamp changed: {path}" ) + + def test_prevent_suggest_removal_on_reimport(self): + """Test that removal suggestions are prevented during reimport.""" + album = self.lib.albums().get() + mb_albumid = album.mb_albumid + + # Reimport from library + reimporter = self.setup_importer(import_dir=self.libdir) + reimporter.add_choice(importer.Action.APPLY) + reimporter.run() + + plugin = plugins._instances[0] + assert mb_albumid in plugin.stop_suggestions_for_albums + + # Calling suggest_removal should exit early without prompting + item = self.lib.items().get() + plugin.suggest_removal(item) + assert os.path.exists(item.source_path) + + def test_prevent_suggest_removal_handles_skipped_task(self): + """Test that skipped tasks don't crash prevent_suggest_removal.""" + + class MockTask: + skip = True + + def imported_items(self): + return "whatever" + + plugin = plugins._instances[0] + mock_task = MockTask() + plugin.prevent_suggest_removal(None, mock_task)