From 4df634f1da683fae952908d34c3810ed942f5ef0 Mon Sep 17 00:00:00 2001 From: AlexMachin1997 Date: Sun, 30 Jun 2024 16:00:57 +0100 Subject: [PATCH] feat: When viewing a top billed tv series cast you can now get the episodeCount. Also improved how gender values are mapped to support all genders available. --- .vscode/settings.json | 3 +- src/entertainment/entertainment.service.ts | 25 ++++++----- src/entertainment/entertainment.ts | 25 +---------- src/graphql.schema.ts | 9 +--- src/models/entertainment/Cast.graphql | 2 +- src/models/enum.graphql | 5 --- src/movie/movie.ts | 3 +- src/person/person.service.ts | 29 +------------ src/person/person.ts | 4 +- src/show/show.service.ts | 50 +++++++++++++++++++++- src/show/show.ts | 28 ++++++++++-- src/socials/socials.service.ts | 2 - src/types/credits.ts | 25 +++++++++++ src/types/gender.ts | 1 + src/utils/utils.service.ts | 22 ++++++++++ 15 files changed, 145 insertions(+), 88 deletions(-) create mode 100644 src/types/credits.ts create mode 100644 src/types/gender.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 0dfe76a..1d461d4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,7 +14,8 @@ "source.fixAll.eslint": "explicit" }, "editor.cursorSmoothCaretAnimation": "on", - "editor.fontSize": 30, + "editor.fontSize": 20, + "editor.minimap.enabled": false, "editor.tabSize": 2, diff --git a/src/entertainment/entertainment.service.ts b/src/entertainment/entertainment.service.ts index be9fdfe..fe4fbc8 100644 --- a/src/entertainment/entertainment.service.ts +++ b/src/entertainment/entertainment.service.ts @@ -2,30 +2,29 @@ import { HttpService } from '@nestjs/axios'; import { Injectable } from '@nestjs/common'; import { firstValueFrom } from 'rxjs'; + +import { + ICreditsQueryResponse, + IKeywordsQueryResponse, + IReviewQuery, + IVdoesQueryResponse +} from './entertainment'; import { BelongsToCollection, Cast, Crew, ENTERTAINMENT_TYPES, - GENDER, Keyword, Review, Social, Video -} from 'src/graphql.schema'; +} from '../graphql.schema'; import { TheOpenMovieDatabaseBelongsToCollection, TheOpenMovieDatabaseSpokenLanguages -} from 'src/movie/movie'; -import { SocialsService } from 'src/socials/socials.service'; -import { UtilsService } from 'src/utils/utils.service'; - -import { - ICreditsQueryResponse, - IKeywordsQueryResponse, - IReviewQuery, - IVdoesQueryResponse -} from './entertainment'; +} from '../movie/movie'; +import { SocialsService } from '../socials/socials.service'; +import { UtilsService } from '../utils/utils.service'; // eslint-disable-next-line @typescript-eslint/naming-convention interface IEntertainmentCommonArguments { @@ -109,7 +108,7 @@ export class EntertainmentService { id: el.id, character: el.character, profileImageUrl: this.utilService.getFullImageUrlPath(el.profile_path), - gender: el.gender === 2 ? GENDER.MALE : GENDER.FEMALE + gender: this.utilService.getGender(el.gender) })); } diff --git a/src/entertainment/entertainment.ts b/src/entertainment/entertainment.ts index 4ff12a8..467246e 100644 --- a/src/entertainment/entertainment.ts +++ b/src/entertainment/entertainment.ts @@ -1,28 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { Keyword } from '../graphql.schema'; - -export interface ICastAndCrew { - adult: boolean; - gender: number; - id: number; - known_for_department: string; - name: string; - original_name: string; - popularity: number; - profile_path: string; - credit_id: string; -} -export interface ICast extends ICastAndCrew { - cast_id: number; - character: string; - order: number; -} - -export interface ICrew extends ICastAndCrew { - department: string; - job: string; -} +import { Keyword } from '../graphql.schema'; +import { ICast, ICrew } from '../types/credits'; export interface IReviewQuery { id: number; diff --git a/src/graphql.schema.ts b/src/graphql.schema.ts index 5516d06..82bea45 100644 --- a/src/graphql.schema.ts +++ b/src/graphql.schema.ts @@ -1,18 +1,11 @@ - /* * ------------------------------------------------------- * THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) * ------------------------------------------------------- */ -/* tslint:disable */ /* eslint-disable */ -export enum GENDER { - MALE = "MALE", - FEMALE = "FEMALE" -} - export enum ENTERTAINMENT_TYPES { MOVIE = "MOVIE", TV = "TV" @@ -165,7 +158,7 @@ export interface Cast { id?: Nullable; character?: Nullable; profileImageUrl?: Nullable; - gender?: Nullable; + gender?: Nullable; episodeCount?: Nullable; } diff --git a/src/models/entertainment/Cast.graphql b/src/models/entertainment/Cast.graphql index 202b594..3fede76 100644 --- a/src/models/entertainment/Cast.graphql +++ b/src/models/entertainment/Cast.graphql @@ -2,6 +2,6 @@ type Cast { id: Int character: String profileImageUrl: String - gender: GENDER + gender: String episodeCount: Int } diff --git a/src/models/enum.graphql b/src/models/enum.graphql index 97358db..87a2cfa 100644 --- a/src/models/enum.graphql +++ b/src/models/enum.graphql @@ -1,8 +1,3 @@ -enum GENDER { - MALE - FEMALE -} - enum ENTERTAINMENT_TYPES { MOVIE TV diff --git a/src/movie/movie.ts b/src/movie/movie.ts index b2fb0e6..f2f6025 100644 --- a/src/movie/movie.ts +++ b/src/movie/movie.ts @@ -1,4 +1,5 @@ import { Genre, Keyword } from '../graphql.schema'; +import { Gender } from '../types/gender'; export interface TheOpenMovieDatabaseBelongsToCollection { id: number; @@ -59,7 +60,7 @@ export interface TheOpenMovieDatabaseMovieReview { export interface TheOpenMovieDatabaseMovieCastAndCrew { adult: boolean; - gender: number; + gender: Gender; id: number; known_for_department: string; name: string; diff --git a/src/person/person.service.ts b/src/person/person.service.ts index 1dccf93..bc568e5 100644 --- a/src/person/person.service.ts +++ b/src/person/person.service.ts @@ -6,8 +6,7 @@ import { Group, IGetGroupCredits, TheOpenMovieDatabasePerson, - TheOpenMovieDatabasePersonCombinedCredits, - TheOpenMovieDatabasePersonGender + TheOpenMovieDatabasePersonCombinedCredits } from './person'; import { SocialsService } from '../socials/socials.service'; import { UtilsService } from '../utils/utils.service'; @@ -42,30 +41,6 @@ export class PersonService { return `${birthdayInReadableFormat} (${age} years old)`; } - getGender(gender: TheOpenMovieDatabasePersonGender) { - switch (gender) { - case 0: { - return 'Not set / not specified'; - } - - case 1: { - return 'Female'; - } - - case 2: { - return 'Male'; - } - - case 3: { - return 'Non-bindary'; - } - - default: { - return ''; - } - } - } - async getPerson(personId: number) { const { data } = await firstValueFrom( this.httpService.get( @@ -87,7 +62,7 @@ export class PersonService { knowForDepartment: data.known_for_department, name: data.name, alsoKnownAs: data.also_known_as, - gender: this.getGender(data.gender), + gender: this.utilService.getGender(data.gender), overview: data.biography, placeOfBirth: data.place_of_birth, posterUrl: this.utilService.getFullImageUrlPath(data.profile_path), diff --git a/src/person/person.ts b/src/person/person.ts index 08bde1f..016c505 100644 --- a/src/person/person.ts +++ b/src/person/person.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -export type TheOpenMovieDatabasePersonGender = 0 | 1 | 2 | 3; +import { Gender } from '../types/gender'; export type TheOpenMovieDatabaseDepartments = | 'Production' @@ -14,7 +14,7 @@ export interface TheOpenMovieDatabasePerson { biography: string; birthday: string; deathday: null | string; - gender: TheOpenMovieDatabasePersonGender; + gender: Gender; homepage: string; id: number; imdb_id: string; diff --git a/src/show/show.service.ts b/src/show/show.service.ts index 2716e75..c7151aa 100644 --- a/src/show/show.service.ts +++ b/src/show/show.service.ts @@ -3,7 +3,7 @@ import { HttpService } from '@nestjs/axios'; import { Injectable } from '@nestjs/common'; import { firstValueFrom } from 'rxjs'; -import { TheOpenMovieDatabaseShow } from './show'; +import { IAggregatedCreditsQueryResponse, TheOpenMovieDatabaseShow } from './show'; import { EntertainmentService } from '../entertainment/entertainment.service'; import { CurrentSeason, ENTERTAINMENT_TYPES } from '../graphql.schema'; import { UtilsService } from '../utils/utils.service'; @@ -89,11 +89,57 @@ export class ShowService { }); } + async getCastAggregatedCredits(showId: number) { + const { data } = await firstValueFrom( + this.httpService.get( + `https://api.themoviedb.org/3/tv/${showId}/aggregate_credits?language=en-U`, + { + headers: { + Accept: 'application/json', + Authorization: + // eslint-disable-next-line max-len + 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI1NDMwNWQxNmE1ZThkN2E3ZWMwZmM2NTk5MzZiY2EzMCIsInN1YiI6IjViMzE0MjQ1OTI1MTQxM2M5MTAwNTIwNCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.iqdLKFCSgeWG3SYso7Rqj297FORviPf9hDdn2kKygTA' + } + } + ) + ); + + return data; + } + async getTopBilledCast(showId: number) { - return this.entertainmentService.getTopBilledCast({ + // Get the top billed cast members + const topBilledCast = await this.entertainmentService.getTopBilledCast({ entertainmentId: showId, entertainmentType: ENTERTAINMENT_TYPES.TV }); + + // Since the episode count isn't available via getTopBilledCast perform an additional lookup to get the additional credit + // data like a list of the users roles for the particular show being queried + const aggregatedCredits = await this.getCastAggregatedCredits(showId); + + return topBilledCast?.map((topBilledCastMember) => { + // Find the cast members credits data, found via the aggregate_credits endpoint + const aggregatedCredit = aggregatedCredits.cast.find( + (el) => el.id === topBilledCastMember.id + ); + + // If the aggregatedCredit is available then total up the cast members episode count + if (typeof aggregatedCredit !== 'undefined') { + return { + ...topBilledCastMember, + episodeCount: aggregatedCredit.roles.reduce( + (total, role) => total + role.episode_count, + 0 + ) + }; + } + + return { + ...topBilledCastMember, + episodeCount: 0 + }; + }); } async getFeaturedCrewMembers(showId: number) { diff --git a/src/show/show.ts b/src/show/show.ts index 4c8582c..009f3a5 100644 --- a/src/show/show.ts +++ b/src/show/show.ts @@ -1,6 +1,8 @@ -import { TheOpenMovieDatabaseBelongsToCollection } from 'src/movie/movie'; - +/* eslint-disable @typescript-eslint/naming-convention */ import { Genre } from '../graphql.schema'; +import { TheOpenMovieDatabaseBelongsToCollection } from '../movie/movie'; +import { ICast, ICrew } from '../types/credits'; +import { Gender } from '../types/gender'; export interface TheOpenMovieDatabaseEpisodeToAir { id: number; @@ -34,7 +36,7 @@ export interface TheOpenMovieDatabaseShow { credit_id: string; name: string; original_name: string; - gender: number; + gender: Gender; profile_path: string; }[]; episode_run_time: number[]; @@ -80,3 +82,23 @@ export interface TheOpenMovieDatabaseShow { vote_average: number; vote_count: number; } + +interface IAggregatedCreditJob { + credit_id: string; + job: string; + episode_count: number; +} + +interface IAggregatedCreditsQueryCastResponse extends ICast { + roles: IAggregatedCreditJob[]; +} + +interface IAggregatedCreditsQueryCrewResponse extends ICrew { + roles: IAggregatedCreditJob[]; +} + +export interface IAggregatedCreditsQueryResponse { + id: number; + cast: IAggregatedCreditsQueryCastResponse[]; + crew: IAggregatedCreditsQueryCrewResponse[]; +} diff --git a/src/socials/socials.service.ts b/src/socials/socials.service.ts index 897a1be..9fa42b0 100644 --- a/src/socials/socials.service.ts +++ b/src/socials/socials.service.ts @@ -30,8 +30,6 @@ export class SocialsService { ) ); - console.log('social', data); - let facebook = null; let instagram = null; let twitter = null; diff --git a/src/types/credits.ts b/src/types/credits.ts new file mode 100644 index 0000000..7937de1 --- /dev/null +++ b/src/types/credits.ts @@ -0,0 +1,25 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { Gender } from './gender'; + +export interface ICastAndCrew { + adult: boolean; + gender: Gender; + id: number; + known_for_department: string; + name: string; + original_name: string; + popularity: number; + profile_path: string; + credit_id: string; +} + +export interface ICast extends ICastAndCrew { + cast_id: number; + character: string; + order: number; +} + +export interface ICrew extends ICastAndCrew { + department: string; + job: string; +} diff --git a/src/types/gender.ts b/src/types/gender.ts new file mode 100644 index 0000000..fef23f3 --- /dev/null +++ b/src/types/gender.ts @@ -0,0 +1 @@ +export type Gender = 0 | 1 | 2 | 3; diff --git a/src/utils/utils.service.ts b/src/utils/utils.service.ts index 60fa67c..13657cf 100644 --- a/src/utils/utils.service.ts +++ b/src/utils/utils.service.ts @@ -1,5 +1,7 @@ import { Injectable } from '@nestjs/common'; +import { Gender } from '../types/gender'; + @Injectable() export class UtilsService { getFullImageUrlPath(imageUrl: string | null | undefined = null): string { @@ -24,4 +26,24 @@ export class UtilsService { currency: 'GBP' }); } + + getGender(gender: Gender) { + switch (gender) { + case 1: { + return 'Female'; + } + + case 2: { + return 'Male'; + } + + case 3: { + return 'Non-binary'; + } + + default: { + return 'Not set / not specified'; + } + } + } }