]> git.parisson.com Git - mezzo.git/commitdiff
add abstract Media and Audio models with automatic URL retrieval
authorGuillaume Pellerin <guillaume.pellerin@ircam.fr>
Mon, 21 Mar 2016 23:34:41 +0000 (00:34 +0100)
committerGuillaume Pellerin <guillaume.pellerin@ircam.fr>
Mon, 21 Mar 2016 23:34:50 +0000 (00:34 +0100)
app/festival/admin.py
app/festival/migrations/0008_auto_20160322_0018.py [new file with mode: 0644]
app/festival/migrations/0009_auto_20160322_0021.py [new file with mode: 0644]
app/festival/models.py
app/festival/templates/festival/audio_playlist.html [new file with mode: 0644]
app/festival/templates/festival/playlist.html [deleted file]
app/sandbox/local_settings.py
app/translations.py

index 65918868b1b293a388381ef3d4bed87e92f73d47..df00c8a0bb21d43ecaa8c1df4b3dfeec0d6f5b00 100644 (file)
@@ -29,6 +29,16 @@ class VideoAdminDisplayable(DisplayableAdmin):
     fieldsets = deepcopy(VideoAdmin.fieldsets)
 
 
+class AudioAdmin(admin.ModelAdmin):
+
+    model = Audio
+
+
+class AudioAdminDisplayable(DisplayableAdmin):
+
+    fieldsets = deepcopy(AudioAdmin.fieldsets)
+
+
 class ArtistAdminDisplayable(DisplayableAdmin):
 
     fieldsets = deepcopy(ArtistAdmin.fieldsets)
@@ -37,3 +47,4 @@ class ArtistAdminDisplayable(DisplayableAdmin):
 admin.site.register(PageCategory)
 admin.site.register(Artist, ArtistAdminDisplayable)
 admin.site.register(Video, VideoAdminDisplayable)
+admin.site.register(Audio, AudioAdminDisplayable)
diff --git a/app/festival/migrations/0008_auto_20160322_0018.py b/app/festival/migrations/0008_auto_20160322_0018.py
new file mode 100644 (file)
index 0000000..98de723
--- /dev/null
@@ -0,0 +1,58 @@
+# -*- 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'),
+        ),
+    ]
diff --git a/app/festival/migrations/0009_auto_20160322_0021.py b/app/festival/migrations/0009_auto_20160322_0021.py
new file mode 100644 (file)
index 0000000..d2be559
--- /dev/null
@@ -0,0 +1,46 @@
+# -*- 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'),
+        ),
+    ]
index 71c892a82ddf015eaab31c0f5b2630ea6db3d60c..a9b690ab8bdf4bdddcb279e04baa9e150cdedec2 100644 (file)
@@ -1,6 +1,7 @@
 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
@@ -8,13 +9,17 @@ from mezzanine.utils.models import AdminThumbMixin, upload_to
 
 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:
 
@@ -46,6 +51,13 @@ class BaseTitleModel(models.Model):
         return self.title
 
 
+class PageCategory(BaseNameModel):
+    """Page Category"""
+
+    class Meta(MetaCore):
+        verbose_name = _('page category')
+
+
 class Artist(Displayable, RichText, AdminThumbMixin):
     """Artist"""
 
@@ -76,30 +88,71 @@ class Artist(Displayable, RichText, AdminThumbMixin):
         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})
diff --git a/app/festival/templates/festival/audio_playlist.html b/app/festival/templates/festival/audio_playlist.html
new file mode 100644 (file)
index 0000000..073ffda
--- /dev/null
@@ -0,0 +1,74 @@
+<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>
diff --git a/app/festival/templates/festival/playlist.html b/app/festival/templates/festival/playlist.html
deleted file mode 100644 (file)
index 073ffda..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-<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>
index 7121d4a910278a4b8c27d4d6689cef59c57e719e..7ea53d1d4b927d327b0c51488da6f1bcd3fa5b68 100644 (file)
@@ -78,7 +78,7 @@ EVENT_USE_FEATURED_IMAGE = True
 
 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",)),
index 794a7429c202cd22800b048dca54a1dbf9fe16d8..e625b9beaa391b818d26f5f059ae5037b61c35b5 100644 (file)
@@ -20,3 +20,9 @@ class ArtistTranslationOptions(TranslationOptions):
 class VideoTranslationOptions(TranslationOptions):
 
     fields = ('title', 'description', 'content')
+
+
+@register(Audio)
+class AudioTranslationOptions(TranslationOptions):
+
+    fields = ('title', 'description', 'content')