forked from rc/aircox
- Writes tests for aircox streamer application; - Add test utilities in aircox Co-authored-by: bkfox <thomas bkfox net> Reviewed-on: rc/aircox#110
This commit is contained in:
141
aircox_streamer/controllers/sources.py
Executable file
141
aircox_streamer/controllers/sources.py
Executable file
@ -0,0 +1,141 @@
|
||||
import os
|
||||
import tzlocal
|
||||
|
||||
from aircox.utils import to_seconds
|
||||
|
||||
from .metadata import Metadata, Request
|
||||
|
||||
|
||||
__all__ = (
|
||||
"Source",
|
||||
"PlaylistSource",
|
||||
"QueueSource",
|
||||
)
|
||||
|
||||
local_tz = tzlocal.get_localzone()
|
||||
|
||||
|
||||
class Source(Metadata):
|
||||
controller = None
|
||||
"""Parent controller."""
|
||||
id = None
|
||||
"""Source id."""
|
||||
remaining = 0.0
|
||||
"""Remaining time."""
|
||||
status = "stopped"
|
||||
|
||||
@property
|
||||
def station(self):
|
||||
return self.controller.station
|
||||
|
||||
def __init__(self, controller=None, id=None, *args, **kwargs):
|
||||
super().__init__(controller, *args, **kwargs)
|
||||
self.id = id
|
||||
|
||||
def sync(self):
|
||||
"""Synchronize what should be synchronized."""
|
||||
|
||||
def fetch(self):
|
||||
try:
|
||||
data = self.controller.send(self.id, ".remaining")
|
||||
if data:
|
||||
self.remaining = float(data)
|
||||
except ValueError:
|
||||
self.remaining = None
|
||||
|
||||
data = self.controller.send(self.id, ".get", parse=True)
|
||||
if data:
|
||||
self.validate(data if data and isinstance(data, dict) else {})
|
||||
|
||||
def skip(self):
|
||||
"""Skip the current source sound."""
|
||||
self.controller.send(self.id, ".skip")
|
||||
|
||||
def restart(self):
|
||||
"""Restart current sound."""
|
||||
# seek 10 hours back since there is not possibility to get current pos
|
||||
self.seek(-216000 * 10)
|
||||
|
||||
def seek(self, n):
|
||||
"""Seeks into the sound."""
|
||||
self.controller.send(self.id, ".seek ", str(n))
|
||||
|
||||
|
||||
class PlaylistSource(Source):
|
||||
"""Source handling playlists (program streams)"""
|
||||
|
||||
path = None
|
||||
"""Path to playlist."""
|
||||
program = None
|
||||
"""Related program."""
|
||||
playlist = None
|
||||
"""The playlist."""
|
||||
|
||||
def __init__(self, controller, id=None, program=None, **kwargs):
|
||||
id = program.slug.replace("-", "_") if id is None else id
|
||||
self.program = program
|
||||
|
||||
super().__init__(controller, id=id, **kwargs)
|
||||
self.path = os.path.join(self.station.path, f"{self.id}.m3u")
|
||||
|
||||
def get_sound_queryset(self):
|
||||
"""Get playlist's sounds queryset."""
|
||||
return self.program.sound_set.archive()
|
||||
|
||||
def get_playlist(self):
|
||||
"""Get playlist from db."""
|
||||
return self.get_sound_queryset().playlist()
|
||||
|
||||
def write_playlist(self, playlist=[]):
|
||||
"""Write playlist to file."""
|
||||
os.makedirs(os.path.dirname(self.path), exist_ok=True)
|
||||
with open(self.path, "w") as file:
|
||||
file.write("\n".join(playlist or []))
|
||||
|
||||
def stream(self):
|
||||
"""Return program's stream info if any (or None) as dict."""
|
||||
# used in templates
|
||||
# TODO: multiple streams
|
||||
stream = self.program.stream_set.all().first()
|
||||
if not stream or (not stream.begin and not stream.delay):
|
||||
return
|
||||
|
||||
return {
|
||||
"begin": stream.begin.strftime("%Hh%M") if stream.begin else None,
|
||||
"end": stream.end.strftime("%Hh%M") if stream.end else None,
|
||||
"delay": to_seconds(stream.delay) if stream.delay else 0,
|
||||
}
|
||||
|
||||
def sync(self):
|
||||
playlist = self.get_playlist()
|
||||
self.write_playlist(playlist)
|
||||
|
||||
|
||||
class QueueSource(Source):
|
||||
queue = None
|
||||
"""Source's queue (excluded on_air request)"""
|
||||
|
||||
@property
|
||||
def requests(self):
|
||||
"""Queue as requests metadata."""
|
||||
requests = [Request(self.controller, rid) for rid in self.queue]
|
||||
for request in requests:
|
||||
request.fetch()
|
||||
return requests
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def push(self, *paths):
|
||||
"""Add the provided paths to source's play queue."""
|
||||
for path in paths:
|
||||
self.controller.send(f"{self.id}_queue.push {path}")
|
||||
|
||||
def fetch(self):
|
||||
super().fetch()
|
||||
queue = self.controller.send(f"{self.id}_queue.queue").strip()
|
||||
if not queue:
|
||||
self.queue = []
|
||||
return
|
||||
|
||||
self.queue = queue.split(" ")
|
Reference in New Issue
Block a user