adjustments for hass integration
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Thu, 17 Sep 2020 00:02:16 +0000 (02:02 +0200)
committerMarcel van der Veldt <m.vanderveldt@outlook.com>
Thu, 17 Sep 2020 00:02:16 +0000 (02:02 +0200)
music_assistant/constants.py
music_assistant/http_streamer.py
music_assistant/models/player.py
music_assistant/models/player_queue.py
music_assistant/music_manager.py
music_assistant/player_manager.py
music_assistant/providers/chromecast/player.py
music_assistant/providers/demo/demo_playerprovider.py
music_assistant/providers/home_assistant/__init__.py
music_assistant/providers/qobuz/__init__.py

index 00f9fbdda8e89d93fea7929078e8a3c4fae53c47..67a7294699fa413e22333cb6a7481f65c427c445 100755 (executable)
@@ -1,6 +1,6 @@
 """All constants for Music Assistant."""
 
-__version__ = "0.0.30"
+__version__ = "0.0.31"
 REQUIRED_PYTHON_VER = "3.7"
 
 CONF_USERNAME = "username"
@@ -25,11 +25,10 @@ EVENT_PLAYER_CHANGED = "player changed"
 EVENT_STREAM_STARTED = "streaming started"
 EVENT_STREAM_ENDED = "streaming ended"
 EVENT_CONFIG_CHANGED = "config changed"
-EVENT_PLAYBACK_STARTED = "playback started"
-EVENT_PLAYBACK_STOPPED = "playback stopped"
 EVENT_MUSIC_SYNC_STATUS = "music sync status"
 EVENT_QUEUE_UPDATED = "queue updated"
 EVENT_QUEUE_ITEMS_UPDATED = "queue items updated"
+EVENT_QUEUE_TIME_UPDATED = "queue time updated"
 EVENT_SHUTDOWN = "application shutdown"
 EVENT_PROVIDER_REGISTERED = "provider registered"
 EVENT_PLAYER_CONTROL_REGISTERED = "player control registered"
index fe8d2d940adfb1fb9b361bf63b3c115b2ade8de3..e972fbb62ace21637d5f9de4d856d80b059efc7c 100755 (executable)
@@ -441,6 +441,7 @@ class HTTPStreamer:
             yield (True, b"")
             return
         # fire event that streaming has started for this track
+        streamdetails.path = ""  # invalidate
         self.mass.signal_event(EVENT_STREAM_STARTED, streamdetails)
         # yield chunks from stdout
         # we keep 1 chunk behind to detect end of stream properly
@@ -462,10 +463,12 @@ class HTTPStreamer:
                 yield (False, prev_chunk)
             prev_chunk = chunk
         # fire event that streaming has ended
-        self.mass.signal_event(EVENT_STREAM_ENDED, streamdetails)
-        # send task to background to analyse the audio
-        if queue_item.media_type == MediaType.Track:
-            self.mass.loop.run_in_executor(None, self.__analyze_audio, streamdetails)
+        if not cancelled.is_set():
+            streamdetails.seconds_played = queue_item.duration
+            self.mass.signal_event(EVENT_STREAM_ENDED, streamdetails)
+            # send task to background to analyse the audio
+            if queue_item.media_type == MediaType.Track:
+                self.mass.add_job(self.__analyze_audio, streamdetails)
 
     def __get_player_sox_options(
         self, player_id: str, streamdetails: StreamDetails
index 15999a3f488b36071bf77ab6f6c8b91d801f796e..63aa45fab4bd0ce8d1b8e3fc8989e8329c6d773f 100755 (executable)
@@ -13,7 +13,6 @@ from music_assistant.utils import CustomIntEnum
 class PlayerState(Enum):
     """Enum for the playstate of a player."""
 
-    Off = "off"
     Stopped = "stopped"
     Paused = "paused"
     Playing = "playing"
@@ -45,7 +44,7 @@ class Player(DataClassDictMixin):
     name: str = ""
     powered: bool = False
     elapsed_time: int = 0
-    state: PlayerState = PlayerState.Off
+    state: PlayerState = PlayerState.Stopped
     available: bool = True
     current_uri: str = ""
     volume_level: int = 0
index 73bb5532e919cae4f3234dbb382833df5e586ddb..5bfbb2e38ef98aeee9fdbb043115c8221e1f659d 100755 (executable)
@@ -8,9 +8,8 @@ from enum import Enum
 from typing import List
 
 from music_assistant.constants import (
-    EVENT_PLAYBACK_STARTED,
-    EVENT_PLAYBACK_STOPPED,
     EVENT_QUEUE_ITEMS_UPDATED,
+    EVENT_QUEUE_TIME_UPDATED,
     EVENT_QUEUE_UPDATED,
 )
 from music_assistant.models.media_types import Track
@@ -67,7 +66,6 @@ class PlayerQueue:
         self._last_item_time = 0
         self._last_queue_startindex = 0
         self._next_queue_startindex = 0
-        self._last_player_state = PlayerState.Stopped
         self._last_track = None
         # load previous queue settings from disk
         self.mass.add_job(self.__async_restore_saved_state())
@@ -237,6 +235,7 @@ class PlayerQueue:
             return
         if self.use_queue_stream:
             return await self.async_play_index(self.cur_index + 1)
+        await self.mass.player_manager.async_cmd_power_on(self.player_id)
         return await self.mass.player_manager.get_player_provider(
             self.player_id
         ).async_cmd_next(self.player_id)
@@ -245,6 +244,7 @@ class PlayerQueue:
         """Play the previous track in the queue."""
         if self.cur_index is None:
             return
+        await self.mass.player_manager.async_cmd_power_on(self.player_id)
         if self.use_queue_stream:
             return await self.async_play_index(self.cur_index - 1)
         return await self.mass.player_manager.async_cmd_previous(self.player_id)
@@ -252,6 +252,7 @@ class PlayerQueue:
     async def async_resume(self):
         """Resume previous queue."""
         if self.items:
+            await self.mass.player_manager.async_cmd_power_on(self.player_id)
             prev_index = self.cur_index
             supports_queue = PlayerFeature.QUEUE in self.player.features
             if self.use_queue_stream or not supports_queue:
@@ -271,6 +272,7 @@ class PlayerQueue:
 
     async def async_play_index(self, index):
         """Play item at index X in queue."""
+        await self.mass.player_manager.async_cmd_power_on(self.player_id)
         player_prov = self.mass.player_manager.get_player_provider(self.player_id)
         supports_queue = PlayerFeature.QUEUE in self.player.features
         if not isinstance(index, int):
@@ -329,6 +331,7 @@ class PlayerQueue:
 
     async def async_load(self, queue_items: List[QueueItem]):
         """Load (overwrite) queue with new items."""
+        await self.mass.player_manager.async_cmd_power_on(self.player_id)
         supports_queue = PlayerFeature.QUEUE in self.player.features
         for index, item in enumerate(queue_items):
             item.sort_index = index
@@ -470,7 +473,6 @@ class PlayerQueue:
                     break
         # process new index
         await self.async_process_queue_update(cur_index, track_time)
-        self.mass.signal_event(EVENT_QUEUE_UPDATED, self.to_dict())
 
     async def async_start_queue_stream(self):
         """Call when queue_streamer starts playing the queue stream."""
@@ -521,34 +523,21 @@ class PlayerQueue:
     async def async_process_queue_update(self, new_index, track_time):
         """Compare the queue index to determine if playback changed."""
         new_track = self.get_item(new_index)
-        if (not self._last_track and new_track) or self._last_track != new_track:
+        self._cur_item_time = track_time
+        self._cur_index = new_index
+        if self._last_track != new_track:
             # queue track updated
-            # account for track changing state so trigger track change after 1 second
-            if self._last_track and self._last_track.streamdetails:
-                self._last_track.streamdetails.seconds_played = self._last_item_time
-                self.mass.signal_event(
-                    EVENT_PLAYBACK_STOPPED, self._last_track.streamdetails
-                )
-            if new_track and new_track.streamdetails:
-                self.mass.signal_event(EVENT_PLAYBACK_STARTED, new_track.streamdetails)
-                self._last_track = new_track
-        if self._last_player_state != self.player.state:
-            self._last_player_state = self.player.state
-            if self.player.elapsed_time == 0 and self.player.state in [
-                PlayerState.Stopped,
-                PlayerState.Off,
-            ]:
-                # player stopped playing
-                if self._last_track:
-                    self.mass.signal_event(
-                        EVENT_PLAYBACK_STOPPED, self._last_track.streamdetails
-                    )
+            self._last_track = new_track
+            self.mass.signal_event(EVENT_QUEUE_UPDATED, self.to_dict())
+            if self._last_track:
+                self._last_track.streamdetails = None  # invalidate streamdetails
         # update vars
-        if track_time > 2:
-            # account for track changing state so keep this a few seconds behind
+        if self._last_item_time != track_time:
             self._last_item_time = track_time
-        self._cur_item_time = track_time
-        self._cur_index = new_index
+            self.mass.signal_event(
+                EVENT_QUEUE_TIME_UPDATED,
+                {"player_id": self.player_id, "cur_item_time": track_time},
+            )
 
     @staticmethod
     def __shuffle_items(queue_items):
index 2d487e478d1a4b9b0a9c6758373fb2e97e977337..ab45025578d4bb2582938029d87d04a625ed3d5d 100755 (executable)
@@ -24,7 +24,7 @@ from music_assistant.models.media_types import (
 )
 from music_assistant.models.musicprovider import MusicProvider
 from music_assistant.models.provider import ProviderType
-from music_assistant.models.streamdetails import StreamDetails
+from music_assistant.models.streamdetails import ContentType, StreamDetails, StreamType
 from music_assistant.utils import compare_strings, run_periodic
 from PIL import Image
 
@@ -1077,29 +1077,38 @@ class MusicManager:
             param media_item: The MediaItem (track/radio) for which to request the streamdetails for.
             param player_id: Optionally provide the player_id which will play this stream.
         """
-        if media_item.streamdetails:
-            media_item.streamdetails.player_id = player_id
-            return media_item.streamdetails  # already present, no need to fetch again!
-        # always request the full db track as there might be other qualities available
-        # except for radio
-        if media_item.media_type == MediaType.Radio:
-            full_track = media_item
-        else:
-            full_track = await self.async_get_track(
-                media_item.item_id, media_item.provider, lazy=True, refresh=True
+        if media_item.provider == "uri":
+            # special type: a plain uri was added to the queue
+            streamdetails = StreamDetails(
+                type=StreamType.URL,
+                provider="uri",
+                item_id=media_item.item_id,
+                path=media_item.item_id,
+                content_type=ContentType(media_item.item_id.split(".")[-1]),
+                sample_rate=44100,
+                bit_depth=16,
             )
-        # sort by quality and check track availability
-        for prov_media in sorted(
-            full_track.provider_ids, key=lambda x: x.quality, reverse=True
-        ):
-            # get streamdetails from provider
-            music_prov = self.mass.get_provider(prov_media.provider)
-            if not music_prov:
-                continue  # provider temporary unavailable ?
+        else:
+            # always request the full db track as there might be other qualities available
+            # except for radio
+            if media_item.media_type == MediaType.Radio:
+                full_track = media_item
+            else:
+                full_track = await self.async_get_track(
+                    media_item.item_id, media_item.provider, lazy=True, refresh=True
+                )
+            # sort by quality and check track availability
+            for prov_media in sorted(
+                full_track.provider_ids, key=lambda x: x.quality, reverse=True
+            ):
+                # get streamdetails from provider
+                music_prov = self.mass.get_provider(prov_media.provider)
+                if not music_prov:
+                    continue  # provider temporary unavailable ?
 
-            streamdetails = await music_prov.async_get_stream_details(
-                prov_media.item_id
-            )
+                streamdetails = await music_prov.async_get_stream_details(
+                    prov_media.item_id
+                )
 
             if streamdetails:
                 streamdetails.player_id = player_id
index 62459f4f41fb6c78e11795429c353e0c68664e69..938e41f5a9732964404d68e31c654bdb779a630c 100755 (executable)
@@ -24,7 +24,6 @@ from music_assistant.models.player import (
 from music_assistant.models.player_queue import PlayerQueue, QueueItem, QueueOption
 from music_assistant.models.playerprovider import PlayerProvider
 from music_assistant.models.provider import ProviderType
-from music_assistant.models.streamdetails import ContentType, StreamDetails, StreamType
 from music_assistant.utils import (
     async_iter_items,
     callback,
@@ -272,18 +271,15 @@ class PlayerManager:
         queue_item = QueueItem(
             Track(
                 item_id=uri,
-                provider="",
-                name="uri",
+                provider="uri",
+                name=uri,
             )
         )
-        queue_item.streamdetails = StreamDetails(
-            type=StreamType.URL,
-            provider="",
-            item_id=uri,
-            path=uri,
-            content_type=ContentType(uri.split(".")[-1]),
-            sample_rate=44100,
-            bit_depth=16,
+        # generate uri for this queue item
+        queue_item.uri = "%s/stream/%s/%s" % (
+            self.mass.web.internal_url,
+            player_id,
+            queue_item.queue_item_id,
         )
         # turn on player
         await self.async_cmd_power_on(player_id)
@@ -388,6 +384,22 @@ class PlayerManager:
             for child_player_id in player.group_childs:
                 if self._players.get(child_player_id):
                     await self.async_cmd_power_off(child_player_id)
+        else:
+            # if this was the last powered player in the group, turn off group
+            for parent_player_id in player.group_parents:
+                parent_player = self._players.get(parent_player_id)
+                if not parent_player:
+                    continue
+                has_powered_players = False
+                for child_player_id in parent_player.group_childs:
+                    if child_player_id == player_id:
+                        continue
+                    child_player = self._players.get(child_player_id)
+                    if child_player and child_player.powered:
+                        has_powered_players = True
+                        break
+                if not has_powered_players:
+                    await self.async_cmd_power_off(parent_player_id)
 
     async def async_cmd_power_toggle(self, player_id: str):
         """
@@ -591,8 +603,6 @@ class PlayerManager:
     @callback
     def __get_player_state(self, player: Player, active_parent: str):
         """Get final/calculated player's state."""
-        if not player.available or not player.powered:
-            return PlayerState.Off
         if active_parent != player.player_id:
             # use group state
             return self._players[active_parent].state
index 81facca8da2ca75399819c817c54c347a21632d6..9cce49c161d05af42005a6c8016954a7fddceba0 100644 (file)
@@ -76,8 +76,6 @@ class ChromecastPlayer:
     @property
     def state(self) -> PlayerState:
         """Return the state of the player."""
-        if not self._powered:
-            return PlayerState.Off
         if self.media_status is None:
             return PlayerState.Stopped
         if self.media_status.player_is_playing:
index 01a740e234f95e36a5d5c5d479ef2d7f5bef24b5..082de6e04bf4409d3ac4099287c501a93656830e 100644 (file)
@@ -104,12 +104,17 @@ class DemoPlayerProvider(PlayerProvider):
         player.current_uri = uri
         player.sox = subprocess.Popen(["play", uri])
         player.state = PlayerState.Playing
+        player.powered = True
         self.mass.add_job(self.mass.player_manager.async_update_player(player))
 
         async def report_progress():
             """Report fake progress while sox is playing."""
             player.elapsed_time = 0
-            while player.sox and not player.sox.poll():
+            while (
+                player.state == PlayerState.Playing
+                and player.sox
+                and not player.sox.poll()
+            ):
                 await asyncio.sleep(1)
                 player.elapsed_time += 1
                 self.mass.add_job(self.mass.player_manager.async_update_player(player))
index d43dff50bafcc511afa59b5b5c5fd04a9e7389d0..db96378cc42431f4591de28ec85e3e8199842c9e 100644 (file)
@@ -3,24 +3,17 @@
 import logging
 from typing import List
 
-import slugify as slug
 from hass_client import (
     EVENT_CONNECTED,
     EVENT_STATE_CHANGED,
     IS_SUPERVISOR,
     HomeAssistant,
 )
-from music_assistant.constants import (
-    CONF_URL,
-    EVENT_PLAYER_ADDED,
-    EVENT_PLAYER_CHANGED,
-    EVENT_PLAYER_REMOVED,
-)
+from music_assistant.constants import CONF_URL
 from music_assistant.models.config_entry import ConfigEntry, ConfigEntryType
-from music_assistant.models.media_types import MediaType
-from music_assistant.models.player import Player, PlayerControl, PlayerControlType
+from music_assistant.models.player import PlayerControl, PlayerControlType
 from music_assistant.models.provider import Provider
-from music_assistant.utils import callback, run_periodic, try_parse_float
+from music_assistant.utils import callback, try_parse_float
 
 PROV_ID = "homeassistant"
 PROV_NAME = "Home Assistant integration"
@@ -40,14 +33,6 @@ CONFIG_ENTRY_TOKEN = ConfigEntry(
     entry_type=ConfigEntryType.PASSWORD,
     description_key="hass_token",
 )
-CONFIG_ENTRY_PUBLISH_PLAYERS = ConfigEntry(
-    entry_key=CONF_PUBLISH_PLAYERS,
-    entry_type=ConfigEntryType.BOOL,
-    description_key=CONF_PUBLISH_PLAYERS,
-    default_value=True,
-)
-
-# TODO: handle player removals and renames in publishing to hass
 
 
 async def async_setup(mass):
@@ -59,7 +44,6 @@ async def async_setup(mass):
 class HomeAssistantPlugin(Provider):
     """Homeassistant plugin.
 
-    allows publishing of our players to hass
     allows using hass entities (like switches, media_players or gui inputs) to be triggered
     """
 
@@ -69,7 +53,6 @@ class HomeAssistantPlugin(Provider):
         self._tasks = []
         self._tracked_entities = []
         self._sources = []
-        self._published_players = {}
         super().__init__(*args, **kwargs)
 
     @property
@@ -90,7 +73,6 @@ class HomeAssistantPlugin(Provider):
             entries.append(CONFIG_ENTRY_URL)
             entries.append(CONFIG_ENTRY_TOKEN)
         entries += [
-            CONFIG_ENTRY_PUBLISH_PLAYERS,
             ConfigEntry(
                 entry_key=CONF_POWER_ENTITIES,
                 entry_type=ConfigEntryType.STRING,
@@ -121,12 +103,7 @@ class HomeAssistantPlugin(Provider):
             )
         # register callbacks
         self._hass.register_event_callback(self.__async_hass_event)
-        self.mass.add_event_listener(
-            self.__async_mass_event,
-            [EVENT_PLAYER_CHANGED, EVENT_PLAYER_ADDED, EVENT_PLAYER_REMOVED],
-        )
         await self._hass.async_connect()
-        self._tasks.append(self.mass.add_job(self.__async_get_sources()))
         return True
 
     async def async_on_stop(self):
@@ -136,167 +113,16 @@ class HomeAssistantPlugin(Provider):
         if self._hass:
             await self._hass.async_close()
 
-    async def __async_mass_event(self, event, event_data):
-        """Receive event from Music Assistant."""
-        if event in [EVENT_PLAYER_CHANGED, EVENT_PLAYER_ADDED]:
-            await self.__async_publish_player(event_data)
-        # TODO: player removals
-
     async def __async_hass_event(self, event_type, event_data):
         """Receive event from Home Assistant."""
         if event_type == EVENT_STATE_CHANGED:
             if event_data["entity_id"] in self._tracked_entities:
                 new_state = event_data["new_state"]
                 await self.__async_update_player_controls(new_state)
-        elif event_type == "call_service" and event_data["domain"] == "media_player":
-            await self.__async_handle_player_command(
-                event_data["service"], event_data["service_data"]
-            )
         elif event_type == EVENT_CONNECTED:
             # register player controls on connect
             self.mass.add_job(self.__async_register_player_controls())
 
-    async def __async_handle_player_command(self, service, service_data):
-        """Handle forwarded service call for one of our players."""
-        if isinstance(service_data["entity_id"], list):
-            # can be a list of entity ids if action fired on multiple items
-            entity_ids = service_data["entity_id"]
-        else:
-            entity_ids = [service_data["entity_id"]]
-        for entity_id in entity_ids:
-            if entity_id in self._published_players:
-                # call is for one of our players so handle it
-                player_id = self._published_players[entity_id]
-                if not self.mass.player_manager.get_player(player_id):
-                    return
-                if service == "turn_on":
-                    await self.mass.player_manager.async_cmd_power_on(player_id)
-                elif service == "turn_off":
-                    await self.mass.player_manager.async_cmd_power_off(player_id)
-                elif service == "toggle":
-                    await self.mass.player_manager.async_cmd_power_toggle(player_id)
-                elif service == "volume_mute":
-                    await self.mass.player_manager.async_cmd_volume_mute(
-                        player_id, service_data["is_volume_muted"]
-                    )
-                elif service == "volume_up":
-                    await self.mass.player_manager.async_cmd_volume_up(player_id)
-                elif service == "volume_down":
-                    await self.mass.player_manager.async_cmd_volume_down(player_id)
-                elif service == "volume_set":
-                    volume_level = service_data["volume_level"] * 100
-                    await self.mass.player_manager.async_cmd_volume_set(
-                        player_id, volume_level
-                    )
-                elif service == "media_play":
-                    await self.mass.player_manager.async_cmd_play(player_id)
-                elif service == "media_pause":
-                    await self.mass.player_manager.async_cmd_pause(player_id)
-                elif service == "media_stop":
-                    await self.mass.player_manager.async_cmd_stop(player_id)
-                elif service == "media_next_track":
-                    await self.mass.player_manager.async_cmd_next(player_id)
-                elif service == "media_play_pause":
-                    await self.mass.player_manager.async_cmd_play_pause(player_id)
-                elif service in ["play_media", "select_source"]:
-                    return await self.__async_handle_play_media(player_id, service_data)
-                else:
-                    LOGGER.error(
-                        "%s service is unhandled. Service data: %s",
-                        service,
-                        service_data,
-                    )
-
-    async def __async_handle_play_media(self, player_id, service_data):
-        """Handle play media request from homeassistant."""
-        media_content_id = service_data.get("media_content_id")
-        if not media_content_id:
-            media_content_id = service_data.get("source")
-        queue_opt = "add" if service_data.get("enqueue") else "play"
-        if "://" not in media_content_id:
-            media_items = []
-            for playlist_str in media_content_id.split(","):
-                playlist_str = playlist_str.strip()
-                playlist = (
-                    await self.mass.music_manager.async_get_library_playlist_by_name(
-                        playlist_str
-                    )
-                )
-                if playlist:
-                    media_items.append(playlist)
-                else:
-                    radio = await self.mass.music_manager.async_get_radio_by_name(
-                        playlist_str
-                    )
-                    if radio:
-                        media_items.append(radio)
-                        queue_opt = "play"
-            return await self.mass.player_manager.async_play_media(
-                player_id, media_items, queue_opt
-            )
-        if "spotify://playlist" in media_content_id:
-            # TODO: handle parsing of other uri's here
-            playlist = await self.mass.music_manager.async_getplaylist(
-                "spotify", media_content_id.split(":")[-1]
-            )
-            return await self.mass.player_manager.async_play_media(
-                player_id, playlist, queue_opt
-            )
-
-    async def __async_publish_player(self, player: Player):
-        """Publish player details to Home Assistant."""
-        if not self.mass.config.providers[PROV_ID][CONF_PUBLISH_PLAYERS]:
-            return False
-        if not player.available:
-            return
-        player_id = player.player_id
-        entity_id = (
-            "media_player.mass_" + slug.slugify(player.name, separator="_").lower()
-        )
-        player_queue = self.mass.player_manager.get_player_queue(player_id)
-        cur_item = player_queue.cur_item if player_queue else None
-        state_attributes = {
-            "supported_features": 196541,
-            "friendly_name": player.name,
-            "source_list": self._sources,
-            "source": "unknown",
-            "volume_level": player.volume_level / 100,
-            "is_volume_muted": player.muted,
-            "media_position_updated_at": player.updated_at.isoformat(),
-            "media_duration": cur_item.duration if cur_item else None,
-            "media_position": player_queue.cur_item_time if player_queue else None,
-            "media_title": cur_item.name if cur_item else None,
-            "media_artist": cur_item.artists[0].name
-            if cur_item and cur_item.artists
-            else None,
-            "media_album_name": cur_item.album.name
-            if cur_item and cur_item.album
-            else None,
-            "entity_picture": "",
-            "mass_player_id": player_id,
-        }
-        if cur_item:
-            host = self.mass.web.internal_url
-            item_type = "radio" if cur_item.media_type == MediaType.Radio else "track"
-            # pylint: disable=line-too-long
-            img_url = f"{host}/api/{item_type}/{cur_item.item_id}/thumb?provider={cur_item.provider}"
-            state_attributes["entity_picture"] = img_url
-        self._published_players[entity_id] = player.player_id
-        await self._hass.async_set_state(entity_id, player.state, state_attributes)
-
-    @run_periodic(600)
-    async def __async_get_sources(self):
-        """We build a list of all playlists to use as player sources."""
-        # pylint: disable=attribute-defined-outside-init
-        self._sources = [
-            playlist.name
-            async for playlist in self.mass.music_manager.async_get_library_playlists()
-        ]
-        self._sources += [
-            playlist.name
-            async for playlist in self.mass.music_manager.async_get_library_radios()
-        ]
-
     @callback
     def __get_power_control_entities(self):
         """Return list of entities that can be used as power control."""
index 7d50f963f08ea60926ef5a4ca400652b24166f60..3699477f3041029802367a62b66850d5fd065c41 100644 (file)
@@ -10,7 +10,7 @@ from music_assistant.app_vars import get_app_var  # noqa # pylint: disable=all
 from music_assistant.constants import (
     CONF_PASSWORD,
     CONF_USERNAME,
-    EVENT_PLAYBACK_STOPPED,
+    EVENT_STREAM_ENDED,
     EVENT_STREAM_STARTED,
 )
 from music_assistant.models.config_entry import ConfigEntry, ConfigEntryType
@@ -95,7 +95,7 @@ class QobuzProvider(MusicProvider):
         self.__logged_in = False
         self._throttler = Throttler(rate_limit=4, period=1)
         self.mass.add_event_listener(self.async_mass_event, EVENT_STREAM_STARTED)
-        self.mass.add_event_listener(self.async_mass_event, EVENT_PLAYBACK_STOPPED)
+        self.mass.add_event_listener(self.async_mass_event, EVENT_STREAM_ENDED)
         return True
 
     async def async_search(
@@ -392,7 +392,7 @@ class QobuzProvider(MusicProvider):
                 }
             ]
             await self.__async_post_data("track/reportStreamingStart", data=events)
-        elif msg == EVENT_PLAYBACK_STOPPED and msg_details.provider == PROV_ID:
+        elif msg == EVENT_STREAM_ENDED and msg_details.provider == PROV_ID:
             # report streaming ended to qobuz
             # if msg_details.details < 6:
             #     return ????????????? TODO