Skip to content

Di fm favorites#3458

Draft
benklop wants to merge 9 commits intomusic-assistant:devfrom
benklop:di-fm-favorites
Draft

Di fm favorites#3458
benklop wants to merge 9 commits intomusic-assistant:devfrom
benklop:di-fm-favorites

Conversation

@benklop
Copy link
Copy Markdown
Contributor

@benklop benklop commented Mar 23, 2026

This pull request enhances the Digitally Incorporated provider by adding support for user favorites, allowing users to view (read-only) their favorite radio stations from each network via the favorites.pls playlist. The implementation includes robust parsing and mapping of playlist entries to API channel keys, introduces caching for efficiency, and improves error handling and logging. Additionally, the API request method is generalized to support multiple HTTP methods and request bodies.

Favorites support and playlist parsing:

  • Added support for loading user favorites by reading each network's favorites.pls file (read-only), with detailed parsing logic to extract and map stream URLs to channel keys, including handling of codec suffixes and mount prefixes. [1] [2]
  • Updated the get_library_radios method to yield only the user's favorite radio stations, using the parsed favorite channel keys and improved error logging. [1] [2]

Caching and configuration improvements:

  • Introduced a 5-minute cache for favorites to reduce network load and improve performance.
  • Clarified the listen key configuration description to note its use for both playback and loading favorites, and that favorites are read-only.

API and internal method enhancements:

  • Generalized the _api_request method to support different HTTP methods and optional JSON bodies, improving flexibility for future API interactions. [1] [2]
  • Updated internal stream URL retrieval to use the new API request signature and pass the listen key as a parameter.

Copilot AI and others added 4 commits March 22, 2026 14:56
- Add LIBRARY_RADIOS_EDIT to SUPPORTED_FEATURES
- Add CACHE_FAVORITES constant (5 min TTL)
- Refactor _api_request to support POST/DELETE methods and JSON bodies
- Add _get_user_favorites() to fetch favorites from members/me/favorites
- Add _get_channel_id() and _invalidate_favorites_cache() helpers
- Update get_library_radios() to yield only user-favorited stations
- Add library_add() to POST a station to user favorites
- Add library_remove() to DELETE a station from user favorites

Co-authored-by: benklop <2729824+benklop@users.noreply.github.com>
Agent-Logs-Url: https://github.com/benklop/music-assistant-server/sessions/6025c039-23ca-4ac7-ada7-3d9426e814ee
Copilot AI review requested due to automatic review settings March 23, 2026 06:35
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

This PR enhances the Digitally Incorporated provider to expose a read-only “Favorites” radio library by fetching and parsing each network’s favorites.pls, mapping entries to channel keys, and returning only those favorites from get_library_radios.

Changes:

  • Add favorites fetching/parsing logic (PLS download + URL-to-channel-key mapping) with a short-lived cache.
  • Update get_library_radios to yield only favorited stations per enabled network.
  • Generalize _api_request to support arbitrary HTTP methods, optional JSON bodies, and 204 responses.

Comment thread music_assistant/providers/digitally_incorporated/__init__.py
Copilot AI review requested due to automatic review settings March 23, 2026 07:00
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 1 out of 1 changed files in this pull request and generated 2 comments.

Comment thread music_assistant/providers/digitally_incorporated/__init__.py Outdated
Comment thread music_assistant/providers/digitally_incorporated/__init__.py
@MarvinSchenkel MarvinSchenkel added this to the 2.9.0 milestone Mar 23, 2026
@OzGav
Copy link
Copy Markdown
Contributor

OzGav commented Mar 23, 2026

This looks good Ben. It is now correctly using get_library_radios, If you can just resolve the two copilot comments which seem fair (although the second one is pretty minor) we can move this forward. Thanks for the quick turnaround!

apply feedback

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 23, 2026 15:27
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 1 out of 1 changed files in this pull request and generated 1 comment.

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

OzGav commented Mar 28, 2026

@benklop could you address that final copilot comment?

benklop added 2 commits March 31, 2026 00:56
…erived slugs. Introduced a new dictionary for lowercased channel keys to improve lookup efficiency.
Copilot AI review requested due to automatic review settings March 31, 2026 04:56
@benklop
Copy link
Copy Markdown
Contributor Author

benklop commented Mar 31, 2026

@benklop could you address that final copilot comment?

done. sorry for that. I guess i didn't see that one.

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 1 out of 1 changed files in this pull request and generated 1 comment.

Comment on lines +631 to +632
# Build a lowercase-keyed view for case-insensitive matching.
lower_channels_by_key = {key.lower(): value for key, value in channels_by_key.items()}
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

lower_channels_by_key is built on every _channel_data_for_pls_key call but never used, which adds an avoidable O(n) dict construction per favorite lookup.
This can noticeably slow down library loading when a user has many favorites.
Remove this local dict and rely on the already-precomputed channels_lower_by_key passed in (or use the local one instead and stop passing the extra argument).

Suggested change
# Build a lowercase-keyed view for case-insensitive matching.
lower_channels_by_key = {key.lower(): value for key, value in channels_by_key.items()}

Copilot uses AI. Check for mistakes.
@OzGav
Copy link
Copy Markdown
Contributor

OzGav commented Mar 31, 2026

Sorry new copilot comment is valid and is the same as the mypy failure.

return channels_lower_by_key[trimmed_lower]
return None

def _parse_favorites_pls_channel_keys(self, pls_body: str, network_key: str) -> list[str]:
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.

We have a ready to use helper available for pls parsing at music_assistant.helpers.playlists (parse_pls). You could use it like:

def _parse_favorites_pls_channel_keys(self, pls_body: str, network_key: str) -> list[str]:
    try:
        items = parse_pls(pls_body)
    except InvalidDataError:
        return []
    ordered = []
    seen_keys = set()
    for item in items:
        channel_key = self._stream_url_to_channel_key(item.path, network_key)
        if channel_key and channel_key not in seen_keys:
            seen_keys.add(channel_key)
            ordered.append(channel_key)
    return ordered

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.

So 'pls' use that one ;-)

@MarvinSchenkel
Copy link
Copy Markdown
Contributor

Marking this PR as draft so we can keep track of which PRs needs our attention. Please mark as 'Ready for review' when you want us to have another look 🙏 .

@MarvinSchenkel MarvinSchenkel marked this pull request as draft March 31, 2026 11:05
@OzGav
Copy link
Copy Markdown
Contributor

OzGav commented Apr 19, 2026

@benklop This is close to done and we are keen to help get it across the line.

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.

5 participants