This commit is contained in:
bkfox 2016-06-14 04:35:43 +02:00
parent 3936580275
commit 833e7a551d
4 changed files with 87 additions and 51 deletions

View File

@ -1,4 +1,5 @@
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.http import HttpResponse
from django.conf.urls import url from django.conf.urls import url
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.utils.text import slugify from django.utils.text import slugify
@ -73,7 +74,7 @@ def part(view, name = None, pattern = None):
view_.url = url view_.url = url
return view_ return view_
def template(template_name): def template(name):
""" """
the decorated function returns a context that is used to the decorated function returns a context that is used to
render a template value. render a template value.
@ -84,10 +85,10 @@ def template(template_name):
def wrapper(func): def wrapper(func):
def view_(cl, request, *args, **kwargs): def view_(cl, request, *args, **kwargs):
context = func(cl, request, *args, **kwargs) context = func(cl, request, *args, **kwargs)
if not context and hide_empty: if not context:
return '' return ''
context['embed'] = True context['embed'] = True
return render_to_string(template_name, context, request=request) return render_to_string(name, context, request=request)
view_.__name__ = func.__name__ view_.__name__ = func.__name__
return view_ return view_
return wrapper return wrapper

View File

@ -24,6 +24,9 @@ Part_.prototype = {
/// parse request result and save in this.stanza /// parse request result and save in this.stanza
__parse_dom: function() { __parse_dom: function() {
if(self.stanza)
return;
var doc = document.implementation.createHTMLDocument('xhr').documentElement; var doc = document.implementation.createHTMLDocument('xhr').documentElement;
doc.innerHTML = this.xhr.responseText; doc.innerHTML = this.xhr.responseText;
this.stanza = doc; this.stanza = doc;
@ -61,9 +64,10 @@ Part_.prototype = {
return this; return this;
}, },
// set selectors. if callback is set, call this callback // set selectors.
// once data are retrieved with an object of // * callback: if set, call it once data are downloaded with an object
// `selector_name: select_result` // of elements matched with the given selectors only. The object is
// made of `selector_name: select_result` items.
select: function(selectors, callback = undefined) { select: function(selectors, callback = undefined) {
for(var i in selectors) { for(var i in selectors) {
selector = selectors[i]; selector = selectors[i];
@ -71,15 +75,19 @@ Part_.prototype = {
selector = [selector] selector = [selector]
selector = new Part_.Selector(i, selector[0], selector[1], selector[2]) selector = new Part_.Selector(i, selector[0], selector[1], selector[2])
selectors[i] = selector;
this.selectors.push(selector) this.selectors.push(selector)
} }
if(callback) { if(callback) {
var self = this; var self = this;
this.actions.push(function() { this.actions.push(function() {
self.__parse_dom();
var r = {} var r = {}
for(var i in self.selectors) for(var i in selectors) {
r[i] = self.selectors[i].select(self.stanza); r[i] = selectors[i].select(self.stanza);
}
callback(r); callback(r);
}); });
} }
@ -90,8 +98,7 @@ Part_.prototype = {
map: function(dest) { map: function(dest) {
var self = this; var self = this;
this.actions.push(function() { this.actions.push(function() {
if(!self.stanza) self.__parse_dom();
self.__parse_dom();
for(var i = 0; i < self.selectors.length; i++) { for(var i = 0; i < self.selectors.length; i++) {
selector = self.selectors[i] selector = self.selectors[i]
@ -119,9 +126,7 @@ Part_.Selector = function(name, selector, attribute = null, all = false) {
Part_.Selector.prototype = { Part_.Selector.prototype = {
select: function(obj, use_attr = true) { select: function(obj, use_attr = true) {
if(!this.all) { if(!this.all) {
obj = obj.querySelectorAll(this.selector) obj = obj.querySelector(this.selector)
if(obj)
obj = obj[0];
return (this.attribute && use_attr && obj) ? obj[this.attribute] : obj; return (this.attribute && use_attr && obj) ? obj[this.attribute] : obj;
} }

View File

@ -20,16 +20,13 @@ class Player(sections.Section):
template_name = 'aircox/website/player.html' template_name = 'aircox/website/player.html'
live_streams = [] live_streams = []
""" """
A ListItem objects that display a list of available streams. ListItem objects that display a list of available streams.
""" """
#default_sounds #default_sounds
@decorators.part @decorators.part
@decorators.template(template_name = 'aircox/cms/list_item.html') @decorators.template('aircox/cms/list_item.html')
def on_air(cl, request): def on_air(cl, request):
"""
View that return what is on air formatted in JSON.
"""
qs = programs.Diffusion.get( qs = programs.Diffusion.get(
now = True, now = True,
type = programs.Diffusion.Type.normal type = programs.Diffusion.Type.normal
@ -39,22 +36,18 @@ class Player(sections.Section):
return '' return ''
qs = qs[0] qs = qs[0]
post = models.Diffusion.objects.filter(related = qs) post = models.Diffusion.objects.filter(related = qs) or \
if not post: models.Program.objects.filter(related = qs.program)
post = models.Program.objects.filter(related = qs.program) if post:
if not post:
post = ListItem(title = qs.program.name)
else:
post = post[0] post = post[0]
else:
post = ListItem(title = qs.program.name)
return { return {
'item': post, 'item': post,
'list': sections.List, 'list': sections.List,
} }
return json.dumps({ 'title': post.title, 'url': post.url() })
def get_context_data(self, *args, **kwargs): def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs) context = super().get_context_data(*args, **kwargs)
context.update({ context.update({

View File

@ -12,7 +12,6 @@
} }
.player-box { .player-box {
height: 2em;
border-top-left-radius: 0.5em; border-top-left-radius: 0.5em;
border-top-right-radius: 0.5em; border-top-right-radius: 0.5em;
border: 1px #212121 solid; border: 1px #212121 solid;
@ -47,6 +46,30 @@
margin-left: -100%; margin-left: -100%;
} }
#player .on_air {
background-color: #414141;
box-shadow: inset 0 0 0.2em rgba(0, 0, 0, 0.5);
padding: 0.2em;
margin: 0.2em 0em;
}
#player .on_air .title {
font-size: 0.8em;
display: inline;
}
#player .on_air .title:before {
content: "{% trans "on air //" %}";
color: red;
margin: 0.2em;
}
#player .on_air a {
float: right;
color: black;
}
.playlists {} .playlists {}
.playlists nav { .playlists nav {
@ -77,7 +100,7 @@
.playlist .item > * { .playlist .item > * {
display: inline; display: inline;
margin: 0.2em; margin: 0.2em;
vertical-align: center; vertical-align: middle;
} }
.playlist .item .info { .playlist .item .info {
@ -93,9 +116,13 @@
.playlist .item[selected] .title { .playlist .item[selected] .title {
color: #007EDF; color: #007EDF;
} }
</style> </style>
<div id="player"> <div id="player">
<li class='item' style="display: none;">
<h2 class="title"></h2>
<a class="url">+</a>
<div class="info"></div>
</li>
<div class="player-box"> <div class="player-box">
<div id="embed-player"> <div id="embed-player">
</div> </div>
@ -112,16 +139,16 @@
</span> </span>
<h3 class="title"></h3> <h3 class="title"></h3>
<div class='item on_air'>
<h2 class="title"></h2>
<a class="url">+</a>
</div>
</div> </div>
</div> </div>
<div class="playlists"> <div class="playlists">
<nav></nav> <nav></nav>
</div> </div>
<li class='item' style="display: none;">
<h2 class="title"></h2>
<a class="detail">+</a>
<div class="info"></div>
</li>
</div> </div>
<script> <script>
@ -154,7 +181,7 @@ Playlist.prototype = {
/// Create an item and add to the given container [ = this.playlist ] /// Create an item and add to the given container [ = this.playlist ]
add: function (info, container) { add: function (info, container) {
item = player.player.querySelector('.item'); var item = player.player.querySelector('.item');
item = item.cloneNode(true); item = item.cloneNode(true);
item.removeAttribute('style'); item.removeAttribute('style');
@ -167,15 +194,19 @@ Playlist.prototype = {
item.info = info; item.info = info;
item.querySelector('.title').innerHTML = info.title; item.querySelector('.title').innerHTML = info.title;
item.querySelector('.detail').href = info.url; item.querySelector('.url').href = info.url;
item.querySelector('.info').innerHTML = info.info || ''; item.querySelector('.info').innerHTML = info.info || '';
item.addEventListener('click', function(event) { if(info.class)
if(event.target.className.indexOf('detail') != -1) item.className += " " + info.class;
return;
player.select(event.currentTarget.info); if(info.stream || info.embed)
event.preventDefault(); item.addEventListener('click', function(event) {
}, true); if(event.target.className.indexOf('url') != -1)
return;
player.select(event.currentTarget.info);
event.preventDefault();
}, true);
this.items.push(info); this.items.push(info);
}, },
@ -227,16 +258,22 @@ player = {
this.select_playlist(this.recents); this.select_playlist(this.recents);
this.select(this.live.items[0], false) this.select(this.live.items[0], false)
this.update_on_air();
}, },
/// update "on_air" /// update on air informations
get_on_air: function() { update_on_air: function() {
part = Part('').select({ part = Part('{% url "player_on_air" %}').get()
'title': '.title', .select({
'url': 'a', title: '.title',
}, function(r) { url: ['.url', 'href'],
document.title = r.title; })
}); .map(this.player.querySelector('.on_air'))
.send();
window.setTimeout(function() {
player.update_on_air();
}, 60000*5);
}, },
/// play a given item { title, src } /// play a given item { title, src }