Commit 6eafd4eb authored by David Trattnig's avatar David Trattnig
Browse files

Scheduler cmds inherit from EngineExecutor. #41

parent 92e5c12a
......@@ -88,7 +88,7 @@ class PlayerConnector():
"queue_clear",
"playlist_uri_set",
"playlist_uri_clear",
"stream_set_ur",
"stream_set_url",
"stream_start",
"stream_stop",
"stream_status",
......
......@@ -341,10 +341,7 @@ class Player:
self.connector.disable_transaction()
Thread(target=clean_up).start()
# Filesystem meta-changes trigger the event via Liquidsoap, so only
# issue event for LIVE and STREAM:
if not entry.channel in ChannelType.QUEUE.channels:
self.event_dispatcher.on_play(entry)
self.event_dispatcher.on_play(entry)
......@@ -386,6 +383,7 @@ class Player:
self.event_dispatcher.on_fallback_updated(entries)
def stop_fallback_playlist(self):
"""
Performs a fade-out and clears any scheduled fallback playlist.
......@@ -548,7 +546,14 @@ class Player:
self.connector.disable_transaction()
# If successful, Liquidsoap returns a resource ID of the queued track
return int(result) >= 0
resource_id = -1
try:
resource_id = int(result)
except ValueError:
self.logger.error(SU.red("Got an invalid resource ID: '%s'" % result))
return False
return resource_id >= 0
......
......@@ -220,15 +220,18 @@ class EngineEventDispatcher():
def on_play(self, entry):
"""
Event Handler which is called by the engine when some entry is actually playing.
Event Handler which is called by the engine when some play command to Liquidsoap is issued.
This does not indiciate that Liquidsoap started playing actually, only that the command has
been issued. To get the metadata update issued by Liquidsoap use `on_metadata` instead.
Args:
source (String): The `PlaylistEntry` object
"""
def func(self, entry):
self.logger.debug("on_play(..)")
# Assign timestamp for play time
# Assign timestamp indicating start play time. Use the actual playtime when possible.
entry.entry_start_actual = datetime.datetime.now()
self.scheduler.on_play(entry)
self.call_event("on_play", entry)
thread = Thread(target = func, args = (self, entry))
......
......@@ -100,7 +100,7 @@ class AuraCalendarService(threading.Thread):
return
# Check if existing timeslots have been deleted
local_timeslots = Timeslot.select_programme(datetime.now())
local_timeslots = Timeslot.get_timeslots(datetime.now())
for local_timeslot in local_timeslots:
# Only allow deletion of timeslots which are deleted before the start of the scheduling window
......@@ -169,7 +169,7 @@ class AuraCalendarService(threading.Thread):
Args:
timeslot (Timeslot): The timeslot
"""
timeslot_db = Timeslot.select_show_on_datetime(timeslot["start"])
timeslot_db = Timeslot.for_datetime(timeslot["start"])
havetoadd = False
if not timeslot_db:
......
......@@ -26,7 +26,7 @@ from datetime import timedelta
from src.base.config import AuraConfig
from src.base.utils import SimpleUtil as SU
from src.core.resources import ResourceClass
from src.core.resources import ResourceClass, ResourceUtil
from src.core.channels import Channel
from src.core.control import EngineExecutor
......@@ -113,7 +113,12 @@ class FallbackManager:
Args:
source (String): The `PlaylistEntry` object
"""
"""
content_class = ResourceUtil.get_content_class(entry.get_content_type())
if content_class == ResourceClass.FILE:
# Files are handled by "on_metadata" called via Liquidsoap
return
self.update_fallback_state(entry.channel)
......@@ -306,5 +311,5 @@ class FallbackCommand(EngineExecutor):
end_time_offset = int(float(AuraConfig.config().get("fade_out_time")) / 2 * 1000 * -1)
end_time = SU.timestamp(timeslot.timeslot_end + timedelta(milliseconds=end_time_offset))
self.logger.info(f"Starting fade-out of scheduled fallback with an offset of {end_time_offset} milliseconds at {end_time}")
child_timer = EngineExecutor("FALLBACK", None, end_time, do_stop, None)
super().__init__("FALLBACK", child_timer, timeslot.start_unix, do_play, entries)
\ No newline at end of file
super().__init__("FALLBACK", None, timeslot.start_unix, do_play, entries)
EngineExecutor("FALLBACK", self, end_time, do_stop, None)
\ No newline at end of file
......@@ -167,16 +167,23 @@ class Timeslot(DB.Model, AuraDatabaseModel):
musicfocus = Column(String(256))
is_repetition = Column(Boolean())
fadeouttimer = None # Used to fade-out the timeslot, even when entries are longer
# Transients
active_entry = None
@staticmethod
def select_show_on_datetime(date_time):
def for_datetime(date_time):
"""
Select a timeslot at the given datetime.
Args:
date_time (datetime): date and time when the timeslot starts
"""
return DB.session.query(Timeslot).filter(Timeslot.timeslot_start == date_time).first()
@staticmethod
def select_programme(date_from=datetime.date.today()):
def get_timeslots(date_from=datetime.date.today()):
"""
Select all timeslots starting from `date_from` or from today if no
parameter is passed.
......@@ -189,34 +196,26 @@ class Timeslot(DB.Model, AuraDatabaseModel):
"""
timeslots = DB.session.query(Timeslot).\
filter(Timeslot.timeslot_start >= date_from).\
order_by(Timeslot.timeslot_start).all()
order_by(Timeslot.timeslot_start).all()
return timeslots
@staticmethod
def select_upcoming(n):
def set_active_entry(self, entry):
"""
Selects the (`n`) upcoming timeslots.
Sets the currently playing entry.
Args:
entry (PlaylistEntry): The entry playing right now
"""
now = datetime.datetime.now()
DB.session.commit() # Required since independend session is used.
timeslots = DB.session.query(Timeslot).\
filter(Timeslot.timeslot_start > str(now)).\
order_by(Timeslot.timeslot_start.asc()).limit(n).all()
return timeslots
self.active_entry = entry
def has_queued_entries(self):
def get_recent_entry(self):
"""
Checks if entries of this timeslot have been queued at the engine.
Retrieves the most recent played or currently playing entry. This is used to fade-out
the timeslot, when there is no other entry is following the current one.
"""
#TODO Make logic more transparent
if hasattr(self, "queued_entries"):
if len(self.queued_entries) > 0:
return True
return False
return self.active_entry
@hybrid_property
......@@ -332,9 +331,7 @@ class Playlist(DB.Model, AuraDatabaseModel):
"""
playlist = None
playlists = DB.session.query(Playlist).filter(Playlist.timeslot_start == start_date).all()
# FIXME There are unknown issues with the native SQL query by ID
# playlists = DB.session.query(Playlist).filter(Playlist.timeslot_start == datetime and Playlist.playlist_id == playlist_id).all()
for p in playlists:
if p.playlist_id == playlist_id:
playlist = p
......@@ -450,13 +447,11 @@ class PlaylistEntry(DB.Model, AuraDatabaseModel):
source = Column(String(1024))
entry_start = Column(DateTime)
# Transients
entry_start_actual = None # Assigned when the entry is actually played
channel = None # Assigned when entry is actually played
queue_state = None # Assigned when entry is about to be queued
status = None # Assigned when state changes
switchtimer = None
loadtimer = None
fadeouttimer = None
@staticmethod
......
......@@ -104,7 +104,7 @@ class Programme():
them via `self.enable_entries(..)`. After that, the
current message queue is printed to the console.
"""
self.programme = Timeslot.select_programme()
self.programme = Timeslot.get_timeslots()
if not self.programme:
self.logger.critical(SU.red("Could not load programme from database. We are in big trouble my friend!"))
......
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment