import { Api } from "@jellyfin/sdk"; import { useQuery } from "@tanstack/react-query"; import React from "react"; import { DownloadedItem, MediaTimeSegment } from "@/providers/Downloads/types"; import { getAuthHeaders } from "./jellyfin/jellyfin"; interface IntroTimestamps { EpisodeId: string; HideSkipPromptAt: number; IntroEnd: number; IntroStart: number; ShowSkipPromptAt: number; Valid: boolean; } interface CreditTimestamps { Introduction: { Start: number; End: number; Valid: boolean; }; Credits: { Start: number; End: number; Valid: boolean; }; } export const useSegments = ( itemId: string, isOffline: boolean, downloadedFiles: DownloadedItem[] | undefined, api: Api | null, ) => { // Memoize the lookup so the array is only traversed when dependencies change const downloadedItem = React.useMemo( () => downloadedFiles?.find((d) => d.item.Id === itemId), [downloadedFiles, itemId], ); return useQuery({ queryKey: ["segments", itemId, isOffline], queryFn: async () => { if (isOffline && downloadedItem) { return getSegmentsForItem(downloadedItem); } if (!api) { throw new Error("API client is not available"); } return fetchAndParseSegments(itemId, api); }, enabled: isOffline ? !!downloadedItem : !!api, }); }; export const getSegmentsForItem = ( item: DownloadedItem, ): { introSegments: MediaTimeSegment[]; creditSegments: MediaTimeSegment[]; } => { return { introSegments: item.introSegments || [], creditSegments: item.creditSegments || [], }; }; export const fetchAndParseSegments = async ( itemId: string, api: Api, ): Promise<{ introSegments: MediaTimeSegment[]; creditSegments: MediaTimeSegment[]; }> => { const introSegments: MediaTimeSegment[] = []; const creditSegments: MediaTimeSegment[] = []; try { const [introRes, creditRes] = await Promise.allSettled([ api.axiosInstance.get( `${api.basePath}/Episode/${itemId}/IntroTimestamps`, { headers: getAuthHeaders(api) }, ), api.axiosInstance.get( `${api.basePath}/Episode/${itemId}/Timestamps`, { headers: getAuthHeaders(api) }, ), ]); if (introRes.status === "fulfilled" && introRes.value.data.Valid) { introSegments.push({ startTime: introRes.value.data.IntroStart, endTime: introRes.value.data.IntroEnd, text: "Intro", }); } if ( creditRes.status === "fulfilled" && creditRes.value.data.Credits.Valid ) { creditSegments.push({ startTime: creditRes.value.data.Credits.Start, endTime: creditRes.value.data.Credits.End, text: "Credits", }); } } catch (error) { console.error("Failed to fetch segments", error); } return { introSegments, creditSegments }; };