* fix: fixed recommendations page causing infinite network requests to tmdb api TMDB API would only return 40 results and the recommendations page expected more. This would cause an infinite amount of network requests. I set a limit specifically for this solving the problem. fix #2710
102 lines
2.4 KiB
TypeScript
102 lines
2.4 KiB
TypeScript
import useSWRInfinite from 'swr/infinite';
|
|
import { MediaStatus } from '../../server/constants/media';
|
|
import useSettings from './useSettings';
|
|
|
|
export interface BaseSearchResult<T> {
|
|
page: number;
|
|
totalResults: number;
|
|
totalPages: number;
|
|
results: T[];
|
|
}
|
|
|
|
interface BaseMedia {
|
|
mediaType: string;
|
|
mediaInfo?: {
|
|
status: MediaStatus;
|
|
};
|
|
}
|
|
|
|
interface DiscoverResult<T, S> {
|
|
isLoadingInitialData: boolean;
|
|
isLoadingMore: boolean;
|
|
fetchMore: () => void;
|
|
isEmpty: boolean;
|
|
isReachingEnd: boolean;
|
|
error: unknown;
|
|
titles: T[];
|
|
firstResultData?: BaseSearchResult<T> & S;
|
|
}
|
|
|
|
const useDiscover = <T extends BaseMedia, S = Record<string, never>>(
|
|
endpoint: string,
|
|
options?: Record<string, unknown>,
|
|
{ hideAvailable = true } = {}
|
|
): DiscoverResult<T, S> => {
|
|
const settings = useSettings();
|
|
const { data, error, size, setSize, isValidating } = useSWRInfinite<
|
|
BaseSearchResult<T> & S
|
|
>(
|
|
(pageIndex: number, previousPageData) => {
|
|
if (previousPageData && pageIndex + 1 > previousPageData.totalPages) {
|
|
return null;
|
|
}
|
|
|
|
const params: Record<string, unknown> = {
|
|
page: pageIndex + 1,
|
|
...options,
|
|
};
|
|
|
|
const finalQueryString = Object.keys(params)
|
|
.map((paramKey) => `${paramKey}=${params[paramKey]}`)
|
|
.join('&');
|
|
|
|
return `${endpoint}?${finalQueryString}`;
|
|
},
|
|
{
|
|
initialSize: 3,
|
|
}
|
|
);
|
|
|
|
const isLoadingInitialData = !data && !error;
|
|
const isLoadingMore =
|
|
isLoadingInitialData ||
|
|
(size > 0 &&
|
|
!!data &&
|
|
typeof data[size - 1] === 'undefined' &&
|
|
isValidating);
|
|
|
|
const fetchMore = () => {
|
|
setSize(size + 1);
|
|
};
|
|
|
|
let titles = (data ?? []).reduce((a, v) => [...a, ...v.results], [] as T[]);
|
|
|
|
if (settings.currentSettings.hideAvailable && hideAvailable) {
|
|
titles = titles.filter(
|
|
(i) =>
|
|
(i.mediaType === 'movie' || i.mediaType === 'tv') &&
|
|
i.mediaInfo?.status !== MediaStatus.AVAILABLE &&
|
|
i.mediaInfo?.status !== MediaStatus.PARTIALLY_AVAILABLE
|
|
);
|
|
}
|
|
|
|
const isEmpty = !isLoadingInitialData && titles?.length === 0;
|
|
const isReachingEnd =
|
|
isEmpty ||
|
|
(!!data && (data[data?.length - 1]?.results.length ?? 0) < 20) ||
|
|
(!!data && (data[data?.length - 1]?.totalResults ?? 0) < 41);
|
|
|
|
return {
|
|
isLoadingInitialData,
|
|
isLoadingMore,
|
|
fetchMore,
|
|
isEmpty,
|
|
isReachingEnd,
|
|
error,
|
|
titles,
|
|
firstResultData: data?.[0],
|
|
};
|
|
};
|
|
|
|
export default useDiscover;
|