From 1354a1ddc55f0f87194c10ce161528d4d9698f07 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Tue, 16 Feb 2010 18:11:57 +0530 Subject: [PATCH] serve frames and videos with X-Sendfile header --- README | 4 ++++ apache/vhost.conf.in | 17 +++++++++++------ pandora/backend/models.py | 10 +++++++++- pandora/backend/urls.py | 2 ++ pandora/backend/views.py | 24 +++++++++++++++++++++++- pandora/settings.py | 2 ++ 6 files changed, 51 insertions(+), 8 deletions(-) diff --git a/README b/README index 810806f88..759851432 100644 --- a/README +++ b/README @@ -30,3 +30,7 @@ Development: we are using django, http://docs.djangoproject.com/en/dev/ communication between webserver and background tasks is done via rabbitmq http://github.com/ask/carrot/ for more info on the lib used to communicate + + +Apache setup: + sudo apt-get install libapache2-mod-wsgi libapache2-mod-xsendfile diff --git a/apache/vhost.conf.in b/apache/vhost.conf.in index cbcfb1107..8811d4b52 100644 --- a/apache/vhost.conf.in +++ b/apache/vhost.conf.in @@ -8,16 +8,21 @@ Allow from all - Alias /.bzr /oxdb/.bzr - Alias /static __PREFIX__/oxdb/static - Alias /favicon.ico __PREFIX__/oxdb/static/favicon.ico - Alias /media __PREFIX__/oxdb/media + + XSendFile on + XSendFileAllowAbove on + + + Alias /.bzr __PREFIX__/.bzr + Alias /static __PREFIX__/pandora/static + Alias /favicon.ico __PREFIX__/pandora/static/favicon.ico + Alias /media __PREFIX__/pandora/media Alias /admin/media __PREFIX__/src/django/django/contrib/admin/media Alias /static/js/jquery.js __PREFIX__/src/django/django/contrib/admin/media/js/jquery.min.js WSGIScriptAlias / __PREFIX__/wsgi/django.wsgi - WSGIDaemonProcess oxdb user=oxdb group=oxdb threads=25 python-path=__PREFIX__/lib/python2.6/site-packages/ - WSGIProcessGroup oxdb + WSGIDaemonProcess pandora user=pandora group=pandora threads=25 python-path=__PREFIX__/lib/python2.6/site-packages/ + WSGIProcessGroup pandora ServerSignature Off diff --git a/pandora/backend/models.py b/pandora/backend/models.py index b36b6cd59..e7f610a0e 100644 --- a/pandora/backend/models.py +++ b/pandora/backend/models.py @@ -10,6 +10,7 @@ from django.db.models import Q from django.contrib.auth.models import User from django.core.files.base import ContentFile from django.utils import simplejson as json +from django.conf import settings from oxdjango import fields import oxlib @@ -430,6 +431,11 @@ class Movie(models.Model): self.get('series_title', ''), self.get('episode_title', ''), self.get('season', ''), self.get('episode', '')) + def frame(self, position, width=128): + #FIXME: compute offset and so on + f = self.files.all()[0] + return f.frame(position, width) + def updateFind(self): try: f = self.find @@ -1155,7 +1161,9 @@ class File(models.Model): def frame(self, position, width=128): videoFile = getattr(self, 'stream_%s'%settings.VIDEO_PROFILE).path frameFolder = os.path.join(os.path.dirname(videoFile), 'frames') - extract.frame(videoFile, position, frameFolder, width) + if position<= self.duration: + return extract.frame(videoFile, position, frameFolder, width) + return None def editable(self, user): ''' diff --git a/pandora/backend/urls.py b/pandora/backend/urls.py index 481095624..b1a9ffec1 100644 --- a/pandora/backend/urls.py +++ b/pandora/backend/urls.py @@ -6,6 +6,8 @@ from django.conf.urls.defaults import * urlpatterns = patterns("backend.views", (r'^upload/$', 'firefogg_upload'), + (r'^frame/(?P.*)/(?P.*)\.(?P\d+).jpg$', 'frame'), + (r'^stream/(?P.*).(?P.*).ogv$', 'video'), (r'^$', 'api'), ) diff --git a/pandora/backend/views.py b/pandora/backend/views.py index 8e30cffb8..f23dd1a58 100644 --- a/pandora/backend/views.py +++ b/pandora/backend/views.py @@ -1,17 +1,19 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 +from __future__ import division import os.path import re from datetime import datetime from urllib2 import unquote import json +import mimetypes from django import forms from django.core.paginator import Paginator from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from django.db.models import Q, Avg, Count -from django.http import HttpResponse +from django.http import HttpResponse, Http404 from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404 from django.template import RequestContext from django.conf import settings @@ -23,6 +25,8 @@ except ImportError: from oxdjango.decorators import login_required_json from oxdjango.shortcuts import render_to_json_response, get_object_or_404_json, json_response +from oxdjango.http import HttpFileResponse +import oxlib import models import utils @@ -630,6 +634,24 @@ def api_subtitles(request): l = models.Subtitles.objects.filter(movie_file__oshash=oshash).values('language') response['data']['languages'] = [f['language'] for f in l] return render_to_json_response(response) + +def video(request, id, quality): + movie = get_object_or_404(models.Movie, movieId=id) + if quality not in settings.VIDEO_ENCODING: + raise Http404 + stream = getattr(movie, 'stream_'+quality) + response = HttpFileResponse(stream.path, content_type='video/ogg') + #FIXME: movie needs duration field + #response['Content-Duration'] = movie.duration + return response + +def frame(request, id, position, size): + movie = get_object_or_404(models.Movie, movieId=id) + position = oxlib.time2ms(position)/1000 + frame = movie.frame(position, int(size)) + if not frame: + raise Http404 + return HttpFileResponse(frame, content_type='image/jpeg') ''' GET list diff --git a/pandora/settings.py b/pandora/settings.py index 8c7ea2435..0b35d6cbd 100644 --- a/pandora/settings.py +++ b/pandora/settings.py @@ -13,6 +13,8 @@ DEBUG = True TEMPLATE_DEBUG = DEBUG JSON_DEBUG = False +XSENDFILE = False + ADMINS = ( ('j', 'j@mailb.org'), )