Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Lars Kruse
aura-engine
Commits
94c38f18
Commit
94c38f18
authored
Jul 29, 2021
by
david
Browse files
Default playlists for show and schedule-level. #52
parent
e87be140
Changes
9
Show whitespace changes
Inline
Side-by-side
src/engine.py
View file @
94c38f18
...
...
@@ -374,41 +374,41 @@ class Player:
def
start_fallback_playlist
(
self
,
entries
):
"""
Sets any scheduled fallback playlist and performs a fade-in.
Args:
entries ([Entry]): The playlist entries
"""
self
.
preload_group
(
entries
,
ChannelType
.
FALLBACK_QUEUE
)
self
.
play
(
entries
[
0
],
TransitionType
.
FADE
)
self
.
event_dispatcher
.
on_fallback_updated
(
entries
)
def
stop_fallback_playlist
(
self
):
"""
Performs a fade-out and clears any scheduled fallback playlist.
"""
dirty_channel
=
self
.
channel_router
.
get_active
(
ChannelType
.
FALLBACK_QUEUE
)
self
.
logger
.
info
(
f
"Fading out channel '
{
dirty_channel
}
'"
)
self
.
connector
.
enable_transaction
()
self
.
mixer_fallback
.
fade_out
(
dirty_channel
)
self
.
connector
.
disable_transaction
()
def
clean_up
():
# Wait a little, if there is some long fade-out. Note, this also means,
# this channel should not be used for at least some seconds (including clearing time).
time
.
sleep
(
2
)
self
.
connector
.
enable_transaction
()
self
.
mixer_fallback
.
channel_activate
(
dirty_channel
.
value
,
False
)
res
=
self
.
queue_clear
(
dirty_channel
)
self
.
logger
.
info
(
"Clear Fallback Queue Response: "
+
res
)
self
.
connector
.
disable_transaction
()
self
.
event_dispatcher
.
on_fallback_cleaned
(
dirty_channel
)
Thread
(
target
=
clean_up
).
start
()
#
def start_fallback_playlist(self, entries):
#
"""
#
Sets any scheduled fallback playlist and performs a fade-in.
#
Args:
#
entries ([Entry]): The playlist entries
#
"""
#
self.preload_group(entries, ChannelType.FALLBACK_QUEUE)
#
self.play(entries[0], TransitionType.FADE)
#
self.event_dispatcher.on_fallback_updated(entries)
#
def stop_fallback_playlist(self):
#
"""
#
Performs a fade-out and clears any scheduled fallback playlist.
#
"""
#
dirty_channel = self.channel_router.get_active(ChannelType.FALLBACK_QUEUE)
#
self.logger.info(f"Fading out channel '{dirty_channel}'")
#
self.connector.enable_transaction()
#
self.mixer_fallback.fade_out(dirty_channel)
#
self.connector.disable_transaction()
#
def clean_up():
#
# Wait a little, if there is some long fade-out. Note, this also means,
#
# this channel should not be used for at least some seconds (including clearing time).
#
time.sleep(2)
#
self.connector.enable_transaction()
#
self.mixer_fallback.channel_activate(dirty_channel.value, False)
#
res = self.queue_clear(dirty_channel)
#
self.logger.info("Clear Fallback Queue Response: " + res)
#
self.connector.disable_transaction()
#
self.event_dispatcher.on_fallback_cleaned(dirty_channel)
#
Thread(target=clean_up).start()
...
...
src/events.py
View file @
94c38f18
...
...
@@ -268,30 +268,30 @@ class EngineEventDispatcher():
thread
.
start
()
def
on_fallback_updated
(
self
,
playlist_uri
):
"""
Called when the scheduled fallback playlist has been updated.
This event does not indicate that the fallback is actually playing.
"""
def
func
(
self
,
playlist_uri
):
self
.
logger
.
debug
(
"on_fallback_updated(..)"
)
self
.
call_event
(
"on_fallback_updated"
,
playlist_uri
)
thread
=
Thread
(
target
=
func
,
args
=
(
self
,
playlist_uri
))
thread
.
start
()
def
on_fallback_cleaned
(
self
,
cleaned_channel
):
"""
Called when the scheduled fallback queue has been cleaned up.
This event does not indicate that some fallback is actually playing.
"""
def
func
(
self
,
cleaned_channel
):
self
.
logger
.
debug
(
"on_fallback_cleaned(..)"
)
self
.
call_event
(
"on_fallback_cleaned"
,
cleaned_channel
)
thread
=
Thread
(
target
=
func
,
args
=
(
self
,
cleaned_channel
))
thread
.
start
()
#
def on_fallback_updated(self, playlist_uri):
#
"""
#
Called when the scheduled fallback playlist has been updated.
#
This event does not indicate that the fallback is actually playing.
#
"""
#
def func(self, playlist_uri):
#
self.logger.debug("on_fallback_updated(..)")
#
self.call_event("on_fallback_updated", playlist_uri)
#
thread = Thread(target = func, args = (self, playlist_uri))
#
thread.start()
#
def on_fallback_cleaned(self, cleaned_channel):
#
"""
#
Called when the scheduled fallback queue has been cleaned up.
#
This event does not indicate that some fallback is actually playing.
#
"""
#
def func(self, cleaned_channel):
#
self.logger.debug("on_fallback_cleaned(..)")
#
self.call_event("on_fallback_cleaned", cleaned_channel)
#
thread = Thread(target = func, args = (self, cleaned_channel))
#
thread.start()
def
on_fallback_active
(
self
,
timeslot
,
fallback_type
):
...
...
src/plugins/trackservice.py
View file @
94c38f18
...
...
@@ -22,7 +22,6 @@ import logging
import
requests
from
collections
import
deque
from
datetime
import
datetime
,
timedelta
from
src.base.config
import
AuraConfig
from
src.base.utils
import
SimpleUtil
as
SU
...
...
@@ -181,7 +180,7 @@ class TrackServiceHandler():
"""
planned_playlist
=
None
if
self
.
engine
.
scheduler
:
(
fallback
_type
,
planned_playlist
)
=
self
.
engine
.
scheduler
.
get_active_playlist
()
(
playlist
_type
,
planned_playlist
)
=
self
.
engine
.
scheduler
.
get_active_playlist
()
(
past_timeslot
,
current_timeslot
,
next_timeslot
)
=
self
.
playlog
.
get_timeslots
()
data
=
dict
()
...
...
@@ -349,21 +348,29 @@ class Playlog:
data ({}): The dictionary holding the (virtual) timeslot
timeslot (Timeslot): The actual timeslot object to retrieve fallback info from
"""
fallback
_type
=
None
playlist
_type
=
None
playlist
=
None
if
timeslot
:
fallback
_type
,
playlist
=
self
.
engine
.
scheduler
.
fallback
.
resolve_playlist
(
timeslot
)
playlist
_type
,
playlist
=
self
.
engine
.
scheduler
.
resolve_playlist
(
timeslot
)
if
playlist
:
data
[
"playlist_id"
]
=
playlist
.
playlist_id
else
:
data
[
"playlist_id"
]
=
-
1
if
fallback_type
:
data
[
"fallback_type"
]
=
fallback_type
.
id
else
:
data
[
"fallback_type"
]
=
FallbackType
.
STATION
.
id
#FIXME "fallback_type" should be a more generic "playout_state"? (compare meta#42)
#FIXME Add field for "playlist_type", which now differs from playout-state
#FIXME Remove dependency to "scheduler" and "scheduler.fallback" module
data
[
"fallback_type"
]
=
0
if
self
.
engine
.
scheduler
:
playout_state
=
self
.
engine
.
scheduler
.
fallback
.
get_playout_state
()
data
[
"fallback_type"
]
=
playout_state
.
id
# if playlist_type:
# data["fallback_type"] = playlist_type.id
# else:
# data["fallback_type"] = FallbackType.STATION.id
def
get_timeslots
(
self
):
...
...
src/scheduling/api.py
View file @
94c38f18
...
...
@@ -121,12 +121,11 @@ class ApiFetcher(threading.Thread):
for
timeslot
in
self
.
fetched_timeslot_data
:
# FIXME Workaround until https://gitlab.servus.at/aura/steering/-/issues/54 is implemented
if
"schedule_fallback_id"
in
timeslot
:
timeslot
[
"default_schedule_playlist_id"
]
=
timeslot
[
"schedule_fallback_id"
]
if
"schedule_default_playlist_id"
in
timeslot
:
timeslot
[
"default_schedule_playlist_id"
]
=
timeslot
[
"schedule_default_playlist_id"
]
timeslot
[
"schedule_fallback_id"
]
=
None
if
"show_
fallback
_id"
in
timeslot
:
timeslot
[
"default_show_playlist_id"
]
=
timeslot
[
"show_
fallback
_id"
]
if
"show_
default_playlist
_id"
in
timeslot
:
timeslot
[
"default_show_playlist_id"
]
=
timeslot
[
"show_
default_playlist
_id"
]
timeslot
[
"show_fallback_id"
]
=
None
self
.
logger
.
debug
(
"Fetching playlists from TANK"
)
...
...
src/scheduling/fallback.py
View file @
94c38f18
...
...
@@ -36,14 +36,12 @@ class FallbackType(Enum):
"""
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: No fallback active, default playout as planned
STATION: The station fallback is 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
]
}
#
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
...
...
@@ -61,8 +59,7 @@ class FallbackType(Enum):
class
FallbackManager
:
"""
Handles all types of fallbacks in case there is an outage or missing schedules
for the radio programme.
Manages if engine is in normal or fallback play-state.
"""
config
=
None
logger
=
None
...
...
@@ -151,6 +148,13 @@ class FallbackManager:
#
def
get_playout_state
(
self
):
"""
Returns the current playout state, like normal or fallback.
"""
return
self
.
state
[
"fallback_type"
]
def
update_fallback_state
(
self
,
channel
):
"""
Update the current and previously active fallback state.
...
...
@@ -168,151 +172,150 @@ class FallbackManager:
"""
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.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.
"""
(
fallback_type
,
playlist
)
=
self
.
get_fallback_playlist
(
timeslot
)
#
def queue_fallback_playlist(self, timeslot):
#
"""
#
Evaluates the scheduled fallback and queues it using a timed thread.
#
"""
#
(fallback_type, playlist) = self.get_fallback_playlist(timeslot)
if
playlist
:
self
.
logger
.
info
(
f
"Resolved
{
fallback_type
.
value
}
fallback"
)
return
FallbackCommand
(
timeslot
,
playlist
.
entries
)
else
:
msg
=
f
"There is no timeslot- or show-
fallback
defined for timeslot#
{
timeslot
.
timeslot_id
}
. "
msg
+=
f
"The station fallback will be used automatically."
self
.
logger
.
info
(
msg
)
#
if playlist:
#
self.logger.info(f"Resolved {fallback_type.value} fallback")
#
return FallbackCommand(timeslot, playlist.entries)
#
else:
#
msg = f"There is no
fallback playlist on
timeslot- or show-
level
defined for timeslot#{timeslot.timeslot_id}. "
#
msg += f"The station fallback will be used automatically."
#
self.logger.info(msg)
def
resolve_playlist
(
self
,
timeslot
):
"""
Retrieves the currently planned
(
fallback
)
playlist. If a normal playlist is available,
this one is returned. In case of station fallback no playlist is returned.
#
def resolve_playlist(self, timeslot):
#
"""
#
Retrieves the currently planned
, default or
fallback playlist. If a normal playlist is available,
#
this one is returned. In case of
a
station fallback
to be triggered,
no playlist is returned.
Args:
timeslot (Timeslot)
#
Args:
#
timeslot (Timeslot)
Returns:
(FallbackType, Playlist)
"""
fallback_type
=
None
planned_playlist
=
self
.
engine
.
scheduler
.
programme
.
get_current_playlist
(
timeslot
)
# Returns:
# (FallbackType, Playlist)
# """
# (playlist_type, planned_playlist) = self.engine.scheduler.programme.get_current_playlist(timeslot)
if
planned_playlist
:
fallback
_type
=
FallbackType
.
NONE
else
:
(
fallback
_type
,
planned_playlist
)
=
self
.
get_fallback_playlist
(
timeslot
)
#
if planned_playlist:
#
playlist
_type = FallbackType.NONE
#
else:
#
(
playlist
_type, planned_playlist) = self.get_fallback_playlist(timeslot)
return
(
fallback
_type
,
planned_playlist
)
#
return (
playlist
_type, planned_playlist)
def
get_fallback_playlist
(
self
,
timeslot
):
"""
Retrieves the playlist to be used in a fallback scenario.
#
def get_fallback_playlist(self, timeslot):
#
"""
#
Retrieves the playlist to be used in a fallback scenario.
Args:
timeslot (Timeslot)
#
Args:
#
timeslot (Timeslot)
Returns:
(Playlist)
"""
playlist
=
None
fallback_type
=
FallbackType
.
STATION
#
Returns:
#
(Playlist)
#
"""
#
playlist = None
#
fallback_type = FallbackType.STATION
if
self
.
validate_playlist
(
timeslot
,
"schedule_fallback"
):
playlist
=
timeslot
.
schedule_fallback
fallback_type
=
FallbackType
.
SCHEDULE
elif
self
.
validate_playlist
(
timeslot
,
"show_fallback"
):
playlist
=
timeslot
.
show_fallback
fallback_type
=
FallbackType
.
SHOW
#
if self.validate_playlist(timeslot, "schedule_fallback"):
#
playlist = timeslot.schedule_fallback
#
fallback_type = FallbackType.SCHEDULE
#
elif self.validate_playlist(timeslot, "show_fallback"):
#
playlist = timeslot.show_fallback
#
fallback_type = FallbackType.SHOW
return
(
fallback_type
,
playlist
)
#
return (fallback_type, playlist)
def
validate_playlist
(
self
,
timeslot
,
playlist_type
):
"""
Checks if a playlist is valid for play-out.
#
def validate_playlist(self, timeslot, playlist_type):
#
"""
#
Checks if a playlist is valid for play-out.
Following checks are done for all playlists:
#
Following checks are done for all playlists:
- has one or more entries
#
- has one or more entries
Fallback playlists should either:
#
Fallback playlists should either:
- have filesystem entries only
- reference a recording of a previous playout of a show (also filesystem)
#
- have filesystem entries only
#
- reference a recording of a previous playout of a show (also filesystem)
Otherwise, if a fallback playlist contains Live or Stream entries,
the exact playout behaviour can hardly be predicted.
"""
playlist
=
getattr
(
timeslot
,
playlist_type
)
if
playlist
\
and
playlist
.
entries
\
and
len
(
playlist
.
entries
)
>
0
:
#
Otherwise, if a fallback playlist contains Live or Stream entries,
#
the exact playout behaviour can hardly be predicted.
#
"""
#
playlist = getattr(timeslot, playlist_type)
#
if playlist \
#
and playlist.entries \
#
and len(playlist.entries) > 0:
# Default playlist
if
playlist_type
==
"playlist"
:
return
True
#
# Default playlist
#
if playlist_type == "playlist":
#
return True
# Fallback playlist
elif
playlist
.
entries
:
is_fs_only
=
True
for
entry
in
playlist
.
entries
:
if
entry
.
get_content_type
()
not
in
ResourceClass
.
FILE
.
types
:
self
.
logger
.
error
(
SU
.
red
(
"Fallback playlist of type '%s' contains not only file-system entries!
\
Skipping fallback level..."
%
playlist_type
))
is_fs_only
=
False
break
return
is_fs_only
#
# Fallback playlist
#
elif playlist.entries:
#
is_fs_only = True
#
for entry in playlist.entries:
#
if entry.get_content_type() not in ResourceClass.FILE.types:
#
self.logger.error(SU.red("Fallback playlist of type '%s' contains not only file-system entries! \
#
Skipping fallback level..." % playlist_type))
#
is_fs_only = False
#
break
#
return is_fs_only
return
False
#
return False
class
FallbackCommand
(
EngineExecutor
):
"""
Command composition for executing timed scheduling and unscheduling of fallback playlists.
#
class FallbackCommand(EngineExecutor):
#
"""
#
Command composition for executing timed scheduling and unscheduling of fallback playlists.
Based on the `timeslot.start_date` and `timeslot.end_date` two `EngineExecutor commands
are created.
"""
#
Based on the `timeslot.start_date` and `timeslot.end_date` two `EngineExecutor commands
#
are created.
#
"""
def
__init__
(
self
,
timeslot
,
entries
):
"""
Constructor
#
def __init__(self, timeslot, entries):
#
"""
#
Constructor
Args:
timeslot (Timeslot): The timeslot any fallback entries should be scheduled for
entries (List): List of entries to be scheduled as fallback
"""
from
src.engine
import
Engine
def
do_play
(
entries
):
self
.
logger
.
info
(
SU
.
cyan
(
f
"=== start_fallback_playlist('
{
entries
}
') ==="
))
Engine
.
get_instance
().
player
.
start_fallback_playlist
(
entries
)
def
do_stop
():
self
.
logger
.
info
(
SU
.
cyan
(
"=== stop_fallback_playlist() ==="
))
Engine
.
get_instance
().
player
.
stop_fallback_playlist
()
# Start fade-out 50% before the end of the timeslot for a more smooth transition
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
}
"
)
super
().
__init__
(
"FALLBACK"
,
None
,
timeslot
.
start_unix
,
do_play
,
entries
)
EngineExecutor
(
"FALLBACK"
,
self
,
end_time
,
do_stop
,
None
)
\ No newline at end of file
# Args:
# timeslot (Timeslot): The timeslot any fallback entries should be scheduled for
# entries (List): List of entries to be scheduled as fallback
# """
# from src.engine import Engine
# def do_play(entries):
# self.logger.info(SU.cyan(f"=== start_fallback_playlist('{entries}') ==="))
# Engine.get_instance().player.start_fallback_playlist(entries)
# def do_stop():
# self.logger.info(SU.cyan("=== stop_fallback_playlist() ==="))
# Engine.get_instance().player.stop_fallback_playlist()
# # Start fade-out 50% before the end of the timeslot for a more smooth transition
# 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}")
# super().__init__("FALLBACK", None, timeslot.start_unix, do_play, entries)
# EngineExecutor("FALLBACK", self, end_time, do_stop, None)
\ No newline at end of file
src/scheduling/models.py
View file @
94c38f18
...
...
@@ -331,6 +331,11 @@ class Playlist(DB.Model, AuraDatabaseModel):
"""
__tablename__
=
'playlist'
# Static Playlist Types
TYPE_TIMESLOT
=
{
"id"
:
0
,
"name"
:
"timeslot"
}
TYPE_SCHEDULE
=
{
"id"
:
1
,
"name"
:
"schedule"
}
TYPE_SHOW
=
{
"id"
:
2
,
"name"
:
"show"
}
# Primary and Foreign Key
artificial_id
=
Column
(
Integer
,
primary_key
=
True
)
timeslot_start
=
Column
(
DateTime
,
ForeignKey
(
"timeslot.timeslot_start"
))
...
...
@@ -345,19 +350,19 @@ class Playlist(DB.Model, AuraDatabaseModel):
entry_count
=
Column
(
Integer
)
@
staticmethod
def
select_all
():
"""
Fetches all entries
"""
all_entries
=
DB
.
session
.
query
(
Playlist
).
filter
(
Playlist
.
fallback_type
==
0
).
all
()
#
@staticmethod
#
def select_all():
#
"""
#
Fetches all entries
#
"""
#
all_entries = DB.session.query(Playlist).filter(Playlist.fallback_type == 0).all()
cnt
=
0
for
entry
in
all_entries
:
entry
.
programme_index
=
cnt
cnt
=
cnt
+
1
#
cnt = 0
#
for entry in all_entries:
#
entry.programme_index = cnt
#
cnt = cnt + 1
return
all_entries
#
return all_entries
@
staticmethod
...
...
@@ -441,21 +446,21 @@ class Playlist(DB.Model, AuraDatabaseModel):
return
total
def
as_dict
(
self
):
"""
Returns the playlist as a dictionary for serialization.
"""
entries
=
[]
for
e
in
self
.
entries
:
entries
.
append
(
e
.
as_dict
())
playlist
=
{
"playlist_id"
:
self
.
playlist_id
,
"fallback_type"
:
self
.
fallback_type
,
"entry_count"
:
self
.
entry_count
,
"entries"
:
entries
}
return
playlist
#
def as_dict(self):
#
"""
#
Returns the playlist as a dictionary for serialization.
#
"""
#
entries = []
#
for e in self.entries:
#
entries.append(e.as_dict())
#
playlist = {
#
"playlist_id": self.playlist_id,
#
"fallback_type": self.fallback_type,
#
"entry_count": self.entry_count,
#
"entries": entries
#
}
#
return playlist
def
__str__
(
self
):
...
...
src/scheduling/programme.py
View file @
94c38f18
...
...
@@ -117,7 +117,7 @@ class ProgrammeService():
return
None
# Check for scheduled playlist
current_playlist
=
self
.
get_current_playlist
(
current_timeslot
)
playlist_type
,
current_playlist
=
self
.
get_current_playlist
(
current_timeslot
)
if
not
current_playlist
:
msg
=
"There's no (default) playlist assigned to the current timeslot. Most likely a fallback will make things okay again."
self
.
logger
.
warning
(
SU
.
red
(
msg
))
...
...
@@ -132,7 +132,7 @@ class ProgrammeService():
if
not
current_entry
:
# Nothing playing ... fallback will kick-in
msg
=
"There's no entry scheduled for playlist
'%s' at %s"
%
(
str
(
current_playlist
)
,
SU
.
fmt_time
(
now_unix
)
)
msg
=
f
"There's no entry scheduled for
'
{
playlist
_type
.
get
(
'name'
)
}
' playlist '
{
str
(
current_playlist
)
}
' at
{
SU
.
fmt_time
(
now_unix
)
}
"
self
.
logger
.
warning
(
SU
.
red
(
msg
))
return
None
...
...
@@ -170,13 +170,16 @@ class ProgrammeService():
Returns:
(FallbackType, Playlist): The currently assigned playlist
"""
playlist_type
=
Playlist
.
TYPE_TIMESLOT
playlist
=
timeslot
.
playlist
if
not
playlist
:
playlist_type
=
Playlist
.
TYPE_SCHEDULE
playlist
=
timeslot
.
default_schedule_playlist
if
not
playlist
:
playlist_type
=
Playlist
.
TYPE_SHOW
playlist
=
timeslot
.
default_show_playlist
return
playlist
return
(
playlist
_type
,
playlist
)