From 495b7949f0d6aebf99cdf80284e5fd6dffb407b1 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 14 Sep 2024 10:01:28 +0200 Subject: [PATCH] Fix API compatibility (#1662) --- music_assistant/common/models/player.py | 31 ++++++++++++++----- music_assistant/common/models/queue_item.py | 5 +++ music_assistant/constants.py | 2 +- .../server/controllers/player_queues.py | 8 ++--- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/music_assistant/common/models/player.py b/music_assistant/common/models/player.py index 567b1b124..e3a156344 100644 --- a/music_assistant/common/models/player.py +++ b/music_assistant/common/models/player.py @@ -49,12 +49,11 @@ class Player(DataClassDictMixin): device_info: DeviceInfo supported_features: tuple[PlayerFeature, ...] = field(default=()) - elapsed_time: float = 0 - elapsed_time_last_updated: float = time.time() - state: PlayerState = PlayerState.IDLE - - volume_level: int = 100 - volume_muted: bool = False + elapsed_time: float | None = None + elapsed_time_last_updated: float | None = None + state: PlayerState | None = None + volume_level: int | None = None + volume_muted: bool | None = None # group_childs: Return list of player group child id's or synced child`s. # - If this player is a dedicated group player, @@ -138,8 +137,10 @@ class Player(DataClassDictMixin): _prev_volume_level: int = 0 @property - def corrected_elapsed_time(self) -> float: + def corrected_elapsed_time(self) -> float | None: """Return the corrected/realtime elapsed time.""" + if self.elapsed_time is None or self.elapsed_time_last_updated is None: + return None if self.state == PlayerState.PLAYING: return self.elapsed_time + (time.time() - self.elapsed_time_last_updated) return self.elapsed_time @@ -155,3 +156,19 @@ def current_item_id(self) -> str | None: def current_item_id(self, uri: str) -> None: """Set current_item_id (for backwards compatibility).""" self.current_media = PlayerMedia(uri) + + def __post_serialize__(self, d: dict[Any, Any]) -> dict[Any, Any]: + """Execute action(s) on serialization.""" + # TEMP: convert values to prevent api breakage + # this may be removed after 2.3 has been launched to stable + if self.elapsed_time is None: + d["elapsed_time"] = 0 + if self.elapsed_time_last_updated is None: + d["elapsed_time_last_updated"] = 0 + if self.volume_level is None: + d["volume_level"] = 0 + if self.volume_muted is None: + d["volume_muted"] = False + if self.state is None: + d["state"] = PlayerState.IDLE + return d diff --git a/music_assistant/common/models/queue_item.py b/music_assistant/common/models/queue_item.py index 716e2b1be..0c7d2aa1b 100644 --- a/music_assistant/common/models/queue_item.py +++ b/music_assistant/common/models/queue_item.py @@ -44,6 +44,11 @@ def __post_serialize__(self, d: dict[Any, Any]) -> dict[Any, Any]: streamdetails.pop("expires", None) streamdetails.pop("path", None) streamdetails.pop("decryption_key", None) + # pop loudness from streamdetails in api to keep api from breaking + # (due to the loudness field's type change in 2.3) + # this may be removed after 2.3 has been launched to stable + streamdetails.pop("loudness", None) + streamdetails.pop("loudness_album", None) return d @property diff --git a/music_assistant/constants.py b/music_assistant/constants.py index 820f909aa..017371ca4 100644 --- a/music_assistant/constants.py +++ b/music_assistant/constants.py @@ -3,7 +3,7 @@ import pathlib from typing import Final -API_SCHEMA_VERSION: Final[int] = 25 +API_SCHEMA_VERSION: Final[int] = 26 MIN_SCHEMA_VERSION: Final[int] = 24 diff --git a/music_assistant/server/controllers/player_queues.py b/music_assistant/server/controllers/player_queues.py index 411f96e4c..f723c9937 100644 --- a/music_assistant/server/controllers/player_queues.py +++ b/music_assistant/server/controllers/player_queues.py @@ -949,12 +949,12 @@ def on_player_update( if item_id := self._parse_player_current_item_id(queue_id, player): queue.current_index = self.index_by_id(queue_id, item_id) if player.state in (PlayerState.PLAYING, PlayerState.PAUSED): - queue.elapsed_time = int(player.corrected_elapsed_time) - queue.elapsed_time_last_updated = player.elapsed_time_last_updated + queue.elapsed_time = int(player.corrected_elapsed_time or 0) + queue.elapsed_time_last_updated = player.elapsed_time_last_updated or 0 # only update these attributes if the queue is active # and has an item loaded so we are able to resume it - queue.state = player.state + queue.state = player.state or PlayerState.IDLE queue.current_item = self.get_item(queue_id, queue.current_index) queue.next_item = self._get_next_item(queue_id) @@ -1448,7 +1448,7 @@ def __get_queue_stream_index(self, queue: PlayerQueue, player: Player) -> tuple[ """Calculate current queue index and current track elapsed time.""" # player is playing a constant stream so we need to do this the hard way queue_index = 0 - elapsed_time_queue = player.corrected_elapsed_time + elapsed_time_queue = player.corrected_elapsed_time or 0 total_time = 0 track_time = 0 queue_items = self._queue_items[queue.queue_id]