subtitles

This commit is contained in:
j 2010-09-18 16:44:35 +02:00
parent c5b74c6f77
commit e64dd48ee2
4 changed files with 115 additions and 85 deletions

View file

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
from __future__ import division
from datetime import datetime from datetime import datetime
import os.path import os.path
import random import random
@ -19,6 +20,7 @@ import ox
from ox import stripTags from ox import stripTags
from ox.normalize import canonicalTitle, canonicalName from ox.normalize import canonicalTitle, canonicalName
from firefogg import Firefogg from firefogg import Firefogg
import chardet
from backend import utils from backend import utils
from pandora.backend.models import Movie from pandora.backend.models import Movie
@ -149,6 +151,65 @@ class File(models.Model):
return self.data.read() return self.data.read()
return None return None
def srt(self):
def _detectEncoding(fp):
bomDict={ # bytepattern : name
(0x00, 0x00, 0xFE, 0xFF) : "utf_32_be",
(0xFF, 0xFE, 0x00, 0x00) : "utf_32_le",
(0xFE, 0xFF, None, None) : "utf_16_be",
(0xFF, 0xFE, None, None) : "utf_16_le",
(0xEF, 0xBB, 0xBF, None) : "utf_8",
}
# go to beginning of file and get the first 4 bytes
oldFP = fp.tell()
fp.seek(0)
(byte1, byte2, byte3, byte4) = tuple(map(ord, fp.read(4)))
# try bom detection using 4 bytes, 3 bytes, or 2 bytes
bomDetection = bomDict.get((byte1, byte2, byte3, byte4))
if not bomDetection :
bomDetection = bomDict.get((byte1, byte2, byte3, None))
if not bomDetection :
bomDetection = bomDict.get((byte1, byte2, None, None))
## if BOM detected, we're done :-)
fp.seek(oldFP)
if bomDetection :
return bomDetection
encoding = 'latin-1'
#more character detecting magick using http://chardet.feedparser.org/
fp.seek(0)
rawdata = fp.read()
encoding = chardet.detect(rawdata)['encoding']
fp.seek(oldFP)
return encoding
def parseTime(t):
return ox.time2ms(t.replace(',', '.')) / 1000
srt = []
f = open(self.data.path)
encoding = _detectEncoding(f)
data = f.read()
f.close()
try:
data = unicode(data, encoding)
except:
try:
data = unicode(data, 'latin-1')
except:
print "failed to detect encoding, giving up"
return srt
srts = re.compile('(\d\d:\d\d:\d\d[,.]\d\d\d)\s*-->\s*(\d\d:\d\d:\d\d[,.]\d\d\d)\s*(.+?)\n\n', re.DOTALL)
for s in srts.findall(data):
_s = {'in': parseTime(s[0]), 'out': parseTime(s[1]), 'text': s[2].strip()}
srt.append(_s)
return srt
def editable(self, user): def editable(self, user):
#FIXME: check that user has instance of this file #FIXME: check that user has instance of this file
return True return True

View file

@ -270,6 +270,16 @@ class Movie(models.Model):
stream['profiles'] = list(set(map(lambda s: int(os.path.splitext(s['profile'])[0][:-1]), self.streams.all().values('profile')))) stream['profiles'] = list(set(map(lambda s: int(os.path.splitext(s['profile'])[0][:-1]), self.streams.all().values('profile'))))
return stream return stream
def get_layers(self):
layers = {}
layers['cuts'] = self.metadata.get('cuts', {})
layers['subtitles'] = {}
qs = self.files.filter(is_subtitle=True, is_main=True, available=True)
if qs.count()>0:
layers['subtitles'] = qs[0].srt()
return layers
def get_json(self, fields=None): def get_json(self, fields=None):
movie = {} movie = {}
for key in self._public_fields: for key in self._public_fields:

View file

@ -279,7 +279,10 @@ def api_getItem(request):
itemId = json.loads(request.POST['data']) itemId = json.loads(request.POST['data'])
item = get_object_or_404_json(models.Movie, movieId=itemId) item = get_object_or_404_json(models.Movie, movieId=itemId)
#FIXME: check permissions #FIXME: check permissions
response['data'] = {'item': item.get_json()} info = item.get_json()
info['stream'] = item.get_stream()
info['layers'] = item.get_layers()
response['data'] = {'item': info}
return render_to_json_response(response) return render_to_json_response(response)
@login_required_json @login_required_json
@ -316,45 +319,6 @@ def api_removeItem(request):
response = json_response(status=403, text='permissino denied') response = json_response(status=403, text='permissino denied')
return render_to_json_response(response) return render_to_json_response(response)
def api_info(request):
'''
param data
string id
return {'status': {'code': int, 'text': string}, 'data': {'info': {}}}
'''
response = json_response({})
itemId = json.loads(request.POST['data'])
item = get_object_or_404_json(models.Movie, movieId=itemId)
response['data'] = {'info': movie.get_stream()}
return render_to_json_response(response)
def api_subtitles(request):
'''
param data
string id
return {'status': {'code': int, 'text': string}, 'data': {'subtitles': {}}}
'''
response = json_response({})
itemId = json.loads(request.POST['data'])
item = get_object_or_404_json(models.Movie, movieId=itemId)
response['data'] = {'subtitles': movie.metadata.get('subtitles', {})}
return render_to_json_response(response)
def api_cuts(request):
'''
param data
string id
return {'status': {'code': int, 'text': string}, 'data': {'cuts': {}}}
'''
response = json_response({})
itemId = json.loads(request.POST['data'])
item = get_object_or_404_json(models.Movie, movieId=itemId)
response['data'] = {'cuts': movie.metadata.get('cuts', {})}
return render_to_json_response(response)
@login_required_json @login_required_json
def api_addLayer(request): def api_addLayer(request):
''' '''

View file

@ -518,57 +518,52 @@ app.constructItem = function(id, view) {
app.$ui.contentPanel.resize(0, 80); app.$ui.contentPanel.resize(0, 80);
app.$ui.groupsOuterPanel.empty(); app.$ui.groupsOuterPanel.empty();
if (view == 'timeline') { if (view == 'timeline') {
// fixme: this should be one app request, not three getJSONs app.api.getItem(id, function(result) {
$.getJSON('/' + id + '/data/video.json', function(data) { item_debug = result.data.item;
var video = data; var video = result.data.item.stream,
video.height = 96; cuts = result.data.item.layers.cuts || {},
video.width = parseInt(video.height * video.aspectRatio / 2) * 2; subtitles = result.data.item.layers.subtitles || [{
video.url = video.baseUrl + '/' + video.height + 'p.' + ($.support.video.webm ? 'webm' : 'mp4');
$.getJSON('/' + id + '/data/subtitles.json', function(data) {
var subtitles = data;
subtitles = [{
'in': 5, 'in': 5,
'out': 10, 'out': 10,
'text': 'This subtitle is just a test...' 'text': 'This subtitle is just a test...'
}]; }];
$.getJSON('/' + id + '/data/cuts.json', function(data) { video.height = 96;
var cuts = data; video.width = parseInt(video.height * video.aspectRatio / 2) * 2;
$item = new Ox.VideoEditor({ video.url = video.baseUrl + '/' + video.height + 'p.' + ($.support.video.webm ? 'webm' : 'mp4');
cuts: cuts, $item = new Ox.VideoEditor({
duration: video.duration, cuts: cuts,
find: '', duration: video.duration,
frameURL: function(position) { find: '',
return '/' + id + '/frame/' + video.width.toString() + '/' + position.toString() + '.jpg' frameURL: function(position) {
}, return '/' + id + '/frame/' + video.width.toString() + '/' + position.toString() + '.jpg'
id: 'editor', },
largeTimeline: true, id: 'editor',
matches: [], largeTimeline: true,
points: [0, 0], matches: [],
position: 0, points: [0, 0],
posterFrame: parseInt(video.duration / 2), position: 0,
subtitles: subtitles, posterFrame: parseInt(video.duration / 2),
videoHeight: video.height, subtitles: subtitles,
videoId: id, videoHeight: video.height,
videoWidth: video.width, videoId: id,
videoSize: 'small', videoWidth: video.width,
videoURL: video.url, videoSize: 'small',
width: app.$document.width() - app.$ui.leftPanel.width() - 1 - 256 - 1 videoURL: video.url,
}); width: app.$document.width() - app.$ui.leftPanel.width() - 1 - 256 - 1
app.$ui.contentPanel.replace(1, $item); });
app.$ui.rightPanel app.$ui.contentPanel.replace(1, $item);
/*.unbindEvent('resize')*/ app.$ui.rightPanel
.bindEvent('resize', function(event, data) { /*.unbindEvent('resize')*/
Ox.print('seems to work', data) .bindEvent('resize', function(event, data) {
$item.options({ Ox.print('seems to work', data)
width: data - 256 - 1 $item.options({
}); width: data - 256 - 1
});
app.$window.resize(function() {
$item.options({
width: app.$document.width() - app.$ui.leftPanel.width() - 1 - 256 - 1
});
}); });
}); });
app.$window.resize(function() {
$item.options({
width: app.$document.width() - app.$ui.leftPanel.width() - 1 - 256 - 1
});
}); });
}); });
} }