mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 02:46:16 -08:00
fix(tmdb): address PR review — best-effort fallback fetch, /embed/ scope, names-only trigger
- A failing original-language fallback fetch no longer costs the already-fetched primary details payload (Codex P2) — it is wrapped best-effort and the primary payload is returned on error. - The YouTube Referer shim now scopes to /embed/ paths, so regular www.youtube.com requests keep their real (missing) Referer (greptile). - seasonNeedsTextFallback also triggers when episode overviews exist but ALL episode names are empty (partially translated seasons; greptile). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
28177c391b
commit
7d868d77fe
5 files changed
+64
-14
No files matched your search
@@ -281,6 +281,21 @@ describe('request header overrides', () => {
|
||||
expect(headers['Referer']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('does not inject the Referer for non-embed YouTube paths', async () => {
|
||||
const { registerStaticHeaderShims } = await import(
|
||||
'./request-header-overrides.service'
|
||||
);
|
||||
|
||||
registerStaticHeaderShims();
|
||||
const listener = mockOnBeforeSendHeaders.mock.calls[0][1];
|
||||
const headers = runHeaderListener(
|
||||
listener,
|
||||
'https://www.youtube.com/watch?v=abc123'
|
||||
);
|
||||
|
||||
expect(headers['Referer']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('does not inject the embed Referer for non-YouTube hosts', async () => {
|
||||
const { registerStaticHeaderShims } = await import(
|
||||
'./request-header-overrides.service'
|
||||
|
||||
@@ -77,13 +77,18 @@ function applyYoutubeEmbedRefererShim(
|
||||
url: string,
|
||||
requestHeaders: Record<string, string>
|
||||
): void {
|
||||
let host: string;
|
||||
let parsed: URL;
|
||||
try {
|
||||
host = new URL(url).hostname;
|
||||
parsed = new URL(url);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
if (!YOUTUBE_EMBED_HOSTS.has(host)) {
|
||||
// Scope strictly to embed player requests — www.youtube.com also
|
||||
// serves regular pages that must keep their real (missing) Referer
|
||||
if (
|
||||
!YOUTUBE_EMBED_HOSTS.has(parsed.hostname) ||
|
||||
!parsed.pathname.startsWith('/embed/')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -222,12 +222,19 @@ export class TmdbEnrichmentService {
|
||||
if (!fallbackLanguage) {
|
||||
return details;
|
||||
}
|
||||
const fallback = await this.fetchDetails(
|
||||
mediaType,
|
||||
tmdbId,
|
||||
fallbackLanguage
|
||||
);
|
||||
return fillDetailsFromFallback(details, fallback);
|
||||
// Best-effort: a failing fallback fetch must never cost the
|
||||
// already-fetched primary payload (cast, artwork, trailer, ...)
|
||||
try {
|
||||
const fallback = await this.fetchDetails(
|
||||
mediaType,
|
||||
tmdbId,
|
||||
fallbackLanguage
|
||||
);
|
||||
return fillDetailsFromFallback(details, fallback);
|
||||
} catch (error) {
|
||||
console.warn('TMDB fallback-language fetch failed:', error);
|
||||
return details;
|
||||
}
|
||||
}
|
||||
|
||||
private async fetchDetails(
|
||||
|
||||
@@ -83,11 +83,25 @@ describe('season fallback', () => {
|
||||
expect(
|
||||
seasonNeedsTextFallback({
|
||||
overview: '',
|
||||
episodes: [{ episode_number: 1, overview: 'Text' }],
|
||||
episodes: [
|
||||
{ episode_number: 1, name: 'Ep 1', overview: 'Text' },
|
||||
],
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('triggers when episode overviews exist but ALL names are empty', () => {
|
||||
expect(
|
||||
seasonNeedsTextFallback({
|
||||
overview: 'Season text',
|
||||
episodes: [
|
||||
{ episode_number: 1, name: '', overview: 'Text 1' },
|
||||
{ episode_number: 2, name: ' ', overview: 'Text 2' },
|
||||
],
|
||||
})
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('fills missing season overview and episode texts by number', () => {
|
||||
const merged = fillSeasonFromFallback(emptySeason, russianSeason);
|
||||
expect(merged.overview).toBe('Описание сезона');
|
||||
|
||||
@@ -42,14 +42,23 @@ export function fillDetailsFromFallback(
|
||||
: primary;
|
||||
}
|
||||
|
||||
/** True when the season payload carries no usable text at all */
|
||||
/**
|
||||
* True when the season payload carries no usable text: no overviews at
|
||||
* all, or episodes whose names are ALL empty (partially translated
|
||||
* seasons keep localized overviews but lose the episode names).
|
||||
*/
|
||||
export function seasonNeedsTextFallback(season: TmdbSeasonDetails): boolean {
|
||||
const episodes = season.episodes ?? [];
|
||||
if (
|
||||
episodes.length > 0 &&
|
||||
!episodes.some((episode) => hasText(episode.name))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (hasText(season.overview)) {
|
||||
return false;
|
||||
}
|
||||
return !(season.episodes ?? []).some((episode) =>
|
||||
hasText(episode.overview)
|
||||
);
|
||||
return !episodes.some((episode) => hasText(episode.overview));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user