normalize omdb response

main
Inga 🏳‍🌈 1 year ago
parent 7a18087a1b
commit 560f75b7c9
  1. 3
      .eslintrc.js
  2. 10
      src/integration/movies/omdb/apiClient.spec.ts
  3. 18
      src/integration/movies/omdb/apiClient.ts
  4. 276
      src/integration/movies/omdb/converters.spec.ts
  5. 121
      src/integration/movies/omdb/converters.ts
  6. 39
      src/integration/movies/omdb/index.spec.ts
  7. 18
      src/integration/movies/omdb/index.ts
  8. 45
      src/integration/movies/omdb/types.ts
  9. 96
      src/integration/movies/types.ts
  10. 1
      tsconfig.json

@ -19,6 +19,7 @@ module.exports = {
rules: { rules: {
'@typescript-eslint/interface-name-prefix': 'off', '@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off' '@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-unused-vars': ['error', { varsIgnorePattern: '^_' }]
}, },
}; };

@ -1,11 +1,11 @@
import { describe, it, expect } from '@jest/globals'; import { describe, it, expect } from '@jest/globals';
import { createOmdbClient } from './omdb'; import { createOmdbApiClient } from './apiClient';
describe('createOmdbClient', () => { describe('createOmdbApiClient', () => {
const client = createOmdbClient('68fd98ab'); const client = createOmdbApiClient('68fd98ab');
it('returns some data for the sample movie id', async () => { it('returns some data for the sample movie id', async () => {
const result = await client.getMovieMetadata('tt11873472'); const result = await client.fetchMetadata('tt11873472');
expect(result).toMatchObject({ expect(result).toMatchObject({
Actors: 'Cheryl Isheja, Elvis Ngabo, Diogène Ntarindwa', Actors: 'Cheryl Isheja, Elvis Ngabo, Diogène Ntarindwa',
Awards: expect.any(String), Awards: expect.any(String),
@ -35,7 +35,7 @@ describe('createOmdbClient', () => {
}, 10_000); }, 10_000);
it('returns undefined for non-existend movie id', async () => { it('returns undefined for non-existend movie id', async () => {
const result = await client.getMovieMetadata('tt99999999999'); const result = await client.fetchMetadata('tt99999999999');
expect(result).toBeUndefined(); expect(result).toBeUndefined();
}, 10_000); }, 10_000);
}); });

@ -1,17 +1,8 @@
import fetch from 'node-fetch'; import fetch from 'node-fetch';
import PQueue from 'p-queue'; import PQueue from 'p-queue';
import { OmdbMovieData, OmdbMoviesProvider } from './types'; import { OmdbApiClient, OmdbResponse } from './types';
type OmdbResponse = export const createOmdbApiClient = (apiKey: string): OmdbApiClient => {
| {
Response: 'False';
Error: string;
}
| (OmdbMovieData & {
Response: 'True';
});
export const createOmdbClient = (apiKey: string): OmdbMoviesProvider => {
// Rate limit (according to readme, it's 1k per day; // Rate limit (according to readme, it's 1k per day;
// here we set it 1 per second, should be enough for the demo app goal) // here we set it 1 per second, should be enough for the demo app goal)
const queue = new PQueue({ const queue = new PQueue({
@ -22,7 +13,7 @@ export const createOmdbClient = (apiKey: string): OmdbMoviesProvider => {
}); });
return { return {
getMovieMetadata: async (imdbId: string) => fetchMetadata: async (imdbId: string) =>
queue.add(async () => { queue.add(async () => {
const url = new URL('https://www.omdbapi.com/'); const url = new URL('https://www.omdbapi.com/');
url.searchParams.append('i', imdbId); url.searchParams.append('i', imdbId);
@ -45,7 +36,8 @@ export const createOmdbClient = (apiKey: string): OmdbMoviesProvider => {
); );
} }
return body; const { Response: _status, ...rawOmdbData } = body;
return rawOmdbData;
}), }),
}; };
}; };

@ -0,0 +1,276 @@
import { describe, it, expect } from '@jest/globals';
import { normalizeRawOmdbData } from './converters';
describe('normalizeRawOmdbData', () => {
it('normalizes data correctly for tt19500164 (online-release animation)', () => {
const rawOmdbData = {
Title: 'Nimona',
Year: '2023',
Rated: 'PG',
Released: '30 Jun 2023',
Runtime: '101 min',
Genre: 'Animation, Action, Adventure',
Director: 'Nick Bruno, Troy Quane',
Writer: 'Robert L. Baird, Lloyd Taylor, Pamela Ribon',
Actors: 'Chloë Grace Moretz, Riz Ahmed, Eugene Lee Yang',
Plot: "When a knight in a futuristic medieval world is framed for a crime he didn't commit, the only one who can help him prove his innocence is Nimona -- a mischievous teen who happens to be a shapeshifting creature he's sworn to destroy.",
Language: 'English',
Country: 'United States',
Awards: '2 nominations',
Poster: 'https://m.media-amazon.com/images/M/MV5BNDJkNzQzODQtM2Q0MC00MWE4LTlkMjMtNWZmZWQyMTYwZGRmXkEyXkFqcGdeQXVyMTY1MTAyOTk1._V1_SX300.jpg',
Ratings: [
{ Source: 'Internet Movie Database', Value: '7.6/10' },
{ Source: 'Metacritic', Value: '75/100' },
],
Metascore: '75',
imdbRating: '7.6',
imdbVotes: '34,896',
imdbID: 'tt19500164',
Type: 'movie',
DVD: 'N/A',
BoxOffice: 'N/A',
Production: 'N/A',
Website: 'N/A',
} as const;
const result = normalizeRawOmdbData(rawOmdbData);
expect(result).toEqual({
actors: ['Chloë Grace Moretz', 'Riz Ahmed', 'Eugene Lee Yang'],
awards: '2 nominations',
contentRating: 'PG',
description:
"When a knight in a futuristic medieval world is framed for a crime he didn't commit, the only one who can help him prove his innocence is Nimona -- a mischievous teen who happens to be a shapeshifting creature he's sworn to destroy.",
directors: ['Nick Bruno', 'Troy Quane'],
duration: 101,
genres: ['Animation', 'Action', 'Adventure'],
imdbId: 'tt19500164',
posterUrl:
'https://m.media-amazon.com/images/M/MV5BNDJkNzQzODQtM2Q0MC00MWE4LTlkMjMtNWZmZWQyMTYwZGRmXkEyXkFqcGdeQXVyMTY1MTAyOTk1._V1_SX300.jpg',
productionCountries: ['United States'],
productionYear: 2023,
ratings: [
{ source: 'Internet Movie Database', value: '7.6/10' },
{ source: 'Metacritic', value: '75/100' },
],
releaseDate: '30 Jun 2023',
title: 'Nimona',
type: 'movie',
writers: ['Robert L. Baird', 'Lloyd Taylor', 'Pamela Ribon'],
});
});
it('normalizes data correctly for tt10482560 (series)', () => {
const rawOmdbData = {
Title: 'Kipo and the Age of Wonderbeasts',
Year: '2020',
Rated: 'TV-Y7',
Released: '14 Jan 2020',
Runtime: '24 min',
Genre: 'Animation, Action, Adventure',
Director: 'N/A',
Writer: 'Bill Wolkoff, Radford Sechrist',
Actors: 'Karen Fukuhara, Sydney Mikayla, Dee Bradley Baker',
Plot: 'A girl explores the possibilities in a post-apocalyptic world.',
Language: 'English',
Country: 'United States',
Awards: '3 nominations',
Poster: 'https://m.media-amazon.com/images/M/MV5BZDczZDIxZjEtNDJiZS00NmQwLWJjMGEtN2UwNDY0ODdjODNiXkEyXkFqcGdeQXVyMTAwMzM3NDI3._V1_SX300.jpg',
Ratings: [{ Source: 'Internet Movie Database', Value: '8.3/10' }],
Metascore: 'N/A',
imdbRating: '8.3',
imdbVotes: '6,911',
imdbID: 'tt10482560',
Type: 'series',
totalSeasons: '3',
} as const;
const result = normalizeRawOmdbData(rawOmdbData);
expect(result).toEqual({
actors: ['Karen Fukuhara', 'Sydney Mikayla', 'Dee Bradley Baker'],
awards: '3 nominations',
contentRating: 'TV-Y7',
description:
'A girl explores the possibilities in a post-apocalyptic world.',
duration: 24,
genres: ['Animation', 'Action', 'Adventure'],
imdbId: 'tt10482560',
posterUrl:
'https://m.media-amazon.com/images/M/MV5BZDczZDIxZjEtNDJiZS00NmQwLWJjMGEtN2UwNDY0ODdjODNiXkEyXkFqcGdeQXVyMTAwMzM3NDI3._V1_SX300.jpg',
productionCountries: ['United States'],
productionYear: 2020,
ratings: [{ source: 'Internet Movie Database', value: '8.3/10' }],
releaseDate: '14 Jan 2020',
title: 'Kipo and the Age of Wonderbeasts',
totalSeasons: 3,
type: 'series',
writers: ['Bill Wolkoff', 'Radford Sechrist'],
});
});
it('normalizes data correctly for tt5580266 (cinema-release movie)', () => {
const rawOmdbData = {
Title: 'The Hate U Give',
Year: '2018',
Rated: 'PG-13',
Released: '19 Oct 2018',
Runtime: '133 min',
Genre: 'Crime, Drama',
Director: 'George Tillman Jr.',
Writer: 'Audrey Wells, Angie Thomas',
Actors: 'Amandla Stenberg, Regina Hall, Russell Hornsby',
Plot: "Starr Carter is constantly switching between two worlds: the poor, mostly black, neighborhood where she lives and the rich, mostly white, prep school she attends. The uneasy balance between these worlds is shattered when Starr witnesses the fatal shooting of her childhood best friend Khalil at the hands of a police officer. Now, facing pressures from all sides of the community, Starr must find her voice and stand up for what's right.",
Language: 'English',
Country: 'United States',
Awards: '22 wins & 38 nominations',
Poster: 'https://m.media-amazon.com/images/M/MV5BZDVkMWJiMzUtNjQyOS00MGVmLWJhYmMtN2IxYzU4MjY3MDRmXkEyXkFqcGdeQXVyNzA5NjIzODk@._V1_SX300.jpg',
Ratings: [
{ Source: 'Internet Movie Database', Value: '7.5/10' },
{ Source: 'Rotten Tomatoes', Value: '97%' },
{ Source: 'Metacritic', Value: '81/100' },
],
Metascore: '81',
imdbRating: '7.5',
imdbVotes: '39,280',
imdbID: 'tt5580266',
Type: 'movie',
DVD: '08 Jan 2019',
BoxOffice: '$29,719,483',
Production: 'N/A',
Website: 'N/A',
} as const;
const result = normalizeRawOmdbData(rawOmdbData);
expect(result).toEqual({
actors: ['Amandla Stenberg', 'Regina Hall', 'Russell Hornsby'],
awards: '22 wins & 38 nominations',
boxOffice: '$29,719,483',
contentRating: 'PG-13',
description:
"Starr Carter is constantly switching between two worlds: the poor, mostly black, neighborhood where she lives and the rich, mostly white, prep school she attends. The uneasy balance between these worlds is shattered when Starr witnesses the fatal shooting of her childhood best friend Khalil at the hands of a police officer. Now, facing pressures from all sides of the community, Starr must find her voice and stand up for what's right.",
dvdReleaseDate: '08 Jan 2019',
directors: ['George Tillman Jr.'],
duration: 133,
genres: ['Crime', 'Drama'],
imdbId: 'tt5580266',
posterUrl:
'https://m.media-amazon.com/images/M/MV5BZDVkMWJiMzUtNjQyOS00MGVmLWJhYmMtN2IxYzU4MjY3MDRmXkEyXkFqcGdeQXVyNzA5NjIzODk@._V1_SX300.jpg',
productionCountries: ['United States'],
productionYear: 2018,
ratings: [
{ source: 'Internet Movie Database', value: '7.5/10' },
{ source: 'Rotten Tomatoes', value: '97%' },
{ source: 'Metacritic', value: '81/100' },
],
releaseDate: '19 Oct 2018',
title: 'The Hate U Give',
type: 'movie',
writers: ['Audrey Wells', 'Angie Thomas'],
});
});
it('normalizes data correctly for tt1508328 (foreign release)', () => {
const rawOmdbData = {
Title: 'Pumzi',
Year: '2009',
Rated: 'N/A',
Released: '01 Jan 2010',
Runtime: '21 min',
Genre: 'Short, Sci-Fi',
Director: 'Wanuri Kahiu',
Writer: 'Wanuri Kahiu',
Actors: 'Kudzani Moswela, Chantelle Burger, Tammy Richards',
Plot: 'As a result of the Third World War, the war for water, life died out on Earth. Asha lives and works as a curator of the Natural History Museum in one of the communities established in Africa. Once he receives a sample of the earth and tries to plant one of the seeds on it. It turns out that the land is not contaminated radioactive, the grain begins to germinate. He asks the Community Council to explore the possibility of recreating life on the planet. The answer is negative and the woman is arrested. He decides to escape to the surface, to the deadly desert, and plant his little tree somewhere.',
Language: 'English',
Country: 'South Africa, Kenya',
Awards: '3 wins & 2 nominations',
Poster: 'https://m.media-amazon.com/images/M/MV5BZTE4ODAzNzktNTBjZi00ZjBkLWFlYmYtZWZiZDJiNzEzMTBjXkEyXkFqcGdeQXVyNjkzNzg5Njg@._V1_SX300.jpg',
Ratings: [{ Source: 'Internet Movie Database', Value: '7.2/10' }],
Metascore: 'N/A',
imdbRating: '7.2',
imdbVotes: '345',
imdbID: 'tt1508328',
Type: 'movie',
DVD: 'N/A',
BoxOffice: 'N/A',
Production: 'N/A',
Website: 'N/A',
} as const;
const result = normalizeRawOmdbData(rawOmdbData);
expect(result).toEqual({
actors: ['Kudzani Moswela', 'Chantelle Burger', 'Tammy Richards'],
awards: '3 wins & 2 nominations',
description:
'As a result of the Third World War, the war for water, life died out on Earth. Asha lives and works as a curator of the Natural History Museum in one of the communities established in Africa. Once he receives a sample of the earth and tries to plant one of the seeds on it. It turns out that the land is not contaminated radioactive, the grain begins to germinate. He asks the Community Council to explore the possibility of recreating life on the planet. The answer is negative and the woman is arrested. He decides to escape to the surface, to the deadly desert, and plant his little tree somewhere.',
directors: ['Wanuri Kahiu'],
duration: 21,
genres: ['Short', 'Sci-Fi'],
imdbId: 'tt1508328',
posterUrl:
'https://m.media-amazon.com/images/M/MV5BZTE4ODAzNzktNTBjZi00ZjBkLWFlYmYtZWZiZDJiNzEzMTBjXkEyXkFqcGdeQXVyNjkzNzg5Njg@._V1_SX300.jpg',
productionCountries: ['South Africa', 'Kenya'],
productionYear: 2009,
ratings: [{ source: 'Internet Movie Database', value: '7.2/10' }],
releaseDate: '01 Jan 2010',
title: 'Pumzi',
type: 'movie',
writers: ['Wanuri Kahiu'],
});
});
it('normalizes data correctly for tt7224520 (local release)', () => {
const rawOmdbData = {
Title: 'Ever After',
Year: '2018',
Rated: 'Not Rated',
Released: '21 Jun 2019',
Runtime: '90 min',
Genre: 'Fantasy, Horror, Romance',
Director: 'Carolina Hellsgård',
Writer: 'Olivia Vieweg',
Actors: 'Gro Swantje Kohlhof, Maja Lehrer, Trine Dyrholm',
Plot: 'It has been two years since a zombie virus epidemic infected all but two German cities. Vivi and Eva flee the struggling community in Weimar for the one other safe-haven: Jena.',
Language: 'German',
Country: 'Germany',
Awards: '3 nominations',
Poster: 'https://m.media-amazon.com/images/M/MV5BZjRhZWRmZTItMjU4Zi00OTg5LTg2YjAtNmY2ODA2OGM2ZjZmXkEyXkFqcGdeQXVyNjEwNzcwNzU@._V1_SX300.jpg',
Ratings: [
{ Source: 'Internet Movie Database', Value: '4.9/10' },
{ Source: 'Rotten Tomatoes', Value: '80%' },
{ Source: 'Metacritic', Value: '63/100' },
],
Metascore: '63',
imdbRating: '4.9',
imdbVotes: '924',
imdbID: 'tt7224520',
Type: 'movie',
DVD: '15 Dec 2019',
BoxOffice: 'N/A',
Production: 'N/A',
Website: 'N/A',
} as const;
const result = normalizeRawOmdbData(rawOmdbData);
expect(result).toEqual({
actors: ['Gro Swantje Kohlhof', 'Maja Lehrer', 'Trine Dyrholm'],
awards: '3 nominations',
contentRating: 'Not Rated',
description:
'It has been two years since a zombie virus epidemic infected all but two German cities. Vivi and Eva flee the struggling community in Weimar for the one other safe-haven: Jena.',
directors: ['Carolina Hellsgård'],
duration: 90,
dvdReleaseDate: '15 Dec 2019',
genres: ['Fantasy', 'Horror', 'Romance'],
imdbId: 'tt7224520',
posterUrl:
'https://m.media-amazon.com/images/M/MV5BZjRhZWRmZTItMjU4Zi00OTg5LTg2YjAtNmY2ODA2OGM2ZjZmXkEyXkFqcGdeQXVyNjEwNzcwNzU@._V1_SX300.jpg',
productionCountries: ['Germany'],
productionYear: 2018,
ratings: [
{ source: 'Internet Movie Database', value: '4.9/10' },
{ source: 'Rotten Tomatoes', value: '80%' },
{ source: 'Metacritic', value: '63/100' },
],
releaseDate: '21 Jun 2019',
title: 'Ever After',
type: 'movie',
writers: ['Olivia Vieweg'],
});
});
});

@ -0,0 +1,121 @@
import { NormalizedOmdbData } from '../types';
import { RawOmdbData } from './types';
const identity = <T>(value: T) => value;
const stringToArray = (value: string) => value.split(', ');
const stringToNumber = (value: string) => parseInt(value, 10);
const stringToDuration = (value: string) => {
const match = /^(?<time>\d+)\smin$/.exec(value);
if (!match) {
throw new Error(`Cannot parse duration: "${value}"`);
}
// Both `groups` and `groups['time']` are guaranteed to be defined because of regex definition, but TS doesn't know that.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return stringToNumber(match.groups!['time']!);
};
const omdbRatingsToNormalizedRatings = (ratings: RawOmdbData['Ratings']) =>
ratings.map(({ Source, Value }) => ({ source: Source, value: Value }));
const createRequiredField = <TKey extends keyof NormalizedOmdbData, TRawValue>(
key: TKey,
value: TRawValue,
transformer: (value: TRawValue) => NormalizedOmdbData[TKey],
) => {
if (value === undefined) {
throw new Error(`Value for ${key} is not defined`);
}
if (value === 'N/A') {
throw new Error(`Value for ${key} is "N/A"`);
}
return {
[key]: transformer(value),
} as Record<TKey, NormalizedOmdbData[TKey]>;
};
const createOptionalField = <TKey extends keyof NormalizedOmdbData, TRawValue>(
key: TKey,
value: TRawValue,
transformer: (
value: Exclude<TRawValue, undefined>,
) => NormalizedOmdbData[TKey],
) => {
if (value === undefined || value === 'N/A') {
return undefined;
}
return createRequiredField(
key,
value as Exclude<TRawValue, undefined>,
transformer,
);
};
export const normalizeRawOmdbData = (
rawOmdbData: RawOmdbData,
): NormalizedOmdbData => {
const {
Actors,
Awards,
BoxOffice,
Country,
DVD,
Director,
Genre,
Language: _language,
Metascore: _metascore,
Plot,
Poster,
Production: _production,
Rated,
Ratings,
Released,
Runtime,
Title,
Type,
Website,
Writer,
Year,
imdbID,
imdbRating: _imdbRating,
imdbVotes: _imdbVotes,
totalSeasons,
...rest
} = rawOmdbData;
const restKeys = Object.keys(rest);
if (restKeys.length) {
throw new Error(
`Unexpected fields in OMDB response: ${restKeys.join(', ')}`,
);
}
return {
...createRequiredField('actors', Actors, stringToArray),
...createRequiredField('awards', Awards, identity),
...createOptionalField('boxOffice', BoxOffice, identity),
...createOptionalField('contentRating', Rated, identity),
...createRequiredField('description', Plot, identity),
...createOptionalField('directors', Director, stringToArray),
...createRequiredField('duration', Runtime, stringToDuration),
...createOptionalField('dvdReleaseDate', DVD, identity),
...createRequiredField('genres', Genre, stringToArray),
...createRequiredField('imdbId', imdbID, identity),
...createRequiredField('posterUrl', Poster, identity),
...createRequiredField('productionCountries', Country, stringToArray),
...createRequiredField('productionYear', Year, stringToNumber),
...createRequiredField(
'ratings',
Ratings,
omdbRatingsToNormalizedRatings,
),
...createRequiredField('releaseDate', Released, identity),
...createRequiredField('title', Title, identity),
...createOptionalField('totalSeasons', totalSeasons, stringToNumber),
...createRequiredField('type', Type, identity),
...createOptionalField('website', Website, identity),
...createRequiredField('writers', Writer, stringToArray),
};
};

@ -0,0 +1,39 @@
import { describe, it, expect } from '@jest/globals';
import { createOmdbProvider } from '.';
describe('createOmdbProvider', () => {
const client = createOmdbProvider('68fd98ab');
it('returns correct data for tt10687116', async () => {
const result = await client.getMetadata('tt10687116');
expect(result).toMatchObject({
actors: ['Kid Cudi', 'Jessica Williams', 'Laura Harrier'],
awards: expect.any(String),
contentRating: 'TV-MA',
description: expect.any(String),
directors: ['Fletcher Moules'],
duration: 93,
dvdReleaseDate: '30 Sep 2022',
genres: ['Animation', 'Comedy', 'Music'],
imdbId: 'tt10687116',
posterUrl: expect.any(String),
productionCountries: ['United Kingdom', 'United States'],
productionYear: 2022,
ratings: expect.arrayContaining([
{
source: expect.any(String),
value: expect.any(String),
},
]),
releaseDate: '30 Sep 2022',
title: 'Entergalactic',
type: 'movie',
writers: ['Kid Cudi', 'Kenya Barris', 'Ian Edelman'],
});
}, 10_000);
it('returns undefined for non-existend movie id', async () => {
const result = await client.getMetadata('tt99999999999');
expect(result).toBeUndefined();
}, 10_000);
});

@ -0,0 +1,18 @@
import { OmdbProvider } from '../types';
import { createOmdbApiClient } from './apiClient';
import { normalizeRawOmdbData } from './converters';
export const createOmdbProvider = (apiKey: string): OmdbProvider => {
const apiClient = createOmdbApiClient(apiKey);
return {
getMetadata: async (imdbId: string) => {
const rawOmdbData = await apiClient.fetchMetadata(imdbId);
if (!rawOmdbData) {
return undefined;
}
return normalizeRawOmdbData(rawOmdbData);
},
};
};

@ -0,0 +1,45 @@
export type RawOmdbData = Readonly<{
Actors: string;
Awards: string;
BoxOffice?: string;
Country: string;
DVD?: string;
Director: string;
Genre: string;
Language: string;
Metascore: string;
Plot: string;
Poster: string;
Production?: string;
Rated: string;
Ratings: Readonly<
{
Source: string;
Value: string;
}[]
>;
Released: string;
Runtime: string;
Title: string;
Type: 'movie' | 'series';
Website?: string;
Writer: string;
Year: string;
imdbID: string;
imdbRating: string;
imdbVotes: string;
totalSeasons?: string;
}>;
export type OmdbResponse =
| {
Response: 'False';
Error: string;
}
| (RawOmdbData & {
Response: 'True';
});
export type OmdbApiClient = {
fetchMetadata(imdbId: string): Promise<RawOmdbData | undefined>;
};

@ -1,33 +1,3 @@
export type OmdbMovieData = {
Actors: string;
Awards: string;
BoxOffice: string;
Country: string;
DVD: string;
Director: string;
Genre: string;
Language: string;
Metascore: string;
Plot: string;
Poster: string;
Production: string;
Rated: string;
Ratings: {
Source: string;
Value: string;
}[];
Released: string;
Runtime: string;
Title: string;
Type: string;
Website: string;
Writer: string;
Year: string;
imdbID: string;
imdbRating: string;
imdbVotes: string;
};
type InternalMovieData = { type InternalMovieData = {
/** /**
* Description in local language * Description in local language
@ -63,6 +33,68 @@ type InternalMovieData = {
}; };
}; };
type MovieData = {
internalId?: number;
imdbId: string;
title: string;
localTitle: string;
description: string;
localDescription: string;
posterUrl: string;
type: 'movie' | 'series';
/**
* A whole number of minutes
*/
duration: number;
totalSeasons: number;
/**
* Two-letter code
*/
originalLanguage: string;
/**
* Two-letter codes
*/
availableLanguages: string[];
productionYear: number;
releaseDate: string;
dvdReleaseDate: string;
genres: string[];
directors: string[];
writers: string[];
actors: string[];
studios: string[];
awards: string;
productionCountries: string[];
boxOffice: string;
contentRating: string;
website: string;
ratings: {
source: string;
value: string;
}[];
};
export type StrictPartial<
T,
TForbiddenKeys extends keyof T,
TOptionalKeys extends Exclude<keyof T, TForbiddenKeys>,
> = Omit<T, TForbiddenKeys | TOptionalKeys> & Partial<Pick<T, TOptionalKeys>>;
export type NormalizedOmdbData = StrictPartial<
MovieData,
| 'availableLanguages'
| 'localDescription'
| 'localTitle'
| 'originalLanguage'
| 'studios',
| 'boxOffice'
| 'contentRating'
| 'directors'
| 'dvdReleaseDate'
| 'totalSeasons'
| 'website'
>;
export type InternalMoviesProvider = { export type InternalMoviesProvider = {
getMovieMetadataByInternalId( getMovieMetadataByInternalId(
internalId: number, internalId: number,
@ -72,6 +104,6 @@ export type InternalMoviesProvider = {
): Promise<InternalMovieData | undefined>; ): Promise<InternalMovieData | undefined>;
}; };
export type OmdbMoviesProvider = { export type OmdbProvider = {
getMovieMetadata(imdbId: string): Promise<OmdbMovieData | undefined>; getMetadata(imdbId: string): Promise<NormalizedOmdbData | undefined>;
}; };

@ -8,6 +8,7 @@
"experimentalDecorators": true, "experimentalDecorators": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"lib": ["ES2021"],
"target": "ES2021", "target": "ES2021",
"sourceMap": true, "sourceMap": true,
"outDir": "./dist", "outDir": "./dist",

Loading…
Cancel
Save