diff --git a/cms/models.py b/cms/models.py index ba65c57..a173439 100644 --- a/cms/models.py +++ b/cms/models.py @@ -418,6 +418,11 @@ class DiffusionPage(Publication): 'initial__isnull': True, }, ) + publish_archive = models.BooleanField( + _('publish archive'), + default = False, + help_text = _('publish the podcast of the complete diffusion'), + ) class Meta: verbose_name = _('Diffusion') @@ -425,11 +430,11 @@ class DiffusionPage(Publication): content_panels = [ FieldPanel('diffusion'), + FieldPanel('publish_archive'), ] + Publication.content_panels + [ InlinePanel('tracks', label=_('Tracks')), ] - @classmethod def from_diffusion(cl, diff, model = None, **kwargs): model = model or cl @@ -470,9 +475,50 @@ class DiffusionPage(Publication): item.css_class = 'diffusion' return item + def get_archive(self): + if not self.publish_archive: + return + + sound = self.diffusion.get_archives() \ + .filter(public = True).first() + if sound: + sound.detail_url = self.detail_url + return sound + + def get_podcasts(self): + """ + Return a list of podcasts, with archive as the first item of the + list when available. + """ + podcasts = [] + archive = self.get_archive() + if archive: + podcasts.append(archive) + + qs = self.diffusion.get_excerpts().filter(public = True) + podcasts.extend(qs[:]) + for podcast in podcasts: + podcast.detail_url = self.url + return podcasts + + def save(self, *args, **kwargs): + # TODO: update public attribute of the archive + podcasts check if live if self.diffusion: self.date = self.diffusion.start + + # update podcasts' attributes + for podcast in self.diffusion.sound_set \ + .exclude(type = programs.Sound.Type.removed): + publish = self.live and self.publish_archive \ + if podcast.type == podcast.Type.archive else self.live + + if podcast.public != publish: + podcast.public = publish + podcast.save() + + + super().save(*args, **kwargs) diff --git a/cms/static/cms/js/player.js b/cms/static/cms/js/player.js index 144b576..26ec4f5 100644 --- a/cms/static/cms/js/player.js +++ b/cms/static/cms/js/player.js @@ -51,8 +51,8 @@ PlayerPlaylist.prototype = { items: undefined, find: function(stream) { - return this.items.find(function(v) { - return v.stream == item; + return this.items.find(function(stream_) { + return stream_ == stream; }); }, diff --git a/cms/templates/cms/diffusion_page.html b/cms/templates/cms/diffusion_page.html index e71ac42..4b088a4 100644 --- a/cms/templates/cms/diffusion_page.html +++ b/cms/templates/cms/diffusion_page.html @@ -30,6 +30,17 @@ +{% with podcasts=self.get_podcasts %} +{% if podcasts %} +
+

{% trans "Podcasts" %}

+ {% for item in podcasts %} + {% include 'cms/snippets/sound_list_item.html' %} + {% endfor %} +
+{% endif %} +{% endwith %} + {# TODO: podcasts #} {% endblock %} diff --git a/cms/templates/cms/snippets/sound_list_item.html b/cms/templates/cms/snippets/sound_list_item.html new file mode 100644 index 0000000..7a5d766 --- /dev/null +++ b/cms/templates/cms/snippets/sound_list_item.html @@ -0,0 +1,13 @@ +{% load static %} + +{# TODO: complete archive podcast -> info #} + +

{{ item.name }}

+ + {{ duration.date|date:'H:i:s' }} + +
+ diff --git a/cms/wagtail_hooks.py b/cms/wagtail_hooks.py index 53d00c8..55937ee 100644 --- a/cms/wagtail_hooks.py +++ b/cms/wagtail_hooks.py @@ -66,7 +66,7 @@ class DiffusionsMenu(GenericMenu): def register_programs_menu_item(): return SubmenuMenuItem( _('Today\'s Diffusions'), DiffusionsMenu(), - classnames='icon icon-folder-open-inverse', order=10 + classnames='icon icon-folder-open-inverse', order=101 ) @@ -97,7 +97,7 @@ class ProgramsMenu(GenericMenu): def register_programs_menu_item(): return SubmenuMenuItem( _('Programs'), ProgramsMenu(), - classnames='icon icon-folder-open-inverse', order=10 + classnames='icon icon-folder-open-inverse', order=102 ) diff --git a/programs/admin.py b/programs/admin.py index 812ff94..1e6656b 100755 --- a/programs/admin.py +++ b/programs/admin.py @@ -26,7 +26,7 @@ class StreamInline(admin.TabularInline): extra = 1 class SoundInline(admin.TabularInline): - fields = ['type', 'path', 'duration'] + fields = ['type', 'path', 'duration','public'] # readonly_fields = fields model = Sound extra = 0 @@ -66,11 +66,11 @@ class TrackInline(GenericTabularInline): class SoundAdmin(NameableAdmin): fields = None list_display = ['id', 'name', 'duration', 'type', 'mtime', - 'public', 'good_quality', 'removed'] + 'public', 'good_quality'] fieldsets = [ (None, { 'fields': NameableAdmin.fields + ['path', 'type', 'diffusion'] } ), (None, { 'fields': ['embed', 'duration', 'public', 'mtime'] }), - (None, { 'fields': ['removed', 'good_quality' ] } ) + (None, { 'fields': ['good_quality' ] } ) ] readonly_fields = ('path', 'duration',) inlines = [TrackInline] diff --git a/programs/management/commands/import_playlist.py b/programs/management/commands/import_playlist.py index 0ea04d2..f7c29db 100644 --- a/programs/management/commands/import_playlist.py +++ b/programs/management/commands/import_playlist.py @@ -79,7 +79,7 @@ class Importer: position = position, ) - track.in_seconds = pos_in_secs + track.in_seconds = in_seconds track.info = self.__get(line, 'info') tags = self.__get(line, 'tags') if tags: diff --git a/programs/management/commands/sounds_monitor.py b/programs/management/commands/sounds_monitor.py index e45d154..d3bc886 100644 --- a/programs/management/commands/sounds_monitor.py +++ b/programs/management/commands/sounds_monitor.py @@ -157,7 +157,7 @@ class SoundInfo: diffusion = diffusion[0] logger.info('diffusion %s mathes to sound -> %s', str(diffusion), - sound.path) + self.sound.path) self.sound.diffusion = diffusion if save: self.sound.save() @@ -201,7 +201,7 @@ class MonitorHandler(PatternMatchingEventHandler): sound = Sound.objects.filter(path = event.src_path) if sound: sound = sound[0] - sound.removed = True + sound.type = sound.Type.removed sound.save() def on_moved(self, event): @@ -296,7 +296,6 @@ class Command(BaseCommand): # sounds in directory for path in os.listdir(subdir): - print(path) path = os.path.join(subdir, path) if not path.endswith(settings.AIRCOX_SOUND_FILE_EXT): continue @@ -319,21 +318,23 @@ class Command(BaseCommand): import aircox.programs.management.commands.sounds_quality_check \ as quality_check - sounds = Sound.objects.filter(good_quality = False) + # get available sound files + sounds = Sound.objects.filter(good_quality = False) \ + .exclude(type = Sound.Type.removed) if check: self.check_sounds(sounds) - files = [ sound.path for sound in sounds - if not sound.removed and os.path.exists(sound.path) ] - else: - files = [ sound.path for sound in sounds.filter(removed = False) - if os.path.exists(sound.path) ] + files = [ sound.path for sound in sounds + if os.path.exists(sound.path) ] + + # check quality logger.info('quality check...',) cmd = quality_check.Command() cmd.handle( files = files, **settings.AIRCOX_SOUND_QUALITY ) - logger.info('update database') + # update stats + logger.info('update stats in database') def update_stats(sound_info, sound): stats = sound_info.get_file_stats() if stats: diff --git a/programs/models.py b/programs/models.py index 0bb856a..8f0615f 100755 --- a/programs/models.py +++ b/programs/models.py @@ -121,6 +121,7 @@ class Sound(Nameable): other = 0x00, archive = 0x01, excerpt = 0x02, + removed = 0x03, diffusion = models.ForeignKey( 'Diffusion', @@ -157,11 +158,6 @@ class Sound(Nameable): blank = True, null = True, help_text = _('last modification date and time'), ) - removed = models.BooleanField( - _('removed'), - default = False, - help_text = _('this sound has been removed from filesystem'), - ) good_quality = models.BooleanField( _('good quality'), default = False, @@ -204,15 +200,21 @@ class Sound(Nameable): needed (do not save). Return True if there was changes. """ if not self.file_exists(): - if self.removed: + if self.type == self.Type.removed: return logger.info('sound %s: has been removed', self.path) - self.removed = True + self.type = self.Type.removed return True - old_removed = self.removed - self.removed = False + # not anymore removed + changed = False + if self.type == self.Type.removed and self.program: + changed = True + self.type = self.Type.archive \ + if self.path.startswith(self.program.archives_path) else \ + self.Type.excerpt + # check mtime -> reset quality if changed (assume file changed) mtime = self.get_mtime() if self.mtime != mtime: self.mtime = mtime @@ -220,7 +222,7 @@ class Sound(Nameable): logger.info('sound %s: m_time has changed. Reset quality info', self.path) return True - return old_removed != self.removed + return changed def check_perms(self): """ @@ -529,6 +531,18 @@ class Program(Nameable): os.makedirs(path, exist_ok = True) return os.path.exists(path) + @property + def archives_path(self): + return os.path.join( + self.path, settings.AIRCOX_SOUND_ARCHIVES_SUBDIR + ) + + @property + def excerpts_path(self): + return os.path.join( + self.path, settings.AIRCOX_SOUND_ARCHIVES_SUBDIR + ) + def find_schedule(self, date): """ Return the first schedule that matches a given date. @@ -684,8 +698,15 @@ class Diffusion(models.Model): ordered by path. """ sounds = self.initial.sound_set if self.initial else self.sound_set - return sounds.filter(type = Sound.Type.archive, removed = False). \ - order_by('path') + return sounds.filter(type = Sound.Type.archive).order_by('path') + + def get_excerpts(self): + """ + Return a list of available archives sounds for the given episode, + ordered by path. + """ + sounds = self.initial.sound_set if self.initial else self.sound_set + return sounds.filter(type = Sound.Type.excerpt).order_by('path') def is_date_in_range(self, date = None): """