diff --git a/cms/sections.py b/cms/sections.py index fec4362..5a239a9 100644 --- a/cms/sections.py +++ b/cms/sections.py @@ -530,9 +530,10 @@ class SectionItemMeta(models.base.ModelBase): cl = super().__new__(cls, name, bases, attrs) if not 'template' in attrs: + cl.snake_name = camelcase_to_underscore(name) cl.template = '{}/sections/{}.html'.format( cl._meta.app_label, - camelcase_to_underscore(name), + cl.snake_name, ) if name != 'SectionItem': try: diff --git a/cms/static/cms/css/layout.css b/cms/static/cms/css/layout.css index 952ae33..78c7d02 100644 --- a/cms/static/cms/css/layout.css +++ b/cms/static/cms/css/layout.css @@ -76,6 +76,11 @@ nav.menu { display: inline-block; } + .menu.top a { + display: inline-block; + margin: 0.2em 1em; + } + .page_left > section, .page_right > section { margin-bottom: 1em; @@ -328,4 +333,3 @@ main .body ~ section:not(.comments) { } - diff --git a/cms/static/cms/css/theme.css b/cms/static/cms/css/theme.css index 908f500..3476e63 100644 --- a/cms/static/cms/css/theme.css +++ b/cms/static/cms/css/theme.css @@ -87,7 +87,8 @@ main { } main .content img.cover { - width: 100%; + width: calc(100% + 2em); + margin-left: -1em; } diff --git a/cms/templates/cms/sections/section_item.html b/cms/templates/cms/sections/section_item.html index e31b8b2..1f4143f 100644 --- a/cms/templates/cms/sections/section_item.html +++ b/cms/templates/cms/sections/section_item.html @@ -1,4 +1,4 @@ -
+
{% block title %} {% if self.show_title %}

{{ self.title }}

{% endif %} {% endblock %} diff --git a/controllers/monitor.py b/controllers/monitor.py index d48798c..de93c32 100644 --- a/controllers/monitor.py +++ b/controllers/monitor.py @@ -27,7 +27,6 @@ class Monitor: """ def __init__(self, station, **kwargs): - Log.objects.all().delete() self.station = station self.__dict__.update(kwargs) @@ -169,7 +168,7 @@ class Monitor: ) sounds = [ sound.related.path for sound in sounds - if not sound.related.removed + if sound.related.type != programs.Sound.Type.removed ] return ( @@ -229,8 +228,6 @@ class Monitor: if next_diff and not dealer.controller.active and \ next_diff.start <= now: dealer.controller.active = True - for source in station.get_sources(): - source.controller.skip() self.log( type = Log.Type.play, source = dealer.id_, diff --git a/controllers/templates/aircox/controllers/liquidsoap.liq b/controllers/templates/aircox/controllers/liquidsoap.liq index 7fb98bf..7d6d7db 100644 --- a/controllers/templates/aircox/controllers/liquidsoap.liq +++ b/controllers/templates/aircox/controllers/liquidsoap.liq @@ -19,6 +19,8 @@ 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 %} + +{% block functions %} {% comment %} An interactive source is a source that: - is skippable through the given id on external interfaces @@ -36,7 +38,7 @@ def interactive_source (id, s, ~active=true, ~disable_switch=false) = end {% comment %} -a stream is a source that: +A stream is a source that: - is a playlist on random mode (playlist object accessible at {id}_playlist - is interactive {% endcomment %} @@ -44,70 +46,104 @@ def stream (id, file) = s = playlist(id = '#{id}_playlist', mode = "random", file) interactive_source(id, s) end - -{% block post_funcs %} {% endblock %} -{# config #} +{% block functions_extras %} +{% endblock %} + + +{% block config %} set("server.socket", true) set("server.socket.path", "{{ station.controller.socket_path }}") set("log.file.path", "{{ station.controller.station.path }}/liquidsoap.log") {% for key, value in settings.AIRCOX_LIQUIDSOAP_SET.items %} set("{{ key|safe }}", {{ value|safe }}) {% endfor %} +{% endblock %} -{% block post_config %} +{% block config_extras %} {% endblock %} -{# station #} +{% block sources %} +live = fallback([ + {% for source in station.file_sources %} + {% with controller=source.controller %} + interactive_source( + '{{ source.id_ }}', single("{{ source.url }}"), active=false + ), + {% endwith %} + {% endfor %} + + {% with source=station.dealer controller=station.dealer.controller %} + interactive_source('{{ source.id_ }}', + playlist.once(reload_mode='watch', "{{ controller.path }}"), + active=false + ), + {% endwith %} +]) + + +stream = fallback([ + rotate([ + {% for source in station.stream_sources %} + {% with controller=source.controller stream=source.controller.stream %} + {% if stream.delay %} + delay({{ stream.delay }}., + stream("{{ source.id_ }}", "{{ controller.path }}")), + {% elif stream.begin and stream.end %} + at({ {{stream.begin}}-{{stream.end}} }, + stream("{{ source.id_ }}", "{{ controller.path }}")), + {% elif not stream %} + stream("{{ source.id_ }}", "{{ controller.path }}"), + {% endif %} + {% endwith %} + {% endfor %} + ]), + + {% for source in station.fallback_sources %} + {% with controller=source.controller %} + single("{{ source.value }}"), + {% endwith %} + {% endfor %} + + blank(id="blank_fallback", duration=0.1), +]) + +{% endblock %} + +{% block sources_extras %} +{% endblock %} + + +def to_live(stream,live) + stream = fade.final(duration=2., type='log', stream) + live = fade.initial(duration=2., type='log', live) + add(normalize=false, [stream,live]) +end + +def to_stream(live,stream) + source.skip(stream) + add(normalize=false, [live,stream]) +end + + +{% block station %} {{ station.id_ }} = interactive_source ( "{{ station.id_ }}", - fallback(track_sensitive = false, [ - {% for source in station.file_sources %} - {% with controller=source.controller %} - interactive_source( - '{{ source.id_ }}', single("{{ source.url }}"), - active=false - ), - {% endwith %} - {% endfor %} - - {% with source=station.dealer %} - {% with controller=source.controller %} - interactive_source('{{ source.id_ }}', - playlist.once(reload_mode='watch', "{{ controller.path }}"), - active=false - ), - {% endwith %} - {% endwith %} - - rotate([ - {% for source in station.stream_sources %} - {% with controller=source.controller stream=source.controller.stream %} - {% if stream.delay %} - delay({{ stream.delay }}., - stream("{{ source.id_ }}", "{{ controller.path }}")), - {% elif stream.begin and stream.end %} - at({ {{stream.begin}}-{{stream.end}} }, - stream("{{ source.id_ }}", "{{ controller.path }}")), - {% elif not stream %} - stream("{{ source.id_ }}", "{{ controller.path }}"), - {% endif %} - {% endwith %} - {% endfor %} - ]), - - {% for source in station.fallback_sources %} - {% with controller=source.controller %} - single("{{ source.value }}"), - {% endwith %} - {% endfor %} - - blank(id="blank_fallback", duration=0.1), - ]), + fallback( + track_sensitive=false, + transitions=[to_live,to_stream], + [ live, stream ] + ), disable_switch=true ) +{% endblock %} + + +{% block station_extras %} +{% endblock %} + {% block outputs %} {% for output in station.outputs %} @@ -120,6 +156,6 @@ output.{{ output.get_type_display }}( {% endfor %} {% endblock %} -{% block post_output %} +{% block output_extras %} {% endblock %} diff --git a/controllers/templates/aircox/controllers/monitor.html b/controllers/templates/aircox/controllers/monitor.html index aee33ed..dd3f888 100644 --- a/controllers/templates/aircox/controllers/monitor.html +++ b/controllers/templates/aircox/controllers/monitor.html @@ -54,8 +54,11 @@ var Monitor = { return document.cookie.replace(/.*csrftoken=([^;]+)(;.*|$)/, '$1'); }, - post: function(station, action) { + post: function(station, source, action) { var params = 'station=' + station + '&&action=' + action; + if(source) + params += '&&source=' + source; + var req = new XMLHttpRequest() req.open('POST', '{% url 'controllers.monitor' %}', false); req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); @@ -66,8 +69,8 @@ var Monitor = { this.update(); }, - skip: function(station) { - this.post(station, 'skip'); + skip: function(station, source) { + this.post(station, source, 'skip'); }, update: function(timeout) { @@ -110,6 +113,8 @@ Monitor.update(1000);
{{ source.name }} {{ source.controller.current_sound }} +
{% endif %} {% endfor %} diff --git a/controllers/views.py b/controllers/views.py index 9f75064..780cfed 100644 --- a/controllers/views.py +++ b/controllers/views.py @@ -94,7 +94,7 @@ class Monitor(View,TemplateResponseMixin,LoginRequiredMixin): if not request.user.is_active: return Http404() - if not 'action' in request.POST: + if not ('action' or 'station') in request.POST: return HttpResponse('') POST = request.POST @@ -107,8 +107,22 @@ class Monitor(View,TemplateResponseMixin,LoginRequiredMixin): return HttpResponse('') station.prepare(fetch=True) + source = None + if 'source' in POST: + source = station.source_set.filter(name = POST['source']) \ + .first() + if not source and POST['source'] == station.dealer.name: + source = station.dealer + + if source: + source.prepare() + if station and action == 'skip': - station.controller.skip() + if source: + print('skip ', source) + source.controller.skip() + else: + station.controller.skip() return HttpResponse('') diff --git a/programs/models.py b/programs/models.py index 8f0615f..5922727 100755 --- a/programs/models.py +++ b/programs/models.py @@ -591,7 +591,7 @@ class Program(Nameable): class DiffusionManager(models.Manager): - def get_at(self, date = None): + def get_at(self, date = None, next = False): """ Return a queryset of diffusions that have the given date in their range. @@ -606,9 +606,12 @@ class DiffusionManager(models.Manager): models.Q(end__contains = date) ) + if not next: + return self.filter(start__lte = date, end__gte = date) \ + .order_by('start') + return self.filter( models.Q(start__lte = date, end__gte = date) | - # FIXME: should not be here? models.Q(start__gte = date), ).order_by('start')