forked from rc/aircox
new management tool: add
This commit is contained in:
parent
57f9159dbb
commit
f7d36467f0
|
@ -81,6 +81,7 @@ class SoundFileAdmin (MetadataAdmin):
|
||||||
]
|
]
|
||||||
|
|
||||||
#inlines = [ EpisodeInline ]
|
#inlines = [ EpisodeInline ]
|
||||||
|
inlines = [ EventInline ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -93,16 +94,15 @@ class ArticleAdmin (PublicationAdmin):
|
||||||
|
|
||||||
class ProgramAdmin (PublicationAdmin):
|
class ProgramAdmin (PublicationAdmin):
|
||||||
fieldsets = copy.deepcopy(PublicationAdmin.fieldsets)
|
fieldsets = copy.deepcopy(PublicationAdmin.fieldsets)
|
||||||
prepopulated_fields = { 'tag': ('title',) }
|
|
||||||
inlines = [ EpisodeInline, ScheduleInline ]
|
inlines = [ EpisodeInline, ScheduleInline ]
|
||||||
|
|
||||||
fieldsets[1][1]['fields'] += ['email', 'url', 'tag']
|
fieldsets[1][1]['fields'] += ['email', 'url', 'non_stop']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class EpisodeAdmin (PublicationAdmin):
|
class EpisodeAdmin (PublicationAdmin):
|
||||||
fieldsets = copy.deepcopy(PublicationAdmin.fieldsets)
|
fieldsets = copy.deepcopy(PublicationAdmin.fieldsets)
|
||||||
inlines = [ EventInline, SoundFileInline ]
|
inlines = [ SoundFileInline ]
|
||||||
list_filter = ['parent'] + PublicationAdmin.list_filter
|
list_filter = ['parent'] + PublicationAdmin.list_filter
|
||||||
|
|
||||||
fieldsets[0][1]['fields'] += ['tracks']
|
fieldsets[0][1]['fields'] += ['tracks']
|
||||||
|
|
143
programs/management/commands/add.py
Normal file
143
programs/management/commands/add.py
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
from django.utils import timezone
|
||||||
|
import programs.models as models
|
||||||
|
|
||||||
|
|
||||||
|
class Model:
|
||||||
|
# dict: key is the argument name, value is the constructor
|
||||||
|
required = {}
|
||||||
|
optional = {}
|
||||||
|
model = None
|
||||||
|
|
||||||
|
|
||||||
|
def __init__ (self, model, required = {}, optional = {}, post = None):
|
||||||
|
self.model = model
|
||||||
|
self.required = required
|
||||||
|
self.optional = optional
|
||||||
|
self.post = post
|
||||||
|
|
||||||
|
|
||||||
|
def check_or_raise (self, options):
|
||||||
|
for req in self.required:
|
||||||
|
if req not in options:
|
||||||
|
raise ValueError('required argument ' + req + ' is missing')
|
||||||
|
|
||||||
|
|
||||||
|
def get_kargs (self, options):
|
||||||
|
kargs = {}
|
||||||
|
|
||||||
|
for i in self.required:
|
||||||
|
if options.get(i):
|
||||||
|
fn = self.required[i]
|
||||||
|
kargs[i] = fn(options[i])
|
||||||
|
|
||||||
|
for i in self.optional:
|
||||||
|
if options.get(i):
|
||||||
|
print(i, options)
|
||||||
|
fn = self.optional[i]
|
||||||
|
kargs[i] = fn(options[i])
|
||||||
|
|
||||||
|
return kargs
|
||||||
|
|
||||||
|
|
||||||
|
def make (self, options):
|
||||||
|
self.check_or_raise(options)
|
||||||
|
|
||||||
|
kargs = self.get_kargs(options)
|
||||||
|
instance = self.model(**kargs)
|
||||||
|
instance.save()
|
||||||
|
|
||||||
|
if self.post:
|
||||||
|
self.post(instance, options)
|
||||||
|
|
||||||
|
print(instance.__dict__)
|
||||||
|
|
||||||
|
|
||||||
|
def DateTime (string):
|
||||||
|
dt = timezone.datetime.strptime(string, '%Y-%m-%d %H:%M:%S')
|
||||||
|
return timezone.make_aware(dt, timezone.get_current_timezone())
|
||||||
|
|
||||||
|
|
||||||
|
def Time (string):
|
||||||
|
dt = timezone.datetime.strptime(string, '%H:%M')
|
||||||
|
return timezone.datetime.time(dt)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def AddTags (instance, options):
|
||||||
|
if options.get('tags'):
|
||||||
|
instance.tags.add(*options['tags'])
|
||||||
|
|
||||||
|
|
||||||
|
models = {
|
||||||
|
'program': Model( models.Program
|
||||||
|
, { 'title': str }
|
||||||
|
, { 'subtitle': str, 'can_comment': bool, 'date': DateTime
|
||||||
|
, 'parent_id': int, 'public': bool
|
||||||
|
, 'url': str, 'email': str, 'non_stop': bool
|
||||||
|
}
|
||||||
|
, AddTags
|
||||||
|
)
|
||||||
|
, 'article': Model( models.Article
|
||||||
|
, { 'title': str }
|
||||||
|
, { 'subtitle': str, 'can_comment': bool, 'date': DateTime
|
||||||
|
, 'parent_id': int, 'public': bool
|
||||||
|
, 'static_page': bool, 'focus': bool
|
||||||
|
}
|
||||||
|
, AddTags
|
||||||
|
)
|
||||||
|
, 'schedule': Model( models.Schedule
|
||||||
|
, { 'parent_id': int, 'date': DateTime, 'duration': Time
|
||||||
|
, 'frequency': int }
|
||||||
|
, { 'rerun': bool }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Command (BaseCommand):
|
||||||
|
help="Add an element of the given model"
|
||||||
|
|
||||||
|
|
||||||
|
def add_arguments (self, parser):
|
||||||
|
parser.add_argument( 'model', type=str
|
||||||
|
, metavar="MODEL"
|
||||||
|
, help="model to add. It must be in [schedule,program,article]")
|
||||||
|
|
||||||
|
# publication/generic
|
||||||
|
parser.add_argument('--parent_id', type=str)
|
||||||
|
parser.add_argument('--title', type=str)
|
||||||
|
parser.add_argument('--subtitle', type=str)
|
||||||
|
parser.add_argument('--can_comment',action='store_true')
|
||||||
|
parser.add_argument('--public', action='store_true')
|
||||||
|
parser.add_argument( '--date', type=str
|
||||||
|
, help='a valid date time (Y/m/d H:m:s')
|
||||||
|
parser.add_argument('--tags', type=str, nargs='+')
|
||||||
|
|
||||||
|
# program
|
||||||
|
parser.add_argument('--url', type=str)
|
||||||
|
parser.add_argument('--email', type=str)
|
||||||
|
parser.add_argument('--non_stop', type=int)
|
||||||
|
|
||||||
|
# article
|
||||||
|
parser.add_argument('--static_page',action='store_true')
|
||||||
|
parser.add_argument('--focus', action='store_true')
|
||||||
|
|
||||||
|
# schedule
|
||||||
|
parser.add_argument('--duration', type=str)
|
||||||
|
parser.add_argument('--frequency', type=int)
|
||||||
|
parser.add_argument('--rerun', action='store_true')
|
||||||
|
|
||||||
|
|
||||||
|
def handle (self, *args, **options):
|
||||||
|
model = options.get('model')
|
||||||
|
if not model:
|
||||||
|
return
|
||||||
|
|
||||||
|
model = model.lower()
|
||||||
|
if model not in models:
|
||||||
|
raise ValueError("model {} is not supported".format(str(model)))
|
||||||
|
|
||||||
|
models[model].make(options)
|
||||||
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
import os
|
|
||||||
|
|
||||||
from django.core.management.base import BaseCommand, CommandError
|
|
||||||
import programs.models as models
|
|
||||||
import programs.settings
|
|
||||||
|
|
||||||
|
|
||||||
class Command (BaseCommand):
|
|
||||||
help= "Take a look at the programs directory to check on new podcasts"
|
|
||||||
|
|
||||||
|
|
||||||
def handle (self, *args, **options):
|
|
||||||
programs = models.Program.objects.filter(schedule__isnull = True)
|
|
||||||
|
|
||||||
for program in programs:
|
|
||||||
self.scan(program, program.path + '/public', public = True)
|
|
||||||
self.scan(program, program.path + '/podcasts', embed = True)
|
|
||||||
self.scan(program, program.path + '/private')
|
|
||||||
|
|
||||||
|
|
||||||
def scan (self, program, path, public = False, embed = False):
|
|
||||||
try:
|
|
||||||
for filename in os.listdir(path):
|
|
||||||
long_filename = path + '/' + filename
|
|
||||||
|
|
||||||
# check for new sound files
|
|
||||||
# stat the sound files
|
|
||||||
# match sound files against episodes - if not found, create it
|
|
||||||
# upload public podcasts to mixcloud if required
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
import datetime
|
|
||||||
|
|
||||||
from django.core.management.base import BaseCommand, CommandError
|
|
||||||
from django.utils import timezone, dateformat
|
|
||||||
|
|
||||||
import programs.models as models
|
|
||||||
import programs.settings
|
|
||||||
|
|
||||||
|
|
||||||
class Diffusion:
|
|
||||||
ref = None
|
|
||||||
date_start = None
|
|
||||||
date_end = None
|
|
||||||
|
|
||||||
def __init__ (self, ref, date_start, date_end):
|
|
||||||
self.ref = ref
|
|
||||||
self.date_start = date_start
|
|
||||||
self.date_end = date_end
|
|
||||||
|
|
||||||
def __lt__ (self, d):
|
|
||||||
return self.date_start < d.date_start and \
|
|
||||||
self.date_end < d.date_end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Command (BaseCommand):
|
|
||||||
help= "check sounds to diffuse"
|
|
||||||
|
|
||||||
diffusions = set()
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
self.get_next_events()
|
|
||||||
self.get_next_episodes()
|
|
||||||
|
|
||||||
for diffusion in self.diffusions:
|
|
||||||
print( diffusion.ref.__str__()
|
|
||||||
, diffusion.date_start
|
|
||||||
, diffusion.date_end)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_next_episodes (self):
|
|
||||||
schedules = models.Schedule.objects.filter()
|
|
||||||
for schedule in schedules:
|
|
||||||
date = schedule.next_date()
|
|
||||||
if not date:
|
|
||||||
continue
|
|
||||||
|
|
||||||
dt = datetime.timedelta( hours = schedule.duration.hour
|
|
||||||
, minutes = schedule.duration.minute
|
|
||||||
, seconds = schedule.duration.second )
|
|
||||||
|
|
||||||
ref = models.Episode.objects.filter(date = date)[:1]
|
|
||||||
if not ref:
|
|
||||||
ref = ( schedule.parent, )
|
|
||||||
|
|
||||||
diffusion = Diffusion(ref[0], date, date + dt)
|
|
||||||
self.diffusions.add(diffusion)
|
|
||||||
|
|
||||||
|
|
||||||
def get_next_events (self):
|
|
||||||
events = models.Event.objects.filter(date_end__gt = timezone.now(),
|
|
||||||
canceled = False) \
|
|
||||||
.extra(order_by = ['date'])[:10]
|
|
||||||
for event in events:
|
|
||||||
diffusion = Diffusion(event, event.date, event.date_end)
|
|
||||||
self.diffusions.add(diffusion)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,45 +1,38 @@
|
||||||
import datetime
|
import os
|
||||||
|
|
||||||
# django
|
# django
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.template.defaultfilters import slugify
|
from django.template.defaultfilters import slugify
|
||||||
|
|
||||||
from django.http import HttpResponse, Http404
|
|
||||||
|
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.html import strip_tags
|
from django.utils.html import strip_tags
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
# extensions
|
# extensions
|
||||||
from taggit.managers import TaggableManager
|
from taggit.managers import TaggableManager
|
||||||
|
|
||||||
|
|
||||||
import programs.settings as settings
|
import programs.settings as settings
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AFrequency = {
|
Frequency = {
|
||||||
'ponctual': 0x000000,
|
'ponctual': 0b000000
|
||||||
'every week': 0b001111,
|
, 'every week': 0b001111
|
||||||
'first week': 0x000001,
|
, 'first week': 0b000001
|
||||||
'second week': 0x000010,
|
, 'second week': 0b000010
|
||||||
'third week': 0x000100,
|
, 'third week': 0b000100
|
||||||
'fourth week': 0x001000,
|
, 'fourth week': 0b001000
|
||||||
'first and third': 0x000101,
|
, 'first and third': 0b000101
|
||||||
'second and fourth': 0x001010,
|
, 'second and fourth': 0b001010
|
||||||
'one week on two': 0x010010,
|
, 'one week on two': 0b010010
|
||||||
#'uneven week': 0x100000,
|
#'uneven week': 0b100000
|
||||||
# TODO 'every day': 0x110000
|
# TODO 'every day': 0b110000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Translators: html safe values
|
# Translators: html safe values
|
||||||
ugettext_lazy('ponctual')
|
ugettext_lazy('ponctual')
|
||||||
ugettext_lazy('every week')
|
ugettext_lazy('every week')
|
||||||
|
@ -52,10 +45,15 @@ ugettext_lazy('second and fourth')
|
||||||
ugettext_lazy('one week on two')
|
ugettext_lazy('one week on two')
|
||||||
|
|
||||||
|
|
||||||
Frequency = [ (y, x) for x,y in AFrequency.items() ]
|
EventType = {
|
||||||
RFrequency = { y: x for x,y in AFrequency.items() }
|
'play': 0x02 # the sound is playing / planified to play
|
||||||
|
, 'cancel': 0x03 # the sound has been canceled from grid; useful to give
|
||||||
|
# the info to the users
|
||||||
|
, 'stop': 0x04 # the sound has been arbitrary stopped (non-stop or not)
|
||||||
|
, 'non-stop': 0x05 # the sound has been played as non-stop
|
||||||
|
#, 'streaming'
|
||||||
|
}
|
||||||
|
|
||||||
Frequency.sort(key = lambda e: e[0])
|
|
||||||
|
|
||||||
|
|
||||||
class Model (models.Model):
|
class Model (models.Model):
|
||||||
|
@ -106,7 +104,7 @@ class Metadata (Model):
|
||||||
)
|
)
|
||||||
date = models.DateTimeField(
|
date = models.DateTimeField(
|
||||||
_('date')
|
_('date')
|
||||||
, default = datetime.datetime.now
|
, default = timezone.datetime.now
|
||||||
)
|
)
|
||||||
public = models.BooleanField(
|
public = models.BooleanField(
|
||||||
_('public')
|
_('public')
|
||||||
|
@ -190,12 +188,6 @@ class Publication (Metadata):
|
||||||
#
|
#
|
||||||
# Instance's methods
|
# Instance's methods
|
||||||
#
|
#
|
||||||
def get_parent (self, raise_404 = False ):
|
|
||||||
if not parent and raise_404:
|
|
||||||
raise Http404
|
|
||||||
return parent
|
|
||||||
|
|
||||||
|
|
||||||
def get_parents ( self, order_by = "desc", include_fields = None ):
|
def get_parents ( self, order_by = "desc", include_fields = None ):
|
||||||
"""
|
"""
|
||||||
Return an array of the parents of the item.
|
Return an array of the parents of the item.
|
||||||
|
@ -262,10 +254,9 @@ class SoundFile (Metadata):
|
||||||
, blank = True
|
, blank = True
|
||||||
, null = True
|
, null = True
|
||||||
)
|
)
|
||||||
file = models.FileField(
|
file = models.FileField( #FIXME: filefield
|
||||||
_('file')
|
_('file')
|
||||||
, upload_to = "data/tracks"
|
, upload_to = lambda i, f: SoundFile.__upload_path(i,f)
|
||||||
, blank = True
|
|
||||||
)
|
)
|
||||||
duration = models.TimeField(
|
duration = models.TimeField(
|
||||||
_('duration')
|
_('duration')
|
||||||
|
@ -277,12 +268,24 @@ class SoundFile (Metadata):
|
||||||
, default = False
|
, default = False
|
||||||
, help_text = _("the file has been cut")
|
, help_text = _("the file has been cut")
|
||||||
)
|
)
|
||||||
embed = models.TextField (
|
embed = models.TextField(
|
||||||
_('embed HTML code from external website')
|
_('embed HTML code from external website')
|
||||||
, blank = True
|
, blank = True
|
||||||
, null = True
|
, null = True
|
||||||
, help_text = _('if set, consider the sound podcastable from there')
|
, help_text = _('if set, consider the sound podcastable from there')
|
||||||
)
|
)
|
||||||
|
removed = models.BooleanField(
|
||||||
|
default = False
|
||||||
|
, help_text = _('this sound has been removed from filesystem')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def __upload_path (self, filename):
|
||||||
|
if self.parent and self.parent.parent:
|
||||||
|
path = self.parent.parent.path
|
||||||
|
else:
|
||||||
|
path = settings.AIRCOX_SOUNDFILE_DEFAULT_DIR
|
||||||
|
return os.path.join(path, filename)
|
||||||
|
|
||||||
|
|
||||||
def __str__ (self):
|
def __str__ (self):
|
||||||
|
@ -294,29 +297,44 @@ class SoundFile (Metadata):
|
||||||
verbose_name_plural = _('Sounds')
|
verbose_name_plural = _('Sounds')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Schedule (Model):
|
class Schedule (Model):
|
||||||
parent = models.ForeignKey( 'Program', blank = True, null = True )
|
parent = models.ForeignKey( 'Program', blank = True, null = True )
|
||||||
date = models.DateTimeField(_('start'))
|
date = models.DateTimeField(_('start'))
|
||||||
duration = models.TimeField(_('duration'))
|
duration = models.TimeField(
|
||||||
frequency = models.SmallIntegerField(_('frequency'), choices = Frequency)
|
_('duration')
|
||||||
|
, blank = True
|
||||||
|
, null = True
|
||||||
|
)
|
||||||
|
frequency = models.SmallIntegerField(
|
||||||
|
_('frequency')
|
||||||
|
, choices = [ (y, x) for x,y in Frequency.items() ]
|
||||||
|
)
|
||||||
rerun = models.BooleanField(_('rerun'), default = False)
|
rerun = models.BooleanField(_('rerun'), default = False)
|
||||||
|
|
||||||
|
|
||||||
def match_week (self, at = datetime.date.today()):
|
def match_date (self, at = timezone.datetime.today()):
|
||||||
|
"""
|
||||||
|
Return True if the given datetime matches the schedule
|
||||||
|
"""
|
||||||
|
if self.date.weekday() == at.weekday() and self.match_week(date):
|
||||||
|
return self.date.time() == at.date.time()
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def match_week (self, at = timezone.datetime.today()):
|
||||||
"""
|
"""
|
||||||
Return True if the given week number matches the schedule, False
|
Return True if the given week number matches the schedule, False
|
||||||
otherwise.
|
otherwise.
|
||||||
If the schedule is ponctual, return None.
|
If the schedule is ponctual, return None.
|
||||||
"""
|
"""
|
||||||
if self.frequency == AFrequency['ponctual']:
|
if self.frequency == Frequency['ponctual']:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if self.frequency == AFrequency['one week on two']:
|
if self.frequency == Frequency['one week on two']:
|
||||||
week = at.isocalendar()[1]
|
week = at.isocalendar()[1]
|
||||||
return (week % 2) == (self.date.isocalendar()[1] % 2)
|
return (week % 2) == (self.date.isocalendar()[1] % 2)
|
||||||
|
|
||||||
first_of_month = datetime.date(at.year, at.month, 1)
|
first_of_month = timezone.datetime.date(at.year, at.month, 1)
|
||||||
week = at.isocalendar()[1] - first_of_month.isocalendar()[1]
|
week = at.isocalendar()[1] - first_of_month.isocalendar()[1]
|
||||||
|
|
||||||
# weeks of month
|
# weeks of month
|
||||||
|
@ -326,30 +344,29 @@ class Schedule (Model):
|
||||||
return (self.frequency & (0b0001 << week) > 0)
|
return (self.frequency & (0b0001 << week) > 0)
|
||||||
|
|
||||||
|
|
||||||
|
def next_date (self, at = timezone.datetime.today()):
|
||||||
def next_date (self, at = datetime.date.today()):
|
if self.frequency == Frequency['ponctual']:
|
||||||
if self.frequency == AFrequency['ponctual']:
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# first day of the week
|
# first day of the week
|
||||||
date = at - datetime.timedelta( days = at.weekday() )
|
date = at - timezone.timedelta( days = at.weekday() )
|
||||||
|
|
||||||
# for the next five week, we look for a matching week.
|
# for the next five week, we look for a matching week.
|
||||||
# when found, add the number of day since de start of the
|
# when found, add the number of day since de start of the
|
||||||
# we need to test if the result is >= at
|
# we need to test if the result is >= at
|
||||||
for i in range(0,5):
|
for i in range(0,5):
|
||||||
if self.match_week(date):
|
if self.match_week(date):
|
||||||
date_ = date + datetime.timedelta( days = self.date.weekday() )
|
date_ = date + timezone.timedelta( days = self.date.weekday() )
|
||||||
if date_ >= at:
|
if date_ >= at:
|
||||||
# we don't want past events
|
# we don't want past events
|
||||||
return datetime.datetime(date_.year, date_.month, date_.day,
|
return timezone.datetime(date_.year, date_.month, date_.day,
|
||||||
self.date.hour, self.date.minute)
|
self.date.hour, self.date.minute)
|
||||||
date += datetime.timedelta( days = 7 )
|
date += timezone.timedelta( days = 7 )
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def next_dates (self, at = datetime.date.today(), n = 52):
|
def next_dates (self, at = timezone.datetime.today(), n = 52):
|
||||||
# we could have optimized this function, but since it should not
|
# we could have optimized this function, but since it should not
|
||||||
# be use too often, we keep a more readable and easier to debug
|
# be use too often, we keep a more readable and easier to debug
|
||||||
# solution
|
# solution
|
||||||
|
@ -362,20 +379,20 @@ class Schedule (Model):
|
||||||
if not e:
|
if not e:
|
||||||
break
|
break
|
||||||
res.append(e)
|
res.append(e)
|
||||||
at = res[-1] + datetime.timedelta(days = 1)
|
at = res[-1] + timezone.timedelta(days = 1)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def to_string(self):
|
#def to_string(self):
|
||||||
s = ugettext_lazy( RFrequency[self.frequency] )
|
# s = ugettext_lazy( RFrequency[self.frequency] )
|
||||||
if self.rerun:
|
# if self.rerun:
|
||||||
return s + ' (' + _('rerun') + ')'
|
# return s + ' (' + _('rerun') + ')'
|
||||||
return s
|
# return s
|
||||||
|
|
||||||
|
|
||||||
def __str__ (self):
|
def __str__ (self):
|
||||||
return self.parent.title + ': ' + RFrequency[self.frequency]
|
frequency = [ x for x,y in Frequency.items() if y == self.frequency ]
|
||||||
|
return self.parent.title + ': ' + frequency[0]
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -427,15 +444,17 @@ class Program (Publication):
|
||||||
, blank = True
|
, blank = True
|
||||||
, null = True
|
, null = True
|
||||||
)
|
)
|
||||||
tag = models.CharField(
|
non_stop = models.SmallIntegerField(
|
||||||
_('tag')
|
_('non-stop priority')
|
||||||
, max_length = 64
|
, help_text = _('this program can be used as non-stop')
|
||||||
, help_text = _('used in articles to refer to it')
|
, default = -1
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def path(self):
|
def path(self):
|
||||||
return settings.AIRCOX_PROGRAMS_DATA + slugify(self.title + '_' + self.id)
|
return os.path.join( settings.AIRCOX_PROGRAMS_DIR
|
||||||
|
, slugify(self.title + '_' + str(self.id))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -455,8 +474,6 @@ class Episode (Publication):
|
||||||
parent = models.ForeignKey(
|
parent = models.ForeignKey(
|
||||||
Program
|
Program
|
||||||
, verbose_name = _('parent')
|
, verbose_name = _('parent')
|
||||||
, blank = True
|
|
||||||
, null = True
|
|
||||||
)
|
)
|
||||||
tracks = models.ManyToManyField(
|
tracks = models.ManyToManyField(
|
||||||
Track
|
Track
|
||||||
|
@ -473,37 +490,22 @@ class Episode (Publication):
|
||||||
|
|
||||||
class Event (Model):
|
class Event (Model):
|
||||||
"""
|
"""
|
||||||
|
Event logs and planification of a sound file
|
||||||
"""
|
"""
|
||||||
parent = models.ForeignKey (
|
sound = models.ForeignKey (
|
||||||
Episode
|
SoundFile
|
||||||
, verbose_name = _('episode')
|
, verbose_name = _('sound file')
|
||||||
, blank = True
|
|
||||||
, null = True
|
|
||||||
)
|
)
|
||||||
date = models.DateTimeField( _('date of start') )
|
type = models.SmallIntegerField(
|
||||||
date_end = models.DateTimeField(
|
_('type')
|
||||||
_('date of end')
|
, choices = [ (y, x) for x,y in EventType.items() ]
|
||||||
, blank = True
|
|
||||||
, null = True
|
|
||||||
)
|
|
||||||
public = models.BooleanField(
|
|
||||||
_('public')
|
|
||||||
, default = False
|
|
||||||
, help_text = _('publication is accessible to the public')
|
|
||||||
)
|
)
|
||||||
|
date = models.DateTimeField( _('date of event start') )
|
||||||
meta = models.TextField (
|
meta = models.TextField (
|
||||||
_('meta')
|
_('meta')
|
||||||
, blank = True
|
, blank = True
|
||||||
, null = True
|
, null = True
|
||||||
)
|
)
|
||||||
canceled = models.BooleanField( _('canceled'), default = False )
|
|
||||||
|
|
||||||
|
|
||||||
def testify (self):
|
|
||||||
parent = self.parent
|
|
||||||
self.parent.testify()
|
|
||||||
self.parent.date = self.date
|
|
||||||
return self.parent
|
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
|
import os
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
def ensure (key, default):
|
def ensure (key, default):
|
||||||
globals()[key] = getattr(settings, key, default)
|
globals()[key] = getattr(settings, key, default)
|
||||||
|
|
||||||
|
|
||||||
ensure('AIRCOX_PROGRAMS_DATA', settings.MEDIA_ROOT + '/programs')
|
ensure('AIRCOX_PROGRAMS_DIR',
|
||||||
|
os.path.join(settings.MEDIA_ROOT, 'programs'))
|
||||||
|
ensure('AIRCOX_SOUNDFILE_DEFAULT_DIR',
|
||||||
|
os.path.join(AIRCOX_PROGRAMS_DIR + 'default'))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,76 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from django.core.serializers.json import DjangoJSONEncoder
|
||||||
|
from django.utils import timezone, dateformat
|
||||||
|
|
||||||
|
import programs.models as models
|
||||||
|
import programs.settings
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class EventList:
|
||||||
|
type = None
|
||||||
|
next = None
|
||||||
|
prev = None
|
||||||
|
at = None
|
||||||
|
count = None
|
||||||
|
|
||||||
|
|
||||||
|
def __init__ (self, **kwargs):
|
||||||
|
self.__dict__ = kwargs
|
||||||
|
if kwargs:
|
||||||
|
self.get_queryset()
|
||||||
|
|
||||||
|
|
||||||
|
def get_queryset (self):
|
||||||
|
events = models.Event.objects;
|
||||||
|
|
||||||
|
if self.next: events = events.filter( date_end__ge = timezone.now() )
|
||||||
|
elif self.prev: events = events.filter( date_end__le = timezone.now() )
|
||||||
|
else: events = events.all()
|
||||||
|
|
||||||
|
events = events.extra(order_by = ['date'])
|
||||||
|
if self.at: events = events[self.at:]
|
||||||
|
if self.count: events = events[:self.count]
|
||||||
|
|
||||||
|
self.events = events
|
||||||
|
|
||||||
|
|
||||||
|
def raw_string():
|
||||||
|
"""
|
||||||
|
Return a string with events rendered as raw
|
||||||
|
"""
|
||||||
|
res = []
|
||||||
|
for event in events:
|
||||||
|
r = [ dateformat.format(event.date, "Y/m/d H:i:s")
|
||||||
|
, str(event.type)
|
||||||
|
, event.parent.file.path
|
||||||
|
, event.parent.file.url
|
||||||
|
]
|
||||||
|
|
||||||
|
res.push(' '.join(r))
|
||||||
|
|
||||||
|
return '\n'.join(res)
|
||||||
|
|
||||||
|
|
||||||
|
def json_string():
|
||||||
|
import json
|
||||||
|
|
||||||
|
res = []
|
||||||
|
for event in events:
|
||||||
|
r = {
|
||||||
|
'date': dateformat.format(event.date, "Y/m/d H:i:s")
|
||||||
|
, 'date_end': dateformat.format(event.date_end, "Y/m/d H:i:s")
|
||||||
|
, 'type': str(event.type)
|
||||||
|
, 'file_path': event.parent.file.path
|
||||||
|
, 'file_url': event.parent.file.url
|
||||||
|
}
|
||||||
|
|
||||||
|
res.push(json.dumps(r))
|
||||||
|
|
||||||
|
return '\n'.join(res)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user