refactor webvttfunctional

This commit is contained in:
dukeeagle 2022-12-31 15:09:34 -06:00
parent 1ce655be52
commit 4709d32be0
3 changed files with 130 additions and 313 deletions

View File

@ -1,5 +1,5 @@
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import WebVttPlayerFunctional from "./WebVttPlayer/WebVttPlayerFunctional"; import WebVttPlayer from "./WebVttPlayer/WebVttPlayer";
// functional component PlayerReact that uses ReactPlayer // functional component PlayerReact that uses ReactPlayer
// TODO: better parameterize video source and VTT source with props (general spec for 3rd party use!). must define spec. // TODO: better parameterize video source and VTT source with props (general spec for 3rd party use!). must define spec.
@ -17,7 +17,7 @@ export default function Player() {
<div id="control-panel" className="flex flex-row"> <div id="control-panel" className="flex flex-row">
<button id="show-metadata" className="bg-gray-200 hover:bg-gray-400 dark:bg-gray-800 dark:hover:bg-gray-700 text-gray-800 dark:text-gray-200 py-2 px-4">Show Metadata</button> <button id="show-metadata" className="bg-gray-200 hover:bg-gray-400 dark:bg-gray-800 dark:hover:bg-gray-700 text-gray-800 dark:text-gray-200 py-2 px-4">Show Metadata</button>
</div> </div>
<WebVttPlayerFunctional <WebVttPlayer
preload={false} preload={false}
audio={audioUrl} audio={audioUrl}
videoUrl={videoUrl} videoUrl={videoUrl}

View File

@ -1,183 +1,144 @@
import React, { Component } from 'react' import { useLayoutEffect, useState, useEffect, useRef } from 'react';
import dynamic from "next/dynamic";
// const ReactPlayer = dynamic(() => import("react-player/lazy"), { ssr: false });
import Transcript from './Transcript' import Transcript from './Transcript'
import Metadata from './Metadata' import Metadata from './Metadata'
import Search from './Search' import Search from './Search'
import './WebVttPlayer.module.css' const VideoPlayer = dynamic(() => import("../VideoPlayer"), { ssr: false });
import dynamic from "next/dynamic"; type WebVttPlayerProps = {
const ReactPlayer = dynamic(() => import("react-player/lazy"), { ssr: false }); audio: string,
videoUrl: string, // TODO: make naming scheme consistent lol
transcript: string,
metadataUrl: string,
preload: boolean,
};
// type for props interface ReactPlayerRef {
type WebVttProps = { seeking: boolean;
video: string, played: number;
transcript: string, duration: number;
metadata: string, seekTo: (time: number) => void;
preload: boolean
} }
interface NativePlayerRef {
interface VideoRef { currentTime: number;
seeking: boolean; ended: boolean;
played: number; loop: boolean;
duration: number; muted: boolean;
seekTo: (time: number) => void; play: () => void;
} }
class WebVttPlayer extends Component<WebVttProps, { loaded: boolean, currentTime: number, query: string, seeking: boolean, played: Float64Array, playing: boolean }> { export default function WebVttPlayer(props: WebVttPlayerProps) {
metatrack: React.RefObject<unknown> const [trackLoaded, setTrackLoaded] = useState(false);
video: React.RefObject<unknown> const [metatrackLoaded, setMetatrackLoaded] = useState(false);
audio: React.RefObject<unknown> const [query, setQuery] = useState('');
track: React.RefObject<unknown>
constructor(props: WebVttProps) { // TODO: determine if these should be set
super(props) const [currentTime, setCurrentTime] = useState(0);
this.state = { const [seeking, setSeeking] = useState(false);
loaded: false, const [played, setPlayed] = useState(new Float64Array(0));
currentTime: 0, const [playing, setPlaying] = useState(false);
query: '',
seeking: false, const trackRef = useRef(null);
played: new Float64Array(0), const metatrackRef = useRef(null);
playing: false,
const reactPlayerRef = useRef<ReactPlayerRef>(null);
const nativePlayerRef = useRef<NativePlayerRef>(null);
const preload = props.preload ? "true" : "false"
useLayoutEffect(() => {
// Get a reference to the track and metatrack elements
const track = trackRef.current;
const metatrack = metatrackRef.current;
// Check if the tracks are fully loaded
if (track && track.track && track.track.cues && track.track.cues.length > 0) {
setTrackLoaded(true);
}
if (metatrack && metatrack.track && metatrack.track.cues && metatrack.track.cues.length > 0) {
setMetatrackLoaded(true);
}
}, [trackLoaded, metatrackLoaded]);
// if we figure out how to get access to Track refs with react-player (even in YouTube videos! That would be awesome), then we can start using this
function reactPlayerSeek(secs: string) {
if (reactPlayerRef.current) {
reactPlayerRef.current.seekTo(parseFloat(secs))
}
setPlaying(true);
} }
this.track = React.createRef() function seek(secs: number) {
this.metatrack = React.createRef() if (nativePlayerRef.current) {
this.audio = React.createRef()
this.video = React.createRef();
// const playerRef=useRef();
this.onLoaded = this.onLoaded.bind(this) nativePlayerRef.current.currentTime = secs;
this.seek = this.seek.bind(this) nativePlayerRef.current.play();
this.checkIfLoaded = this.checkIfLoaded.bind(this) }
this.updateQuery = this.updateQuery.bind(this) setPlaying(true);
}
componentDidMount() {
this.checkIfLoaded()
}
handlePause = () => {
console.log('onPause')
this.setState({ playing: false })
}
render() {
let track = null
let metatrack = null
if (this.state.loaded) {
track = this.track.current.track
metatrack = this.metatrack.current.track
console.log("loaded video.current : ", this.video.current);
} }
const preload = this.props.preload ? "true" : "false"
const metadata = this.props.metadata
? <Metadata
url={this.props.metadata}
seek={this.seek}
track={metatrack} />
: ""
return ( return (
<div className="webvtt-player"> <>
<div className="media"> <div className="webvtt-player">
<div className="player"> <div className="media">
<div className="player">
<ReactPlayer {/* <VideoPlayer playerRef={video} playing={playing} videoUrl={props.videoUrl} transcriptUrl={props.transcript} /> */}
// a ref that works in our class component {/* a vanilla video element with source and tracks. so much easier oh my god */}
ref={this.video} <video
controls={true} preload={preload}
onPause={this.handlePause} ref={nativePlayerRef}
crossOrigin="anonymous" crossOrigin="anonymous"
className="react-player" controls={true}
url="https://youtu.be/TGKk3iwoI9I" >
onSeek={e => console.log('onSeek', e)} <source src={props.videoUrl} type="video/mp4" />
onProgress={this.handleProgress} <track
/> ref={trackRef}
<audio kind="subtitles"
controls src={props.transcript}
crossOrigin="anonymous" srcLang="en"
onLoad={this.onLoaded} default={true}
preload={preload} />
ref={this.audio}> <track default
<source src={this.props.audio} /> kind="metadata"
<track default src={props.metadataUrl}
kind="subtitles" ref={metatrackRef} />
src={this.props.transcript} </video>
ref={this.track} /> </div>
<track default <div className="tracks">
kind="metadata" {trackLoaded ? (
src={this.props.metadata} <>
ref={this.metatrack} /> <Transcript
</audio> url={props.transcript}
</div> seek={seek}
<div className="tracks"> track={trackRef.current.track}
<Transcript query={query}
url={this.props.transcript} />
seek={this.seek} </>
track={track} ) : (
query={this.state.query} /> "Loading transcript..."
{metadata} )}
</div> {metatrackLoaded && props.metadataUrl ? (
<Search query={this.state.query} updateQuery={this.updateQuery} /> <>
</div> <Metadata
</div> url={props.metadataUrl}
) seek={seek}
} track={metatrackRef.current.track}
/>
onLoaded() { </>
this.setState({ loaded: true }) ) : (
} "\nLoading metadata..." // TODO: make better logic for showing if we wanna serve metadata
)}
checkIfLoaded(tries = 0) { </div>
tries += 1 </div>
const e = this.track.current </div>
if (e && e.track && e.track.cues && e.track.cues.length > 0) { </>
this.onLoaded() );
} else if (!this.state.loaded) {
const wait = 25 * Math.pow(tries, 2)
setTimeout(this.checkIfLoaded, wait, tries)
}
}
// handleSeekMouseDown = e => {
// this.setState({ seeking: true })
// }
// handleSeekChange = e => {
// this.setState({ played: parseFloat(e.target.value) })
// }
// handleSeekMouseUp = e => {
// this.setState({ seeking: false })
// this.player.seekTo(parseFloat(e.target.value))
// }
handleProgress = state => {
console.log('onProgress', state)
// We only want to update time slider if we are not currently seeking
if (!this.state.seeking) {
this.setState(state)
}
}
// ORIGINAL
seek(secs: number) {
// scrub audio
this.audio.current.currentTime = secs
this.audio.current.play()
// scrub video
this.setState({ seeking: true })
console.log("this.video", this.video);
this.video.current?.seekTo(parseFloat(secs)) // TODO: should probs refactor ref to this.player
}
updateQuery(query: string) {
this.setState({ query: query })
}
} }
export default WebVttPlayer

View File

@ -1,144 +0,0 @@
import { useLayoutEffect, useState, useEffect, useRef } from 'react';
import dynamic from "next/dynamic";
// const ReactPlayer = dynamic(() => import("react-player/lazy"), { ssr: false });
import Transcript from './Transcript'
import Metadata from './Metadata'
import Search from './Search'
const VideoPlayer = dynamic(() => import("../VideoPlayer"), { ssr: false });
type WebVttPlayerFunctionalProps = {
audio: string,
videoUrl: string, // TODO: make naming scheme consistent lol
transcript: string,
metadataUrl: string,
preload: boolean,
};
interface ReactPlayerRef {
seeking: boolean;
played: number;
duration: number;
seekTo: (time: number) => void;
}
interface NativePlayerRef {
currentTime: number;
ended: boolean;
loop: boolean;
muted: boolean;
play: () => void;
}
export default function WebVttPlayerFunctional(props: WebVttPlayerFunctionalProps) {
const [trackLoaded, setTrackLoaded] = useState(false);
const [metatrackLoaded, setMetatrackLoaded] = useState(false);
const [query, setQuery] = useState('');
// TODO: determine if these should be set
const [currentTime, setCurrentTime] = useState(0);
const [seeking, setSeeking] = useState(false);
const [played, setPlayed] = useState(new Float64Array(0));
const [playing, setPlaying] = useState(false);
const trackRef = useRef(null);
const metatrackRef = useRef(null);
const reactPlayerRef = useRef<ReactPlayerRef>(null);
const nativePlayerRef = useRef<NativePlayerRef>(null);
const preload = props.preload ? "true" : "false"
useLayoutEffect(() => {
// Get a reference to the track and metatrack elements
const track = trackRef.current;
const metatrack = metatrackRef.current;
// Check if the tracks are fully loaded
if (track && track.track && track.track.cues && track.track.cues.length > 0) {
setTrackLoaded(true);
}
if (metatrack && metatrack.track && metatrack.track.cues && metatrack.track.cues.length > 0) {
setMetatrackLoaded(true);
}
}, [trackLoaded, metatrackLoaded]);
// if we figure out how to get access to Track refs with react-player (even in YouTube videos! That would be awesome), then we can start using this
function reactPlayerSeek(secs: string) {
if (reactPlayerRef.current) {
reactPlayerRef.current.seekTo(parseFloat(secs))
}
setPlaying(true);
}
function seek(secs: number) {
if (nativePlayerRef.current) {
nativePlayerRef.current.currentTime = secs;
nativePlayerRef.current.play();
}
setPlaying(true);
}
return (
<>
<div className="webvtt-player">
<div className="media">
<div className="player">
{/* <VideoPlayer playerRef={video} playing={playing} videoUrl={props.videoUrl} transcriptUrl={props.transcript} /> */}
{/* a vanilla video element with source and tracks. so much easier oh my god */}
<video
preload={preload}
ref={nativePlayerRef}
crossOrigin="anonymous"
controls={true}
>
<source src={props.videoUrl} type="video/mp4" />
<track
ref={trackRef}
kind="subtitles"
src={props.transcript}
srcLang="en"
default={true}
/>
<track default
kind="metadata"
src={props.metadataUrl}
ref={metatrackRef} />
</video>
</div>
<div className="tracks">
{trackLoaded ? (
<>
<Transcript
url={props.transcript}
seek={seek}
track={trackRef.current.track}
query={query}
/>
</>
) : (
"Loading transcript..."
)}
{metatrackLoaded && props.metadataUrl ? (
<>
<Metadata
url={props.metadataUrl}
seek={seek}
track={metatrackRef.current.track}
/>
</>
) : (
"\nLoading metadata..." // TODO: make better logic for showing if we wanna serve metadata
)}
</div>
</div>
</div>
</>
);
}