Remove HTML video element

This commit is contained in:
Rob Watson 2021-09-30 16:12:40 +02:00
parent 0cdc728587
commit b08165d7f1
4 changed files with 21 additions and 64 deletions

View File

@ -47,8 +47,8 @@ func getThumbnails(c echo.Context) error {
return c.File(mediaSet.ThumbnailPath()) return c.File(mediaSet.ThumbnailPath())
} }
// getVideo is a handler that responds with the video file for a MediaSet // getAudio is a handler that responds with the audio file for a MediaSet
func getVideo(c echo.Context) error { func getAudio(c echo.Context) error {
videoID := c.Param("id") videoID := c.Param("id")
mediaSet := media.NewMediaSet(videoID) mediaSet := media.NewMediaSet(videoID)
if err := mediaSet.Load(); err != nil { if err := mediaSet.Load(); err != nil {
@ -56,7 +56,7 @@ func getVideo(c echo.Context) error {
return echo.NewHTTPError(http.StatusInternalServerError, "could not load media set") return echo.NewHTTPError(http.StatusInternalServerError, "could not load media set")
} }
return c.File(mediaSet.VideoPath()) return c.File(mediaSet.EncodedAudioPath())
} }
// getPeaks is a handler that returns a two-dimensional array of peaks, with // getPeaks is a handler that returns a two-dimensional array of peaks, with

View File

@ -24,7 +24,7 @@ func Start(opts Options) error {
e.GET("/api/media_sets/:id", getMediaSet) e.GET("/api/media_sets/:id", getMediaSet)
e.GET("/api/media_sets/:id/thumbnails", getThumbnails) e.GET("/api/media_sets/:id/thumbnails", getThumbnails)
e.GET("/api/media_sets/:id/video", getVideo) e.GET("/api/media_sets/:id/audio", getAudio)
e.GET("/api/media_sets/:id/peaks", getPeaks) e.GET("/api/media_sets/:id/peaks", getPeaks)
return e.Start(opts.BindAddr) return e.Start(opts.BindAddr)

View File

@ -87,7 +87,7 @@ func (d *Downloader) Download(ctx context.Context, videoID string) (*media.Media
}() }()
go func() { go func() {
defer close(videoResultChan) defer close(videoResultChan)
video, videoErr := d.downloadVideo(ctx, video, mediaSet.VideoPath(), mediaSet.ThumbnailPath()) video, videoErr := d.downloadVideo(ctx, video, mediaSet.ThumbnailPath())
result := videoResult{video, videoErr} result := videoResult{video, videoErr}
videoResultChan <- result videoResultChan <- result
wg.Done() wg.Done()
@ -197,7 +197,7 @@ func thumbnailGridSize(msecs int) (int, int) {
return x, x return x, x
} }
func (d *Downloader) downloadVideo(ctx context.Context, video *youtubev2.Video, outPath, thumbnailOutPath string) (*media.Video, error) { func (d *Downloader) downloadVideo(ctx context.Context, video *youtubev2.Video, thumbnailOutPath string) (*media.Video, error) {
if len(video.Formats) == 0 { if len(video.Formats) == 0 {
return nil, errors.New("error selecting audio format: no format available") return nil, errors.New("error selecting audio format: no format available")
} }
@ -209,12 +209,6 @@ func (d *Downloader) downloadVideo(ctx context.Context, video *youtubev2.Video,
return nil, fmt.Errorf("error fetching video stream: %v", err) return nil, fmt.Errorf("error fetching video stream: %v", err)
} }
videoFile, err := os.Create(outPath)
if err != nil {
return nil, fmt.Errorf("error creating video file: %v", err)
}
streamReader := io.TeeReader(stream, videoFile)
durationMsecs, err := strconv.Atoi(format.ApproxDurationMs) durationMsecs, err := strconv.Atoi(format.ApproxDurationMs)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not parse video duration: %s", err) return nil, fmt.Errorf("could not parse video duration: %s", err)
@ -235,7 +229,7 @@ func (d *Downloader) downloadVideo(ctx context.Context, video *youtubev2.Video,
"0", "0",
thumbnailOutPath, thumbnailOutPath,
) )
cmd.Stdin = streamReader cmd.Stdin = stream
cmd.Stderr = &errOut cmd.Stderr = &errOut
if err = cmd.Run(); err != nil { if err = cmd.Run(); err != nil {

View File

@ -56,7 +56,6 @@ export const Waveform: React.FC<Props> = ({ audioContext }: Props) => {
const [waveformPeaks, setWaveformPeaks] = useState(null); const [waveformPeaks, setWaveformPeaks] = useState(null);
const [overviewPeaks, setOverviewPeaks] = useState(null); const [overviewPeaks, setOverviewPeaks] = useState(null);
const hudCanvasRef = useRef<HTMLCanvasElement>(null); const hudCanvasRef = useRef<HTMLCanvasElement>(null);
const videoRef = useRef<HTMLVideoElement>(null);
// TODO: error handling // TODO: error handling
const videoID = new URLSearchParams(window.location.search).get('video_id'); const videoID = new URLSearchParams(window.location.search).get('video_id');
@ -85,16 +84,11 @@ export const Waveform: React.FC<Props> = ({ audioContext }: Props) => {
// setup player on page load: // setup player on page load:
useEffect(() => { useEffect(() => {
(async function () { (async function () {
const video = videoRef.current; audio.addEventListener('timeupdate', () => {
if (video == null) { setCurrentTime(audio.currentTime);
return;
}
video.addEventListener('timeupdate', () => {
setCurrentTime(video.currentTime);
}); });
})(); })();
}); }, []);
// fetch mediaset on page load: // fetch mediaset on page load:
useEffect(() => { useEffect(() => {
@ -139,16 +133,10 @@ export const Waveform: React.FC<Props> = ({ audioContext }: Props) => {
return; return;
} }
const video = videoRef.current; const url = `http://localhost:8888/api/media_sets/${videoID}/audio`;
if (video == null) { audio.src = url;
return; audio.muted = false;
} audio.volume = 1;
const url = `http://localhost:8888/api/media_sets/${videoID}/video`;
video.src = url;
video.muted = false;
video.volume = 1;
video.controls = true;
}, [mediaSet]); }, [mediaSet]);
// fetch new waveform peaks when zoom settings are updated: // fetch new waveform peaks when zoom settings are updated:
@ -238,20 +226,11 @@ export const Waveform: React.FC<Props> = ({ audioContext }: Props) => {
}; };
const handlePlay = async () => { const handlePlay = async () => {
const video = videoRef.current; await audio.play();
if (video == null) {
return;
}
await video.play();
}; };
const handlePause = () => { const handlePause = () => {
const video = videoRef.current; audio.pause();
if (video == null) {
return;
}
video.pause();
}; };
const handleZoomIn = () => { const handleZoomIn = () => {
@ -281,14 +260,9 @@ export const Waveform: React.FC<Props> = ({ audioContext }: Props) => {
}; };
const handleSelectionStart = (x: number) => { const handleSelectionStart = (x: number) => {
const video = videoRef.current;
if (video == null) {
return;
}
const frame = canvasXToFrame(x, mediaSet.audio.frames); const frame = canvasXToFrame(x, mediaSet.audio.frames);
if (video.paused) { if (audio.paused) {
video.currentTime = frame / mediaSet.audio.sampleRate; audio.currentTime = frame / mediaSet.audio.sampleRate;
} }
}; };
@ -304,18 +278,14 @@ export const Waveform: React.FC<Props> = ({ audioContext }: Props) => {
}; };
setZoomSettings(settings); setZoomSettings(settings);
const video = videoRef.current; audio.currentTime = startFrame / mediaSet.audio.sampleRate;
if (video == null) {
return;
}
video.currentTime = startFrame / mediaSet.audio.sampleRate;
}; };
// render component: // render component:
const wrapperProps = { const wrapperProps = {
width: '90%', width: '90%',
height: '250px', height: '550px',
position: 'relative', position: 'relative',
margin: '0 auto', margin: '0 auto',
} as React.CSSProperties; } as React.CSSProperties;
@ -342,17 +312,11 @@ export const Waveform: React.FC<Props> = ({ audioContext }: Props) => {
zIndex: 1, zIndex: 1,
} as React.CSSProperties; } as React.CSSProperties;
const overviewStyles = { ...wrapperProps, height: '60px' }; const overviewStyles = { ...wrapperProps, height: '120px' };
// TODO: why is the margin needed? // TODO: why is the margin needed?
const controlPanelStyles = { margin: '1em' } as React.CSSProperties; const controlPanelStyles = { margin: '1em' } as React.CSSProperties;
const clockTextAreaProps = { color: '#999', width: '400px' }; const clockTextAreaProps = { color: '#999', width: '400px' };
const videoStyles = {
width: '30%',
height: 'auto',
margin: '10px auto 0 auto',
zIndex: 2,
} as React.CSSProperties;
const thumbnailStyles = { const thumbnailStyles = {
width: '90%', width: '90%',
height: '35px', height: '35px',
@ -362,7 +326,6 @@ export const Waveform: React.FC<Props> = ({ audioContext }: Props) => {
return ( return (
<> <>
<video ref={videoRef} style={videoStyles}></video>
<Thumbnails mediaSet={mediaSet} style={thumbnailStyles} /> <Thumbnails mediaSet={mediaSet} style={thumbnailStyles} />
<WaveformOverview <WaveformOverview
peaks={overviewPeaks} peaks={overviewPeaks}