add sound item in diffusions; move programs.Sound's attribute 'remove' into the type + update its public attribute based on diffusion publication
This commit is contained in:
parent
502af1dba0
commit
801a89e503
|
@ -418,6 +418,11 @@ class DiffusionPage(Publication):
|
||||||
'initial__isnull': True,
|
'initial__isnull': True,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
publish_archive = models.BooleanField(
|
||||||
|
_('publish archive'),
|
||||||
|
default = False,
|
||||||
|
help_text = _('publish the podcast of the complete diffusion'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('Diffusion')
|
verbose_name = _('Diffusion')
|
||||||
|
@ -425,11 +430,11 @@ class DiffusionPage(Publication):
|
||||||
|
|
||||||
content_panels = [
|
content_panels = [
|
||||||
FieldPanel('diffusion'),
|
FieldPanel('diffusion'),
|
||||||
|
FieldPanel('publish_archive'),
|
||||||
] + Publication.content_panels + [
|
] + Publication.content_panels + [
|
||||||
InlinePanel('tracks', label=_('Tracks')),
|
InlinePanel('tracks', label=_('Tracks')),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_diffusion(cl, diff, model = None, **kwargs):
|
def from_diffusion(cl, diff, model = None, **kwargs):
|
||||||
model = model or cl
|
model = model or cl
|
||||||
|
@ -470,9 +475,50 @@ class DiffusionPage(Publication):
|
||||||
item.css_class = 'diffusion'
|
item.css_class = 'diffusion'
|
||||||
return item
|
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):
|
def save(self, *args, **kwargs):
|
||||||
|
# TODO: update public attribute of the archive + podcasts check if live
|
||||||
if self.diffusion:
|
if self.diffusion:
|
||||||
self.date = self.diffusion.start
|
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)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -51,8 +51,8 @@ PlayerPlaylist.prototype = {
|
||||||
items: undefined,
|
items: undefined,
|
||||||
|
|
||||||
find: function(stream) {
|
find: function(stream) {
|
||||||
return this.items.find(function(v) {
|
return this.items.find(function(stream_) {
|
||||||
return v.stream == item;
|
return stream_ == stream;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,17 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% with podcasts=self.get_podcasts %}
|
||||||
|
{% if podcasts %}
|
||||||
|
<div class="podcasts list">
|
||||||
|
<h2>{% trans "Podcasts" %}</h2>
|
||||||
|
{% for item in podcasts %}
|
||||||
|
{% include 'cms/snippets/sound_list_item.html' %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
{# TODO: podcasts #}
|
{# TODO: podcasts #}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
13
cms/templates/cms/snippets/sound_list_item.html
Normal file
13
cms/templates/cms/snippets/sound_list_item.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{# TODO: complete archive podcast -> info #}
|
||||||
|
<a class="list_item sound" onclick="player.playlist.add(new Sound(
|
||||||
|
title='{{ item.name|escape }}',
|
||||||
|
detail='{{ item.detail_url }}',
|
||||||
|
stream='{% static item.path %}'));">
|
||||||
|
<h3>{{ item.name }}</h3>
|
||||||
|
<span class="info">
|
||||||
|
{{ duration.date|date:'H:i:s' }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
|
|
@ -66,7 +66,7 @@ class DiffusionsMenu(GenericMenu):
|
||||||
def register_programs_menu_item():
|
def register_programs_menu_item():
|
||||||
return SubmenuMenuItem(
|
return SubmenuMenuItem(
|
||||||
_('Today\'s Diffusions'), DiffusionsMenu(),
|
_('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():
|
def register_programs_menu_item():
|
||||||
return SubmenuMenuItem(
|
return SubmenuMenuItem(
|
||||||
_('Programs'), ProgramsMenu(),
|
_('Programs'), ProgramsMenu(),
|
||||||
classnames='icon icon-folder-open-inverse', order=10
|
classnames='icon icon-folder-open-inverse', order=102
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ class StreamInline(admin.TabularInline):
|
||||||
extra = 1
|
extra = 1
|
||||||
|
|
||||||
class SoundInline(admin.TabularInline):
|
class SoundInline(admin.TabularInline):
|
||||||
fields = ['type', 'path', 'duration']
|
fields = ['type', 'path', 'duration','public']
|
||||||
# readonly_fields = fields
|
# readonly_fields = fields
|
||||||
model = Sound
|
model = Sound
|
||||||
extra = 0
|
extra = 0
|
||||||
|
@ -66,11 +66,11 @@ class TrackInline(GenericTabularInline):
|
||||||
class SoundAdmin(NameableAdmin):
|
class SoundAdmin(NameableAdmin):
|
||||||
fields = None
|
fields = None
|
||||||
list_display = ['id', 'name', 'duration', 'type', 'mtime',
|
list_display = ['id', 'name', 'duration', 'type', 'mtime',
|
||||||
'public', 'good_quality', 'removed']
|
'public', 'good_quality']
|
||||||
fieldsets = [
|
fieldsets = [
|
||||||
(None, { 'fields': NameableAdmin.fields + ['path', 'type', 'diffusion'] } ),
|
(None, { 'fields': NameableAdmin.fields + ['path', 'type', 'diffusion'] } ),
|
||||||
(None, { 'fields': ['embed', 'duration', 'public', 'mtime'] }),
|
(None, { 'fields': ['embed', 'duration', 'public', 'mtime'] }),
|
||||||
(None, { 'fields': ['removed', 'good_quality' ] } )
|
(None, { 'fields': ['good_quality' ] } )
|
||||||
]
|
]
|
||||||
readonly_fields = ('path', 'duration',)
|
readonly_fields = ('path', 'duration',)
|
||||||
inlines = [TrackInline]
|
inlines = [TrackInline]
|
||||||
|
|
|
@ -79,7 +79,7 @@ class Importer:
|
||||||
position = position,
|
position = position,
|
||||||
)
|
)
|
||||||
|
|
||||||
track.in_seconds = pos_in_secs
|
track.in_seconds = in_seconds
|
||||||
track.info = self.__get(line, 'info')
|
track.info = self.__get(line, 'info')
|
||||||
tags = self.__get(line, 'tags')
|
tags = self.__get(line, 'tags')
|
||||||
if tags:
|
if tags:
|
||||||
|
|
|
@ -157,7 +157,7 @@ class SoundInfo:
|
||||||
diffusion = diffusion[0]
|
diffusion = diffusion[0]
|
||||||
|
|
||||||
logger.info('diffusion %s mathes to sound -> %s', str(diffusion),
|
logger.info('diffusion %s mathes to sound -> %s', str(diffusion),
|
||||||
sound.path)
|
self.sound.path)
|
||||||
self.sound.diffusion = diffusion
|
self.sound.diffusion = diffusion
|
||||||
if save:
|
if save:
|
||||||
self.sound.save()
|
self.sound.save()
|
||||||
|
@ -201,7 +201,7 @@ class MonitorHandler(PatternMatchingEventHandler):
|
||||||
sound = Sound.objects.filter(path = event.src_path)
|
sound = Sound.objects.filter(path = event.src_path)
|
||||||
if sound:
|
if sound:
|
||||||
sound = sound[0]
|
sound = sound[0]
|
||||||
sound.removed = True
|
sound.type = sound.Type.removed
|
||||||
sound.save()
|
sound.save()
|
||||||
|
|
||||||
def on_moved(self, event):
|
def on_moved(self, event):
|
||||||
|
@ -296,7 +296,6 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
# sounds in directory
|
# sounds in directory
|
||||||
for path in os.listdir(subdir):
|
for path in os.listdir(subdir):
|
||||||
print(path)
|
|
||||||
path = os.path.join(subdir, path)
|
path = os.path.join(subdir, path)
|
||||||
if not path.endswith(settings.AIRCOX_SOUND_FILE_EXT):
|
if not path.endswith(settings.AIRCOX_SOUND_FILE_EXT):
|
||||||
continue
|
continue
|
||||||
|
@ -319,21 +318,23 @@ class Command(BaseCommand):
|
||||||
import aircox.programs.management.commands.sounds_quality_check \
|
import aircox.programs.management.commands.sounds_quality_check \
|
||||||
as 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:
|
if check:
|
||||||
self.check_sounds(sounds)
|
self.check_sounds(sounds)
|
||||||
|
|
||||||
files = [ sound.path for sound in 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) ]
|
if os.path.exists(sound.path) ]
|
||||||
|
|
||||||
|
# check quality
|
||||||
logger.info('quality check...',)
|
logger.info('quality check...',)
|
||||||
cmd = quality_check.Command()
|
cmd = quality_check.Command()
|
||||||
cmd.handle( files = files,
|
cmd.handle( files = files,
|
||||||
**settings.AIRCOX_SOUND_QUALITY )
|
**settings.AIRCOX_SOUND_QUALITY )
|
||||||
|
|
||||||
logger.info('update database')
|
# update stats
|
||||||
|
logger.info('update stats in database')
|
||||||
def update_stats(sound_info, sound):
|
def update_stats(sound_info, sound):
|
||||||
stats = sound_info.get_file_stats()
|
stats = sound_info.get_file_stats()
|
||||||
if stats:
|
if stats:
|
||||||
|
|
|
@ -121,6 +121,7 @@ class Sound(Nameable):
|
||||||
other = 0x00,
|
other = 0x00,
|
||||||
archive = 0x01,
|
archive = 0x01,
|
||||||
excerpt = 0x02,
|
excerpt = 0x02,
|
||||||
|
removed = 0x03,
|
||||||
|
|
||||||
diffusion = models.ForeignKey(
|
diffusion = models.ForeignKey(
|
||||||
'Diffusion',
|
'Diffusion',
|
||||||
|
@ -157,11 +158,6 @@ class Sound(Nameable):
|
||||||
blank = True, null = True,
|
blank = True, null = True,
|
||||||
help_text = _('last modification date and time'),
|
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 = models.BooleanField(
|
||||||
_('good quality'),
|
_('good quality'),
|
||||||
default = False,
|
default = False,
|
||||||
|
@ -204,15 +200,21 @@ class Sound(Nameable):
|
||||||
needed (do not save). Return True if there was changes.
|
needed (do not save). Return True if there was changes.
|
||||||
"""
|
"""
|
||||||
if not self.file_exists():
|
if not self.file_exists():
|
||||||
if self.removed:
|
if self.type == self.Type.removed:
|
||||||
return
|
return
|
||||||
logger.info('sound %s: has been removed', self.path)
|
logger.info('sound %s: has been removed', self.path)
|
||||||
self.removed = True
|
self.type = self.Type.removed
|
||||||
return True
|
return True
|
||||||
|
|
||||||
old_removed = self.removed
|
# not anymore removed
|
||||||
self.removed = False
|
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()
|
mtime = self.get_mtime()
|
||||||
if self.mtime != mtime:
|
if self.mtime != mtime:
|
||||||
self.mtime = mtime
|
self.mtime = mtime
|
||||||
|
@ -220,7 +222,7 @@ class Sound(Nameable):
|
||||||
logger.info('sound %s: m_time has changed. Reset quality info',
|
logger.info('sound %s: m_time has changed. Reset quality info',
|
||||||
self.path)
|
self.path)
|
||||||
return True
|
return True
|
||||||
return old_removed != self.removed
|
return changed
|
||||||
|
|
||||||
def check_perms(self):
|
def check_perms(self):
|
||||||
"""
|
"""
|
||||||
|
@ -529,6 +531,18 @@ class Program(Nameable):
|
||||||
os.makedirs(path, exist_ok = True)
|
os.makedirs(path, exist_ok = True)
|
||||||
return os.path.exists(path)
|
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):
|
def find_schedule(self, date):
|
||||||
"""
|
"""
|
||||||
Return the first schedule that matches a given date.
|
Return the first schedule that matches a given date.
|
||||||
|
@ -684,8 +698,15 @@ class Diffusion(models.Model):
|
||||||
ordered by path.
|
ordered by path.
|
||||||
"""
|
"""
|
||||||
sounds = self.initial.sound_set if self.initial else self.sound_set
|
sounds = self.initial.sound_set if self.initial else self.sound_set
|
||||||
return sounds.filter(type = Sound.Type.archive, removed = False). \
|
return sounds.filter(type = Sound.Type.archive).order_by('path')
|
||||||
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):
|
def is_date_in_range(self, date = None):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue
Block a user