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()
|
||||
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:
|
||||
- $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: []
|
||||
|
@@ -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) => {
|
||||
|
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