diff --git a/cms/routes.py b/cms/routes.py
index f76a02c..b213241 100644
--- a/cms/routes.py
+++ b/cms/routes.py
@@ -127,10 +127,14 @@ class ThreadRoute(Route):
@classmethod
def get_title(cl, model, request, thread_model, pk, **kwargs):
- return _('%(name)s: %(model)s') % {
- 'model': model._meta.verbose_name_plural,
- 'name': cl.get_thread(model, thread_model, pk).title,
- }
+ thread = cl.get_thread(model, thread_model, pk)
+ return '{title}'.format(
+ url = thread.url(),
+ title = _('%(name)s: %(model)s') % {
+ 'model': model._meta.verbose_name_plural,
+ 'name': thread.title,
+ }
+ )
class DateRoute(Route):
diff --git a/cms/templates/aircox/cms/website.html b/cms/templates/aircox/cms/website.html
index f8e6470..83fae0a 100644
--- a/cms/templates/aircox/cms/website.html
+++ b/cms/templates/aircox/cms/website.html
@@ -14,7 +14,7 @@
{% endif %}
-
{% if title %}{{ title }} - {% endif %}{{ website.name }}
+ {% if title %}{{ title|striptags }} - {% endif %}{{ website.name }}
{% block page_header %}
@@ -51,7 +51,7 @@
{% endif %}
{% block title %}
{% if title %}
- {{ title }}
+ {{ title|safe }}
{% endif %}
{% endblock %}
diff --git a/cms/views.py b/cms/views.py
index 542e2f6..b52b386 100644
--- a/cms/views.py
+++ b/cms/views.py
@@ -187,7 +187,7 @@ class PostListView(BaseView, ListView):
context = super().get_context_data(**kwargs)
- if not context.get('title') and self.route:
+ if self.route and not context.get('title'):
context['title'] = self.route.get_title(
self.model, self.request, **self.kwargs
)
diff --git a/liquidsoap/management/commands/liquidsoap.py b/liquidsoap/management/commands/liquidsoap.py
index add2512..2773d08 100644
--- a/liquidsoap/management/commands/liquidsoap.py
+++ b/liquidsoap/management/commands/liquidsoap.py
@@ -95,15 +95,18 @@ class Monitor:
# - preload next diffusion's tracks
args = {'start__gt': prev_diff.start } if prev_diff else {}
- next_diff = programs.Diffusion \
- .get(now, now = True,
- type = programs.Diffusion.Type.normal,
- sounds__isnull = False,
- **args) \
- .prefetch_related('sounds')
+ next_diff = programs.Diffusion.get(
+ now, now = True,
+ type = programs.Diffusion.Type.normal,
+ **args
+ )
if next_diff:
- next_diff = next_diff[0]
- playlist += next_diff.playlist
+ for diff in next_diffs:
+ if not diff.playlist:
+ continue
+ next_diff = diff
+ playlist += next_diff.playlist
+ break
# playlist update
if dealer.playlist != playlist:
diff --git a/liquidsoap/management/commands/liquidsoap_log.py b/liquidsoap/management/commands/liquidsoap_log.py
deleted file mode 100644
index 8d36e50..0000000
--- a/liquidsoap/management/commands/liquidsoap_log.py
+++ /dev/null
@@ -1,62 +0,0 @@
-"""
-This script is used by liquidsoap in order to log a file change. It should not
-be used for other purposes.
-"""
-import os
-from argparse import RawTextHelpFormatter
-
-from django.utils import timezone as tz
-from django.core.management.base import BaseCommand, CommandError
-
-import aircox.programs.models as programs
-
-
-class Command (BaseCommand):
- help= __doc__
-
- @staticmethod
- def date(s):
- try:
- return tz.make_aware(tz.datetime.strptime(s, '%Y/%m/%d %H:%M:%S'))
- except ValueError:
- raise argparse.ArgumentTypeError('Invalid date format')
-
-
- def add_arguments (self, parser):
- parser.formatter_class=RawTextHelpFormatter
- parser.add_argument(
- '-c', '--comment', type=str,
- help='log comment'
- )
- parser.add_argument(
- '-s', '--source', type=str,
- required=True,
- help='source path'
- )
- parser.add_argument(
- '-p', '--path', type=str,
- required=True,
- help='sound path to log'
- )
- parser.add_argument(
- '-d', '--date', type=Command.date,
- help='set date instead of now (using format "%Y/%m/%d %H:%M:%S")'
- )
-
-
- def handle (self, *args, **options):
- comment = options.get('comment') or ''
- path = os.path.realpath(options.get('path'))
-
- sound = programs.Sound.objects.filter(path = path)
- if sound:
- sound = sound[0]
- else:
- sound = None
- comment += '\nunregistered sound: {}'.format(path)
-
- programs.Log(source = options.get('source'),
- comment = comment,
- related_object = sound).save()
-
-
diff --git a/notes.md b/notes.md
index 83d374b..eb808a5 100644
--- a/notes.md
+++ b/notes.md
@@ -13,9 +13,9 @@
- sounds:
- check that a sound is available when uploading too
- one sound, one diffusion
- -> update admin & inlining
-> sound_monitor
-> liquidsoap
+ -> tests: sound_monitor, liquidsoap (monitor)
- liquidsoap:
- update rc's supervisor scripts
@@ -29,15 +29,15 @@
- cms.script
- cms.qcombine
- routes
- - customized header depending on the list (e.g. thread -> link to thread parent)
- integrate QCombine
- admin cms
- content management -> do we use a markup language?
- sections:
- - article list with the focus
- similar articles (using tags)
- calendar
- - tags: allow tags_url on all publications
+ - article list with the focus
+ -> set html attribute based on values that are public
+ - tags: allow tags_url route QCombine
- website:
- diffusions:
@@ -51,6 +51,7 @@
- load complete week for a schedule?
- finish that fucking website
- list of played diffusions and tracks when non-stop;
+ - search field -- section
diff --git a/programs/admin.py b/programs/admin.py
index b85d193..f8c52e0 100755
--- a/programs/admin.py
+++ b/programs/admin.py
@@ -24,8 +24,17 @@ class StreamInline(admin.TabularInline):
model = Stream
extra = 1
-class SoundDiffInline(admin.TabularInline):
+class SoundInline(admin.TabularInline):
+ fields = ['type', 'path', 'duration']
+ readonly_fields = fields
model = Sound
+ extra = 0
+
+
+class DiffusionInline(admin.StackedInline):
+ model = Diffusion
+ extra = 0
+ fields = ['type', 'start', 'end']
# from suit.admin import SortableTabularInline, SortableModelAdmin
#class TrackInline(SortableTabularInline):
@@ -83,11 +92,6 @@ class ProgramAdmin(NameableAdmin):
#return super().get_form(request, obj, **kwargs)
-class DiffusionInline(admin.StackedInline):
- model = Diffusion
- extra = 0
- fields = ['type', 'start', 'end']
-
@admin.register(Diffusion)
class DiffusionAdmin(admin.ModelAdmin):
def archives(self, obj):
@@ -112,8 +116,7 @@ class DiffusionAdmin(admin.ModelAdmin):
ordering = ('-start', 'id')
fields = ['type', 'start', 'end', 'initial', 'program']
- inlines = [ DiffusionInline, SoundDiffInline ]
- exclude = ('sounds',)
+ inlines = [ DiffusionInline, SoundInline ]
def get_form(self, request, obj=None, **kwargs):
@@ -121,9 +124,6 @@ class DiffusionAdmin(admin.ModelAdmin):
self.readonly_fields = []
else:
self.readonly_fields = ['program', 'start', 'end']
-
- if obj and obj.initial:
- self.readonly_fields += ['program', 'sounds']
return super().get_form(request, obj, **kwargs)
def get_object(self, *args, **kwargs):
diff --git a/programs/management/commands/sounds_monitor.py b/programs/management/commands/sounds_monitor.py
index b84bff7..57b92ed 100644
--- a/programs/management/commands/sounds_monitor.py
+++ b/programs/management/commands/sounds_monitor.py
@@ -51,11 +51,11 @@ class SoundInfo:
duration = None
@property
- def path (self):
+ def path(self):
return self._path
@path.setter
- def path (self, value):
+ def path(self, value):
"""
Parse file name to get info on the assumption it has the correct
format (given in Command.help)
@@ -83,10 +83,10 @@ class SoundInfo:
self.n = r.get('n')
return r
- def __init__ (self, path = ''):
+ def __init__(self, path = ''):
self.path = path
- def get_duration (self):
+ def get_duration(self):
p = subprocess.Popen(['soxi', '-D', self.path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
@@ -96,7 +96,7 @@ class SoundInfo:
self.duration = duration
return duration
- def get_sound (self, kwargs = None, save = True):
+ def get_sound(self, kwargs = None, save = True):
"""
Get or create a sound using self info.
@@ -116,47 +116,42 @@ class SoundInfo:
self.sound = sound
return sound
- def find_diffusion (self, program, attach = False):
+ def find_diffusion(self, program, save = True):
"""
For a given program, check if there is an initial diffusion
- to associate to, using the date info we have.
+ to associate to, using the date info we have. Update self.sound
+ and save it consequently.
We only allow initial diffusion since there should be no
rerun.
-
- If attach is True and we have self.sound, we add self.sound to
- the diffusion and update the DB.
"""
- if self.year == None:
+ if self.year == None or not self.sound or self.sound.diffusion:
return;
- # check on episodes
diffusion = Diffusion.objects.filter(
program = program,
+ initial__isnull = True,
start__year = self.year,
start__month = self.month,
start__day = self.day,
- initial = None,
)
if not diffusion:
return
-
diffusion = diffusion[0]
- if attach and self.sound:
- qs = diffusion.sounds.get_queryset().filter(path = sound.path)
- if not qs:
- logger.info('diffusion %s mathes to sound -> %s', str(diffusion),
- sound.path)
- diffusion.sounds.add(sound.pk)
- diffusion.save()
+
+ logger.info('diffusion %s mathes to sound -> %s', str(diffusion),
+ sound.path)
+ self.sound.diffusion = diffusion
+ if save:
+ self.sound.save()
return diffusion
-class MonitorHandler (PatternMatchingEventHandler):
+class MonitorHandler(PatternMatchingEventHandler):
"""
Event handler for watchdog, in order to be used in monitoring.
"""
- def __init__ (self, subdir):
+ def __init__(self, subdir):
"""
subdir: AIRCOX_SOUND_ARCHIVES_SUBDIR or AIRCOX_SOUND_EXCERPTS_SUBDIR
"""
@@ -170,10 +165,10 @@ class MonitorHandler (PatternMatchingEventHandler):
for ext in settings.AIRCOX_SOUND_FILE_EXT ]
super().__init__(patterns=patterns, ignore_directories=True)
- def on_created (self, event):
+ def on_created(self, event):
self.on_modified(event)
- def on_modified (self, event):
+ def on_modified(self, event):
logger.info('sound modified: %s', event.src_path)
program = Program.get_from_path(event.src_path)
if not program:
@@ -182,9 +177,9 @@ class MonitorHandler (PatternMatchingEventHandler):
si = SoundInfo(event.src_path)
si.get_sound(self.sound_kwargs, True)
if si.year != None:
- si.find_diffusion(program, True)
+ si.find_diffusion(program)
- def on_deleted (self, event):
+ def on_deleted(self, event):
logger.info('sound deleted: %s', event.src_path)
sound = Sound.objects.filter(path = event.src_path)
if sound:
@@ -192,7 +187,7 @@ class MonitorHandler (PatternMatchingEventHandler):
sound.removed = True
sound.save()
- def on_moved (self, event):
+ def on_moved(self, event):
logger.info('sound moved: %s -> %s', event.src_path, event.dest_path)
sound = Sound.objects.filter(path = event.src_path)
if not sound:
@@ -206,17 +201,17 @@ class MonitorHandler (PatternMatchingEventHandler):
sound.save()
-class Command (BaseCommand):
+class Command(BaseCommand):
help= __doc__
- def report (self, program = None, component = None, *content):
+ def report(self, program = None, component = None, *content):
if not component:
logger.info('%s: %s', str(program), ' '.join([str(c) for c in content]))
else:
logger.info('%s, %s: %s', str(program), str(component),
' '.join([str(c) for c in content]))
- def add_arguments (self, parser):
+ def add_arguments(self, parser):
parser.formatter_class=RawTextHelpFormatter
parser.add_argument(
'-q', '--quality_check', action='store_true',
@@ -226,7 +221,7 @@ class Command (BaseCommand):
parser.add_argument(
'-s', '--scan', action='store_true',
help='Scan programs directories for changes, plus check for a '
- ' matching episode on sounds that have not been yet assigned'
+ ' matching diffusion on sounds that have not been yet assigned'
)
parser.add_argument(
'-m', '--monitor', action='store_true',
@@ -235,7 +230,7 @@ class Command (BaseCommand):
)
- def handle (self, *args, **options):
+ def handle(self, *args, **options):
if options.get('scan'):
self.scan()
if options.get('quality_check'):
@@ -244,7 +239,7 @@ class Command (BaseCommand):
self.monitor()
@staticmethod
- def check_sounds (qs):
+ def check_sounds(qs):
"""
Only check for the sound existence or update
"""
@@ -253,7 +248,7 @@ class Command (BaseCommand):
if sound.check_on_file():
sound.save(check = False)
- def scan (self):
+ def scan(self):
"""
For all programs, scan dirs
"""
@@ -271,7 +266,7 @@ class Command (BaseCommand):
type = Sound.Type.excerpt,
)
- def scan_for_program (self, program, subdir, **sound_kwargs):
+ def scan_for_program(self, program, subdir, **sound_kwargs):
"""
Scan a given directory that is associated to the given program, and
update sounds information.
@@ -281,7 +276,7 @@ class Command (BaseCommand):
return
subdir = os.path.join(program.path, subdir)
- new_sounds = []
+ sounds = []
# sounds in directory
for path in os.listdir(subdir):
@@ -291,15 +286,15 @@ class Command (BaseCommand):
si = SoundInfo(path)
si.get_sound(sound_kwargs, True)
- if si.year != None:
- si.find_diffusion(program, True)
- new_sounds = [si.sound.pk]
+ si.find_diffusion(program)
+ sounds.append(si.sound.pk)
- # sounds in db
- self.check_sounds(Sound.objects.filter(path__startswith = subdir) \
- .exclude(pk__in = new_sounds ))
+ # sounds in db & unchecked
+ sounds = Sound.objects.filter(path__startswith = subdir). \
+ exclude(pk__in = sounds)
+ self.check_sounds(sounds)
- def check_quality (self, check = False):
+ def check_quality(self, check = False):
"""
Check all files where quality has been set to bad
"""
@@ -338,7 +333,7 @@ class Command (BaseCommand):
update_stats(sound_info, sound)
sound.save(check = False)
- def monitor (self):
+ def monitor(self):
"""
Run in monitor mode
"""
diff --git a/programs/models.py b/programs/models.py
index a967fc7..b3f1a36 100755
--- a/programs/models.py
+++ b/programs/models.py
@@ -577,31 +577,18 @@ class Diffusion(models.Model):
@property
def playlist(self):
"""
- List of sounds as playlist
+ List of archives' path; uses get_archives
"""
- playlist = [ sound.path for sound in self.sounds.all() ]
- playlist.sort()
- return playlist
-
- def archives_duration(self):
- """
- Get total duration of the archives. May differ from the schedule
- duration.
- """
- sounds = self.initial.sounds if self.initial else self.sounds
- r = [ sound.duration
- for sound in sounds.filter(type = Sound.Type.archive)
- if sound.duration ]
- return utils.time_sum(r)
+ return [ sound.path for sound in self.get_archives() ]
def get_archives(self):
"""
- Return an ordered list of archives sounds for the given episode.
+ Return a list of available archives sounds for the given episode,
+ ordered by path.
"""
- sounds = self.initial.sounds if self.initial else self.sounds
- r = [ sound for sound in sounds.all().order_by('path')
- if sound.type == Sound.Type.archive ]
- return r
+ sounds = self.initial.sound_set if self.initial else self.sound_set
+ return sounds.filter(type = Sound.Type.archive, removed = False). \
+ order_by('path')
@classmethod
def get(cl, date = None,
diff --git a/programs/utils.py b/programs/utils.py
index 9e46ea5..5f3f1aa 100644
--- a/programs/utils.py
+++ b/programs/utils.py
@@ -19,12 +19,3 @@ def seconds_to_time (seconds):
hours, minutes = divmod(minutes, 60)
return datetime.time(hour = hours, minute = minutes, second = seconds)
-def time_sum (times):
- """
- Sum up a list of time elements
- """
- seconds = sum([ time.hour * 3600 + time.minute * 60 + time.second
- for time in times ])
- return seconds_to_time(seconds)
-
-