fix(web): subscribe from a TMDB candidate by creating the entity first

The search page 订阅 button and the new-subscription wizard threw away
the TMDB id and created a title-only subscription, which stays pending
(metadata_pending) with no seasons, episode totals or coverage matrix
until some release happens to be identified. Call
/files/entity-from-candidate first and subscribe the entity; fall back
to title tracking only if that fails. Picking a TMDB row in the wizard
now creates the library entity even if the dialog is then cancelled
(idempotent per TMDB id).

Found in REAL-1b on the v0.2.2 test stack; needs an image rebuild to
take effect.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-29 00:37:45 +08:00
1 parent 775344f597
commit 39f5897df6
2 files changed
+27 -9

No files matched your search

@@ -13,6 +13,7 @@ import { ExternalLink, Search, X } from "lucide-react";
import { type ReactNode, useEffect, useId, useMemo, useState } from "react";
import { Link } from "react-router";
import { toast } from "sonner";
import { useEntityFromCandidate } from "~/api/files.ts";
import { downloaders, useSiteOptions } from "~/api/instances.ts";
import { useEntityDetail, useLibraryRoots } from "~/api/library.ts";
import { usePolicyRevisions } from "~/api/policies.ts";
@@ -141,11 +142,19 @@ function WorkPicker({ onPick, error }: { onPick: (t: Target) => void; error?: st
year: h.entity.year,
mediaKind: toSubKind(h.entity.kind),
});
const pickTmdb = (c: TmdbCandidate) =>
c.localEntityId
const entity = useEntityFromCandidate();
const pickTmdb = async (c: TmdbCandidate) => {
// 库里没有:先按 TMDB id 建档(季/集与总集数随之就位),失败才退回按标题追踪
const id =
c.localEntityId ??
(await entity
.mutateAsync({ provider: "tmdb", externalId: c.externalId, kind: c.entityType === "movie" ? "movie" : "tv" })
.then((r) => r.mediaEntityId)
.catch(() => null));
return id
? onPick({
kind: "entity",
id: c.localEntityId,
id,
title: c.title,
year: c.year,
mediaKind: c.entityType === "movie" ? "movie" : "series",
@@ -154,8 +163,9 @@ function WorkPicker({ onPick, error }: { onPick: (t: Target) => void; error?: st
kind: "title",
titleQuery: c.year ? `${c.title} ${c.year}` : c.title,
mediaKind: c.entityType === "movie" ? "movie" : "series",
note: `TMDB ${c.externalId},建档后自动关联`,
note: `TMDB ${c.externalId},建档失败,按标题追踪`,
});
};
const row = (key: string, main: ReactNode, sub: string, onClick: () => void) => (
<li key={key}>
<button
@@ -405,7 +415,7 @@ export function SubscriptionFormDialog({
<DialogHeader>
<DialogTitle>{editing ? "编辑订阅" : "新建订阅"}</DialogTitle>
<DialogDescription>
{editing ? titleText : "从媒体库或 TMDB 选作品;库里没有的按标题追踪,建档后自动关联。"}
{editing ? titleText : "从媒体库或 TMDB 选作品;选 TMDB 条目会先建档。"}
</DialogDescription>
</DialogHeader>
{dup ? (