feat(library): show stored versions per episode and movie (LIBV-1)
- domain versionSpecOf: file name + ffprobe + ingest quality -> version spec;
summarizeVersions; matchVersions (satisfied / missing / upgradeable, single target)
- GET /library/{id}/versions: per-season/episode versions, summaries, matches[]
- organize writes full spec into media_asset.delivery (specVersion 1)
- scripts/asset-spec-backfill.ts: dry-run by default, --probe local only, --apply
- web: season summary line, one-line spec per episode, N versions expand,
tech info details (TODO: DEAI-2 TechInfo), movie versions panel
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
3763c86481
commit
bf9e73e86e
19 files changed
+2060
-9
No files matched your search
@@ -0,0 +1,55 @@
|
||||
// LIBV-1 回填已入库视频资产的版本规格(media_asset.delivery)。默认只读(dry-run),加 --apply 才改库。
|
||||
//
|
||||
// 用法(DATABASE_URL 必须显式给出,脚本不带默认库):
|
||||
// DATABASE_URL=… deno run -A scripts/asset-spec-backfill.ts # 看清单:哪些资产会更新、前后规格
|
||||
// DATABASE_URL=… deno run -A scripts/asset-spec-backfill.ts --entity <作品 id> # 只看一部作品
|
||||
// DATABASE_URL=… deno run -A scripts/asset-spec-backfill.ts --probe # 对缺探测结果的本地文件跑 ffprobe(只读文件)
|
||||
// DATABASE_URL=… deno run -A scripts/asset-spec-backfill.ts --apply # 写库
|
||||
// --json 输出 JSON;--limit N 只处理前 N 个资产
|
||||
//
|
||||
// 规格来源:库内文件名解析 + 已有 media_info.probe + 入库时记下的资源解析(media_info._umt.quality)。
|
||||
// 不请求任何站点;--probe 只读库根里的本地文件。写回只合并 delivery 的键,可重复执行。
|
||||
|
||||
import { ffprobe } from "@umt/adapters";
|
||||
import { createDb } from "@umt/db";
|
||||
import { backfillVersionSpecs } from "../apps/server/src/modules/acquisition-organize/services/version-backfill.ts";
|
||||
|
||||
const argv = [...Deno.args];
|
||||
const APPLY = argv.includes("--apply");
|
||||
if (APPLY && argv.includes("--dry-run")) {
|
||||
console.error("--apply 与 --dry-run 不能同时给出");
|
||||
Deno.exit(2);
|
||||
}
|
||||
const arg = (k: string) => {
|
||||
const i = argv.indexOf(k);
|
||||
return i >= 0 ? argv[i + 1] : undefined;
|
||||
};
|
||||
const url = Deno.env.get("DATABASE_URL");
|
||||
if (!url) {
|
||||
console.error("需要 DATABASE_URL(脚本不带默认库)");
|
||||
Deno.exit(2);
|
||||
}
|
||||
const db = createDb({ connectionString: url, max: 2 });
|
||||
try {
|
||||
const report = await backfillVersionSpecs(db, {
|
||||
apply: APPLY,
|
||||
entityId: arg("--entity"),
|
||||
limit: arg("--limit") ? Number(arg("--limit")) : undefined,
|
||||
probe: argv.includes("--probe") ? (p) => ffprobe(p, { timeoutMs: 30_000 }) : undefined,
|
||||
});
|
||||
if (argv.includes("--json")) console.log(JSON.stringify(report, null, 2));
|
||||
else {
|
||||
console.log(`# asset-spec-backfill (${APPLY ? "APPLY" : "DRY-RUN"})\n`);
|
||||
console.log(
|
||||
`扫描 ${report.scanned} 个视频资产:已是当前口径 ${report.upToDate},${APPLY ? "已更新" : "将更新"} ${report.changed}` +
|
||||
`,本次探测 ${report.probed},无库内位置 ${report.noLocation}\n`,
|
||||
);
|
||||
for (const it of report.items) {
|
||||
console.log(`- [${it.reason}] ${it.entityTitle ?? "(无作品)"} · ${it.path ?? it.assetId}`);
|
||||
console.log(` 前:${it.before}`);
|
||||
console.log(` 后:${it.after}(来源 ${it.specFrom.join("+") || "无"})`);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
await db.destroy();
|
||||
}
|
||||
Reference in new issue
Block a user