]> git.parisson.com Git - timeside.git/commitdiff
Server: add download methods for transcoded media (for api serilaizers and timeside...
authorThomas Fillon <thomas@parisson.com>
Mon, 1 Dec 2014 15:15:19 +0000 (16:15 +0100)
committerThomas Fillon <thomas@parisson.com>
Mon, 1 Dec 2014 15:15:19 +0000 (16:15 +0100)
Add a html5 audio player to the item page

see:
- for app : /item/1, /item/1/download/ogg, /item/1/download/mp3
- for api Serializers : /results/1/audio/

timeside/server/models.py
timeside/server/templates/timeside/index.html
timeside/server/templates/timeside/item_detail.html [new file with mode: 0644]
timeside/server/urls.py
timeside/server/utils.py [new file with mode: 0644]
timeside/server/views.py

index 762855e5128f238c289d37325a5c94dac3791b38..2d36944467d09459c4b578caf212da8f16511780 100644 (file)
@@ -34,7 +34,7 @@ from timeside.decoder.utils import sha1sum_file
 from django.db import models
 from django.utils.translation import ugettext_lazy as _
 from django.contrib.auth.models import User
-from django.db.models.signals import post_save
+from django.db.models.signals import post_save, pre_save
 from django.conf import settings
 
 app = 'timeside'
@@ -310,8 +310,7 @@ class Task(BaseResource):
                 item.save()
             pipe.run()
             item.lock_setter(True)
-            pipe.results.to_hdf5(item.hdf5.path)
-            item.lock_setter(False)
+            #pipe.results.to_hdf5(item.hdf5.path)
 
             for preset in presets.keys():
                 proc = presets[preset]
@@ -339,6 +338,8 @@ class Task(BaseResource):
                     result.status_setter(_DONE)
                 del proc
 
+            item.lock_setter(False)
+
             # except:
             #     self.status_setter(0)
             #     item.lock_setter(False)
@@ -368,7 +369,7 @@ def run(sender, **kwargs):
         instance.run()
 
 
-post_save.connect(set_mimetype, sender=Item)
-post_save.connect(set_hash, sender=Item)
-post_save.connect(set_mimetype, sender=Result)
+pre_save.connect(set_mimetype, sender=Item)
+pre_save.connect(set_hash, sender=Item)
+pre_save.connect(set_mimetype, sender=Result)
 post_save.connect(run, sender=Task)
index 9e67fd7ccff704f0b6a09d800b44f4e2df725052..68f9d37aca11eb93f9bc8653488346189dd1ac2d 100644 (file)
@@ -5,7 +5,7 @@
 
 <ul>
  {% for item in object_list %}
-  <li>{{ item.title }}</li>
+  <li><a href="/items/{{ item.id }}/">{{ item.title }}</a></li>
  {% endfor %}
 </ul>
 
diff --git a/timeside/server/templates/timeside/item_detail.html b/timeside/server/templates/timeside/item_detail.html
new file mode 100644 (file)
index 0000000..2511ceb
--- /dev/null
@@ -0,0 +1,70 @@
+{% extends "timeside/base.html" %}
+{% load i18n %}
+
+{% block content %}
+
+<ul>
+   <li>File: {{ object.file }}</li>
+   <li>url : {{ object.url }}</li>
+   <li>sha1 : {{ object.sha1 }}</li>
+   <li>mime_type : {{ object.mime_type }}</li>
+   <li>hdf5 : {{ object.hdf5 }}</li>
+   <li>author: {{ object.author }}</li>
+   <li>lock : {{ object.lock }}</li>
+
+
+</ul>
+{% block html5-player %}
+ <audio controls>
+  <source src="download/ogg" type="audio/ogg">
+  <source src="download/mp3" type="audio/mpeg">
+Your browser does not support the audio element.
+</audio>
+{% endblock html5-player %}
+    {% block player %}
+
+
+    <div id="player_maximized" class="ts-skin-lab">
+       <div id="player_header">
+        <a href="#" class="toggle">Minimize</a>
+        <a href="#" class="embed_player_frame">&lt;/&gt;</a>
+       </div>
+        <div class="wazing"></div>
+    </div>
+    <div id="rightcol">
+        <div id="player_minimized" class="ts-skin-lab">
+            <a href="#" class="toggle">Maximize</a>
+            <a href="#" class="embed_player_frame">&lt;/&gt;</a>
+            <div class="wazing"></div>
+            <div id="player" class="ts-player">
+            </div>
+        </div>
+
+    {% if "video" in mime_type %}
+    <div>
+    <video id="my_video_1" class="video-js vjs-default-skin" width="362" height="240" controls preload="auto" data-setup="{}">
+        <!-- Hello Chrome and Firefox (and Opera?) -->
+        {% comment "Optional note" %}
+            <source src="{% url "telemeta-item-export" item.public_id mime_type|mime_to_ext %}" type="{{ mime_type }}" />
+        {% endcomment %}
+        </video>
+        <!--<div id="videotime"></div>-->
+    </div>
+    <script>
+    (function(){
+        var v = document.getElementsByTagName('video')[0]
+        var t = document.getElementById('videotime');
+        v.addEventListener('timeupdate',function(event){
+            t.innerHTML = v.currentTime;
+            },false);
+            })();
+    </script>
+    {% endif %}
+
+
+    </div>
+
+
+
+    {% endblock player %}
+{% endblock content %}
index 8b15d22659b1b5ec896fdece843ef0399694dbfa..e1b7a6704053f5466dd96fec8b526f4116c912c0 100644 (file)
@@ -4,6 +4,9 @@ from django.conf.urls import patterns, include, url
 from django.contrib import admin
 from rest_framework import routers
 from timeside.server import views
+from timeside.server.utils import TS_ENCODERS_EXT
+
+EXPORT_EXT = "|".join(TS_ENCODERS_EXT.keys())
 
 admin.autodiscover()
 
@@ -22,8 +25,19 @@ urlpatterns = patterns(
     url(r'^admin/', include(admin.site.urls)),
     url(r'^api/', include(api_router.urls)),
     url(r'^$', views.IndexView.as_view(), name="timeside-index"),
+    # Items
+    # ex: /item/5/
+    url(r'^items/(?P<pk>\d+)/$', views.ItemDetail.as_view(),
+        name='timeside-item-detail'),
+    # Get transcoded audio
+    # Ex: /item/5/download/ogg
+    url(r'^items/(?P<pk>\d+)/download/(?P<extension>' + EXPORT_EXT + ')$',
+        views.ItemExport.as_view(), name="item-export"),
+    # Results
     url(r'^results/(?P<pk>.*)/json/$', views.ResultAnalyzerView.as_view(),
         name="timeside-result-json"),
     url(r'^results/(?P<pk>.*)/png/$', views.ResultGrapherView.as_view(),
         name="timeside-result-png"),
+    url(r'^results/(?P<pk>.*)/audio/$', views.ResultEncoderView.as_view(),
+        name="timeside-result-audio"),
     )
diff --git a/timeside/server/utils.py b/timeside/server/utils.py
new file mode 100644 (file)
index 0000000..d09f73b
--- /dev/null
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+
+import timeside.core
+from timeside.api import IEncoder
+
+TS_ENCODERS = timeside.core.processors(IEncoder)
+TS_ENCODERS_EXT = {encoder.file_extension(): encoder.id()
+                   for encoder in TS_ENCODERS
+                   if encoder.file_extension()}
+
index 6a0c752d6f83f88838ca70f0103fcd902da4ce03..d77ad691e9470e7d866e09f90502a633a7762c9c 100644 (file)
 # You should have received a copy of the GNU General Public License
 # along with TimeSide.  If not, see <http://www.gnu.org/licenses/>.
 #
-# Author : Guillaume Pellerin <yomguy@parisson.com>
+# Authors : Guillaume Pellerin <yomguy@parisson.com>
+#           Thomas Fillon <thomas@parisson.com>
 
-
-from django.views.generic import *
-from django.http import HttpResponse, HttpResponseRedirect
+from django.http import Http404
+from django.views.generic.base import View
+from django.views.generic import DetailView, ListView
+from django.views.generic.detail import SingleObjectMixin
+from django.http import HttpResponse
 
 from rest_framework import viewsets
-from rest_framework.mixins import UpdateModelMixin
 
-from timeside.server.models import *
-from timeside.server.serializers import *
+from timeside.server.models import Experience, Item, Result, Processor
+from timeside.server.models import Preset, Selection, Task, User
+from timeside.server.models import _PENDING
+from timeside.server.serializers import ExperienceSerializer, ItemSerializer
+from timeside.server.serializers import PresetSerializer
+from timeside.server.serializers import ProcessorSerializer
+from timeside.server.serializers import ResultSerializer
+from timeside.server.serializers import SelectionSerializer
+from timeside.server.serializers import TaskSerializer
+from timeside.server.serializers import UserSerializer
+
+from timeside.analyzer.core import AnalyzerResultContainer
+import os
 
 
 def stream_from_file(file):
@@ -123,3 +136,57 @@ class ResultGrapherView(View):
         return HttpResponse(stream_from_file(result.file.path),
                             mimetype='image/png')
 
+
+class ResultEncoderView(View):
+
+    model = Result
+
+    def get(self, request, *args, **kwargs):
+        result = Result.objects.get(pk=kwargs['pk'])
+        return HttpResponse(stream_from_file(result.file.path),
+                            mimetype=result.mime_type)
+
+
+class ItemDetail(DetailView):
+
+    model = Item
+    template_name = 'timeside/item_detail.html'
+
+
+class ItemExport(DetailView, SingleObjectMixin):
+    model = Item
+
+    def get(self, request, pk, extension):
+        from . utils import TS_ENCODERS_EXT
+
+        if extension not in TS_ENCODERS_EXT:
+            raise Http404('Unknown export file extension: %s' % extension)
+
+        encoder = TS_ENCODERS_EXT[extension]
+        # Get or Create Processor = encoder
+        processor, created = Processor.objects.get_or_create(pid=encoder)
+        # Get or Create Preset with processor
+        preset, created = Preset.objects.get_or_create(processor=processor)
+        # Get Result with preset and item
+        item = self.get_object()
+        try:
+            result = Result.objects.get(item=item, preset=preset)
+            if not os.path.exists(result.file.path):
+                result.delete()
+                return self.get(request, pk, extension)
+            return HttpResponse(stream_from_file(result.file.path),
+                                mimetype=result.mime_type)
+        except Result.DoesNotExist:
+            # Result does not exist
+            # the corresponding task has to be created and run
+            experience = Experience()
+            experience.save()
+            experience.presets.add(preset)
+            selection = Selection()
+            selection.save()
+            selection.items.add(item)
+            task = Task(experience=experience, selection=selection,
+                        status=_PENDING)
+            task.save()  # save task and run
+            # TODO : find a way to stream during task ...
+            return self.get(request, pk, extension)