mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-11 17:45:38 +00:00
fix(player): dedupe skip-segment fetches and harden segment hook
This commit is contained in:
parent
275a75b61d
commit
3a8ec97a7b
4 changed files with 40 additions and 9 deletions
|
|
@ -223,7 +223,7 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
|
||||
const nextEpisodeHook = useNextEpisode(type, season, episode, groupedEpisodes, (metadataResult as any)?.groupedEpisodes, episodeId);
|
||||
|
||||
const { outroSegment } = useSkipSegments({
|
||||
const { segments: skipIntervals, outroSegment } = useSkipSegments({
|
||||
imdbId: imdbId || (id?.startsWith('tt') ? id : undefined),
|
||||
type,
|
||||
season,
|
||||
|
|
@ -986,6 +986,7 @@ const AndroidVideoPlayer: React.FC = () => {
|
|||
episode={episode}
|
||||
malId={(metadata as any)?.mal_id || (metadata as any)?.external_ids?.mal_id}
|
||||
kitsuId={id?.startsWith('kitsu:') ? id.split(':')[1] : undefined}
|
||||
skipIntervals={skipIntervals}
|
||||
currentTime={playerState.currentTime}
|
||||
onSkip={(endTime) => controlsHook.seekToTime(endTime)}
|
||||
controlsVisible={playerState.showControls}
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ const KSPlayerCore: React.FC = () => {
|
|||
episodeId
|
||||
});
|
||||
|
||||
const { outroSegment } = useSkipSegments({
|
||||
const { segments: skipIntervals, outroSegment } = useSkipSegments({
|
||||
imdbId: imdbId || (id?.startsWith('tt') ? id : undefined),
|
||||
type,
|
||||
season,
|
||||
|
|
@ -956,6 +956,7 @@ const KSPlayerCore: React.FC = () => {
|
|||
episode={episode}
|
||||
malId={(metadata as any)?.mal_id || (metadata as any)?.external_ids?.mal_id}
|
||||
kitsuId={id?.startsWith('kitsu:') ? id.split(':')[1] : undefined}
|
||||
skipIntervals={skipIntervals}
|
||||
currentTime={currentTime}
|
||||
onSkip={(endTime) => controls.seekToTime(endTime)}
|
||||
controlsVisible={showControls}
|
||||
|
|
@ -1114,4 +1115,4 @@ const KSPlayerCore: React.FC = () => {
|
|||
);
|
||||
};
|
||||
|
||||
export default KSPlayerCore;
|
||||
export default KSPlayerCore;
|
||||
|
|
|
|||
|
|
@ -28,10 +28,12 @@ export const useSkipSegments = ({
|
|||
|
||||
useEffect(() => {
|
||||
const key = `${imdbId}-${season}-${episode}-${malId}-${kitsuId}`;
|
||||
|
||||
|
||||
if (!enabled || type !== 'series' || (!imdbId && !malId && !kitsuId) || !season || !episode) {
|
||||
setSegments([]);
|
||||
setIsLoading(false);
|
||||
fetchedRef.current = false;
|
||||
lastKeyRef.current = '';
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -39,23 +41,41 @@ export const useSkipSegments = ({
|
|||
return;
|
||||
}
|
||||
|
||||
// Clear stale intervals while resolving a new episode/key.
|
||||
if (lastKeyRef.current !== key) {
|
||||
setSegments([]);
|
||||
fetchedRef.current = false;
|
||||
}
|
||||
|
||||
lastKeyRef.current = key;
|
||||
fetchedRef.current = true;
|
||||
setIsLoading(true);
|
||||
let cancelled = false;
|
||||
|
||||
const fetchSegments = async () => {
|
||||
try {
|
||||
const intervals = await introService.getSkipTimes(imdbId, season, episode, malId, kitsuId);
|
||||
|
||||
// Ignore stale responses from old requests.
|
||||
if (cancelled || lastKeyRef.current !== key) return;
|
||||
setSegments(intervals);
|
||||
fetchedRef.current = true;
|
||||
} catch (error) {
|
||||
if (cancelled || lastKeyRef.current !== key) return;
|
||||
logger.error('[useSkipSegments] Error fetching skip data:', error);
|
||||
setSegments([]);
|
||||
// Keep this key retryable on transient failures.
|
||||
fetchedRef.current = false;
|
||||
} finally {
|
||||
if (cancelled || lastKeyRef.current !== key) return;
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchSegments();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [imdbId, type, season, episode, malId, kitsuId, enabled]);
|
||||
|
||||
const getActiveSegment = (currentTime: number) => {
|
||||
|
|
@ -64,7 +84,12 @@ export const useSkipSegments = ({
|
|||
);
|
||||
};
|
||||
|
||||
const outroSegment = segments.find(s => ['ed', 'outro', 'mixed-ed'].includes(s.type));
|
||||
const outroSegment = segments
|
||||
.filter(s => ['ed', 'outro', 'mixed-ed'].includes(s.type))
|
||||
.reduce<SkipInterval | null>((latest, interval) => {
|
||||
if (!latest || interval.endTime > latest.endTime) return interval;
|
||||
return latest;
|
||||
}, null);
|
||||
|
||||
return {
|
||||
segments,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ interface SkipIntroButtonProps {
|
|||
episode?: number;
|
||||
malId?: string;
|
||||
kitsuId?: string;
|
||||
skipIntervals?: SkipInterval[] | null;
|
||||
currentTime: number;
|
||||
onSkip: (endTime: number) => void;
|
||||
controlsVisible?: boolean;
|
||||
|
|
@ -36,6 +37,7 @@ export const SkipIntroButton: React.FC<SkipIntroButtonProps> = ({
|
|||
episode,
|
||||
malId,
|
||||
kitsuId,
|
||||
skipIntervals: externalSkipIntervals,
|
||||
currentTime,
|
||||
onSkip,
|
||||
controlsVisible = false,
|
||||
|
|
@ -47,15 +49,17 @@ export const SkipIntroButton: React.FC<SkipIntroButtonProps> = ({
|
|||
|
||||
const skipIntroEnabled = settings.skipIntroEnabled;
|
||||
|
||||
const { segments: skipIntervals } = useSkipSegments({
|
||||
const { segments: fetchedSkipIntervals } = useSkipSegments({
|
||||
imdbId,
|
||||
type,
|
||||
season,
|
||||
episode,
|
||||
malId,
|
||||
kitsuId,
|
||||
enabled: skipIntroEnabled
|
||||
// Allow parent components to provide pre-fetched intervals to avoid duplicate requests.
|
||||
enabled: skipIntroEnabled && !externalSkipIntervals
|
||||
});
|
||||
const skipIntervals = externalSkipIntervals ?? fetchedSkipIntervals;
|
||||
|
||||
// State
|
||||
const [currentInterval, setCurrentInterval] = useState<SkipInterval | null>(null);
|
||||
|
|
@ -293,4 +297,4 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
});
|
||||
|
||||
export default SkipIntroButton;
|
||||
export default SkipIntroButton;
|
||||
|
|
|
|||
Loading…
Reference in a new issue