aboutsummaryrefslogtreecommitdiff
path: root/pages/present.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'pages/present.tsx')
-rw-r--r--pages/present.tsx127
1 files changed, 93 insertions, 34 deletions
diff --git a/pages/present.tsx b/pages/present.tsx
index 97f48ac..3150784 100644
--- a/pages/present.tsx
+++ b/pages/present.tsx
@@ -1,5 +1,8 @@
import Button from '@material-ui/core/Button';
import { useEffect, useState } from 'react';
+import { timeline } from '../timeline';
+import * as timelineSchema from '../timeline.schema.json';
+import Ajv from 'ajv';
import ExitToAppRoundedIcon from '@material-ui/icons/ExitToAppRounded';
import PlayArrowRoundedIcon from '@material-ui/icons/PlayArrowRounded';
@@ -9,12 +12,71 @@ import SettingsRoundedIcon from '@material-ui/icons/SettingsRounded';
import CodeRoundedIcon from '@material-ui/icons/CodeRounded';
import MovieRoundedIcon from '@material-ui/icons/MovieRounded';
-function previous() {
- console.log('previous slide');
-}
+class TimedVideoPlayer {
+ slide: number;
+ timeline: timeline;
+ precision: number;
+ player: HTMLVideoElement;
+ video: string;
+
+ constructor(public framerate: number) {
+ this.slide = 0;
+ this.precision = 3;
+ }
+
+ timestampToFrame(timestamp: number): number {
+ return Math.round((timestamp * 1e3) / (1e3 / this.framerate));
+ }
+
+ frameToTimestamp(frame: number): number {
+ return frame / this.framerate;
+ }
+
+ registerPlayer(player: HTMLVideoElement) {
+ this.player = player;
+ if (this.video) this.player.src = this.video;
+ this.registerEventListeners();
+ }
+
+ registerEventListeners() {
+ if(!this.video ||
+ !this.player ||
+ !this.timeline ) return;
+ console.log('we\'re good to go!');
+ }
+
+ loadVideo(base64Video: string) {
+ this.video = base64Video;
+ if (this.player) this.player.src = this.video;
+ this.registerEventListeners();
+ }
+
+ loadSlides(jsonString: string) {
+ try {
+ var timeline = JSON.parse(jsonString);
+ } catch (e) {
+ console.log("invalid json object!" + e);
+ return;
+ }
+ var ajv = new Ajv({ allErrors: true });
+ var validate = ajv.compile(timelineSchema);
+ if (!validate(timeline)) {
+ console.log("schema not passed!")
+ return;
+ }
+
+ this.timeline = timeline;
-function next() {
- console.log('next slide');
+ this.registerEventListeners();
+ }
+
+ next() {
+ console.log('next slide');
+ }
+
+ previous() {
+ console.log('previous slide');
+ }
}
export default function Present() {
@@ -24,42 +86,39 @@ export default function Present() {
}, 500);
}, []);
- var [videoSRC, setVideoSRC] = useState('');
- var [slides, setSlides] = useState();
-
- var precision = 3;
- var framerate = 60;
+ var player = new TimedVideoPlayer(60);
useEffect(() => {
var videoEL = document.getElementById('player') as HTMLVideoElement;
- videoEL.addEventListener('loadeddata', () => {
- console.log('initial load');
- });
- videoEL.addEventListener('canplaythrough', () => {
- videoEL.play();
- });
+ player.registerPlayer(videoEL);
+ /* videoEL.addEventListener('loadeddata', () => { */
+ /* console.log('initial load'); */
+ /* }); */
+ /* videoEL.addEventListener('canplaythrough', () => { */
+ /* console.log('full load') */
+ /* }); */
- setInterval(() => {
- if (videoEL.paused) return;
- var frame = Math.round((videoEL.currentTime * 1e3) / (1e3 / framerate));
- document.getElementById('frame').innerText = frame.toString();
- if (frame >= framerate) {
- videoEL.pause();
- console.log(videoEL.currentTime);
- }
- }, 1e3 / (precision * framerate));
+ /* setInterval(() => { */
+ /* if (videoEL.paused) return; */
+ /* var frame = TimedVideoPlayer.timestampToFrame(videoEL.currentTime, framerate); */
+ /* document.getElementById('frame').innerText = frame.toString(); */
+ /* if (frame >= framerate) { */
+ /* videoEL.pause(); */
+ /* console.log(videoEL.currentTime); */
+ /* } */
+ /* }, 1e3 / (precision * framerate)); */
}, []);
return <div className='presentation posfix a0 h100vh'>
<div className='slideWrapper abscenterv posrel'>
<div className='slide posrel'>
<div className='innner posabs a0'>
- <video src={videoSRC} id='player' className='fullwidth' />
+ <video id='player' className='fullwidth' />
</div>
</div>
</div>
<div className='fullscreenControls posabs a0'>
- <div className='control previous' onClick={previous}>
+ <div className='control previous' onClick={player.previous}>
<span id='frame'>0</span>
</div>
<div
@@ -68,7 +127,7 @@ export default function Present() {
document.getElementById('menu').classList.add('active');
}}
/>
- <div className='control next' onClick={next} />
+ <div className='control next' onClick={player.next} />
</div>
<div className='menu posabs a0' id='menu'>
<div
@@ -119,7 +178,7 @@ export default function Present() {
});
reader.addEventListener('load', ev => {
console.log('reader done!');
- setVideoSRC(ev.target.result as string);
+ player.loadVideo(ev.target.result as string);
});
reader.addEventListener('progress', (progEv) => {
console.log(progEv.loaded);
@@ -146,7 +205,7 @@ export default function Present() {
});
reader.addEventListener('load', ev => {
console.log('reader done!');
- setSlides(JSON.parse(ev.target.result as string));
+ player.loadSlides(ev.target.result as string);
});
reader.addEventListener('progress', (progEv) => {
console.log(progEv.loaded);
@@ -154,20 +213,20 @@ export default function Present() {
reader.readAsText(file);
}}
/>
- {!videoSRC && <Button
+ <Button
variant='contained'
color='default'
children='Load video'
startIcon={<MovieRoundedIcon />}
onClick={() => document.getElementById('vidUpload').click()}
- />}
- {!slides && <Button
+ />
+ <Button
variant='contained'
color='default'
children='Load json'
startIcon={<CodeRoundedIcon />}
onClick={() => document.getElementById('jsonUpload').click()}
- />}
+ />
{false && <Button
variant='contained'
color='default'