mirror of
https://github.com/KuekHaoYang/KVideo.git
synced 2026-08-17 17:53:43 +08:00
feat: Add usePlaybackPolling hook for robust playback progress updates and refine history item matching logic.
This commit is contained in:
@@ -34,11 +34,14 @@ export function VideoPlayer({ playUrl, videoId, currentEpisode, onBack }: VideoP
|
||||
if (!videoId) return 0;
|
||||
|
||||
// Directly check HistoryStore for progress
|
||||
// This is the single source of truth for playback resumption
|
||||
// We prioritize a strict match (including source), but fall back to any match for this video/episode
|
||||
// This fixes issues where the source parameter might be missing or different
|
||||
const historyItem = viewingHistory.find(item =>
|
||||
// Loose match for videoId (string vs number)
|
||||
item.videoId.toString() === videoId?.toString() &&
|
||||
item.source === source &&
|
||||
item.episodeIndex === currentEpisode &&
|
||||
(source ? item.source === source : true)
|
||||
) || viewingHistory.find(item =>
|
||||
item.videoId.toString() === videoId?.toString() &&
|
||||
item.episodeIndex === currentEpisode
|
||||
);
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { formatTime } from '@/lib/utils/format-utils';
|
||||
import { usePlaybackPolling } from '../usePlaybackPolling';
|
||||
|
||||
interface UsePlaybackControlsProps {
|
||||
videoRef: React.RefObject<HTMLVideoElement | null>;
|
||||
@@ -112,13 +114,14 @@ export function usePlaybackControls({
|
||||
}
|
||||
}, [videoRef, setPlaybackRate, setShowSpeedMenu, speedMenuTimeoutRef]);
|
||||
|
||||
const formatTime = useCallback((seconds: number) => {
|
||||
if (isNaN(seconds)) return '0:00:00';
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const mins = Math.floor((seconds % 3600) / 60);
|
||||
const secs = Math.floor(seconds % 60);
|
||||
return `${hours}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
|
||||
}, []);
|
||||
// Polling fallback for AirPlay and throttled events
|
||||
usePlaybackPolling({
|
||||
isPlaying,
|
||||
videoRef,
|
||||
isDraggingProgressRef,
|
||||
setCurrentTime,
|
||||
setDuration
|
||||
});
|
||||
|
||||
return {
|
||||
togglePlay,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { formatTime } from '@/lib/utils/format-utils';
|
||||
import { usePlaybackPolling } from '../usePlaybackPolling';
|
||||
|
||||
interface UseMobilePlaybackProps {
|
||||
videoRef: React.RefObject<HTMLVideoElement>;
|
||||
@@ -124,13 +126,14 @@ export function useMobilePlaybackControls({
|
||||
setShowSpeedMenu(false);
|
||||
}, [videoRef, setPlaybackRate, setShowSpeedMenu]);
|
||||
|
||||
const formatTime = useCallback((seconds: number) => {
|
||||
if (isNaN(seconds)) return '0:00:00';
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const mins = Math.floor((seconds % 3600) / 60);
|
||||
const secs = Math.floor(seconds % 60);
|
||||
return `${hours}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
|
||||
}, []);
|
||||
// Polling fallback for AirPlay and throttled events
|
||||
usePlaybackPolling({
|
||||
isPlaying,
|
||||
videoRef,
|
||||
isDraggingProgressRef,
|
||||
setCurrentTime,
|
||||
setDuration
|
||||
});
|
||||
|
||||
return {
|
||||
togglePlay,
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
interface UsePlaybackPollingProps {
|
||||
isPlaying: boolean;
|
||||
videoRef: React.RefObject<HTMLVideoElement | null>;
|
||||
isDraggingProgressRef: React.MutableRefObject<boolean>;
|
||||
setCurrentTime: (time: number) => void;
|
||||
setDuration: (duration: number) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Polling fallback for AirPlay and throttled events
|
||||
* Updates playback progress manually when events are suppressed
|
||||
*/
|
||||
export function usePlaybackPolling({
|
||||
isPlaying,
|
||||
videoRef,
|
||||
isDraggingProgressRef,
|
||||
setCurrentTime,
|
||||
setDuration
|
||||
}: UsePlaybackPollingProps) {
|
||||
useEffect(() => {
|
||||
if (!isPlaying || !videoRef.current) return;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
if (videoRef.current && !isDraggingProgressRef.current) {
|
||||
const current = videoRef.current.currentTime;
|
||||
const total = videoRef.current.duration;
|
||||
|
||||
// Only update if significantly different to avoid jitter
|
||||
setCurrentTime(current);
|
||||
if (!isNaN(total) && total > 0) {
|
||||
setDuration(total);
|
||||
}
|
||||
}
|
||||
}, 500); // Poll every 500ms
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [isPlaying, videoRef, isDraggingProgressRef, setCurrentTime, setDuration]);
|
||||
}
|
||||
Reference in New Issue
Block a user