fix stuff; sound inline in admin
This commit is contained in:
parent
35e7e407e7
commit
361cf88bb2
|
@ -1,5 +1,6 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.utils.translation import gettext as _, gettext_lazy
|
from django.utils.safestring import mark_safe
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from adminsortable2.admin import SortableInlineAdminMixin
|
from adminsortable2.admin import SortableInlineAdminMixin
|
||||||
|
|
||||||
|
@ -21,9 +22,13 @@ class SoundTrackInline(TrackInline):
|
||||||
|
|
||||||
class SoundInline(admin.TabularInline):
|
class SoundInline(admin.TabularInline):
|
||||||
model = Sound
|
model = Sound
|
||||||
fields = ['type', 'path', 'embed', 'duration', 'is_public']
|
fields = ['type', 'name', 'audio', 'duration', 'is_good_quality', 'is_public']
|
||||||
readonly_fields = ['type', 'path', 'duration']
|
readonly_fields = ['type', 'audio', 'duration', 'is_good_quality']
|
||||||
extra = 0
|
extra = 0
|
||||||
|
max_num = 0
|
||||||
|
|
||||||
|
def audio(self, obj):
|
||||||
|
return mark_safe('<audio src="{}" controls></audio>'.format(obj.url()))
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
return super().get_queryset(request).available()
|
return super().get_queryset(request).available()
|
||||||
|
@ -40,11 +45,10 @@ class SoundAdmin(admin.ModelAdmin):
|
||||||
'is_public', 'is_good_quality', 'episode', 'filename']
|
'is_public', 'is_good_quality', 'episode', 'filename']
|
||||||
list_filter = ('type', 'is_good_quality', 'is_public')
|
list_filter = ('type', 'is_good_quality', 'is_public')
|
||||||
|
|
||||||
search_fields = ['name', 'program']
|
search_fields = ['name', 'program__title']
|
||||||
fieldsets = [
|
fieldsets = [
|
||||||
(None, {'fields': ['name', 'path', 'type', 'program', 'episode']}),
|
(None, {'fields': ['name', 'path', 'type', 'program', 'episode']}),
|
||||||
(None, {'fields': ['embed', 'duration', 'is_public', 'mtime']}),
|
(None, {'fields': ['duration', 'is_public', 'is_good_quality', 'mtime']}),
|
||||||
(None, {'fields': ['is_good_quality']})
|
|
||||||
]
|
]
|
||||||
readonly_fields = ('path', 'duration',)
|
readonly_fields = ('path', 'duration',)
|
||||||
inlines = [SoundTrackInline]
|
inlines = [SoundTrackInline]
|
||||||
|
|
|
@ -60,6 +60,12 @@ class Stats:
|
||||||
self.parse(str(out, encoding='utf-8'))
|
self.parse(str(out, encoding='utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
#class SoundFile:
|
||||||
|
# path = None
|
||||||
|
# sample_rate = None
|
||||||
|
# length = None
|
||||||
|
|
||||||
|
|
||||||
class Sound:
|
class Sound:
|
||||||
path = None # file path
|
path = None # file path
|
||||||
sample_length = 120 # default sample length in seconds
|
sample_length = 120 # default sample length in seconds
|
||||||
|
|
|
@ -37,9 +37,9 @@ class SoundQuerySet(models.QuerySet):
|
||||||
def available(self):
|
def available(self):
|
||||||
return self.exclude(type=Sound.TYPE_REMOVED)
|
return self.exclude(type=Sound.TYPE_REMOVED)
|
||||||
|
|
||||||
def podcasts(self):
|
def public(self):
|
||||||
""" Return sounds available as podcasts """
|
""" Return sounds available as podcasts """
|
||||||
return self.filter(Q(embed__isnull=False) | Q(is_public=True))
|
return self.filter(is_public=True)
|
||||||
|
|
||||||
def archive(self):
|
def archive(self):
|
||||||
""" Return sounds that are archives """
|
""" Return sounds that are archives """
|
||||||
|
@ -103,11 +103,11 @@ class Sound(models.Model):
|
||||||
recursive=True, max_length=255,
|
recursive=True, max_length=255,
|
||||||
blank=True, null=True, unique=True,
|
blank=True, null=True, unique=True,
|
||||||
)
|
)
|
||||||
embed = models.TextField(
|
#embed = models.TextField(
|
||||||
_('embed'),
|
# _('embed'),
|
||||||
blank=True, null=True,
|
# blank=True, null=True,
|
||||||
help_text=_('HTML code to embed a sound from an external plateform'),
|
# help_text=_('HTML code to embed a sound from an external plateform'),
|
||||||
)
|
#)
|
||||||
duration = models.TimeField(
|
duration = models.TimeField(
|
||||||
_('duration'),
|
_('duration'),
|
||||||
blank=True, null=True,
|
blank=True, null=True,
|
||||||
|
@ -156,19 +156,12 @@ class Sound(models.Model):
|
||||||
return tz.make_aware(mtime, tz.get_current_timezone())
|
return tz.make_aware(mtime, tz.get_current_timezone())
|
||||||
|
|
||||||
def url(self):
|
def url(self):
|
||||||
"""
|
""" Return an url to the stream. """
|
||||||
Return an url to the stream
|
|
||||||
"""
|
|
||||||
# path = self._meta.get_field('path').path
|
|
||||||
path = self.path.replace(main_settings.MEDIA_ROOT, '', 1)
|
path = self.path.replace(main_settings.MEDIA_ROOT, '', 1)
|
||||||
#path = self.path.replace(path, '', 1)
|
|
||||||
|
|
||||||
return main_settings.MEDIA_URL + '/' + path
|
return main_settings.MEDIA_URL + '/' + path
|
||||||
|
|
||||||
def file_exists(self):
|
def file_exists(self):
|
||||||
"""
|
""" Return true if the file still exists. """
|
||||||
Return true if the file still exists
|
|
||||||
"""
|
|
||||||
|
|
||||||
return os.path.exists(self.path)
|
return os.path.exists(self.path)
|
||||||
|
|
||||||
|
@ -241,23 +234,6 @@ class Sound(models.Model):
|
||||||
|
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
def check_perms(self):
|
|
||||||
"""
|
|
||||||
Check file permissions and update it if the sound is public
|
|
||||||
"""
|
|
||||||
|
|
||||||
if not settings.AIRCOX_SOUND_AUTO_CHMOD or \
|
|
||||||
self.removed or not os.path.exists(self.path):
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
flags = settings.AIRCOX_SOUND_CHMOD_FLAGS[self.is_public]
|
|
||||||
try:
|
|
||||||
os.chmod(self.path, flags)
|
|
||||||
except PermissionError as err:
|
|
||||||
logger.error('cannot set permissions {} to file {}: {}'.format(
|
|
||||||
self.flags[self.is_public], self.path, err))
|
|
||||||
|
|
||||||
def __check_name(self):
|
def __check_name(self):
|
||||||
if not self.name and self.path:
|
if not self.name and self.path:
|
||||||
# FIXME: later, remove date?
|
# FIXME: later, remove date?
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import os
|
import os
|
||||||
import stat
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
@ -38,8 +37,6 @@ from django.conf import settings
|
||||||
# sounds_default_dir = os.path.join(settings.MEDIA_ROOT, 'programs/defaults')
|
# sounds_default_dir = os.path.join(settings.MEDIA_ROOT, 'programs/defaults')
|
||||||
# sound_archive_dir = 'archives'
|
# sound_archive_dir = 'archives'
|
||||||
# sound_excerpt_dir = 'excerpts'
|
# sound_excerpt_dir = 'excerpts'
|
||||||
# sound_auto_chmod = True
|
|
||||||
# sound_chmod_flags = (stat.S_IRWXU, stat.S_IRWXU | stat.S_IRWXG | stat.S_IROTH)
|
|
||||||
# sound_quality = {
|
# sound_quality = {
|
||||||
# 'attribute': 'RMS lev dB',
|
# 'attribute': 'RMS lev dB',
|
||||||
# 'range': (-18.0, -8.0),
|
# 'range': (-18.0, -8.0),
|
||||||
|
@ -116,15 +113,6 @@ ensure('AIRCOX_SOUND_ARCHIVES_SUBDIR', 'archives')
|
||||||
# Sub directory used for the excerpts of the episode
|
# Sub directory used for the excerpts of the episode
|
||||||
ensure('AIRCOX_SOUND_EXCERPTS_SUBDIR', 'excerpts')
|
ensure('AIRCOX_SOUND_EXCERPTS_SUBDIR', 'excerpts')
|
||||||
|
|
||||||
# Change sound perms based on 'public' attribute if True
|
|
||||||
ensure('AIRCOX_SOUND_AUTO_CHMOD', True)
|
|
||||||
# Chmod bits flags as a tuple for (not public, public). Use os.chmod
|
|
||||||
# and stat.*
|
|
||||||
ensure(
|
|
||||||
'AIRCOX_SOUND_CHMOD_FLAGS',
|
|
||||||
(stat.S_IRWXU, stat.S_IRWXU | stat.S_IRWXG | stat.S_IROTH)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Quality attributes passed to sound_quality_check from sounds_monitor
|
# Quality attributes passed to sound_quality_check from sounds_monitor
|
||||||
ensure('AIRCOX_SOUND_QUALITY', {
|
ensure('AIRCOX_SOUND_QUALITY', {
|
||||||
'attribute': 'RMS lev dB',
|
'attribute': 'RMS lev dB',
|
||||||
|
|
|
@ -28,7 +28,7 @@ The audio player
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:track="{ onAir }">
|
<template v-slot:track="{ onAir }">
|
||||||
<h4 class="title is-4">
|
<h4 class="title is-4" :aria-description="{% trans "Track currently on air" %}">
|
||||||
<span class="has-text-info is-size-3">♬</span>
|
<span class="has-text-info is-size-3">♬</span>
|
||||||
<span>[[ onAir.title ]]</span>
|
<span>[[ onAir.title ]]</span>
|
||||||
<span class="has-text-grey-dark has-text-weight-light">
|
<span class="has-text-grey-dark has-text-weight-light">
|
||||||
|
@ -39,14 +39,14 @@ The audio player
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:diffusion="{ onAir }">
|
<template v-slot:diffusion="{ onAir }">
|
||||||
<h4 class="title is-4">
|
<h4 class="title is-4" :aria-description="{% trans "Diffusion currently on air" %}">
|
||||||
<a :href="onAir.url">[[ onAir.title ]]</a>
|
<a :href="onAir.url">[[ onAir.title ]]</a>
|
||||||
</h4>
|
</h4>
|
||||||
<div class="">[[ onAir.info ]]</div>
|
<div class="">[[ onAir.info ]]</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:empty>
|
<template v-slot:empty>
|
||||||
<h4 class="title is-4">{{ station.name }}</h4>
|
<h4 class="title is-4" :aria-description="{% trans "Currently playing" %}">{{ station.name }}</h4>
|
||||||
</template>
|
</template>
|
||||||
</a-player>
|
</a-player>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,9 +3,11 @@ List item for a podcast.
|
||||||
|
|
||||||
{% endcomment %}
|
{% endcomment %}
|
||||||
<div class="podcast">
|
<div class="podcast">
|
||||||
|
{# comment #}
|
||||||
{% if object.embed %}
|
{% if object.embed %}
|
||||||
{{ object.embed|safe }}
|
{{ object.embed|safe }}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
{# endcomment #}
|
||||||
<audio src="{{ object.url }}" controls>
|
<audio src="{{ object.url }}" controls>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,6 @@ from collections import OrderedDict
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from django.views.generic import ListView
|
from django.views.generic import ListView
|
||||||
from django.utils.translation import gettext as _
|
|
||||||
|
|
||||||
from ..models import Diffusion, Episode, Program, StaticPage, Sound
|
from ..models import Diffusion, Episode, Program, StaticPage, Sound
|
||||||
from .base import BaseView
|
from .base import BaseView
|
||||||
|
@ -17,14 +16,11 @@ __all__ = ['EpisodeDetailView', 'EpisodeListView', 'DiffusionListView']
|
||||||
class EpisodeDetailView(ProgramPageDetailView):
|
class EpisodeDetailView(ProgramPageDetailView):
|
||||||
model = Episode
|
model = Episode
|
||||||
|
|
||||||
def get_podcasts(self, diffusion):
|
|
||||||
return Sound.objects.diffusion(diffusion).podcasts()
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
if not 'tracks' in kwargs:
|
if not 'tracks' in kwargs:
|
||||||
kwargs['tracks'] = self.object.track_set.order_by('position')
|
kwargs['tracks'] = self.object.track_set.order_by('position')
|
||||||
if not 'podcasts' in kwargs:
|
if not 'podcasts' in kwargs:
|
||||||
kwargs['podcasts'] = self.object.sound_set.podcasts()
|
kwargs['podcasts'] = self.object.sound_set.public()
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,8 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
state: State.paused,
|
state: State.paused,
|
||||||
liveInfo: new LiveInfo(this.liveInfoUrl, this.liveInfoTimeout),
|
liveInfo: this.liveInfoUrl ? new LiveInfo(this.liveInfoUrl, this.liveInfoTimeout)
|
||||||
|
: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -55,7 +56,7 @@ export default {
|
||||||
loading() { return this.state == State.loading; },
|
loading() { return this.state == State.loading; },
|
||||||
|
|
||||||
onAir() {
|
onAir() {
|
||||||
return this.liveInfo.items && this.liveInfo.items[0];
|
return this.liveInfo && this.liveInfo.items && this.liveInfo.items[0];
|
||||||
},
|
},
|
||||||
|
|
||||||
buttonStyle() {
|
buttonStyle() {
|
||||||
|
@ -83,7 +84,6 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
toggle() {
|
toggle() {
|
||||||
console.log('tooogle', this.paused, '-', this.$refs.audio.src)
|
|
||||||
if(this.paused)
|
if(this.paused)
|
||||||
this.play()
|
this.play()
|
||||||
else
|
else
|
||||||
|
@ -97,11 +97,11 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.liveInfo.refresh()
|
this.liveInfo && this.liveInfo.refresh()
|
||||||
},
|
},
|
||||||
|
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.liveInfo.drop()
|
this.liveInfo && this.liveInfo.drop()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user