add view to controls stations

This commit is contained in:
bkfox
2016-07-29 18:44:39 +02:00
parent 5329e983a4
commit 9728acef81
8 changed files with 378 additions and 4 deletions

View File

@ -0,0 +1,125 @@
{% comment %}
TODO: update doc
Base configuration file to configure a station on liquidsoap.
# Interactive elements:
An interactive element is accessible to the people, in order to:
- get metadata
- skip the current sound
- enable/disable it
# 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
- can be disabled
- store metadata
{% endcomment %}
def interactive_source (id, s, ~active=true, ~disable_switch=false) =
s = store_metadata(id=id, size=1, s)
add_skip_command(s)
if disable_switch then
s
else
at(interactive.bool('#{id}_active', active), s)
end
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)
interactive_source(id, s)
end
{% block post_funcs %}
{% endblock %}
{# 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 %}
{% block post_config %}
{% endblock %}
{# 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),
]),
disable_switch=true
)
{% block outputs %}
{% for output in station.outputs %}
output.{{ output.get_type_display }}(
{{ station.id_ }},
{% if controller.settings %},
{{ output.settings }}
{% endif %}
)
{% endfor %}
{% endblock %}
{% block post_output %}
{% endblock %}

View File

@ -0,0 +1,121 @@
{% load i18n %}
<style>
section.station {
padding: 0.4em;
font-size: 0.9em;
}
section.station header {
margin: 0.4em 0em;
}
section.station header > * {
margin: 0em 0.2em;
}
section.station h1 {
display: inline;
margin: 0px;
font-size: 1.4em;
}
section.station button {
float: right;
}
section.station .sources {
border: 1px grey solid;
}
section.station .source {
margin: 0.2em 0em;
}
section.station .name {
display: inline-block;
width: 10em;
}
section.station .file {
color: #007EDF;
}
section.station .source.current:before {
content: '▶';
color: red;
margin: 0em 1em;
}
</style>
<script>
// HERE
var Monitor = {
get_token: function () {
return document.cookie.replace(/.*csrftoken=([^;]+)(;.*|$)/, '$1');
},
post: function(station, action) {
params = 'station=' + station + '&&action=' + action;
req = new XMLHttpRequest()
req.open('POST', '{% url 'controllers.monitor' %}', false);
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.setRequestHeader("Content-length", params.length);
req.setRequestHeader("Connection", "close");
req.setRequestHeader("X-CSRFToken", this.get_token());
req.send(params);
this.update();
},
skip: function(station) {
this.post(station, 'skip');
},
update: function(timeout) {
req = new XMLHttpRequest()
req.open('GET', '{% url 'controllers.monitor' %}', true);
req.onreadystatechange = function() {
if(req.readyState != 4 || (req.status != 200 && req.status != 0))
return;
var doc = document.implementation.createHTMLDocument('xhr')
.documentElement;
doc.innerHTML = req.responseText;
document.getElementById('stations').innerHTML =
doc.querySelector('#stations').innerHTML;
if(timeout)
window.setTimeout(function() { Monitor.update(timeout);}, 5000);
};
req.send();
},
}
Monitor.update(1000);
</script>
<div id='stations'>
{% for station in stations %}
<section class="station">
<header>
<h1>{{ station.name }}</h1>
<button onclick="Monitor.skip('{{ station.name }}');">{% trans "skip" %}</button>
<button onclick="Monitor.update();">{% trans "update" %}</button>
</header>
<div class="sources">
{% for source in station.all_sources %}
{% if source.controller.current_sound %}
<div class="source{% if source == station.controller.current_source %} current{% endif %}">
<span class="name">{{ source.name }}</span>
<span class="file">{{ source.controller.current_sound }}</span>
</div>
{% endif %}
{% endfor %}
</div>
</section>
{% endfor %}
</div>