From 14ae8ef1d5d0d306a37b9f6bec0b7e9e86b712e6 Mon Sep 17 00:00:00 2001 From: j Date: Mon, 22 Nov 2021 09:47:48 +0100 Subject: [PATCH] player --- app/static/css/partials/_player.scss | 40 +++++ app/static/css/style.scss | 1 + app/static/js/play.js | 215 +++++++-------------------- 3 files changed, 96 insertions(+), 160 deletions(-) create mode 100644 app/static/css/partials/_player.scss diff --git a/app/static/css/partials/_player.scss b/app/static/css/partials/_player.scss new file mode 100644 index 0000000..b2af648 --- /dev/null +++ b/app/static/css/partials/_player.scss @@ -0,0 +1,40 @@ +#player { + font-family: "noto_sans"; + width: 100%; + color: #ddd; + + h1 { + padding-left: var(--spacing-2); + padding-right: var(--spacing-2); + padding-top: 32px; + font-size: 20px; + letter-spacing: 1px; + font-weight: bold; + max-width: var(--container-width); + margin: auto; + } + h2 { + padding: 4px var(--spacing-2); + max-width: var(--container-width); + margin: auto; + } + .info { + margin-bottom: 16px; + } + .vbox { + max-width: var(--container-width); + margin: auto; + text-align: center; + } + .player { + width: 100%; + height: auto; + max-width: var(--container-width); + max-height: 80vh; + margin: auto; + } + .annotation { + display: none; + text-align: center; + } +} diff --git a/app/static/css/style.scss b/app/static/css/style.scss index 09be792..2daecc0 100755 --- a/app/static/css/style.scss +++ b/app/static/css/style.scss @@ -7,5 +7,6 @@ @import "partials/film"; @import "partials/text"; @import "partials/ascroll"; +@import "partials/player"; @import "partials/about"; @import "partials/contact"; diff --git a/app/static/js/play.js b/app/static/js/play.js index ab9e34a..0721748 100644 --- a/app/static/js/play.js +++ b/app/static/js/play.js @@ -119,6 +119,21 @@ function scrollTo(element) { } 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) @@ -146,120 +161,41 @@ function timeupdate(event) { } } -function formatInfo(config, ascroll) { +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.innerHTML = config.title + h1.appendChild(folder) + var title = document.createElement('span') + title.innerHTML = ': ' + config.title + h1.appendChild(title) info.appendChild(h1) - var h2 = document.createElement('h2') - h2.innerHTML = config.byline - info.appendChild(h2) - var div = document.createElement('div') - div.classList.add('intro') - div.innerHTML = config.body - info.appendChild(div) - ascroll.appendChild(info) + + player.appendChild(info) return info } -function showOverlay(event) { - event.stopPropagation() - event.preventDefault() - document.querySelectorAll('#video-overlay').forEach(element => element.remove()) - var video = event.target - var rect = video.getBoundingClientRect(); - var overlay = document.createElement('div') - overlay.id = 'video-overlay' - overlay.style.top = video.style.top - overlay.style.width = rect.width + 'px' - overlay.style.height = rect.height + 'px' - overlay.style.position = 'absolute' - overlay.style.display = 'flex' - overlay.style.alignItems = 'center' - overlay.style.justifyContent = 'center' - //overlay.style.fontSize = '45px' - video.controls = false - var off = `` - var on = `` - - if (video.muted) { - overlay.innerHTML = off - } else { - overlay.innerHTML = on - } - overlay.addEventListener('click', event=> { - video.muted = !video.muted - if (video.muted) { - overlay.innerHTML = off - } else { - overlay.innerHTML = on - } - }) - var timeout = setTimeout(() => { - video.controls = false - overlay.remove() - }, 3000) - overlay.addEventListener('mousemove', event=> { - clearTimeout(timeout) - timeout = setTimeout(() => { - video.controls = false - overlay.remove() - }, 500) - }) - video.parentElement.appendChild(overlay) - -} - -function renderAnnotation(config, video, ascroll, annotation) { +function renderAnnotation(config, video, player, annotation) { var div = document.createElement('div') div.classList.add('annotation') - var color1 = `hsl(${annotation.color1.hue}, 70%, 75%)` - var color2 = `hsl(${annotation.color2.hue}, 70%, 75%)` - if (!config.first) { - config.first = annotation - config.info.style.background = color1 - } - div.style.background = `linear-gradient(to bottom, ${color1}, ${color2})`; - var figcaption = '' - if (annotation.title) { - if (config.language == 'zh') { - var title = annotation.title.split('/')[1] || annotation.title - var director = annotation.director[1] - } else { - var title = annotation.title.split('/')[0] - var director = annotation.director[0] - } - var txt = `${title} (${director})` - figcaption = `
${txt}
` - } 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 = ` -
-
- - ${figcaption} -
-
${annotation.value}
` - ascroll.appendChild(div) - var frame = div.querySelector('.frame') - document.addEventListener('scroll', onVisibilityChange(div.querySelector('.frame'), function(visible) { - var src - if (config.edit) { - src = `${pandoraURL}/${annotation.id.split('/')[0]}/480p.webm` - } - if (config.loaded && visible) { - updatePlayer(video, frame, annotation['in'], annotation['out'], src) - } - - })) + player.appendChild(div) } -function renderAnnotations(config) { - var ascroll = document.querySelector('#ascroll') +function renderPlayer(config) { + var player = document.querySelector('#ascroll') + player.id = 'player' + config.loaded = false var video = document.createElement('video') video.classList.add('player') @@ -267,73 +203,24 @@ function renderAnnotations(config) { video.setAttribute('playsinline', 'playsinline') video.setAttribute('webkit-playsinline', 'webkit-playsinline') video.WebKitPlaysInline = true - video.muted = 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) - video.addEventListener('touchstart', showOverlay) - video.addEventListener('mouseover', showOverlay) var box = document.createElement('div') box.classList.add('vbox') box.appendChild(video) - ascroll.appendChild(box) + config.info = formatInfo(config, player) + player.appendChild(box) + - config.info = formatInfo(config, ascroll) config.annotations.forEach(annotation => { - renderAnnotation(config, video, ascroll, annotation) + renderAnnotation(config, video, player, annotation) }) config.loaded = true - if (config.first) { - let frame = ascroll.querySelector('.annotation .frame') - if (frame) { - var src - if (config.edit) { - src = `${pandoraURL}/${config.first.id.split('/')[0]}/480p.webm` - } - updatePlayer(video, frame, config.first['in'], config.first['out'], src) - } - } - if (config.item_url || config.cited) { - var box = document.createElement('div') - var color = config.annotations[config.annotations.length - 1].color2 - box.style.background = `hsl(${color.hue}, 70%, 75%)` - var div = document.createElement('div') - div.classList.add('related-film') - if (config.item_url) { - if (config.language == 'zh') { - div.innerHTML = ` - 引用影片: ${config.item_title_zh} (${config.item_director[1]}) - ` - } else { - div.innerHTML = ` - Film cited: ${config.item_title} (${config.item_director[0]})
- ` - } - } else { - var html = [] - config.cited.forEach(film => { - var title_en = film.title.split(' / ')[0] - var title_zh = film.title.split(' / ')[1] || title_en - if (config.language == 'en') { - var director = film.director ? ` (${film.director[0]})` : '' - html.push(`${title_en}${director}`) - } else { - var director = film.director ? ` (${film.director[1]})` : '' - html.push(`${title_zh}${director}`) - } - }) - var films = html.length == 1 ? 'Film' : 'Films' - html= html.join(', ') - if (config.language == 'zh') { - div.innerHTML = ` 引用影片: ${html}` - } else { - div.innerHTML = `${films} cited: ${html}` - } - } - box.appendChild(div) - ascroll.appendChild(box) - } } async function loadClips(annotations) { @@ -367,10 +254,18 @@ async function loadClips(annotations) { function loadAnnotations(config) { if (config.item) { pandoraAPI('get', {id: config.item, keys: [ - 'layers' + 'title', 'date', 'country', 'featuring', 'layers', 'folder' ]}).then(response => { - var annotations = response.data.layers[config.layer].filter(annotation => { - return !(config.user && annotation.user != config.user) + ['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 => { @@ -385,7 +280,7 @@ function loadAnnotations(config) { return annotation.value.slice(0, 2) != 'E:' } }) - renderAnnotations(config) + renderPlayer(config) }) }) } else { @@ -420,7 +315,7 @@ function loadAnnotations(config) { loadClips(annotations).then(annotations => { config.annotations = annotations config.cited = Object.values(cited) - renderAnnotations(config) + renderPlayer(config) }) }) } @@ -429,7 +324,7 @@ function loadAnnotations(config) { config.layer = config.layer || layer if (config.annotations) { - renderAnnotations(config) + renderPlayer(config) } else { loadAnnotations(config) }