From 4eea0f280230cc296773511e4278b343efffbbaf Mon Sep 17 00:00:00 2001 From: Thomas Fillon Date: Mon, 1 Dec 2014 16:15:19 +0100 Subject: [PATCH] Server: add download methods for transcoded media (for api serilaizers and timeside.server app) 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 | 13 +-- timeside/server/templates/timeside/index.html | 2 +- .../templates/timeside/item_detail.html | 70 ++++++++++++++++ timeside/server/urls.py | 14 ++++ timeside/server/utils.py | 10 +++ timeside/server/views.py | 81 +++++++++++++++++-- 6 files changed, 176 insertions(+), 14 deletions(-) create mode 100644 timeside/server/templates/timeside/item_detail.html create mode 100644 timeside/server/utils.py diff --git a/timeside/server/models.py b/timeside/server/models.py index 762855e..2d36944 100644 --- a/timeside/server/models.py +++ b/timeside/server/models.py @@ -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) diff --git a/timeside/server/templates/timeside/index.html b/timeside/server/templates/timeside/index.html index 9e67fd7..68f9d37 100644 --- a/timeside/server/templates/timeside/index.html +++ b/timeside/server/templates/timeside/index.html @@ -5,7 +5,7 @@ diff --git a/timeside/server/templates/timeside/item_detail.html b/timeside/server/templates/timeside/item_detail.html new file mode 100644 index 0000000..2511ceb --- /dev/null +++ b/timeside/server/templates/timeside/item_detail.html @@ -0,0 +1,70 @@ +{% extends "timeside/base.html" %} +{% load i18n %} + +{% block content %} + + +{% block html5-player %} + +{% endblock html5-player %} + {% block player %} + + +
+
+ Minimize + </> +
+
+
+
+
+ Maximize + </> +
+
+
+
+ + {% if "video" in mime_type %} +
+ + +
+ + {% endif %} + + +
+ + + + {% endblock player %} +{% endblock content %} diff --git a/timeside/server/urls.py b/timeside/server/urls.py index 8b15d22..e1b7a67 100644 --- a/timeside/server/urls.py +++ b/timeside/server/urls.py @@ -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\d+)/$', views.ItemDetail.as_view(), + name='timeside-item-detail'), + # Get transcoded audio + # Ex: /item/5/download/ogg + url(r'^items/(?P\d+)/download/(?P' + EXPORT_EXT + ')$', + views.ItemExport.as_view(), name="item-export"), + # Results url(r'^results/(?P.*)/json/$', views.ResultAnalyzerView.as_view(), name="timeside-result-json"), url(r'^results/(?P.*)/png/$', views.ResultGrapherView.as_view(), name="timeside-result-png"), + url(r'^results/(?P.*)/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 index 0000000..d09f73b --- /dev/null +++ b/timeside/server/utils.py @@ -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()} + diff --git a/timeside/server/views.py b/timeside/server/views.py index 6a0c752..d77ad69 100644 --- a/timeside/server/views.py +++ b/timeside/server/views.py @@ -18,17 +18,30 @@ # You should have received a copy of the GNU General Public License # along with TimeSide. If not, see . # -# Author : Guillaume Pellerin +# Authors : Guillaume Pellerin +# Thomas Fillon - -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) -- 2.39.5