subtitles timeline and wave audio
Shwave is a subtitles timeline to help people build subtitles easily.
It also support audio-only.
REACT
npm i shwave -S
import { ShWave } from "shwave";
<ShWave
duration={15}
backgroundColor={"#529393"}
currentTime={currentTime}
throttleWait={1}
url={videoUrl}
waveColor={"#fbf8f86b"}
alterWaveColor={"#57e3e3"}
waveScale={0.8}
click={onWaveClick}
contextmenu={onWaveContextmenu}
subArray={subArray}
onSubMove={onSubMove}
onSubMoveError={onSubMoveError}
/>;
REACT
import React, { Fragment, useState, useCallback } from "react";
/** @jsx jsx */
import { css, jsx } from "@emotion/core";
import ShWave from "./componets/shwave";
import VideoPlayer from "./componets/videoPlayer";
const App = () => {
const [player, setPlayer] = useState(null);
const [currentTime, setCurrentTime] = useState(0);
const [duration, setDuration] = useState(15);
const [url, setUrl] = useState("");
const [subArray, setSubArray] = useState([
{
content: "content 1",
end: 0.999,
length: 0.999,
start: 0,
},
{
content: `content 2
content 2 2
content 2 4
content 2 e
content 2 e`,
end: 6.999,
length: 1.999,
start: 5,
},
{
content: `sdddddddddddddddddddddddddddddddddddd`,
end: 14.999,
length: 4.999,
start: 10,
},
{
content: "content 4",
end: 18,
length: 3,
start: 15,
},
]);
const handleVideoFile = useCallback(
(e) => {
URL.revokeObjectURL(url);
const file = e.currentTarget.files[0];
const videoUrl = URL.createObjectURL(file);
setUrl(videoUrl);
const videoRegx = /^video\/(mp4|x-(flv))+$/;
const found = file.type.match(videoRegx);
const videoType =
found && found[2] ? found[2] + "Custom" : found ? found[1] : "";
player.switchVideo({
url: videoUrl,
type: videoType,
});
},
[url, setUrl, player]
);
const contextmenu = useCallback(
(time, event) => {
if (!player) return;
player.play();
player.seek(time);
},
[player]
);
const click = useCallback(
(time, event) => {
if (!player) return;
player.pause();
player.seek(time);
},
[player]
);
const handleSubClick = useCallback((sub) => {
console.log(sub);
});
const handleSubMove = useCallback((originSub, translateSecond) => {
const subs = [...subArray];
const index = subs.indexOf(originSub);
const sub = { ...subs[index] };
sub.start += translateSecond;
sub.end += translateSecond;
subs[index] = sub;
console.log("update subArray");
setSubArray(subs);
});
const handleSubMoveError = useCallback(() => {});
const handleSubResize = useCallback((originSub, translateSecond, type) => {
const subs = [...subArray];
const index = subs.indexOf(originSub);
const sub = { ...subs[index] };
if (type === "start") {
sub.start += translateSecond;
} else {
sub.end += translateSecond;
}
sub.length = sub.end - sub.start;
subs[index] = sub;
console.log("update subArray");
setSubArray(subs);
});
const handleDurationChange = useCallback((duration) => {
setDuration(duration);
//pause the video
});
return (
<Fragment>
<div
className="container"
css={css`
height: 600px;
width: 600px;
`}
>
<VideoPlayer
url={url}
player={player}
setPlayer={setPlayer}
setCurrentTime={setCurrentTime}
/>
<input
className="uploadVideo"
type="file"
name="file"
onChange={handleVideoFile}
/>
<input
type="range"
title={duration}
value={duration}
min="5"
max="30"
step="1"
onChange={(e) => {
handleDurationChange(Number(e.currentTarget.value));
}}
/>
</div>
<div
css={css`
position: relative;
height: 150px;
`}
>
<ShWave
duration={duration}
backgroundColor="#529393"
pointerColor="#ddd"
pointerWidth={3}
waveColor="#fbf8f86b"
alterWaveColor="#57e3e3"
waveScale={0.8}
currentTime={currentTime}
throttleWait={300}
url={url}
click={click}
contextmenu={contextmenu}
subArray={subArray}
onSubClick={handleSubClick}
onSubMove={handleSubMove}
onSubMoveError={handleSubMoveError}
ErrorWait={2000}
ErrorColor="#f09b50d9"
onSubResize={handleSubResize}
subBlockClass="mySubBlockClass"
/>
</div>
</Fragment>
);
};
export default App;
yarn
# yarn start
yarn pro