恢复水位 / 硬阈值 → 恢复线 / 暂停线;库根、哨兵、Feed、快照、建档、纳管等按术语表改。 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
202 lines
5.6 KiB
TypeScript
202 lines
5.6 KiB
TypeScript
import { z } from "zod";
|
|
import * as assets from "../assets.ts";
|
|
import { Id, IdParam } from "../common.ts";
|
|
import * as content from "../content.ts";
|
|
import * as identity from "../identity.ts";
|
|
import {
|
|
crud,
|
|
del,
|
|
ep,
|
|
FieldOverrideResult,
|
|
FieldParam,
|
|
IdentityRevisionList,
|
|
R,
|
|
TaskAccepted,
|
|
UnitFieldOverrideResult,
|
|
UnitFieldParam,
|
|
} from "./shared.ts";
|
|
|
|
export const contentApi = {
|
|
// ── 内容 / 身份 ──
|
|
mediaEntities: {
|
|
...crud(
|
|
"/media-entities",
|
|
"作品",
|
|
{
|
|
row: content.MediaEntity,
|
|
create: content.MediaEntityCreate,
|
|
update: content.MediaEntityUpdate,
|
|
filters: {
|
|
kind: content.MediaKind.optional(),
|
|
status: content.MediaEntityStatus.optional(),
|
|
q: z.string().max(200).optional(),
|
|
},
|
|
},
|
|
R,
|
|
),
|
|
merge: ep({
|
|
method: "post",
|
|
path: "/media-entities/{id}/merge",
|
|
scope: "admin",
|
|
summary: "合并重复作品(保留旧 ID 跳转)",
|
|
params: IdParam,
|
|
body: z.object({ intoId: Id, reason: z.string().max(2000) }),
|
|
response: content.MediaEntity,
|
|
}),
|
|
detail: ep({
|
|
method: "get",
|
|
path: "/media-entities/{id}/detail",
|
|
scope: "read",
|
|
summary: "作品详情:外部身份、别名、内容单元、字段来源与覆盖(旧 ID 自动跳转)",
|
|
params: IdParam,
|
|
response: content.MediaEntityDetail,
|
|
}),
|
|
setIdentity: ep({
|
|
method: "post",
|
|
path: "/media-entities/{id}/identities",
|
|
scope: "organize.execute",
|
|
summary: "人工纠错外部映射:旧映射退役(留修订),新映射 accepted + 人工锁",
|
|
params: IdParam,
|
|
body: identity.EntityIdentitySet,
|
|
response: z.object({
|
|
mediaEntityId: Id,
|
|
changed: z.boolean(),
|
|
identityId: Id.optional(),
|
|
retired: z.array(Id).optional(),
|
|
}),
|
|
}),
|
|
refresh: ep({
|
|
method: "post",
|
|
path: "/media-entities/{id}/refresh",
|
|
scope: "organize.execute",
|
|
summary:
|
|
"刷新元数据(字段级;用户锁优先,不动路径)。标题 / 简介按设置 metadata.languages 回退;full=1 拉取全部季的每集信息",
|
|
params: IdParam,
|
|
query: z.object({ full: z.enum(["0", "1", "true", "false"]).optional() }),
|
|
response: TaskAccepted,
|
|
}),
|
|
setField: ep({
|
|
method: "put",
|
|
path: "/media-entities/{id}/fields/{field}",
|
|
scope: "organize.execute",
|
|
summary: "覆盖作品字段并锁定(自动刷新不再改写)",
|
|
params: FieldParam,
|
|
body: content.FieldOverrideInput,
|
|
response: FieldOverrideResult,
|
|
}),
|
|
clearField: ep({
|
|
method: "delete",
|
|
path: "/media-entities/{id}/fields/{field}",
|
|
scope: "organize.execute",
|
|
summary: "取消字段覆盖与锁定",
|
|
params: FieldParam,
|
|
response: FieldOverrideResult,
|
|
}),
|
|
},
|
|
contentUnits: {
|
|
...crud(
|
|
"/content-units",
|
|
"内容单元",
|
|
{
|
|
row: content.ContentUnit,
|
|
update: content.ContentUnitUpdate,
|
|
filters: { mediaEntityId: Id.optional(), seasonNumber: z.coerce.number().int().optional() },
|
|
},
|
|
R,
|
|
),
|
|
setField: ep({
|
|
method: "put",
|
|
path: "/content-units/{id}/fields/{field}",
|
|
scope: "organize.execute",
|
|
summary: "覆盖季 / 集字段并锁定(元数据刷新不再改写)",
|
|
params: UnitFieldParam,
|
|
body: content.FieldOverrideInput,
|
|
response: UnitFieldOverrideResult,
|
|
}),
|
|
clearField: ep({
|
|
method: "delete",
|
|
path: "/content-units/{id}/fields/{field}",
|
|
scope: "organize.execute",
|
|
summary: "取消季 / 集字段覆盖与锁定",
|
|
params: UnitFieldParam,
|
|
response: UnitFieldOverrideResult,
|
|
}),
|
|
},
|
|
titleAliases: {
|
|
...crud(
|
|
"/title-aliases",
|
|
"别名",
|
|
{
|
|
row: content.TitleAlias,
|
|
create: content.TitleAliasCreate,
|
|
filters: { mediaEntityId: Id.optional(), q: z.string().max(200).optional() },
|
|
},
|
|
R,
|
|
),
|
|
remove: del("/title-aliases/{id}", "删除别名"),
|
|
},
|
|
externalIdentities: {
|
|
...crud(
|
|
"/external-identities",
|
|
"外部身份",
|
|
{
|
|
row: identity.ExternalIdentity,
|
|
create: identity.ExternalIdentityCreate,
|
|
update: identity.ExternalIdentityUpdate,
|
|
filters: {
|
|
mediaEntityId: Id.optional(),
|
|
provider: z.string().optional(),
|
|
status: identity.IdentityStatus.optional(),
|
|
},
|
|
},
|
|
R,
|
|
),
|
|
revisions: ep({
|
|
method: "get",
|
|
path: "/external-identities/{id}/revisions",
|
|
scope: "read",
|
|
summary: "身份修订历史",
|
|
params: IdParam,
|
|
response: IdentityRevisionList,
|
|
}),
|
|
},
|
|
|
|
// ── 文件(只读;写入只经整理/对账流程,不开放直接改) ──
|
|
mediaAssets: crud(
|
|
"/media-assets",
|
|
"文件",
|
|
{
|
|
row: assets.MediaAsset,
|
|
filters: { mediaEntityId: Id.optional(), status: assets.AssetStatus.optional() },
|
|
},
|
|
R,
|
|
),
|
|
assetUnitCoverage: crud(
|
|
"/asset-unit-coverage",
|
|
"文件覆盖",
|
|
{
|
|
row: assets.AssetUnitCoverage,
|
|
filters: { mediaAssetId: Id.optional(), contentUnitId: Id.optional() },
|
|
},
|
|
R,
|
|
),
|
|
assetLocations: crud(
|
|
"/asset-locations",
|
|
"文件位置",
|
|
{
|
|
row: assets.AssetLocation,
|
|
filters: { mediaAssetId: Id.optional(), status: assets.LocationStatus.optional() },
|
|
},
|
|
R,
|
|
),
|
|
pathBindings: crud(
|
|
"/path-bindings",
|
|
"路径绑定",
|
|
{
|
|
row: assets.PathBinding,
|
|
filters: { mediaEntityId: Id.optional(), status: assets.BindingStatus.optional() },
|
|
},
|
|
R,
|
|
),
|
|
} as const;
|