diff --git a/server/api/themoviedb.ts b/server/api/themoviedb.ts index 7790b6a7..e7e7d1b4 100644 --- a/server/api/themoviedb.ts +++ b/server/api/themoviedb.ts @@ -99,6 +99,27 @@ interface TmdbSearchTvResponse extends TmdbPaginatedResponse { results: TmdbTvResult[]; } +export interface TmdbCreditCast { + cast_id: number; + character: string; + credit_id: string; + gender?: number; + id: number; + name: string; + order: number; + profile_path?: string; +} + +export interface TmdbCreditCrew { + credit_id: string; + gender?: number; + id: number; + name: string; + profile_path?: string; + job: string; + department: string; +} + export interface TmdbMovieDetails { id: number; imdb_id?: string; @@ -138,6 +159,10 @@ export interface TmdbMovieDetails { video: boolean; vote_average: number; vote_count: number; + credits: { + cast: TmdbCreditCast[]; + crew: TmdbCreditCrew[]; + }; } export interface TmdbTvEpisodeDetails { @@ -258,7 +283,7 @@ class TheMovieDb { const response = await this.axios.get( `/movie/${movieId}`, { - params: { language }, + params: { language, append_to_response: 'credits' }, } ); diff --git a/server/models/Movie.ts b/server/models/Movie.ts index 8bb35c7c..f03f4c11 100644 --- a/server/models/Movie.ts +++ b/server/models/Movie.ts @@ -1,7 +1,32 @@ -import { TmdbMovieDetails } from '../api/themoviedb'; +import { + TmdbMovieDetails, + TmdbCreditCast, + TmdbCreditCrew, +} from '../api/themoviedb'; import { MediaRequest } from '../entity/MediaRequest'; import { ProductionCompany, Genre } from './common'; +export interface Cast { + id: number; + castId: number; + character: string; + creditId: string; + gender?: number; + name: string; + order: number; + profilePath?: string; +} + +export interface Crew { + id: number; + creditId: string; + department: string; + gender?: number; + job: string; + name: string; + profilePath?: string; +} + export interface MovieDetails { id: number; imdbId?: string; @@ -33,9 +58,34 @@ export interface MovieDetails { video: boolean; voteAverage: number; voteCount: number; + credits: { + cast: Cast[]; + crew: Crew[]; + }; request?: MediaRequest; } +const mapCast = (person: TmdbCreditCast): Cast => ({ + castId: person.cast_id, + character: person.character, + creditId: person.credit_id, + id: person.id, + name: person.name, + order: person.order, + gender: person.gender, + profilePath: person.profile_path, +}); + +const mapCrew = (person: TmdbCreditCrew): Crew => ({ + creditId: person.credit_id, + department: person.department, + id: person.id, + job: person.job, + name: person.name, + gender: person.gender, + profilePath: person.profile_path, +}); + export const mapMovieDetails = ( movie: TmdbMovieDetails, request?: MediaRequest @@ -69,5 +119,9 @@ export const mapMovieDetails = ( posterPath: movie.poster_path, runtime: movie.runtime, tagline: movie.tagline, + credits: { + cast: movie.credits.cast.map(mapCast), + crew: movie.credits.crew.map(mapCrew), + }, request, }); diff --git a/server/overseerr-api.yml b/server/overseerr-api.yml index d7812d18..60d921d3 100644 --- a/server/overseerr-api.yml +++ b/server/overseerr-api.yml @@ -419,6 +419,17 @@ components: type: number voteCount: type: number + credits: + type: object + properties: + cast: + type: array + items: + $ref: '#/components/schemas/Cast' + crew: + type: array + items: + $ref: '#/components/schemas/Crew' request: $ref: '#/components/schemas/MediaRequest' Episode: @@ -590,6 +601,48 @@ components: - mediaId - mediaType - status + Cast: + type: object + properties: + id: + type: number + example: 123 + castId: + type: number + example: 1 + character: + type: string + example: Some Character Name + creditId: + type: string + gender: + type: number + name: + type: string + example: Some Persons Name + order: + type: number + profilePath: + type: string + Crew: + type: object + properties: + id: + type: number + example: 123 + creditId: + type: string + gender: + type: number + name: + type: string + example: Some Persons Name + job: + type: string + department: + type: string + profilePath: + type: string securitySchemes: cookieAuth: diff --git a/src/components/Common/ListView/index.tsx b/src/components/Common/ListView/index.tsx index 0ab8328a..96817966 100644 --- a/src/components/Common/ListView/index.tsx +++ b/src/components/Common/ListView/index.tsx @@ -6,6 +6,7 @@ import { } from '../../../../server/models/Search'; import TitleCard from '../../TitleCard'; import useVerticalScroll from '../../../hooks/useVerticalScroll'; +import PersonCard from '../../PersonCard'; interface ListViewProps { items?: (TvResult | MovieResult | PersonResult)[]; @@ -64,7 +65,9 @@ const ListView: React.FC = ({ ); break; case 'person': - titleCard =
{title.name}
; + titleCard = ( + + ); break; } diff --git a/src/components/MovieDetails/index.tsx b/src/components/MovieDetails/index.tsx index a6c79466..fe21a473 100644 --- a/src/components/MovieDetails/index.tsx +++ b/src/components/MovieDetails/index.tsx @@ -11,6 +11,7 @@ import type { MovieResult } from '../../../server/models/Search'; import Link from 'next/link'; import Slider from '../Slider'; import TitleCard from '../TitleCard'; +import PersonCard from '../PersonCard'; interface MovieDetailsProps { movie?: MovieDetailsType; @@ -280,6 +281,42 @@ const MovieDetails: React.FC = ({ movie }) => { +
+ +
+ ( + + ))} + />
= ({ + name, + subName, + profilePath, +}) => { + return ( +
+
+
+ {profilePath && ( +
+ )} + {!profilePath && ( + + + + )} +
{name}
+ {subName && ( +
+ {subName} +
+ )} +
+
+
+ ); +}; + +export default PersonCard; diff --git a/src/components/TitleCard/index.tsx b/src/components/TitleCard/index.tsx index ea07286e..2853d258 100644 --- a/src/components/TitleCard/index.tsx +++ b/src/components/TitleCard/index.tsx @@ -99,7 +99,7 @@ const TitleCard: React.FC = ({ onOk={() => cancelRequest()} />