feat(scrape): 任意目录就地刮削,按路径识别作品,每次刮削一条记录(SCR-2)
- POST /files/scrape 改为对目录 / 视频文件刮削:已登记用作品,否则按路径识别(本地 + TMDB), 认不准返回候选,选定后再提交;未登记直接用 TMDB 字段,addToLibrary 顺手建作品 - 作品详情重新刮削、入库后自动刮削改为对作品目录刮削,同一实现 - 迁移 0058_scrape_record 替代 media_scrape;GET /files/scrape-records - 与 MP ScrapingChain 的文件布局差分(7 个场景,3 处登记偏离) Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
f60254e265
commit
87bf33b42b
29 files changed
+2272
-653
No files matched your search
@@ -22,6 +22,7 @@ import { EventBus } from "../../src/http/sse.ts";
|
||||
import { createLogger } from "../../src/logger.ts";
|
||||
import { fakeEngine } from "../../src/modules/acquisition-organize/__tests__/harness.ts";
|
||||
import { executeRecord, type FrozenPlan } from "../../src/modules/acquisition-organize/services/organize.ts";
|
||||
import { runScrapeRecord } from "../../src/modules/acquisition-organize/services/scrape.ts";
|
||||
import { createCapabilityRegistry } from "../../src/modules/agent/capability-registry.ts";
|
||||
import { createFileManagerModule, type FmOverrides } from "../../src/modules/file-manager/index.ts";
|
||||
import type { ServerContext } from "../../src/modules/types.ts";
|
||||
@@ -57,6 +58,17 @@ export async function pgAvailable() {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: 测试断言直接读响应 JSON
|
||||
type Loose = any;
|
||||
|
||||
/** catalog.lookup 远端候选(测试用) */
|
||||
export interface RemoteHit {
|
||||
provider: string;
|
||||
entityType: "movie" | "tv";
|
||||
externalId: string;
|
||||
title: string;
|
||||
originalTitle?: string | null;
|
||||
year: number | null;
|
||||
posterPath?: string | null;
|
||||
}
|
||||
|
||||
export interface FmHarness {
|
||||
db: Kysely<DB>;
|
||||
engine: ReturnType<typeof fakeEngine>;
|
||||
@@ -80,7 +92,11 @@ export async function createFmHarness(
|
||||
name: string,
|
||||
overrides: FmOverrides = {},
|
||||
/** runTransfers(默认 true):假引擎收到 /files 移动/复制的 verifyAndImport 时就地执行(模拟 worker) */
|
||||
opts: { catalog?: boolean; runTransfers?: boolean } = {},
|
||||
opts: {
|
||||
/** true = 内置假 catalog.lookup("Remote Film");函数 = 自定义远端候选(按查询词返回) */
|
||||
catalog?: boolean | ((query: string) => RemoteHit[]);
|
||||
runTransfers?: boolean;
|
||||
} = {},
|
||||
): Promise<FmHarness> {
|
||||
const schema = `fm_test_${name}_${process.pid.toString(36)}${Math.random().toString(36).slice(2, 7)}`;
|
||||
const admin = new pg.Client({ connectionString: DB_URL });
|
||||
@@ -124,9 +140,12 @@ export async function createFmHarness(
|
||||
if (opts.catalog)
|
||||
capabilities.register(capabilitySpec("catalog.lookup"), async (input) => ({
|
||||
local: [],
|
||||
remote: String(input.query).includes("Remote")
|
||||
? [{ provider: "tmdb", entityType: "movie" as const, externalId: "999", title: "Remote Film", year: 2019 }]
|
||||
: [],
|
||||
remote:
|
||||
typeof opts.catalog === "function"
|
||||
? opts.catalog(String(input.query))
|
||||
: String(input.query).includes("Remote")
|
||||
? [{ provider: "tmdb", entityType: "movie" as const, externalId: "999", title: "Remote Film", year: 2019 }]
|
||||
: [],
|
||||
}));
|
||||
const ctx: ServerContext = {
|
||||
role: "all",
|
||||
@@ -173,6 +192,9 @@ export async function createFmHarness(
|
||||
engine.enqueue = async (task, input, o) => {
|
||||
const r = await enqueue(task, input, o);
|
||||
const recordId = (input as { recordId?: string }).recordId;
|
||||
// SCR-2 刮削:模拟 worker 就地执行 scrapeMedia
|
||||
if (task === "scrapeMedia" && recordId)
|
||||
setTimeout(() => void runScrapeRecord(module.deps().ao, recordId).catch(() => {}), 0);
|
||||
if (task === "verifyAndImport" && recordId)
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
|
||||
Reference in new issue
Block a user