forked from 0x2620/pandora
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
|
||||
|
||||
def intro(request):
|
||||
context = RequestContext(request, {'settings':settings})
|
||||
return render_to_response('intro.html', context)
|
||||
|
||||
def index(request):
|
||||
context = RequestContext(request, {'settings':settings})
|
||||
return render_to_response('index.html', context)
|
||||
|
|
|
@ -24,6 +24,9 @@ from backend import utils
|
|||
from backend import extract
|
||||
from pandora.backend.models import Movie
|
||||
|
||||
import extract
|
||||
|
||||
|
||||
def parse_decimal(string):
|
||||
string = string.replace(':', '/')
|
||||
if '/' not in string:
|
||||
|
@ -133,6 +136,11 @@ class File(models.Model):
|
|||
r[k] = unicode(self[k])
|
||||
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 Meta:
|
||||
unique_together = ("user", "name")
|
||||
|
@ -171,8 +179,8 @@ class FileInstance(models.Model):
|
|||
return File.objects.get(oshash=self.oshash).movieId
|
||||
|
||||
def frame_path(f, name):
|
||||
ext = os.path.splitext(name)
|
||||
name = "%s.%s" % (f.position, ext)
|
||||
ext = os.path.splitext(name)[-1]
|
||||
name = "%s%s" % (f.position, ext)
|
||||
h = f.file.oshash
|
||||
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
|
||||
|
||||
def __unicode__(self):
|
||||
return '%s at %s' % (self.file, self.position)
|
||||
return u'%s at %s' % (self.file, self.position)
|
||||
|
||||
def stream_path(f):
|
||||
h = f.file.oshash
|
||||
|
@ -204,10 +212,43 @@ class Stream(models.Model):
|
|||
source = models.ForeignKey('Stream', related_name='derivatives', default=None, null=True)
|
||||
available = models.BooleanField(default=False)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.video
|
||||
|
||||
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
|
||||
|
||||
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):
|
||||
#FIXME: possibly needs user setting for stream
|
||||
return True
|
||||
|
@ -230,4 +271,15 @@ class Stream(models.Model):
|
|||
self.file.save()
|
||||
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,25 +159,34 @@ def api_update(request):
|
|||
|
||||
|
||||
@login_required_json
|
||||
#FIXME: is this part of the api or does it have to be outside due to multipart?
|
||||
def api_upload(request):
|
||||
'''
|
||||
multipart
|
||||
param data
|
||||
oshash: string
|
||||
frame: [] //multipart frames
|
||||
file: [] //multipart file
|
||||
|
||||
return {'status': {'code': int, 'text': string},
|
||||
'data': {info: object, rename: object}}
|
||||
'''
|
||||
user = request.user
|
||||
f = get_object_or_404(models.File, oshash=request.POST['oshash'])
|
||||
if f.frames.count() == 0 and 'frame' in request.FILES:
|
||||
for frame in request.FILES['frame']:
|
||||
if 'frame' in request.FILES:
|
||||
if f.frames.count() == 0:
|
||||
for frame in request.FILES.getlist('frame'):
|
||||
name = frame.name
|
||||
#float required?
|
||||
position = float(os.path.splitext(name)[0])
|
||||
fr = models.Frame(file=f, position=position)
|
||||
fr.save()
|
||||
fr.frame.save(frame, name)
|
||||
fr.frame.save(name, frame)
|
||||
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')
|
||||
|
@ -198,7 +207,6 @@ def firefogg_upload(request):
|
|||
|
||||
#post next chunk
|
||||
if 'chunk' in request.FILES and oshash:
|
||||
print "all chunk now"
|
||||
stream = get_object_or_404(models.Stream, file__oshash=oshash, profile=profile)
|
||||
|
||||
form = VideoChunkForm(request.POST, request.FILES)
|
||||
|
@ -233,7 +241,6 @@ def firefogg_upload(request):
|
|||
'result': 1
|
||||
}
|
||||
return render_to_json_response(response)
|
||||
print request.GET, request.POST
|
||||
response = json_response(status=400, text='this request requires POST')
|
||||
return render_to_json_response(response)
|
||||
|
||||
|
|
|
@ -73,3 +73,5 @@ def resize_image(image_source, image_output, width):
|
|||
resize_method = Image.BICUBIC
|
||||
output = source.resize((width, height), resize_method)
|
||||
output.save(image_output)
|
||||
|
||||
|
||||
|
|
|
@ -25,11 +25,6 @@ import load
|
|||
import utils
|
||||
import extract
|
||||
|
||||
def plural_key(term):
|
||||
return {
|
||||
'country': 'countries',
|
||||
}.get(term, term + 's')
|
||||
|
||||
|
||||
def getMovie(info):
|
||||
'''
|
||||
|
@ -210,6 +205,7 @@ class Movie(models.Model):
|
|||
else:
|
||||
movie[pub_key] = value
|
||||
movie['poster'] = self.get_poster()
|
||||
|
||||
if fields:
|
||||
for f in fields:
|
||||
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('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):
|
||||
#FIXME: compute offset and so on
|
||||
f = self.files.all()[0]
|
||||
|
@ -254,7 +257,7 @@ class Movie(models.Model):
|
|||
elif key == 'character':
|
||||
values = [i[1] for i in self.get('actor', [])]
|
||||
else:
|
||||
values = self.get(plural_key(key), [])
|
||||
values = self.get(utils.plural_key(key), [])
|
||||
setattr(f, key, '|%s|'%'|'.join(values))
|
||||
|
||||
f.summary = self.get('plot', '') + self.get('plot_outline', '')
|
||||
|
@ -303,10 +306,10 @@ class Movie(models.Model):
|
|||
s.year = self.get('year', '')
|
||||
|
||||
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'):
|
||||
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)
|
||||
|
||||
|
@ -351,7 +354,7 @@ class Movie(models.Model):
|
|||
elif key == 'character':
|
||||
current_values = [i[1] for i in self.get('actor', [])]
|
||||
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)]
|
||||
removed_values = filter(lambda x: x not in current_values, saved_values)
|
||||
if removed_values:
|
||||
|
@ -625,7 +628,6 @@ class Layer(models.Model):
|
|||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Collection(models.Model):
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
modified = models.DateTimeField(auto_now=True)
|
||||
|
|
|
@ -12,6 +12,12 @@ import ox
|
|||
import ox.iso
|
||||
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):
|
||||
director = ', '.join(directors)
|
||||
oxid_value = u"\n".join([title, director, year])
|
||||
|
|
|
@ -120,14 +120,18 @@ INSTALLED_APPS = (
|
|||
AUTH_PROFILE_MODULE = 'oxuser.UserProfile'
|
||||
|
||||
#Video encoding settings
|
||||
VIDEO_PROFILE = 'low' # possible values low, mid or high
|
||||
VIDEO_ENCODING = {
|
||||
'low': {'height': 96, 'videoBitrate': 180, 'softTarget': True,
|
||||
'samplerate': 44100, 'audioQuality': -1, 'channels': 1, 'noUpscaling': True},
|
||||
'mid': {'maxSize': 320, 'videoBitrate': 500,
|
||||
'samplerate': 44100, 'audioQuality': 0, 'channels': 1, 'noUpscaling': True},
|
||||
'high': {'profile': 'padma'}
|
||||
}
|
||||
#available profiles: 96p, 270p, 360p, 480p, 720p, 1080p
|
||||
|
||||
VIDEO_PROFILE = '96p'
|
||||
VIDEO_DERIVATIVES = []
|
||||
VIDEO_H264 = True
|
||||
|
||||
|
||||
#Pad.ma
|
||||
#VIDEO_PROFILE = '480p'
|
||||
#VIDEO_DERIVATIVES = ['96p', '270p', '360p']
|
||||
#VIDEO_H264 = False
|
||||
|
||||
|
||||
TRANSMISSON_HOST='localhost'
|
||||
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/upload/$', 'archive.views.firefogg_upload'),
|
||||
(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'),
|
||||
|
||||
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
|
||||
|
|
Loading…
Reference in a new issue