Skip to content

Commit 26ed478

Browse files
feat: Created the single person credits resolver to generate the credits in the correct format
1 parent bebef58 commit 26ed478

File tree

3 files changed

+301
-2
lines changed

3 files changed

+301
-2
lines changed

src/person/person.resolver.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,9 @@ export class PersonResolver {
2626
homepage: person.homepage
2727
};
2828
}
29+
30+
@ResolveField()
31+
async credits(@Parent() person: Person) {
32+
return this.personService.getCredits(person.id ?? 0);
33+
}
2934
}

src/person/person.service.ts

Lines changed: 188 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ import { HttpService } from '@nestjs/axios';
22
import { Injectable } from '@nestjs/common';
33
import { firstValueFrom } from 'rxjs';
44

5-
import { TheOpenMovieDatabasePerson, TheOpenMovieDatabasePersonGender } from './person';
5+
import {
6+
Group,
7+
IGetGroupCredits,
8+
TheOpenMovieDatabasePerson,
9+
TheOpenMovieDatabasePersonCombinedCredits,
10+
TheOpenMovieDatabasePersonGender
11+
} from './person';
612
import { SocialsService } from '../socials/socials.service';
713
import { UtilsService } from '../utils/utils.service';
814

@@ -95,4 +101,185 @@ export class PersonService {
95101
resourceType: 'PERSON'
96102
});
97103
}
104+
105+
private getGroupCredits(departmentCredits: IGetGroupCredits) {
106+
const credits: Group[] = [];
107+
108+
departmentCredits.forEach((departmentCredit) => {
109+
// Crew credit for a "movie"
110+
if (departmentCredit.type === 'crew' && departmentCredit.media_type === 'movie') {
111+
credits.push({
112+
mediaType: 'movie',
113+
character: departmentCredit.character,
114+
title: departmentCredit.title || departmentCredit.original_title,
115+
year: departmentCredit.release_date
116+
? new Date(departmentCredit.release_date).getFullYear()
117+
: '-',
118+
type: 'crew',
119+
department: departmentCredit.department
120+
});
121+
}
122+
123+
// Crew credit for a "tv" show
124+
if (departmentCredit.type === 'crew' && departmentCredit.media_type === 'tv') {
125+
credits.push({
126+
mediaType: 'tv',
127+
character: departmentCredit.character,
128+
title: departmentCredit.name || departmentCredit.original_name,
129+
episodeCount: departmentCredit.episode_count,
130+
year: departmentCredit.first_air_date
131+
? new Date(departmentCredit.first_air_date).getFullYear()
132+
: '-',
133+
type: 'crew',
134+
department: departmentCredit.department
135+
});
136+
}
137+
138+
// Cast credit for a "movie"
139+
if (departmentCredit.type === 'cast' && departmentCredit.media_type === 'movie') {
140+
credits.push({
141+
mediaType: 'movie',
142+
character: departmentCredit.character,
143+
title: departmentCredit.title || departmentCredit.original_title,
144+
year: departmentCredit.release_date
145+
? new Date(departmentCredit.release_date).getFullYear()
146+
: '-',
147+
type: 'cast'
148+
});
149+
}
150+
151+
// Cast credit for a "tv" show
152+
if (departmentCredit.type === 'cast' && departmentCredit.media_type === 'tv') {
153+
credits.push({
154+
mediaType: 'tv',
155+
character: departmentCredit.character,
156+
title: departmentCredit.name || departmentCredit.original_name,
157+
episodeCount: departmentCredit.episode_count,
158+
year: departmentCredit.first_air_date
159+
? new Date(departmentCredit.first_air_date).getFullYear()
160+
: '-',
161+
type: 'cast'
162+
});
163+
}
164+
});
165+
166+
// Sort the credits by the assigned year, it should be highest to lowest
167+
credits.sort((departmentCreditA, departmentCreditB) => {
168+
if (
169+
typeof departmentCreditA.year === 'number' &&
170+
typeof departmentCreditB.year === 'number'
171+
) {
172+
return departmentCreditA.year - departmentCreditB.year;
173+
}
174+
175+
return 0;
176+
});
177+
178+
const allCreditsWithEmptyYears = credits.filter((credit) => typeof credit.type === 'string');
179+
const allCreditsWithoutEmptyYears = credits.filter((credit) => typeof credit.year === 'number');
180+
181+
// Add the credits with empty years to the top of the list so they are rendered at the top of the list in the user-interface
182+
const creditsWithEmptyYearsAtTop = [
183+
...allCreditsWithEmptyYears,
184+
...allCreditsWithoutEmptyYears
185+
];
186+
187+
const groups: { year: number | '-'; credits: Group[] }[] = [];
188+
189+
creditsWithEmptyYearsAtTop.forEach((credit) => {
190+
const groupIndex = groups.findIndex((el) => el.year === credit.year);
191+
192+
// Add the credit to the existing group
193+
if (groupIndex !== -1) {
194+
groups[groupIndex].credits.push(credit);
195+
}
196+
197+
// Create a new credit group
198+
if (groupIndex === -1) {
199+
groups.push({
200+
year: credit.year,
201+
credits: [credit]
202+
});
203+
}
204+
});
205+
206+
return groups;
207+
}
208+
209+
async getCredits(personId: number) {
210+
const { data } = await firstValueFrom(
211+
this.httpService.get<TheOpenMovieDatabasePersonCombinedCredits>(
212+
`https://api.themoviedb.org/3/person/${personId}/combined_credits?language=en-U`,
213+
{
214+
headers: {
215+
Accept: 'application/json',
216+
Authorization:
217+
// eslint-disable-next-line max-len
218+
'Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI1NDMwNWQxNmE1ZThkN2E3ZWMwZmM2NTk5MzZiY2EzMCIsInN1YiI6IjViMzE0MjQ1OTI1MTQxM2M5MTAwNTIwNCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.iqdLKFCSgeWG3SYso7Rqj297FORviPf9hDdn2kKygTA'
219+
}
220+
}
221+
)
222+
);
223+
224+
const ActingGroup = this.getGroupCredits(
225+
data.cast.map((el) => ({
226+
...el,
227+
type: 'cast'
228+
}))
229+
);
230+
231+
const ProductionGroup = this.getGroupCredits(
232+
data.crew
233+
.filter((el) => el.department === 'Production')
234+
.map((el) => ({
235+
...el,
236+
type: 'crew'
237+
}))
238+
);
239+
240+
const WritingGroup = this.getGroupCredits(
241+
data.crew
242+
.filter((el) => el.department === 'Writing')
243+
.map((el) => ({
244+
...el,
245+
type: 'crew'
246+
}))
247+
);
248+
249+
const DirectingGroup = this.getGroupCredits(
250+
data.crew
251+
.filter((el) => el.department === 'Directing')
252+
.map((el) => ({
253+
...el,
254+
type: 'crew'
255+
}))
256+
);
257+
258+
const CrewGroup = this.getGroupCredits(
259+
data.crew
260+
.filter((el) => el.department === 'Crew')
261+
.map((el) => ({
262+
...el,
263+
type: 'crew'
264+
}))
265+
);
266+
267+
const LightingGroup = this.getGroupCredits(
268+
data.crew
269+
.filter((el) => el.department === 'Lighting')
270+
.map((el) => ({
271+
...el,
272+
type: 'crew'
273+
}))
274+
);
275+
276+
return {
277+
ActingGroup,
278+
ProductionGroup,
279+
WritingGroup,
280+
DirectingGroup,
281+
CrewGroup,
282+
LightingGroup
283+
};
284+
}
98285
}

src/person/person.ts

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1+
/* eslint-disable @typescript-eslint/naming-convention */
12
export type TheOpenMovieDatabasePersonGender = 0 | 1 | 2 | 3;
23

4+
export type TheOpenMovieDatabaseDepartments =
5+
| 'Production'
6+
| 'Writing'
7+
| 'Directing'
8+
| 'Crew'
9+
| 'Lighting';
10+
311
export interface TheOpenMovieDatabasePerson {
412
adult: boolean;
513
also_known_as: string[];
@@ -10,9 +18,108 @@ export interface TheOpenMovieDatabasePerson {
1018
homepage: string;
1119
id: number;
1220
imdb_id: string;
13-
known_for_department: string;
21+
known_for_department: TheOpenMovieDatabaseDepartments;
1422
name: string;
1523
place_of_birth: string;
1624
popularity: number;
1725
profile_path: string;
1826
}
27+
28+
interface ICredit {
29+
adult: boolean;
30+
backdrop_path: string | null;
31+
genre_ids: number[];
32+
id: number;
33+
overview: string;
34+
popularity: number;
35+
poster_path: string | null;
36+
vote_average: number;
37+
vote_count: number;
38+
character: string;
39+
credit_id: string;
40+
}
41+
42+
type IMovieCredit = {
43+
original_language: string;
44+
original_title: string;
45+
release_date: string;
46+
title: string;
47+
video: boolean;
48+
order: number;
49+
media_type: 'movie';
50+
} & ICredit;
51+
52+
type ITVCredits = {
53+
origin_country: string[];
54+
original_language: string;
55+
original_name: string;
56+
first_air_date: string;
57+
name: string;
58+
episode_count: number;
59+
media_type: 'tv';
60+
} & ICredit;
61+
62+
export type IMovieCrew = {
63+
department: TheOpenMovieDatabaseDepartments;
64+
job: string;
65+
type: 'crew';
66+
} & IMovieCredit;
67+
68+
export type ITVCrew = {
69+
department: TheOpenMovieDatabaseDepartments;
70+
job: string;
71+
type: 'crew';
72+
} & ITVCredits;
73+
74+
export type IMovieCast = {
75+
type: 'cast';
76+
} & IMovieCredit;
77+
78+
export type ITVCast = {
79+
type: 'cast';
80+
} & ITVCredits;
81+
82+
export type Crew = IMovieCrew | ITVCrew;
83+
84+
export type Cast = IMovieCast | ITVCast;
85+
86+
export type IGetGroupCredits = Crew[] | Cast[];
87+
export interface TheOpenMovieDatabasePersonCombinedCredits {
88+
cast: Omit<IMovieCast, 'type'>[] | Omit<ITVCast, 'type'>[];
89+
crew: Omit<IMovieCrew, 'type'>[] | Omit<ITVCrew, 'type'>[];
90+
id: number;
91+
}
92+
93+
export type Group =
94+
| {
95+
mediaType: 'tv';
96+
year: number | '-';
97+
character: string;
98+
title: string;
99+
episodeCount: number;
100+
type: 'cast';
101+
}
102+
| {
103+
mediaType: 'movie';
104+
year: number | '-';
105+
character: string;
106+
title: string;
107+
type: 'cast';
108+
}
109+
| {
110+
mediaType: 'tv';
111+
year: number | '-';
112+
character: string;
113+
title: string;
114+
episodeCount: number;
115+
type: 'crew';
116+
department: TheOpenMovieDatabaseDepartments;
117+
}
118+
| {
119+
mediaType: 'movie';
120+
year: number | '-';
121+
character: string;
122+
title: string;
123+
type: 'crew';
124+
department: TheOpenMovieDatabaseDepartments;
125+
};

0 commit comments

Comments
 (0)