diff --git a/src/utils/tmdb.test.ts b/src/utils/tmdb.test.ts index 76ee9b2..337ae03 100644 --- a/src/utils/tmdb.test.ts +++ b/src/utils/tmdb.test.ts @@ -1,4 +1,4 @@ -import { getImdbIdFromTmdbId, getTmdbIdFromImdbId } from './tmdb'; +import { getImdbIdFromTmdbId, getTmdbIdFromImdbId, parseTmdbId } from './tmdb'; import { Fetcher } from './Fetcher'; import { Context } from '../types'; jest.mock('../utils/Fetcher'); @@ -7,6 +7,44 @@ jest.mock('../utils/Fetcher'); const fetcher = new Fetcher(); const ctx: Context = { id: 'id', ip: '127.0.0.1', config: { de: 'on' } }; +describe('tmdb id parsing', () => { + test('splits id properly', () => { + const { id, series, episode } = parseTmdbId('2085059:2:4'); + + expect(id).toBe(2085059); + expect(series).toBe(2); + expect(episode).toBe(4); + }); + + test('handles weird 0 prefixes in series and episode', () => { + const { id, series, episode } = parseTmdbId('2085059:02:04'); + + expect(id).toBe(2085059); + expect(series).toBe(2); + expect(episode).toBe(4); + }); + + test('supports movie with missing series and episode', () => { + const { id, series, episode } = parseTmdbId('2085059'); + + expect(id).toBe(2085059); + expect(series).toBeUndefined(); + expect(episode).toBeUndefined(); + }); + + test('throws for empty ids', () => { + expect(() => { + parseTmdbId(''); + }).toThrow('TMDB ID "" is invalid'); + }); + + test('throws for invalid ids', () => { + expect(() => { + parseTmdbId('foo'); + }).toThrow('TMDB ID "foo" is invalid'); + }); +}); + describe('getTmdbIdFromImdbId', () => { test('series', async () => { expect(await getTmdbIdFromImdbId(ctx, fetcher, { id: 'tt2085059', series: 2, episode: 4 })) diff --git a/src/utils/tmdb.ts b/src/utils/tmdb.ts index f3d14f7..53e9b33 100644 --- a/src/utils/tmdb.ts +++ b/src/utils/tmdb.ts @@ -18,6 +18,20 @@ interface ExternalIdsResponsePartial { imdb_id: string; } +export const parseTmdbId = (id: string): TmdbId => { + const idParts = id.split(':'); + + if (!idParts[0] || !/^\d+$/.test(idParts[0])) { + throw new Error(`TMDB ID "${id}" is invalid`); + } + + return { + id: parseInt(idParts[0]), + series: idParts[1] ? parseInt(idParts[1]) : undefined, + episode: idParts[2] ? parseInt(idParts[2]) : undefined, + }; +}; + const fetch = async (ctx: Context, fetcher: Fetcher, url: URL): Promise => { const config = { 'headers': { Authorization: 'Bearer ' + envGet('TMDB_ACCESS_TOKEN') }, 'Content-Type': 'application/json' };