Remove HTML video element
This commit is contained in:
parent
0cdc728587
commit
b08165d7f1
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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}
|
||||||
|
|
Loading…
Reference in New Issue