change strategy on liquidsoap logging
This commit is contained in:
parent
1a71aeb166
commit
f03acb4c1b
|
@ -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
|
||||
|
||||
|
|
|
@ -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 []
|
||||
|
|
|
@ -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)
|
||||
|
|
62
aircox/liquidsoap/management/commands/liquidsoap_log.py
Normal file
62
aircox/liquidsoap/management/commands/liquidsoap_log.py
Normal 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()
|
||||
|
||||
|
|
@ -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">
|
|
@ -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 %}
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user