mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-01-15 23:59:08 +00:00
106 lines
2.9 KiB
TypeScript
106 lines
2.9 KiB
TypeScript
import { useCallback, useEffect, useRef } from "react";
|
|
import { MediaTimeSegment } from "@/providers/Downloads/types";
|
|
import { useSettings } from "@/utils/atoms/settings";
|
|
import { useHaptic } from "./useHaptic";
|
|
|
|
type SegmentType = "Intro" | "Outro" | "Recap" | "Commercial" | "Preview";
|
|
|
|
interface UseSegmentSkipperProps {
|
|
segments: MediaTimeSegment[];
|
|
segmentType: SegmentType;
|
|
currentTime: number;
|
|
totalDuration?: number;
|
|
seek: (time: number) => void;
|
|
isPaused: boolean;
|
|
}
|
|
|
|
interface UseSegmentSkipperReturn {
|
|
currentSegment: MediaTimeSegment | null;
|
|
skipSegment: (notifyOrUseHaptics?: boolean) => void;
|
|
}
|
|
|
|
/**
|
|
* Generic hook to handle all media segment types (intro, outro, recap, commercial, preview)
|
|
* Supports three modes: 'none' (disabled), 'ask' (show button), 'auto' (auto-skip)
|
|
*/
|
|
export const useSegmentSkipper = ({
|
|
segments,
|
|
segmentType,
|
|
currentTime,
|
|
totalDuration,
|
|
seek,
|
|
isPaused,
|
|
}: UseSegmentSkipperProps): UseSegmentSkipperReturn => {
|
|
const { settings } = useSettings();
|
|
const haptic = useHaptic();
|
|
const autoSkipTriggeredRef = useRef(false);
|
|
|
|
// Get skip mode based on segment type
|
|
const skipMode = (() => {
|
|
switch (segmentType) {
|
|
case "Intro":
|
|
return settings.skipIntro;
|
|
case "Outro":
|
|
return settings.skipOutro;
|
|
case "Recap":
|
|
return settings.skipRecap;
|
|
case "Commercial":
|
|
return settings.skipCommercial;
|
|
case "Preview":
|
|
return settings.skipPreview;
|
|
default:
|
|
return "none";
|
|
}
|
|
})();
|
|
|
|
// Find current segment
|
|
const currentSegment =
|
|
segments.find(
|
|
(segment) =>
|
|
currentTime >= segment.startTime && currentTime < segment.endTime,
|
|
) || null;
|
|
|
|
// Skip function with optional haptic feedback
|
|
const skipSegment = useCallback(
|
|
(notifyOrUseHaptics = true) => {
|
|
if (!currentSegment) return;
|
|
|
|
// For Outro segments, prevent seeking past the end
|
|
if (segmentType === "Outro" && totalDuration) {
|
|
const seekTime = Math.min(currentSegment.endTime, totalDuration);
|
|
seek(seekTime);
|
|
} else {
|
|
seek(currentSegment.endTime);
|
|
}
|
|
|
|
// Only trigger haptic feedback if explicitly requested (manual skip)
|
|
if (notifyOrUseHaptics) {
|
|
haptic();
|
|
}
|
|
},
|
|
[currentSegment, segmentType, totalDuration, seek, haptic],
|
|
);
|
|
// Auto-skip logic when mode is 'auto'
|
|
useEffect(() => {
|
|
if (skipMode !== "auto" || isPaused) {
|
|
autoSkipTriggeredRef.current = false;
|
|
return;
|
|
}
|
|
|
|
if (currentSegment && !autoSkipTriggeredRef.current) {
|
|
autoSkipTriggeredRef.current = true;
|
|
skipSegment(false); // Don't trigger haptics for auto-skip
|
|
}
|
|
|
|
if (!currentSegment) {
|
|
autoSkipTriggeredRef.current = false;
|
|
}
|
|
}, [currentSegment, skipMode, isPaused, skipSegment]);
|
|
|
|
// Return null segment if skip mode is 'none'
|
|
return {
|
|
currentSegment: skipMode === "none" ? null : currentSegment,
|
|
skipSegment,
|
|
};
|
|
};
|