|
@@ -1,5 +1,16 @@
|
|
|
'use strict';
|
|
|
(() => {
|
|
|
+
|
|
|
+ function ShowFile(file, delay, latency) {
|
|
|
+ this.file = file;
|
|
|
+ this.delay = delay;
|
|
|
+ this.latency = latency;
|
|
|
+ }
|
|
|
+
|
|
|
+ ShowFile.prototype.Delay = function() {
|
|
|
+ return this.latency ? this.latency * (this.delay ? this.delay : 1) : this.delay;
|
|
|
+ }
|
|
|
+
|
|
|
function Show(parent, files, delay) {
|
|
|
this.index = 0;
|
|
|
this.elapsed = 0;
|
|
@@ -10,7 +21,7 @@
|
|
|
this.delay = !isNaN(delay) ? delay : 3000;
|
|
|
this.parent = parent;
|
|
|
this.parent.innerHTML = '';
|
|
|
- this.parent.appendChild(document.createElement('img'));
|
|
|
+ this.parent.appendChild(new Image());
|
|
|
(() => {
|
|
|
this.parse(files);
|
|
|
window.requestAnimationFrame(() => { this.render(); });
|
|
@@ -46,15 +57,68 @@
|
|
|
return f
|
|
|
};
|
|
|
|
|
|
+ Show.prototype.add = function(file, delay, latency) {
|
|
|
+ let o = new ShowFile(file, delay, latency);
|
|
|
+ // let o = {file: file, delay: delay, latency: latency};
|
|
|
+ this.list.push(o);
|
|
|
+ }
|
|
|
+
|
|
|
+ Show.prototype.parse = function(files) {
|
|
|
+ if (!(files instanceof Array)) return;
|
|
|
+ files.map((o) => {
|
|
|
+ if (typeof o === 'string') {
|
|
|
+ this.add(o);
|
|
|
+ } else if (o instanceof Object && !(o instanceof Array) && o !== null && typeof o.file !== 'undefined' && typeof o.file === 'string') {
|
|
|
+ if (typeof o.range !== 'undefined' && o.range instanceof Array) {
|
|
|
+ if (o.range.length === 2 && !(isNaN(o.range[2]) && isNaN(o.range[1])) && parseInt(o.range[0]) < parseInt(o.range[1])) {
|
|
|
+ for (let i = parseInt(o.range[0]); i <= parseInt(o.range[1]); i++) {
|
|
|
+ this.add(this.format(o.file, i), o.delay, o.latency);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ for (let i of o.range) {
|
|
|
+ this.add(this.format(o.file, i), o.delay, o.latency);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.add(o.file, o.delay, o.latency);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ Show.prototype.gifDuration = async (el, o) => {
|
|
|
+ try {
|
|
|
+ let response = await fetch(o.file);
|
|
|
+ let data = await response.blob();
|
|
|
+ let f = new FileReader();
|
|
|
+ f.readAsArrayBuffer(data);
|
|
|
+ f.onload = (event) => {
|
|
|
+ let arr = new Uint8Array(f.result);
|
|
|
+ let d = 0;
|
|
|
+ for (var i = 0; i < arr.length; i++) {
|
|
|
+ if (arr[i] == 0x21
|
|
|
+ && arr[i + 1] == 0xF9
|
|
|
+ && arr[i + 2] == 0x04
|
|
|
+ && arr[i + 7] == 0x00) {
|
|
|
+ const delay = (arr[i + 5] << 8) | (arr[i + 4] & 0xFF)
|
|
|
+ d += delay < 2 ? 10 : delay;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ o.latency = d*10;
|
|
|
+ }
|
|
|
+ } catch(e) {}
|
|
|
+ }
|
|
|
+
|
|
|
Show.prototype.generate = function(idx) {
|
|
|
let o = this.list[idx];
|
|
|
- let el;
|
|
|
+ let el = new Image();
|
|
|
if (o.file.endsWith('.mp4') || o.file.endsWith('.webm') || o.file.endsWith('.ogg')) {
|
|
|
el = document.createElement('video');
|
|
|
+ el.addEventListener('canplay', () => { o.latency = (isNaN(o.delay) ? 1 : o.delay) * Math.trunc(el.duration * 1000); }, {once: true});
|
|
|
el.muted = true;
|
|
|
el.loop = true;
|
|
|
- } else {
|
|
|
- el = document.createElement('img');
|
|
|
+ } else if (o.file.endsWith('.gif')) {
|
|
|
+ el.addEventListener('load', () => { this.gifDuration(el, o); }, {once: true});
|
|
|
}
|
|
|
el.src = o.file;
|
|
|
el.addEventListener('error', () => { this.list.splice(this.list.indexOf(o), 1); }, {once: true});
|
|
@@ -62,65 +126,35 @@
|
|
|
}
|
|
|
|
|
|
Show.prototype.preload = function() {
|
|
|
- let partial = Math.max(Math.trunc(.1 * this.list.length), 1);
|
|
|
+ let partial = Math.min(.4 * this.list.length << 0, 5);
|
|
|
let position = partial > this.index ? this.list.length - Math.abs(partial - this.index) : this.index - partial;
|
|
|
for (let i = 0; i <= partial*2; i++) {
|
|
|
let l = (position+i)%this.list.length;
|
|
|
let o = this.list[l];
|
|
|
if (!this.preloaded.hasOwnProperty(o.file)) {
|
|
|
this.preloaded[o.file] = this.generate(l);
|
|
|
- setTimeout(() => { delete this.preloaded[o.file]; }, 2*(o.delay ? o.delay : this.delay));
|
|
|
+ setTimeout(() => { delete this.preloaded[o.file]; }, partial*o.delay);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- Show.prototype.add = function(file, delay) {
|
|
|
- let o = {file: file, delay: delay};
|
|
|
- this.list.push(o);
|
|
|
- if (o.file.endsWith('.mp4') || o.file.endsWith('.webm') || o.file.endsWith('.ogg')) {
|
|
|
- let el = document.createElement('video');
|
|
|
- el.addEventListener('canplay', () => { o.delay = (isNaN(o.delay) ? 1 : o.delay) * Math.trunc(el.duration * 1000); }, {once: true});
|
|
|
- el.src = o.file;
|
|
|
- }
|
|
|
+ Show.prototype.resize = function() {
|
|
|
+ let el = this.parent.firstChild;
|
|
|
+ let vid = (el.tagName == 'VIDEO') ? 'video' : 'natural';
|
|
|
+ this.parent.firstChild.className = (el[vid+'Width'] / el[vid+'Height'] < this.parent.clientWidth / this.parent.clientHeight) ? 'fillheight' : 'fillwidth';
|
|
|
}
|
|
|
|
|
|
- Show.prototype.parse = function(files) {
|
|
|
- if (!(files instanceof Array)) return;
|
|
|
- files.map((o) => {
|
|
|
- if (typeof o === 'string') {
|
|
|
- this.add(o);
|
|
|
- } else if (o instanceof Object && !(o instanceof Array) && typeof o.file !== 'undefined' && typeof o.file === 'string') {
|
|
|
- if (o.file.indexOf('%') > -1 && typeof o.range !== 'undefined' && o.range instanceof Array) {
|
|
|
- if (o.range.length === 2 && !(isNaN(o.range[2]) && isNaN(o.range[1])) && parseInt(o.range[0]) < parseInt(o.range[1])) {
|
|
|
- for (let i = parseInt(o.range[0]); i <= parseInt(o.range[1]); i++) {
|
|
|
- this.add(this.format(o.file, i), o.delay);
|
|
|
- }
|
|
|
- } else {
|
|
|
- for (let i of o.range) {
|
|
|
- this.add(this.format(o.file, i), o.delay);
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- this.add(o.file, o.delay);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- };
|
|
|
-
|
|
|
Show.prototype.render = function() {
|
|
|
if (!this.list.length) return;
|
|
|
+ this.resize();
|
|
|
let d = Date.now();
|
|
|
- let el = this.parent.firstChild;
|
|
|
- let vid = (el.tagName == 'VIDEO') ? 'video' : 'natural';
|
|
|
- this.parent.firstChild.className = (el[vid+'Width'] / el[vid+'Height'] < this.parent.clientWidth / this.parent.clientHeight) ? 'fillheight' : 'fillwidth';
|
|
|
let o = this.list[this.index];
|
|
|
if (this.current != this.index) {
|
|
|
this.current = this.index;
|
|
|
this.preload();
|
|
|
let el = this.preloaded[o.file];
|
|
|
- let vid = (el.tagName == 'VIDEO') ? 'video' : 'natural';
|
|
|
if (el.tagName !== this.parent.firstChild.tagName) this.parent.replaceChild(el.cloneNode(), this.parent.firstChild);
|
|
|
- if (vid === 'video') {
|
|
|
+ if (el.tagName == 'VIDEO') {
|
|
|
if (this.parent.firstChild.src !== el.src) this.parent.firstChild.src = el.src;
|
|
|
this.parent.firstChild.currentTime = 0;
|
|
|
this.parent.firstChild.loop = true;
|
|
@@ -131,7 +165,7 @@
|
|
|
}
|
|
|
}
|
|
|
if (this.playing && document.hasFocus()) this.elapsed += (d - this.updated);
|
|
|
- if (this.elapsed >= (o.delay | this.delay)) this.next();
|
|
|
+ if (this.elapsed >= (o.Delay() | this.delay)) this.next();
|
|
|
s.updated = d;
|
|
|
window.requestAnimationFrame(() => { this.render(); });
|
|
|
}
|