phrasal-player-provider
Version:
react player provider based on wavesurfer.js, for play and edit phrases (subtitles, captions)
138 lines (117 loc) • 3.56 kB
text/typescript
import RegionsPlugin, {
RegionParams,
RegionsPluginParams
} from 'wavesurfer.js/src/plugin/regions'
import TimelinePlugin from 'wavesurfer.js/src/plugin/timeline'
import WaveSurfer from 'wavesurfer.js'
import { RefObject } from 'react'
import { PlayerContextState, Phrase } from '.'
import { findCurrentPhraseNum } from 'frazy-parser'
import { WaveSurferParams } from 'wavesurfer.js/types/params'
interface InitProps {
waveformContainerRef: RefObject<HTMLDivElement>
wavesurferTimelineRef: RefObject<HTMLDivElement>
mediaElementRef: RefObject<HTMLMediaElement>
regionsOptions?: RegionsPluginParams
wavesurferOptions?: WaveSurferParams
phrases?: Phrase[]
setPlayerState: React.Dispatch<React.SetStateAction<PlayerContextState>>
}
export const initWavesurfer = ({
waveformContainerRef,
wavesurferTimelineRef,
mediaElementRef,
phrases,
regionsOptions,
wavesurferOptions,
setPlayerState
}: InitProps) => {
console.log('init')
const wavesurfer = WaveSurfer.create({
container: waveformContainerRef.current!,
...wavesurferOptions,
plugins: [
RegionsPlugin.create({
// regionsMinLength: 2,
regions: phrases,
...regionsOptions
}),
TimelinePlugin.create({
container: wavesurferTimelineRef.current!
})
]
})
wavesurfer.load(mediaElementRef.current!)
// UTILS
const updatePhrase = (region: RegionParams) => {
const {
id,
start,
end,
// @ts-ignore
data: { text }
} = region
const phrase = { id, start, end, text } as Phrase
setPlayerState(oldState => {
const oldPhrases = oldState.phrases
const phrases = updatePhrases(phrase, oldPhrases)
return { ...oldState, phrases }
})
}
const updateCurrentPhraseNum = (delta = 0) => {
const currentTime: number = wavesurfer.getCurrentTime() + delta
setPlayerState(oldState => {
const phrases = oldState.phrases
const currentPhraseNum = findCurrentPhraseNum(phrases, currentTime)
return { ...oldState, currentPhraseNum }
})
}
//EVENT HANDLERS
wavesurfer.on('ready', () => {
setPlayerState(oldState => ({ ...oldState, isReady: true }))
})
wavesurfer.on('audioprocess', () => {
const currentTime = wavesurfer.getCurrentTime()
setPlayerState(oldState => ({ ...oldState, currentTime }))
})
wavesurfer.on('region-click', (region, event) => {
event.stopPropagation()
region.play()
})
wavesurfer.on('region-removed', (region, event) => {
setPlayerState(oldState => {
const oldPhrases = oldState.phrases
const phrases = oldPhrases.filter(elem => elem.id !== region.id)
return { ...oldState, phrases }
})
})
wavesurfer.on('region-updated', (region: Phrase, event) => {
updatePhrase(region)
})
wavesurfer.on('region-in', (/* region: Phrase */) => {
updateCurrentPhraseNum()
})
wavesurfer.on('region-out', (/* region: Phrase */) => {
updateCurrentPhraseNum()
})
wavesurfer.on('seek', (/* region: Phrase */) => {
updateCurrentPhraseNum()
})
wavesurfer.on('play', (/* region: Phrase */) => {
setPlayerState(oldState => ({ ...oldState, isPlaying: true }))
})
wavesurfer.on('pause', (/* region: Phrase */) => {
setPlayerState(oldState => ({ ...oldState, isPlaying: false }))
})
wavesurfer.on('finish', (/* region: Phrase */) => {
setPlayerState(oldState => ({ ...oldState, isPlaying: false }))
})
return wavesurfer
}
function updatePhrases(phrase: Phrase, phrases: Phrase[]) {
const phrasesExcept1 = phrases.filter(elem => elem.id !== phrase.id)
const newPhrases = [...phrasesExcept1, phrase].sort(
(a, b) => a.start - b.start
)
return newPhrases
}