forked from rc/aircox
liquidsoap: fix error in template, station.current_source on request's id
This commit is contained in:
parent
0d75f65ed4
commit
a5638f0071
|
@ -2,12 +2,25 @@ from django.contrib import admin
|
||||||
|
|
||||||
import aircox.controllers.models as models
|
import aircox.controllers.models as models
|
||||||
|
|
||||||
|
|
||||||
|
class SourceInline(admin.StackedInline):
|
||||||
|
model = models.Source
|
||||||
|
extra = 0
|
||||||
|
|
||||||
|
class OutputInline(admin.StackedInline):
|
||||||
|
model = models.Output
|
||||||
|
extra = 0
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(models.Station)
|
||||||
|
class StationAdmin(admin.ModelAdmin):
|
||||||
|
inlines = [ SourceInline, OutputInline ]
|
||||||
|
|
||||||
#@admin.register(Log)
|
#@admin.register(Log)
|
||||||
#class LogAdmin(admin.ModelAdmin):
|
#class LogAdmin(admin.ModelAdmin):
|
||||||
# list_display = ['id', 'date', 'source', 'comment', 'related_object']
|
# list_display = ['id', 'date', 'source', 'comment', 'related_object']
|
||||||
# list_filter = ['date', 'source', 'related_type']
|
# list_filter = ['date', 'source', 'related_type']
|
||||||
|
|
||||||
admin.site.register(models.Station)
|
|
||||||
admin.site.register(models.Source)
|
admin.site.register(models.Source)
|
||||||
admin.site.register(models.Output)
|
admin.site.register(models.Output)
|
||||||
admin.site.register(models.Log)
|
admin.site.register(models.Log)
|
||||||
|
|
|
@ -51,6 +51,10 @@ class Station(programs.Nameable):
|
||||||
plugin.StationController
|
plugin.StationController
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id_(self):
|
||||||
|
return self.slug
|
||||||
|
|
||||||
def get_sources(self, type = None, prepare = True):
|
def get_sources(self, type = None, prepare = True):
|
||||||
"""
|
"""
|
||||||
Return a list of active sources that can have their controllers
|
Return a list of active sources that can have their controllers
|
||||||
|
@ -87,7 +91,8 @@ class Station(programs.Nameable):
|
||||||
"""
|
"""
|
||||||
List of active outputs
|
List of active outputs
|
||||||
"""
|
"""
|
||||||
return [ output for output in self.output_set if output.active ]
|
print(self.output_set)
|
||||||
|
return [ output for output in self.output_set.filter(active = True) ]
|
||||||
|
|
||||||
def prepare(self, fetch = True):
|
def prepare(self, fetch = True):
|
||||||
"""
|
"""
|
||||||
|
@ -129,6 +134,32 @@ class Station(programs.Nameable):
|
||||||
if self.plugin_name:
|
if self.plugin_name:
|
||||||
self.plugin = Plugins.registry.get(self.plugin_name)
|
self.plugin = Plugins.registry.get(self.plugin_name)
|
||||||
|
|
||||||
|
|
||||||
|
def play_logs(self, include_diffusions = True,
|
||||||
|
include_sounds = True,
|
||||||
|
exclude_archives = True):
|
||||||
|
"""
|
||||||
|
Return a queryset with what is playing on air for this station.
|
||||||
|
Ordered by date ascending.
|
||||||
|
"""
|
||||||
|
models = []
|
||||||
|
if include_diffusions: models.append(programs.Diffusion)
|
||||||
|
if include_sounds: models.append(programs.Sound)
|
||||||
|
|
||||||
|
qs = Log.get_for(model = models) \
|
||||||
|
.filter(station = station, type = Log.Type.play)
|
||||||
|
|
||||||
|
if exclude_archives and self.dealer:
|
||||||
|
qs = qs.exclude(
|
||||||
|
source = self.dealer.id_,
|
||||||
|
related_type = ContentType.objects.get_for_model(
|
||||||
|
program.Sound
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return qs.order_by('date')
|
||||||
|
|
||||||
|
|
||||||
def save(self, make_sources = True, *args, **kwargs):
|
def save(self, make_sources = True, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
* make_sources: if the model has not been yet saved, generate
|
* make_sources: if the model has not been yet saved, generate
|
||||||
|
@ -216,6 +247,10 @@ class Source(programs.Nameable):
|
||||||
implements plugin.SourceController;
|
implements plugin.SourceController;
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id_(self):
|
||||||
|
return self.slug
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def stream(self):
|
def stream(self):
|
||||||
if self.type != self.Type.stream or not self.program:
|
if self.type != self.Type.stream or not self.program:
|
||||||
|
@ -392,8 +427,14 @@ class Log(models.Model):
|
||||||
if not model and object:
|
if not model and object:
|
||||||
model = type(object)
|
model = type(object)
|
||||||
|
|
||||||
qs = cl.objects.filter(related_type__pk =
|
if type(model) in (list, tuple):
|
||||||
ContentTYpe.objects.get_for_model(model).id)
|
model = [ ContentType.objects.get_for_model(m).id
|
||||||
|
for m in model ]
|
||||||
|
qs = cl.objects.filter(related_type__pk__in = model)
|
||||||
|
else:
|
||||||
|
model = ContentType.objects.get_for_model(model)
|
||||||
|
qs = cl.objects.filter(related_type__pk = model.id)
|
||||||
|
|
||||||
if object:
|
if object:
|
||||||
qs = qs.filter(related_id = object.pk)
|
qs = qs.filter(related_id = object.pk)
|
||||||
return qs
|
return qs
|
||||||
|
@ -408,7 +449,7 @@ class Log(models.Model):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '#{} ({}, {})'.format(
|
return '#{} ({}, {})'.format(
|
||||||
self.id, self.date.strftime('%Y/%m/%d %H:%M'), self.source.name
|
self.pk, self.date.strftime('%Y/%m/%d %H:%M'), self.source.name
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,18 @@ class Monitor:
|
||||||
do that.
|
do that.
|
||||||
"""
|
"""
|
||||||
station = None
|
station = None
|
||||||
|
controller = None
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""
|
||||||
|
Run all monitoring functions. Ensure that station has controllers
|
||||||
|
"""
|
||||||
|
if not self.controller:
|
||||||
|
self.station.prepare()
|
||||||
|
self.controller = self.station.controller
|
||||||
|
|
||||||
|
self.track()
|
||||||
|
self.handler()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def log(**kwargs):
|
def log(**kwargs):
|
||||||
|
@ -27,25 +39,23 @@ class Monitor:
|
||||||
Check the current_sound of the station and update logs if
|
Check the current_sound of the station and update logs if
|
||||||
needed
|
needed
|
||||||
"""
|
"""
|
||||||
station = self.station
|
self.controller.fetch()
|
||||||
station.controller.fetch()
|
current_sound = self.controller.current_sound
|
||||||
|
current_source = self.controller.current_source
|
||||||
current_sound = station.controller.current_sound
|
|
||||||
current_source = station.controller.current_source
|
|
||||||
if not current_sound:
|
if not current_sound:
|
||||||
return
|
return
|
||||||
|
|
||||||
log = Log.get_for(model = programs.Sound) \
|
log = Log.get_for(model = programs.Sound) \
|
||||||
.filter(station = station).order_by('date').last()
|
.filter(station = self.station).order_by('date').last()
|
||||||
# TODO: expiration
|
# TODO: expiration
|
||||||
if log and (log.source == current_source and \
|
if log and (log.source == current_source.id_ and \
|
||||||
log.related.path == current_sound):
|
log.related.path == current_sound):
|
||||||
return
|
return
|
||||||
|
|
||||||
sound = programs.Sound.object.filter(path = current_sound)
|
sound = programs.Sound.object.filter(path = current_sound)
|
||||||
self.log(
|
self.log(
|
||||||
type = Log.Type.play,
|
type = Log.Type.play,
|
||||||
source = current_source,
|
source = current_source.id_,
|
||||||
date = tz.make_aware(tz.datetime.now()),
|
date = tz.make_aware(tz.datetime.now()),
|
||||||
|
|
||||||
related = sound[0] if sound else None,
|
related = sound[0] if sound else None,
|
||||||
|
@ -60,17 +70,21 @@ class Monitor:
|
||||||
station = self.station
|
station = self.station
|
||||||
now = tz.make_aware(tz.datetime.now())
|
now = tz.make_aware(tz.datetime.now())
|
||||||
|
|
||||||
sound_log = Log.get_for(model = programs.Sound) \
|
|
||||||
.filter(station = station).order_by('date').last()
|
|
||||||
diff_log = Log.get_for(model = programs.Diffusion) \
|
diff_log = Log.get_for(model = programs.Diffusion) \
|
||||||
.filter(station = station).order_by('date').last()
|
.filter(station = station, type = Log.Type.play) \
|
||||||
|
.order_by('date').last()
|
||||||
|
|
||||||
if not sound_log or not diff_log or \
|
if not diff_log or \
|
||||||
sound_log.source != diff_log.source or \
|
not diff_log.related.is_date_in_my_range(now):
|
||||||
diff_log.related.is_date_in_my_range(now) :
|
|
||||||
return None, []
|
return None, []
|
||||||
|
|
||||||
# last registered diff is still playing: update the playlist
|
# sound has switched? assume it has been (forced to) stopped
|
||||||
|
sound_log = Log.get_for(model = programs.Sound) \
|
||||||
|
.filter(station = station).order_by('date').last()
|
||||||
|
if sound_log and sound_log.source != diff_log.source:
|
||||||
|
return None, []
|
||||||
|
|
||||||
|
# last diff is still playing: get the remaining playlist
|
||||||
sounds = Log.get_for(model = programs.Sound) \
|
sounds = Log.get_for(model = programs.Sound) \
|
||||||
.filter(station = station, source = diff_log.source) \
|
.filter(station = station, source = diff_log.source) \
|
||||||
.filter(pk__gt = diff.log.pk)
|
.filter(pk__gt = diff.log.pk)
|
||||||
|
@ -94,13 +108,13 @@ class Monitor:
|
||||||
diff = programs.Diffusion.get(
|
diff = programs.Diffusion.get(
|
||||||
now, now = True,
|
now, now = True,
|
||||||
type = programs.Diffusion.Type.normal,
|
type = programs.Diffusion.Type.normal,
|
||||||
|
|
||||||
sound__type = programs.Sound.Type.archive,
|
sound__type = programs.Sound.Type.archive,
|
||||||
sound__removed = False,
|
sound__removed = False,
|
||||||
**args
|
**args
|
||||||
).distinct().order_by('start').first()
|
).distinct().order_by('start').first()
|
||||||
return (diff, diff and diff.playlist or [])
|
return (diff, diff and diff.playlist or [])
|
||||||
|
|
||||||
|
|
||||||
def handle(self):
|
def handle(self):
|
||||||
"""
|
"""
|
||||||
Handle scheduled diffusion, trigger if needed, preload playlists
|
Handle scheduled diffusion, trigger if needed, preload playlists
|
||||||
|
@ -116,7 +130,7 @@ class Monitor:
|
||||||
diff, playlist = self.__current_diff()
|
diff, playlist = self.__current_diff()
|
||||||
dealer.on = bool(playlist)
|
dealer.on = bool(playlist)
|
||||||
|
|
||||||
next_diff, next_playlist = self.__next_diff()
|
next_diff, next_playlist = self.__next_diff(diff)
|
||||||
playlist += next_playlist
|
playlist += next_playlist
|
||||||
|
|
||||||
# playlist update
|
# playlist update
|
||||||
|
@ -125,7 +139,7 @@ class Monitor:
|
||||||
if next_diff:
|
if next_diff:
|
||||||
self.log(
|
self.log(
|
||||||
type = Log.Type.load,
|
type = Log.Type.load,
|
||||||
source = dealer.id,
|
source = dealer.id_,
|
||||||
date = now,
|
date = now,
|
||||||
related_object = next_diff
|
related_object = next_diff
|
||||||
)
|
)
|
||||||
|
@ -137,7 +151,7 @@ class Monitor:
|
||||||
source.controller.skip()
|
source.controller.skip()
|
||||||
cl.log(
|
cl.log(
|
||||||
type = Log.Type.play,
|
type = Log.Type.play,
|
||||||
source = dealer.id,
|
source = dealer.id_,
|
||||||
date = now,
|
date = now,
|
||||||
related_object = next_diff,
|
related_object = next_diff,
|
||||||
)
|
)
|
||||||
|
|
|
@ -34,17 +34,20 @@ class StationController(plugins.StationController):
|
||||||
def fetch(self):
|
def fetch(self):
|
||||||
super().fetch()
|
super().fetch()
|
||||||
|
|
||||||
data = self._send('request.on_air')
|
rid = self._send('request.on_air')
|
||||||
if not data:
|
if not rid:
|
||||||
return
|
return
|
||||||
|
|
||||||
data = self._send('request.metadata', data, parse = True)
|
data = self._send('request.metadata', rid, parse = True)
|
||||||
if not data:
|
if not data:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.current_sound = data.get('initial_uri')
|
self.current_sound = data.get('initial_uri')
|
||||||
# FIXME: point to the Source object
|
self.current_source = [
|
||||||
self.current_source = data.get('source')
|
# we assume sound is always from a registered source
|
||||||
|
source for source in self.station.get_sources()
|
||||||
|
if source.rid = rid
|
||||||
|
][0]
|
||||||
|
|
||||||
|
|
||||||
class SourceController(plugins.SourceController):
|
class SourceController(plugins.SourceController):
|
||||||
|
@ -77,10 +80,7 @@ class SourceController(plugins.SourceController):
|
||||||
if not data:
|
if not data:
|
||||||
return
|
return
|
||||||
|
|
||||||
# FIXME: still usefull? originally tested only if there ass self.program
|
self.rid = data.get('rid')
|
||||||
source = data.get('source') or ''
|
|
||||||
if not source.startswith(self.id):
|
|
||||||
return
|
|
||||||
self.current_sound = data.get('initial_uri')
|
self.current_sound = data.get('initial_uri')
|
||||||
|
|
||||||
def stream(self):
|
def stream(self):
|
||||||
|
|
|
@ -53,10 +53,10 @@ class StationController:
|
||||||
"""
|
"""
|
||||||
Current sound being played (retrieved by fetch)
|
Current sound being played (retrieved by fetch)
|
||||||
"""
|
"""
|
||||||
|
current_source = None
|
||||||
@property
|
"""
|
||||||
def id(self):
|
Current source object that is responsible of self.current_sound
|
||||||
return '{station.slug}_{station.pk}'.format(station = self.station)
|
"""
|
||||||
|
|
||||||
# TODO: add function to launch external program?
|
# TODO: add function to launch external program?
|
||||||
|
|
||||||
|
@ -72,6 +72,7 @@ class StationController:
|
||||||
"""
|
"""
|
||||||
sources = self.station.get_sources()
|
sources = self.station.get_sources()
|
||||||
for source in sources:
|
for source in sources:
|
||||||
|
source.prepare()
|
||||||
if source.controller:
|
if source.controller:
|
||||||
source.controller.fetch()
|
source.controller.fetch()
|
||||||
|
|
||||||
|
@ -110,7 +111,6 @@ class StationController:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SourceController:
|
class SourceController:
|
||||||
"""
|
"""
|
||||||
Controller of a Source. Value are usually updated directly on the
|
Controller of a Source. Value are usually updated directly on the
|
||||||
|
@ -138,10 +138,6 @@ class SourceController:
|
||||||
Current source being responsible of the current sound
|
Current source being responsible of the current sound
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@property
|
|
||||||
def id(self):
|
|
||||||
return '{source.station.slug}_{source.slug}'.format(source = self.source)
|
|
||||||
|
|
||||||
__playlist = None
|
__playlist = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
4
notes.md
4
notes.md
|
@ -39,7 +39,9 @@
|
||||||
- list of played diffusions and tracks when non-stop;
|
- list of played diffusions and tracks when non-stop;
|
||||||
|
|
||||||
# Long term TODO
|
# Long term TODO
|
||||||
- automatic cancel of passed diffusion based on logs
|
- automatic cancel of passed diffusion based on logs?
|
||||||
|
- archives can be set afterwards for rerun, so check must be done
|
||||||
|
at the same time we monitor
|
||||||
- sounds monitor: max_size of path, take in account
|
- sounds monitor: max_size of path, take in account
|
||||||
- logs: archive functionnality
|
- logs: archive functionnality
|
||||||
- track stats for diffusions
|
- track stats for diffusions
|
||||||
|
|
Loading…
Reference in New Issue
Block a user