File size: 2,563 Bytes
08dfd47
ed37070
 
 
eb27538
ed37070
08dfd47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ed37070
 
f76d503
08dfd47
 
 
 
 
 
 
 
ed37070
08dfd47
 
 
 
 
 
 
 
 
 
 
 
ed37070
08dfd47
 
eb27538
 
 
 
ed37070
eb27538
 
 
 
 
 
ed37070
 
 
 
eb27538
ed37070
f76d503
eb27538
ed37070
08dfd47
 
 
 
 
ed37070
08dfd47
 
 
ed37070
eb27538
ed37070
 
 
 
eb27538
ed37070
 
 
08dfd47
ed37070
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import { useEffect, useRef, useImperativeHandle, forwardRef } from 'react'
import WaveSurfer from 'wavesurfer.js'
// @ts-ignore: No types for timeline.esm.js
import TimelinePlugin from 'wavesurfer.js/dist/plugins/timeline.esm.js'
import API from '../API'

export interface AudioPlayerHandle {
  getCurrentTime: () => number
  setTime: (t: number) => void
  play: () => void
  pause: () => void
}

const AudioPlayer = forwardRef<
  AudioPlayerHandle,
  {
    src: string
    playing: boolean
    // seekTo: number
    onPlay: () => void
    onPause: () => void
    onAudioProcess?: (currentTime: number) => void
  }
>(({ src, playing, onPlay, onPause, onAudioProcess }, ref) => {
  const containerRef = useRef<HTMLDivElement>(null)
  const wavesurferRef = useRef<WaveSurfer | null>(null)

  useImperativeHandle(ref, () => ({
    getCurrentTime: () => wavesurferRef.current?.getCurrentTime() || 0,
    setTime: (t: number) => wavesurferRef.current?.setTime(t),
    play: () => wavesurferRef.current?.play(),
    pause: () => wavesurferRef.current?.pause(),
  }))

  // Sync play/pause and seek
  useEffect(() => {
    if (wavesurferRef.current) {
      // wavesurferRef.current.setTime(seekTo)
      if (playing) {
        wavesurferRef.current.play()
      } else {
        wavesurferRef.current.pause()
      }
    }
  }, [
    playing,
    // seekTo
  ])

  useEffect(() => {
    if (!containerRef.current) return
    if (wavesurferRef.current) {
      wavesurferRef.current.destroy()
      wavesurferRef.current = null
    }
    const proxiedUrl = API.getProxiedUrl(src)
    const bottomTimeline = TimelinePlugin.create({
      height: 16,
      timeInterval: 0.1,
      primaryLabelInterval: 1,
      style: { fontSize: '10px' },
    })
    wavesurferRef.current = WaveSurfer.create({
      container: containerRef.current,
      waveColor: 'rgb(200, 0, 200)',
      progressColor: 'rgb(100, 0, 100)',
      url: proxiedUrl,
      minPxPerSec: 100,
      mediaControls: true,
      plugins: [bottomTimeline],
    })
    wavesurferRef.current.on('play', onPlay)
    wavesurferRef.current.on('pause', onPause)
    if (onAudioProcess) {
      wavesurferRef.current.on('audioprocess', onAudioProcess)
    }
    return () => {
      if (wavesurferRef.current && onAudioProcess) {
        wavesurferRef.current.un('audioprocess', onAudioProcess)
      }
      wavesurferRef.current?.destroy()
      wavesurferRef.current = null
    }
  }, [src])

  return (
    <div className="w-full">
      <div ref={containerRef} />
    </div>
  )
})

export default AudioPlayer