Test Fungsi Tombol Musik Player

This commit is contained in:
2026-03-02 10:17:02 +08:00
parent 341ff5779f
commit 9e267e75f6
13 changed files with 3148 additions and 85 deletions

View File

@@ -0,0 +1,292 @@
# Music Player Implementation Options
## Option 1: Using `react-player` Library (RECOMMENDED) ✅
### Installation
```bash
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
```typescript
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
```typescript
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
```typescript
import ReactPlayer from 'react-player';
function BasicPlayer() {
return (
<ReactPlayer
url="https://example.com/song.mp3"
playing={true}
controls={true}
/>
);
}
```
### Custom Player with Progress
```typescript
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
```typescript
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