|  | @@ -13,6 +13,7 @@ type AudioBtnProps = {
 | 
	
		
			
				|  |  |    voice?: string
 | 
	
		
			
				|  |  |    className?: string
 | 
	
		
			
				|  |  |    isAudition?: boolean
 | 
	
		
			
				|  |  | +  noCache: boolean
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  type AudioState = 'initial' | 'loading' | 'playing' | 'paused' | 'ended'
 | 
	
	
		
			
				|  | @@ -22,6 +23,7 @@ const AudioBtn = ({
 | 
	
		
			
				|  |  |    voice,
 | 
	
		
			
				|  |  |    className,
 | 
	
		
			
				|  |  |    isAudition,
 | 
	
		
			
				|  |  | +  noCache,
 | 
	
		
			
				|  |  |  }: AudioBtnProps) => {
 | 
	
		
			
				|  |  |    const audioRef = useRef<HTMLAudioElement | null>(null)
 | 
	
		
			
				|  |  |    const [audioState, setAudioState] = useState<AudioState>('initial')
 | 
	
	
		
			
				|  | @@ -38,12 +40,12 @@ const AudioBtn = ({
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    const loadAudio = async () => {
 | 
	
		
			
				|  |  |      const formData = new FormData()
 | 
	
		
			
				|  |  | +    formData.append('text', removeCodeBlocks(value))
 | 
	
		
			
				|  |  | +    formData.append('voice', removeCodeBlocks(voice))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      if (value !== '') {
 | 
	
		
			
				|  |  |        setAudioState('loading')
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      formData.append('text', removeCodeBlocks(value))
 | 
	
		
			
				|  |  | -      formData.append('voice', removeCodeBlocks(voice))
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |        let url = ''
 | 
	
		
			
				|  |  |        let isPublic = false
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -72,15 +74,16 @@ const AudioBtn = ({
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  const handleToggle = () => {
 | 
	
		
			
				|  |  | -    if (audioState === 'initial')
 | 
	
		
			
				|  |  | -      loadAudio()
 | 
	
		
			
				|  |  | -    if (audioRef.current) {
 | 
	
		
			
				|  |  | +  const handleToggle = async () => {
 | 
	
		
			
				|  |  | +    if (audioState === 'initial' || noCache) {
 | 
	
		
			
				|  |  | +      await loadAudio()
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    else if (audioRef.current) {
 | 
	
		
			
				|  |  |        if (audioState === 'playing') {
 | 
	
		
			
				|  |  |          audioRef.current.pause()
 | 
	
		
			
				|  |  |          setAudioState('paused')
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | -      else if (audioState === 'paused' || audioState === 'ended') {
 | 
	
		
			
				|  |  | +      else {
 | 
	
		
			
				|  |  |          audioRef.current.play()
 | 
	
		
			
				|  |  |          setAudioState('playing')
 | 
	
		
			
				|  |  |        }
 | 
	
	
		
			
				|  | @@ -89,27 +92,31 @@ const AudioBtn = ({
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    useEffect(() => {
 | 
	
		
			
				|  |  |      const currentAudio = audioRef.current
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      const handleLoading = () => {
 | 
	
		
			
				|  |  |        setAudioState('loading')
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      const handlePlay = () => {
 | 
	
		
			
				|  |  |        currentAudio?.play()
 | 
	
		
			
				|  |  |        setAudioState('playing')
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      const handleEnded = () => {
 | 
	
		
			
				|  |  |        setAudioState('ended')
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      currentAudio?.addEventListener('progress', handleLoading)
 | 
	
		
			
				|  |  |      currentAudio?.addEventListener('canplaythrough', handlePlay)
 | 
	
		
			
				|  |  |      currentAudio?.addEventListener('ended', handleEnded)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      return () => {
 | 
	
		
			
				|  |  | -      if (currentAudio) {
 | 
	
		
			
				|  |  | -        currentAudio.removeEventListener('progress', handleLoading)
 | 
	
		
			
				|  |  | -        currentAudio.removeEventListener('canplaythrough', handlePlay)
 | 
	
		
			
				|  |  | -        currentAudio.removeEventListener('ended', handleEnded)
 | 
	
		
			
				|  |  | -        URL.revokeObjectURL(currentAudio.src)
 | 
	
		
			
				|  |  | -        currentAudio.src = ''
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | +      currentAudio?.removeEventListener('progress', handleLoading)
 | 
	
		
			
				|  |  | +      currentAudio?.removeEventListener('canplaythrough', handlePlay)
 | 
	
		
			
				|  |  | +      currentAudio?.removeEventListener('ended', handleEnded)
 | 
	
		
			
				|  |  | +      URL.revokeObjectURL(currentAudio?.src || '')
 | 
	
		
			
				|  |  | +      currentAudio?.pause()
 | 
	
		
			
				|  |  | +      currentAudio?.setAttribute('src', '')
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }, [])
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -131,9 +138,17 @@ const AudioBtn = ({
 | 
	
		
			
				|  |  |          <button
 | 
	
		
			
				|  |  |            disabled={audioState === 'loading'}
 | 
	
		
			
				|  |  |            className={`box-border p-0.5 flex items-center justify-center cursor-pointer ${isAudition || '!p-0 rounded-md bg-white'}`}
 | 
	
		
			
				|  |  | -          onClick={handleToggle}>
 | 
	
		
			
				|  |  | -          {audioState === 'loading' && <div className='w-6 h-6 rounded-md flex items-center justify-center p-2'><Loading /></div>}
 | 
	
		
			
				|  |  | -          {audioState !== 'loading' && <div className={`w-6 h-6 rounded-md ${!isAudition ? 'w-4 h-4 hover:bg-gray-50' : 'hover:bg-gray-50'} ${(audioState === 'playing') ? s.pauseIcon : s.playIcon}`}></div>}
 | 
	
		
			
				|  |  | +          onClick={handleToggle}
 | 
	
		
			
				|  |  | +        >
 | 
	
		
			
				|  |  | +          {audioState === 'loading'
 | 
	
		
			
				|  |  | +            ? (
 | 
	
		
			
				|  |  | +              <div className='w-6 h-6 rounded-md flex items-center justify-center p-2'>
 | 
	
		
			
				|  |  | +                <Loading />
 | 
	
		
			
				|  |  | +              </div>
 | 
	
		
			
				|  |  | +            )
 | 
	
		
			
				|  |  | +            : (
 | 
	
		
			
				|  |  | +              <div className={`w-6 h-6 rounded-md ${!isAudition ? 'w-4 h-4 hover:bg-gray-50' : 'hover:bg-gray-50'} ${(audioState === 'playing') ? s.pauseIcon : s.playIcon}`}></div>
 | 
	
		
			
				|  |  | +            )}
 | 
	
		
			
				|  |  |          </button>
 | 
	
		
			
				|  |  |        </Tooltip>
 | 
	
		
			
				|  |  |        <audio ref={audioRef} src='' className='hidden' />
 |