fix some issues, make the liquidsoap monitor working

This commit is contained in:
bkfox
2015-11-23 02:04:37 +01:00
parent 25e3d4cb53
commit edfdd94eda
8 changed files with 88 additions and 123 deletions

View File

@ -1,10 +1,7 @@
"""
Control Liquidsoap
"""
import os
import re
import datetime
import collections
import time
from argparse import RawTextHelpFormatter
from django.core.management.base import BaseCommand, CommandError
@ -14,74 +11,6 @@ import aircox_liquidsoap.settings as settings
import aircox_liquidsoap.utils as utils
import aircox_programs.models as models
class DiffusionInfo:
date = None
original = None
sounds = None
duration = 0
def __init__ (self, diffusion):
episode = diffusion.episode
self.original = diffusion
self.sounds = [ sound for sound in episode.sounds
if sound.type = models.Sound.Type['archive'] ]
self.sounds.sort(key = 'path')
self.date = diffusion.date
self.duration = episode.get_duration()
self.end = self.date + tz.datetime.timedelta(seconds = self.duration)
def __eq___ (self, info):
return self.original.id == info.original.id
class ControllerMonitor:
current = None
queue = None
def get_next (self, controller):
upcoming = models.Diffusion.get_next(
station = controller.station,
# diffusion__episode__not blank
# diffusion__episode__sounds not blank
)
return Monitor.Info(upcoming[0]) if upcoming else None
def playlist (self, controller):
dealer = controller.dealer
on_air = dealer.current_sound
playlist = dealer.playlist
next = self.queue[0]
# last track: time to reload playlist
if on_air == playlist[-1] or on_air not in playlist:
dealer.playlist = [sound.path for sound in next.sounds]
dealer.on = False
def current (self, controller):
# time to switch...
if on_air not in self.current.sounds:
self.current = self.queue.popleft()
if self.current.date <= tz.datetime.now() and not dealer.on:
dealer.on = True
print('start ', self.current.original)
# HERE
upcoming = self.get_next(controller)
if upcoming.date <= tz.datetime.now() and not self.current:
self.current = upcoming
if not self.upcoming or upcoming != self.upcoming:
dealer.playlist = [sound.path for sound in upcomming.sounds]
dealer.on = False
self.upcoming = upcoming
class Command (BaseCommand):
help= __doc__
@ -98,24 +27,27 @@ class Command (BaseCommand):
help='Runs in monitor mode'
)
parser.add_argument(
'-s', '--sleep', type=int,
default=1,
help='Time to sleep before update'
'-d', '--delay', type=int,
default=1000,
help='Time to sleep in milliseconds before update on monitor'
)
# start and run liquidsoap
def handle (self, *args, **options):
connector = utils.Connector()
self.monitor = utils.Monitor()
self.monitor = utils.Monitor(connector)
self.monitor.update()
if options.get('on_air'):
for id, controller in self.monitor.controller.items():
print(id, controller.master.current_sound())
if options.get('monitor'):
sleep =
delay = options.get('delay') / 1000
while True:
for controller in self.monitor.controllers.values():
controller.dealer.monitor()
time.sleep(delay)

View File

@ -1,11 +1,6 @@
{# Utilities #}
def interactive_source (id, s, ) = \
def apply_metadata(m) = \
m = json_of(compact=true, m) \
ignore(interactive.string('#{id}_meta', m)) \
end \
\
s = on_metadata(id = id, apply_metadata, s) \
s = store_metadata(id=id, size=1, s) \
add_skip_command(s) \
s \
end \

View File

@ -4,6 +4,7 @@ import re
import json
from django.utils.translation import ugettext as _, ugettext_lazy
from django.utils import timezone as tz
from aircox_programs.utils import to_timedelta
import aircox_programs.models as models
@ -50,10 +51,10 @@ class Connector:
data = bytes(''.join([str(d) for d in data]) + '\n', encoding='utf-8')
try:
reg = re.compile('(.*)[\n\r]+END[\n\r]*$')
reg = re.compile(r'(.*)\s+END\s*$')
self.__socket.sendall(data)
data = ''
while not reg.match(data):
while not reg.search(data):
data += self.__socket.recv(1024).decode('unicode_escape')
if data:
@ -166,7 +167,7 @@ class Source:
@property
def current_sound (self):
self.update()
self.metadata['initial_uri']
self.metadata.get('initial_uri')
def stream_info (self):
"""
@ -201,15 +202,29 @@ class Source:
Return -1 in case no update happened
"""
if metadata:
if metadata is not None:
source = metadata.get('source') or ''
if self.program and not source.startswith(self.id):
return -1
self.metadata = metadata
return
r = self.connector.send('var.get ', self.id + '_meta', parse_json=True)
return self.update(metadata = r) if r else -1
# r = self.connector.send('var.get ', self.id + '_meta', parse_json=True)
r = self.connector.send(self.id, '.get', parse=True)
return self.update(metadata = r or {})
class Master (Source):
"""
A master Source
"""
def update (self, metadata = None):
if metadata is not None:
return super().update(metadata)
r = self.connector.send('request.on_air')
r = self.connector.send('request.metadata ', r, parse = True)
return self.update(metadata = r or {})
class Dealer (Source):
@ -221,7 +236,7 @@ class Dealer (Source):
@property
def id (self):
return self.station.name + '_dealer'
return self.station.slug + '_dealer'
def stream_info (self):
pass
@ -257,31 +272,24 @@ class Dealer (Source):
file.write('\n'.join(sounds))
def __get_queue (self, date):
def __get_next (self, date, on_air):
"""
Return a list of diffusion candidates of being running right now.
Add an attribute "sounds" with the episode's archives.
Return which diffusion should be played now and not playing
"""
r = [ models.Diffusion.get_prev(self.station, date),
models.Diffusion.get_next(self.station, date) ]
r = [ diffusion.prefetch_related('episode__sounds')[0]
r = [ diffusion.prefetch_related('sounds')[0]
for diffusion in r if diffusion.count() ]
for diffusion in r:
setattr(diffusion, 'sounds',
[ sound.path for sound in diffusion.get_sounds() ])
return r
def __what_now (self, date, on_air, queue):
"""
Return which diffusion is on_air from the given queue
"""
for diffusion in queue:
duration = diffusion.archives_duration()
end_at = diffusion.date + tz.timedelta(seconds = diffusion.archives_duration())
for diffusion in r:
duration = to_timedelta(diffusion.archives_duration())
end_at = diffusion.date + duration
if end_at < date:
continue
if diffusion.sounds and on_air in diffusion.sounds:
diffusion.playlist = [ sound.path
for sound in diffusion.get_archives() ]
if diffusion.playlist and on_air not in diffusion.playlist:
return diffusion
def monitor (self):
@ -289,12 +297,25 @@ class Dealer (Source):
Monitor playlist (if it is time to load) and if it time to trigger
the button to start a diffusion.
"""
on_air = self.current_soudn
playlist = self.playlist
on_air = self.current_sound
now = tz.make_aware(tz.datetime.now())
queue = self.__get_queue()
current_diffusion = self.__what_now()
diff = self.__get_next(now, on_air)
if not diff:
return # there is nothing we can do
# playlist reload
if self.playlist != diff.playlist:
if not playlist or on_air == playlist[-1] or \
on_air not in playlist:
self.on = False
self.playlist = diff.playlist
# run the diff
if self.playlist == diff.playlist and diff.date <= now:
# FIXME: log
self.on = True
class Controller:
@ -324,7 +345,7 @@ class Controller:
self.station = station
self.station.controller = self
self.master = Source(self)
self.master = Master(self)
self.dealer = Dealer(self)
self.streams = {
source.id : source