diff --git a/panikdb/aa/models.py b/panikdb/aa/models.py
index 712604d3880e049d13ac1c57a0fb5e5a5d21696f..bd1537cbc59e2c3e57ccec18d869b7e9ec64715f 100644
--- a/panikdb/aa/models.py
+++ b/panikdb/aa/models.py
@@ -4,7 +4,7 @@ from django.contrib.auth.models import AbstractUser
from django.core import validators
from django.db import models
-from ..emissions.models import Emission
+from emissions.models import Emission
class User(AbstractUser):
emissions = models.ManyToManyField(Emission)
diff --git a/panikdb/emissions/__init__.py b/panikdb/emissions/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/panikdb/emissions/admin.py b/panikdb/emissions/admin.py
deleted file mode 100644
index 228c2b3bd9cc07ae7d98d7c0c0b5f1a7333f5b25..0000000000000000000000000000000000000000
--- a/panikdb/emissions/admin.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from django.contrib import admin
-
-from .models import Emission, Episode, Category, Schedule, \
- SoundFile, NewsItem, NewsCategory, Nonstop
-
-class EmissionAdmin(admin.ModelAdmin):
- prepopulated_fields = {'slug': ('title',)}
-
-admin.site.register(Emission, EmissionAdmin)
-
-
-class EpisodeAdmin(admin.ModelAdmin):
- prepopulated_fields = {'slug': ('title',)}
-
-admin.site.register(Episode, EpisodeAdmin)
-
-
-class CategoryAdmin(admin.ModelAdmin):
- pass
-
-admin.site.register(Category, CategoryAdmin)
-
-
-class ScheduleAdmin(admin.ModelAdmin):
- pass
-
-admin.site.register(Schedule, ScheduleAdmin)
-
-
-class NewsCategoryAdmin(admin.ModelAdmin):
- pass
-
-admin.site.register(NewsCategory, NewsCategoryAdmin)
-
-
-class NewsItemAdmin(admin.ModelAdmin):
- pass
-
-admin.site.register(NewsItem, NewsItemAdmin)
-
-
-class SoundFileAdmin(admin.ModelAdmin):
- pass
-
-admin.site.register(SoundFile, SoundFileAdmin)
-
-
-class NonstopAdmin(admin.ModelAdmin):
- pass
-
-admin.site.register(Nonstop, NonstopAdmin)
diff --git a/panikdb/emissions/fixtures/nonstop.json b/panikdb/emissions/fixtures/nonstop.json
deleted file mode 100644
index 8c0352fa127451c23352f60be0e4c1cc9fa0688e..0000000000000000000000000000000000000000
--- a/panikdb/emissions/fixtures/nonstop.json
+++ /dev/null
@@ -1,83 +0,0 @@
-[
- {
- "fields": {
- "end": "02:00:00",
- "start": "22:00:00",
- "title": "Biodiversit\u00e9"
- },
- "model": "emissions.nonstop",
- "pk": 1
- },
- {
- "fields": {
- "end": "05:00:00",
- "start": "02:00:00",
- "title": "R\u00eaveries"
- },
- "model": "emissions.nonstop",
- "pk": 2
- },
- {
- "fields": {
- "end": "07:30:00",
- "start": "05:00:00",
- "title": "La Panique"
- },
- "model": "emissions.nonstop",
- "pk": 3
- },
- {
- "fields": {
- "end": "10:00:00",
- "start": "07:30:00",
- "title": "Matin tranquille"
- },
- "model": "emissions.nonstop",
- "pk": 4
- },
- {
- "fields": {
- "end": "12:00:00",
- "start": "10:00:00",
- "title": "Up Beat Tempo"
- },
- "model": "emissions.nonstop",
- "pk": 5
- },
- {
- "fields": {
- "end": "13:00:00",
- "start": "12:00:00",
- "title": "L'heure de pointe"
- },
- "model": "emissions.nonstop",
- "pk": 6
- },
- {
- "fields": {
- "end": "16:00:00",
- "start": "13:00:00",
- "title": "Le Mange Disque"
- },
- "model": "emissions.nonstop",
- "pk": 7
- },
- {
- "fields": {
- "end": "19:00:00",
- "start": "16:00:00",
- "title": "Hop Bop and co"
- },
- "model": "emissions.nonstop",
- "pk": 8
- },
- {
- "fields": {
- "end": "22:00:00",
- "start": "19:00:00",
- "title": "Acouph\u00e8ne"
- },
- "model": "emissions.nonstop",
- "pk": 9
- }
-]
diff --git a/panikdb/emissions/forms.py b/panikdb/emissions/forms.py
deleted file mode 100644
index 8c6477971b79722621290ec0ba811f38413a9efa..0000000000000000000000000000000000000000
--- a/panikdb/emissions/forms.py
+++ /dev/null
@@ -1,196 +0,0 @@
-import datetime
-import re
-import unicodedata
-import os
-import uuid
-
-from django import forms
-from django.forms import fields
-
-from django.core.files.storage import DefaultStorage
-from django.core.urlresolvers import reverse
-from django.utils.safestring import mark_safe
-from django.conf import settings
-from django.template.loader import render_to_string
-
-from taggit.forms import TagWidget
-import datetimewidget.widgets
-
-from .models import Emission, Episode, Diffusion, Schedule, SoundFile
-
-
-DATETIME_OPTIONS = {
- 'format': 'dd/mm/yyyy hh:ii',
- 'language': 'fr',
- 'weekStart': '1',
- 'autoclose': 'true',
- }
-
-class DateTimeWidget(datetimewidget.widgets.DateTimeWidget):
- def __init__(self, *args, **kwargs):
- super(DateTimeWidget, self).__init__(*args, options=DATETIME_OPTIONS, **kwargs)
-
-
-def slugify(s):
- s = unicodedata.normalize('NFKD', s).encode('ascii', 'ignore').lower()
- return re.sub(r'\W+', '-', s)
-
-
-class DayAndHourWidget(forms.MultiWidget):
- def __init__(self, attrs=None):
- WEEKDAYS = [u'Lundi', u'Mardi', u'Mercredi', u'Jeudi', u'Vendredi', u'Samedi', u'Dimanche']
- widgets = (
- forms.Select(attrs=attrs, choices=([(weekday, WEEKDAYS[weekday]) for weekday in range(7)])),
- forms.Select(attrs=attrs, choices=([(hour, hour) for hour in range(24)])),
- forms.Select(attrs=attrs, choices=([(minute, str(minute).zfill(2)) for minute in range(60)])),
- )
- super(DayAndHourWidget, self).__init__(widgets, attrs)
-
- def decompress(self, value):
- if value:
- return [value.weekday(), value.hour, value.minute]
- return [None, None, None]
-
- def value_from_datadict(self, data, files, name):
- # we only care about day/hour/minutes, but we conveniently use a
- # datetime value to store that; we pick 2007 as reference year as
- # it had its January 1st on a Monday.
- data_list = [
- widget.value_from_datadict(data, files, name + '_%s' % i)
- for i, widget in enumerate(self.widgets)]
-
- if data_list:
- return datetime.datetime(2007, 1, int(data_list[0])+1, int(data_list[1]), int(data_list[2]))
- return None
-
-
-class JqueryFileUploadFileInput(forms.FileInput):
- def render(self, name, value, attrs=None):
- output = render_to_string('emissions/upload.html', {
- 'upload_url': self.url,
- 'files': self.files,
- 'name': name,
- 'STATIC_URL': settings.STATIC_URL})
- return mark_safe(output)
-
-
-class JqueryFileUploadInput(forms.MultiWidget):
- needs_multipart_form = True
- upload_id_re = re.compile(r'^[a-z0-9A-Z-]+$')
- upload_id = None
-
- def __init__(self, attrs=None, choices=[], max_filename_length=None):
- self.max_filename_length = max_filename_length
- widget_list = (forms.HiddenInput(attrs=attrs),
- JqueryFileUploadFileInput(attrs=attrs))
- super(JqueryFileUploadInput, self).__init__(widget_list, attrs)
-
- def decompress(self, value):
- # map python value to widget contents
- if self.upload_id:
- pass
- elif isinstance(value, (list, tuple)) and value and value[0] is not None:
- self.upload_id = str(value[0])
- else:
- self.upload_id = str(uuid.uuid4())
- return [self.upload_id, None]
-
- def get_files_for_id(self, upload_id):
- storage = DefaultStorage()
- path = os.path.join('upload', upload_id)
- if not storage.exists(path):
- return
- for filepath in storage.listdir(path)[1]:
- name = os.path.basename(filepath)
- yield storage.open(os.path.join(path, name))
-
- def value_from_datadict(self, data, files, name):
- '''
- If some file was submitted, that's the value,
- If a regular hidden_id is present, use it to find uploaded files,
- otherwise return an empty list
- '''
- upload_id, file_input = super(JqueryFileUploadInput, self).value_from_datadict(data, files, name)
- if file_input:
- pass
- elif JqueryFileUploadInput.upload_id_re.match(upload_id):
- file_input = list(self.get_files_for_id(upload_id))
- else:
- file_input = []
- return file_input[0]
-
- def render(self, name, value, attrs=None):
- self.decompress(value)
- self.widgets[1].url = '/upload/%s/' % self.upload_id
- self.widgets[1].url = reverse('upload', kwargs={'transaction_id': self.upload_id})
- if self.max_filename_length:
- self.widgets[1].url += '?max_filename_length=%d' % self.max_filename_length
- self.widgets[1].files = '/upload/%s/' % self.get_files_for_id(self.upload_id)
- output = super(JqueryFileUploadInput, self).render(name, value,
- attrs)
- fileinput_id = '%s_%s' % (attrs['id'], '1')
- return output
-
-
-class EmissionForm(forms.ModelForm):
- class Meta:
- model = Emission
- exclude = ('slug',)
-
- def save(self, commit=True):
- if not self.instance.slug:
- self.instance.slug = slugify(self.instance.title)
- return super(EmissionForm, self).save(commit=commit)
-
-
-class EpisodeForm(forms.ModelForm):
- class Meta:
- model = Episode
- exclude = ('slug',)
- widgets = {'emission': forms.HiddenInput(),
- 'tags': TagWidget()}
-
- def save(self, commit=True):
- if not self.instance.slug:
- self.instance.slug = slugify(self.instance.title)
- return super(EpisodeForm, self).save(commit=commit)
-
-
-class EpisodeNewForm(EpisodeForm):
- diffusion = forms.DateTimeField(label='First Diffusion',
- widget=DateTimeWidget)
-
- def save(self, commit=True):
- episode = super(EpisodeNewForm, self).save(commit=commit)
- diffusion = Diffusion()
- diffusion.episode_id = episode.id
- diffusion.datetime = self.cleaned_data.get('diffusion')
- diffusion.save()
- return episode
-
-
-class ScheduleForm(forms.ModelForm):
- class Meta:
- model = Schedule
- widgets = {
- 'emission': forms.HiddenInput(),
- 'datetime': DayAndHourWidget(),
- }
-
-
-class SoundFileForm(forms.ModelForm):
- class Meta:
- model = SoundFile
- widgets = {
- 'episode': forms.HiddenInput(),
- 'file': JqueryFileUploadInput(),
- }
-
-
-class DiffusionForm(forms.ModelForm):
- class Meta:
- model = Diffusion
- widgets = {
- 'episode': forms.HiddenInput(),
- 'datetime': DateTimeWidget(),
- }
diff --git a/panikdb/emissions/management/__init__.py b/panikdb/emissions/management/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/panikdb/emissions/management/commands/__init__.py b/panikdb/emissions/management/commands/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/panikdb/emissions/management/commands/_spip2html.py b/panikdb/emissions/management/commands/_spip2html.py
deleted file mode 100644
index 70fdb070ba2d4f6aff42ec86e993d8fb5a1490ce..0000000000000000000000000000000000000000
--- a/panikdb/emissions/management/commands/_spip2html.py
+++ /dev/null
@@ -1,1073 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Code scavenged from Glasnost
-# By: Odile Bénassy
-# Romain Chantereau
-# Nicolas Clapiès
-# Pierre-Antoine Dejace
-# Thierry Dulieu
-# Florent Monnier
-# Cédric Musso
-# Frédéric Péters
-# Benjamin Poussin
-# Emmanuel Raviart
-# Sébastien Régnier
-# Emmanuel Saracco
-#
-# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
-# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
-# Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
-# Emmanuel Saracco & Théridion
-# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
-# Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
-# Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
-# Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
-# Régnier, Emmanuel Saracco, Théridion & Vecam
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-import re
-import sys
-
-_non_id_chars = re.compile('[^a-z0-9]+')
-_non_id_at_ends = re.compile('^[-0-9]+|-+$')
-
-def enhanceTypo(s):
- # typographic junkie
- # idea from: http://daringfireball.net/projects/smartypants/
- s = s.replace('...', '…') # ellipsis (...)
- s = s.replace(' -- ', ' — ') # em-dash
- s = s.replace('(c)', '© ') # copyright symbol
- return s
-
-
-def parseSpipLink(link):
- link = link.replace('\n', ' ')
- matchObject = re.match(
- r'(?Palias|art(icle)?|atom|book|card|election|file|'\
- 'grade|group|heading|im(g|age)?|person(ne)?|rubri(c|que)'\
- ') *(?P\S+) *(?P
-
-
-{% if episode.description %}
-
-{{ episode.description|safe }}
-
-{% endif %}
-
-{% if episode.text %}
-{{ episode.text|safe }}
-{% endif %}
-
-Diffusions
-
-
-{% for diffusion in diffusions %}
-- {{ diffusion.datetime }}
-
-
-{% endfor %}
-
-
-
-
-
-
-Sons
-
-
-
-
- Fichier |
- Titre |
- Podcastable? |
- Fragment? |
-
-
-{% for soundfile in soundfiles %}
-
-{{ soundfile.file.name }} |
-{{ soundfile.title }} |
-{{ soundfile.podcastable }} |
-{{ soundfile.fragment }} |
-{% endfor %}
-
-
-
-
-
-{% endblock %}
-
-
-{% block page-end %}
-
-{% endblock %}
diff --git a/panikdb/emissions/templates/emissions/episode_form.html b/panikdb/emissions/templates/emissions/episode_form.html
deleted file mode 100644
index 0310f937ed1e0312d8ee758148e784ed66660d5f..0000000000000000000000000000000000000000
--- a/panikdb/emissions/templates/emissions/episode_form.html
+++ /dev/null
@@ -1,35 +0,0 @@
-{% extends "base.html" %}
-
-{% block extrascripts %}
-
-{% endblock %}
-
-{% block appbar %}
-{% if episode.id %}
-{{ episode.emission.title }} — {{ episode.title }}
-Retourner à l'épisode
-{% else %}
-{{ emission.title }} — Nouvel épisode
-Retourner à l'émission
-{% endif %}
-{% endblock %}
-
-
-{% block content %}
-
-
-{% endblock %}
diff --git a/panikdb/emissions/templates/emissions/soundfile_form.html b/panikdb/emissions/templates/emissions/soundfile_form.html
deleted file mode 100644
index abb879cc309b6a7279b152813f618096e2832055..0000000000000000000000000000000000000000
--- a/panikdb/emissions/templates/emissions/soundfile_form.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{% extends "base.html" %}
-
-{% block extrascripts %}
-
-{% endblock %}
-
-{% block content %}
-
-{% endblock %}
-
diff --git a/panikdb/emissions/templates/emissions/upload.html b/panikdb/emissions/templates/emissions/upload.html
deleted file mode 100644
index 5aaa7a527fb6b6d44e9ffca571009040f955f71d..0000000000000000000000000000000000000000
--- a/panikdb/emissions/templates/emissions/upload.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% load i18n %}
-
diff --git a/panikdb/emissions/templates/search/indexes/emissions/emission_text.txt b/panikdb/emissions/templates/search/indexes/emissions/emission_text.txt
deleted file mode 100644
index 5916825b3a537b996b2989a96982596cf51b0efb..0000000000000000000000000000000000000000
--- a/panikdb/emissions/templates/search/indexes/emissions/emission_text.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-{{ object.title }}
-
-{{ object.description|striptags }}
-
-{{ object.text|striptags }}
diff --git a/panikdb/emissions/templates/search/indexes/emissions/episode_text.txt b/panikdb/emissions/templates/search/indexes/emissions/episode_text.txt
deleted file mode 100644
index 47238eb79df7ff34d1cc9817b3336303a9c9ddf5..0000000000000000000000000000000000000000
--- a/panikdb/emissions/templates/search/indexes/emissions/episode_text.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-{{ object.title }}
-
-{{ object.description|striptags }}
-
-{{ object.text|striptags }}
-
-{% for tag in object.tags.all %} {{ tag.name }} {% endfor %}
diff --git a/panikdb/emissions/templates/search/indexes/emissions/newsitem_text.txt b/panikdb/emissions/templates/search/indexes/emissions/newsitem_text.txt
deleted file mode 100644
index 6f1d5ee11c5f25d8873ceda973059d3665fd82e0..0000000000000000000000000000000000000000
--- a/panikdb/emissions/templates/search/indexes/emissions/newsitem_text.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-{{ object.title }}
-
-{{ object.text|striptags }}
-
-{% if object.emission %}
-{{ object.emission.title }}
-{% endif %}
-
-{% for tag in object.tags.all %} {{ tag.name }} {% endfor %}
diff --git a/panikdb/emissions/templatetags/__init__.py b/panikdb/emissions/templatetags/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/panikdb/emissions/templatetags/soundfiles.py b/panikdb/emissions/templatetags/soundfiles.py
deleted file mode 100644
index a3234c57f8e32836e73f65f764f5600d9e439d5c..0000000000000000000000000000000000000000
--- a/panikdb/emissions/templatetags/soundfiles.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import os
-
-from django.template import Library
-
-register = Library()
-
-
-@register.filter(name='is_format_available')
-def is_available(soundfile, format='ogg'):
- if soundfile is None:
- return False
- sound_path = soundfile.get_format_path(format)
- if not sound_path:
- return False
- return os.path.exists(sound_path)
-
-@register.filter(name='format_url')
-def format_url(soundfile, format='ogg'):
- return soundfile.get_format_url(format)
diff --git a/panikdb/emissions/tests.py b/panikdb/emissions/tests.py
deleted file mode 100644
index 501deb776c16733b19f3509d86e125df78958261..0000000000000000000000000000000000000000
--- a/panikdb/emissions/tests.py
+++ /dev/null
@@ -1,16 +0,0 @@
-"""
-This file demonstrates writing tests using the unittest module. These will pass
-when you run "manage.py test".
-
-Replace this with more appropriate tests for your application.
-"""
-
-from django.test import TestCase
-
-
-class SimpleTest(TestCase):
- def test_basic_addition(self):
- """
- Tests that 1 + 1 always equals 2.
- """
- self.assertEqual(1 + 1, 2)
diff --git a/panikdb/emissions/urls.py b/panikdb/emissions/urls.py
deleted file mode 100644
index c84660f294232a5d2dd66b1d859a7d4489101772..0000000000000000000000000000000000000000
--- a/panikdb/emissions/urls.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from django.conf.urls import patterns, url
-
-from .views import *
-
-urlpatterns = patterns('',
- url(r'^$', EmissionListView.as_view(), name='emission-list'),
- url(r'^categories$', CategoryListView.as_view(), name='category-list'),
- url(r'^days$', DaysView.as_view(), name='days'),
- url(r'^add$', EmissionCreateView.as_view(), name='emission-add'),
-
- url(r'^upload/(?P[a-zA-Z0-9-]+)/$', UploadView.as_view(), name='upload'),
-
- url(r'^(?P[\w,-]+)/$', EmissionDetailView.as_view(), name='emission-view'),
- url(r'^(?P[\w,-]+)/edit/$', EmissionUpdateView.as_view(), name='emission-update'),
- url(r'^(?P[\w,-]+)/delete/$', EmissionDeleteView.as_view(), name='emission-delete'),
- url(r'^(?P[\w,-]+)/add-schedule$', EmissionAddScheduleView.as_view(), name='emission-add-schedule'),
-
- url(r'^(?P[\w,-]+)/schedule/(?P\d+)/remove$',
- ScheduleDeleteView.as_view(), name='schedule-delete'),
-
- url(r'^(?P[\w,-]+)/add$', EpisodeCreateView.as_view(), name='episode-add'),
- url(r'^(?P[\w,-]+)/(?P[\w,-]+)/$', EpisodeDetailView.as_view(), name='episode-view'),
- url(r'^(?P[\w,-]+)/(?P[\w,-]+)/edit/$', EpisodeUpdateView.as_view(), name='episode-update'),
- url(r'^(?P[\w,-]+)/(?P[\w,-]+)/delete/$', EpisodeDeleteView.as_view(), name='episode-delete'),
- url(r'^(?P[\w,-]+)/(?P[\w,-]+)/add-soundfile$',
- EpisodeAddSoundFileView.as_view(), name='episode-add-soundfile'),
- url(r'^(?P[\w,-]+)/(?P[\w,-]+)/add-diffusion$',
- EpisodeAddDiffusionView.as_view(), name='episode-add-diffusion'),
- url(r'^(?P[\w,-]+)/(?P[\w,-]+)/diffusion/(?P\d+)/remove$',
- DiffusionDeleteView.as_view(), name='diffusion-delete'),
-
-)
diff --git a/panikdb/emissions/utils.py b/panikdb/emissions/utils.py
deleted file mode 100644
index ac06e613c553979228e2568504fab28675500302..0000000000000000000000000000000000000000
--- a/panikdb/emissions/utils.py
+++ /dev/null
@@ -1,212 +0,0 @@
-from datetime import datetime, timedelta, time
-import os
-from PIL import Image
-
-def maybe_resize(image_path):
- if not os.path.exists(image_path):
- return
- image = Image.open(image_path)
- if max(image.size) > 1000:
- # no sense storing images that large
- factor = 1000. / max(image.size)
- image = image.resize(
- (int(image.size[0]*factor), int(image.size[1]*factor)),
- Image.ANTIALIAS)
- image.save(image_path)
-
-
-def whatsonair():
- from models import Diffusion, Schedule, Nonstop
-
- now = datetime.now()
- program = day_program(now)
- program = [x for x in program if not x.datetime > now]
-
- emission = None
- episode = None
- nonstop = None
- current_slot = None
- if program and program[-1].datetime + timedelta(minutes=program[-1].get_duration()) > now:
- current_slot = program[-1]
- if isinstance(current_slot, Schedule):
- emission = current_slot.emission
- elif isinstance(current_slot, Diffusion):
- episode = current_slot.episode
- emission = episode.emission
- else:
- for nonstop in Nonstop.objects.all():
- if (nonstop.start < nonstop.end and (
- now.time() >= nonstop.start and now.time() < nonstop.end)) or \
- (nonstop.start > nonstop.end and (
- now.time() >= nonstop.start or now.time() < nonstop.end)):
- current_slot = nonstop
- break
- else:
- nonstop = None
-
- return {'emission': emission,
- 'episode': episode,
- 'nonstop': nonstop,
- 'current_slot': current_slot}
-
-
-def period_program(date_start, date_end):
- from models import Diffusion, Schedule, Nonstop, WeekdayMixin
-
- diffusions = Diffusion.objects.select_related().filter(
- datetime__range=(date_start, date_end)).order_by('datetime')
- diffusions = [x for x in diffusions if x.datetime >= date_start and
- x.datetime < date_end]
-
- # the secondary sortkey puts schedules that happens everyweek after
- # specific ones, this will be useful later on, when multiple schedules
- # happen at the same time and we have to remove the least specific.
- period_schedules = Schedule.objects.select_related().order_by('datetime', 'weeks')
-
- program = []
- current_date = date_start
- while current_date < date_end:
- week_day = current_date.weekday()
- week_no = ((current_date.day-1) // 7)
- day_schedules = [x for x in period_schedules if x.get_weekday() == week_day and x.match_week(week_no)]
- for schedule in day_schedules:
- schedule.datetime = datetime(
- current_date.year, current_date.month, current_date.day,
- schedule.datetime.hour, schedule.datetime.minute) + \
- timedelta(days=schedule.datetime.weekday()-current_date.weekday())
- program.extend(day_schedules)
- current_date += timedelta(days=1)
-
- for i, schedule in enumerate(program):
- if schedule is None:
- continue
-
- # look for a diffusion matching this schedule
- d = [x for x in diffusions if x.datetime.timetuple()[:5] == schedule.datetime.timetuple()[:5]]
- if d:
- diffusions.remove(d[0])
- program[i] = d[0]
- for j, other_schedule in enumerate(program[i+1:]):
- # remove other emissions scheduled at the same time
- if other_schedule.datetime.timetuple()[:5] == schedule.datetime.timetuple()[:5]:
- program[i+1+j] = None
- else:
- break
-
- # here we are with remaining diffusions, those that were not overriding a
- # planned schedle
- for diffusion in diffusions:
- program = [x for x in program if x is not None]
- try:
- just_before_program = [x for x in program if x.datetime < diffusion.datetime][-1]
- new_diff_index = program.index(just_before_program)+1
- except IndexError:
- # nothing before
- new_diff_index = 0
- program.insert(new_diff_index, diffusion)
-
- # cut (or even remove) programs that started earlier but continued over
- # this program start time
- i = new_diff_index
- while i > 0:
- previous = program[i-1]
- previous_endtime = previous.datetime + timedelta(minutes=previous.get_duration())
- if previous_endtime > diffusion.datetime:
- previous.duration = (diffusion.datetime - previous.datetime).seconds / 60
- if previous.duration <= 0:
- program[i-1] = None
- i -= 1
-
- # push back (or remove) programs that started before this program ends
- # (this may be unnecessary as next step does that again for all
- # programs)
- diffusion_endtime = diffusion.datetime + timedelta(minutes=diffusion.get_duration())
- i = new_diff_index
- while i < len(program)-1:
- next_prog = program[i+1]
- if next_prog.datetime < diffusion_endtime:
- diff = diffusion_endtime - next_prog.datetime
- if (diff.seconds/60) > next_prog.get_duration():
- program[i+1] = None
- else:
- next_prog.datetime = diffusion_endtime
- next_prog.duration = next_prog.get_duration() - (diff.seconds/60)
- i += 1
-
- # remove overlapping programs
- program = [x for x in program if x is not None]
- for i, slot in enumerate(program):
- if slot is None:
- continue
-
- slot_end = slot.datetime + timedelta(minutes=slot.get_duration())
-
- j = i+1
- while j < len(program)-1:
- if program[j]:
- if slot_end > program[j].datetime:
- program[j] = None
- j += 1
-
- program = [x for x in program if x is not None]
-
- # last step is adding nonstop zones between slots
- nonstops = Nonstop.objects.all()
-
- class NonstopSlot(WeekdayMixin):
- def __init__(self, start, end):
- self.datetime = None
- labels = []
- for nonstop in nonstops:
- nonstop_day_start = start.replace(hour=nonstop.start.hour, minute=nonstop.start.minute)
- nonstop_day_end = start.replace(hour=nonstop.end.hour, minute=nonstop.end.minute)
- if nonstop.end < nonstop.start:
- if start.time() < nonstop.end:
- nonstop_day_start -= timedelta(days=1)
- else:
- nonstop_day_end += timedelta(days=1)
-
- if nonstop_day_start < end and nonstop_day_end > start:
- if self.datetime is None:
- self.datetime = nonstop_day_end
- labels.append(nonstop.title)
- self.label = u', '.join(labels)
-
- def __repr__(self):
- return repr(self.label)
-
- def get_duration(self):
- # fake duration
- return 0
-
-
- first_day_start = datetime(*date_start.replace(hour=6, minute=0).timetuple()[:5])
- last_day_end = datetime(*date_end.replace(hour=5, minute=0).timetuple()[:5])
-
- program.insert(0, NonstopSlot(first_day_start, program[0].datetime))
-
- i = 0
- while i < len(program)-1:
- slot = program[i]
- if not isinstance(slot, NonstopSlot):
- slot_end = slot.datetime + timedelta(minutes=slot.get_duration())
- next_slot = program[i+1]
-
- if slot_end < next_slot.datetime:
- next_day_start = next_slot.datetime.replace(hour=5, minute=0)
- if slot_end < next_day_start and next_slot.datetime > next_day_start:
- program[i+1:i+1] = [NonstopSlot(slot_end, next_day_start),
- NonstopSlot(next_day_start, next_slot.datetime)]
- else:
- program[i+1:i+1] = [NonstopSlot(slot_end, next_slot.datetime)]
-
- i += 1
-
- program.append(NonstopSlot(program[-1].datetime, last_day_end))
-
- return program
-
-def day_program(date):
- date_start = datetime(*date.timetuple()[:3])
- date_end = date_start + timedelta(days=1)
- return period_program(date_start, date_end)
diff --git a/panikdb/emissions/views.py b/panikdb/emissions/views.py
deleted file mode 100644
index ebb596fcd29cad3bc9b99632307832fc47ee5f56..0000000000000000000000000000000000000000
--- a/panikdb/emissions/views.py
+++ /dev/null
@@ -1,256 +0,0 @@
-import datetime
-import os
-
-from django.core.files.storage import DefaultStorage
-from django.http import HttpResponse, Http404
-from django.core.urlresolvers import reverse, reverse_lazy
-from django.utils import simplejson
-
-from django.views.decorators.csrf import csrf_exempt
-from django.views.generic.base import View, TemplateView, RedirectView
-from django.views.generic.edit import CreateView, UpdateView, DeleteView
-from django.views.generic.list import ListView
-from django.views.generic.detail import DetailView
-
-import haystack.views
-
-from .models import Emission, Episode, Diffusion, Category, Schedule, SoundFile
-from .forms import EmissionForm, EpisodeForm, EpisodeNewForm, ScheduleForm, \
- DiffusionForm, SoundFileForm
-
-
-__all__ = ['EmissionListView', 'EmissionDetailView', 'EmissionCreateView',
- 'EmissionUpdateView', 'EmissionDeleteView',
- 'EpisodeCreateView', 'EpisodeDetailView', 'EpisodeUpdateView',
- 'EpisodeDeleteView', 'EmissionAddScheduleView',
- 'ScheduleDeleteView', 'CategoryListView', 'DaysView',
- 'UploadView', 'EpisodeAddSoundFileView',
- 'EpisodeAddDiffusionView', 'DiffusionDeleteView']
-
-
-class EmissionListView(ListView):
- model = Emission
-
- def get_queryset(self):
- return Emission.objects.order_by('title')
-
-
-class CategoryListView(ListView):
- model = Category
-
- def get_queryset(self):
- return Category.objects.order_by('title')
-
-
-class EmissionDetailView(DetailView):
- model = Emission
-
- def get_context_data(self, **kwargs):
- context = super(EmissionDetailView, self).get_context_data(**kwargs)
- context['add_schedule_form'] = ScheduleForm(initial={'emission': self.object})
- context['schedules'] = Schedule.objects.filter(emission=self.object).order_by('datetime')
-
- # get all episodes, with an additional attribute to get the date of
- # their first diffusion
- context['episodes'] = \
- Episode.objects.select_related().filter(emission=self.object
- ).extra(select={
- 'first_diffusion': 'emissions_diffusion.datetime',
- },
- select_params=(False, True),
- where=['''datetime = (SELECT MIN(datetime)
- FROM emissions_diffusion
- WHERE episode_id = emissions_episode.id)'''],
- tables=['emissions_diffusion'],
- ).order_by('-first_diffusion')
-
- # get all related soundfiles in a single query
- soundfiles = {}
- for soundfile in SoundFile.objects.filter(podcastable=True,
- fragment=False, episode__emission=self.object):
- soundfiles[soundfile.episode_id] = soundfile
-
- # replace dynamic property by a static attribute, to avoid database
- # lookups
- for episode in context['episodes']:
- episode.main_sound = soundfiles.get(episode.id)
-
- return context
-
-
-class EmissionCreateView(CreateView):
- form_class = EmissionForm
- model = Emission
-
- success_url = reverse_lazy('emission-list')
-
-
-class EmissionUpdateView(UpdateView):
- form_class = EmissionForm
- model = Emission
-
-
-class EmissionDeleteView(DeleteView):
- model = Emission
-
-
-class EpisodeCreateView(CreateView):
- model = Episode
- form_class = EpisodeNewForm
-
- def get_initial(self):
- initial = super(EpisodeCreateView, self).get_initial()
- initial['emission'] = Emission.objects.get(slug=self.kwargs.get('emission_slug'))
- initial['duration'] = initial['emission'].duration
- return initial
-
- def get_context_data(self, **kwargs):
- context = super(EpisodeCreateView, self).get_context_data(**kwargs)
- context['emission'] = Emission.objects.get(slug=self.kwargs.get('emission_slug'))
- return context
-
- def get_success_url(self):
- return self.object.get_absolute_url()
-
-
-class EpisodeDetailView(DetailView):
- model = Episode
-
- def get_context_data(self, **kwargs):
- context = super(EpisodeDetailView, self).get_context_data(**kwargs)
- context['diffusions'] = Diffusion.objects.filter(episode=self.object.id)
- context['soundfiles'] = SoundFile.objects.filter(episode=self.object.id)
- context['add_soundfile_form'] = SoundFileForm(initial={'episode': self.object})
- context['add_diffusion_form'] = DiffusionForm(initial={'episode': self.object})
- context['emission'] = Emission.objects.get(slug=self.kwargs.get('emission_slug'))
- # get all episodes, with an additional attribute to get the date of
- # their first diffusion
- context['episodes'] = \
- Episode.objects.filter(emission=context['emission']
- ).extra(select={
- 'first_diffusion': 'emissions_diffusion.datetime',
- },
- select_params=(False, True),
- where=['''datetime = (SELECT MIN(datetime)
- FROM emissions_diffusion
- WHERE episode_id = emissions_episode.id)'''],
- tables=['emissions_diffusion'],
- ).order_by('-first_diffusion')
-
- # get all related soundfiles in a single query
- soundfiles = {}
- for soundfile in SoundFile.objects.filter(podcastable=True,
- fragment=False, episode__emission=self.object):
- soundfiles[soundfile.episode_id] = soundfile
-
- # replace dynamic property by a static attribute, to avoid database
- # lookups
- for episode in context['episodes']:
- episode.main_sound = soundfiles.get(episode.id)
- return context
-
-
-class EpisodeUpdateView(UpdateView):
- form_class = EpisodeForm
- model = Episode
-
-
-class EpisodeDeleteView(DeleteView):
- model = Episode
-
-
-class EmissionAddScheduleView(CreateView):
- form_class = ScheduleForm
- model = Schedule
-
- def get_success_url(self):
- return self.object.emission.get_absolute_url()
-
-
-class ScheduleDeleteView(RedirectView):
- def get_redirect_url(self, emission_slug, pk):
- Schedule.objects.filter(id=pk).delete()
- return reverse('emission-view', kwargs={'slug': str(emission_slug)})
-
-
-class DaysView(TemplateView):
- template_name = 'emissions/days.html'
-
- def get_context_data(self, **kwargs):
- context = super(DaysView, self).get_context_data(**kwargs)
- schedules = Schedule.objects.all().order_by('datetime')
- days = []
- for day in range(7):
- days.append({'schedules': [x for x in schedules if x.is_on_weekday(day+1)],
- 'datetime': datetime.datetime(2007, 1, day+1)})
- context['days'] = days
- return context
-
-class JSONResponse(HttpResponse):
- """JSON response class."""
- def __init__(self, obj='', json_opts={}, mimetype='application/json', *args, **kwargs):
- content = simplejson.dumps(obj, **json_opts)
- super(JSONResponse,self).__init__(content, mimetype, *args, **kwargs)
-
-
-class UploadView(View):
-
- def response_mimetype(self, request):
- if 'application/json' in request.META['HTTP_ACCEPT']:
- return 'application/json'
- else:
- return 'text/plain'
-
- @csrf_exempt
- def post(self, request, transaction_id):
- storage = DefaultStorage()
- max_filename_length = 256
- url = reverse('upload', kwargs={'transaction_id': transaction_id})
- if request.FILES is None:
- response = JSONResponse({}, {}, self.response_mimetype(request))
- response['Content-Disposition'] = 'inline; filename=files.json'
- return response
- data = []
- for uploaded_file in request.FILES.values():
- path = os.path.join('upload', str(transaction_id), uploaded_file.name)
- filename = storage.save(path, uploaded_file)
- url = '%s%s' % (url, os.path.basename(filename))
- data.append({'name': uploaded_file.name, 'size': uploaded_file.size, 'url': url})
- response = JSONResponse(data, {}, self.response_mimetype(request))
- response['Content-Disposition'] = 'inline; filename=files.json'
- return response
-
-
-class EpisodeAddSoundFileView(CreateView):
- form_class = SoundFileForm
- model = SoundFile
-
- def get_success_url(self):
- return self.object.episode.get_absolute_url()
-
-
-class EpisodeAddDiffusionView(CreateView):
- form_class = DiffusionForm
- model = Diffusion
-
- def get_success_url(self):
- return self.object.episode.get_absolute_url()
-
-
-class DiffusionDeleteView(RedirectView):
- def get_redirect_url(self, emission_slug, slug, pk):
- Diffusion.objects.filter(id=pk).delete()
- return reverse('episode-view', kwargs={'emission_slug': str(emission_slug),
- 'slug': str(slug)})
-
-
-class FacetedSearchView(haystack.views.FacetedSearchView):
- def extra_context(self):
- context = super(FacetedSearchView, self).extra_context()
- context['selected_categories'] = [
- x.split(':', 1)[1] for x in self.request.GET.getlist('selected_facets')
- if x.startswith('categories_exact')]
- context['selected_tags'] = [
- x.split(':', 1)[1] for x in self.request.GET.getlist('selected_facets')
- if x.startswith('tags_exact')]
- return context
diff --git a/panikdb/settings.py b/panikdb/settings.py
index 6193fe38ea962b04cf0b12fe2fd99be8725e949d..bda0ca80739afc8778d67ab7194fa12364d12933 100644
--- a/panikdb/settings.py
+++ b/panikdb/settings.py
@@ -130,7 +130,7 @@ INSTALLED_APPS = (
'jquery',
'datetimewidget',
'django_bootstrap_staticfiles',
- 'panikdb.emissions',
+ 'emissions',
'panikdb.aa',
)
diff --git a/panikdb/urls.py b/panikdb/urls.py
index 219c2104f8c49c54ffefe48def77fd0a050695eb..60bedce62c2ad6ae22dfb50ce55a33af5b295b8f 100644
--- a/panikdb/urls.py
+++ b/panikdb/urls.py
@@ -12,7 +12,7 @@ from haystack.forms import FacetedSearchForm
from haystack.query import SearchQuerySet
from emissions.views import FacetedSearchView
-from .emissions.urls import urlpatterns as emissions_urlpatterns
+from emissions.urls import urlpatterns as emissions_urlpatterns
from urls_utils import decorated_includes
diff --git a/requirements.txt b/requirements.txt
index 23f050462682d160d6b5fd5f0da070b84f5b8e15..4883cff51d81c149c685a221c074dde1c81cf89d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,3 +7,4 @@ django-registration
django-jquery
django-datetime-widget
django-bootstrap-staticfiles
+git+http://git.domainepublic.net/git/django-panik-emissions.git