fix(identity): persist verified auxiliary season mappings and reuse source ids
This commit is contained in:
1 parent
c85b139ec4
commit
ee0d62ae6f
15 files changed
+397
-38
No files matched your search
@@ -0,0 +1,24 @@
|
||||
import type { Kysely } from "kysely";
|
||||
import { execDdl } from "../src/migration-helpers.ts";
|
||||
|
||||
// Bangumi/豆瓣按分季建条目,一个 TMDB 作品可关联多个来源 ID;来源 ID 仍全局唯一。
|
||||
// biome-ignore lint/suspicious/noExplicitAny: 迁移不依赖应用表类型
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await execDdl(
|
||||
db,
|
||||
`drop index external_identity_entity_accepted_key;
|
||||
create unique index external_identity_entity_accepted_key on external_identity (media_entity_id, provider, entity_type)
|
||||
where status = 'accepted' and media_entity_id is not null and provider not in ('bangumi', 'douban');`,
|
||||
);
|
||||
}
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: 同上
|
||||
export async function down(db: Kysely<any>): Promise<void> {
|
||||
// 已有多分季映射时唯一索引重建会拒绝回退,不删除或猜测保留哪条身份。
|
||||
await execDdl(
|
||||
db,
|
||||
`drop index external_identity_entity_accepted_key;
|
||||
create unique index external_identity_entity_accepted_key on external_identity (media_entity_id, provider, entity_type)
|
||||
where status = 'accepted' and media_entity_id is not null;`,
|
||||
);
|
||||
}
|
||||
@@ -647,6 +647,12 @@ function walkTokens(tokens: string[], d: Draft): void {
|
||||
stop("complete");
|
||||
continue;
|
||||
}
|
||||
if ((u === "BATCH" || u === "合集" || u === "全集") && d.episodes) {
|
||||
d._complete = true;
|
||||
ev.push("pack:batch");
|
||||
stop("complete");
|
||||
continue;
|
||||
}
|
||||
if ((u === "FIN" || u === "END") && d.episodes) {
|
||||
d._fin = true;
|
||||
ev.push("pack:fin");
|
||||
@@ -1017,6 +1023,13 @@ export function parseRelease(input: string, opts: ParseOptions = {}): ParsedRele
|
||||
ev.push("pack:fin");
|
||||
return MARK_HARD;
|
||||
});
|
||||
// BT 动漫明确区间:名称后的「 - 01-12」不是片名,Batch/合集标记另决定是否整季包。
|
||||
s = s.replace(/\s-\s(\d{1,3})(?:v\d)?\s*[-~]\s*(\d{1,3})(?:v\d)?(?=\s|\[|【|$)/u, (all, a: string, b: string) => {
|
||||
if (d.episodes || Number(b) < Number(a)) return all;
|
||||
d.episodes = { start: Number(a), end: Number(b) };
|
||||
ev.push("episode:anime_dash_range");
|
||||
return MARK_HARD;
|
||||
});
|
||||
// `Travis - 12 Memories`:数字后紧跟一个普通单词时是片名的一部分,不是集号
|
||||
s = s.replace(
|
||||
/\s-\s(\d{1,3})(?:v\d)?(?=\s|\[|【|$)(?!\s+(?!(?:END|Fin|Final|RAW)\b)[A-Za-z][a-z]+\b)/u,
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { ContentType } from "@umt/contracts";
|
||||
import type { CompiledGlobalWord } from "../identify-words/apply.ts";
|
||||
|
||||
/** 解析器版本:规则变化时递增,缓存/识别结果按此失效 */
|
||||
export const PARSER_VERSION = 2;
|
||||
export const PARSER_VERSION = 3;
|
||||
|
||||
export type Resolution = "4320p" | "2160p" | "1440p" | "1080p" | "1080i" | "720p" | "576p" | "480p";
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
expandEpisodes,
|
||||
fileKindOf,
|
||||
OffsetExpressionError,
|
||||
PARSER_VERSION,
|
||||
type ParsedRelease,
|
||||
parseRelease,
|
||||
parseReleasePath,
|
||||
@@ -742,7 +743,7 @@ describe("parseRelease 样本表", () => {
|
||||
it(`${s.id} ${s.input}${s.deviation ? ` [deviation: ${s.deviation}]` : ""}`, () => {
|
||||
const r = parseRelease(s.input, s.subtitle ? { subtitle: s.subtitle } : {});
|
||||
check(r, s.expect);
|
||||
expect(r.parserVersion).toBe(2);
|
||||
expect(r.parserVersion).toBe(PARSER_VERSION);
|
||||
expect(r.raw).toBe(s.input);
|
||||
});
|
||||
}
|
||||
@@ -936,3 +937,32 @@ describe("辅助函数", () => {
|
||||
expect(parseRelease("12").episodes).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
// BT 发布的原编号保持来源事实;不根据作品季度或分辨率改写。
|
||||
describe("BT 动漫复杂命名", () => {
|
||||
it("dash 范围和 Batch 合集", () => {
|
||||
const parsed = parseRelease("[SubsPlease] Dr. Stone - 01-12 [1080p] [Batch]");
|
||||
expect(parsed.title).toBe("Dr Stone");
|
||||
expect(parsed.episodes).toEqual({ start: 1, end: 12 });
|
||||
expect(parsed.packHint).toBe("season_pack");
|
||||
expect(parsed.evidence).toContain("episode:anime_dash_range");
|
||||
});
|
||||
it("方括号范围加中文合集", () => {
|
||||
const parsed = parseRelease("[Group][葬送的芙莉莲][01-28][1080p][合集]");
|
||||
expect(parsed.titleCn).toBe("葬送的芙莉莲");
|
||||
expect(parsed.episodes).toEqual({ start: 1, end: 28 });
|
||||
expect(parsed.packHint).toBe("season_pack");
|
||||
});
|
||||
it("双语、分季、v2 与发布组保留", () => {
|
||||
const parsed = parseRelease(
|
||||
"[喵萌奶茶屋] 药屋少女的呢喃 第二季 / Kusuriya no Hitorigoto 2nd Season - 05v2 [1080p][HEVC-10bit][简繁内封]",
|
||||
);
|
||||
expect(parsed.titleCn).toBe("药屋少女的呢喃");
|
||||
expect(parsed.season).toBe(2);
|
||||
expect(parsed.episodes).toEqual({ start: 5, end: 5 });
|
||||
expect(parsed.releaseGroup?.name).toBe("喵萌奶茶屋");
|
||||
});
|
||||
it("小数特别集不猜成普通集", () => {
|
||||
expect(parseRelease("[Group] Sousou no Frieren - 05.5 [1080p]").episodes).toBeUndefined();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user