diff --git a/src/components/player/hooks/useSkipTime.ts b/src/components/player/hooks/useSkipTime.ts index 3dc37195..3b84f84d 100644 --- a/src/components/player/hooks/useSkipTime.ts +++ b/src/components/player/hooks/useSkipTime.ts @@ -8,17 +8,52 @@ import { usePreferencesStore } from "@/stores/preferences"; import { getTurnstileToken } from "@/utils/turnstile"; // Thanks Nemo for this API +const THE_INTRO_DB_BASE_URL = "https://api.theintrodb.org"; const FED_SKIPS_BASE_URL = "https://fed-skips.pstream.mov"; // const VELORA_BASE_URL = "https://veloratv.ru/api/intro-end/confirmed"; const INTRODB_BASE_URL = "https://api.introdb.app/intro"; const MAX_RETRIES = 3; +// Track the source of the current skip time (for analytics filtering) +let currentSkipTimeSource: "fed-skips" | "introdb" | "theintrodb" | null = null; + +export function useSkipTimeSource(): typeof currentSkipTimeSource { + return currentSkipTimeSource; +} + export function useSkipTime() { const { playerMeta: meta } = usePlayerMeta(); const [skiptime, setSkiptime] = useState(null); const febboxKey = usePreferencesStore((s) => s.febboxKey); useEffect(() => { + const fetchTheIntroDBTime = async (): Promise => { + if (!meta?.imdbId) return null; + + try { + let apiUrl = `${THE_INTRO_DB_BASE_URL}?imdb_id=${meta.imdbId}`; + if ( + meta.type !== "movie" && + meta.season?.number && + meta.episode?.number + ) { + apiUrl += `&season=${meta.season.number}&episode=${meta.episode.number}`; + } + + const data = await proxiedFetch(apiUrl); + + if (data && typeof data.end_ms === "number") { + // Convert milliseconds to seconds + return Math.floor(data.end_ms / 1000); + } + + return null; + } catch (error) { + console.error("Error fetching TIDB time:", error); + return null; + } + }; + // const fetchVeloraSkipTime = async (): Promise => { // if (!meta?.tmdbId) return null; @@ -105,17 +140,33 @@ export function useSkipTime() { }; const fetchSkipTime = async (): Promise => { + // Reset source + currentSkipTimeSource = null; + // If user has febbox key, prioritize Fed-skips (better quality) - if (febboxKey) { + // Note: Fed-skips only supports TV shows, not movies + if (febboxKey && meta?.type !== "movie") { const fedSkipsTime = await fetchFedSkipsTime(); if (fedSkipsTime !== null) { + currentSkipTimeSource = "fed-skips"; setSkiptime(fedSkipsTime); return; } } - // Fall back to IntroDB API (available to all users) + // Try TheIntroDB API (supports both movies and TV shows) + const theIntroDBTime = await fetchTheIntroDBTime(); + if (theIntroDBTime !== null) { + currentSkipTimeSource = "theintrodb"; + setSkiptime(theIntroDBTime); + return; + } + + // Fall back to IntroDB API (TV shows only, available to all users) const introDBTime = await fetchIntroDBTime(); + if (introDBTime !== null) { + currentSkipTimeSource = "introdb"; + } setSkiptime(introDBTime); }; diff --git a/src/components/player/internals/Backend/SkipTracker.tsx b/src/components/player/internals/Backend/SkipTracker.tsx index bf6bc1e9..9a9cd335 100644 --- a/src/components/player/internals/Backend/SkipTracker.tsx +++ b/src/components/player/internals/Backend/SkipTracker.tsx @@ -1,5 +1,6 @@ import { useCallback, useEffect, useRef, useState } from "react"; +import { useSkipTimeSource } from "@/components/player/hooks/useSkipTime"; import { useSkipTracking } from "@/components/player/hooks/useSkipTracking"; import { usePlayerStore } from "@/stores/player/store"; @@ -18,6 +19,7 @@ interface PendingSkip { startTime: number; endTime: number; hasBackwardMovement: boolean; + skipTimeSource: "fed-skips" | "introdb" | "theintrodb" | null; timer: ReturnType; } @@ -31,6 +33,7 @@ export function SkipTracker() { const meta = usePlayerStore((s) => s.meta); const progress = usePlayerStore((s) => s.progress); const turnstileToken = ""; + const skipTimeSource = useSkipTimeSource(); const sendSkipAnalytics = useCallback( async (skip: SkipEvent, adjustedConfidence: number) => { @@ -71,8 +74,14 @@ export function SkipTracker() { ? Math.max(0.1, pendingSkip.originalConfidence * 0.5) // Reduce confidence by half if adjusted : pendingSkip.originalConfidence; - // Send analytics - sendSkipAnalytics(pendingSkip.skip, adjustedConfidence); + // Only send analytics if skip time came from fed-skips or introdb (not theintrodb) + if ( + pendingSkip.skipTimeSource === "fed-skips" || + pendingSkip.skipTimeSource === "introdb" + ) { + // Send analytics + sendSkipAnalytics(pendingSkip.skip, adjustedConfidence); + } // Remove from pending return prev.filter((p) => p.skip.timestamp !== skip.timestamp); @@ -85,10 +94,11 @@ export function SkipTracker() { startTime: skip.startTime, endTime: skip.endTime, hasBackwardMovement: false, + skipTimeSource, timer, }; }, - [sendSkipAnalytics], + [sendSkipAnalytics, skipTimeSource], ); useEffect(() => {