50 lines
1.7 KiB
TypeScript
50 lines
1.7 KiB
TypeScript
import type { ParsedRelease } from "../release-parser/types.ts";
|
|
import { compareRank, currentPri, qualityTier, softRank } from "./evaluate.ts";
|
|
import type { QualityFacts, SlotSpec } from "./types.ts";
|
|
|
|
/** 缺少关键规格时不能声称同套;集号、文件名、种子 ID 不属于版本身份。 */
|
|
export function seasonReleaseKey(q: QualityFacts): string | null {
|
|
if (!q.resolution || !q.source || !q.videoCodec || !q.releaseGroup?.name) return null;
|
|
return JSON.stringify([
|
|
q.resolution,
|
|
q.source,
|
|
q.videoCodec,
|
|
q.releaseGroup.name
|
|
.toLowerCase()
|
|
.split("@")
|
|
.map((g) => g.trim())
|
|
.sort(),
|
|
[...(q.hdr ?? [])].sort(),
|
|
q.cut ?? "default",
|
|
]);
|
|
}
|
|
|
|
export function upgradeSpec(spec: SlotSpec): SlotSpec {
|
|
return {
|
|
...spec,
|
|
...(spec.upgradeRules ? { rules: spec.upgradeRules } : {}),
|
|
...(spec.upgradeHard ? { hard: spec.upgradeHard } : {}),
|
|
};
|
|
}
|
|
|
|
/** 优先级、软偏好、规范化规格形成稳定顺序;同档对齐不允许质量降档。 */
|
|
export function selectSeasonRelease(spec: SlotSpec, versions: readonly QualityFacts[]): QualityFacts | undefined {
|
|
let target: QualityFacts | undefined;
|
|
const rank = (q: QualityFacts) => {
|
|
const tier = qualityTier(q, spec);
|
|
return [
|
|
currentPri(spec, q),
|
|
tier.source,
|
|
tier.resolution,
|
|
...softRank(spec, { raw: "", hdr: [], audio: [], ...q } as unknown as ParsedRelease),
|
|
];
|
|
};
|
|
for (const q of versions) {
|
|
const key = seasonReleaseKey(q);
|
|
if (!key) continue;
|
|
const compared = target ? compareRank(rank(q), rank(target)) : 1;
|
|
if (compared > 0 || (compared === 0 && key < seasonReleaseKey(target!)!)) target = q;
|
|
}
|
|
return target;
|
|
}
|