use new Ox.VideoElement, add inital player to edits and view as video results view

This commit is contained in:
j 2013-07-09 22:49:01 +00:00
parent 15be34955e
commit 9cd9611306
16 changed files with 218 additions and 80 deletions

View file

@ -78,7 +78,7 @@ class MetaClip:
for a in annotations] for a in annotations]
for key in keys: for key in keys:
if key not in self.clip_keys and key not in j: if key not in self.clip_keys and key not in j:
value = self.item.get(key) value = self.item.get(key) or self.item.json.get(key)
if not value and hasattr(self.item.sort, key): if not value and hasattr(self.item.sort, key):
value = getattr(self.item.sort, key) value = getattr(self.item.sort, key)
j[key] = value j[key] = value

View file

@ -678,7 +678,7 @@
//{"id": "maps", "title": "with Maps"}, //{"id": "maps", "title": "with Maps"},
//{"id": "calendars", "title": "with Calendars"}, //{"id": "calendars", "title": "with Calendars"},
{"id": "clip", "title": "as Clips"}, {"id": "clip", "title": "as Clips"},
//{"id": "video", "title": "as Video"}, {"id": "video", "title": "as Video"},
{"id": "map", "title": "on Map"}, {"id": "map", "title": "on Map"},
{"id": "calendar", "title": "on Calendar"} {"id": "calendar", "title": "on Calendar"}
], ],

View file

@ -691,6 +691,7 @@
{"id": "timelines", "title": "with Timelines"}, {"id": "timelines", "title": "with Timelines"},
{"id": "clips", "title": "with Clips"}, {"id": "clips", "title": "with Clips"},
{"id": "clip", "title": "as Clips"}, {"id": "clip", "title": "as Clips"},
{"id": "video", "title": "as Videos"},
{"id": "map", "title": "on Map"}, {"id": "map", "title": "on Map"},
{"id": "calendar", "title": "on Calendar"} {"id": "calendar", "title": "on Calendar"}
], ],

View file

@ -575,6 +575,7 @@
{"id": "timelines", "title": "with Timelines"}, {"id": "timelines", "title": "with Timelines"},
{"id": "clips", "title": "with Clips"}, {"id": "clips", "title": "with Clips"},
{"id": "clip", "title": "as Clips"}, {"id": "clip", "title": "as Clips"},
{"id": "video", "title": "as Video"},
{"id": "map", "title": "on Map"}, {"id": "map", "title": "on Map"},
{"id": "calendar", "title": "on Calendar"} {"id": "calendar", "title": "on Calendar"}
], ],

View file

@ -494,6 +494,7 @@
{"id": "timelines", "title": "with Timelines"}, {"id": "timelines", "title": "with Timelines"},
{"id": "clips", "title": "with Clips"}, {"id": "clips", "title": "with Clips"},
{"id": "clip", "title": "as Clips"}, {"id": "clip", "title": "as Clips"},
{"id": "video", "title": "as Video"},
{"id": "map", "title": "on Map"}, {"id": "map", "title": "on Map"},
{"id": "calendar", "title": "on Calendar"} {"id": "calendar", "title": "on Calendar"}
], ],

View file

@ -297,10 +297,14 @@ class Clip(models.Model):
data['annotation'] = self.annotation.public_id data['annotation'] = self.annotation.public_id
data['in'] = self.annotation.start data['in'] = self.annotation.start
data['out'] = self.annotation.end data['out'] = self.annotation.end
data['parts'] = self.annotation.item.json['parts']
data['durations'] = self.annotation.item.json['durations']
else: else:
data['item'] = self.item.itemId data['item'] = self.item.itemId
data['in'] = self.start data['in'] = self.start
data['out'] = self.end data['out'] = self.end
data['parts'] = self.item.json['parts']
data['durations'] = self.item.json['durations']
data['duration'] = data['out'] - data['in'] data['duration'] = data['out'] - data['in']
return data return data

View file

@ -31,6 +31,8 @@ pandora.ui.browser = function() {
pandora.$ui.map.resizeMap(); pandora.$ui.map.resizeMap();
} else if (pandora.user.ui.listView == 'calendar') { } else if (pandora.user.ui.listView == 'calendar') {
pandora.$ui.calendar.resizeCalendar(); pandora.$ui.calendar.resizeCalendar();
} else if (pandora.user.ui.listView == 'video') {
pandora.$ui.list.size();
} }
}, },
resizeend: function(data) { resizeend: function(data) {
@ -59,6 +61,8 @@ pandora.ui.browser = function() {
pandora.$ui.map.resizeMap(); pandora.$ui.map.resizeMap();
} else if (pandora.user.ui.listView == 'calendar') { } else if (pandora.user.ui.listView == 'calendar') {
pandora.$ui.calendar.resizeCalendar(); pandora.$ui.calendar.resizeCalendar();
} else if (pandora.user.ui.listView == 'video') {
pandora.$ui.list.size();
} }
} }
}); });

View file

@ -175,25 +175,23 @@ pandora.ui.clipList = function(videoRatio) {
} }
pandora.api.get({id: item, keys: ['durations', 'rightslevel']}, function(result) { pandora.api.get({id: item, keys: ['durations', 'rightslevel']}, function(result) {
var points = [that.value(id, 'in'), that.value(id, 'out')], var points = [that.value(id, 'in'), that.value(id, 'out')],
partsAndPoints = pandora.getVideoPartsAndPoints(
result.data.durations, points
),
$player = Ox.VideoPlayer({ $player = Ox.VideoPlayer({
censored: pandora.site.capabilities.canPlayClips[pandora.user.level] < result.data.rightslevel censored: pandora.site.capabilities.canPlayClips[pandora.user.level] < result.data.rightslevel
? [{'in': partsAndPoints.points[0], out: partsAndPoints.points[1]}] ? [{'in': 0, out: points[1] - points[0]}]
: [], : [],
censoredIcon: pandora.site.cantPlay.icon, censoredIcon: pandora.site.cantPlay.icon,
censoredTooltip: pandora.site.cantPlay.text, censoredTooltip: pandora.site.cantPlay.text,
height: height, height: height,
'in': partsAndPoints.points[0],
out: partsAndPoints.points[1],
paused: true, paused: true,
playInToOut: true,
poster: '/' + item + '/' + height + 'p' + points[0] + '.jpg', poster: '/' + item + '/' + height + 'p' + points[0] + '.jpg',
rewind: true, rewind: true,
video: partsAndPoints.parts.map(function(i) { video: pandora.getClipVideos({
return pandora.getVideoURL(item, Ox.min(pandora.site.video.resolutions), i + 1); item: item,
}), parts: result.data.durations.length,
durations: result.data.durations,
'in': points[0],
out: points[1]
}, Ox.min(pandora.site.video.resolutions)),
width: width width: width
}) })
.addClass('OxTarget') .addClass('OxTarget')

View file

@ -1,61 +0,0 @@
// vim: et:ts=4:sw=4:sts=4:ft=javascript
'use strict';
pandora.ui.clipPlayer = function() {
// FIXME: is clipPlayer the best name for this?
var that = Ox.VideoPlayer({
controlsBottom: ['play', 'previous', 'next', 'volume'],
controlsTop: ['fullscreen', 'scale'],
enableMouse: true,
height: 384,
paused: true,
position: 0,
video: function(range, callback) {
var callback = arguments[arguments.length - 1],
range = arguments.length == 2 ? arguments[0] : null,
itemsQuery = pandora.user.ui.find,
query = {conditions:[]};
//fixme: can this be in pandora.Query? dont just check for subtitles
itemsQuery.conditions.forEach(function(q) {
if (q.key == 'subtitles') {
query.conditions.push({key: 'subtitles', value: q.value, operator: q.operator});
}
});
pandora.api.findClips(Ox.extend({
query: query,
itemsQuery: itemsQuery
}, range ? {
keys: ['id', 'in', 'out', 'subtitles'],
range: range,
sort: pandora.user.ui.listSort
} : {}), function(result) {
//Ox.Log('', 'API findClips range', range, 'result', result.data);
if (!range) {
callback(result.data.items);
} else {
var counter = 0,
length = range[1] - range[0],
data = [];
result.data.items.forEach(function(item, i) {
var id = item.id.split('/')[0];
pandora.api.get({id: id, keys: ['durations']}, function(result) {
//Ox.Log('', 'API get item', id, 'result', result.data);
var points = [item['in'], item.out],
partsAndPoints = pandora.getVideoPartsAndPoints(result.data.durations, points);
data[i] = {
parts: partsAndPoints.parts.map(function(i) {
return pandora.getVideoURL(item, Ox.min(pandora.site.video.resolutions), i + 1);
}),
points: partsAndPoints.points
};
if (++counter == length) {
callback(data);
}
});
});
}
});
},
width: 512
});
return that;
};

View file

@ -22,6 +22,25 @@ pandora.ui.editPanel = function() {
$editMenu, $editMenu,
$viewSelect = Ox.Select({
items: [
{'id': 'list', 'title': Ox._('View as List')},
{'id': 'player', 'title': Ox._('View as Player')},
],
value: 'list',
width: 128
})
.css({
float: 'left',
margin: '4px 0 0 4px'
})
.bindEvent({
change: function(data) {
$panel.replaceElement(0, pandora.$ui.edit = pandora.ui[
data.value == 'player' ? 'editPlayer' : 'editList'
](edit));
},
}).appendTo($toolbar),
$statusbar = Ox.Bar({size: 16}), $statusbar = Ox.Bar({size: 16}),
@ -145,7 +164,7 @@ pandora.ui.editList = function(edit) {
edit: pandora.user.ui.edit edit: pandora.user.ui.edit
}, function(result) { }, function(result) {
Ox.Request.clearCache(); Ox.Request.clearCache();
pandora.$ui.rightPanel.reload() pandora.$ui.rightPanel.reload();
}); });
} }
}, },
@ -198,3 +217,35 @@ pandora.ui.editList = function(edit) {
return that; return that;
}; };
pandora.ui.editPlayer = function(edit) {
var that = Ox.Element()
.css({
'overflow-y': 'auto'
});
self.$player = Ox.VideoPlayer({
controlsBottom: ['play', 'previous', 'next', 'volume', 'position'],
controlsTop: ['fullscreen', 'scale'],
enableMouse: true,
height: getHeight(),
paused: true,
position: 0,
video: Ox.flatten(edit.clips.map(function(clip) {
return pandora.getClipVideos(clip);
})),
width: getWidth()
}).appendTo(that);
function getHeight() {
// 24 menu + 24 toolbar + 16 statusbar + 32 title + 32 margins
// + 1px to ge trid of scrollbar
return window.innerHeight - 128 -1;
}
function getWidth() {
return window.innerWidth
- pandora.user.ui.showSidebar * pandora.user.ui.sidebarSize - 1;
}
return that;
};

View file

@ -27,7 +27,7 @@ pandora.ui.embedPlayer = function() {
$title, $player, $controls, $timeline, $annotations; $title, $player, $controls, $timeline, $annotations;
pandora.api.get({id: ui.item, keys: [ pandora.api.get({id: ui.item, keys: [
'duration', 'layers', 'parts', 'posterFrame', 'duration', 'durations', 'layers', 'parts', 'posterFrame',
'rightslevel', 'size', 'title', 'videoRatio' 'rightslevel', 'size', 'title', 'videoRatio'
]}, function(result) { ]}, function(result) {

View file

@ -13,11 +13,11 @@ pandora.ui.item = function() {
pandora.api.get({ pandora.api.get({
id: pandora.user.ui.item, id: pandora.user.ui.item,
keys: isVideoView ? [ keys: isVideoView ? [
'cuts', 'director', 'duration', 'editable', 'layers', 'cuts', 'director', 'duration', 'durations', 'editable', 'layers',
'modified', 'parts', 'posterFrame', 'rendered', 'rightslevel', 'modified', 'parts', 'posterFrame', 'rendered', 'rightslevel',
'size', 'title', 'videoRatio', 'year' 'size', 'title', 'videoRatio', 'year'
] : pandora.user.ui.itemView == 'documents' ? [ ] : pandora.user.ui.itemView == 'documents' ? [
'director', 'documents', 'duration', 'editable', 'director', 'documents', 'duration', 'durations', 'editable',
'rightslevel', 'size', 'title', 'videoRatio', 'year' 'rightslevel', 'size', 'title', 'videoRatio', 'year'
] : [] ] : []
}, pandora.user.ui.itemView == 'info' && pandora.site.capabilities.canEditMetadata[pandora.user.level] ? 0 : -1, function(result) { }, pandora.user.ui.itemView == 'info' && pandora.site.capabilities.canEditMetadata[pandora.user.level] ? 0 : -1, function(result) {

View file

@ -377,7 +377,7 @@ pandora.ui.list = function() {
} else if (view == 'clip') { } else if (view == 'clip') {
that = pandora.$ui.clipList = pandora.ui.clipList(); that = pandora.$ui.clipList = pandora.ui.clipList();
} else if (view == 'video') { } else if (view == 'video') {
that = pandora.ui.clipPlayer(); that = pandora.ui.videoView();
} else if (['map', 'calendar'].indexOf(view) > -1) { } else if (['map', 'calendar'].indexOf(view) > -1) {
that = pandora.ui.navigationView(view); that = pandora.ui.navigationView(view);
} }

View file

@ -38,6 +38,8 @@ pandora.ui.rightPanel = function() {
pandora.$ui.map.resizeMap(); pandora.$ui.map.resizeMap();
} else if (pandora.user.ui.listView == 'calendar') { } else if (pandora.user.ui.listView == 'calendar') {
pandora.$ui.calendar.resizeCalendar(); pandora.$ui.calendar.resizeCalendar();
} else if (pandora.user.ui.listView == 'video') {
pandora.$ui.list.resize();
} }
} else { } else {
pandora.$ui.browser.scrollToSelection(); pandora.$ui.browser.scrollToSelection();
@ -53,6 +55,8 @@ pandora.ui.rightPanel = function() {
pandora.$ui.map.resizeMap(); pandora.$ui.map.resizeMap();
} else if (pandora.user.ui.listView == 'calendar') { } else if (pandora.user.ui.listView == 'calendar') {
pandora.$ui.calendar.resizeCalendar(); pandora.$ui.calendar.resizeCalendar();
} else if (pandora.user.ui.listView == 'video') {
pandora.$ui.list.size();
} }
} }
} }

View file

@ -584,6 +584,45 @@ pandora.getClipsQuery = function() {
return clipsQuery; return clipsQuery;
}; };
pandora.getClipVideos = function(clip, resolution) {
var currentTime = 0,
start = clip['in'] || 0,
end = clip.out;
resolution = resolution || pandora.user.ui.videoResolution;
return Ox.flatten(Ox.range(clip.parts).map(function(i) {
var item = {
src: pandora.getVideoURL(clip.item, resolution, i + 1)
};
if(currentTime + clip.durations[i] < start || currentTime > end) {
item = null;
} else {
if(currentTime <= start && currentTime + clip.durations[i] > start) {
item['in'] = start - currentTime;
}
if (currentTime + clip.durations[i] >= end) {
item.out = end - currentTime;
}
if (item['in'] && item.out) {
item.duration = item.out - item['in']
} else if (item.out) {
item.duration = item.out;
} else if (!Ox.isUndefined(item['in'])) {
item.duration = clip.durations[i] - item['in'];
item.out = clip.durations[i];
} else {
item.duration = clip.durations[i];
item['in'] = 0;
item.out = item.duration;
}
}
currentTime += clip.durations[i];
return item;
}).filter(function(c) {
return !!c;
}));
};
(function() { (function() {
var itemTitles = {}; var itemTitles = {};
pandora.getDocumentTitle = function(itemTitle) { pandora.getDocumentTitle = function(itemTitle) {
@ -1065,7 +1104,7 @@ pandora.getStatusText = function(data) {
var ui = pandora.user.ui, var ui = pandora.user.ui,
canSeeMedia = pandora.site.capabilities.canSeeMedia[pandora.user.level], canSeeMedia = pandora.site.capabilities.canSeeMedia[pandora.user.level],
canSeeSize = pandora.site.capabilities.canSeeSize[pandora.user.level], canSeeSize = pandora.site.capabilities.canSeeSize[pandora.user.level],
itemName = ui.listView == 'clip' itemName = ['clip', 'video'].indexOf(ui.listView) > -1
? (data.items == 1 ? Ox._('Clip') : Ox._('Clips')) ? (data.items == 1 ? Ox._('Clip') : Ox._('Clips'))
: (pandora.site.itemName[data.items == 1 ? 'singular' : 'plural']), : (pandora.site.itemName[data.items == 1 ? 'singular' : 'plural']),
parts = []; parts = [];
@ -1139,7 +1178,10 @@ pandora.getVideoOptions = function(data) {
options.video = {}; options.video = {};
pandora.site.video.resolutions.forEach(function(resolution) { pandora.site.video.resolutions.forEach(function(resolution) {
options.video[resolution] = Ox.range(data.parts).map(function(i) { options.video[resolution] = Ox.range(data.parts).map(function(i) {
return pandora.getVideoURL(data.item || pandora.user.ui.item, resolution, i + 1); return {
duration: data.durations[i],
src: pandora.getVideoURL(data.item || pandora.user.ui.item, resolution, i + 1)
};
}); });
}); });
options.annotations = []; options.annotations = [];

View file

@ -0,0 +1,93 @@
// vim: et:ts=4:sw=4:sts=4:ft=javascript
'use strict';
pandora.ui.videoView = function() {
var ui = pandora.user.ui,
itemsQuery,
query,
that = Ox.Element().css({
width: '100%',
hegiht: '100%',
}),
range = [0, 500],
clips = [],
player;
if (!ui.item) {
itemsQuery = ui.find;
query = {conditions: [], operator: '&'};
// if the item query contains a layer condition,
// then this condition is added to the clip query
itemsQuery.conditions.forEach(function(condition) {
if (
condition.key == 'annotations'
|| Ox.getIndexById(pandora.site.layers, condition.key) > -1
) {
query.conditions.push(condition);
}
});
} else {
itemsQuery = {
conditions:[{key: 'id', value: ui.item, operator: '=='}],
operator: '&'
};
query = {
conditions: ui.itemFind === '' ? [] : [{
key: 'annotations',
value: ui.itemFind,
operator: '='
}],
operator: '&'
};
}
loadPlayer();
function loadPlayer() {
pandora.api.findClips({
query: query,
itemsQuery: itemsQuery,
keys: ['id', 'in', 'out', 'durations', 'parts'],
range: range,
sort: pandora.user.ui.listSort
}, function(result) {
pandora.$ui.statusbar.set('total', {
items: result.data.items.length
});
player && player.remove();
player = Ox.VideoPlayer({
controlsBottom: ['play', 'previous', 'next', 'volume'],
controlsTop: ['fullscreen', 'scale'],
enableMouse: true,
height: getHeight(),
paused: true,
position: 0,
video: Ox.flatten(result.data.items.map(function(clip) {
clip.item = clip.id.split('/')[0];
var r = pandora.getClipVideos(clip);
console.log(clip, r);
return r;
})),
width: getWidth()
}).appendTo(that);
});
}
function getHeight() {
return that.height();
}
function getWidth() {
return that.width();
}
that.reloadList = function() {
loadPlayer();
};
that.size = function() {
player && player.options({
height: getHeight(),
width: getWidth(),
})
}
return that;
};