mirror of
https://github.com/p-stream/p-stream.git
synced 2026-05-14 21:41:25 +00:00
fix skip time fetching with a slice cache
This commit is contained in:
parent
644b6ca8c9
commit
6bfb07f867
5 changed files with 50 additions and 10 deletions
|
|
@ -1,9 +1,11 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
// import { proxiedFetch } from "@/backend/helpers/fetch";
|
// import { proxiedFetch } from "@/backend/helpers/fetch";
|
||||||
import { mwFetch, proxiedFetch } from "@/backend/helpers/fetch";
|
import { mwFetch, proxiedFetch } from "@/backend/helpers/fetch";
|
||||||
import { usePlayerMeta } from "@/components/player/hooks/usePlayerMeta";
|
import { usePlayerMeta } from "@/components/player/hooks/usePlayerMeta";
|
||||||
import { conf } from "@/setup/config";
|
import { conf } from "@/setup/config";
|
||||||
|
import { usePlayerStore } from "@/stores/player/store";
|
||||||
|
import { getMediaKey } from "@/stores/player/slices/source";
|
||||||
import { usePreferencesStore } from "@/stores/preferences";
|
import { usePreferencesStore } from "@/stores/preferences";
|
||||||
import { getTurnstileToken } from "@/utils/turnstile";
|
import { getTurnstileToken } from "@/utils/turnstile";
|
||||||
|
|
||||||
|
|
@ -30,10 +32,16 @@ export interface SegmentData {
|
||||||
|
|
||||||
export function useSkipTime() {
|
export function useSkipTime() {
|
||||||
const { playerMeta: meta } = usePlayerMeta();
|
const { playerMeta: meta } = usePlayerMeta();
|
||||||
const [segments, setSegments] = useState<SegmentData[]>([]);
|
|
||||||
const febboxKey = usePreferencesStore((s) => s.febboxKey);
|
const febboxKey = usePreferencesStore((s) => s.febboxKey);
|
||||||
|
const cacheKey = getMediaKey(meta ?? null);
|
||||||
|
const skipSegmentsCacheKey = usePlayerStore((s) => s.skipSegmentsCacheKey);
|
||||||
|
const skipSegments = usePlayerStore((s) => s.skipSegments);
|
||||||
|
const setSkipSegments = usePlayerStore((s) => s.setSkipSegments);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!cacheKey) return;
|
||||||
|
// Already have segments for this media – don't refetch (e.g. when opening menu)
|
||||||
|
if (cacheKey === skipSegmentsCacheKey) return;
|
||||||
// Validate segment data according to rules
|
// Validate segment data according to rules
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
const validateSegment = (
|
const validateSegment = (
|
||||||
|
|
@ -212,9 +220,7 @@ export function useSkipTime() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchSkipTime = async (): Promise<void> => {
|
const fetchSkipTime = async (): Promise<void> => {
|
||||||
// Reset source and segments
|
|
||||||
currentSkipTimeSource = null;
|
currentSkipTimeSource = null;
|
||||||
setSegments([]);
|
|
||||||
|
|
||||||
// Try TheIntroDB API first (supports both movies and TV shows with full segment data)
|
// Try TheIntroDB API first (supports both movies and TV shows with full segment data)
|
||||||
const theIntroDBSegments = await fetchTheIntroDBSegments();
|
const theIntroDBSegments = await fetchTheIntroDBSegments();
|
||||||
|
|
@ -228,7 +234,7 @@ export function useSkipTime() {
|
||||||
// If we have a valid intro from TIDB, use all TIDB segments
|
// If we have a valid intro from TIDB, use all TIDB segments
|
||||||
if (hasIntroSegment) {
|
if (hasIntroSegment) {
|
||||||
currentSkipTimeSource = "theintrodb";
|
currentSkipTimeSource = "theintrodb";
|
||||||
setSegments(theIntroDBSegments);
|
setSkipSegments(cacheKey, theIntroDBSegments);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -275,13 +281,15 @@ export function useSkipTime() {
|
||||||
// Add any valid recap/credits segments from TIDB
|
// Add any valid recap/credits segments from TIDB
|
||||||
finalSegments.push(...nonIntroSegments);
|
finalSegments.push(...nonIntroSegments);
|
||||||
|
|
||||||
if (finalSegments.length > 0) {
|
// Always update cache (even when empty) so we don't refetch for this media
|
||||||
setSegments(finalSegments);
|
setSkipSegments(cacheKey, finalSegments);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchSkipTime();
|
fetchSkipTime();
|
||||||
}, [
|
}, [
|
||||||
|
cacheKey,
|
||||||
|
skipSegmentsCacheKey,
|
||||||
|
setSkipSegments,
|
||||||
meta?.tmdbId,
|
meta?.tmdbId,
|
||||||
meta?.imdbId,
|
meta?.imdbId,
|
||||||
meta?.title,
|
meta?.title,
|
||||||
|
|
@ -291,5 +299,6 @@ export function useSkipTime() {
|
||||||
febboxKey,
|
febboxKey,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return segments;
|
// Only return segments when they're for the current media (avoid showing stale data)
|
||||||
|
return cacheKey === skipSegmentsCacheKey ? skipSegments : [];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
26
src/stores/player/slices/skipSegments.ts
Normal file
26
src/stores/player/slices/skipSegments.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import type { SegmentData } from "@/components/player/hooks/useSkipTime";
|
||||||
|
import { MakeSlice } from "@/stores/player/slices/types";
|
||||||
|
|
||||||
|
export interface SkipSegmentsSlice {
|
||||||
|
skipSegmentsCacheKey: string | null;
|
||||||
|
skipSegments: SegmentData[];
|
||||||
|
setSkipSegments(cacheKey: string, segments: SegmentData[]): void;
|
||||||
|
clearSkipSegments(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createSkipSegmentsSlice: MakeSlice<SkipSegmentsSlice> = (set) => ({
|
||||||
|
skipSegmentsCacheKey: null,
|
||||||
|
skipSegments: [],
|
||||||
|
setSkipSegments(cacheKey, segments) {
|
||||||
|
set((s) => {
|
||||||
|
s.skipSegmentsCacheKey = cacheKey;
|
||||||
|
s.skipSegments = segments;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
clearSkipSegments() {
|
||||||
|
set((s) => {
|
||||||
|
s.skipSegmentsCacheKey = null;
|
||||||
|
s.skipSegments = [];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -396,6 +396,7 @@ export const createSourceSlice: MakeSlice<SourceSlice> = (set, get) => ({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
reset() {
|
reset() {
|
||||||
|
get().clearSkipSegments?.();
|
||||||
set((s) => {
|
set((s) => {
|
||||||
s.source = null;
|
s.source = null;
|
||||||
s.sourceId = null;
|
s.sourceId = null;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { DisplaySlice } from "@/stores/player/slices/display";
|
||||||
import { InterfaceSlice } from "@/stores/player/slices/interface";
|
import { InterfaceSlice } from "@/stores/player/slices/interface";
|
||||||
import { PlayingSlice } from "@/stores/player/slices/playing";
|
import { PlayingSlice } from "@/stores/player/slices/playing";
|
||||||
import { ProgressSlice } from "@/stores/player/slices/progress";
|
import { ProgressSlice } from "@/stores/player/slices/progress";
|
||||||
|
import { SkipSegmentsSlice } from "@/stores/player/slices/skipSegments";
|
||||||
import { SourceSlice } from "@/stores/player/slices/source";
|
import { SourceSlice } from "@/stores/player/slices/source";
|
||||||
import { ThumbnailSlice } from "@/stores/player/slices/thumbnails";
|
import { ThumbnailSlice } from "@/stores/player/slices/thumbnails";
|
||||||
|
|
||||||
|
|
@ -14,7 +15,8 @@ export type AllSlices = InterfaceSlice &
|
||||||
SourceSlice &
|
SourceSlice &
|
||||||
DisplaySlice &
|
DisplaySlice &
|
||||||
CastingSlice &
|
CastingSlice &
|
||||||
ThumbnailSlice;
|
ThumbnailSlice &
|
||||||
|
SkipSegmentsSlice;
|
||||||
export type MakeSlice<Slice> = StateCreator<
|
export type MakeSlice<Slice> = StateCreator<
|
||||||
AllSlices,
|
AllSlices,
|
||||||
[["zustand/immer", never]],
|
[["zustand/immer", never]],
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { createDisplaySlice } from "@/stores/player/slices/display";
|
||||||
import { createInterfaceSlice } from "@/stores/player/slices/interface";
|
import { createInterfaceSlice } from "@/stores/player/slices/interface";
|
||||||
import { createPlayingSlice } from "@/stores/player/slices/playing";
|
import { createPlayingSlice } from "@/stores/player/slices/playing";
|
||||||
import { createProgressSlice } from "@/stores/player/slices/progress";
|
import { createProgressSlice } from "@/stores/player/slices/progress";
|
||||||
|
import { createSkipSegmentsSlice } from "@/stores/player/slices/skipSegments";
|
||||||
import { createSourceSlice } from "@/stores/player/slices/source";
|
import { createSourceSlice } from "@/stores/player/slices/source";
|
||||||
import { createThumbnailSlice } from "@/stores/player/slices/thumbnails";
|
import { createThumbnailSlice } from "@/stores/player/slices/thumbnails";
|
||||||
import { AllSlices } from "@/stores/player/slices/types";
|
import { AllSlices } from "@/stores/player/slices/types";
|
||||||
|
|
@ -19,5 +20,6 @@ export const usePlayerStore = create(
|
||||||
...createDisplaySlice(...a),
|
...createDisplaySlice(...a),
|
||||||
...createCastingSlice(...a),
|
...createCastingSlice(...a),
|
||||||
...createThumbnailSlice(...a),
|
...createThumbnailSlice(...a),
|
||||||
|
...createSkipSegmentsSlice(...a),
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue