feat(copy): 处理状态的「入库」改为「整理」,术语表与 check:copy 同步
真正入库取决于媒体服务器有没有扫到,本工具只负责整理(元数据、NFO 与图片、按规则归到目录)。 界面与面向用户的服务端文案里「已入库 / 未入库 / 部分入库 / 入库失败 / 入库中 / 入库后 / 原地入库…」 改为「已整理 / 未整理 / 部分整理 / 整理失败 / 整理中 / 整理后 / 原地整理…」;文件管理快速筛选「已整理」、 目录副行「n 个已整理 / 未整理」、季卡片「已整理 x/y」。代码标识符不改,「Emby 已有」这类媒体服务器状态保留。 glossary 加「整理」口径条目;check:copy 拦处理状态语境的「入库」搭配,其它线待替换的文件暂列 TERM_PENDING。 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
79c3b8c9b9
commit
550ac285f4
67 files changed
+171
-143
No files matched your search
@@ -45,9 +45,9 @@ export function seasonLine(s: Pick<EpisodeStructureSeason, "airDate" | "episodeC
|
||||
return [s.airDate ? s.airDate.slice(0, 4) : null, `${s.episodeCount} 集`].filter(Boolean).join(" · ");
|
||||
}
|
||||
|
||||
/** 已入库 x/y;一集都没有时返回 null(只列非零项) */
|
||||
/** 已整理 x/y;一集都没有时返回 null(只列非零项) */
|
||||
export function inLibraryText(s: Pick<EpisodeStructureSeason, "inLibrary" | "episodeCount">): string | null {
|
||||
return s.inLibrary > 0 ? `已入库 ${s.inLibrary}/${s.episodeCount}` : null;
|
||||
return s.inLibrary > 0 ? `已整理 ${s.inLibrary}/${s.episodeCount}` : null;
|
||||
}
|
||||
|
||||
const pad = (n: number) => String(n).padStart(2, "0");
|
||||
@@ -63,5 +63,5 @@ export function originText(
|
||||
|
||||
/** 切换确认的说明:改的是作品设置,影响季表、集数映射、订阅与刮削 */
|
||||
export function switchDescription(target: string): string {
|
||||
return `作品改按「${target}」分季:季与集按 TMDB 原季集迁到新位置,已入库文件跟着走;集数映射、订阅和刮削都按新季集,已绑定的资源会重新换算。之后可以再切回来。`;
|
||||
return `作品改按「${target}」分季:季与集按 TMDB 原季集迁到新位置,已整理文件跟着走;集数映射、订阅和刮削都按新季集,已绑定的资源会重新换算。之后可以再切回来。`;
|
||||
}
|
||||
@@ -110,7 +110,7 @@ describe("季集结构:纯函数", () => {
|
||||
it("季卡片文案与原季集对照", () => {
|
||||
expect(seasonLine({ airDate: "2024-07-07", episodeCount: 13 })).toBe("2024 · 13 集");
|
||||
expect(inLibraryText({ inLibrary: 0, episodeCount: 13 })).toBeNull();
|
||||
expect(inLibraryText({ inLibrary: 3, episodeCount: 13 })).toBe("已入库 3/13");
|
||||
expect(inLibraryText({ inLibrary: 3, episodeCount: 13 })).toBe("已整理 3/13");
|
||||
expect(originText(2, { episodeNumber: 2, tmdbSeason: 1, tmdbEpisode: 14 })).toBe("原 S01E14");
|
||||
expect(originText(1, { episodeNumber: 2, tmdbSeason: 1, tmdbEpisode: 2 })).toBeNull();
|
||||
});
|
||||
@@ -131,14 +131,14 @@ describe("季集结构:组件", () => {
|
||||
expect(html).toContain('aria-label="当前"');
|
||||
});
|
||||
|
||||
it("季卡片:季名、首播年 · 集数、已入库 x/y,选中的高亮", () => {
|
||||
it("季卡片:季名、首播年 · 集数、已整理 x/y,选中的高亮", () => {
|
||||
const html = renderToStaticMarkup(
|
||||
createElement(SeasonCardGrid, { seasons: structure.seasons, selected: 2, onPick: () => {} }),
|
||||
);
|
||||
expect(html).toContain("第一部");
|
||||
expect(html).toContain("2024 · 12 集");
|
||||
expect(html).toContain("已入库 1/13");
|
||||
expect(html).not.toContain("已入库 0/12");
|
||||
expect(html).toContain("已整理 1/13");
|
||||
expect(html).not.toContain("已整理 0/12");
|
||||
expect(html).toMatch(/aria-pressed="true"[^>]*class="[^"]*pill-selected/);
|
||||
});
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ export function StructurePreview({ seasons }: { seasons: EpisodeStructureSeason[
|
||||
overview: null,
|
||||
summary: (
|
||||
<StatusBadge tone={s.episodeCount && s.inLibrary >= s.episodeCount ? "success" : "neutral"}>
|
||||
已入库 {s.inLibrary}/{s.episodeCount}
|
||||
已整理 {s.inLibrary}/{s.episodeCount}
|
||||
</StatusBadge>
|
||||
),
|
||||
}}
|
||||
@@ -171,7 +171,7 @@ export function StructurePreview({ seasons }: { seasons: EpisodeStructureSeason[
|
||||
runtime: null,
|
||||
stillPath: null,
|
||||
voteAverage: null,
|
||||
status: e.inLibrary ? { label: "已入库", tone: "success" } : { label: "未入库", tone: "neutral" },
|
||||
status: e.inLibrary ? { label: "已整理", tone: "success" } : { label: "未整理", tone: "neutral" },
|
||||
extra: originText(s.seasonNumber, e) ? (
|
||||
<p className="mt-0.5 font-mono text-meta text-muted-foreground">
|
||||
{originText(s.seasonNumber, e)}
|
||||
@@ -228,7 +228,7 @@ export function EpisodeStructureSwitcher({ entityId, children }: { entityId: str
|
||||
<div className="space-y-3">
|
||||
<div className="flex flex-wrap items-center justify-between gap-2 rounded-xl border border-dashed border-border px-3 py-2">
|
||||
<p className="text-caption text-muted-foreground">
|
||||
预览「{target?.label ?? DEFAULT_STRUCTURE_LABEL}」的分季,已入库按 TMDB 原季集对照。
|
||||
预览「{target?.label ?? DEFAULT_STRUCTURE_LABEL}」的分季,已整理按 TMDB 原季集对照。
|
||||
</p>
|
||||
<Button size="sm" disabled={setGroup.isPending} onClick={() => setConfirm(true)}>
|
||||
改用这套结构
|
||||
|
||||
@@ -240,7 +240,7 @@ export function ExternalTab() {
|
||||
empty={{
|
||||
icon: Fingerprint,
|
||||
title: "没有外部身份",
|
||||
description: "没有外部编号的作品也能入库。",
|
||||
description: "没有外部编号的作品也能整理。",
|
||||
}}
|
||||
hasMore={list.hasNextPage}
|
||||
onLoadMore={() => list.fetchNextPage()}
|
||||
|
||||
@@ -106,8 +106,8 @@ export const DOWNLOAD_STATUS: Record<DownloadStatus, ToneLabel> = {
|
||||
paused: { label: "已暂停", tone: "warning" },
|
||||
stalled: { label: "无进展", tone: "warning" },
|
||||
completed: { label: "下载完成", tone: "neutral" },
|
||||
importing: { label: "入库中", tone: "neutral" },
|
||||
imported: { label: "已入库", tone: "success" },
|
||||
importing: { label: "整理中", tone: "neutral" },
|
||||
imported: { label: "已整理", tone: "success" },
|
||||
failed: { label: "失败", tone: "destructive" },
|
||||
removed: { label: "已移除", tone: "neutral" },
|
||||
missing: { label: "下载器中缺失", tone: "warning" },
|
||||
@@ -334,10 +334,10 @@ export const opts = <K extends string>(rec: Record<K, string | { label: string }
|
||||
|
||||
/** 收录版本 / 候选的原因串(如 `blocked:no_main_video`、`deferred:slot_busy;inflight:<id>`)→ 中文;不认识的原样显示 */
|
||||
const SLOT_REASON: Record<string, string> = {
|
||||
"blocked:no_main_video": "没有可入库的主视频",
|
||||
"blocked:no_main_video": "没有可整理的主视频",
|
||||
"deferred:slot_busy": "已有计划在途,等它结束再评估",
|
||||
verified: "已核验入库",
|
||||
verified_partial: "部分核验入库",
|
||||
verified: "已核验整理",
|
||||
verified_partial: "部分核验整理",
|
||||
hard_conditions_met: "硬条件全部满足",
|
||||
};
|
||||
export function slotReasonText(raw: string): string {
|
||||
|
||||
@@ -41,7 +41,7 @@ const ROLE: Record<string, string> = {
|
||||
episode_thumb: "剧照",
|
||||
};
|
||||
|
||||
const SOURCE: Record<string, string> = { library: "已入库的作品", auto: "按路径识别", chosen: "手动指定" };
|
||||
const SOURCE: Record<string, string> = { library: "已整理的作品", auto: "按路径识别", chosen: "手动指定" };
|
||||
|
||||
export function scrapeCounts(s: Pick<ScrapeRecord, "written" | "skipped" | "failed">): string {
|
||||
return [
|
||||
@@ -153,7 +153,7 @@ export function ScrapePanel({ detail }: { detail: LibraryDetail }) {
|
||||
title="刮削"
|
||||
description={
|
||||
s?.finishedAt
|
||||
? `上次刮削 ${formatDateTime(s.finishedAt)} · ${s.trigger === "auto" ? "入库后自动" : "手动"}`
|
||||
? `上次刮削 ${formatDateTime(s.finishedAt)} · ${s.trigger === "auto" ? "整理后自动" : "手动"}`
|
||||
: "NFO 和图片写进作品目录,Emby、Jellyfin、Kodi 直接读取。"
|
||||
}
|
||||
actions={
|
||||
|
||||
@@ -109,7 +109,7 @@ function VersionDetail({ v, match }: { v: AssetVersion; match?: UnitMatch | unde
|
||||
{ label: "字幕", value: v.subtitleLanguages.map(langLabel).join("、") || null },
|
||||
{ label: "时长", value: duration(v.durationSec) },
|
||||
{ label: "色深", value: v.bitDepth ? `${v.bitDepth} bit` : null },
|
||||
{ label: "入库时间", value: formatDateTime(v.organizedAt) },
|
||||
{ label: "整理时间", value: formatDateTime(v.organizedAt) },
|
||||
{
|
||||
label: "下载任务",
|
||||
value: v.downloadTaskId ? (
|
||||
@@ -192,7 +192,7 @@ export function VersionList({
|
||||
<PaginatedList
|
||||
rows={versions}
|
||||
as="ul"
|
||||
label="入库文件版本"
|
||||
label="已整理文件版本"
|
||||
resetKey={match?.assetId ?? "all"}
|
||||
compact={compact}
|
||||
className="space-y-0.5"
|
||||
@@ -296,7 +296,7 @@ export function MovieVersionsPanel({ entityId }: { entityId: string }) {
|
||||
);
|
||||
const state = match?.state === "satisfied" ? `符合「${target?.name}」` : gapLine(match);
|
||||
return (
|
||||
<Panel title="入库版本" description={[summaryText(data.summary), state].filter(Boolean).join(" · ")}>
|
||||
<Panel title="已整理版本" description={[summaryText(data.summary), state].filter(Boolean).join(" · ")}>
|
||||
<div className="-mx-2">
|
||||
<VersionList versions={versions} match={match} />
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user