| import React, { useEffect, useRef } from 'react' |
|
|
| export default function AudioPlayer() { |
| const audioRef = useRef(null) |
| const hasStartedRef = useRef(false) |
|
|
| useEffect(() => { |
| const a = new Audio('/jeopardy-themelq.mp3') |
| audioRef.current = a |
| a.preload = 'auto' |
| a.volume = 0.5 |
| a.loop = true |
|
|
| const startPlayback = async () => { |
| if (hasStartedRef.current) return |
| try { |
| await a.play() |
| hasStartedRef.current = true |
| console.log('Audio started playing') |
| } catch (e) { |
| console.log('Autoplay blocked, waiting for user interaction') |
| |
| const startOnInteraction = () => { |
| if (!hasStartedRef.current) { |
| a.play() |
| .then(() => { |
| hasStartedRef.current = true |
| console.log('Audio started after user interaction') |
| }) |
| .catch((err) => { |
| console.error('Failed to start audio:', err) |
| }) |
| } |
| } |
| const events = ['click', 'keydown', 'touchstart', 'mousedown'] |
| events.forEach(event => { |
| document.addEventListener(event, startOnInteraction, { once: true, passive: true }) |
| }) |
| } |
| } |
|
|
| |
| const handlePause = () => { |
| if (hasStartedRef.current && a.paused && document.visibilityState === 'visible') { |
| console.log('Audio paused unexpectedly, restarting...') |
| a.play().catch((err) => { |
| console.error('Failed to restart audio:', err) |
| }) |
| } |
| } |
|
|
| |
| const handleStalled = () => { |
| if (hasStartedRef.current && a.paused) { |
| console.log('Audio stalled, attempting to resume...') |
| a.play().catch((err) => { |
| console.error('Failed to resume audio:', err) |
| }) |
| } |
| } |
|
|
| |
| const handleError = (e) => { |
| console.error('Audio error:', e) |
| |
| a.load() |
| if (hasStartedRef.current) { |
| a.play().catch((err) => { |
| console.error('Failed to restart after error:', err) |
| }) |
| } |
| } |
|
|
| |
| const handleVisibilityChange = () => { |
| if (document.visibilityState === 'visible' && hasStartedRef.current && a.paused) { |
| a.play().catch((err) => { |
| console.error('Failed to resume on visibility change:', err) |
| }) |
| } |
| } |
|
|
| |
| startPlayback() |
|
|
| |
| a.addEventListener('pause', handlePause) |
| a.addEventListener('stalled', handleStalled) |
| a.addEventListener('error', handleError) |
| document.addEventListener('visibilitychange', handleVisibilityChange) |
|
|
| |
| const checkInterval = setInterval(() => { |
| if (hasStartedRef.current && a.paused && document.visibilityState === 'visible') { |
| console.log('Audio stopped, restarting...') |
| a.play().catch((err) => { |
| console.error('Failed to restart in interval check:', err) |
| }) |
| } |
| }, 2000) |
|
|
| return () => { |
| clearInterval(checkInterval) |
| try { |
| a.pause() |
| a.src = '' |
| a.removeEventListener('pause', handlePause) |
| a.removeEventListener('stalled', handleStalled) |
| a.removeEventListener('error', handleError) |
| document.removeEventListener('visibilitychange', handleVisibilityChange) |
| } catch (e) { |
| console.error('Error cleaning up audio:', e) |
| } |
| } |
| }, []) |
|
|
| return null |
| } |
|
|