From 2e985c9b1e9510ef3e4a9f09a7a097e0822884cf Mon Sep 17 00:00:00 2001 From: bkfox Date: Tue, 12 Jul 2016 23:17:12 +0200 Subject: [PATCH] remove liquidsoap application --- README.md | 2 +- liquidsoap/README.md | 14 - liquidsoap/__init__.py | 0 liquidsoap/admin.py | 8 - liquidsoap/management/commands/liquidsoap.py | 257 ------------- liquidsoap/models.py | 26 -- liquidsoap/settings.py | 23 -- .../aircox/liquidsoap/controller.html | 134 ------- .../templates/aircox/liquidsoap/source.html | 14 - .../templates/aircox/liquidsoap/station.liq | 126 ------- liquidsoap/tests.py | 3 - liquidsoap/urls.py | 9 - liquidsoap/utils.py | 356 ------------------ liquidsoap/views.py | 64 ---- 14 files changed, 1 insertion(+), 1035 deletions(-) delete mode 100644 liquidsoap/README.md delete mode 100644 liquidsoap/__init__.py delete mode 100644 liquidsoap/admin.py delete mode 100644 liquidsoap/management/commands/liquidsoap.py delete mode 100644 liquidsoap/models.py delete mode 100644 liquidsoap/settings.py delete mode 100644 liquidsoap/templates/aircox/liquidsoap/controller.html delete mode 100644 liquidsoap/templates/aircox/liquidsoap/source.html delete mode 100644 liquidsoap/templates/aircox/liquidsoap/station.liq delete mode 100644 liquidsoap/tests.py delete mode 100644 liquidsoap/urls.py delete mode 100644 liquidsoap/utils.py delete mode 100644 liquidsoap/views.py diff --git a/README.md b/README.md index 2093089..f145ab1 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Platform to manage a radio, schedules, website, and so on. We use the power of D ## Applications * **programs**: managing stations, programs, schedules and diffusions. This is the core application, that handle most of the work; -* **liquidsoap**: generate configuration and controls over liquidsoap. We use one instance of liquidsoap per station; +* **controllers**: interface with external stream generators. For the moment only support [Liquidsoap](http://liquidsoap.fm/). Generate configuration files, trigger scheduled diffusions and so on; * **cms**: cms manager with reusable tools (can be used in another website application); * **website**: set of common models, sections, and other items ready to be used for a website; diff --git a/liquidsoap/README.md b/liquidsoap/README.md deleted file mode 100644 index de57c80..0000000 --- a/liquidsoap/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Aircox LiquidSoap -This application makes the bridge between Aircox and LiquidSoap. It can monitor scheduled and streamed programs and offer some controls on LiquidSoap. - - -## manage.py's commands -* ** liquidsoap **: monitor LiquidSoap, logs what is playing on the different sources, and plays scheduled diffusions; -* ** liquidsoap_files**: generates playlists and LiquidSoap config based on Programs' parameters; - - -## Requirements -* Liquidsoap -* requirements.txt for python's dependencies - - diff --git a/liquidsoap/__init__.py b/liquidsoap/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/liquidsoap/admin.py b/liquidsoap/admin.py deleted file mode 100644 index ed26b1c..0000000 --- a/liquidsoap/admin.py +++ /dev/null @@ -1,8 +0,0 @@ -from django.contrib import admin -import aircox.liquidsoap.models as models - -@admin.register(models.Output) -class OutputAdmin (admin.ModelAdmin): - list_display = ('id', 'type') - - diff --git a/liquidsoap/management/commands/liquidsoap.py b/liquidsoap/management/commands/liquidsoap.py deleted file mode 100644 index 0d28203..0000000 --- a/liquidsoap/management/commands/liquidsoap.py +++ /dev/null @@ -1,257 +0,0 @@ -""" -Main tool to work with liquidsoap. We can: -- monitor Liquidsoap's sources and do logs, print what's on air. -- generate configuration files and playlists for a given station -""" -import os -import time -import re -import subprocess -import atexit -from argparse import RawTextHelpFormatter - -from django.conf import settings as main_settings -from django.core.management.base import BaseCommand, CommandError -from django.template.loader import render_to_string -from django.utils import timezone as tz - -import aircox.programs.models as programs -import aircox.programs.settings as programs_settings -from aircox.programs.utils import to_timedelta - -import aircox.liquidsoap.settings as settings -import aircox.liquidsoap.utils as utils - - -class Monitor: - @classmethod - def run (cl, controller): - """ - Run once the monitor on the controller - """ - if not controller.connector.available and controller.connector.open(): - return - - cl.run_source(controller.master) - cl.run_dealer(controller) - cl.run_source(controller.dealer) - - for stream in controller.streams.values(): - cl.run_source(stream) - - @staticmethod - def log (**kwargs): - """ - Create a log using **kwargs, and print info - """ - log = programs.Log(**kwargs) - log.save() - log.print() - - @classmethod - def __get_prev_diff(cl, source, played_sounds = True): - diff_logs = programs.Log.get_for_related_model(programs.Diffusion) \ - .filter(source = source.id) \ - .order_by('-date') - if played_sounds: - sound_logs = programs.Log.get_for_related_model(programs.Sound) \ - .filter(source = source.id) \ - .order_by('-date') - if not diff_logs: - return - - diff = diff_logs[0].related_object - playlist = diff.playlist - if played_sounds: - diff.played = [ sound.related_object.path - for sound in sound_logs[0:len(playlist)] - if sound.type = program.Logs.Type.switch ] - return diff - - @classmethod - def run_dealer(cl, controller): - # - this function must recover last state in case of crash - # -> don't store data out of hdd - # - construct gradually the playlist and update it if needed - # -> we force liquidsoap to preload tracks of next diff - # - dealer.on while last logged diff is playing, otherwise off - # - when next diff is now and last diff no more active, play it - # -> log and dealer.on - dealer = controller.dealer - now = tz.make_aware(tz.datetime.now()) - playlist = [] - - # - the last logged diff is the last one played, it can be playing - # -> no sound left or the diff is not more current: dealer.off - # -> otherwise, ensure dealer.on - # - played sounds are logged in run_source - prev_diff = cl.__get_prev_diff(dealer) - if prev_diff and prev_diff.is_date_in_my_range(now): - playlist = [ path for path in prev_diff.playlist - if path not in prev_diff.played ] - dealer.on = bool(playlist) - else: - playlist = [] - dealer.on = False - - # - preload next diffusion's tracks - args = {'start__gt': prev_diff.start } if prev_diff else {} - next_diff = programs.Diffusion.get( - now, now = True, - type = programs.Diffusion.Type.normal, - **args - ) - if next_diff: - for diff in next_diffs: - if not diff.playlist: - continue - next_diff = diff - playlist += next_diff.playlist - break - - # playlist update - if dealer.playlist != playlist: - dealer.playlist = playlist - if next_diff: - cl.log( - type = programs.Log.Type.load, - source = dealer.id, - date = now, - related_object = next_diff - ) - - # dealer.on when next_diff.start <= now - if next_diff and not dealer.on and next_diff.start <= now: - dealer.on = True - for source in controller.streams.values(): - source.skip() - cl.log( - type = programs.Log.Type.play, - source = dealer.id, - date = now, - related_object = next_diff, - ) - - @classmethod - def run_source (cl, source): - """ - Keep trace of played sounds on the given source. - """ - # TODO: repetition of the same sound out of an interval of time - last_log = programs.Log.objects.filter( - source = source.id, - ).prefetch_related('related_object').order_by('-date') - - on_air = source.current_sound - if not on_air: - return - - if last_log: - now = tz.datetime.now() - last_log = last_log[0] - last_obj = last_log.related_object - if type(last_obj) == programs.Sound and on_air == last_obj.path: - #if not last_obj.duration or \ - # now < last_log.date + to_timedelta(last_obj.duration): - return - - sound = programs.Sound.objects.filter(path = on_air) - kwargs = { - 'type': programs.Log.Type.play, - 'source': source.id, - 'date': tz.make_aware(tz.datetime.now()), - } - if sound: - kwargs['related_object'] = sound[0] - else: - kwargs['comment'] = on_air - cl.log(**kwargs) - - -class Command (BaseCommand): - help= __doc__ - output_dir = settings.AIRCOX_LIQUIDSOAP_MEDIA - - def add_arguments (self, parser): - parser.formatter_class=RawTextHelpFormatter - parser.add_argument( - '-e', '--exec', action='store_true', - help='run liquidsoap on exit' - ) - group.add_argument( - '-s', '--station', type=str, - default = 'aircox', - help='use this name as station name (default is "aircox")' - ) - - group = parser.add_argument_group('actions') - group.add_argument( - '-d', '--delay', type=int, - default=1000, - help='time to sleep in milliseconds between two updates when we ' - 'monitor' - ) - group.add_argument( - '-m', '--monitor', action='store_true', - help='run in monitor mode' - ) - group.add_argument( - '-o', '--on_air', action='store_true', - help='print what is on air' - ) - group.add_argument( - '-r', '--run', action='store_true', - help='run liquidsoap with the generated configuration' - ) - group.add_argument( - '-w', '--write', action='store_true', - help='write configuration and playlist' - ) - - def handle (self, *args, **options): - run = options.get('run') - monitor = options.get('on_air') or options.get('monitor') - self.controller = utils.Controller( - station = options.get('station'), - connector = monitor - ) - - # actions - if options.get('write') or run: - self.handle_write() - if run: - self.handle_run() - if monitor: - self.handle_monitor(options) - - # post - if run: - for controller in self.controllers: - controller.process.wait() - - def handle_write (self): - self.controller.write() - - def handle_run (self): - self.controller.process = \ - subprocess.Popen( - ['liquidsoap', '-v', self.controller.config_path], - stderr=subprocess.STDOUT - ) - atexit.register(self.controller.process.terminate) - - def handle_monitor (self, options): - self.controller.update() - - if options.get('on_air'): - print(self.controller.id, self.controller.on_air) - return - - if options.get('monitor'): - delay = options.get('delay') / 1000 - while True: - Monitor.run(self.controller) - time.sleep(delay) - return - - diff --git a/liquidsoap/models.py b/liquidsoap/models.py deleted file mode 100644 index 6764c84..0000000 --- a/liquidsoap/models.py +++ /dev/null @@ -1,26 +0,0 @@ -from enum import Enum, IntEnum - -from django.db import models -from django.utils.translation import ugettext as _, ugettext_lazy - - -class Output (models.Model): - # Note: we don't translate the names since it is project names. - class Type(IntEnum): - jack = 0x00 - alsa = 0x01 - icecast = 0x02 - - type = models.SmallIntegerField( - _('output type'), - choices = [ (int(y), _(x)) for x,y in Type.__members__.items() ], - blank = True, null = True - ) - settings = models.TextField( - _('output settings'), - help_text = _('list of comma separated params available; ' - 'this is put in the output config as raw code'), - blank = True, null = True - ) - - diff --git a/liquidsoap/settings.py b/liquidsoap/settings.py deleted file mode 100644 index 161e90f..0000000 --- a/liquidsoap/settings.py +++ /dev/null @@ -1,23 +0,0 @@ - -from django.conf import settings - -def ensure (key, default): - globals()[key] = getattr(settings, key, default) - - -# dict of values to set (do not forget to escape chars) -ensure('AIRCOX_LIQUIDSOAP_SET', { - 'log.file.path': '"/tmp/liquidsoap.log"', -}) - -# security source: used when no source are available -ensure('AIRCOX_LIQUIDSOAP_SECURITY_SOURCE', '/media/data/musique/creation/Mega Combi/MegaCombi241-PT134-24062015_Comme_des_lyca_ens.mp3') - -# start the server on monitor if not present -ensure('AIRCOX_LIQUIDSOAP_AUTOSTART', True) - -# output directory for the generated files and socket. Each station has a subdir -# with the station's slug as name. -ensure('AIRCOX_LIQUIDSOAP_MEDIA', '/tmp') - - diff --git a/liquidsoap/templates/aircox/liquidsoap/controller.html b/liquidsoap/templates/aircox/liquidsoap/controller.html deleted file mode 100644 index 518305e..0000000 --- a/liquidsoap/templates/aircox/liquidsoap/controller.html +++ /dev/null @@ -1,134 +0,0 @@ -{% if not embed %} - - - - - - - -
-{% endif %} - {% for c_id, controller in monitor.controllers.items %} - {% with on_air=controller.on_air %} -
-
- {% if not controller.connector.available %} - disconnected - {% endif %} -

- {{ controller.station.name }} -

-
-
- {% with source=controller.master %} - {% include 'aircox/liquidsoap/source.html' %} - {% endwith %} - - {% with source=controller.dealer %} - {% include 'aircox/liquidsoap/source.html' %} - {% endwith %} - - {% for source in controller.streams.values %} - {% include 'aircox/liquidsoap/source.html' %} - {% endfor %} -
- -
- {% endwith %} - {% endfor %} - -{% if not embed %} -
- - -{% endif %} - diff --git a/liquidsoap/templates/aircox/liquidsoap/source.html b/liquidsoap/templates/aircox/liquidsoap/source.html deleted file mode 100644 index d48166f..0000000 --- a/liquidsoap/templates/aircox/liquidsoap/source.html +++ /dev/null @@ -1,14 +0,0 @@ -{% with metadata=source.metadata %} -
-

{{ source.name }}

- - {{ metadata.initial_uri }} - {{ metadata.status }} - - -
-{% endwith %} - - diff --git a/liquidsoap/templates/aircox/liquidsoap/station.liq b/liquidsoap/templates/aircox/liquidsoap/station.liq deleted file mode 100644 index 36d8188..0000000 --- a/liquidsoap/templates/aircox/liquidsoap/station.liq +++ /dev/null @@ -1,126 +0,0 @@ -{% comment %} -Base configuration file to configure a station on liquidsoap. - -A Station is composed of multiple streams, that includes: -- controller.dealer: used to play scheduled programs; -- controller.streams: streams configured to play random sounds; - -# Interactive elements: -An interactive element is accessible to the people, in order to: -- get metadata -- skip the current sound -- enable/disable it, only for the dealer - -- {controller.id}: the station itself -- {controller.id}_streams: all the streams of a controller -- {source.id}: for each stream of a controller + dealer - - -# Element of the context -We use theses elements from the template's context: -- controller: controller describing the station itself -- settings: global settings - -# Overwrite the template -It is possible to overwrite the template, there are blocks at different -position in order to do it. Keep in mind that you might want to avoid to -put station specific configuration in the template itself. -{% endcomment %} - - -{% comment %} -An interactive source is a source that: -- is skippable through the given id on external interfaces -- store metadata -{% endcomment %} -def interactive_source (id, s) = - s = store_metadata(id=id, size=1, s) - add_skip_command(s) - s -end - -{% comment %} -a stream is a source that: -- is a playlist on random mode (playlist object accessible at {id}_playlist -- is interactive -{% endcomment %} -def stream (id, file) = - #s = playlist(id = '#{id}_playlist', mode = "random", - # file) - s = playlist(id = '#{id}_playlist', mode = "random", file) - interactive_source(id, s) -end - -{% block extra_funcs %} -{% endblock %} -\ -{# config #} -set("server.socket", true) -set("server.socket.path", "{{ controller.socket_path }}") -{% for key, value in settings.AIRCOX_LIQUIDSOAP_SET.items %} -set("{{ key|safe }}", {{ value|safe }}) -{% endfor %} - -{% block extra_config %} -{% endblock %} - - -{# station #} -{{ controller.id }} = interactive_source ( - "{{ controller.id }}", - fallback(track_sensitive = false, [ - {# dealer #} - {% with source=controller.dealer %} - {% if source %} - at(interactive.bool('{{ source.id }}_on', false), - interactive_source('{{ source.id }}', playlist.once( - reload_mode='watch', - "{{ source.path }}", - )) - ), - {% endif %} - {% endwith %} - - {# streams #} - interactive_source("{{ controller.id }}_streams", rotate([ - {% for source in controller.streams.values %} - {% with info=source.stream_info %} - {% if info.delay %} - delay({{ info.delay }}., stream("{{ source.id }}", "{{ source.path }}")), - {% elif info.begin and info.end %} - at({ {{info.begin}}-{{info.end}} }, stream("{{ source.id }}", "{{ source.path }}")), - {% endif %} - {% endwith %} - {% endfor %} - - {% for source in controller.streams.values %} - {% if not source.stream_info %} - stream("{{ source.id }}", "{{ source.path }}"), - {% endif %} - {% endfor %} - ])), - - {# fallback #} - {% if controller.station.fallback %} - single("{{ controller.station.fallback }}"), - {% else %} - blank(id="scheize_blank", duration=0.1), - {% endif %} - ]) -) -\ - -{% block outputs %} -{% for output in controller.outputs %} -output.{{ output.get_type_display }}( - {{ controller.id }} - {% if controller.settings %}, - {{ controller.settings }} - {% endif %} -) -{% endfor %} - -{% block extra_output %} -{% endblock %} -{% endfor %} - diff --git a/liquidsoap/tests.py b/liquidsoap/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/liquidsoap/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/liquidsoap/urls.py b/liquidsoap/urls.py deleted file mode 100644 index 4fe671d..0000000 --- a/liquidsoap/urls.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.conf.urls import url - -import aircox.liquidsoap.views as views - -urlpatterns = [ - url('^controller/', views.LiquidControl.as_view(), name = 'liquid-controller'), -] - - diff --git a/liquidsoap/utils.py b/liquidsoap/utils.py deleted file mode 100644 index 3270dfe..0000000 --- a/liquidsoap/utils.py +++ /dev/null @@ -1,356 +0,0 @@ -import os -import socket -import re -import json - -from django.utils import timezone as tz -from django.utils.translation import ugettext as _, ugettext_lazy -from django.utils.text import slugify -from django.conf import settings as main_settings -from django.template.loader import render_to_string - -import aircox.programs.models as programs -import aircox.programs.settings as programs_settings -import aircox.liquidsoap.models as models -import aircox.liquidsoap.settings as settings - - -class Connector: - """ - Telnet connector utility. - - address: a string to the unix domain socket file, or a tuple - (host, port) for TCP/IP connection - """ - __socket = None - __available = False - address = None - - @property - def available(self): - return self.__available - - def __init__(self, address = None): - if address: - self.address = address - - def open(self): - if self.__available: - return - - try: - family = socket.AF_INET if type(self.address) in (tuple, list) else \ - socket.AF_UNIX - self.__socket = socket.socket(family, socket.SOCK_STREAM) - self.__socket.connect(self.address) - self.__available = True - except: - self.__available = False - return -1 - - def send(self, *data, try_count = 1, parse = False, parse_json = False): - if self.open(): - return '' - data = bytes(''.join([str(d) for d in data]) + '\n', encoding='utf-8') - - try: - reg = re.compile(r'(.*)\s+END\s*$') - self.__socket.sendall(data) - data = '' - while not reg.search(data): - data += self.__socket.recv(1024).decode('utf-8') - - if data: - data = reg.sub(r'\1', data) - data = data.strip() - - if parse: - data = self.parse(data) - elif parse_json: - data = self.parse_json(data) - return data - except: - self.__available = False - if try_count > 0: - return self.send(data, try_count - 1) - - def parse(self, string): - string = string.split('\n') - data = {} - for line in string: - line = re.search(r'(?P[^=]+)="?(?P([^"]|\\")+)"?', line) - if not line: - continue - line = line.groupdict() - data[line['key']] = line['value'] - return data - - def parse_json(self, string): - try: - if string[0] == '"' and string[-1] == '"': - string = string[1:-1] - return json.loads(string) if string else None - except: - return None - -class BaseSource: - id = None - name = None - controller = None - metadata = None - - def __init__(self, controller, id, name): - self.id = id - self.name = name - self.controller = controller - - def _send(self, *args, **kwargs): - return self.controller.connector.send(*args, **kwargs) - - @property - def current_sound(self): - self.update() - return self.metadata.get('initial_uri') if self.metadata else {} - - def skip(self): - """ - Skip a given source. If no source, use master. - """ - self._send(self.id, '.skip') - - def update(self, metadata = None): - """ - Update metadata with the given metadata dict or request them to - liquidsoap if nothing is given. - - Return -1 in case no update happened - """ - if metadata is None: - r = self._send(self.id, '.get', parse=True) - return self.update(metadata = r or {}) - - source = metadata.get('source') or '' - if hasattr(self, 'program') and self.program \ - and not source.startswith(self.id): - return -1 - self.metadata = metadata - return - - -class Source(BaseSource): - __playlist = None # playlist file - program = None # related program (if given) - is_dealer = False # Source is a dealer - metadata = None - - def __init__(self, controller, program = None, is_dealer = None): - if is_dealer: - id, name = '{}_dealer'.format(controller.id), \ - 'Dealer' - self.is_dealer = True - else: - id, name = '{}_stream_{}'.format(controller.id, program.id), \ - program.name - - super().__init__(controller, id, name) - - self.program = program - self.path = os.path.join(settings.AIRCOX_LIQUIDSOAP_MEDIA, - controller.id, - self.id + '.m3u') - if program: - self.playlist_from_db() - - @property - def on(self): - """ - Switch on-off; - """ - if not self.is_dealer: - raise RuntimeError('only dealers can do that') - r = self._send('var.get ', self.id, '_on') - return (r == 'true') - - @on.setter - def on(self, value): - if not self.is_dealer: - raise RuntimeError('only dealers can do that') - return self._send('var.set ', self.id, '_on', '=', - 'true' if value else 'false') - - @property - def playlist(self): - return self.__playlist - - @playlist.setter - def playlist(self, value): - self.__playlist = value - self.write() - - def write(self): - """ - Write stream's data (playlist) - """ - os.makedirs(os.path.dirname(self.path), exist_ok = True) - with open(self.path, 'w') as file: - file.write('\n'.join(self.playlist or [])) - - def playlist_from_db(self): - """ - Update content from the database using the source's program - """ - sounds = programs.Sound.objects.filter( - type = programs.Sound.Type['archive'], - path__startswith = os.path.join( - programs_settings.AIRCOX_SOUND_ARCHIVES_SUBDIR, - self.program.path - ), - # good_quality = True - removed = False - ) - self.playlist = [sound.path for sound in sounds] - - def stream_info(self): - """ - Return a dict with info related to the program's stream. - """ - if not self.program: - return - - stream = programs.Stream.objects.get(program = self.program) - if not stream.begin and not stream.delay: - return - - def to_seconds(time): - return 3600 * time.hour + 60 * time.minute + time.second - - 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 - } - - -class Master (BaseSource): - """ - A master Source based on a given station - """ - def update(self, metadata = None): - if metadata is not None: - return super().update(metadata) - - r = self._send('request.on_air') - r = self._send('request.metadata ', r, parse = True) - return self.update(metadata = r or {}) - - -class Controller: - """ - Main class controller for station and sources (streams and dealer) - """ - id = None - name = None - path = None - - connector = None - master = None # master source - dealer = None # dealer source - streams = None # streams streams - - # FIXME: used nowhere except in liquidsoap cli to get on air item but is not - # correct - @property - def on_air(self): - return self.master - - @property - def socket_path(self): - """ - Connector's socket path - """ - return os.path.join(self.path, 'station.sock') - - @property - def config_path(self): - """ - Connector's socket path - """ - return os.path.join(self.path, 'station.liq') - - def __init__(self, station, connector = True, update = False): - """ - Params: - - station: managed station - - connector: if true, create a connector, else do not - - Initialize a master, a dealer and all streams that are connected - to the given station; We ensure the existence of the controller's - files dir. - """ - self.id = slugify(station) - self.name = station - self.path = os.path.join(settings.AIRCOX_LIQUIDSOAP_MEDIA, self.id) - - self.outputs = models.Output.objects.all() - - self.connector = connector and Connector(self.socket_path) - - self.master = Master(self) - self.dealer = Source(self, is_dealer = True) - self.streams = { - source.id : source - for source in [ - Source(self, program) - for program in programs.Program.objects.filter(active = True) - if program.stream_set.count() - ] - } - - if update: - self.update() - - def get(self, source_id): - """ - Get a source by its id - """ - if source_id == self.master.id: - return self.master - if source_id == self.dealer.id: - return self.dealer - return self.streams.get(source_id) - - def update(self): - """ - Fetch and update all streams metadata. - """ - self.master.update() - self.dealer.update() - for source in self.streams.values(): - source.update() - - def write(self, playlist = True, config = True): - """ - Write stream's playlists, and config - """ - if playlist: - for source in self.streams.values(): - source.write() - self.dealer.write() - - if not config: - return - - context = { - 'controller': self, - 'settings': settings, - } - - # FIXME: remove this crappy thing - data = render_to_string('aircox/liquidsoap/station.liq', context) - data = re.sub(r'\s*\\\n', r'#\\n#', data) - data = data.replace('\n', '') - data = re.sub(r'#\\n#', '\n', data) - with open(self.config_path, 'w+') as file: - file.write(data) - - diff --git a/liquidsoap/views.py b/liquidsoap/views.py deleted file mode 100644 index 9abce54..0000000 --- a/liquidsoap/views.py +++ /dev/null @@ -1,64 +0,0 @@ -import re - -from django.views.generic.base import View, TemplateResponseMixin -from django.template.loader import render_to_string -from django.shortcuts import render -from django.http import HttpResponse - -import aircox.liquidsoap.settings as settings -import aircox.liquidsoap.utils as utils -import aircox.programs.models as models - - -view_monitor = None - -def get_monitor(): - global view_monitor - if not view_monitor: - view_monitor = utils.Monitor() - return view_monitor - -class Actions: - @classmethod - def exec (cl, monitor, controller, source, action): - controller = monitor.controllers.get(controller) - source = controller and controller.get(source) - - if not controller or not source or \ - action.startswith('__') or \ - action not in cl.__dict__: - return -1 - - action = getattr(Actions, action) - return action(monitor, controller, source) - - @classmethod - def skip (cl, monitor, controller, source): - source.skip() - -class LiquidControl (View): - template_name = 'aircox/liquidsoap/controller.html' - - def get_context_data (self, **kwargs): - get_monitor().update() - return { - 'request': self.request, - 'monitor': get_monitor(), - 'embed': 'embed' in self.request.GET, - } - - def post (self, request = None, **kwargs): - if 'action' in request.POST: - POST = request.POST - controller = POST.get('controller') - source = POST.get('source') - action = POST.get('action') - Actions.exec(get_monitor(), controller, source, action) - return HttpResponse('') - - def get (self, request = None, **kwargs): - self.request = request - context = self.get_context_data(**kwargs) - return render(request, self.template_name, context) - -