phantasma/app/static/js/play.js
2021-11-22 09:47:48 +01:00

332 lines
10 KiB
JavaScript

var cache = cache || {}
var layer = 'keywords'
var imageResolution = 480
var videoExtension
async function pandoraAPI(action, data) {
var url = pandoraURL + '/api/'
//var url = '/pandoraAPI/'
var key = JSON.stringify([action, data])
if (!cache[key]) {
var response = await fetch(url, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
action: action,
data: data
})
})
cache[key] = await response.json()
}
return cache[key]
}
function setVideoSrc(video, src) {
var ext
if (!videoExtension) {
[
['video/mp4; codecs="avc1.42E01E, mp4a.40.2"', '.mp4'],
['video/webm; codecs="vp8, vorbis"', '.webm'],
].forEach(opt => {
if (videoExtension) { return }
if (video.canPlayType(opt[0]).replace('no', '')) {
videoExtension = opt[1]
}
})
}
src = src.replace('.webm', videoExtension)
if (src != video.src) {
video.src = src
}
}
function resize() {
var video = document.querySelector('video')
if (video && video._frame) {
var rect = video._frame.getBoundingClientRect();
video.style.top = (rect.top + window.scrollY) + 'px'
}
}
function updatePlayer(video, frame, currentTime, out, src) {
var rect = frame.getBoundingClientRect();
video.style.opacity = 0
video.style.top = (rect.top + window.scrollY) + 'px'
video.style.display = 'block';
if (src) {
setVideoSrc(video, src)
}
//video.poster = frame.querySelector('img').src
var muted = video.muted
// video.muted = true
video.currentTime = currentTime
video.dataset.in = currentTime
video.dataset.out = out
video._frame = frame
const show = event => {
video.style.opacity = 1
video.muted = muted
video.removeEventListener('seeked', show)
}
video.addEventListener('seeked', show)
video.play()
}
function isElementInViewport (el) {
var rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /* or $(window).height() */
Math.floor(rect.right) <= (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */
);
}
function onVisibilityChange(el, callback) {
var old_visible;
return function () {
var visible = isElementInViewport(el);
if (visible != old_visible) {
old_visible = visible;
if (visible) {
el.classList.add('visible')
} else {
el.classList.remove('visible')
}
if (typeof callback == 'function') {
callback(visible);
}
}
}
}
function scrollTo(element) {
var delta = element.offsetTop - document.scrollingElement.scrollTop,
duration = 1000, t = 40, n = duration / t,
step = delta / n;
function scroll() {
if (document.scrollingElement.scrollTop + step > element.offsetTop) {
document.scrollingElement.scrollTop = element.offsetTop
n = 0
} else {
document.scrollingElement.scrollTop += step
}
n--
if (n) setTimeout(scroll, t)
}
scroll()
}
function timeupdate(event) {
var video = event.target
var now = video.currentTime
document.querySelectorAll('#player .annotation').forEach(annotation => {
var display
if (
parseFloat(annotation.dataset['in']) < now && parseFloat(annotation.dataset['out']) > now
) {
display = 'block'
} else {
display = 'none'
}
if (annotation.style.display != display) {
annotation.style.display = display
}
})
if (event.target.dataset.out && event.target.dataset.in) {
var in_= parseFloat(event.target.dataset.in)
var out_= parseFloat(event.target.dataset.out)
if (event.target.currentTime >= out_) {
/*
var next
if (event.target._frame) {
next = event.target._frame.parentElement.nextSibling
if (next) {
next = next.querySelector('.frame')
}
}
if (next) {
scrollTo(next)
} else {
event.target.pause()
}
*/
if (config.pause) {
event.target.pause()
} else {
event.target.currentTime = in_
}
}
}
}
function formatInfo(config, player) {
var info = document.createElement('div')
info.classList.add('info')
var folder = document.createElement('a')
folder.href = '..'
folder.innerText = config.folder
var h1 = document.createElement('h1')
h1.appendChild(folder)
var title = document.createElement('span')
title.innerHTML = ': ' + config.title
h1.appendChild(title)
info.appendChild(h1)
player.appendChild(info)
return info
}
function renderAnnotation(config, video, player, annotation) {
var div = document.createElement('div')
div.classList.add('annotation')
annotation.value = annotation.value.replace(/src="\//g, `src="${pandoraURL}/`).replace(/href="\//g, `href="${pandoraURL}/`)
div.dataset['in'] = annotation['in']
div.dataset['out'] = annotation['out']
div.innerHTML = `
<div class="text">${annotation.value}</div>
`
player.appendChild(div)
}
function renderPlayer(config) {
var player = document.querySelector('#ascroll')
player.id = 'player'
config.loaded = false
var video = document.createElement('video')
video.classList.add('player')
video.playsinline = true
video.setAttribute('playsinline', 'playsinline')
video.setAttribute('webkit-playsinline', 'webkit-playsinline')
video.WebKitPlaysInline = true
video.muted = false
video.controls = true
if (config.item) {
setVideoSrc(video, `${pandoraURL}/${config.item}/480p.webm`)
video.poster = `${pandoraURL}/${config.item}/480p.jpg`
}
video.addEventListener('timeupdate', timeupdate)
var box = document.createElement('div')
box.classList.add('vbox')
box.appendChild(video)
config.info = formatInfo(config, player)
player.appendChild(box)
config.annotations.forEach(annotation => {
renderAnnotation(config, video, player, annotation)
})
config.loaded = true
}
async function loadClips(annotations) {
var items = annotations.map(annotation => annotation.id.split('/')[0])
items = [...new Set(items)]
return pandoraAPI('findClips', {itemsQuery: {
conditions: [{key: 'id', operator: '&', value: items}]
}, range: [0, 10000], keys: [
'id', 'hue', 'saturation', 'lightness'
]}).then(response => {
var colors = {}
response.data.items.forEach(clip => {
colors[clip.id] = clip
})
var previous
annotations.forEach(annotation => {
var clipId = annotation.id.split('/')[0] + '/' + annotation.in.toFixed(3) + '-'+ annotation.out.toFixed(3)
annotation.color1 = colors[clipId]
if(previous) {
previous.color2 = annotation.color1
}
previous = annotation
})
if (annotations.length) {
annotations[annotations.length - 1].color2 = annotations[0].color1
}
return annotations
})
}
function loadAnnotations(config) {
if (config.item) {
pandoraAPI('get', {id: config.item, keys: [
'title', 'date', 'country', 'featuring', 'layers', 'folder'
]}).then(response => {
['title', 'date', 'country', 'featuring', 'folder'].forEach(key => {
config[key] = response.data[key]
})
var annotations = []
Object.keys(response.data.layers).forEach(layer => {
response.data.layers[layer].forEach(annotation => {
if (!(config.user && annotation.user != config.user)) {
annotations.push(annotation)
}
})
})
loadClips(annotations).then(annotations => {
config.annotations = annotations.filter(annotation => {
if (config.only_e) {
if (annotation.value.slice(0, 2) == 'E:') {
annotation.value = annotation.value.slice(2).trim()
return true
} else {
return false
}
} else {
return annotation.value.slice(0, 2) != 'E:'
}
})
renderPlayer(config)
})
})
} else {
var cited = {}
pandoraAPI('getEdit', {id: config.edit, keys: []}).then(response => {
var annotations = []
response.data.clips.forEach(clip => {
cited[clip.item] = {
title: clip.title,
director: clip.director,
id: clip.item
}
clip.layers[config.layer].forEach(annotation => {
if (config.user && annotation.user != config.user) {
return
}
;['title', 'director', 'date'].forEach(key => {
annotation[key] = clip[key]
})
if (config.only_e) {
if (annotation.value.slice(0, 2) == 'E:') {
annotation.value = annotation.value.slice(2).trim()
annotations.push(annotation)
}
} else {
if (annotation.value.slice(0, 2) != 'E:') {
annotations.push(annotation)
}
}
})
})
loadClips(annotations).then(annotations => {
config.annotations = annotations
config.cited = Object.values(cited)
renderPlayer(config)
})
})
}
}
config.layer = config.layer || layer
if (config.annotations) {
renderPlayer(config)
} else {
loadAnnotations(config)
}
window.addEventListener('resize', resize, false);