Files

77 lines
2.5 KiB
TypeScript

import { useInfiniteQuery, useMutation, useQuery } from "@tanstack/react-query";
import { DiscoverCalendar, type DiscoverItem, DiscoverMatchResult, DiscoverPage } from "@umt/contracts";
import type { ApiQuery } from "~/components/discover/discover-state.ts";
import { api } from "~/lib/api.ts";
import { getParsed, parseOrThrow } from "./library.ts";
// 发现:TMDB / 豆瓣 / bgm 列表(服务端走请求缓存);点豆瓣 / bgm 条目时匹配 TMDB 作品。
const STALE = 10 * 60_000;
export const discoverKeys = {
calendar: ["discover", "calendar"] as const,
list: (q: ApiQuery) => ["discover", q] as const,
};
async function fetchCalendar(signal?: AbortSignal) {
return getParsed(DiscoverCalendar, "/discover/bangumi-calendar", {}, signal);
}
/** 一页;每日放送取那一天,不分页 */
export async function fetchDiscoverPage(q: ApiQuery, page: number, signal?: AbortSignal): Promise<DiscoverPage> {
if (q.kind === "calendar") {
const cal = await fetchCalendar(signal);
const items = cal.days.find((d) => String(d.weekday) === q.weekday)?.items ?? [];
return { items, page: 1, hasMore: false };
}
return getParsed(DiscoverPage, q.path, { ...q.params, page }, signal);
}
/** 推荐分区:只取第一页;enabled 由分区是否进入视口决定 */
export function useDiscoverSection(q: ApiQuery, enabled: boolean) {
return useQuery({
queryKey: [...discoverKeys.list(q), 1],
enabled,
queryFn: ({ signal }) => fetchDiscoverPage(q, 1, signal),
staleTime: STALE,
});
}
/** 探索:无限滚动 */
export function useDiscoverInfinite(q: ApiQuery) {
return useInfiniteQuery({
queryKey: [...discoverKeys.list(q), "all"],
initialPageParam: 1,
queryFn: ({ pageParam, signal }) => fetchDiscoverPage(q, pageParam, signal),
getNextPageParam: (last) => (last.hasMore ? last.page + 1 : undefined),
staleTime: STALE,
});
}
export function useBangumiCalendar(enabled = true) {
return useQuery({
queryKey: discoverKeys.calendar,
enabled,
queryFn: ({ signal }) => fetchCalendar(signal),
staleTime: STALE,
});
}
export function useDiscoverMatch() {
return useMutation({
mutationFn: async (it: DiscoverItem) =>
parseOrThrow(
DiscoverMatchResult,
await api.post<unknown>("/discover/tmdb-match", {
source: it.source,
id: it.id,
title: it.title,
aliases: it.aliases,
year: it.year,
kind: it.kind,
}),
"/discover/tmdb-match",
),
});
}