105 lines
2.9 KiB
Markdown
105 lines
2.9 KiB
Markdown
# UI Implementation Plan: Duration and Progress Bar Fixes
|
|
|
|
## 🎯 **Goal**
|
|
Fix two critical UI issues:
|
|
1. Duration showing buffered duration instead of real video duration
|
|
2. Progress bar jumping backwards during buffering
|
|
|
|
## 🔍 **Root Cause**
|
|
- **Duration Issue**: Video metadata events fire before real duration is loaded
|
|
- **Progress Issue**: Browser buffering reports backward timestamps
|
|
|
|
## 🏗️ **Solution Strategy**
|
|
|
|
### **1. Duration Protection Hook**
|
|
```typescript
|
|
// hooks/use-protected-duration.ts
|
|
export const useProtectedDuration = (videoId: string) => {
|
|
const [duration, setDuration] = useState(0);
|
|
const hasRealDuration = useRef(false);
|
|
|
|
// Priority: Database > Headers > Video Metadata
|
|
const fetchRealDuration = async () => {
|
|
// 1. Try database first
|
|
const dbDuration = await getStoredDuration(videoId);
|
|
if (dbDuration > 0) {
|
|
setDuration(dbDuration);
|
|
hasRealDuration.current = true;
|
|
return;
|
|
}
|
|
|
|
// 2. Try transcoding headers
|
|
const headerDuration = await getHeaderDuration(videoId);
|
|
if (headerDuration > 0) {
|
|
setDuration(headerDuration);
|
|
hasRealDuration.current = true;
|
|
}
|
|
};
|
|
|
|
// Block metadata duration if we have real duration
|
|
const handleDurationChange = (newDuration: number) => {
|
|
if (hasRealDuration.current) {
|
|
return; // Keep real duration
|
|
}
|
|
// Only accept significantly larger durations
|
|
if (newDuration > duration * 2.0) {
|
|
setDuration(newDuration);
|
|
}
|
|
};
|
|
|
|
return { duration, handleDurationChange };
|
|
};
|
|
```
|
|
|
|
### **2. Stable Progress Hook**
|
|
```typescript
|
|
// hooks/use-stable-progress.ts
|
|
export const useStableProgress = (videoRef: RefObject<HTMLVideoElement>) => {
|
|
const [currentTime, setCurrentTime] = useState(0);
|
|
const lastStableTime = useRef(0);
|
|
|
|
const handleTimeUpdate = () => {
|
|
if (!videoRef.current) return;
|
|
|
|
const newTime = videoRef.current.currentTime;
|
|
|
|
// Prevent backward jumps
|
|
if (newTime < lastStableTime.current - 0.1) {
|
|
console.log(`[PROGRESS] Blocked backward jump: ${newTime}s -> ${lastStableTime.current}s`);
|
|
return;
|
|
}
|
|
|
|
setCurrentTime(newTime);
|
|
lastStableTime.current = newTime;
|
|
};
|
|
|
|
return { currentTime, handleTimeUpdate };
|
|
};
|
|
```
|
|
|
|
## 📋 **Implementation Steps**
|
|
|
|
### **Day 1: Create Hooks**
|
|
- [ ] Create `use-protected-duration.ts`
|
|
- [ ] Create `use-stable-progress.ts`
|
|
- [ ] Test hooks independently
|
|
|
|
### **Day 2: Update Video Viewer**
|
|
- [ ] Remove old duration/progress logic
|
|
- [ ] Integrate new hooks
|
|
- [ ] Test duration protection
|
|
|
|
### **Day 3: Test and Debug**
|
|
- [ ] Test with direct videos
|
|
- [ ] Test with transcoded streams
|
|
- [ ] Verify no backward jumps
|
|
|
|
## 🎯 **Expected Results**
|
|
- ✅ Duration always shows real video length (9 min, not 6 sec)
|
|
- ✅ Progress bar never jumps backward
|
|
- ✅ Professional streaming experience
|
|
- ✅ Simple, maintainable code
|
|
|
|
## 🚀 **Next Steps**
|
|
After UI fixes, implement FFmpeg process management for seek optimization.
|