Skip to content

Commit 277030f

Browse files
committed
core: render stream metadata from provider and TMDB facts
1 parent 575c884 commit 277030f

1 file changed

Lines changed: 31 additions & 0 deletions

File tree

engine_v2/src/resolver-core.mjs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { normalizeResolveRequest, normalizeStreamCandidate } from "./contracts.m
22
import { addEvidenceError, newEvidenceRecord, recordStage, summarizeEvidence } from "./evidence.mjs";
33
import { validateMediaCandidates } from "./media-validator.mjs";
44
import { planRepair } from "./repair-brain.mjs";
5+
import { presentStreamCandidates } from "./stream-presentation.mjs";
56

67
const PIPELINE = Object.freeze(["homepage", "search", "identity", "detail", "episode", "player", "media", "validation"]);
78

@@ -10,6 +11,10 @@ export class ResolverCore {
1011
this.maxRepairHypotheses = Math.max(1, Math.min(3, Number(options.maxRepairHypotheses ?? 3)));
1112
this.mediaValidator = options.mediaValidator ?? validateMediaCandidates;
1213
this.mediaValidationOptions = options.mediaValidationOptions ?? {};
14+
// Optional shared metadata resolver (normally TMDB-backed). Metadata enriches
15+
// presentation only: a metadata outage must never turn a playable provider into
16+
// a provider failure or fabricate media facts.
17+
this.metadataResolver = typeof options.metadataResolver === "function" ? options.metadataResolver : null;
1318
}
1419

1520
async resolve({ provider, adapter, request, fixtureId = "adhoc", clientRef = "unknown", runtimeCompatibility = null }) {
@@ -36,6 +41,15 @@ export class ResolverCore {
3641
streams: [],
3742
};
3843

44+
if (this.metadataResolver) {
45+
try {
46+
const metadata = await this.metadataResolver(canonical);
47+
if (metadata && typeof metadata === "object") context.state.coreMetadata = metadata;
48+
} catch (error) {
49+
context.state.coreMetadataError = String(error?.message ?? error);
50+
}
51+
}
52+
3953
try {
4054
if (typeof adapter.discover === "function") {
4155
const discovery = await adapter.discover(context);
@@ -71,6 +85,7 @@ export class ResolverCore {
7185

7286
if (stage === "media") {
7387
context.streams = normalizeStreams(result, provider.id);
88+
context.streams = presentStreamCandidates(context.streams, presentationMetadata(context), provider);
7489
evidence.playableStreams = 0;
7590
recordStage(evidence, stage, stageEvidence(stage, { ...asObject(result), streams: context.streams }));
7691
} else if (stage === "validation") {
@@ -192,6 +207,22 @@ function normalizeStreams(result, providerId) {
192207
return out;
193208
}
194209

210+
function presentationMetadata(context) {
211+
const request = context.request ?? {};
212+
const shared = context.state.coreMetadata && typeof context.state.coreMetadata === "object"
213+
? context.state.coreMetadata
214+
: {};
215+
const providerMetadata = context.state.metadata && typeof context.state.metadata === "object"
216+
? context.state.metadata
217+
: {};
218+
return {
219+
title: request.title ?? null,
220+
year: request.year ?? null,
221+
...shared,
222+
...providerMetadata,
223+
};
224+
}
225+
195226
function applyValidationResult(context, result = {}) {
196227
const rows = Array.isArray(result.results) ? result.results : [];
197228
const byUrl = new Map(rows.map((row) => [row?.candidate?.url, row?.validation]));

0 commit comments

Comments
 (0)