From 03cb05e2a369fe5741a690e0c1fc374ddc5e5a01 Mon Sep 17 00:00:00 2001 From: WebStreamr <210764791+webstreamr@users.noreply.github.com> Date: Sun, 18 May 2025 21:16:47 +0200 Subject: [PATCH] feat: implement IMDb -> TMDB ID conversion helper --- ...b.org3findtt12345678external_sourceimdb_id | 1 + ...db.org3findtt2085059external_sourceimdb_id | 1 + ...b.org3findtt29141112external_sourceimdb_id | 1 + src/utils/index.ts | 1 + src/utils/manifest.test.ts | 1 + src/utils/tmdb.test.ts | 34 +++++++++++++++++++ src/utils/tmdb.ts | 19 +++++++++++ 7 files changed, 58 insertions(+) create mode 100644 src/utils/__fixtures__/Fetcher/https:api.themoviedb.org3findtt12345678external_sourceimdb_id create mode 100644 src/utils/__fixtures__/Fetcher/https:api.themoviedb.org3findtt2085059external_sourceimdb_id create mode 100644 src/utils/__fixtures__/Fetcher/https:api.themoviedb.org3findtt29141112external_sourceimdb_id create mode 100644 src/utils/tmdb.test.ts create mode 100644 src/utils/tmdb.ts diff --git a/src/utils/__fixtures__/Fetcher/https:api.themoviedb.org3findtt12345678external_sourceimdb_id b/src/utils/__fixtures__/Fetcher/https:api.themoviedb.org3findtt12345678external_sourceimdb_id new file mode 100644 index 0000000..f33dea4 --- /dev/null +++ b/src/utils/__fixtures__/Fetcher/https:api.themoviedb.org3findtt12345678external_sourceimdb_id @@ -0,0 +1 @@ +{"movie_results":[{"backdrop_path":null,"id":1427398,"title":"Hold & Kick","original_title":"Hold & Kick","overview":"","poster_path":null,"media_type":"movie","adult":false,"original_language":"id","genre_ids":[],"popularity":0.0,"release_date":"","video":false,"vote_average":0.0,"vote_count":0}],"person_results":[],"tv_results":[],"tv_episode_results":[],"tv_season_results":[]} \ No newline at end of file diff --git a/src/utils/__fixtures__/Fetcher/https:api.themoviedb.org3findtt2085059external_sourceimdb_id b/src/utils/__fixtures__/Fetcher/https:api.themoviedb.org3findtt2085059external_sourceimdb_id new file mode 100644 index 0000000..918ed42 --- /dev/null +++ b/src/utils/__fixtures__/Fetcher/https:api.themoviedb.org3findtt2085059external_sourceimdb_id @@ -0,0 +1 @@ +{"movie_results":[],"person_results":[],"tv_results":[{"backdrop_path":"/dg3OindVAGZBjlT3xYKqIAdukPL.jpg","id":42009,"name":"Black Mirror","original_name":"Black Mirror","overview":"Twisted tales run wild in this mind-bending anthology series that reveals humanity's worst traits, greatest innovations and more.","poster_path":"/seN6rRfN0I6n8iDXjlSMk1QjNcq.jpg","media_type":"tv","adult":false,"original_language":"en","genre_ids":[10765,18,9648],"popularity":97.3279,"first_air_date":"2011-12-04","vote_average":8.288,"vote_count":5485,"origin_country":["GB"]}],"tv_episode_results":[],"tv_season_results":[]} \ No newline at end of file diff --git a/src/utils/__fixtures__/Fetcher/https:api.themoviedb.org3findtt29141112external_sourceimdb_id b/src/utils/__fixtures__/Fetcher/https:api.themoviedb.org3findtt29141112external_sourceimdb_id new file mode 100644 index 0000000..9f14698 --- /dev/null +++ b/src/utils/__fixtures__/Fetcher/https:api.themoviedb.org3findtt29141112external_sourceimdb_id @@ -0,0 +1 @@ +{"movie_results":[{"backdrop_path":"/j4RUnJz8QCuWkmB8CPykD5UvgBb.jpg","id":931944,"title":"The Devil's Bath","original_title":"Des Teufels Bad","overview":"In 1750 Austria, a deeply religious woman named Agnes has just married her beloved, but her mind and heart soon grow heavy as her life becomes a long list of chores and expectations. Day after day, she is increasingly trapped in a murky and lonely path leading to evil thoughts, until the possibility of committing a shocking act of violence seems like the only way out of her inner prison.","poster_path":"/ycoXsJomPmPjtCfNweM0UWiTkPY.jpg","media_type":"movie","adult":false,"original_language":"de","genre_ids":[18,9648,36,27],"popularity":3.3607,"release_date":"2024-03-08","video":false,"vote_average":6.6,"vote_count":114}],"person_results":[],"tv_results":[],"tv_episode_results":[],"tv_season_results":[]} \ No newline at end of file diff --git a/src/utils/index.ts b/src/utils/index.ts index eb1e328..54af3ae 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -3,3 +3,4 @@ export * from './StreamResolver'; export * from './embed'; export * from './imdb'; export * from './manifest'; +export * from './tmdb'; diff --git a/src/utils/manifest.test.ts b/src/utils/manifest.test.ts index b1c6b78..3cf316d 100644 --- a/src/utils/manifest.test.ts +++ b/src/utils/manifest.test.ts @@ -3,6 +3,7 @@ import { buildManifest } from './manifest'; import { KinoKiste, MeineCloud, VerHdLink } from '../handler'; import { Fetcher } from './Fetcher'; import { ExtractorRegistry } from '../extractor'; +jest.mock('../utils/Fetcher'); const logger = winston.createLogger({ transports: [new winston.transports.Console({ level: 'nope' })] }); // @ts-expect-error No constructor args needed diff --git a/src/utils/tmdb.test.ts b/src/utils/tmdb.test.ts new file mode 100644 index 0000000..d9746ad --- /dev/null +++ b/src/utils/tmdb.test.ts @@ -0,0 +1,34 @@ +import { getTmdbIdFromImdbId } from './tmdb'; +import { Fetcher } from './Fetcher'; +import { Context } from '../types'; +jest.mock('../utils/Fetcher'); + +// @ts-expect-error No constructor args needed +const fetcher = new Fetcher(); +const ctx: Context = { id: 'id', ip: '127.0.0.1', config: { de: 'on' } }; + +describe('getTmdbIdFromImdbId', () => { + test('series', async () => { + const tmdbId = await getTmdbIdFromImdbId(ctx, fetcher, { id: 'tt2085059', series: 2, episode: 4 }); + + expect(tmdbId).toStrictEqual({ + id: 42009, + series: 2, + episode: 4, + }); + }); + + test('movie', async () => { + const tmdbId = await getTmdbIdFromImdbId(ctx, fetcher, { id: 'tt29141112', series: undefined, episode: undefined }); + + expect(tmdbId).toStrictEqual({ + id: 931944, + series: undefined, + episode: undefined, + }); + }); + + test('throws with invalid imdb id', async () => { + await expect(getTmdbIdFromImdbId(ctx, fetcher, { id: 'tt12345678', series: 1, episode: 1 })).rejects.toThrow('Could not get TMDB ID of IMDb ID "tt12345678"'); + }); +}); diff --git a/src/utils/tmdb.ts b/src/utils/tmdb.ts new file mode 100644 index 0000000..d6e298e --- /dev/null +++ b/src/utils/tmdb.ts @@ -0,0 +1,19 @@ +import { ImdbId } from './imdb'; +import { Context } from '../types'; +import { Fetcher } from './Fetcher'; + +export interface TmdbId { id: number; series: number | undefined; episode: number | undefined } + +export const getTmdbIdFromImdbId = async (ctx: Context, fetcher: Fetcher, imdbId: ImdbId): Promise => { + const url = new URL(`https://api.themoviedb.org/3/find/${imdbId.id}?external_source=imdb_id`); + const config = { headers: { Authorization: 'Bearer ' + process.env['TMDB_ACCESS_TOKEN'] } }; + const response = JSON.parse(await fetcher.text(ctx, url, config)); + + const id = (imdbId.series ? response.tv_results[0] : response.movie_results[0])?.id; + + if (!id) { + throw new Error(`Could not get TMDB ID of IMDb ID "${imdbId.id}"`); + } + + return { id, series: imdbId.series, episode: imdbId.episode }; +};