From 7298a71a6f961aeff3105b6078134b976912ef50 Mon Sep 17 00:00:00 2001
From: David Trattnig <david@subsquare.at>
Date: Mon, 2 Oct 2023 16:01:27 +0200
Subject: [PATCH] refactor: play state as part of domain models

---
 src/aura_engine/engine.py               | 19 +++-----------
 src/aura_engine/scheduling/domain.py    | 35 ++++++++++++++++++++++---
 src/aura_engine/scheduling/scheduler.py |  7 ++---
 3 files changed, 40 insertions(+), 21 deletions(-)

diff --git a/src/aura_engine/engine.py b/src/aura_engine/engine.py
index add5809e..75fb027b 100644
--- a/src/aura_engine/engine.py
+++ b/src/aura_engine/engine.py
@@ -235,17 +235,6 @@ class Player:
         INSTANT = "instant"
         FADE = "fade"
 
-    class ItemPlayState(str, Enum):
-        """
-        Play-state of a playlist item.
-        """
-
-        UNKNOWN = "unknown"
-        LOADING = "loading"
-        READY = "ready_to_play"
-        PLAYING = "playing"
-        FINISHED = "finished"
-
     config = None
     logger = None
     channels = None
@@ -286,7 +275,7 @@ class Player:
         """
         is_queue = item.get_content_type() in ResourceClass.FILE.types
         metadata = ResourceUtil.generate_track_metadata(item, not is_queue)
-        item.status = Player.ItemPlayState.LOADING
+        item.status = PlaylistItem.PlayStatus.LOADING
         self.logger.debug(SU.pink(f"Loading item '{item}'"))
         uri = None
         is_ready = False
@@ -316,7 +305,7 @@ class Player:
         is_ready = item.channel.load(uri, metadata=metadata)
 
         if is_ready:
-            item.status = Player.ItemPlayState.READY
+            item.status = PlaylistItem.PlayStatus.READY
         self.event_dispatcher.on_queue([item])
 
     def preload_group(self, items: list(PlaylistItem)):
@@ -349,14 +338,14 @@ class Player:
 
         for item in items:
             item.channel = free_channel
-            item.status = Player.ItemPlayState.LOADING
+            item.status = PlaylistItem.PlayStatus.LOADING
             self.logger.debug(SU.pink(f"Loading item '{item}'"))
 
             # Choose and save the input channel
             metadata = ResourceUtil.generate_track_metadata(item)
             file_path = ResourceUtil.source_to_filepath(item.source, self.config)
             if item.channel.load(file_path, metadata):
-                item.status = Player.ItemPlayState.READY
+                item.status = PlaylistItem.PlayStatus.READY
 
         self.event_dispatcher.on_queue(items)
         return channels
diff --git a/src/aura_engine/scheduling/domain.py b/src/aura_engine/scheduling/domain.py
index 722ac4f0..0e503aec 100644
--- a/src/aura_engine/scheduling/domain.py
+++ b/src/aura_engine/scheduling/domain.py
@@ -35,7 +35,6 @@ from typing import NamedTuple
 
 from aura_engine.base.utils import SimpleUtil
 from aura_engine.core.channels import GenericChannel
-from aura_engine.engine import Player
 from aura_engine.resources import ResourceType, ResourceUtil
 from aura_engine.scheduling.utils import ItemQueueState
 
@@ -294,11 +293,11 @@ class PlaylistItem:
         volume (int): Value from 0-100% indicating loudness.
         source (str): URI referencing the audio source.
 
+        play_status (PlaylistItem.PlayStatus): Play-out state, set when playing starts.
         play_start_time (int): UNIX epoch, when item actually started playing. \
             Not necessary matching `start`.
         play_channel (GenericChannel): Play-out channel, set when item is starts playing.
         play_queue_state (ItemQueueState): Progress on queuing, set when item is queued.
-        play_status (Player.ItemPlayState): Play-out state, set when playing starts.
 
     """
 
@@ -309,13 +308,25 @@ class PlaylistItem:
     source: str
     duration: int
     volume: int
+
     Metadata = NamedTuple("Metadata", [("artist", str), ("album", str), ("title", str)])
     metadata: Metadata
 
+    class PlayStatus(str, enum.Enum):
+        """
+        Play-state of a playlist item.
+        """
+
+        UNKNOWN = "unknown"
+        LOADING = "loading"
+        READY = "ready_to_play"
+        PLAYING = "playing"
+        FINISHED = "finished"
+
+    play_status: PlayStatus
     play_start_time: int
     play_channel: GenericChannel
     play_queue_state: ItemQueueState
-    play_status: Player.ItemPlayState
 
     def __init__(self, source: str, duration: int, volume: int, metadata: Metadata):
         self.prev = None
@@ -414,6 +425,24 @@ class PlaylistItem:
         else:
             return []
 
+    def set_play_status(self, status: PlayStatus):
+        """
+        Set the play-out status of the current item.
+
+        Args:
+            status (PlayStatus): Info on the play status.
+        """
+        self.play_status = status
+
+    def get_play_status(self):
+        """
+        Returns the play-out status.
+
+        Returns:
+            PlayStatus: Info on the items is being played, buffered etc.
+        """
+        return self.play_status
+
     def __str__(self):
         """
         String representation.
diff --git a/src/aura_engine/scheduling/scheduler.py b/src/aura_engine/scheduling/scheduler.py
index 54b02a85..387eda71 100644
--- a/src/aura_engine/scheduling/scheduler.py
+++ b/src/aura_engine/scheduling/scheduler.py
@@ -31,6 +31,7 @@ from aura_engine.control import EngineExecutor
 from aura_engine.core.channels import LoadSourceException
 from aura_engine.engine import Engine, Player
 from aura_engine.resources import ResourceClass, ResourceUtil
+from aura_engine.scheduling.domain import PlaylistItem
 from aura_engine.scheduling.models import AuraDatabaseModel
 from aura_engine.scheduling.timetable import TimetableService
 from aura_engine.scheduling.utils import TimetableRenderer
@@ -552,7 +553,7 @@ class PlayCommand(EngineExecutor):
         except LoadSourceException as e:
             self.logger.critical(SU.red(f"Could not preload items {items_str}"), e)
 
-        if items[-1].status != Player.ItemPlayState.READY:
+        if items[-1].status != PlaylistItem.PlayStatus.READY:
             msg = f"Items didn't reach 'ready' state during preloading (Items: {items_str})"
             self.logger.warning(SU.red(msg))
 
@@ -562,11 +563,11 @@ class PlayCommand(EngineExecutor):
         """
         items_str = ResourceUtil.get_items_string(items)
         self.logger.info(SU.cyan(f"=== play('{items_str}') ==="))
-        if items[-1].status != Player.ItemPlayState.READY:
+        if items[-1].status != PlaylistItem.PlayStatus.READY:
             # Let 'em play anyway ...
             msg = f"PLAY: Item(s) not yet ready to be played" f" (Items: {items_str})"
             self.logger.critical(SU.red(msg))
-            while items[-1].status != Player.ItemPlayState.READY:
+            while items[-1].status != PlaylistItem.PlayStatus.READY:
                 self.logger.info("PLAY: Wait a little bit until preloading is done ...")
                 time.sleep(2)
 
-- 
GitLab