cfr #121 Co-authored-by: Christophe Siraut <d@tobald.eu.org> Co-authored-by: bkfox <thomas bkfox net> Co-authored-by: Thomas Kairos <thomas@bkfox.net> Reviewed-on: #131 Co-authored-by: Chris Tactic <ctactic@noreply.git.radiocampus.be> Co-committed-by: Chris Tactic <ctactic@noreply.git.radiocampus.be>
144 lines
4.0 KiB
Python
Executable File
144 lines
4.0 KiB
Python
Executable File
import os
|
|
import tzlocal
|
|
|
|
from aircox.utils import to_seconds
|
|
|
|
from ..conf import settings
|
|
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(f"var.get {self.id}_meta", parse_json=True)
|
|
if data:
|
|
self.validate(data if data and isinstance(data, (dict, list)) else {}, as_dict=True)
|
|
|
|
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 = settings.get_dir(self.station, f"{self.id}.m3u")
|
|
|
|
def get_sound_queryset(self):
|
|
"""Get playlist's sounds queryset."""
|
|
return self.program.sound_set.broadcast()
|
|
|
|
def get_playlist(self):
|
|
"""Get playlist from db."""
|
|
return self.get_sound_queryset().playlist()
|
|
|
|
def write_playlist(self, playlist=[]):
|
|
"""Write playlist to file."""
|
|
playlist = playlist or self.get_playlist()
|
|
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:
|
|
print(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(" ")
|