diff --git a/README.md b/README.md index 66a116e..eb93234 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Python modules: * `django-honeypot`: `aircox.cms` * `bleach`: 'aircox.cms` (comments sanitization) * `dateutils`: `aircox.programs` (used for tests) -* `Pillow`: `aircox.cms` +* `Pillow`: `aircox.cms` (needed by `wagtail`) Applications: * `liquidsoap`: `aircox.controllers` (generation of the audio streams) diff --git a/controllers/models.py b/controllers/models.py index 9c57636..e2dc0fa 100644 --- a/controllers/models.py +++ b/controllers/models.py @@ -170,7 +170,9 @@ class Station(programs.Nameable): @staticmethod def __mix_logs_and_diff(diffs, logs, count = 0): """ - Mix together logs and diffusion items ordering by their date. + Mix together logs and diffusion items of the same day, + ordered by their date. + Diffs and Logs are assumed to be ordered by -date, and so is the resulting list """ @@ -189,10 +191,15 @@ class Station(programs.Nameable): if count and len(items) >= count: break - if diff_ and (not count or len(items) <= count): - logs_ = logs.filter(date__lt = diff_.end) - items.extend(logs_) + if diff_: + if count and len(items) >= count: + return items[:count] + logs_ = logs.filter(date__lt = diff_.end) + else: + logs_ = logs.all() + + items.extend(logs_) return items[:count] if count else items @@ -305,7 +312,8 @@ class Source(programs.Nameable): program = models.ForeignKey( programs.Program, verbose_name = _('related program'), - blank = True, null = True + blank = True, null = True, + limit_choices_to = { 'stream__isnull': False }, ) url = models.TextField( _('url'), @@ -355,7 +363,7 @@ class Source(programs.Nameable): self.controller.playlist = [ sound.path for sound in programs.Sound.objects.filter( type = programs.Sound.Type.archive, - path__startswith = program.path + program = program, ) ] return diff --git a/controllers/monitor.py b/controllers/monitor.py index de93c32..4b059df 100644 --- a/controllers/monitor.py +++ b/controllers/monitor.py @@ -25,6 +25,14 @@ class Monitor: Time in seconds before a diffusion that have archives is cancelled because it has not been played. """ + sync_timeout = 60*10 + """ + Time in minuts before all stream playlists are checked and updated + """ + sync_next = None + """ + Datetime of the next sync + """ def __init__(self, station, **kwargs): self.station = station @@ -44,6 +52,7 @@ class Monitor: return self.trace() + self.sync_playlists() self.handle() def log(self, **kwargs): @@ -112,6 +121,22 @@ class Monitor: related = track ) + def sync_playlists(self): + """ + Synchronize updated playlists + """ + now = tz.now() + if self.sync_next and self.sync_next < now: + return + + self.sync_next = now + tz.timedelta(seconds = self.sync_timeout) + + for source in self.station.stream_sources: + playlist = [ sound.path for sound in + source.program.sound_set.all().order_by('path') ] + if playlist != source.controller.playlist: + source.controller.playlist = playlist + def trace_canceled(self): """ Check diffusions that should have been played but did not start, diff --git a/controllers/templates/aircox/controllers/liquidsoap.liq b/controllers/templates/aircox/controllers/liquidsoap.liq index 7d6d7db..d958b69 100644 --- a/controllers/templates/aircox/controllers/liquidsoap.liq +++ b/controllers/templates/aircox/controllers/liquidsoap.liq @@ -43,7 +43,8 @@ A stream is a source that: - is interactive {% endcomment %} def stream (id, file) = - s = playlist(id = '#{id}_playlist', mode = "random", file) + s = playlist(id = '#{id}_playlist', mode = "random", reload_mode='watch', + file) interactive_source(id, s) end {% endblock %} diff --git a/notes.md b/notes.md index c02110b..a20db13 100644 --- a/notes.md +++ b/notes.md @@ -10,35 +10,6 @@ This file is used as a reminder, can be used as crappy documentation too. * icons: cropped to 32x32 * cover in list items: cropped 64x64 - - -# TODO: -- general: - - timezone shit - - translation - -- programs: - - schedule changes -> update later diffusions according to the new schedule - - users - - tests: - - sound_monitor - - import_playlist - -- controllers : - - models to template -> note - - input stream - - streamed program disable -> remote control on liquidsoap - - tests: - - monitor - - config generation and sound diffusion - -- cms: - - player: - - mixcloud - - remove from playing playlist -> stop - - filter choices on DiffusionPage and ProgramPage related objects - - # Long term TODO - debug/prod configuration @@ -46,9 +17,8 @@ programs: - sounds monitor: max_size of path, take in account controllers: - - 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 + - archives can be set afterwards for rerun, so check must be done + at the same time we monitor - logs: archive functionnality - tools: - track stats for diffusions diff --git a/programs/admin.py b/programs/admin.py index 1e6656b..2fa9f43 100755 --- a/programs/admin.py +++ b/programs/admin.py @@ -37,14 +37,6 @@ class DiffusionInline(admin.StackedInline): extra = 0 fields = ['type', 'start', 'end'] -# from suit.admin import SortableTabularInline, SortableModelAdmin -#class TrackInline(SortableTabularInline): -# fields = ['artist', 'name', 'tags', 'position'] -# form = TrackForm -# model = Track -# sortable = 'position' -# extra = 10 - class NameableAdmin(admin.ModelAdmin): fields = [ 'name' ] @@ -58,7 +50,7 @@ class TrackInline(GenericTabularInline): ct_fk_field = 'related_id' model = Track extra = 0 - fields = ('artist', 'title', 'tags', 'info', 'position') + fields = ('artist', 'title', 'info', 'position') readonly_fields = ('position',) @@ -68,7 +60,8 @@ class SoundAdmin(NameableAdmin): list_display = ['id', 'name', 'duration', 'type', 'mtime', 'public', 'good_quality'] fieldsets = [ - (None, { 'fields': NameableAdmin.fields + ['path', 'type', 'diffusion'] } ), + (None, { 'fields': NameableAdmin.fields + + ['path', 'type', 'program', 'diffusion'] } ), (None, { 'fields': ['embed', 'duration', 'public', 'mtime'] }), (None, { 'fields': ['good_quality' ] } ) ] diff --git a/programs/management/commands/sounds_monitor.py b/programs/management/commands/sounds_monitor.py index d3bc886..e180e4d 100644 --- a/programs/management/commands/sounds_monitor.py +++ b/programs/management/commands/sounds_monitor.py @@ -291,6 +291,8 @@ class Command(BaseCommand): if not program.ensure_dir(subdir): return + sound_kwargs['program'] = program + subdir = os.path.join(program.path, subdir) sounds = [] diff --git a/programs/models.py b/programs/models.py index 6179d31..0e3b7ea 100755 --- a/programs/models.py +++ b/programs/models.py @@ -123,11 +123,17 @@ class Sound(Nameable): excerpt = 0x02, removed = 0x03, + program = models.ForeignKey( + 'Program', + verbose_name = _('program'), + blank = True, null = True, + help_text = _('program related to it'), + ) diffusion = models.ForeignKey( 'Diffusion', verbose_name = _('diffusion'), blank = True, null = True, - help_text = _('this is set for scheduled programs') + help_text = _('initial diffusion related it') ) type = models.SmallIntegerField( verbose_name = _('type'), diff --git a/requirements.txt b/requirements.txt index 0f8f0d3..65cf9c0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,9 @@ Django>=1.9a1 -django-taggit>=0.12.1 +django-taggit>=0.18.3 watchdog>=0.8.3 wagtail>=1.5.3 +Pillow>=3.3.0 django-honeypot>=0.5.0 dateutils>=0.6.6 +bleach>=1.4.3