Skip to content
Snippets Groups Projects
Commit 900ff081 authored by David Trattnig's avatar David Trattnig
Browse files

Trigger new "on_fallback_active" event. #38

parent 09e04442
No related branches found
No related tags found
No related merge requests found
......@@ -34,17 +34,26 @@ from src.core.control import EngineExecutor
class FallbackType(Enum):
"""
Types of playlists.
Types of fallbacks.
NONE: No fallback active, default playout
SCHEDULE: The first played when some default playlist fails
SHOW: The second played when the timeslot fallback fails
STATION: The last played when everything else fails
"""
NONE = { "id": 0, "name": "default", "lqs_sources": [ Channel.QUEUE_A, Channel.QUEUE_A] } # No fallback active, default playout
SCHEDULE = { "id": 1, "name": "schedule", "lqs_sources": [ Channel.FALLBACK_QUEUE_A, Channel.FALLBACK_QUEUE_B]} # The first played when some default playlist fails
SHOW = { "id": 2, "name": "show", "lqs_sources": [ "station_folder", "station_playlist"]} # The second played when the timeslot fallback fails
STATION = { "id": 3, "name": "station", "lqs_sources": [ "station_folder", "station_playlist"] } # The last played when everything else fails
NONE = { "id": 0, "name": "default", "channels": [ Channel.QUEUE_A, Channel.QUEUE_B ] }
SCHEDULE = { "id": 1, "name": "schedule", "channels": [ Channel.FALLBACK_QUEUE_A, Channel.FALLBACK_QUEUE_B ] }
SHOW = { "id": 2, "name": "show", "channels": [ Channel.FALLBACK_QUEUE_A, Channel.FALLBACK_QUEUE_B ] }
STATION = { "id": 3, "name": "station", "channels": [ Channel.FALLBACK_STATION_FOLDER, Channel.FALLBACK_STATION_PLAYLIST ] }
@property
def id(self):
return self.value["id"]
@property
def channels(self):
return self.value["channels"]
def __str__(self):
return str(self.value["name"])
......@@ -52,30 +61,80 @@ class FallbackType(Enum):
class FallbackManager:
"""
Handles all types of fallbacks in case there is an outage
for the regular radio programme.
Attributes:
config (AuraConfig): The engine configuration
logger (AuraLogger): The logger
mail (AuraMailer): Mail service
scheduler (AuraScheduler): The scheduler
Handles all types of fallbacks in case there is an outage or missing schedules
for the radio programme.
"""
config = None
logger = None
scheduler = None
engine = None
state = None
def __init__(self, scheduler):
def __init__(self, engine):
"""
Constructor
Args:
scheduler (Scheduler): The scheduler
"""
self.config = AuraConfig.config()
self.logger = logging.getLogger("AuraEngine")
self.scheduler = scheduler
self.engine = engine
self.state = {
"fallback_type": FallbackType.NONE,
"previous_fallback_type": None,
"timeslot": None
}
#
# EVENTS
#
def on_timeslot_start(self, timeslot=None):
"""
Some new timeslot has just started.
"""
self.state["timeslot"] = timeslot
def on_timeslot_end(self, timeslot):
"""
The timeslot has ended and the state is updated. The method ensures that any intermediate state update doesn't get overwritten.
"""
if self.state["timeslot"] == timeslot:
self.state["timeslot"] = None
def on_play(self, entry):
"""
Event Handler which is called by the engine when some entry is actually playing.
Args:
source (String): The `PlaylistEntry` object
"""
self.update_fallback_state(entry.channel)
def on_metadata(self, data):
"""
Event called by the soundsystem implementation (i.e. Liquidsoap) when some entry is actually playing.
This does not include live or stream sources, since they ain't have metadata and are triggered from
engine core (see `on_play(..)`).
Args:
data (dict): A collection of metadata related to the current track
"""
channel = data.get("source")
fallback_type = self.update_fallback_state(channel)
# If we turned into a fallback state we issue an event
if fallback_type is not FallbackType.NONE:
# Only trigger the event the upon first state change
if fallback_type != self.state.get("previous_fallback_type"):
self.engine.event_dispatcher.on_fallback_active(self.state["timeslot"], fallback_type)
#
......@@ -83,6 +142,32 @@ class FallbackManager:
#
def update_fallback_state(self, channel):
"""
Update the current and previously active fallback state.
Returns:
(FallbackType): The current fallback
"""
fallback_type = self.type_for_channel(channel)
self.state["previous_fallback_type"] = self.state["fallback_type"]
self.state["fallback_type"] = fallback_type
return fallback_type
def type_for_channel(self, source):
"""
Retrieves the matching fallback type for the given source.
"""
if source in [str(i) for i in FallbackType.SCHEDULE.channels]:
return FallbackType.SCHEDULE
if source in [str(i) for i in FallbackType.SHOW.channels]:
return FallbackType.SHOW
if source in [str(i) for i in FallbackType.STATION.channels]:
return FallbackType.STATION
return FallbackType.NONE
def queue_fallback_playlist(self, timeslot):
"""
Evaluates the scheduled fallback and queues it using a timed thread.
......@@ -198,6 +283,7 @@ class FallbackCommand(EngineExecutor):
are created.
"""
def __init__(self, timeslot, entries):
"""
Constructor
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment