End of Day WIP on marker support
This commit is contained in:
parent
6718ddcf2d
commit
cc861e2869
4 changed files with 105 additions and 3 deletions
51
player.py
51
player.py
|
@ -20,7 +20,9 @@
|
||||||
# that we respond with something, FAIL or OKAY. The server doesn't like to be kept waiting.
|
# that we respond with something, FAIL or OKAY. The server doesn't like to be kept waiting.
|
||||||
|
|
||||||
# Stop the Pygame Hello message.
|
# Stop the Pygame Hello message.
|
||||||
|
from logging import exception
|
||||||
import os
|
import os
|
||||||
|
from types.marker import Marker
|
||||||
os.environ["PYGAME_HIDE_SUPPORT_PROMPT"] = "hide"
|
os.environ["PYGAME_HIDE_SUPPORT_PROMPT"] = "hide"
|
||||||
|
|
||||||
from queue import Empty
|
from queue import Empty
|
||||||
|
@ -36,7 +38,7 @@ from mutagen.mp3 import MP3
|
||||||
from helpers.myradio_api import MyRadioAPI
|
from helpers.myradio_api import MyRadioAPI
|
||||||
from helpers.state_manager import StateManager
|
from helpers.state_manager import StateManager
|
||||||
from helpers.logging_manager import LoggingManager
|
from helpers.logging_manager import LoggingManager
|
||||||
from plan import PlanItem
|
from types.plan import PlanItem
|
||||||
|
|
||||||
|
|
||||||
# TODO ENUM
|
# TODO ENUM
|
||||||
|
@ -74,6 +76,7 @@ class Player:
|
||||||
"play_on_load": False,
|
"play_on_load": False,
|
||||||
"output": None,
|
"output": None,
|
||||||
"show_plan": [],
|
"show_plan": [],
|
||||||
|
"markers": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
__rate_limited_params = ["pos", "pos_offset", "pos_true", "remaining"]
|
__rate_limited_params = ["pos", "pos_offset", "pos_true", "remaining"]
|
||||||
|
@ -402,7 +405,48 @@ class Player:
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def ended(self):
|
def set_marker(self, timeslotitemid: int, marker_str: str):
|
||||||
|
set_loaded = False
|
||||||
|
success = True
|
||||||
|
try:
|
||||||
|
marker = Marker(marker_str)
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.log.error("Failed to create Marker instance with {} {}: {}".format(timeslotitemid, marker_str, e))
|
||||||
|
return False
|
||||||
|
|
||||||
|
if timeslotitemid == -1:
|
||||||
|
set_loaded = True
|
||||||
|
if not self.isLoaded:
|
||||||
|
return False
|
||||||
|
timeslotitemid = self.state.state["loaded_item"]["timeslotitemid"]
|
||||||
|
|
||||||
|
for i in range(len(self.state.state["show_plan"])):
|
||||||
|
plan = self.state.state["show_plan"]
|
||||||
|
item = plan[i]
|
||||||
|
|
||||||
|
if item.timeslotitemid == timeslotitemid:
|
||||||
|
try:
|
||||||
|
item = item.set_marker(marker)
|
||||||
|
|
||||||
|
self.state.update("show_plan", plan)
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.log.error(
|
||||||
|
"Failed to set marker on item {}: {} with marker \n{}".format(timeslotitemid, e, marker))
|
||||||
|
success = False
|
||||||
|
|
||||||
|
if set_loaded:
|
||||||
|
try:
|
||||||
|
self.state.update("loaded_item", self.state.state["show_plan"]["loaded_item"].set_marker(marker))
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.log.error(
|
||||||
|
"Failed to set marker on loaded_item {}: {} with marker \n{}".format(timeslotitemid, e, marker))
|
||||||
|
success = False
|
||||||
|
|
||||||
|
return success
|
||||||
|
|
||||||
|
# Helper functions
|
||||||
|
|
||||||
|
def _ended(self):
|
||||||
loaded_item = self.state.state["loaded_item"]
|
loaded_item = self.state.state["loaded_item"]
|
||||||
|
|
||||||
# Track has ended
|
# Track has ended
|
||||||
|
@ -459,7 +503,7 @@ class Player:
|
||||||
and not self.isPlaying
|
and not self.isPlaying
|
||||||
and not self.stopped_manually
|
and not self.stopped_manually
|
||||||
):
|
):
|
||||||
self.ended()
|
self._ended()
|
||||||
|
|
||||||
self.state.update("playing", self.isPlaying)
|
self.state.update("playing", self.isPlaying)
|
||||||
self.state.update("loaded", self.isLoaded)
|
self.state.update("loaded", self.isLoaded)
|
||||||
|
@ -656,6 +700,7 @@ class Player:
|
||||||
int(self.last_msg.split(":")[1]))
|
int(self.last_msg.split(":")[1]))
|
||||||
),
|
),
|
||||||
"CLEAR": lambda: self._retMsg(self.clear_channel_plan()),
|
"CLEAR": lambda: self._retMsg(self.clear_channel_plan()),
|
||||||
|
"SETMARKER": lambda: self._retMsg(self.set_marker(self.last_msg.split(":")[1])),
|
||||||
}
|
}
|
||||||
|
|
||||||
message_type: str = self.last_msg.split(":")[0]
|
message_type: str = self.last_msg.split(":")[0]
|
||||||
|
|
|
@ -349,6 +349,8 @@ class TestPlayer(unittest.TestCase):
|
||||||
self.assertEquals(item["cue"], None)
|
self.assertEquals(item["cue"], None)
|
||||||
self.assertEquals(item["markers"], markers[3:])
|
self.assertEquals(item["markers"], markers[3:])
|
||||||
|
|
||||||
|
# TODO: Now test editing/deleting them
|
||||||
|
|
||||||
|
|
||||||
# runs the unit tests in the module
|
# runs the unit tests in the module
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
41
types/marker.py
Normal file
41
types/marker.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import json
|
||||||
|
from typing import Dict, Optional, Union
|
||||||
|
|
||||||
|
POSITIONS = ["start", "mid", "end"]
|
||||||
|
PARAMS = ["name", "time", "position", "section"]
|
||||||
|
|
||||||
|
|
||||||
|
class Marker:
|
||||||
|
marker: Dict
|
||||||
|
|
||||||
|
def __init__(self, marker_str: str):
|
||||||
|
try:
|
||||||
|
marker = json.loads(marker_str)
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError("Failed to decode JSON for marker: {}".format(e))
|
||||||
|
|
||||||
|
for key in marker.keys():
|
||||||
|
if key not in PARAMS:
|
||||||
|
raise ValueError("Key {} is not a valid marker parameter.".format(key))
|
||||||
|
|
||||||
|
if not isinstance(marker["name"], str):
|
||||||
|
raise ValueError("Name is not str.")
|
||||||
|
self.name = marker["name"]
|
||||||
|
|
||||||
|
if not isinstance(marker["time"], Union[int, float]):
|
||||||
|
raise ValueError("Time is not a float or int")
|
||||||
|
|
||||||
|
if marker["position"] not in POSITIONS:
|
||||||
|
raise ValueError("Position is not in allowed values.")
|
||||||
|
|
||||||
|
if not isinstance(marker["section"], Optional[str]):
|
||||||
|
raise ValueError("Section name is not str or None.")
|
||||||
|
|
||||||
|
# If everything checks out, let's save it.
|
||||||
|
self.marker = marker
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return json.dumps(self.marker)
|
||||||
|
|
||||||
|
def __dict__(self):
|
||||||
|
return self.marker
|
|
@ -12,6 +12,7 @@
|
||||||
November 2020
|
November 2020
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from types.marker import Marker
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -90,6 +91,9 @@ class PlanItem:
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
"filename": self.filename,
|
"filename": self.filename,
|
||||||
"length": self.length,
|
"length": self.length,
|
||||||
|
"intro": self.intro,
|
||||||
|
"cue": self.cue,
|
||||||
|
"outro": self.outro,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, new_item: Dict[str, Any]):
|
def __init__(self, new_item: Dict[str, Any]):
|
||||||
|
@ -108,9 +112,19 @@ class PlanItem:
|
||||||
self._artist = new_item["artist"] if "artist" in new_item else None
|
self._artist = new_item["artist"] if "artist" in new_item else None
|
||||||
self._length = new_item["length"]
|
self._length = new_item["length"]
|
||||||
|
|
||||||
|
# Edit this to handle markers when MyRadio supports them
|
||||||
|
self._
|
||||||
|
|
||||||
# Fix any OS specific / or \'s
|
# Fix any OS specific / or \'s
|
||||||
if self.filename:
|
if self.filename:
|
||||||
if os.path.sep == "/":
|
if os.path.sep == "/":
|
||||||
self._filename = self.filename.replace("\\", "/")
|
self._filename = self.filename.replace("\\", "/")
|
||||||
else:
|
else:
|
||||||
self._filename = self.filename.replace("/", "\\")
|
self._filename = self.filename.replace("/", "\\")
|
||||||
|
|
||||||
|
def set_marker(self, marker: Marker):
|
||||||
|
if not isinstance(marker, Marker):
|
||||||
|
raise ValueError("Marker provided is not of type Marker.")
|
||||||
|
|
||||||
|
# Return updated item for easy chaining.
|
||||||
|
return self
|
Loading…
Reference in a new issue