From b1761484cb2861329763d51a868f37dd3098760d Mon Sep 17 00:00:00 2001 From: sct Date: Wed, 16 Sep 2020 05:33:37 +0000 Subject: [PATCH] feat(api): add movie details endpoint --- server/entity/MediaRequest.ts | 17 +++++ server/models/Movie.ts | 82 ++++++++++++++++++++++++ server/overseerr-api.yml | 117 ++++++++++++++++++++++++++++++++++ server/routes/index.ts | 2 + server/routes/movie.ts | 18 ++++++ 5 files changed, 236 insertions(+) create mode 100644 server/models/Movie.ts create mode 100644 server/routes/movie.ts diff --git a/server/entity/MediaRequest.ts b/server/entity/MediaRequest.ts index bf1c537ed..af53a299b 100644 --- a/server/entity/MediaRequest.ts +++ b/server/entity/MediaRequest.ts @@ -47,6 +47,23 @@ export class MediaRequest { } } + public static async getRequest( + id: number + ): Promise { + const requestRepository = getRepository(MediaRequest); + + try { + const request = await requestRepository.findOneOrFail({ + where: { tmdbId: id }, + }); + + return request; + } catch (e) { + console.error(e.messaage); + return undefined; + } + } + @PrimaryGeneratedColumn() public id: number; diff --git a/server/models/Movie.ts b/server/models/Movie.ts new file mode 100644 index 000000000..97f5a3ab5 --- /dev/null +++ b/server/models/Movie.ts @@ -0,0 +1,82 @@ +import { TmdbMovieDetails } from '../api/themoviedb'; +import { MediaRequest } from '../entity/MediaRequest'; + +interface ProductionCompany { + id: number; + logoPath?: string; + originCountry: string; + name: string; +} + +export interface MovieDetails { + id: number; + imdbId?: string; + adult: boolean; + backdropPath?: string; + budget: number; + genres: { + id: number; + name: string; + }[]; + homepage?: string; + originalLanguage: string; + originalTitle: string; + overview?: string; + popularity: number; + posterPath?: string; + productionCompanies: ProductionCompany[]; + productionCountries: { + iso_3166_1: string; + name: string; + }[]; + releaseDate: string; + revenue: number; + runtime?: number; + spokenLanguages: { + iso_639_1: string; + name: string; + }[]; + status: string; + tagline?: string; + title: string; + video: boolean; + voteAverage: number; + voteCount: number; + request?: MediaRequest; +} + +export const mapMovieDetails = ( + movie: TmdbMovieDetails, + request?: MediaRequest +): MovieDetails => ({ + id: movie.id, + adult: movie.adult, + budget: movie.budget, + genres: movie.genres, + originalLanguage: movie.original_language, + originalTitle: movie.original_title, + popularity: movie.popularity, + productionCompanies: movie.production_companies.map((company) => ({ + id: company.id, + logoPath: company.logo_path, + originCountry: company.origin_country, + name: company.name, + })), + productionCountries: movie.production_countries, + releaseDate: movie.release_date, + revenue: movie.revenue, + spokenLanguages: movie.spoken_languages, + status: movie.status, + title: movie.title, + video: movie.video, + voteAverage: movie.vote_average, + voteCount: movie.vote_count, + backdropPath: movie.backdrop_path, + homepage: movie.homepage, + imdbId: movie.imdb_id, + overview: movie.overview, + posterPath: movie.poster_path, + runtime: movie.runtime, + tagline: movie.tagline, + request, +}); diff --git a/server/overseerr-api.yml b/server/overseerr-api.yml index 8f1c0d087..f628d3a01 100644 --- a/server/overseerr-api.yml +++ b/server/overseerr-api.yml @@ -325,6 +325,103 @@ components: oneOf: - $ref: '#/components/schemas/MovieResult' - $ref: '#/components/schemas/TvResult' + Genre: + type: object + properties: + id: + type: number + example: 1 + name: + type: string + example: Adventure + ProductionCompany: + type: object + properties: + id: + type: number + example: 1 + logoPath: + type: string + originCountry: + type: string + name: + type: string + MovieDetails: + type: object + properties: + id: + type: number + example: 123 + readOnly: true + imdbId: + type: string + example: 123 + adult: + type: boolean + backdropPath: + type: string + posterPath: + type: string + budget: + type: number + example: 1000000 + genres: + type: array + items: + $ref: '#/components/schemas/Genre' + homepage: + type: string + originalLanguage: + type: string + originalTitle: + type: string + overview: + type: string + popularity: + type: number + productionCompanies: + type: array + items: + $ref: '#/components/schemas/ProductionCompany' + productionCountries: + type: array + items: + type: object + properties: + iso_3166_1: + type: string + name: + type: string + releaseDate: + type: string + revenue: + type: string + runtime: + type: number + spokenLanguages: + type: array + items: + type: object + properties: + iso_639_1: + type: string + name: + type: string + status: + type: string + tagline: + type: string + title: + type: string + video: + type: boolean + voteAverage: + type: number + voteCount: + type: number + request: + $ref: '#/components/schemas/MediaRequest' + MediaRequest: type: object properties: @@ -991,6 +1088,26 @@ paths: application/json: schema: $ref: '#/components/schemas/MediaRequest' + /movie/{movieId}: + get: + summary: Request movie details + description: Returns back full movie details in JSON format + tags: + - movies + parameters: + - in: path + name: movieId + required: true + schema: + type: number + example: 337401 + responses: + '200': + description: Movie details + content: + application/json: + schema: + $ref: '#/components/schemas/MovieDetails' security: - cookieAuth: [] diff --git a/server/routes/index.ts b/server/routes/index.ts index 134e79714..e46aa1719 100644 --- a/server/routes/index.ts +++ b/server/routes/index.ts @@ -8,6 +8,7 @@ import { getSettings } from '../lib/settings'; import searchRoutes from './search'; import discoverRoutes from './discover'; import requestRoutes from './request'; +import movieRoutes from './movie'; const router = Router(); @@ -21,6 +22,7 @@ router.use( router.use('/search', isAuthenticated(), searchRoutes); router.use('/discover', isAuthenticated(), discoverRoutes); router.use('/request', isAuthenticated(), requestRoutes); +router.use('/movie', isAuthenticated(), movieRoutes); router.use('/auth', authRoutes); router.get('/settings/public', (_req, res) => { diff --git a/server/routes/movie.ts b/server/routes/movie.ts new file mode 100644 index 000000000..129da8f54 --- /dev/null +++ b/server/routes/movie.ts @@ -0,0 +1,18 @@ +import { Router } from 'express'; +import TheMovieDb from '../api/themoviedb'; +import { mapMovieDetails } from '../models/Movie'; +import { MediaRequest } from '../entity/MediaRequest'; + +const movieRoutes = Router(); + +movieRoutes.get('/:id', async (req, res) => { + const tmdb = new TheMovieDb(); + + const movie = await tmdb.getMovie({ movieId: Number(req.params.id) }); + + const request = await MediaRequest.getRequest(movie.id); + + return res.status(200).json(mapMovieDetails(movie, request)); +}); + +export default movieRoutes;