Fixed some small glitches (#335)
authorMarcel van der Veldt <m.vanderveldt@outlook.com>
Sat, 21 May 2022 23:06:20 +0000 (01:06 +0200)
committerGitHub <noreply@github.com>
Sat, 21 May 2022 23:06:20 +0000 (01:06 +0200)
* fix exception when audio analyze fails

* cleanup event enum

* allow provider object to be serialized to dict

* emit events on all media library changes

music_assistant/controllers/music/albums.py
music_assistant/controllers/music/artists.py
music_assistant/controllers/music/playlists.py
music_assistant/controllers/music/radio.py
music_assistant/controllers/music/tracks.py
music_assistant/helpers/audio.py
music_assistant/models/enums.py
music_assistant/models/media_controller.py
music_assistant/models/provider.py

index 72d97fa531aa41d251dd7406fb50fb0b411016f3..32a59c4d2c3f704344442b4ad9bfdf8c0d90681c 100644 (file)
@@ -94,9 +94,6 @@ class AlbumsController(MediaControllerBase[Album]):
         # also fetch same album on all providers
         await self._match(db_item)
         db_item = await self.get_db_item(db_item.item_id)
-        self.mass.signal_event(
-            MassEvent(EventType.ALBUM_ADDED, object_id=db_item.uri, data=db_item)
-        )
         return db_item
 
     async def get_provider_album_tracks(
@@ -150,7 +147,13 @@ class AlbumsController(MediaControllerBase[Album]):
             item_id = new_item["item_id"]
             self.logger.debug("added %s to database", album.name)
             # return created object
-            return await self.get_db_item(item_id, db=db)
+            db_item = await self.get_db_item(item_id, db=db)
+            self.mass.signal_event(
+                MassEvent(
+                    EventType.MEDIA_ITEM_ADDED, object_id=db_item.uri, data=db_item
+                )
+            )
+            return db_item
 
     async def update_db_item(
         self,
@@ -192,7 +195,13 @@ class AlbumsController(MediaControllerBase[Album]):
                 db=db,
             )
             self.logger.debug("updated %s in database: %s", album.name, item_id)
-            return await self.get_db_item(item_id, db=db)
+            db_item = await self.get_db_item(item_id, db=db)
+            self.mass.signal_event(
+                MassEvent(
+                    EventType.MEDIA_ITEM_UPDATED, object_id=db_item.uri, data=db_item
+                )
+            )
+            return db_item
 
     async def _match(self, db_album: Album) -> None:
         """
index 346871c12b6b4c267ae8cdd27118faa6b88e5cb2..fa4a1612f514f36f61b453e3b94f5ccd5d911a90 100644 (file)
@@ -87,9 +87,6 @@ class ArtistsController(MediaControllerBase[Artist]):
         # also fetch same artist on all providers
         await self.match_artist(db_item)
         db_item = await self.get_db_item(db_item.item_id)
-        self.mass.signal_event(
-            MassEvent(EventType.ARTIST_ADDED, object_id=db_item.uri, data=db_item)
-        )
         return db_item
 
     async def match_artist(self, db_artist: Artist):
@@ -168,7 +165,13 @@ class ArtistsController(MediaControllerBase[Artist]):
             item_id = new_item["item_id"]
             self.logger.debug("added %s to database", artist.name)
             # return created object
-            return await self.get_db_item(item_id, db=db)
+            db_item = await self.get_db_item(item_id, db=db)
+            self.mass.signal_event(
+                MassEvent(
+                    EventType.MEDIA_ITEM_ADDED, object_id=db_item.uri, data=db_item
+                )
+            )
+            return db_item
 
     async def update_db_item(
         self,
@@ -200,7 +203,13 @@ class ArtistsController(MediaControllerBase[Artist]):
                 db=db,
             )
             self.logger.debug("updated %s in database: %s", artist.name, item_id)
-            return await self.get_db_item(item_id, db=db)
+            db_item = await self.get_db_item(item_id, db=db)
+            self.mass.signal_event(
+                MassEvent(
+                    EventType.MEDIA_ITEM_UPDATED, object_id=db_item.uri, data=db_item
+                )
+            )
+            return db_item
 
     async def _match(self, db_artist: Artist, provider: MusicProvider) -> bool:
         """Try to find matching artists on given provider for the provided (database) artist."""
index 3f740d448f661f5fb8c69cc7d805d78bbbfb0e16..c7392ae12c92ee0c94d772c5c1f5a1ad57f8bab6 100644 (file)
@@ -50,11 +50,7 @@ class PlaylistController(MediaControllerBase[Playlist]):
         """Add playlist to local db and return the new database item."""
         item.metadata.last_refresh = int(time())
         await self.mass.metadata.get_playlist_metadata(item)
-        db_item = await self.add_db_item(item)
-        self.mass.signal_event(
-            MassEvent(EventType.PLAYLIST_ADDED, object_id=db_item.uri, data=db_item)
-        )
-        return db_item
+        return await self.add_db_item(item)
 
     async def add_playlist_tracks(self, db_playlist_id: str, uris: List[str]) -> None:
         """Add multiple tracks to playlist. Creates background tasks to process the action."""
@@ -132,7 +128,9 @@ class PlaylistController(MediaControllerBase[Playlist]):
         # update local db entry
         self.mass.signal_event(
             MassEvent(
-                type=EventType.PLAYLIST_UPDATED, object_id=db_playlist_id, data=playlist
+                type=EventType.MEDIA_ITEM_UPDATED,
+                object_id=db_playlist_id,
+                data=playlist,
             )
         )
 
@@ -158,7 +156,9 @@ class PlaylistController(MediaControllerBase[Playlist]):
                 await provider.remove_playlist_tracks(prov.item_id, track_ids_to_remove)
         self.mass.signal_event(
             MassEvent(
-                type=EventType.PLAYLIST_UPDATED, object_id=db_playlist_id, data=playlist
+                type=EventType.MEDIA_ITEM_UPDATED,
+                object_id=db_playlist_id,
+                data=playlist,
             )
         )
 
@@ -181,7 +181,13 @@ class PlaylistController(MediaControllerBase[Playlist]):
             item_id = new_item["item_id"]
             self.logger.debug("added %s to database", playlist.name)
             # return created object
-            return await self.get_db_item(item_id, db=db)
+            db_item = await self.get_db_item(item_id, db=db)
+            self.mass.signal_event(
+                MassEvent(
+                    EventType.MEDIA_ITEM_ADDED, object_id=db_item.uri, data=db_item
+                )
+            )
+            return db_item
 
     async def update_db_item(
         self,
@@ -218,7 +224,7 @@ class PlaylistController(MediaControllerBase[Playlist]):
             db_item = await self.get_db_item(item_id, db=db)
             self.mass.signal_event(
                 MassEvent(
-                    type=EventType.PLAYLIST_UPDATED, object_id=item_id, data=playlist
+                    EventType.MEDIA_ITEM_UPDATED, object_id=db_item.uri, data=db_item
                 )
             )
             return db_item
index ae65a6c11bfbd7995ac8c4b3e5688645b6b99573..06eb3755bd5451e981c0c1c23e7c9e84beaf0413 100644 (file)
@@ -29,11 +29,7 @@ class RadioController(MediaControllerBase[Radio]):
         """Add radio to local db and return the new database item."""
         item.metadata.last_refresh = int(time())
         await self.mass.metadata.get_radio_metadata(item)
-        db_item = await self.add_db_item(item)
-        self.mass.signal_event(
-            MassEvent(EventType.RADIO_ADDED, object_id=db_item.uri, data=db_item)
-        )
-        return db_item
+        return await self.add_db_item(item)
 
     async def add_db_item(self, radio: Radio, db: Optional[Db] = None) -> Radio:
         """Add a new radio record to the database."""
@@ -53,7 +49,13 @@ class RadioController(MediaControllerBase[Radio]):
             item_id = new_item["item_id"]
             self.logger.debug("added %s to database", radio.name)
             # return created object
-            return await self.get_db_item(item_id, db=db)
+            db_item = await self.get_db_item(item_id, db=db)
+            self.mass.signal_event(
+                MassEvent(
+                    EventType.MEDIA_ITEM_ADDED, object_id=db_item.uri, data=db_item
+                )
+            )
+            return db_item
 
     async def update_db_item(
         self,
@@ -85,4 +87,10 @@ class RadioController(MediaControllerBase[Radio]):
                 db=db,
             )
             self.logger.debug("updated %s in database: %s", radio.name, item_id)
-            return await self.get_db_item(item_id, db=db)
+            db_item = await self.get_db_item(item_id, db=db)
+            self.mass.signal_event(
+                MassEvent(
+                    EventType.MEDIA_ITEM_UPDATED, object_id=db_item.uri, data=db_item
+                )
+            )
+            return db_item
index 8448aa3a596e575d31e1ccd1a1b57b40851222bc..9a22c6205548877493636ce37fc80c142b976d02 100644 (file)
@@ -54,11 +54,7 @@ class TracksController(MediaControllerBase[Track]):
         db_item = await self.add_db_item(item)
         # also fetch same track on all providers (will also get other quality versions)
         await self._match(db_item)
-        db_item = await self.get_db_item(db_item.item_id)
-        self.mass.signal_event(
-            MassEvent(EventType.TRACK_ADDED, object_id=db_item.uri, data=db_item)
-        )
-        return db_item
+        return await self.get_db_item(db_item.item_id)
 
     async def versions(
         self,
@@ -162,7 +158,13 @@ class TracksController(MediaControllerBase[Track]):
             item_id = new_item["item_id"]
             # return created object
             self.logger.debug("added %s to database: %s", track.name, item_id)
-            return await self.get_db_item(item_id, db=db)
+            db_item = await self.get_db_item(item_id, db=db)
+            self.mass.signal_event(
+                MassEvent(
+                    EventType.MEDIA_ITEM_ADDED, object_id=db_item.uri, data=db_item
+                )
+            )
+            return db_item
 
     async def update_db_item(
         self,
@@ -200,7 +202,13 @@ class TracksController(MediaControllerBase[Track]):
                 db=db,
             )
             self.logger.debug("updated %s in database: %s", track.name, item_id)
-            return await self.get_db_item(item_id, db=db)
+            db_item = await self.get_db_item(item_id, db=db)
+            self.mass.signal_event(
+                MassEvent(
+                    EventType.MEDIA_ITEM_UPDATED, object_id=db_item.uri, data=db_item
+                )
+            )
+            return db_item
 
     async def _get_track_artists(
         self,
index 78e06178d65d7504920e631a0d5e55b1a4907392..727cc4bea6801965795c7553fc8ea809d0e4fe5b 100644 (file)
@@ -165,16 +165,15 @@ async def analyze_audio(mass: MusicAssistant, streamdetails: StreamDetails) -> N
         stdout=asyncio.subprocess.PIPE,
         stdin=asyncio.subprocess.PIPE if audio_data else None,
     )
-    stdout, stderr = await proc.communicate(audio_data or None)
+    stdout, _ = await proc.communicate(audio_data or None)
     try:
         loudness = float(stdout.decode().strip())
     except (ValueError, AttributeError):
         LOGGER.warning(
-            "Could not determine integrated loudness of %s/%s - %s %s",
+            "Could not determine integrated loudness of %s/%s - %s",
             streamdetails.provider.value,
             streamdetails.item_id,
-            stdout.decode(),
-            stderr.decode(),
+            stdout.decode() or "received empty value",
         )
     else:
         await mass.music.set_track_loudness(
index 022eb6fce8613d854695a3177528b3de3009a6b5..b0046a04818e52d8d1ac3e3469730791a452785c 100644 (file)
@@ -185,21 +185,17 @@ class PlayerState(Enum):
 class EventType(Enum):
     """Enum with possible Events."""
 
-    PLAYER_ADDED = "player added"
-    PLAYER_UPDATED = "player updated"
-    STREAM_STARTED = "streaming started"
-    STREAM_ENDED = "streaming ended"
+    PLAYER_ADDED = "player_added"
+    PLAYER_UPDATED = "player_updated"
+    STREAM_STARTED = "streaming_started"
+    STREAM_ENDED = "streaming_ended"
     QUEUE_ADDED = "queue_added"
-    QUEUE_UPDATED = "queue updated"
-    QUEUE_ITEMS_UPDATED = "queue items updated"
-    QUEUE_TIME_UPDATED = "queue time updated"
-    SHUTDOWN = "application shutdown"
-    ARTIST_ADDED = "artist added"
-    ALBUM_ADDED = "album added"
-    TRACK_ADDED = "track added"
-    PLAYLIST_ADDED = "playlist added"
-    PLAYLIST_UPDATED = "playlist updated"
-    RADIO_ADDED = "radio added"
+    QUEUE_UPDATED = "queue_updated"
+    QUEUE_ITEMS_UPDATED = "queue_items_updated"
+    QUEUE_TIME_UPDATED = "queue_time_updated"
+    SHUTDOWN = "application_shutdown"
+    MEDIA_ITEM_ADDED = "media_item_added"
+    MEDIA_ITEM_UPDATED = "media_item_updated"
     BACKGROUND_JOB_UPDATED = "background_job_updated"
 
 
index d14a97902d7ba5a20f62968374c8c1928abdbf3e..bf71a31ece2399f1fd7d38ba9d7b9d16f3616569 100644 (file)
@@ -8,8 +8,9 @@ from typing import TYPE_CHECKING, Generic, List, Optional, Tuple, TypeVar
 from databases import Database as Db
 
 from music_assistant.models.errors import MediaNotFoundError, ProviderUnavailableError
+from music_assistant.models.event import MassEvent
 
-from .enums import MediaType, ProviderType
+from .enums import EventType, MediaType, ProviderType
 from .media_items import MediaItemType
 
 if TYPE_CHECKING:
@@ -139,7 +140,13 @@ class MediaControllerBase(Generic[ItemCls], metaclass=ABCMeta):
                 await prov.library_add(prov_id.item_id, self.media_type)
         # mark as library item in internal db
         if not db_item.in_library:
+            db_item.in_library = True
             await self.set_db_library(db_item.item_id, True)
+            self.mass.signal_event(
+                MassEvent(
+                    EventType.MEDIA_ITEM_UPDATED, object_id=db_item.uri, data=db_item
+                )
+            )
 
     async def remove_from_library(
         self,
@@ -158,7 +165,13 @@ class MediaControllerBase(Generic[ItemCls], metaclass=ABCMeta):
                 await prov.library_remove(prov_id.item_id, self.media_type)
         # unmark as library item in internal db
         if db_item.in_library:
+            db_item.in_library = False
             await self.set_db_library(db_item.item_id, False)
+            self.mass.signal_event(
+                MassEvent(
+                    EventType.MEDIA_ITEM_UPDATED, object_id=db_item.uri, data=db_item
+                )
+            )
 
     async def get_provider_id(
         self, item: ItemCls, db: Optional[Db] = None
index 7088b19c69bd49838c8f2a841e3d71ac349b930e..588505bd1a6052e30d4247a95dc620c76d510207 100644 (file)
@@ -2,7 +2,7 @@
 from __future__ import annotations
 
 from abc import abstractmethod
-from typing import TYPE_CHECKING, AsyncGenerator, List, Optional
+from typing import TYPE_CHECKING, Any, AsyncGenerator, Dict, List, Optional
 
 from music_assistant.models.config import MusicProviderConfig
 from music_assistant.models.enums import MediaType, ProviderType
@@ -240,6 +240,15 @@ class MusicProvider:
         """Return unique provider id to distinguish multiple instances of the same provider."""
         return self.config.id
 
+    def to_dict(self) -> Dict[str, Any]:
+        """Return (serializable) dict representation of MusicProvider."""
+        return {
+            "type": self.type.value,
+            "name": self.name,
+            "id": self.id,
+            "supported_mediatypes": [x.value for x in self.supported_mediatypes],
+        }
+
     def _get_library_gen(self, media_type: MediaType) -> AsyncGenerator[MediaItemType]:
         """Return library generator for given media_type."""
         if media_type == MediaType.ARTIST: