uploads, transcodes, /ra
This commit is contained in:
parent
b81d08fae5
commit
fba5070bc2
9 changed files with 128 additions and 40 deletions
|
@ -8,6 +8,10 @@ from oxdjango.shortcuts import json_response, render_to_json_response, get_objec
|
||||||
|
|
||||||
import models
|
import models
|
||||||
|
|
||||||
|
def intro(request):
|
||||||
|
context = RequestContext(request, {'settings':settings})
|
||||||
|
return render_to_response('intro.html', context)
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
context = RequestContext(request, {'settings':settings})
|
context = RequestContext(request, {'settings':settings})
|
||||||
return render_to_response('index.html', context)
|
return render_to_response('index.html', context)
|
||||||
|
|
|
@ -24,6 +24,9 @@ from backend import utils
|
||||||
from backend import extract
|
from backend import extract
|
||||||
from pandora.backend.models import Movie
|
from pandora.backend.models import Movie
|
||||||
|
|
||||||
|
import extract
|
||||||
|
|
||||||
|
|
||||||
def parse_decimal(string):
|
def parse_decimal(string):
|
||||||
string = string.replace(':', '/')
|
string = string.replace(':', '/')
|
||||||
if '/' not in string:
|
if '/' not in string:
|
||||||
|
@ -133,6 +136,11 @@ class File(models.Model):
|
||||||
r[k] = unicode(self[k])
|
r[k] = unicode(self[k])
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
def contents(self):
|
||||||
|
if self.contents_set.count() > 0:
|
||||||
|
return self.contents_set.all()[0].data
|
||||||
|
return None
|
||||||
|
|
||||||
class Volume(models.Model):
|
class Volume(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ("user", "name")
|
unique_together = ("user", "name")
|
||||||
|
@ -171,8 +179,8 @@ class FileInstance(models.Model):
|
||||||
return File.objects.get(oshash=self.oshash).movieId
|
return File.objects.get(oshash=self.oshash).movieId
|
||||||
|
|
||||||
def frame_path(f, name):
|
def frame_path(f, name):
|
||||||
ext = os.path.splitext(name)
|
ext = os.path.splitext(name)[-1]
|
||||||
name = "%s.%s" % (f.position, ext)
|
name = "%s%s" % (f.position, ext)
|
||||||
h = f.file.oshash
|
h = f.file.oshash
|
||||||
return os.path.join('frame', h[:2], h[2:4], h[4:6], name)
|
return os.path.join('frame', h[:2], h[2:4], h[4:6], name)
|
||||||
|
|
||||||
|
@ -188,7 +196,7 @@ class Frame(models.Model):
|
||||||
#FIXME: frame path should be renamed on save to match current position
|
#FIXME: frame path should be renamed on save to match current position
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return '%s at %s' % (self.file, self.position)
|
return u'%s at %s' % (self.file, self.position)
|
||||||
|
|
||||||
def stream_path(f):
|
def stream_path(f):
|
||||||
h = f.file.oshash
|
h = f.file.oshash
|
||||||
|
@ -204,10 +212,43 @@ class Stream(models.Model):
|
||||||
source = models.ForeignKey('Stream', related_name='derivatives', default=None, null=True)
|
source = models.ForeignKey('Stream', related_name='derivatives', default=None, null=True)
|
||||||
available = models.BooleanField(default=False)
|
available = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.video
|
||||||
|
|
||||||
def extract_derivates(self):
|
def extract_derivates(self):
|
||||||
#here based on settings derivates like smaller versions or other formats would be created
|
if settings.VIDEO_H264:
|
||||||
|
profile = self.profile.replace('.webm', '.mp4')
|
||||||
|
if Stream.objects.filter(profile=profile, source=self).count() == 0:
|
||||||
|
derivate = Stream(file=self.file, source=self, profile=profile)
|
||||||
|
derivate.video.name = self.video.name.replace(self.profile, profile)
|
||||||
|
derivate.encode()
|
||||||
|
|
||||||
|
for p in settings.VIDEO_DERIVATIVES:
|
||||||
|
profile = p + '.webm'
|
||||||
|
target = self.video.path.replace(self.profile, profile)
|
||||||
|
if Stream.objects.filter(profile=profile, source=self).count() == 0:
|
||||||
|
derivate = Stream(file=self.file, source=self, profile=profile)
|
||||||
|
derivate.video.name = self.video.name.replace(self.profile, profile)
|
||||||
|
derivate.encode()
|
||||||
|
|
||||||
|
if settings.VIDEO_H264:
|
||||||
|
profile = p + '.mp4'
|
||||||
|
if Stream.objects.filter(profile=profile, source=self).count() == 0:
|
||||||
|
derivate = Stream(file=self.file, source=self, profile=profile)
|
||||||
|
derivate.video.name = self.video.name.replace(self.profile, profile)
|
||||||
|
derivate.encode()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def encode(self):
|
||||||
|
if self.source:
|
||||||
|
video = self.source.video.path
|
||||||
|
target = self.video.path
|
||||||
|
profile = self.profile
|
||||||
|
info = self.file.info
|
||||||
|
if extract.stream(video, target, profile, info):
|
||||||
|
self.available=True
|
||||||
|
self.save()
|
||||||
|
|
||||||
def editable(self, user):
|
def editable(self, user):
|
||||||
#FIXME: possibly needs user setting for stream
|
#FIXME: possibly needs user setting for stream
|
||||||
return True
|
return True
|
||||||
|
@ -230,4 +271,15 @@ class Stream(models.Model):
|
||||||
self.file.save()
|
self.file.save()
|
||||||
super(Stream, self).save(*args, **kwargs)
|
super(Stream, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
class FileContents(models.Model):
|
||||||
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
|
modified = models.DateTimeField(auto_now=True)
|
||||||
|
file = models.ForeignKey(File, related_name="contents_set")
|
||||||
|
data = models.TextField(default=u'')
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if self.data and not self.file.available:
|
||||||
|
self.file.available = True
|
||||||
|
self.file.save()
|
||||||
|
super(FileContents, self).save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -159,28 +159,37 @@ def api_update(request):
|
||||||
|
|
||||||
|
|
||||||
@login_required_json
|
@login_required_json
|
||||||
#FIXME: is this part of the api or does it have to be outside due to multipart?
|
|
||||||
def api_upload(request):
|
def api_upload(request):
|
||||||
'''
|
'''
|
||||||
multipart
|
oshash: string
|
||||||
param data
|
frame: [] //multipart frames
|
||||||
oshash: string
|
file: [] //multipart file
|
||||||
frame: [] //multipart frames
|
|
||||||
return {'status': {'code': int, 'text': string},
|
return {'status': {'code': int, 'text': string},
|
||||||
'data': {info: object, rename: object}}
|
'data': {info: object, rename: object}}
|
||||||
'''
|
'''
|
||||||
user = request.user
|
user = request.user
|
||||||
f = get_object_or_404(models.File, oshash=request.POST['oshash'])
|
f = get_object_or_404(models.File, oshash=request.POST['oshash'])
|
||||||
if f.frames.count() == 0 and 'frame' in request.FILES:
|
if 'frame' in request.FILES:
|
||||||
for frame in request.FILES['frame']:
|
if f.frames.count() == 0:
|
||||||
name = frame.name
|
for frame in request.FILES.getlist('frame'):
|
||||||
position = float(os.path.splitext(name)[0])
|
name = frame.name
|
||||||
fr = models.Frame(file=f, position=position)
|
#float required?
|
||||||
fr.save()
|
position = float(os.path.splitext(name)[0])
|
||||||
fr.frame.save(frame, name)
|
fr = models.Frame(file=f, position=position)
|
||||||
response = json_response({})
|
fr.save()
|
||||||
else:
|
fr.frame.save(name, frame)
|
||||||
response = json_response(status=403, text='permissino denied')
|
response = json_response({})
|
||||||
|
else:
|
||||||
|
response = json_response(status=403, text='permissino denied')
|
||||||
|
if 'file' in request.FILES:
|
||||||
|
if f.contents.count() == 0:
|
||||||
|
contents = models.FileContents(file=f)
|
||||||
|
contents.data = request.FILES['file'].read()
|
||||||
|
contents.save()
|
||||||
|
response = json_response({})
|
||||||
|
else:
|
||||||
|
response = json_response(status=403, text='permissino denied')
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
|
|
||||||
class VideoChunkForm(forms.Form):
|
class VideoChunkForm(forms.Form):
|
||||||
|
@ -198,7 +207,6 @@ def firefogg_upload(request):
|
||||||
|
|
||||||
#post next chunk
|
#post next chunk
|
||||||
if 'chunk' in request.FILES and oshash:
|
if 'chunk' in request.FILES and oshash:
|
||||||
print "all chunk now"
|
|
||||||
stream = get_object_or_404(models.Stream, file__oshash=oshash, profile=profile)
|
stream = get_object_or_404(models.Stream, file__oshash=oshash, profile=profile)
|
||||||
|
|
||||||
form = VideoChunkForm(request.POST, request.FILES)
|
form = VideoChunkForm(request.POST, request.FILES)
|
||||||
|
@ -233,7 +241,6 @@ def firefogg_upload(request):
|
||||||
'result': 1
|
'result': 1
|
||||||
}
|
}
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
print request.GET, request.POST
|
|
||||||
response = json_response(status=400, text='this request requires POST')
|
response = json_response(status=400, text='this request requires POST')
|
||||||
return render_to_json_response(response)
|
return render_to_json_response(response)
|
||||||
|
|
||||||
|
|
|
@ -73,3 +73,5 @@ def resize_image(image_source, image_output, width):
|
||||||
resize_method = Image.BICUBIC
|
resize_method = Image.BICUBIC
|
||||||
output = source.resize((width, height), resize_method)
|
output = source.resize((width, height), resize_method)
|
||||||
output.save(image_output)
|
output.save(image_output)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,6 @@ import load
|
||||||
import utils
|
import utils
|
||||||
import extract
|
import extract
|
||||||
|
|
||||||
def plural_key(term):
|
|
||||||
return {
|
|
||||||
'country': 'countries',
|
|
||||||
}.get(term, term + 's')
|
|
||||||
|
|
||||||
|
|
||||||
def getMovie(info):
|
def getMovie(info):
|
||||||
'''
|
'''
|
||||||
|
@ -210,6 +205,7 @@ class Movie(models.Model):
|
||||||
else:
|
else:
|
||||||
movie[pub_key] = value
|
movie[pub_key] = value
|
||||||
movie['poster'] = self.get_poster()
|
movie['poster'] = self.get_poster()
|
||||||
|
|
||||||
if fields:
|
if fields:
|
||||||
for f in fields:
|
for f in fields:
|
||||||
if f.endswith('.length') and f[:-7] in ('cast', 'genre', 'trivia'):
|
if f.endswith('.length') and f[:-7] in ('cast', 'genre', 'trivia'):
|
||||||
|
@ -231,6 +227,13 @@ class Movie(models.Model):
|
||||||
self.get('series title', ''), self.get('episode title', ''),
|
self.get('series title', ''), self.get('episode title', ''),
|
||||||
self.get('season', ''), self.get('episode', ''))
|
self.get('season', ''), self.get('episode', ''))
|
||||||
|
|
||||||
|
def streams(self):
|
||||||
|
streams = []
|
||||||
|
for f in self.files.filter(is_main=True, available=True):
|
||||||
|
for s in f.streams.all():
|
||||||
|
streams.append(s.video.url)
|
||||||
|
return streams
|
||||||
|
|
||||||
def frame(self, position, width=128):
|
def frame(self, position, width=128):
|
||||||
#FIXME: compute offset and so on
|
#FIXME: compute offset and so on
|
||||||
f = self.files.all()[0]
|
f = self.files.all()[0]
|
||||||
|
@ -254,7 +257,7 @@ class Movie(models.Model):
|
||||||
elif key == 'character':
|
elif key == 'character':
|
||||||
values = [i[1] for i in self.get('actor', [])]
|
values = [i[1] for i in self.get('actor', [])]
|
||||||
else:
|
else:
|
||||||
values = self.get(plural_key(key), [])
|
values = self.get(utils.plural_key(key), [])
|
||||||
setattr(f, key, '|%s|'%'|'.join(values))
|
setattr(f, key, '|%s|'%'|'.join(values))
|
||||||
|
|
||||||
f.summary = self.get('plot', '') + self.get('plot_outline', '')
|
f.summary = self.get('plot', '') + self.get('plot_outline', '')
|
||||||
|
@ -303,10 +306,10 @@ class Movie(models.Model):
|
||||||
s.year = self.get('year', '')
|
s.year = self.get('year', '')
|
||||||
|
|
||||||
for key in self.person_keys:
|
for key in self.person_keys:
|
||||||
setattr(s, key, sortNames(self.get(plural_key(key), [])))
|
setattr(s, key, sortNames(self.get(utils.plural_key(key), [])))
|
||||||
|
|
||||||
for key in ('language', 'country'):
|
for key in ('language', 'country'):
|
||||||
setattr(s, key, ','.join(self.get(plural_key(key), [])))
|
setattr(s, key, ','.join(self.get(utils.plural_key(key), [])))
|
||||||
|
|
||||||
s.runtime = self.get('runtime', 0)
|
s.runtime = self.get('runtime', 0)
|
||||||
|
|
||||||
|
@ -351,7 +354,7 @@ class Movie(models.Model):
|
||||||
elif key == 'character':
|
elif key == 'character':
|
||||||
current_values = [i[1] for i in self.get('actor', [])]
|
current_values = [i[1] for i in self.get('actor', [])]
|
||||||
else:
|
else:
|
||||||
current_values = self.get(plural_key(key), [])
|
current_values = self.get(utils.plural_key(key), [])
|
||||||
saved_values = [i.value for i in Facet.objects.filter(movie=self, key=key)]
|
saved_values = [i.value for i in Facet.objects.filter(movie=self, key=key)]
|
||||||
removed_values = filter(lambda x: x not in current_values, saved_values)
|
removed_values = filter(lambda x: x not in current_values, saved_values)
|
||||||
if removed_values:
|
if removed_values:
|
||||||
|
@ -625,7 +628,6 @@ class Layer(models.Model):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class Collection(models.Model):
|
class Collection(models.Model):
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
modified = models.DateTimeField(auto_now=True)
|
modified = models.DateTimeField(auto_now=True)
|
||||||
|
|
|
@ -12,6 +12,12 @@ import ox
|
||||||
import ox.iso
|
import ox.iso
|
||||||
from ox.normalize import normalizeName, normalizeTitle
|
from ox.normalize import normalizeName, normalizeTitle
|
||||||
|
|
||||||
|
|
||||||
|
def plural_key(term):
|
||||||
|
return {
|
||||||
|
'country': 'countries',
|
||||||
|
}.get(term, term + 's')
|
||||||
|
|
||||||
def oxid(title, directors, year='', seriesTitle='', episodeTitle='', season=0, episode=0):
|
def oxid(title, directors, year='', seriesTitle='', episodeTitle='', season=0, episode=0):
|
||||||
director = ', '.join(directors)
|
director = ', '.join(directors)
|
||||||
oxid_value = u"\n".join([title, director, year])
|
oxid_value = u"\n".join([title, director, year])
|
||||||
|
|
|
@ -120,14 +120,18 @@ INSTALLED_APPS = (
|
||||||
AUTH_PROFILE_MODULE = 'oxuser.UserProfile'
|
AUTH_PROFILE_MODULE = 'oxuser.UserProfile'
|
||||||
|
|
||||||
#Video encoding settings
|
#Video encoding settings
|
||||||
VIDEO_PROFILE = 'low' # possible values low, mid or high
|
#available profiles: 96p, 270p, 360p, 480p, 720p, 1080p
|
||||||
VIDEO_ENCODING = {
|
|
||||||
'low': {'height': 96, 'videoBitrate': 180, 'softTarget': True,
|
VIDEO_PROFILE = '96p'
|
||||||
'samplerate': 44100, 'audioQuality': -1, 'channels': 1, 'noUpscaling': True},
|
VIDEO_DERIVATIVES = []
|
||||||
'mid': {'maxSize': 320, 'videoBitrate': 500,
|
VIDEO_H264 = True
|
||||||
'samplerate': 44100, 'audioQuality': 0, 'channels': 1, 'noUpscaling': True},
|
|
||||||
'high': {'profile': 'padma'}
|
|
||||||
}
|
#Pad.ma
|
||||||
|
#VIDEO_PROFILE = '480p'
|
||||||
|
#VIDEO_DERIVATIVES = ['96p', '270p', '360p']
|
||||||
|
#VIDEO_H264 = False
|
||||||
|
|
||||||
|
|
||||||
TRANSMISSON_HOST='localhost'
|
TRANSMISSON_HOST='localhost'
|
||||||
TRANSMISSON_PORT=9091
|
TRANSMISSON_PORT=9091
|
||||||
|
|
10
pandora/templates/intro.html
Normal file
10
pandora/templates/intro.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>pan.do/ra</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
this is a pan.do/ra development preview, <a href="/ra">click here to continue</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -13,7 +13,8 @@ urlpatterns = patterns('',
|
||||||
(r'^api/', include('backend.urls')),
|
(r'^api/', include('backend.urls')),
|
||||||
(r'^api/upload/$', 'archive.views.firefogg_upload'),
|
(r'^api/upload/$', 'archive.views.firefogg_upload'),
|
||||||
(r'^site.js$', 'app.views.site_js'),
|
(r'^site.js$', 'app.views.site_js'),
|
||||||
(r'^$', 'app.views.index'),
|
(r'^$', 'app.views.intro'),
|
||||||
|
(r'^ra$', 'app.views.index'),
|
||||||
(r'^r/(?P<key>.*)$', 'oxuser.views.recover'),
|
(r'^r/(?P<key>.*)$', 'oxuser.views.recover'),
|
||||||
|
|
||||||
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
|
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
|
||||||
|
|
Loading…
Reference in a new issue