fieldsets = deepcopy(VideoAdmin.fieldsets)
+class AudioAdmin(admin.ModelAdmin):
+
+ model = Audio
+
+
+class AudioAdminDisplayable(DisplayableAdmin):
+
+ fieldsets = deepcopy(AudioAdmin.fieldsets)
+
+
class ArtistAdminDisplayable(DisplayableAdmin):
fieldsets = deepcopy(ArtistAdmin.fieldsets)
admin.site.register(PageCategory)
admin.site.register(Artist, ArtistAdminDisplayable)
admin.site.register(Video, VideoAdminDisplayable)
+admin.site.register(Audio, AudioAdminDisplayable)
--- /dev/null
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.2 on 2016-03-21 23:18
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+import mezzanine.core.fields
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('mezzanine_agenda', '0003_auto_20160309_1621'),
+ ('sites', '0002_alter_domain_unique'),
+ ('festival', '0007_auto_20160309_1441'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Audio',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('keywords_string', models.CharField(blank=True, editable=False, max_length=500)),
+ ('title', models.CharField(max_length=500, verbose_name='Title')),
+ ('slug', models.CharField(blank=True, help_text='Leave blank to have the URL auto-generated from the title.', max_length=2000, null=True, verbose_name='URL')),
+ ('_meta_title', models.CharField(blank=True, help_text='Optional title to be used in the HTML title tag. If left blank, the main title field will be used.', max_length=500, null=True, verbose_name='Title')),
+ ('description', models.TextField(blank=True, verbose_name='Description')),
+ ('gen_description', models.BooleanField(default=True, help_text='If checked, the description will be automatically generated from content. Uncheck if you want to manually set a custom description.', verbose_name='Generate description')),
+ ('created', models.DateTimeField(editable=False, null=True)),
+ ('updated', models.DateTimeField(editable=False, null=True)),
+ ('status', models.IntegerField(choices=[(1, 'Draft'), (2, 'Published')], default=2, help_text='With Draft chosen, will only be shown for admin users on the site.', verbose_name='Status')),
+ ('publish_date', models.DateTimeField(blank=True, db_index=True, help_text="With Published chosen, won't be shown until this time", null=True, verbose_name='Published from')),
+ ('expiry_date', models.DateTimeField(blank=True, help_text="With Published chosen, won't be shown after this time", null=True, verbose_name='Expires on')),
+ ('short_url', models.URLField(blank=True, null=True)),
+ ('in_sitemap', models.BooleanField(default=True, verbose_name='Show in sitemap')),
+ ('content', mezzanine.core.fields.RichTextField(verbose_name='Content')),
+ ('media_id', models.CharField(max_length=128, verbose_name='media id')),
+ ('open_source_url', models.URLField(blank=True, max_length=1024, verbose_name='open source URL')),
+ ('closed_source_url', models.URLField(blank=True, max_length=1024, verbose_name='closed source URL')),
+ ('event', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='audios', to='mezzanine_agenda.Event', verbose_name='event')),
+ ('site', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
+ ],
+ options={
+ 'db_table': 'festival_audios',
+ 'verbose_name': 'audio',
+ },
+ ),
+ migrations.AddField(
+ model_name='video',
+ name='closed_source_url',
+ field=models.URLField(blank=True, max_length=1024, verbose_name='closed source URL'),
+ ),
+ migrations.AddField(
+ model_name='video',
+ name='open_source_url',
+ field=models.URLField(blank=True, max_length=1024, verbose_name='open source URL'),
+ ),
+ ]
--- /dev/null
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.2 on 2016-03-21 23:21
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import mezzanine.core.fields
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('festival', '0008_auto_20160322_0018'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='audio',
+ name='content_en',
+ field=mezzanine.core.fields.RichTextField(null=True, verbose_name='Content'),
+ ),
+ migrations.AddField(
+ model_name='audio',
+ name='content_fr',
+ field=mezzanine.core.fields.RichTextField(null=True, verbose_name='Content'),
+ ),
+ migrations.AddField(
+ model_name='audio',
+ name='description_en',
+ field=models.TextField(blank=True, null=True, verbose_name='Description'),
+ ),
+ migrations.AddField(
+ model_name='audio',
+ name='description_fr',
+ field=models.TextField(blank=True, null=True, verbose_name='Description'),
+ ),
+ migrations.AddField(
+ model_name='audio',
+ name='title_en',
+ field=models.CharField(max_length=500, null=True, verbose_name='Title'),
+ ),
+ migrations.AddField(
+ model_name='audio',
+ name='title_fr',
+ field=models.CharField(max_length=500, null=True, verbose_name='Title'),
+ ),
+ ]
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse, reverse_lazy
+from django.conf import settings
from mezzanine.core.models import RichText, Displayable
from mezzanine.core.fields import RichTextField, OrderField, FileField
from mezzanine_agenda.models import Event
+import requests
+from pyquery import PyQuery as pq
+
# import eve.models
from .related import SpanningForeignKey
app_label = 'festival'
-
ALIGNMENT_CHOICES = (('left', _('left')), ('right', _('right')))
+MEDIA_BASE_URL = getattr(settings, 'MEDIA_BASE_URL', 'http://medias.ircam.fr/embed/media/')
+
class MetaCore:
return self.title
+class PageCategory(BaseNameModel):
+ """Page Category"""
+
+ class Meta(MetaCore):
+ verbose_name = _('page category')
+
+
class Artist(Displayable, RichText, AdminThumbMixin):
"""Artist"""
return reverse("festival-artist-detail", kwargs={'slug': self.slug})
-class Video(Displayable, RichText):
- """Video"""
+class Media(Displayable, RichText):
+ """Media"""
- event = models.ForeignKey(Event, related_name='videos', verbose_name=_('event'), blank=True, null=True, on_delete=models.SET_NULL)
media_id = models.CharField(_('media id'), max_length=128)
+ open_source_url = models.URLField(_('open source URL'), max_length=1024, blank=True)
+ closed_source_url = models.URLField(_('closed source URL'), max_length=1024, blank=True)
class Meta(MetaCore):
- verbose_name = _('video')
- db_table = app_label + '_videos'
+ abstract = True
def __unicode__(self):
return self.title
@property
- def html(self):
- #TODO: get html content from medias.ircam.fr with request module
- pass
+ def uri(self):
+ return MEDIA_BASE_URL + self.media_id
+
+ def get_html(self):
+ r = requests.get(self.uri)
+ return r.content
+
+ def clean(self):
+ super(Media, self).clean()
+ self.q = pq(self.get_html())
+ self.title = self.q.attr('data-title')
+ sources = self.q('source')
+ for source in sources:
+ if self.open_source_mime_type in source.attrib['type']:
+ self.open_source_url = source.attrib['src']
+ elif self.closed_source_mime_type in source.attrib['type']:
+ self.closed_source_url = source.attrib['src']
+
+
+class Audio(Media):
+ """Audio"""
+
+ open_source_mime_type = 'audio/ogg'
+ closed_source_mime_type = 'audio/mp4'
+
+ event = models.ForeignKey(Event, related_name='audios', verbose_name=_('event'), blank=True, null=True, on_delete=models.SET_NULL)
+
+ class Meta(MetaCore):
+ verbose_name = _('audio')
+ db_table = app_label + '_audios'
def get_absolute_url(self):
return reverse("festival-video-detail", kwargs={"slug": self.slug})
-class PageCategory(BaseNameModel):
- """Page Category"""
+class Video(Media):
+ """Video"""
+
+ open_source_mime_type = 'video/webm'
+ closed_source_mime_type = 'video/mp4'
+
+ event = models.ForeignKey(Event, related_name='videos', verbose_name=_('event'), blank=True, null=True, on_delete=models.SET_NULL)
class Meta(MetaCore):
- verbose_name = _('page category')
+ verbose_name = _('video')
+ db_table = app_label + '_videos'
+
+ @property
+ def html(self):
+ #TODO: get html content from medias.ircam.fr with request module
+ pass
+
+ def get_absolute_url(self):
+ return reverse("festival-video-detail", kwargs={"slug": self.slug})
--- /dev/null
+<html>
+ <head>
+ <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
+ </head>
+<body>
+
+
+<audio id="audio" preload="auto" tabindex="0" controls="" >
+ <source id="primarysrc" src="http://www.archive.org/download/bolero_69/Bolero.mp3">
+ <source id="secondarysrc" src="http://www.archive.org/download/bolero_69/Bolero.ogg">
+ Your Fallback goes here
+</audio>
+
+
+<ul id="playlist">
+ <li class="active">
+ <a href="http://www.archive.org/download/bolero_69/Bolero.mp3" data-altsrc="http://www.archive.org/download/bolero_69/Bolero.ogg">
+ Ravel Bolero
+ </a>
+ </li>
+ <li>
+ <a href="http://www.archive.org/download/MoonlightSonata_755/Beethoven-MoonlightSonata.mp3" data-altsrc="http://www.archive.org/download/MoonlightSonata_755/Beethoven-MoonlightSonata.ogg">
+ Moonlight Sonata - Beethoven
+ </a>
+ </li>
+ <li>
+ <a href="http://www.archive.org/download/CanonInD_261/CanoninD.mp3" data-altsrc="http://www.archive.org/download/CanonInD_261/CanoninD.ogg">
+ Canon in D Pachabel
+ </a>
+ </li>
+ </ul>
+<script>
+var audio;
+var playlist;
+var tracks;
+var current;
+
+init();
+function init(){
+ current = 0;
+ audio = $('#audio');
+ playlist = $('#playlist');
+ tracks = playlist.find('li a');
+ len = tracks.length - 1;
+ audio[0].volume = .60;
+// audio[0].play();
+ playlist.find('a').click(function(e){
+ e.preventDefault();
+ link = $(this);
+ current = link.parent().index();
+ run(link, audio[0]);
+ });
+ audio[0].addEventListener('ended',function(e){
+ current++;
+ if(current == len){
+ current = 0;
+ link = playlist.find('a')[0];
+ }else{
+ link = playlist.find('a')[current];
+ }
+ run($(link),audio[0]);
+ });
+}
+function run(link, player){
+ $(player).find('#primarysrc').attr('src', link.attr('href'));
+ $(player).find('#secondarysrc').attr('src', link.attr('data-altsrc'));
+ par = link.parent();
+ par.addClass('active').siblings().removeClass('active');
+ player.load();
+ player.play();
+}
+</script>
+</body>
+</html>
+++ /dev/null
-<html>
- <head>
- <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
- </head>
-<body>
-
-
-<audio id="audio" preload="auto" tabindex="0" controls="" >
- <source id="primarysrc" src="http://www.archive.org/download/bolero_69/Bolero.mp3">
- <source id="secondarysrc" src="http://www.archive.org/download/bolero_69/Bolero.ogg">
- Your Fallback goes here
-</audio>
-
-
-<ul id="playlist">
- <li class="active">
- <a href="http://www.archive.org/download/bolero_69/Bolero.mp3" data-altsrc="http://www.archive.org/download/bolero_69/Bolero.ogg">
- Ravel Bolero
- </a>
- </li>
- <li>
- <a href="http://www.archive.org/download/MoonlightSonata_755/Beethoven-MoonlightSonata.mp3" data-altsrc="http://www.archive.org/download/MoonlightSonata_755/Beethoven-MoonlightSonata.ogg">
- Moonlight Sonata - Beethoven
- </a>
- </li>
- <li>
- <a href="http://www.archive.org/download/CanonInD_261/CanoninD.mp3" data-altsrc="http://www.archive.org/download/CanonInD_261/CanoninD.ogg">
- Canon in D Pachabel
- </a>
- </li>
- </ul>
-<script>
-var audio;
-var playlist;
-var tracks;
-var current;
-
-init();
-function init(){
- current = 0;
- audio = $('#audio');
- playlist = $('#playlist');
- tracks = playlist.find('li a');
- len = tracks.length - 1;
- audio[0].volume = .60;
-// audio[0].play();
- playlist.find('a').click(function(e){
- e.preventDefault();
- link = $(this);
- current = link.parent().index();
- run(link, audio[0]);
- });
- audio[0].addEventListener('ended',function(e){
- current++;
- if(current == len){
- current = 0;
- link = playlist.find('a')[0];
- }else{
- link = playlist.find('a')[current];
- }
- run($(link),audio[0]);
- });
-}
-function run(link, player){
- $(player).find('#primarysrc').attr('src', link.attr('href'));
- $(player).find('#secondarysrc').attr('src', link.attr('data-altsrc'));
- par = link.parent();
- par.addClass('active').siblings().removeClass('active');
- player.load();
- player.play();
-}
-</script>
-</body>
-</html>
ADMIN_MENU_ORDER = (
(_("Content"), ("pages.Page", "blog.BlogPost", "mezzanine_agenda.Event",
- "festival.Artist", "festival.Video",
+ "festival.Artist", "festival.Video", "festival.Audio",
"generic.ThreadedComment", (_("Media Library"), "fb_browse"),)),
(_("Site"), ("sites.Site", "redirects.Redirect", "conf.Setting")),
(_("Users"), ("auth.User", "auth.Group",)),
class VideoTranslationOptions(TranslationOptions):
fields = ('title', 'description', 'content')
+
+
+@register(Audio)
+class AudioTranslationOptions(TranslationOptions):
+
+ fields = ('title', 'description', 'content')