Files
desa-darmasaba/src/app/darmasaba/(pages)/musik/lib/MUSIC_PLAYER_OPTIONS.md
2026-03-02 10:17:02 +08:00

6.4 KiB

Music Player Implementation Options

Installation

bun add react-player

Benefits

  • Battle-tested - Used in production by thousands of apps
  • Handles all edge cases - Browser differences, loading states, etc.
  • Simple API - Easy to use and maintain
  • Supports multiple formats - MP3, WAV, OGG, YouTube, Vimeo, etc.
  • Built-in progress handling - No manual interval management
  • Seek works perfectly - No browser compatibility issues

Usage Example

import { MusicPlayer } from './lib/MusicPlayer';

function MyComponent() {
  return (
    <MusicPlayer
      url="https://example.com/song.mp3"
      playing={true}
      volume={0.7}
      onEnded={() => console.log('Song ended')}
    />
  );
}

Files Created

  • MusicPlayer.tsx - Wrapper component using react-player
  • Handles all audio logic internally
  • Progress bar with seek functionality
  • Play/pause controls

Option 2: Custom Hook useAudioPlayer

When to Use

  • Need full control over audio element
  • Want to avoid external dependencies
  • Custom requirements not supported by libraries

Files Created

  • use-audio-player.ts - Custom React hook
  • SimpleMusicPlayer.tsx - Example component

Usage

import { useAudioPlayer } from './lib/use-audio-player';

function MyComponent() {
  const {
    isPlaying,
    currentTime,
    duration,
    play,
    pause,
    seek,
  } = useAudioPlayer({ src: '/path/to/audio.mp3' });

  return (
    <div>
      <button onClick={isPlaying ? pause : play}>
        {isPlaying ? 'Pause' : 'Play'}
      </button>
      <input
        type="range"
        min="0"
        max={duration}
        value={currentTime}
        onChange={(e) => seek(Number(e.target.value))}
      />
    </div>
  );
}

Option 3: Original Implementation (FIXED)

Current Status

  • Working with Pause→Seek→Play pattern
  • hasSeeked flag prevents reset
  • Retry logic with load()
  • ⚠️ Complex, hard to maintain
  • ⚠️ Multiple edge cases to handle

When to Keep

  • Already invested time in custom implementation
  • Need specific customizations
  • Don't want external dependencies

Recommendation

🎯 USE OPTION 1: react-player

Why?

  1. Less code - 100+ lines saved
  2. More reliable - Battle-tested library
  3. Easier maintenance - Library handles updates
  4. Better browser support - Handles cross-browser issues
  5. More features - Supports video, YouTube, Vimeo, etc.

Migration Steps:

  1. Install: bun add react-player
  2. Import: import MusicPlayer from './lib/MusicPlayer'
  3. Replace existing player component
  4. Done!

Comparison

Feature react-player Custom Hook Original
Lines of Code ~50 ~100 ~300
Browser Support Excellent ⚠️ Manual ⚠️ Manual
Seek Functionality Perfect Good ⚠️ Complex
Progress Updates Built-in Manual Manual
Format Support Many ⚠️ Limited ⚠️ Limited
Maintenance Library ⚠️ You ⚠️ You
Bundle Size +15kb +0kb +0kb

Implementation with react-player

Basic Player

import ReactPlayer from 'react-player';

function BasicPlayer() {
  return (
    <ReactPlayer
      url="https://example.com/song.mp3"
      playing={true}
      controls={true}
    />
  );
}

Custom Player with Progress

import ReactPlayer from 'react-player';
import { useState } from 'react';

function CustomPlayer() {
  const [played, setPlayed] = useState(0);
  
  return (
    <>
      <ReactPlayer
        url="https://example.com/song.mp3"
        onProgress={(e) => setPlayed(e.played)}
      />
      <input
        type="range"
        min="0"
        max="1"
        value={played}
        onChange={(e) => playerRef.current?.seekTo(parseFloat(e.target.value))}
      />
    </>
  );
}

Advanced Player with All Controls

import ReactPlayer from 'react-player';
import { useRef, useState } from 'react';

function AdvancedPlayer({ url }) {
  const playerRef = useRef(null);
  const [playing, setPlaying] = useState(false);
  const [volume, setVolume] = useState(0.5);
  const [muted, setMuted] = useState(false);
  const [played, setPlayed] = useState(0);
  const [duration, setDuration] = useState(0);

  return (
    <div>
      <ReactPlayer
        ref={playerRef}
        url={url}
        playing={playing}
        volume={volume}
        muted={muted}
        onProgress={(e) => setPlayed(e.played)}
        onDuration={setDuration}
        onEnded={() => setPlaying(false)}
      />
      
      {/* Progress Bar */}
      <input
        type="range"
        min="0"
        max="1"
        value={played}
        onChange={(e) => playerRef.current?.seekTo(parseFloat(e.target.value))}
      />
      
      {/* Controls */}
      <button onClick={() => setPlaying(!playing)}>
        {playing ? 'Pause' : 'Play'}
      </button>
      
      <button onClick={() => setMuted(!muted)}>
        {muted ? 'Unmute' : 'Mute'}
      </button>
      
      <input
        type="range"
        min="0"
        max="1"
        step="0.01"
        value={volume}
        onChange={(e) => setVolume(parseFloat(e.target.value))}
      />
    </div>
  );
}

Next Steps

If Using react-player:

  1. Already installed
  2. Use MusicPlayer.tsx component
  3. Or create custom wrapper for your needs
  4. Remove old complex logic

If Keeping Custom Implementation:

  1. Keep current files
  2. Test thoroughly
  3. Handle edge cases manually
  4. Maintain browser compatibility

Additional Libraries (Alternatives)

1. howler.js

  • Great for audio sprites
  • Good for games
  • More low-level control

2. wavesurfer.js

  • Waveform visualization
  • Audio editing features
  • More complex use cases

3. use-sound

  • React hook for sound effects
  • Simple API
  • Built on howler.js

Conclusion

For your use case (Desa Darmasaba music player):

USE react-player because:

  • Simple integration
  • Reliable seek functionality
  • Less code to maintain
  • Better browser support
  • Already installed!

Files to use:

  • MusicPlayer.tsx - Base component
  • Customize as needed
  • Remove old complex implementation

Updated: February 27, 2026
Recommendation: Use react-player library
Status: Installed and ready to use