refactor: make TMDB detail fetching more DRY

This commit is contained in:
WebStreamr 2025-07-18 16:42:17 +00:00
parent 603bcff935
commit f6dcd74dfb
No known key found for this signature in database
5 changed files with 31 additions and 44 deletions

View file

@ -1,7 +1,7 @@
import * as cheerio from 'cheerio';
import { ContentType } from 'stremio-addon-sdk';
import { Context, CountryCode } from '../types';
import { Fetcher, getTmdbId, getTmdbMovieDetails, getTmdbTvDetails, Id, TmdbId } from '../utils';
import { Fetcher, getTmdbId, getTmdbNameAndYear, Id, TmdbId } from '../utils';
import { Source, SourceResult } from './types';
export class Cuevana implements Source {
@ -22,9 +22,7 @@ export class Cuevana implements Source {
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
const tmdbId = await getTmdbId(ctx, this.fetcher, id);
const name = tmdbId.season
? (await getTmdbTvDetails(ctx, this.fetcher, tmdbId, 'es')).name
: (await getTmdbMovieDetails(ctx, this.fetcher, tmdbId, 'es')).title;
const [name] = await getTmdbNameAndYear(ctx, this.fetcher, tmdbId, 'es');
const pageUrl = await this.fetchPageUrl(ctx, name);
if (!pageUrl) {

View file

@ -1,7 +1,7 @@
import * as cheerio from 'cheerio';
import { ContentType } from 'stremio-addon-sdk';
import { Context, CountryCode } from '../types';
import { Fetcher, getTmdbId, getTmdbTvDetails, Id } from '../utils';
import { Fetcher, getTmdbId, getTmdbNameAndYear, Id } from '../utils';
import { Source, SourceResult } from './types';
export class Eurostreaming implements Source {
@ -21,9 +21,9 @@ export class Eurostreaming implements Source {
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
const tmdbId = await getTmdbId(ctx, this.fetcher, id);
const tmdbTvDetails = await getTmdbTvDetails(ctx, this.fetcher, tmdbId, 'it');
const [name] = await getTmdbNameAndYear(ctx, this.fetcher, tmdbId, 'it');
const seriesPageUrl = await this.fetchSeriesPageUrl(ctx, tmdbTvDetails.name);
const seriesPageUrl = await this.fetchSeriesPageUrl(ctx, name);
if (!seriesPageUrl) {
return [];
}
@ -32,7 +32,7 @@ export class Eurostreaming implements Source {
const $ = cheerio.load(html);
const title = `${tmdbTvDetails.name} ${tmdbId.season}x${tmdbId.episode}`;
const title = `${name} ${tmdbId.season}x${tmdbId.episode}`;
return Promise.all(
$(`[data-num="${tmdbId.season}x${tmdbId.episode}"]`)

View file

@ -1,7 +1,7 @@
import * as cheerio from 'cheerio';
import { ContentType } from 'stremio-addon-sdk';
import { Context, CountryCode } from '../types';
import { Fetcher, getTmdbId, getTmdbMovieDetails, getTmdbTvDetails, Id, TmdbId } from '../utils';
import { Fetcher, getTmdbId, getTmdbNameAndYear, Id } from '../utils';
import { Source, SourceResult } from './types';
export class KinoGer implements Source {
@ -24,14 +24,14 @@ export class KinoGer implements Source {
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
const tmdbId = await getTmdbId(ctx, this.fetcher, id);
const [keyword, year] = await this.getKeywordAndYear(ctx, tmdbId);
const [name, year] = await getTmdbNameAndYear(ctx, this.fetcher, tmdbId, 'de');
const pageUrl = await this.fetchPageUrl(ctx, keyword, year);
const pageUrl = await this.fetchPageUrl(ctx, name, year);
if (!pageUrl) {
return [];
}
const title = tmdbId.season ? `${keyword} ${tmdbId.season}x${tmdbId.episode}` : `${keyword} (${year})`;
const title = tmdbId.season ? `${name} ${tmdbId.season}x${tmdbId.episode}` : `${name} (${year})`;
const seasonIndex = (tmdbId.season ?? 1) - 1;
const episodeIndex = (tmdbId.episode ?? 1) - 1;
@ -73,16 +73,4 @@ export class KinoGer implements Source {
.map((_i, el) => new URL($(el).attr('href') as string, this.baseUrl))
.get(0);
};
private readonly getKeywordAndYear = async (ctx: Context, tmdbId: TmdbId): Promise<[string, number]> => {
if (tmdbId.season) {
const tmdbDetails = await getTmdbTvDetails(ctx, this.fetcher, tmdbId, 'de');
return [tmdbDetails.name, (new Date(tmdbDetails.first_air_date)).getFullYear()];
}
const tmdbDetails = await getTmdbMovieDetails(ctx, this.fetcher, tmdbId, 'de');
return [tmdbDetails.title, (new Date(tmdbDetails.release_date)).getFullYear()];
};
}

View file

@ -1,7 +1,7 @@
import * as cheerio from 'cheerio';
import { ContentType } from 'stremio-addon-sdk';
import { Context, CountryCode } from '../types';
import { Fetcher, getTmdbId, getTmdbMovieDetails, getTmdbTvDetails, Id, TmdbId } from '../utils';
import { Fetcher, getTmdbId, getTmdbNameAndYear, Id } from '../utils';
import { Source, SourceResult } from './types';
export class Soaper implements Source {
@ -24,9 +24,10 @@ export class Soaper implements Source {
public async handle(ctx: Context, _type: string, id: Id): Promise<SourceResult[]> {
const tmdbId = await getTmdbId(ctx, this.fetcher, id);
const [keyword, year, hrefPrefix] = await this.getKeywordYearAndHrefPrefix(ctx, tmdbId);
const [name, year] = await getTmdbNameAndYear(ctx, this.fetcher, tmdbId);
const hrefPrefix = tmdbId.season ? '/tv_' : '/movie_';
const pageUrl = await this.fetchPageUrl(ctx, keyword, year, hrefPrefix);
const pageUrl = await this.fetchPageUrl(ctx, name, year, hrefPrefix);
if (!pageUrl) {
return [];
}
@ -42,12 +43,12 @@ export class Soaper implements Source {
}
const episodeUrl = new URL(episodePageHref, this.baseUrl);
const title = `${keyword} ${tmdbId.season}x${tmdbId.episode}`;
const title = `${name} ${tmdbId.season}x${tmdbId.episode}`;
return [{ countryCode: CountryCode.en, title, url: episodeUrl }];
}
const title = `${keyword} (${year})`;
const title = `${name} (${year})`;
return [{ countryCode: CountryCode.en, title, url: pageUrl }];
};
@ -69,16 +70,4 @@ export class Soaper implements Source {
return exactKeyWordMatchUrl ?? yearMatchUrl;
};
private readonly getKeywordYearAndHrefPrefix = async (ctx: Context, tmdbId: TmdbId): Promise<[string, number, string]> => {
if (tmdbId.season) {
const tmdbDetails = await getTmdbTvDetails(ctx, this.fetcher, tmdbId);
return [tmdbDetails.name, (new Date(tmdbDetails.first_air_date)).getFullYear(), '/tv_'];
}
const tmdbDetails = await getTmdbMovieDetails(ctx, this.fetcher, tmdbId);
return [tmdbDetails.title, (new Date(tmdbDetails.release_date)).getFullYear(), '/movie_'];
};
}

View file

@ -27,7 +27,7 @@ interface TvDetailsResponsePartial {
name: string;
}
export const tmdbFetch = async (ctx: Context, fetcher: Fetcher, path: string, searchParams?: Record<string, string | undefined>): Promise<unknown> => {
const tmdbFetch = async (ctx: Context, fetcher: Fetcher, path: string, searchParams?: Record<string, string | undefined>): Promise<unknown> => {
const config: CustomRequestInit = {
headers: {
'Authorization': 'Bearer ' + envGet('TMDB_ACCESS_TOKEN'),
@ -79,10 +79,22 @@ export const getImdbIdFromTmdbId = async (ctx: Context, fetcher: Fetcher, tmdbId
return new ImdbId(response.imdb_id, tmdbId.season, tmdbId.episode);
};
export const getTmdbMovieDetails = async (ctx: Context, fetcher: Fetcher, tmdbId: TmdbId, language?: string): Promise<MovieDetailsResponsePartial> => {
const getTmdbMovieDetails = async (ctx: Context, fetcher: Fetcher, tmdbId: TmdbId, language?: string): Promise<MovieDetailsResponsePartial> => {
return await tmdbFetch(ctx, fetcher, `/movie/${tmdbId.id}`, { language }) as MovieDetailsResponsePartial;
};
export const getTmdbTvDetails = async (ctx: Context, fetcher: Fetcher, tmdbId: TmdbId, language?: string): Promise<TvDetailsResponsePartial> => {
const getTmdbTvDetails = async (ctx: Context, fetcher: Fetcher, tmdbId: TmdbId, language?: string): Promise<TvDetailsResponsePartial> => {
return await tmdbFetch(ctx, fetcher, `/tv/${tmdbId.id}`, { language }) as TvDetailsResponsePartial;
};
export const getTmdbNameAndYear = async (ctx: Context, fetcher: Fetcher, tmdbId: TmdbId, language?: string): Promise<[string, number]> => {
if (tmdbId.season) {
const tmdbDetails = await getTmdbTvDetails(ctx, fetcher, tmdbId, language);
return [tmdbDetails.name, (new Date(tmdbDetails.first_air_date)).getFullYear()];
}
const tmdbDetails = await getTmdbMovieDetails(ctx, fetcher, tmdbId, language);
return [tmdbDetails.title, (new Date(tmdbDetails.release_date)).getFullYear()];
};