Skip to content

Conversation

snejus
Copy link
Member

@snejus snejus commented Aug 25, 2025

  • Add configurable search_limit option to Deezer and Spotify plugins (default 5) and enforce it when returning search results.
  • Rename musicbrainz.searchlimit to musicbrainz.search_limit (old key still read with deprecation warning; slated for removal in 3.0.0).
  • Update docs and changelog to reflect the changes.

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds configurable search limits to music metadata plugins and standardizes the configuration option naming. The changes enable users to control how many search results are returned from Spotify and Deezer APIs, while maintaining backward compatibility for the MusicBrainz plugin's existing configuration.

  • Add search_limit configuration option (default 5) to Spotify and Deezer plugins
  • Rename MusicBrainz searchlimit to search_limit with deprecation warning for old option
  • Update documentation to reflect the new configuration options

Reviewed Changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
beetsplug/spotify.py Add search_limit config and enforce limit on API responses
beetsplug/deezer.py Add search_limit config and enforce limit on API responses
beetsplug/musicbrainz.py Rename searchlimit to search_limit with backward compatibility
docs/plugins/spotify.rst Document new search_limit configuration option
docs/plugins/deezer.rst Document new search_limit configuration option
docs/plugins/musicbrainz.rst Update documentation for renamed option with deprecation notice
docs/changelog.rst Update historical reference to use new option name

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link

codecov bot commented Aug 25, 2025

Codecov Report

❌ Patch coverage is 90.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 66.49%. Comparing base (b1c9355) to head (17bc110).
⚠️ Report is 5 commits behind head on master.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
beetsplug/discogs.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5960      +/-   ##
==========================================
- Coverage   66.70%   66.49%   -0.21%     
==========================================
  Files         117      117              
  Lines       18112    18119       +7     
  Branches     3070     3070              
==========================================
- Hits        12081    12048      -33     
- Misses       5374     5415      +41     
+ Partials      657      656       -1     
Files with missing lines Coverage Δ
beets/metadata_plugins.py 77.94% <100.00%> (ø)
beetsplug/deezer.py 16.66% <100.00%> (+1.22%) ⬆️
beetsplug/musicbrainz.py 72.14% <100.00%> (+0.37%) ⬆️
beetsplug/spotify.py 46.04% <ø> (ø)
beetsplug/discogs.py 65.87% <0.00%> (ø)

... and 1 file 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.

@snejus snejus force-pushed the add-configurable-search-limit branch 3 times, most recently from a770a2f to 2ef87b7 Compare August 25, 2025 19:42
@semohr
Copy link
Contributor

semohr commented Aug 26, 2025

Maybe we want to add this to the MetadataPlugin abc? Seems like logic for how many candidates are returned should be handled by every metadata plugin. Does it make a difference from an api calling perspective for the deezer and spotify endpoint i.e. do we use less api calls if we limit the returned candidate?

Alternatively, we could also have one global config for this e.g. candidates_per_metadata_plugin and early quite the iteration the plugin core logic?

@JOJ0
Copy link
Member

JOJ0 commented Aug 29, 2025

Maybe we want to add this to the MetadataPlugin abc? Seems like logic for how many candidates are returned should be handled by every metadata plugin. Does it make a difference from an api calling perspective for the deezer and spotify endpoint i.e. do we use less api calls if we limit the returned candidate?

It doesn't look like it in this implementation - full results are fetched and then simply cut off. So there shouldn't be an actual difference in performance.

Alternatively, we could also have one global config for this e.g. candidates_per_metadata_plugin and early quite the iteration the plugin core logic?

Do you mean that a global option sets all source plugins in use to one value always, eg sets a limit of 5 to all of them always? This wouldn't be a good idea in my opinion since I often had the feeling that some sources benefit from having more results available to the user than others. So individual config possiblity per source plugin should be kept I think.

I think we should merge this PR as-is since most of all it is a streamlining of options. Moving some to metadata source plugin after that. And you are the expert for that @semohr :-)

@JOJ0
Copy link
Member

JOJ0 commented Aug 29, 2025

Maybe we want to add this to the MetadataPlugin abc? Seems like logic for how many candidates are returned should be handled by every metadata plugin. Does it make a difference from an api calling perspective for the deezer and spotify endpoint i.e. do we use less api calls if we limit the returned candidate?

It doesn't look like it in this implementation - full results are fetched and then simply cut off. So there shouldn't be an actual difference in performance.

Now i was curious and investigated how for example the Discogs plugin handles that seach_limit option. In that case it does limit the api calls in the first place since that per_page option in the underlying library handles that. In case you're interested it generates a URL that only requests that much for a page and we only request one page (first page) in our plugin code:

https://github.com/joalla/discogs_client/blob/e3bd52998023a4f0624e9a28e788c445dda76370/discogs_client/models.py#L345-L351

beets/beetsplug/discogs.py

Lines 251 to 255 in 6c21482

try:
results = self.discogs_client.search(query, type="release")
results.per_page = self.config["search_limit"].as_number()
releases = results.page(1)
except CONNECTION_ERRORS:

So handling this is on a per source plugin basis I think and what this PR does is ok for now but if the libs we use support it, it could be improved. Too lazy right now to look into what deezer and spotify libs (if we use any) support.

Let's merge this and keep an issue open as a reminder? What do you all think?

@semohr
Copy link
Contributor

semohr commented Aug 29, 2025

Do you mean that a global option sets all source plugins in use to one value always, eg sets a limit of 5 to all of them always? This wouldn't be a good idea in my opinion since I often had the feeling that some sources benefit from having more results available to the user than others. So individual config possiblity per source plugin should be kept I think.

We would still have distinct options for each plugin but would handle the configuration option/logic more globally and generic. For example we use the same approach for the source_weight config option.

self.config.add({"source_weight": 0.5})

Let's merge this and keep an issue open as a reminder? What do you all think?

Agreed

@JOJ0
Copy link
Member

JOJ0 commented Aug 30, 2025

We would still have distinct options for each plugin but would handle the configuration option/logic more globally and generic. For example we use the same approach for the source_weight config option.

self.config.add({"source_weight": 0.5})

Let's merge this and keep an issue open as a reminder? What do you all think?

Agreed

I opened that reminder issue just now. But would adding a simple line like this already be a win in that abstract class (and removing it from the plugins in this PR)?

        self.config.add({"search_limit": 5})

Then we could as well add it already. Or should there be more to it in the first place?

@JOJ0 JOJ0 force-pushed the add-configurable-search-limit branch from 2ef87b7 to ccb2f5d Compare August 30, 2025 06:12
@JOJ0
Copy link
Member

JOJ0 commented Aug 30, 2025

Sorry for hijacking @snejus , I fixed that conflict in spotify.py and force-pushed. Hope you don't mind 😬

Copy link
Member

@JOJ0 JOJ0 left a comment

Choose a reason for hiding this comment

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

Include option in abc now or later @snejus ? other than that, ready to merge I guess.

@snejus snejus force-pushed the add-configurable-search-limit branch from ccb2f5d to a674fd3 Compare August 31, 2025 17:50
@snejus
Copy link
Member Author

snejus commented Sep 1, 2025

  • Moved search_limit configuration option initialisation under the common MetadataSourcePlugin interface
  • Following @semohr suggestions spotify and deezer results are now limited using the request parameters.

@snejus
Copy link
Member Author

snejus commented Sep 1, 2025

Relatedly, I started work on centralising the entire search functionality in these autotaggers: #5982

@snejus snejus merged commit c60f0ce into master Sep 4, 2025
20 checks passed
@snejus snejus deleted the add-configurable-search-limit branch September 4, 2025 11:42
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.

spotify: Improve search_limit handling deezer: Improve search_limit and pagination handling
3 participants