Skip to content

Conversation

@Morikko
Copy link

@Morikko Morikko commented Nov 10, 2025

Description

  1. clearart command only writes a file to reset the images if it contains an embedded art. It saves some writing cost, updating the FS stats and potentially breaking COW FS. The downside is that it adds an extra read if the write is required. However, as a read is still done before writing, most OS may correctly cache it and the overhead should be small.

  2. Add a new config property called clearart_on_import. It is disabled by default for retro-compatibility. If set to true, the embedded arts are removed once an import is done.

To Do

  • Documentation.
  • Changelog.
  • Tests

@Morikko Morikko requested a review from a team as a code owner November 10, 2025 22:52
@github-actions
Copy link

Thank you for the PR! The changelog has not been updated, so here is a friendly reminder to check if you need to add an entry.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • The mtime-based assertion in test_clear_art_with_yes_input can be flaky on filesystems with coarse timestamp resolution—consider adding a short sleep or manually bumping the mtime to ensure the modification time actually increases.
  • Rather than conditionally registering import_task_files based on the config at init, register the listener unconditionally and guard execution inside the handler—this avoids needing to unload/reload plugins for config changes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The mtime-based assertion in test_clear_art_with_yes_input can be flaky on filesystems with coarse timestamp resolution—consider adding a short sleep or manually bumping the mtime to ensure the modification time actually increases.
- Rather than conditionally registering import_task_files based on the config at init, register the listener unconditionally and guard execution inside the handler—this avoids needing to unload/reload plugins for config changes.

## Individual Comments

### Comment 1
<location> `beetsplug/_utils/art.py:209-212` </location>
<code_context>
             return real_path


+def clear_item(item, log):
+    if mediafile.MediaFile(syspath(item.path)).images:
+        log.debug("Clearing art for {}", item)
+        item.try_write(tags={"images": None})
+
+
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Consider handling exceptions when clearing art from items.

If item.try_write encounters an error, such as permission issues or file corruption, it will fail silently. Adding a try/except block with logging will help detect and handle these failures.

```suggestion
def clear_item(item, log):
    if mediafile.MediaFile(syspath(item.path)).images:
        log.debug("Clearing art for {}", item)
        try:
            item.try_write(tags={"images": None})
        except Exception as exc:
            log.error("Failed to clear art for {}: {}", item, exc)
```
</issue_to_address>

### Comment 2
<location> `beets/test/helper.py:367` </location>
<code_context>
    def create_mediafile_fixture(self, ext="mp3", images=[], target_dir=None):
        """Copy a fixture mediafile with the extension to `temp_dir`.

        `images` is a subset of 'png', 'jpg', and 'tiff'. For each
        specified extension a cover art image is added to the media
        file.
        """
        if not target_dir:
            target_dir = self.temp_dir
        src = os.path.join(_common.RSRC, util.bytestring_path(f"full.{ext}"))
        handle, path = mkstemp(dir=target_dir)
        path = bytestring_path(path)
        os.close(handle)
        shutil.copyfile(syspath(src), syspath(path))

        if images:
            mediafile = MediaFile(path)
            imgs = []
            for img_ext in images:
                file = util.bytestring_path(f"image-2x3.{img_ext}")
                img_path = os.path.join(_common.RSRC, file)
                with open(img_path, "rb") as f:
                    imgs.append(Image(f.read()))
            mediafile.images = imgs
            mediafile.save()

        return path

</code_context>

<issue_to_address>
**issue (code-quality):** Replace mutable default arguments with None ([`default-mutable-arg`](https://docs.sourcery.ai/Reference/Default-Rules/suggestions/default-mutable-arg/))
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

return self.lib.add_album(items)

def create_mediafile_fixture(self, ext="mp3", images=[]):
def create_mediafile_fixture(self, ext="mp3", images=[], target_dir=None):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Replace mutable default arguments with None (default-mutable-arg)

@codecov
Copy link

codecov bot commented Nov 10, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.47%. Comparing base (29b9958) to head (16c4f6e).
⚠️ Report is 26 commits behind head on master.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6156      +/-   ##
==========================================
+ Coverage   67.34%   67.47%   +0.13%     
==========================================
  Files         136      136              
  Lines       18492    18544      +52     
  Branches     3134     3133       -1     
==========================================
+ Hits        12453    12513      +60     
+ Misses       5370     5366       -4     
+ Partials      669      665       -4     
Files with missing lines Coverage Δ
beetsplug/_utils/art.py 55.31% <100.00%> (+1.47%) ⬆️
beetsplug/embedart.py 73.38% <100.00%> (+1.35%) ⬆️

... and 35 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Morikko
Copy link
Author

Morikko commented Nov 20, 2025

I will add documentation and a changelog entry but I would like first to know if you would accept the proposed changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant