change strategy on liquidsoap logging

This commit is contained in:
bkfox 2015-12-16 21:09:21 +01:00
parent 1a71aeb166
commit f03acb4c1b
22 changed files with 115 additions and 86 deletions

View File

@ -12,10 +12,6 @@ Platform to manage a radio. We use the power of Django
## Applications
* **programs**: managing stations, programs, schedules and diffusions. This is the core application, that handle most of the work.
* **cms**: cms manager with reusable tools.
* **liquidsoap**: liquidsoap manager and control.
* **liquidsoap**: liquidsoap controls.
## Code and names conventions and uses
* absolute dates: datetime fields, named "begin" "end" for ranges and "date" otherwise
* time range: timefield name "duration"
* parents: when only one parent, named "parent", otherwise model/reference's name

View File

@ -70,7 +70,7 @@ class PostListView (PostBaseView, ListView):
return
self.__dict__.update(query)
template_name = 'aircox_cms/list.html'
template_name = 'aircox/cms/list.html'
allow_empty = True
paginate_by = 50
model = None
@ -143,7 +143,7 @@ class PostDetailView (DetailView, PostBaseView):
"""
Detail view for posts and children
"""
template_name = 'aircox_cms/detail.html'
template_name = 'aircox/cms/detail.html'
sections = []
@ -179,7 +179,7 @@ class PostDetailView (DetailView, PostBaseView):
class Menu (View):
template_name = 'aircox_cms/menu.html'
template_name = 'aircox/cms/menu.html'
name = ''
tag = 'nav'
@ -218,7 +218,7 @@ class BaseSection (View):
Base class for sections. Sections are view that can be used in detail view
in order to have extra content about a post, or in menus.
"""
template_name = 'aircox_cms/base_section.html'
template_name = 'aircox/cms/base_section.html'
kwargs = None # kwargs argument passed to get
tag = 'div' # container tags
classes = '' # container classes
@ -253,7 +253,7 @@ class Section (BaseSection):
"""
A Section that can be related to an object.
"""
template_name = 'aircox_cms/section.html'
template_name = 'aircox/cms/section.html'
object = None
object_required = False
title = ''
@ -331,7 +331,7 @@ class Sections:
use_icons = True # print icons
paginate_by = 0 # number of items
icon_size = '32x32' # icons size
template_name = 'aircox_cms/section_list.html'
template_name = 'aircox/cms/section_list.html'
def get_object_list (self):
return []

View File

@ -8,6 +8,7 @@ import time
import re
from argparse import RawTextHelpFormatter
from django.conf import settings as main_settings
from django.core.management.base import BaseCommand, CommandError
from django.template.loader import render_to_string
from django.utils import timezone as tz
@ -36,12 +37,20 @@ class StationConfig:
self.make_playlists()
def make_config (self):
log_script = main_settings.BASE_DIR \
if hasattr(main_settings, 'BASE_DIR') else \
main_settings.PROJECT_ROOT
log_script = os.path.join(log_script, 'manage.py') + \
' liquidsoap_log'
context = {
'controller': self.controller,
'settings': settings,
'log_script': log_script,
}
data = render_to_string('aircox_liquidsoap/station.liq', context)
data = render_to_string('aircox/liquidsoap/station.liq', context)
data = re.sub(r'\s*\\\n', r'#\\n#', data)
data = data.replace('\n', '')
data = re.sub(r'#\\n#', '\n', data)

View File

@ -0,0 +1,62 @@
"""
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()

View File

@ -106,15 +106,15 @@
</header>
<div class="sources">
{% with source=controller.master %}
{% include 'aircox_liquidsoap/base_source.html' %}
{% include 'aircox_liquidsoap/source.html' %}
{% endwith %}
{% with source=controller.dealer %}
{% include 'aircox_liquidsoap/base_source.html' %}
{% include 'aircox_liquidsoap/source.html' %}
{% endwith %}
{% for source in controller.streams.values %}
{% include 'aircox_liquidsoap/base_source.html' %}
{% include 'aircox_liquidsoap/source.html' %}
{% endfor %}
</div>
<div class="next">

View File

@ -1,9 +1,14 @@
{# Context: #}
{# - controller: controller used to generate the current file #}
{# - settings: global settings #}
def interactive_source (id, s) = \
s = store_metadata(id=id, size=1, s) \
def handler(m) = \
file = string.escape(m['filename']) \
system('{{ log_script }} -s "#{id}" -p "#{file}" -c "liquidsoap: play" &') \
end \
\
s = on_track(id=id, handler, s)
# s = store_metadata(id=id, size=1, s) \
add_skip_command(s) \
s \
end \
@ -16,7 +21,7 @@ end \
\
{# Config #}
set("server.socket", true) \
set("server.socket.path", {{ controller.socket_path }}) \
set("server.socket.path", "{{ controller.socket_path }}") \
{% for key, value in settings.AIRCOX_LIQUIDSOAP_SET.items %}
set("{{ key|safe }}", {{ value|safe }}) \
{% endfor %}

View File

@ -279,39 +279,6 @@ class Dealer (Source):
if diffusion.playlist and on_air not in diffusion.playlist:
return diffusion
def monitor (self):
"""
Monitor playlist (if it is time to load) and if it time to trigger
the button to start a diffusion.
"""
playlist = self.playlist
on_air = self.current_sound
now = tz.make_aware(tz.datetime.now())
diff = self.__get_next(now, on_air)
if not diff:
return # there is nothing we can do
# playlist reload
if self.playlist != diff.playlist:
if not playlist or on_air == playlist[-1] or \
on_air not in playlist:
self.on = False
self.playlist = diff.playlist
# run the diff
if self.playlist == diff.playlist and diff.date <= now:
self.on = True
for source in self.controller.streams.values():
source.skip()
self.controller.log(
source = self.id,
date = now,
comment = 'trigger the scheduled diffusion to liquidsoap; '
'skip all other streams',
related_object = diff,
)
class Controller:
"""
@ -412,27 +379,6 @@ class Controller:
for source in self.streams.values():
source.update()
def __change_log (self, source):
last_log = programs.Log.objects.filter(
source = source.id,
).prefetch_related('sound').order_by('-date')
on_air = source.current_sound
if not on_air:
return
if last_log:
last_log = last_log[0]
if last_log.sound and on_air == last_log.sound.path:
return
self.log(
source = source.id,
date = tz.make_aware(tz.datetime.now()),
comment = 'sound has changed',
related_object = programs.Sound.objects.get(path = on_air),
)
def monitor (self):
"""
Log changes in the streams, and call dealer.monitor.
@ -441,9 +387,6 @@ class Controller:
return
self.dealer.monitor()
self.__change_log(self.dealer)
for source in self.streams.values():
self.__change_log(source)
class Monitor:

View File

@ -38,7 +38,7 @@ class Actions:
class LiquidControl (View):
template_name = 'aircox_liquidsoap/controller.html'
template_name = 'aircox/liquidsoap/controller.html'
def get_context_data (self, **kwargs):
get_monitor().update()

View File

@ -100,7 +100,7 @@ class DiffusionAdmin (admin.ModelAdmin):
else:
self.readonly_fields = ['program', 'date', 'duration']
if obj.initial:
if obj and obj.initial:
self.readonly_fields += ['program', 'sounds']
return super().get_form(request, obj, **kwargs)

View File

@ -639,13 +639,9 @@ class Log (models.Model):
help_text = 'source information',
blank = True, null = True,
)
sound = models.ForeignKey(
'Sound',
help_text = _('played sound'),
blank = True, null = True,
)
date = models.DateTimeField(
'date',
auto_now_add=True,
)
comment = models.CharField(
max_length = 512,
@ -662,12 +658,20 @@ class Log (models.Model):
'related_type', 'related_id',
)
@classmethod
def get_for_related_model (cl, model):
"""
Return a queryset that filter related_type to the given one.
"""
return cl.objects.filter(related_type__pk =
ContentType.objects.get_for_model(model).id)
def print (self):
print(str(self), ':', self.comment or '')
if self.diffusion:
print(' - diffusion #' + str(self.diffusion.id))
if self.sound:
print(' - sound #' + str(self.sound.id), self.sound.path)
if self.related_object:
print(' - {}: #{}'.format(self.related_type,
self.related_id))
def __str__ (self):
return self.date.strftime('%Y-%m-%d %H:%M') + ', ' + self.source

10
manage.py Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "instance.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)