import type { TmdbCandidate } from "@umt/contracts";
import { ArrowRight, Film, Plus } from "lucide-react";
import { Link, useNavigate } from "react-router";
import { toast } from "sonner";
import { useEntityFromCandidate } from "~/api/files.ts";
import { useSearch } from "~/api/search.ts";
import { useCreateSubscription } from "~/api/subscriptions.ts";
import { EmptyState, ErrorState, LoadingState } from "~/components/console/empty-state.tsx";
import { settingsPath } from "~/components/console/nav.ts";
import { StatusBadge } from "~/components/console/status-badge.tsx";
import { Button } from "~/components/ui/button.tsx";
import { errorMessage } from "~/lib/api.ts";
import { actionIcon, mediaKindLabel, slotSummary } from "./search-labels.ts";
// 结果页的"作品"与"操作"两段(资源段见 release-results.tsx)
function SectionTitle({ id, title, extra }: { id: string; title: string; extra?: string }) {
return (
{title}
{extra ? {extra} : null}
);
}
/** 从 TMDB 候选建订阅:先按 TMDB id 建档(季/集与总集数随之就位)再订阅作品;建档失败退回按标题追踪 */
export function useSubscribeTmdb() {
const create = useCreateSubscription();
const entity = useEntityFromCandidate();
const navigate = useNavigate();
return {
pending: create.isPending || entity.isPending,
subscribe: async (c: TmdbCandidate, onDone?: () => void) => {
const kind = c.entityType === "movie" ? "movie" : "series";
const mediaEntityId =
c.localEntityId ??
(await entity
.mutateAsync({ provider: "tmdb", externalId: c.externalId, kind: c.entityType === "movie" ? "movie" : "tv" })
.then((r) => r.mediaEntityId)
.catch(() => null));
create.mutate(
{
...(mediaEntityId ? { mediaEntityId } : { titleQuery: c.year ? `${c.title} ${c.year}` : c.title }),
mediaKind: kind,
mode: kind === "movie" ? "once" : "continuous",
seasonScope: kind === "movie" ? "current_season" : "following_seasons",
priority: "new_work",
origin: "user",
},
{
onSuccess: () => {
toast.success(`已订阅「${c.title}」`, {
action: { label: "查看", onClick: () => navigate("/console/subscriptions") },
});
onDone?.();
},
onError: (e) => toast.error(errorMessage(e, "订阅失败")),
},
);
},
};
}
export function MediaSection({ q }: { q: string }) {
const res = useSearch(q, "media", 20);
const sub = useSubscribeTmdb();
const local = res.data?.media?.local.items ?? [];
const tmdb = res.data?.media?.tmdb;
return (
{res.isPending ? (
) : res.isError ? (
res.refetch()} />
) : local.length === 0 && !tmdb?.items.length ? (
) : (
{local.map((h) => (
-
{h.entity.title}
{h.entity.year ? ({h.entity.year}) : null}
{mediaKindLabel(h.entity.kind)} · {slotSummary(h)}
{h.matchedAlias && h.matchedAlias !== h.entity.title ? ` · 命中别名 ${h.matchedAlias}` : ""}
本地
))}
{(tmdb?.items ?? []).map((c) => (
-
{c.title}
{c.year ? ({c.year}) : null}
TMDB · {c.entityType === "movie" ? "电影" : "剧集"}
{c.originalTitle && c.originalTitle !== c.title ? ` · ${c.originalTitle}` : ""}
{c.overview ? ` · ${c.overview}` : ""}
{c.localEntityId ? (
) : (
)}
))}
)}
{tmdb && !tmdb.configured ? (
TMDB 未配置,只搜了本地作品。
去配置
) : null}
{tmdb?.error ? (
TMDB 查询失败:{tmdb.error}
) : null}
);
}
export function ActionsSection({ q }: { q: string }) {
const res = useSearch(q, "actions", 12);
const items = res.data?.actions?.items ?? [];
if (res.isPending || res.isError || items.length === 0) return null;
return (
{items.map((a) => {
const Icon = actionIcon(a.kind);
return (
{a.title}
{a.group}
);
})}
);
}