Merge branch 'scr1'

Co-Authored-By: Claude Fable 5.1 <[email protected]>

# Conflicts:
#	CHANGELOG.md
#	docs/plan/00-first-version-plan.md
This commit is contained in:
root committed 2026-09-30 22:36:46 +08:00
commit 2e83107f68
45 files changed
+2867 -41

No files matched your search

@@ -0,0 +1,38 @@
import type { Kysely } from "kysely";
import { execDdl } from "../src/migration-helpers.ts";
// SCR-1 刮削:每部作品最近一次刮削(往媒体库目录写 NFO 与图片)的状态与逐文件结果。
// 一部作品一行,重新刮削覆盖;历史看审计(organize.scrape)与引擎运行记录。
// biome-ignore lint/suspicious/noExplicitAny: 迁移不依赖应用表类型
export async function up(db: Kysely<any>): Promise<void> {
await execDdl(
db,
`create table if not exists media_scrape (
media_entity_id uuid primary key references media_entity (id) on delete cascade,
status text not null default 'queued' check (status in ('queued', 'running', 'succeeded', 'partial', 'failed')),
trigger text not null default 'manual' check (trigger in ('auto', 'manual')),
mode text not null default 'missing' check (mode in ('missing', 'overwrite')),
record_id uuid references organization_record (id) on delete set null,
engine_run_id text,
requested_at timestamptz not null default now(),
started_at timestamptz,
finished_at timestamptz,
written integer not null default 0,
skipped integer not null default 0,
failed integer not null default 0,
reason text,
files jsonb not null default '[]'::jsonb,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
drop trigger if exists media_scrape_touch_updated_at on media_scrape;
create trigger media_scrape_touch_updated_at before update on media_scrape
for each row execute function umt_touch_updated_at();`,
);
}
// biome-ignore lint/suspicious/noExplicitAny: 同上
export async function down(db: Kysely<any>): Promise<void> {
await execDdl(db, "drop table if exists media_scrape;");
}
+26
View File
@@ -159,6 +159,9 @@ export type MediaAssetKind = "video" | "bluray_dir" | "subtitle" | "audio" | "nf
export type MediaAssetStatus = "active" | "replaced" | "retired" | "missing";
export type MediaEntityKind = "movie" | "series" | "variety" | "collection" | "other";
export type MediaEntityStatus = "provisional" | "active" | "merged" | "archived";
export type MediaScrapeStatus = "queued" | "running" | "succeeded" | "partial" | "failed";
export type MediaScrapeTrigger = "auto" | "manual";
export type MediaScrapeMode = "missing" | "overwrite";
export type MediaServerInstanceKind = "emby" | "jellyfin";
export type MediaServerInstanceHealthStatus = "unknown" | "healthy" | "degraded" | "offline";
export type MetadataEnrichmentStatus = "suggested" | "applied" | "failed";
@@ -915,6 +918,25 @@ export interface MediaEntityTable {
naming_override: Json | null;
}
export interface MediaScrapeTable {
media_entity_id: string;
status: Generated<MediaScrapeStatus>;
trigger: Generated<MediaScrapeTrigger>;
mode: Generated<MediaScrapeMode>;
record_id: string | null;
engine_run_id: string | null;
requested_at: GeneratedTimestamptz;
started_at: Timestamptz | null;
finished_at: Timestamptz | null;
written: Generated<number>;
skipped: Generated<number>;
failed: Generated<number>;
reason: string | null;
files: Generated<Json>;
created_at: GeneratedTimestamptz;
updated_at: GeneratedTimestamptz;
}
export interface MediaServerInstanceTable {
id: Generated<string>;
name: string;
@@ -1698,6 +1720,7 @@ export interface DB {
mcp_server_config: McpServerConfigTable;
media_asset: MediaAssetTable;
media_entity: MediaEntityTable;
media_scrape: MediaScrapeTable;
media_server_instance: MediaServerInstanceTable;
metadata_enrichment: MetadataEnrichmentTable;
metadata_field: MetadataFieldTable;
@@ -1858,6 +1881,9 @@ export type MediaAssetUpdate = Updateable<MediaAssetTable>;
export type MediaEntityRow = Selectable<MediaEntityTable>;
export type NewMediaEntity = Insertable<MediaEntityTable>;
export type MediaEntityUpdate = Updateable<MediaEntityTable>;
export type MediaScrapeRow = Selectable<MediaScrapeTable>;
export type NewMediaScrape = Insertable<MediaScrapeTable>;
export type MediaScrapeUpdate = Updateable<MediaScrapeTable>;
export type MediaServerInstanceRow = Selectable<MediaServerInstanceTable>;
export type NewMediaServerInstance = Insertable<MediaServerInstanceTable>;
export type MediaServerInstanceUpdate = Updateable<MediaServerInstanceTable>;
+3
View File
@@ -26,6 +26,7 @@ const EXPECTED_TABLES = [
"path_mapping",
// 内容 / 身份
"media_entity",
"media_scrape",
"content_unit",
"title_alias",
"external_identity",
@@ -153,6 +154,8 @@ const NON_ENTITY_TABLES = [
"kv_cache",
// 站点请求计数:(site_id, hour) 主键
"site_request_count",
// 作品最近一次刮削:media_entity_id 主键(SCR-1)
"media_scrape",
];
describe.skipIf(skip)("schema migrations (real PG)", () => {