|
4 | 4 |
|
5 | 5 | from typing import TYPE_CHECKING |
6 | 6 |
|
7 | | -from music_assistant_models.enums import EventType |
| 7 | +from music_assistant_models.enums import EventType, MediaType |
| 8 | +from music_assistant_models.errors import PlayerCommandFailed, PlayerUnavailableError |
| 9 | +from music_assistant_models.helpers import create_sort_name |
| 10 | +from music_assistant_models.media_items import Track |
8 | 11 | from music_assistant_models.player import Player |
9 | 12 |
|
10 | 13 | if TYPE_CHECKING: |
@@ -192,6 +195,55 @@ async def player_command_group_volume_down(self, player_id: str) -> None: |
192 | 195 | """Send VOLUME_DOWN command to given playergroup.""" |
193 | 196 | await self.client.send_command("players/cmd/group_volume_down", player_id=player_id) |
194 | 197 |
|
| 198 | + async def add_currently_playing_to_favorites(self, player_id: str) -> None: |
| 199 | + """ |
| 200 | + Add the currently playing item/track on given player to the favorites. |
| 201 | +
|
| 202 | + This tries to resolve the currently playing media to an actual media item |
| 203 | + and add that to the favorites in the library. |
| 204 | +
|
| 205 | + Will raise an error if the player is not currently playing anything |
| 206 | + or if the currently playing media can not be resolved to a media item. |
| 207 | + """ |
| 208 | + if not (player := self._players.get(player_id)): |
| 209 | + raise PlayerUnavailableError(f"Player {player_id} not found") |
| 210 | + if not player.active_source: |
| 211 | + raise PlayerCommandFailed("Player has no active source") |
| 212 | + if mass_queue := self.client.player_queues.get(player.active_source): |
| 213 | + if not (current_item := mass_queue.current_item) or not current_item.media_item: |
| 214 | + raise PlayerCommandFailed("No current item to add to favorites") |
| 215 | + # if we're playing a radio station, try to resolve the currently playing track |
| 216 | + if ( |
| 217 | + current_item.media_item.media_type == MediaType.RADIO |
| 218 | + and (streamdetails := mass_queue.current_item.streamdetails) |
| 219 | + and (stream_title := streamdetails.stream_title) |
| 220 | + and " - " in stream_title |
| 221 | + ): |
| 222 | + search_result = await self.client.music.search( |
| 223 | + search_query=stream_title, |
| 224 | + media_types=[MediaType.TRACK], |
| 225 | + ) |
| 226 | + for search_track in search_result.tracks: |
| 227 | + if not isinstance(search_track, Track): |
| 228 | + continue |
| 229 | + # check if the artist and title match |
| 230 | + # for now we only allow a strict match on the artist and title |
| 231 | + artist, title = stream_title.split(" - ", 1) |
| 232 | + if create_sort_name(artist) != create_sort_name(search_track.artist_str): |
| 233 | + continue |
| 234 | + if create_sort_name(title) != create_sort_name(search_track.name): |
| 235 | + continue |
| 236 | + # we found a match, add it to the favorites |
| 237 | + await self.client.music.add_item_to_favorites(search_track) |
| 238 | + return |
| 239 | + # any other media item, just add it to the favorites |
| 240 | + await self.client.music.add_item_to_favorites(current_item.media_item) |
| 241 | + return |
| 242 | + # handle other source active using the current_media |
| 243 | + if not (current_media := player.current_media) or not current_media.uri: |
| 244 | + raise PlayerCommandFailed("No current item to add to favorites") |
| 245 | + await self.client.music.add_item_to_favorites(current_media.uri) |
| 246 | + |
195 | 247 | # Other endpoints/commands |
196 | 248 |
|
197 | 249 | async def _get_players(self) -> list[Player]: |
|
0 commit comments