update skips!

This commit is contained in:
Pas 2026-01-12 13:05:45 -07:00
parent 02a179b1d8
commit 5b32daac60
2 changed files with 66 additions and 5 deletions

View file

@ -8,17 +8,52 @@ import { usePreferencesStore } from "@/stores/preferences";
import { getTurnstileToken } from "@/utils/turnstile"; import { getTurnstileToken } from "@/utils/turnstile";
// Thanks Nemo for this API // 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 FED_SKIPS_BASE_URL = "https://fed-skips.pstream.mov";
// const VELORA_BASE_URL = "https://veloratv.ru/api/intro-end/confirmed"; // const VELORA_BASE_URL = "https://veloratv.ru/api/intro-end/confirmed";
const INTRODB_BASE_URL = "https://api.introdb.app/intro"; const INTRODB_BASE_URL = "https://api.introdb.app/intro";
const MAX_RETRIES = 3; 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() { export function useSkipTime() {
const { playerMeta: meta } = usePlayerMeta(); const { playerMeta: meta } = usePlayerMeta();
const [skiptime, setSkiptime] = useState<number | null>(null); const [skiptime, setSkiptime] = useState<number | null>(null);
const febboxKey = usePreferencesStore((s) => s.febboxKey); const febboxKey = usePreferencesStore((s) => s.febboxKey);
useEffect(() => { useEffect(() => {
const fetchTheIntroDBTime = async (): Promise<number | null> => {
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<number | null> => { // const fetchVeloraSkipTime = async (): Promise<number | null> => {
// if (!meta?.tmdbId) return null; // if (!meta?.tmdbId) return null;
@ -105,17 +140,33 @@ export function useSkipTime() {
}; };
const fetchSkipTime = async (): Promise<void> => { const fetchSkipTime = async (): Promise<void> => {
// Reset source
currentSkipTimeSource = null;
// If user has febbox key, prioritize Fed-skips (better quality) // 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(); const fedSkipsTime = await fetchFedSkipsTime();
if (fedSkipsTime !== null) { if (fedSkipsTime !== null) {
currentSkipTimeSource = "fed-skips";
setSkiptime(fedSkipsTime); setSkiptime(fedSkipsTime);
return; 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(); const introDBTime = await fetchIntroDBTime();
if (introDBTime !== null) {
currentSkipTimeSource = "introdb";
}
setSkiptime(introDBTime); setSkiptime(introDBTime);
}; };

View file

@ -1,5 +1,6 @@
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { useSkipTimeSource } from "@/components/player/hooks/useSkipTime";
import { useSkipTracking } from "@/components/player/hooks/useSkipTracking"; import { useSkipTracking } from "@/components/player/hooks/useSkipTracking";
import { usePlayerStore } from "@/stores/player/store"; import { usePlayerStore } from "@/stores/player/store";
@ -18,6 +19,7 @@ interface PendingSkip {
startTime: number; startTime: number;
endTime: number; endTime: number;
hasBackwardMovement: boolean; hasBackwardMovement: boolean;
skipTimeSource: "fed-skips" | "introdb" | "theintrodb" | null;
timer: ReturnType<typeof setTimeout>; timer: ReturnType<typeof setTimeout>;
} }
@ -31,6 +33,7 @@ export function SkipTracker() {
const meta = usePlayerStore((s) => s.meta); const meta = usePlayerStore((s) => s.meta);
const progress = usePlayerStore((s) => s.progress); const progress = usePlayerStore((s) => s.progress);
const turnstileToken = ""; const turnstileToken = "";
const skipTimeSource = useSkipTimeSource();
const sendSkipAnalytics = useCallback( const sendSkipAnalytics = useCallback(
async (skip: SkipEvent, adjustedConfidence: number) => { 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 ? Math.max(0.1, pendingSkip.originalConfidence * 0.5) // Reduce confidence by half if adjusted
: pendingSkip.originalConfidence; : pendingSkip.originalConfidence;
// Send analytics // Only send analytics if skip time came from fed-skips or introdb (not theintrodb)
sendSkipAnalytics(pendingSkip.skip, adjustedConfidence); if (
pendingSkip.skipTimeSource === "fed-skips" ||
pendingSkip.skipTimeSource === "introdb"
) {
// Send analytics
sendSkipAnalytics(pendingSkip.skip, adjustedConfidence);
}
// Remove from pending // Remove from pending
return prev.filter((p) => p.skip.timestamp !== skip.timestamp); return prev.filter((p) => p.skip.timestamp !== skip.timestamp);
@ -85,10 +94,11 @@ export function SkipTracker() {
startTime: skip.startTime, startTime: skip.startTime,
endTime: skip.endTime, endTime: skip.endTime,
hasBackwardMovement: false, hasBackwardMovement: false,
skipTimeSource,
timer, timer,
}; };
}, },
[sendSkipAnalytics], [sendSkipAnalytics, skipTimeSource],
); );
useEffect(() => { useEffect(() => {