From b047c0e9c9c221daacdb9f3354e558c76f062967 Mon Sep 17 00:00:00 2001
From: j <0x006A@0x2620.org>
Date: Tue, 26 Mar 2013 14:11:19 +0000
Subject: [PATCH] Add UI to support video upload without Firefogg, fixes #1351;
split encoding/upload into two 100% progress steps, fixes #1453
---
static/js/pandora/filesView.js | 6 +-
static/js/pandora/importAnnotations.js | 10 +-
static/js/pandora/upload.js | 180 -----------------------
static/js/pandora/uploadDialog.js | 194 +++++++++++++++----------
4 files changed, 127 insertions(+), 263 deletions(-)
delete mode 100644 static/js/pandora/upload.js
diff --git a/static/js/pandora/filesView.js b/static/js/pandora/filesView.js
index 86a8590f..a6d33166 100644
--- a/static/js/pandora/filesView.js
+++ b/static/js/pandora/filesView.js
@@ -76,7 +76,7 @@ pandora.ui.filesView = function(options, self) {
columns: [
{
clickable: function(data) {
- return true;
+ return !data.encoding;
},
format: function(value, data) {
return $('')
@@ -99,7 +99,9 @@ pandora.ui.filesView = function(options, self) {
title: 'Status',
titleImage: 'check',
tooltip: function (data) {
- return data.instances.filter(function(i) {return i.ignore; }).length > 0
+ return data.encoding
+ ? 'Processing video on server'
+ : data.instances.filter(function(i) {return i.ignore; }).length > 0
? 'Use this file'
: 'Dont use this file';
},
diff --git a/static/js/pandora/importAnnotations.js b/static/js/pandora/importAnnotations.js
index 599b6b1a..2fde7ab7 100644
--- a/static/js/pandora/importAnnotations.js
+++ b/static/js/pandora/importAnnotations.js
@@ -14,7 +14,7 @@ pandora.ui.importAnnotations = function(data) {
importButton,
selectLayer,
selectFile,
- that = pandora.ui.iconDialog({
+ that = Ox.Dialog({
buttons: [
Ox.Button({
id: 'close',
@@ -36,11 +36,13 @@ pandora.ui.importAnnotations = function(data) {
})
],
closeButton: true,
- text: content,
+ content: content,
keys: {
'escape': 'close'
},
+ height: 128,
removeOnClose: true,
+ width: 368,
title: 'Import Annotations'
})
.bindEvent({
@@ -77,7 +79,9 @@ pandora.ui.importAnnotations = function(data) {
layer: layer
}, function(result) {
if (result.data.taskId) {
- setStatus('Waiting for server to import annotations...');
+ $status.html('').append(Ox.LoadingScreen({
+ text: 'Importing ' + srt.length + ' annotations...'
+ }));
pandora.wait(result.data.taskId, function(result) {
if(result.data.status == 'SUCCESS') {
setStatus(annotations.length + ' annotations imported.');
diff --git a/static/js/pandora/upload.js b/static/js/pandora/upload.js
deleted file mode 100644
index bd76d554..00000000
--- a/static/js/pandora/upload.js
+++ /dev/null
@@ -1,180 +0,0 @@
-// vi:si:et:sw=4:sts=4:ts=4
-'use strict';
-
-pandora.ui.upload = function(oshash, file) {
- var self = {},
- chunkSize = 1024*1024,
- chunkUrl,
- format = pandora.site.video.formats[0],
- maxRetry = -1,
- resolution = Ox.max(pandora.site.video.resolutions),
- retries = 0,
- that = Ox.Element(),
- uploadData = {},
- uploadUrl = '/api/upload/?profile='+resolution+'p.'+format+'&id=' + oshash;
-
- initUpload();
-
- function done() {
- that.triggerEvent('done', {
- status: that.status,
- progress: that.progress,
- responseText: that.responseText
- });
- }
-
- function initUpload() {
- //request upload slot from server
- that.status = 'requesting chunk upload';
- that.progress = 0;
- self.req = new XMLHttpRequest();
- self.req.addEventListener('load', function (evt) {
- var response = {};
- that.responseText = evt.target.responseText;
- try {
- response = JSON.parse(evt.target.responseText);
- } catch(e) {
- response = {};
- that.status = 'failed to parse response';
- that.progress = -1;
- done();
- }
- if (response.status && response.status.code != 200) {
- that.status = response.status.text;
- that.progress = -1;
- done();
- response = {};
- }
- if (response.maxRetry) {
- maxRetry = response.maxRetry;
- }
- chunkUrl = response.uploadUrl;
- if (chunkUrl) {
- if (document.location.protocol == 'https:') {
- chunkUrl = chunkUrl.replace(/http:\/\//, 'https://');
- }
- that.status = 'uploading';
- that.progress = 0.0;
- //start upload
- uploadChunk(0);
- } else {
- that.status = 'upload failed, no upload url provided';
- that.progress = -1;
- done();
- }
- }, false);
- self.req.addEventListener('error', function (evt) {
- that.status = 'uplaod failed';
- that.progress = -1;
- that.responseText = evt.target.responseText;
- done();
- }, false);
- self.req.addEventListener('abort', function (evt) {
- that.status = 'aborted';
- that.progress = -1;
- done();
- }, false);
- var formData = new FormData();
- Ox.forEach(uploadData, function(value, key) {
- formData.append(key, value);
- });
- self.req.open('POST', uploadUrl);
- self.req.send(formData);
- }
-
- function progress(p) {
- that.progress = p;
- that.triggerEvent('progress', {
- progress: that.progress
- });
- }
-
- function uploadChunk(chunkId) {
- var bytesAvailable = file.size,
- chunk,
- chunkOffset = chunkId * chunkSize;
-
- if (file.mozSlice) {
- chunk = file.mozSlice(chunkOffset, chunkOffset+chunkSize, file.type);
- } else if (file.webkitSlice) {
- chunk = file.webkitSlice(chunkOffset, chunkOffset+chunkSize, file.type);
- }
-
- progress(parseFloat(chunkOffset)/bytesAvailable);
-
- self.req = new XMLHttpRequest();
- self.req.addEventListener('load', function (evt) {
- var response;
- that.responseText = evt.target.responseText;
- try {
- response = JSON.parse(evt.target.responseText);
- } catch(e) {
- response = {};
- }
- if (response.done == 1) {
- //upload finished
- that.resultUrl = response.resultUrl;
- that.progress = 1;
- that.status = 'done';
- done();
- } else if (response.result == 1) {
- //reset retry counter
- retries = 0;
- //start uploading next chunk
- uploadChunk(chunkId + 1);
- } else {
- //failed to upload, try again in 5 second
- retries++;
- if (maxRetry > 0 && retries > maxRetry) {
- that.status = 'uplaod failed';
- that.progress = -1;
- done();
- } else {
- setTimeout(function() {
- uploadChunk(chunkId);
- }, 5000);
- }
- }
- }, false);
- self.req.addEventListener('error', function (evt) {
- //failed to upload, try again in 3 second
- retries++;
- if (maxRetry > 0 && retries > maxRetry) {
- that.status = 'uplaod failed';
- that.progress = -1;
- done();
- } else {
- setTimeout(function() {
- uploadChunk(chunkId);
- }, 3000);
- }
- }, false);
- self.req.upload.addEventListener('progress', function (evt) {
- if (evt.lengthComputable) {
- progress(parseFloat(chunkOffset + evt.loaded) / bytesAvailable);
- }
- }, false);
- self.req.addEventListener('abort', function (evt) {
- that.status = 'aborted';
- that.progress = -1;
- done();
- }, false);
-
- var formData = new FormData();
- formData.append('chunkId', chunkId);
- if (bytesAvailable <= chunkOffset + chunkSize) {
- formData.append('done', 1);
- }
- formData.append('chunk', chunk);
- self.req.open('POST', chunkUrl, true);
- self.req.send(formData);
- }
-
- that.abort = function() {
- if (self.req) {
- self.req.abort();
- self.req = null;
- }
- };
- return that;
-};
diff --git a/static/js/pandora/uploadDialog.js b/static/js/pandora/uploadDialog.js
index 9d5e7c64..33f89fcf 100644
--- a/static/js/pandora/uploadDialog.js
+++ b/static/js/pandora/uploadDialog.js
@@ -5,6 +5,7 @@ pandora.ui.uploadDialog = function(data) {
var cancelled = false,
file,
+ hasFirefogg = !(typeof Firefogg == 'undefined'),
selectFile,
$actionButton,
$closeButton,
@@ -18,12 +19,22 @@ pandora.ui.uploadDialog = function(data) {
$closeButton = Ox.Button({
id: 'close',
title: 'Close'
+ }).css({
+ float: 'left'
}).bindEvent({
click: function() {
- that.triggerEvent('close');
+ if ($closeButton.options('title') == 'Cancel') {
+ cancelled = true;
+ pandora.firefogg && pandora.firefogg.cancel();
+ pandora.$ui.upload && pandora.$ui.upload.abort();
+ $closeButton.options('title', 'Close');
+ $actionButton.show();
+ } else {
+ that.triggerEvent('close');
+ }
}
}),
- $actionButton = Ox.Button({
+ $actionButton = hasFirefogg ? Ox.Button({
id: 'action',
title: 'Select Video'
}).bindEvent({
@@ -39,11 +50,24 @@ pandora.ui.uploadDialog = function(data) {
$actionButton.options('title', 'Select Video');
$closeButton.show();
} else {
- $actionButton.options('title', 'Cancel');
- $closeButton.hide();
+ $closeButton.options('title', 'Cancel');
+ $actionButton.hide().options('title', 'Select Video');
encode();
}
}
+ }) : Ox.FileButton({
+ id: 'action',
+ title: 'Select Video',
+ maxFiles: 1,
+ width: 96
+ }).bindEvent({
+ click: function(data) {
+ if(data.files.length) {
+ $actionButton.hide();
+ $closeButton.options('title', 'Cancel');
+ upload(data.files[0]);
+ }
+ }
})
],
content: $content,
@@ -62,9 +86,6 @@ pandora.ui.uploadDialog = function(data) {
}
});
- // FIXME: is this necessary?
- pandora._status = $status;
- pandora._info = $info;
if (!pandora.site.itemRequiresVideo && !pandora.user.ui.item) {
$info.html(
'You can only upload a video to an existing '
@@ -74,44 +95,6 @@ pandora.ui.uploadDialog = function(data) {
+ ' you want to upload exists and create otherwise.'
);
$actionButton.hide();
- } else if (typeof Firefogg == 'undefined') {
- /*
- selectFile = $('')
- .attr({
- type: 'file'
- })
- .css({
- padding: '8px'
- })
- .on({
- change: function(event) {
- if (this.files.length) {
- file = this.files[0];
- if (file.type == 'video/webm') {
- $status.html('');
- uploadButton.options({
- disabled: false
- });
- } else {
- $status.html('Currently only WebM files are supported. (Help encoding video)');
- }
- } else {
- uploadButton.options({
- disabled: true
- });
- }
- }
- })
- .appendTo($content);
- */
- $info.html(
- 'Currently, video upload is only supported in '
- + 'Firefox, with '
- + 'Firefogg installed.
'
- + 'Alternatively, you can use '
- + 'pandora_client.'
- );
- $actionButton.hide();
}
$content.append($info);
$content.append($status);
@@ -138,14 +121,14 @@ pandora.ui.uploadDialog = function(data) {
};
}
- function resetProgress() {
+ function resetProgress(status) {
$progress = Ox.Progressbar({
progress: 0,
showPercent: true,
showTime: true,
width: 304
});
- $status.html('').append($progress);
+ $status.html(status || '').append($progress);
}
function encode() {
@@ -153,6 +136,7 @@ pandora.ui.uploadDialog = function(data) {
info = JSON.parse(pandora.firefogg.sourceInfo),
item,
oshash = info.oshash;
+ $info.html('' + filename + '
encoding...');
resetProgress();
pandora.api.addMedia({
filename: filename,
@@ -171,46 +155,100 @@ pandora.ui.uploadDialog = function(data) {
return;
}
setTimeout(function() {
- //$status.html('uploading... ');
- pandora.$ui.upload = pandora.ui.upload(oshash, file)
- .bindEvent({
- progress: function(data) {
- var progress = data.progress || 0;
- $progress.options({progress: 0.5 + progress / 2});
- },
- done: function(data) {
- if (data.progress == 1) {
- Ox.Request.clearCache();
- if (pandora.user.ui.item == item && pandora.user.ui.itemView == 'files') {
- pandora.$ui.item.reload();
- } else {
- pandora.UI.set({
- item: item,
- itemView: 'files'
- });
- }
- delete pandora.firefogg;
- that.close();
- } else {
- $status.html('Upload Failed.');
- pandora.api.log({
- text: data.responseText,
- url: '/' + item,
- line: 1
- });
- }
- }
- });
+ $info.html('' + filename + '
uploading...');
+ uploadStream(item, oshash, file);
});
},
function(progress) {
progress = JSON.parse(progress).progress || 0;
- $progress.options({progress: progress / 2});
+ $progress.options({progress: progress});
}
);
});
}
+ function uploadStream(item, oshash, file) {
+ var format = pandora.site.video.formats[0],
+ resolution = Ox.max(pandora.site.video.resolutions);
+ pandora.$ui.upload = pandora.chunkupload({
+ file: file,
+ url: '/api/upload/?profile=' + resolution + 'p.' + format + '&id=' + oshash,
+ data: {}
+ }).bindEvent({
+ done: function(data) {
+ if (data.progress == 1) {
+ Ox.Request.clearCache();
+ if (pandora.user.ui.item == item && pandora.user.ui.itemView == 'files') {
+ pandora.$ui.item.reload();
+ } else {
+ pandora.UI.set({
+ item: item,
+ itemView: 'files'
+ });
+ }
+ delete pandora.firefogg;
+ that.close();
+ } else {
+ $status.html('Upload Failed.');
+ pandora.api.log({
+ text: data.responseText,
+ url: '/' + item,
+ line: 1
+ });
+ }
+ },
+ progress: function(data) {
+ $progress.options({progress: data.progress || 0});
+ },
+ });
+ }
+
+ function upload(file) {
+ resetProgress();
+ $info.html('Uploading ' + file.name);
+ Ox.oshash(file, function(oshash) {
+ pandora.api.addMedia({
+ filename: file.name,
+ id: oshash,
+ item: pandora.site.itemRequiresVideo ? undefined : pandora.user.ui.item
+ }, function(result) {
+ var item = result.data.item;
+ pandora.$ui.upload = pandora.chunkupload({
+ file: file,
+ url: '/api/upload/direct/',
+ data: {
+ id: oshash
+ }
+ }).bindEvent({
+ done: function(data) {
+ if (data.progress == 1) {
+ Ox.Request.clearCache();
+ if (pandora.user.ui.item == item && pandora.user.ui.itemView == 'files') {
+ pandora.$ui.item.reload();
+ } else {
+ pandora.UI.set({
+ item: item,
+ itemView: 'files'
+ });
+ }
+ that.close();
+ } else {
+ $status.html(cancelled ? 'Upload cancelled.' : 'Upload failed.');
+ !cancelled && pandora.api.log({
+ text: data.responseText,
+ url: '/' + item,
+ line: 1
+ });
+ }
+ },
+ progress: function(data) {
+ $progress.options({progress: data.progress || 0});
+ }
+ });
+ });
+ });
+ }
+
function getEncodingOptions(info) {
var bpp = 0.17,
dar,