pandora/static/js/uploadVideoDialog.js

603 lines
22 KiB
JavaScript
Raw Normal View History

2012-03-17 00:15:06 +00:00
// vim: et:ts=4:sw=4:sts=4:ft=javascript
'use strict';
2013-08-06 09:00:45 +00:00
pandora.ui.uploadVideoDialog = function(data) {
2012-06-18 10:53:11 +00:00
2012-06-18 11:06:24 +00:00
var cancelled = false,
2012-06-18 10:53:11 +00:00
file,
2015-04-26 14:55:39 +00:00
hasFirefogg = !(Ox.isUndefined(window.Firefogg)) && (
2015-04-19 09:09:12 +00:00
$.browser.version < '35' || Firefogg().version >= 334
),
infoContent = Ox._('Please select the video file that you want to upload.'),
2015-04-20 08:13:56 +00:00
itemView = pandora.site.capabilities.canSeeExtraItemViews[
pandora.user.level
] ? 'media' : 'info',
2012-03-17 00:15:06 +00:00
selectFile,
2012-06-18 11:06:24 +00:00
$actionButton,
$closeButton,
2012-06-18 10:53:11 +00:00
$content = Ox.Element().css({margin: '16px'}),
2015-04-19 09:09:12 +00:00
$info = $('<div>')
.css({padding: '4px'})
.html(infoContent),
2012-06-18 10:53:11 +00:00
$progress,
$status = $('<div>').css({padding: '4px', paddingTop: '8px'}),
2012-03-17 00:15:06 +00:00
that = Ox.Dialog({
buttons: [
2012-06-18 11:06:24 +00:00
$closeButton = Ox.Button({
2012-03-17 00:15:06 +00:00
id: 'close',
2013-05-09 10:13:58 +00:00
title: Ox._('Close')
}).css({
float: 'left'
2012-03-17 00:15:06 +00:00
}).bindEvent({
click: function() {
2013-05-09 10:13:58 +00:00
if ($closeButton.options('title') == Ox._('Cancel')) {
cancelled = true;
$info.html(infoContent);
$status.html('');
pandora.firefogg && pandora.firefogg.cancel();
pandora.$ui.upload && pandora.$ui.upload.abort();
2013-05-09 10:13:58 +00:00
$closeButton.options('title', Ox._('Close'));
if ($actionButton.options('title') == Ox._('Upload')) {
$closeButton.options('title', Ox._('Close'));
$actionButton.replaceWith($actionButton = hasFirefogg
? getFirefoggButton()
: getSelectVideoButton()
);
}
$actionButton.show();
} else {
that.triggerEvent('close');
}
2012-03-17 00:15:06 +00:00
}
}),
$actionButton = hasFirefogg ? getFirefoggButton() : getSelectVideoButton()
2012-03-17 00:15:06 +00:00
],
2012-06-18 10:53:11 +00:00
content: $content,
2012-03-17 00:15:06 +00:00
height: 128,
removeOnClose: true,
width: 368,
2013-05-09 10:13:58 +00:00
title: Ox._('Upload Video'),
2012-03-17 00:15:06 +00:00
})
.bindEvent({
close: function(data) {
if (pandora.firefogg) {
pandora.firefogg.cancel();
delete pandora.firefogg;
}
that.close();
}
2012-06-18 10:53:11 +00:00
});
2012-03-17 00:15:06 +00:00
2013-03-01 09:14:57 +00:00
if (!pandora.site.itemRequiresVideo && !pandora.user.ui.item) {
2013-05-09 10:13:58 +00:00
$info.html(Ox._(
'You can only upload a video to an existing {0}.'
+ ' Please check if an entry for the {0}'
2015-04-19 09:09:12 +00:00
+ ' you want to upload exists, and create one otherwise.',
2013-05-09 10:13:58 +00:00
[pandora.site.itemName.singular.toLowerCase()]
));
2013-03-01 09:14:57 +00:00
$actionButton.hide();
2012-03-17 00:15:06 +00:00
}
2012-06-18 10:53:11 +00:00
$content.append($info);
$content.append($status);
2012-03-17 00:15:06 +00:00
function aspectratio(ratio) {
2012-06-18 10:53:11 +00:00
var denominator, numerator;
2012-03-17 00:15:06 +00:00
ratio = ratio.split(':');
numerator = ratio[0];
2012-06-10 18:31:02 +00:00
if (ratio.length == 2) {
2012-03-17 00:15:06 +00:00
denominator = ratio[1];
}
2012-06-18 10:53:11 +00:00
if (Math.abs(numerator / denominator - 4/3) < 0.03) {
2012-03-17 00:15:06 +00:00
numerator = 4;
denominator = 3;
2012-06-18 10:53:11 +00:00
} else if (Math.abs(numerator / denominator - 16/9) < 0.02) {
2012-03-17 00:15:06 +00:00
numerator = 16;
denominator = 9;
}
return {
denominator: denominator,
2012-06-18 10:53:11 +00:00
'float': numerator / denominator,
numerator: numerator,
ratio: numerator + ':' + denominator
2012-03-17 00:15:06 +00:00
};
}
function resetProgress(status) {
2012-03-17 00:15:06 +00:00
$progress = Ox.Progressbar({
progress: 0,
showPercent: true,
showTime: true,
width: 304
});
$status.html(status || '').append($progress);
2012-03-17 00:15:06 +00:00
}
2012-06-18 10:53:11 +00:00
function directUpload(file, info) {
resetProgress();
pandora.api.addMedia({
filename: info.name,
id: info.oshash,
2015-04-20 08:13:56 +00:00
item: pandora.site.itemRequiresVideo
? undefined
: pandora.user.ui.item
}, function(result) {
uploadStream(result.data.item, info, file);
});
}
2012-03-17 00:15:06 +00:00
function encode() {
2012-06-18 10:53:11 +00:00
var filename = pandora.firefogg.sourceFilename,
info = JSON.parse(pandora.firefogg.sourceInfo),
item,
oshash = info.oshash;
2013-05-09 10:13:58 +00:00
$info.html('<b>' + filename + '</b><br>' + Ox._('encoding...'));
2012-03-17 00:15:06 +00:00
resetProgress();
pandora.api.addMedia({
2012-03-17 00:15:06 +00:00
filename: filename,
2012-06-18 10:53:11 +00:00
id: oshash,
2013-03-01 09:14:57 +00:00
info: info,
2015-04-20 08:13:56 +00:00
item: pandora.site.itemRequiresVideo
? undefined
: pandora.user.ui.item
2012-03-17 00:15:06 +00:00
}, function(result) {
item = result.data.item;
pandora.firefogg.encode(
getEncodingOptions(info),
function(result, file) {
result = JSON.parse(result);
if (result.progress != 1) {
2015-04-20 08:13:56 +00:00
$status.html(
cancelled
? Ox._('Encoding cancelled.')
: Ox._('Encoding failed.')
);
2012-03-17 00:15:06 +00:00
delete pandora.firefogg;
return;
}
setTimeout(function() {
2015-04-20 08:13:56 +00:00
$info.html(
'<b>' + filename + '</b><br>'
+ Ox._('uploading...')
);
uploadStream(item, info, file);
2012-03-17 00:15:06 +00:00
});
},
function(progress) {
progress = JSON.parse(progress).progress || 0;
$progress.options({progress: progress});
2012-03-17 00:15:06 +00:00
}
);
});
}
function getInfo(file, callback) {
Ox.oshash(file, function(oshash) {
var $video = $('<video>'),
url = URL.createObjectURL(file),
info = {
audio: [],
direct: false,
oshash: oshash,
name: file.name,
size: file.size,
video: []
};
$video.one('error', function(event) {
callback(info);
});
$video.one('loadedmetadata', function(event) {
info.duration = $video[0].duration;
if ($video[0].videoHeight > 0) {
info.video.push({
height: $video[0].videoHeight,
width: $video[0].videoWidth
});
}
if (info.duration) {
info.bitrate = info.size * 8 / info.duration / 1000;
}
var format = pandora.site.video.formats[0],
resolution = getResolution(info);
info.direct = Ox.endsWith(info.name, format)
&& info.video.length > 0
&& info.video[0].height <= resolution;
callback(info);
});
$video[0].src = url;
});
}
function getResolution(info) {
var height = info.video && info.video.length
? info.video[0].height
: Ox.max(pandora.site.video.resolutions),
2015-05-15 11:45:04 +00:00
resolution = Ox.sort(pandora.site.video.resolutions)
.filter(function(resolution) {
return height <= resolution;
})[0] || Ox.max(pandora.site.video.resolutions);
return resolution;
}
function getFirefoggButton() {
return Ox.Button({
id: 'action',
title: Ox._('Select Video')
}).bindEvent({
click: function() {
if ($actionButton.options('title') == Ox._('Select Video')) {
if (selectVideo()) {
$closeButton.options('title', Ox._('Cancel'));
$actionButton.options('title', Ox._('Upload'));
}
} else if ($actionButton.options('title') == Ox._('Cancel')) {
cancelled = true;
pandora.firefogg && pandora.firefogg.cancel();
pandora.$ui.upload && pandora.$ui.upload.abort();
$actionButton.options('title', Ox._('Select Video'));
$closeButton.show();
} else {
$closeButton.options('title', Ox._('Cancel'));
$actionButton.hide().options('title', Ox._('Select Video'));
encode();
}
}
})
}
2015-04-26 14:55:39 +00:00
function getSelectVideoButton() {
return Ox.FileButton({
id: 'action',
title: Ox._('Select Video'),
maxFiles: 1,
width: 96
}).css({
float: 'left'
}).bindEvent({
click: function(data) {
if (data.files.length) {
cancelled = false;
$actionButton.replaceWith($actionButton = Ox.Button({
id: 'action',
title: 'Upload',
disabled: true
}).css({
float: 'left'
}));
getInfo(data.files[0], function(info) {
$actionButton.options({
disabled: false
}).bindEvent({
click: function() {
$actionButton.replaceWith($actionButton = getSelectVideoButton().hide());
info.direct
? directUpload(data.files[0], info)
: upload(data.files[0]);
}
});
$info.html(formatVideoInfo(info));
$status.html(
info.direct
? Ox._(
'Your video will be used directly.'
2015-04-26 14:55:39 +00:00
)
: Ox._(
'Your video will be transcoded on the server.'
2015-04-26 14:55:39 +00:00
)
);
});
$closeButton.options('title', Ox._('Cancel'));
}
}
});
}
function uploadStream(item, info, file) {
var oshash = info.oshash,
format = pandora.site.video.formats[0],
resolution = getResolution(info);
pandora.$ui.upload = pandora.chunkupload({
file: file,
2015-04-20 08:13:56 +00:00
url: '/api/upload/?profile=' + resolution + 'p.'
+ format + '&id=' + oshash,
data: {}
}).bindEvent({
done: function(data) {
if (data.progress == 1) {
Ox.Request.clearCache();
2015-04-20 08:13:56 +00:00
if (
pandora.user.ui.item == item
&& pandora.user.ui.itemView == itemView
) {
pandora.$ui.item.reload();
} else {
pandora.UI.set({
item: item,
itemView: itemView
});
}
delete pandora.firefogg;
that.close();
} else {
2013-12-27 10:41:32 +00:00
$status.html(Ox._('Upload failed.'));
2014-12-16 13:44:42 +00:00
pandora.api.logError({
text: data.responseText,
url: '/' + item,
line: 1
});
}
},
progress: function(data) {
$progress.options({progress: data.progress || 0});
},
});
}
function upload(file) {
resetProgress();
2013-05-09 10:13:58 +00:00
$info.html(Ox._('Uploading {0}', [file.name]));
Ox.oshash(file, function(oshash) {
pandora.api.findMedia({
query: {
conditions: [{key: 'oshash', value: oshash}]
},
keys: ['id', 'item', 'available']
}, function(result) {
if (
result.data.items.length === 0
|| !result.data.items[0].available
) {
pandora.api.addMedia({
filename: file.name,
id: oshash,
2015-04-20 08:13:56 +00:00
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();
2015-04-20 08:13:56 +00:00
if (
pandora.user.ui.item == item
&& pandora.user.ui.itemView == itemView
) {
pandora.$ui.item.reload();
} else {
pandora.UI.set({
item: item,
itemView: itemView
});
}
that.close();
} else {
2015-04-20 08:13:56 +00:00
$status.html(
cancelled
? Ox._('Upload cancelled.')
: Ox._('Upload failed.')
);
2014-12-16 13:44:42 +00:00
!cancelled && pandora.api.logError({
text: data.responseText,
url: '/' + item,
line: 1
});
}
},
progress: function(data) {
2015-04-20 08:13:56 +00:00
$progress.options({
progress: data.progress || 0
});
}
});
});
} else {
pandora.UI.set({
item: result.data.items[0].item,
itemView: itemView
});
that.close();
}
});
});
}
2012-03-17 00:15:06 +00:00
function getEncodingOptions(info) {
2012-06-18 10:53:11 +00:00
var bpp = 0.17,
2012-03-17 00:15:06 +00:00
dar,
2012-06-18 10:53:11 +00:00
format = pandora.site.video.formats[0],
fps,
options = {},
resolution = getResolution(info);
2012-06-10 18:31:02 +00:00
if (format == 'webm') {
2012-03-17 00:15:06 +00:00
options.videoCodec = 'vp8';
options.audioCodec = 'vorbis';
} else if (format == 'ogv') {
options.videoCodec = 'theora';
options.audioCodec = 'vorbis';
}
if (resolution == 720) {
options.height = 720;
options.samplerate = 48000;
options.audioQuality = 5;
} else if (resolution == 480) {
options.height = 480;
options.samplerate = 44100;
options.audioQuality = 3;
options.channels = 2;
2012-04-19 16:14:43 +00:00
} else if (resolution == 432) {
options.height = 432;
options.samplerate = 44100;
options.audioQuality = 3;
options.channels = 2;
2012-03-17 00:15:06 +00:00
} else if (resolution == 360) {
options.height = 320;
options.samplerate = 44100;
options.audioQuality = 1;
options.channels = 1;
2012-04-19 16:14:43 +00:00
} else if (resolution == 288) {
options.height = 288;
options.samplerate = 44100;
options.audioQuality = 0;
options.channels = 1;
2012-03-17 00:15:06 +00:00
} else if (resolution == 240) {
options.height = 240;
options.samplerate = 44100;
options.audioQuality = 0;
options.channels = 1;
2012-04-19 16:14:43 +00:00
} else if (resolution == 144) {
options.height = 144;
options.samplerate = 22050;
options.audioQuality = -1;
options.audioBitrate = 22;
options.channels = 1;
2012-03-17 00:15:06 +00:00
} else if (resolution == 96) {
options.height = 96;
options.samplerate = 22050;
options.audioQuality = -1;
options.audioBitrate = 22;
options.channels = 1;
}
if (info.video && info.video.length) {
info.video.forEach(function(video) {
if (!video.display_aspect_ratio) {
video.display_aspect_ratio = video.width + ':' + video.height;
video.pixel_aspect_ratio = '1:1';
}
});
2012-03-17 00:15:06 +00:00
dar = aspectratio(info.video[0].display_aspect_ratio);
fps = aspectratio(info.video[0].framerate).float;
options.width = parseInt(dar.float * options.height, 10);
options.width += options.width % 2;
2012-06-18 10:53:11 +00:00
// interlaced hdv material is detected with double framerates
2012-03-17 00:15:06 +00:00
if (fps == 50) {
fps = options.framerate = 25;
2012-03-17 00:15:06 +00:00
} else if (fps == 60) {
fps = options.framerate = 30;
2012-03-17 00:15:06 +00:00
}
if (Math.abs(options.width/options.height - dar.float) < 0.02) {
options.aspect = options.width + ':' + options.height;
} else {
options.aspect = dar.ratio;
}
2012-06-18 10:53:11 +00:00
options.videoBitrate = Math.round(
options.height * options.width * fps * bpp / 1000
);
2012-03-17 00:15:06 +00:00
options.denoise = true;
options.deinterlace = true;
} else {
options.noVideo = true;
}
if (info.audio) {
if (options.cannels && info.audio[0].channels < options.channels) {
delete options.channels;
}
} else {
options.noAudio = true;
delete options.samplerate;
delete options.audioQuality;
delete options.channels;
}
options.noUpscaling = true;
2012-06-10 18:31:02 +00:00
if (
(!info.video.length || (
info.video[0].codec == options.videoCodec
&& info.video[0].height <= options.height
))
&& (!info.audio.length || info.audio[0].codec == options.audioCodec)
) {
options = {passthrough: true};
2012-03-17 00:15:06 +00:00
}
return JSON.stringify(options);
}
function formatInfo(info) {
2012-06-18 10:53:11 +00:00
var html = '<b>' + info.path + '</b><br>';
2012-06-10 18:31:02 +00:00
if (info.video && info.video.length > 0) {
2012-03-17 00:15:06 +00:00
var video = info.video[0];
2012-06-18 10:53:11 +00:00
html += video.width + '×' + video.height + ' (' + video.codec + ')';
2012-03-17 00:15:06 +00:00
}
2012-06-10 18:31:02 +00:00
if (
info.video && info.video.length > 0
&& info.audio && info.audio.length > 0
) {
2012-03-17 00:15:06 +00:00
html += ' / ';
}
2012-06-10 18:31:02 +00:00
if (info.audio && info.audio.length > 0) {
2012-06-18 10:53:11 +00:00
var audio = info.audio[0];
html += {1: 'mono', 2: 'stereo', 6: '5.1'}[audio.channels]
+ ' ' + audio.samplerate / 1000 + ' kHz (' + audio.codec + ')';
2012-03-17 00:15:06 +00:00
}
2012-06-18 10:53:11 +00:00
html += '<br>' + Ox.formatValue(info.size, 'B')
+ ' / ' + Ox.formatDuration(info.duration);
2012-03-17 00:15:06 +00:00
return html;
}
function formatVideoInfo(info) {
var html = '<b>' + info.name + '</b><br>';
if (info.video && info.video.length > 0) {
html += info.video[0].width + '×' + info.video[0].height;
}
html += '<br>' + Ox.formatValue(info.size, 'B');
if(info.duration) {
html += ' / ' + Ox.formatDuration(info.duration);
}
return html;
}
2012-03-17 00:15:06 +00:00
function selectVideo() {
2012-06-10 18:31:02 +00:00
cancelled = false;
2012-03-17 00:15:06 +00:00
pandora.firefogg = new Firefogg();
pandora.firefogg.setFormat(pandora.site.video.formats[0]);
2012-06-10 18:31:02 +00:00
if (pandora.firefogg.selectVideo()) {
2012-03-17 00:15:06 +00:00
var info = JSON.parse(pandora.firefogg.sourceInfo),
options = JSON.parse(getEncodingOptions(info)),
oshash = info.oshash,
filename = pandora.firefogg.sourceFilename,
item;
pandora.api.findMedia({
2012-03-17 00:15:06 +00:00
query: {
conditions: [{key: 'oshash', value: oshash}]
},
keys: ['id', 'available']
}, function(result) {
2012-06-10 18:31:02 +00:00
if (
2012-06-18 10:53:11 +00:00
result.data.items.length === 0
|| !result.data.items[0].available
2012-06-10 18:31:02 +00:00
) {
2012-03-17 00:15:06 +00:00
$info.html(formatInfo(info));
$status.html(
options.passthrough
2013-05-09 10:13:58 +00:00
? Ox._('Your video will be uploaded directly.')
: Ox._('Your video will be transcoded before upload.')
2012-06-18 10:53:11 +00:00
);
2012-03-17 00:15:06 +00:00
} else {
pandora.api.find({
query: {
conditions: [{key: 'oshash', value: oshash}]
},
keys: ['id']
}, function(result) {
pandora.UI.set({
item: result.data.items[0].id,
itemView: itemView
2012-03-17 00:15:06 +00:00
});
delete pandora.firefogg;
that.close();
});
}
});
return true;
}
return false;
}
return that;
2012-06-18 10:53:11 +00:00
2012-03-17 00:15:06 +00:00
};