mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
feat(api): add movie details endpoint
This commit is contained in:
@@ -47,6 +47,23 @@ export class MediaRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async getRequest(
|
||||||
|
id: number
|
||||||
|
): Promise<MediaRequest | undefined> {
|
||||||
|
const requestRepository = getRepository(MediaRequest);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const request = await requestRepository.findOneOrFail({
|
||||||
|
where: { tmdbId: id },
|
||||||
|
});
|
||||||
|
|
||||||
|
return request;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e.messaage);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id: number;
|
public id: number;
|
||||||
|
|
||||||
|
82
server/models/Movie.ts
Normal file
82
server/models/Movie.ts
Normal file
@@ -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,
|
||||||
|
});
|
@@ -325,6 +325,103 @@ components:
|
|||||||
oneOf:
|
oneOf:
|
||||||
- $ref: '#/components/schemas/MovieResult'
|
- $ref: '#/components/schemas/MovieResult'
|
||||||
- $ref: '#/components/schemas/TvResult'
|
- $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:
|
MediaRequest:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@@ -991,6 +1088,26 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/MediaRequest'
|
$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:
|
security:
|
||||||
- cookieAuth: []
|
- cookieAuth: []
|
||||||
|
@@ -8,6 +8,7 @@ import { getSettings } from '../lib/settings';
|
|||||||
import searchRoutes from './search';
|
import searchRoutes from './search';
|
||||||
import discoverRoutes from './discover';
|
import discoverRoutes from './discover';
|
||||||
import requestRoutes from './request';
|
import requestRoutes from './request';
|
||||||
|
import movieRoutes from './movie';
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ router.use(
|
|||||||
router.use('/search', isAuthenticated(), searchRoutes);
|
router.use('/search', isAuthenticated(), searchRoutes);
|
||||||
router.use('/discover', isAuthenticated(), discoverRoutes);
|
router.use('/discover', isAuthenticated(), discoverRoutes);
|
||||||
router.use('/request', isAuthenticated(), requestRoutes);
|
router.use('/request', isAuthenticated(), requestRoutes);
|
||||||
|
router.use('/movie', isAuthenticated(), movieRoutes);
|
||||||
router.use('/auth', authRoutes);
|
router.use('/auth', authRoutes);
|
||||||
|
|
||||||
router.get('/settings/public', (_req, res) => {
|
router.get('/settings/public', (_req, res) => {
|
||||||
|
18
server/routes/movie.ts
Normal file
18
server/routes/movie.ts
Normal file
@@ -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;
|
Reference in New Issue
Block a user