diff --git a/components/FullScreenVideoPlayer.tsx b/components/FullScreenVideoPlayer.tsx
index c80fdb76..2729aa98 100644
--- a/components/FullScreenVideoPlayer.tsx
+++ b/components/FullScreenVideoPlayer.tsx
@@ -44,6 +44,8 @@ import {
runtimeTicksToSeconds,
ticksToSeconds,
} from "@/utils/time";
+import { useIntroSkipper } from "@/hooks/useIntroSkipper";
+import { useCreditSkipper } from "@/hooks/useCreditSkipper";
const windowDimensions = Dimensions.get("window");
const screenDimensions = Dimensions.get("screen");
@@ -116,6 +118,18 @@ export const FullScreenVideoPlayer: React.FC = () => {
[]
);
+ const { showSkipButton, skipIntro } = useIntroSkipper(
+ currentlyPlaying?.item.Id,
+ currentTime,
+ videoRef
+ );
+
+ const { showSkipCreditButton, skipCredit } = useCreditSkipper(
+ currentlyPlaying?.item.Id,
+ currentTime,
+ videoRef
+ );
+
useAnimatedReaction(
() => ({
progress: progress.value,
@@ -321,46 +335,6 @@ export const FullScreenVideoPlayer: React.FC = () => {
setIgnoreSafeArea((prev) => !prev);
}, []);
- const { data: introTimestamps } = useQuery({
- queryKey: ["introTimestamps", currentlyPlaying?.item.Id],
- queryFn: async () => {
- if (!currentlyPlaying?.item.Id) {
- console.log("No item id");
- return null;
- }
-
- const res = await api?.axiosInstance.get(
- `${api.basePath}/Episode/${currentlyPlaying.item.Id}/IntroTimestamps`,
- {
- headers: getAuthHeaders(api),
- }
- );
-
- if (res?.status !== 200) {
- return null;
- }
-
- return res?.data as {
- EpisodeId: string;
- HideSkipPromptAt: number;
- IntroEnd: number;
- IntroStart: number;
- ShowSkipPromptAt: number;
- Valid: boolean;
- };
- },
- enabled: !!currentlyPlaying?.item.Id,
- });
-
- const skipIntro = useCallback(async () => {
- if (!introTimestamps || !videoRef.current) return;
- try {
- videoRef.current.seek(introTimestamps.IntroEnd);
- } catch (error) {
- writeToLog("ERROR", "Error skipping intro", error);
- }
- }, [introTimestamps]);
-
if (!currentlyPlaying) return null;
return (
@@ -428,28 +402,47 @@ export const FullScreenVideoPlayer: React.FC = () => {
)}
- {introTimestamps &&
- currentTime > introTimestamps.ShowSkipPromptAt &&
- currentTime < introTimestamps.HideSkipPromptAt && (
-
+
-
- Skip Intro
-
-
- )}
+ Skip Intro
+
+
+ )}
+
+ {showSkipCreditButton && (
+
+
+ Skip Credits
+
+
+ )}
{showControls && (
<>
diff --git a/hooks/useCreditSkipper.ts b/hooks/useCreditSkipper.ts
new file mode 100644
index 00000000..2fb2940d
--- /dev/null
+++ b/hooks/useCreditSkipper.ts
@@ -0,0 +1,72 @@
+import { useCallback, useEffect, useState } from "react";
+import { useQuery } from "@tanstack/react-query";
+import { useAtom } from "jotai";
+import { apiAtom } from "@/providers/JellyfinProvider";
+import { getAuthHeaders } from "@/utils/jellyfin/jellyfin";
+import { writeToLog } from "@/utils/log";
+
+interface CreditTimestamps {
+ Introduction: {
+ Start: number;
+ End: number;
+ Valid: boolean;
+ };
+ Credits: {
+ Start: number;
+ End: number;
+ Valid: boolean;
+ };
+}
+
+export const useCreditSkipper = (
+ itemId: string | undefined,
+ currentTime: number,
+ videoRef: React.RefObject
+) => {
+ const [api] = useAtom(apiAtom);
+ const [showSkipCreditButton, setShowSkipCreditButton] = useState(false);
+
+ const { data: creditTimestamps } = useQuery({
+ queryKey: ["creditTimestamps", itemId],
+ queryFn: async () => {
+ if (!itemId) {
+ console.log("No item id");
+ return null;
+ }
+
+ const res = await api?.axiosInstance.get(
+ `${api.basePath}/Episode/${itemId}/Timestamps`,
+ {
+ headers: getAuthHeaders(api),
+ }
+ );
+
+ if (res?.status !== 200) {
+ return null;
+ }
+
+ return res?.data;
+ },
+ enabled: !!itemId,
+ });
+
+ useEffect(() => {
+ if (creditTimestamps) {
+ setShowSkipCreditButton(
+ currentTime > creditTimestamps.Credits.Start &&
+ currentTime < creditTimestamps.Credits.End
+ );
+ }
+ }, [creditTimestamps, currentTime]);
+
+ const skipCredit = useCallback(() => {
+ if (!creditTimestamps || !videoRef.current) return;
+ try {
+ videoRef.current.seek(creditTimestamps.Credits.End);
+ } catch (error) {
+ writeToLog("ERROR", "Error skipping intro", error);
+ }
+ }, [creditTimestamps, videoRef]);
+
+ return { showSkipCreditButton, skipCredit };
+};