Skip to content

Add Recommendations plugin provider#3890

Draft
dmoo500 wants to merge 11 commits into
music-assistant:devfrom
dmoo500:feature/recommendations-plugin
Draft

Add Recommendations plugin provider#3890
dmoo500 wants to merge 11 commits into
music-assistant:devfrom
dmoo500:feature/recommendations-plugin

Conversation

@dmoo500
Copy link
Copy Markdown
Contributor

@dmoo500 dmoo500 commented May 14, 2026

Recommendations Plugin Provider

A new PluginProvider that surfaces library-based discovery folders as recommendations on the home screen. Each folder is individually toggleable and the item count is configurable via a dropdown (10 / 20 / 30 / 50).

⚠️ Frontend companion PR: music-assistant/frontend#1774 (adds en.json translation keys for the folder names)

💬 Related discussion: https://github.com/orgs/music-assistant/discussions/5450


Motivation

The default recommendation folders in _get_default_recommendations (Recently Favorited, Recently Added, Random Artists/Albums, …) are hardcoded in music.py and cannot be configured or toggled individually by the user. This plugin adds library-based equivalents with full user control, and includes additional folders not available in the defaults (Forgotten Tracks/Albums/Artists, Most Played, Never/Rarely Played).


Folders

Folder Default Description
Forgotten Tracks ✅ on Library tracks least recently played
Forgotten Albums ✅ on Library albums least recently played
Forgotten Artists ✅ on Library artists least recently played
Most Played Tracks ✅ on Library tracks with highest play count
Never / Rarely Played ✅ on Library tracks with lowest play count
Recently Favorited Tracks ❌ off Duplicate of builtin — enable when builtin is removed
Recently Favorited Albums ❌ off Duplicate of builtin — enable when builtin is removed
Recently Added Tracks ❌ off Duplicate of builtin — enable when builtin is removed
Random Artists ❌ off Duplicate of builtin — enable when builtin is removed
Random Albums ❌ off Duplicate of builtin — enable when builtin is removed

Each folder has a companion config entry that lets the user choose how many items to show (10 / 20 / 30 / 50). The limit entry is automatically hidden when the folder is disabled (depends_on).

Translation keys follow the recommendation.<key> pattern so they can be cleanly namespaced in en.json.


Screenshots

Forgotten Tracks

forgotten tracks

Forgotten Albums

forgotten albums

Forgotten Artists

forgotten artists

Most Played Tracks

most played tracks

Never / Rarely Played

never rarely played tracks

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 14, 2026

🔒 Dependency Security Report

✅ No dependency changes detected in this PR.

@dmoo500 dmoo500 marked this pull request as ready for review May 14, 2026 11:06
Copilot AI review requested due to automatic review settings May 14, 2026 11:06
Copy link
Copy Markdown
Contributor

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

Note

Copilot was unable to run its full agentic suite in this review.

Adds a new "Recommendations" plugin provider that surfaces additional library-based recommendation folders (e.g., Forgotten Tracks/Albums/Artists, Most Played, Never Played, plus opt-in duplicates of built-in rows) on the home screen, each individually toggleable with a configurable item count.

Changes:

  • New plugin provider recommendations with manifest, icon, and implementation.
  • Per-folder enable/limit ConfigEntry definitions and an async recommendations() method that gathers folders concurrently.
  • Folders use library_items with various order_by modes (e.g., last_played, play_count_desc, random_play_count).

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 5 comments.

File Description
music_assistant/providers/recommendations/manifest.json Declares the new beta plugin provider metadata.
music_assistant/providers/recommendations/icon.svg Adds the provider icon (bookshelf + plus).
music_assistant/providers/recommendations/init.py Implements RecommendationsProvider, config entries, and folder builders.

Comment thread music_assistant/providers/recommendations/__init__.py Outdated
Comment thread music_assistant/providers/recommendations/__init__.py Outdated
Comment thread music_assistant/providers/recommendations/__init__.py Outdated
Comment thread music_assistant/providers/recommendations/__init__.py Outdated
Comment thread music_assistant/providers/recommendations/__init__.py Outdated
Copilot AI review requested due to automatic review settings May 14, 2026 11:39
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 2 out of 3 changed files in this pull request and generated 3 comments.

Comment thread music_assistant/providers/recommendations/__init__.py
Comment thread music_assistant/providers/recommendations/__init__.py Outdated
Comment thread music_assistant/providers/recommendations/__init__.py Outdated
Copilot AI review requested due to automatic review settings May 14, 2026 19:03
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 2 out of 3 changed files in this pull request and generated 4 comments.

Comment thread music_assistant/providers/recommendations/__init__.py
Comment thread music_assistant/providers/recommendations/__init__.py Outdated
Comment thread music_assistant/providers/recommendations/__init__.py Outdated
Comment thread music_assistant/providers/recommendations/__init__.py
Copilot AI review requested due to automatic review settings May 14, 2026 20:49
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 2 out of 3 changed files in this pull request and generated 4 comments.

Comment thread music_assistant/providers/recommendations/__init__.py
Comment thread music_assistant/providers/recommendations/__init__.py
Comment thread music_assistant/providers/recommendations/__init__.py
Comment thread music_assistant/providers/recommendations/__init__.py Outdated
Copilot AI review requested due to automatic review settings May 14, 2026 21:15
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 2 out of 3 changed files in this pull request and generated 4 comments.

Comment thread music_assistant/providers/recommendations/__init__.py
Comment thread music_assistant/providers/recommendations/__init__.py Outdated
Comment thread music_assistant/providers/recommendations/__init__.py Outdated
Comment thread music_assistant/providers/recommendations/__init__.py
Copilot AI review requested due to automatic review settings May 14, 2026 21:39
Copy link
Copy Markdown
Contributor

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

Copilot reviewed 2 out of 3 changed files in this pull request and generated 5 comments.

Comment thread music_assistant/providers/recommendations/__init__.py
Comment thread music_assistant/providers/recommendations/__init__.py
Comment thread music_assistant/providers/recommendations/__init__.py
Comment thread music_assistant/providers/recommendations/__init__.py
Comment thread music_assistant/providers/recommendations/__init__.py
@OzGav
Copy link
Copy Markdown
Contributor

OzGav commented May 17, 2026

I am not sure if we want "the item count is configurable via a dropdown (10 / 20 / 30 / 50)." as that appears to be in response to a comment by one user and Marcel has been talking recently about the need to improve usability for new uers and increasing config options runs counter to that.

Also if you are going to have all the duplicates of the builtin rows then I think you either need to remove them from builtin in this PR or in another one?

Comment on lines +14 to +22
The following folders duplicate the built-in default recommendations and are
disabled by default. Enable them here and disable the built-in rows via the
frontend edit mode to use your custom limits instead.

- Recently Favorited Tracks
- Recently Favorited Albums
- Recently Added Tracks
- Random Artists
- Random Albums
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This doesnt belong here

Comment on lines +233 to +241
def _get_media_controller(self, media: str) -> MediaControllerBase[Any]:
"""Return the music controller for a supported media type."""
if media == "tracks":
return self.mass.music.tracks
if media == "albums":
return self.mass.music.albums
if media == "artists":
return self.mass.music.artists
raise ValueError(f"Unsupported media type for recommendations provider: {media}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think you can just remove this and replace with

_CONTROLLERS = {
    "tracks": lambda self: self.mass.music.tracks,
    "albums": lambda self: self.mass.music.albums,
    "artists": lambda self: self.mass.music.artists,
}

Comment on lines +227 to +231
def _get_bool(self, key: str) -> bool:
return cast("bool", self.config.get_value(key))

def _get_limit(self, key: str) -> int:
return cast("int", self.config.get_value(key))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why have single line helpers which are only used in one place in the code? These should just be inlined.

# Fetch DESC so never-played (NULL last_played) items sort last;
# avoids filtering out the entire batch in libraries with many
# never-played tracks. Reverse afterwards to restore ASC order.
raw = await controller.library_items(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This needs a proper fix. I think the right solution is to add a played_only parameter to library_items in the base controller, which would add last_played IS NOT NULL to the query when set. That keeps the provider code clean. Can you raise this as a separate PR to base.py which will be a prerequisite for this one?

@OzGav
Copy link
Copy Markdown
Contributor

OzGav commented May 18, 2026

Marking as draft just so we can keep track of those that need attention.

@OzGav OzGav marked this pull request as draft May 18, 2026 00:10
@OzGav OzGav added this to the 2.10.0 milestone May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants