tmdb-lumosovich 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -6
- package/dist/detail-types.d.ts +3 -1
- package/dist/details.js +2 -0
- package/dist/index.cjs +129 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/person-resources.d.ts +4 -0
- package/dist/person-resources.js +72 -0
- package/dist/person-types.d.ts +86 -0
- package/dist/person-types.js +1 -0
- package/dist/person-validation.d.ts +5 -0
- package/dist/person-validation.js +40 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
A small, typed Node.js wrapper for the TMDB API, including IMDb ID lookup through TMDB.
|
|
8
8
|
|
|
9
|
-
**Lumosovich** is being built incrementally toward full TMDB v3 API coverage. It currently supports external-ID lookup, search, discovery, trending, movie and TV series catalogs and metadata, reviews, keywords, networks, collections, companies, configuration,
|
|
9
|
+
**Lumosovich** is being built incrementally toward full TMDB v3 API coverage. It currently supports external-ID lookup, search, discovery, trending, movie and TV series catalogs and metadata, reviews, keywords, networks, collections, companies, configuration, people and credit resources, and TV seasons, episodes, and episode groups.
|
|
10
10
|
|
|
11
11
|
The name comes from **Lumos** — a spell for bringing light — with a little Russian-style `-ovich` treatment.
|
|
12
12
|
|
|
@@ -14,11 +14,11 @@ Light up the movie database.
|
|
|
14
14
|
|
|
15
15
|
## Current status
|
|
16
16
|
|
|
17
|
-
Install [tmdb-lumosovich on npm](https://www.npmjs.com/package/tmdb-lumosovich), with source and issues on [GitHub](https://github.com/namipsg/lumosovich). Version `0.
|
|
17
|
+
Install [tmdb-lumosovich on npm](https://www.npmjs.com/package/tmdb-lumosovich), with source and issues on [GitHub](https://github.com/namipsg/lumosovich). Version `0.8.0` covers **121 of 152 TMDB v3 operations**, including all TV, person, and credit operations, measured against the official specification pinned on September 27, 2026. This is an early `0.x` library; full API coverage is still in progress. See the [coverage baseline](https://github.com/namipsg/lumosovich/blob/main/spec/README.md) for how coverage is checked.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
The package moved from `lumosovich` to `tmdb-lumosovich` in version `0.7.1`; the public `Lumosovich` class kept its name. Previously published `lumosovich` versions remain installable, but new projects should use `tmdb-lumosovich`. The read-only live smoke test exercises all 111 public read operations. Account-state and rating methods require a TMDB session and are verified by offline request contracts.
|
|
20
20
|
|
|
21
|
-
The release passes
|
|
21
|
+
The release passes 196 offline tests and TypeScript declaration checks. See the [changelog](https://github.com/namipsg/lumosovich/blob/main/CHANGELOG.md) for earlier releases.
|
|
22
22
|
|
|
23
23
|
## Installation
|
|
24
24
|
|
|
@@ -348,6 +348,30 @@ const group = groups.results[0]
|
|
|
348
348
|
|
|
349
349
|
`changeList()` reports changed series IDs. Episode-group IDs are strings supplied by TMDB. The methods return TMDB's original response fields and preserve empty collections.
|
|
350
350
|
|
|
351
|
+
## People and credits
|
|
352
|
+
|
|
353
|
+
Use numeric TMDB person IDs for people resources. Credit details use the string `credit_id` returned in a person's cast or crew record.
|
|
354
|
+
|
|
355
|
+
```js
|
|
356
|
+
const personId = 31;
|
|
357
|
+
const popularPeople = await tmdb.people.popular({ page: 1 });
|
|
358
|
+
const movieCredits = await tmdb.people.movieCredits(personId);
|
|
359
|
+
const tvCredits = await tmdb.people.tvCredits(personId);
|
|
360
|
+
const combinedCredits = await tmdb.people.combinedCredits(personId);
|
|
361
|
+
const creditId = movieCredits.cast[0]?.credit_id;
|
|
362
|
+
const credit = creditId ? await tmdb.credits.get(creditId) : undefined;
|
|
363
|
+
|
|
364
|
+
const externalIds = await tmdb.people.externalIds(personId);
|
|
365
|
+
const portraits = await tmdb.people.images(personId);
|
|
366
|
+
const tagged = await tmdb.people.taggedImages(personId, { page: 1 });
|
|
367
|
+
const translations = await tmdb.people.translations(personId);
|
|
368
|
+
const latestPerson = await tmdb.people.latest();
|
|
369
|
+
const changedPeople = await tmdb.people.changeList({ page: 1 });
|
|
370
|
+
const changes = await tmdb.people.changes(personId);
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
The three credit collections return `cast` and `crew` arrays with TMDB's original fields; `combinedCredits()` includes both movie and TV roles. `taggedImages()` has paginated image records, including episode stills, while `images()` has portrait profiles. TMDB can report `page: 0` for tagged images even when page 1 is requested. `changeList()` and `changes()` accept optional `startDate`, `endDate`, and `page`; dates use `YYYY-MM-DD`. `popular()` and `taggedImages()` accept a positive page. Credit details, popular people, and the three credit collections support a `language` override. `latest()` can be incomplete while a new person record is being edited on TMDB.
|
|
374
|
+
|
|
351
375
|
## Image URLs
|
|
352
376
|
|
|
353
377
|
TMDB detail responses contain image paths. Build a safe public image URL with:
|
|
@@ -435,12 +459,12 @@ TMDB_API_KEY=... npm run test:live
|
|
|
435
459
|
```
|
|
436
460
|
|
|
437
461
|
The credential is read from the environment, never from a tracked file. This checks
|
|
438
|
-
all
|
|
462
|
+
all 111 public read operations. Account-state and rating methods require a TMDB
|
|
439
463
|
session and are covered by offline contracts; the live test makes read-only requests.
|
|
440
464
|
|
|
441
465
|
## Roadmap
|
|
442
466
|
|
|
443
|
-
|
|
467
|
+
Lists, authentication, and the remaining TMDB resources will expand coverage in future releases. The [coverage ledger](https://github.com/namipsg/lumosovich/blob/main/spec/coverage.json) tracks implemented and remaining operations.
|
|
444
468
|
|
|
445
469
|
The goal is to cover the TMDB API while keeping the library:
|
|
446
470
|
|
package/dist/detail-types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { TmdbId } from './types.js';
|
|
2
|
+
import type { PersonResourceMethods } from './person-types.js';
|
|
2
3
|
import type { MovieMetadataMethods } from './metadata-types.js';
|
|
3
4
|
import type { MovieCatalogMethods } from './catalog-types.js';
|
|
4
5
|
import type { TvCatalogMethods, TvMetadataMethods } from './tv-types.js';
|
|
@@ -87,6 +88,7 @@ export interface TvContentRatingsResponse {
|
|
|
87
88
|
}
|
|
88
89
|
export interface PersonCredit {
|
|
89
90
|
id: TmdbId;
|
|
91
|
+
credit_id?: string;
|
|
90
92
|
media_type?: 'movie' | 'tv';
|
|
91
93
|
title?: string;
|
|
92
94
|
name?: string;
|
|
@@ -251,6 +253,6 @@ export interface TvMethods extends TvMetadataMethods, TvCatalogMethods, TvSeries
|
|
|
251
253
|
get(seriesId: TmdbId, seasonNumber: number, episodeNumber: number, options?: EpisodeDetailOptions): Promise<TvEpisodeDetails>;
|
|
252
254
|
};
|
|
253
255
|
}
|
|
254
|
-
export interface PersonMethods {
|
|
256
|
+
export interface PersonMethods extends PersonResourceMethods {
|
|
255
257
|
get(id: TmdbId, options?: PersonDetailOptions): Promise<PersonDetails>;
|
|
256
258
|
}
|
package/dist/details.js
CHANGED
|
@@ -5,6 +5,7 @@ import { createTvMetadataMethods } from './tv-metadata.js';
|
|
|
5
5
|
import { createTvSeriesResourceMethods, createTvEpisodeGroupMethods } from './tv-series-resources.js';
|
|
6
6
|
import { createTvSeasonResourceMethods } from './tv-season-resources.js';
|
|
7
7
|
import { createTvEpisodeResourceMethods } from './tv-episode-resources.js';
|
|
8
|
+
import { createPersonResourceMethods } from './person-resources.js';
|
|
8
9
|
import { positiveId, slotNumber } from './ids.js';
|
|
9
10
|
import { validateDetailResponse, validateEpisodeResponse, validateSeasonResponse, } from './validation.js';
|
|
10
11
|
const MOVIE_APPEND = [
|
|
@@ -104,6 +105,7 @@ export function createTvMethods(http) {
|
|
|
104
105
|
}
|
|
105
106
|
export function createPersonMethods(http) {
|
|
106
107
|
return {
|
|
108
|
+
...createPersonResourceMethods(http),
|
|
107
109
|
async get(id, options = {}) {
|
|
108
110
|
const validId = positiveId(id);
|
|
109
111
|
const payload = await http.get(`person/${validId}`, detailParameters(options, PERSON_APPEND));
|
package/dist/index.cjs
CHANGED
|
@@ -915,6 +915,132 @@ function createTvEpisodeResourceMethods(http) {
|
|
|
915
915
|
};
|
|
916
916
|
}
|
|
917
917
|
|
|
918
|
+
// src/person-validation.ts
|
|
919
|
+
var positiveId2 = (value) => Number.isSafeInteger(value) && Number(value) > 0;
|
|
920
|
+
var count2 = (value) => Number.isSafeInteger(value) && Number(value) >= 0;
|
|
921
|
+
function validatePersonCredits(value, id) {
|
|
922
|
+
return validateIdShape(value, id, {
|
|
923
|
+
cast: metadataChecks.identities,
|
|
924
|
+
crew: metadataChecks.identities
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
function validatePopularPeople(value) {
|
|
928
|
+
const page3 = validateSearchPage(value);
|
|
929
|
+
if (!page3.results.every((person) => isRecord(person) && typeof person.name === "string")) {
|
|
930
|
+
invalidResponse();
|
|
931
|
+
}
|
|
932
|
+
return page3;
|
|
933
|
+
}
|
|
934
|
+
function validateTaggedImages(value, id) {
|
|
935
|
+
if (!isRecord(value) || value.id !== id || !count2(value.page) || !count2(value.total_pages) || !count2(value.total_results) || !Array.isArray(value.results) || !value.results.every((image) => isRecord(image) && typeof image.id === "string" && !!image.id && typeof image.file_path === "string" && typeof image.media_type === "string" && !!image.media_type && typeof image.image_type === "string" && isRecord(image.media) && positiveId2(image.media.id))) {
|
|
936
|
+
invalidResponse();
|
|
937
|
+
}
|
|
938
|
+
return value;
|
|
939
|
+
}
|
|
940
|
+
function validateCreditDetails(value, id) {
|
|
941
|
+
if (!isRecord(value) || value.id !== id || typeof value.credit_type !== "string" || !["movie", "tv"].includes(String(value.media_type)) || !isRecord(value.person) || !positiveId2(value.person.id) || typeof value.person.name !== "string" || !isRecord(value.media) || !positiveId2(value.media.id)) {
|
|
942
|
+
invalidResponse();
|
|
943
|
+
}
|
|
944
|
+
return value;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
// src/person-resources.ts
|
|
948
|
+
function createPersonResourceMethods(http) {
|
|
949
|
+
return {
|
|
950
|
+
async changeList(options = {}) {
|
|
951
|
+
return validateSearchPage(await http.get(
|
|
952
|
+
"person/changes",
|
|
953
|
+
changeParameters(options),
|
|
954
|
+
{ includeLanguage: false }
|
|
955
|
+
));
|
|
956
|
+
},
|
|
957
|
+
async changes(id, options = {}) {
|
|
958
|
+
const validId = positiveId(id);
|
|
959
|
+
return validateMovieChanges(await http.get(
|
|
960
|
+
`person/${validId}/changes`,
|
|
961
|
+
changeParameters(options),
|
|
962
|
+
{ includeLanguage: false }
|
|
963
|
+
));
|
|
964
|
+
},
|
|
965
|
+
async combinedCredits(id, options = {}) {
|
|
966
|
+
const validId = positiveId(id);
|
|
967
|
+
return validatePersonCredits(await http.get(`person/${validId}/combined_credits`, {
|
|
968
|
+
language: options.language
|
|
969
|
+
}), validId);
|
|
970
|
+
},
|
|
971
|
+
async externalIds(id) {
|
|
972
|
+
const validId = positiveId(id);
|
|
973
|
+
return validateIdShape(await http.get(
|
|
974
|
+
`person/${validId}/external_ids`,
|
|
975
|
+
{},
|
|
976
|
+
{ includeLanguage: false }
|
|
977
|
+
), validId, { imdb_id: metadataChecks.externalId, wikidata_id: metadataChecks.externalId });
|
|
978
|
+
},
|
|
979
|
+
async images(id) {
|
|
980
|
+
const validId = positiveId(id);
|
|
981
|
+
return validateIdShape(await http.get(
|
|
982
|
+
`person/${validId}/images`,
|
|
983
|
+
{},
|
|
984
|
+
{ includeLanguage: false }
|
|
985
|
+
), validId, { profiles: metadataChecks.images });
|
|
986
|
+
},
|
|
987
|
+
async latest() {
|
|
988
|
+
return validateLatestDetail(await http.get("person/latest", {}, { includeLanguage: false }), "name");
|
|
989
|
+
},
|
|
990
|
+
async movieCredits(id, options = {}) {
|
|
991
|
+
const validId = positiveId(id);
|
|
992
|
+
return validatePersonCredits(await http.get(`person/${validId}/movie_credits`, {
|
|
993
|
+
language: options.language
|
|
994
|
+
}), validId);
|
|
995
|
+
},
|
|
996
|
+
async popular(options = {}) {
|
|
997
|
+
if (options.page !== void 0 && (!Number.isSafeInteger(options.page) || options.page < 1)) {
|
|
998
|
+
throw new TypeError("page must be a positive integer");
|
|
999
|
+
}
|
|
1000
|
+
return validatePopularPeople(await http.get("person/popular", {
|
|
1001
|
+
language: options.language,
|
|
1002
|
+
page: options.page
|
|
1003
|
+
}));
|
|
1004
|
+
},
|
|
1005
|
+
async taggedImages(id, options = {}) {
|
|
1006
|
+
const validId = positiveId(id);
|
|
1007
|
+
if (options.page !== void 0 && (!Number.isSafeInteger(options.page) || options.page < 1)) {
|
|
1008
|
+
throw new TypeError("page must be a positive integer");
|
|
1009
|
+
}
|
|
1010
|
+
return validateTaggedImages(await http.get(
|
|
1011
|
+
`person/${validId}/tagged_images`,
|
|
1012
|
+
{ page: options.page },
|
|
1013
|
+
{ includeLanguage: false }
|
|
1014
|
+
), validId);
|
|
1015
|
+
},
|
|
1016
|
+
async translations(id) {
|
|
1017
|
+
const validId = positiveId(id);
|
|
1018
|
+
return validateIdShape(await http.get(
|
|
1019
|
+
`person/${validId}/translations`,
|
|
1020
|
+
{},
|
|
1021
|
+
{ includeLanguage: false }
|
|
1022
|
+
), validId, { translations: metadataChecks.translations });
|
|
1023
|
+
},
|
|
1024
|
+
async tvCredits(id, options = {}) {
|
|
1025
|
+
const validId = positiveId(id);
|
|
1026
|
+
return validatePersonCredits(await http.get(`person/${validId}/tv_credits`, {
|
|
1027
|
+
language: options.language
|
|
1028
|
+
}), validId);
|
|
1029
|
+
}
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
function createCreditMethods(http) {
|
|
1033
|
+
return {
|
|
1034
|
+
async get(creditId, options = {}) {
|
|
1035
|
+
const id = pathId(creditId, "credit ID");
|
|
1036
|
+
return validateCreditDetails(await http.get(
|
|
1037
|
+
`credit/${encodeURIComponent(id)}`,
|
|
1038
|
+
{ language: options.language }
|
|
1039
|
+
), id);
|
|
1040
|
+
}
|
|
1041
|
+
};
|
|
1042
|
+
}
|
|
1043
|
+
|
|
918
1044
|
// src/details.ts
|
|
919
1045
|
var MOVIE_APPEND = [
|
|
920
1046
|
"credits",
|
|
@@ -1024,6 +1150,7 @@ function createTvMethods(http) {
|
|
|
1024
1150
|
}
|
|
1025
1151
|
function createPersonMethods(http) {
|
|
1026
1152
|
return {
|
|
1153
|
+
...createPersonResourceMethods(http),
|
|
1027
1154
|
async get(id, options = {}) {
|
|
1028
1155
|
const validId = positiveId(id);
|
|
1029
1156
|
const payload = await http.get(
|
|
@@ -1582,6 +1709,7 @@ var Lumosovich = class {
|
|
|
1582
1709
|
networks;
|
|
1583
1710
|
tv;
|
|
1584
1711
|
people;
|
|
1712
|
+
credits;
|
|
1585
1713
|
images;
|
|
1586
1714
|
configuration;
|
|
1587
1715
|
certifications;
|
|
@@ -1623,6 +1751,7 @@ var Lumosovich = class {
|
|
|
1623
1751
|
this.networks = createNetworkMethods(http);
|
|
1624
1752
|
this.tv = createTvMethods(http);
|
|
1625
1753
|
this.people = createPersonMethods(http);
|
|
1754
|
+
this.credits = createCreditMethods(http);
|
|
1626
1755
|
this.images = createImageMethods();
|
|
1627
1756
|
this.configuration = createConfigurationMethods(http);
|
|
1628
1757
|
this.certifications = createCertificationMethods(http);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CreditMethods } from './person-types.js';
|
|
1
2
|
import type { CertificationMethods, ConfigurationMethods, GenreMethods } from './reference-types.js';
|
|
2
3
|
import type { ExternalIdSource, FindOptions, FindResponse, LumosovichOptions, SearchMethods } from './types.js';
|
|
3
4
|
import type { MovieMethods, PersonMethods, TvMethods } from './detail-types.js';
|
|
@@ -6,6 +7,7 @@ import type { CollectionMethods, CompanyMethods } from './metadata-types.js';
|
|
|
6
7
|
import type { DiscoverMethods, KeywordMethods, NetworkMethods, ReviewMethods, TrendingMethods } from './catalog-types.js';
|
|
7
8
|
export { TmdbError } from './errors.js';
|
|
8
9
|
export type { TmdbErrorCode } from './errors.js';
|
|
10
|
+
export type { CreditDetails, CreditMethods, PersonChangeListOptions, PersonChangeListPage, PersonChangesOptions, PersonChangesResponse, PersonCreditsResponse, PersonExternalIdsResponse, PersonImagesResponse, PersonPopularHit, PersonPopularPage, PersonResourceMethods, PersonTaggedImage, PersonTaggedImagesPage, PersonTranslationsResponse, } from './person-types.js';
|
|
9
11
|
export type { ImageMethods, ImageSize } from './images.js';
|
|
10
12
|
export type { DiscoverMethods, DiscoverCommonOptions, KeywordDetails, KeywordMethods, KeywordMoviesPage, MovieAccountStates, MovieCatalogMethods, MovieCatalogOptions, MovieCatalogPage, MovieChangeListOptions, MovieChangeListPage, MovieDiscoverOptions, MovieListHit, MovieListPage, NetworkAlternativeNamesResponse, NetworkDetails, NetworkImagesResponse, NetworkMethods, RatingResponse, RatingSession, ReviewDetails, ReviewMethods, ReviewPage, ReviewSummary, TrendingMethods, TrendingWindow, TvDiscoverOptions, } from './catalog-types.js';
|
|
11
13
|
export type { Certification, CertificationMethods, CertificationsResponse, ConfigurationMethods, ConfigurationResponse, Country, CountryTimezones, DepartmentJobs, GenreMethods, GenresResponse, ImageConfiguration, Language, LanguageOptions, } from './reference-types.js';
|
|
@@ -30,6 +32,7 @@ export declare class Lumosovich {
|
|
|
30
32
|
readonly networks: NetworkMethods;
|
|
31
33
|
readonly tv: TvMethods;
|
|
32
34
|
readonly people: PersonMethods;
|
|
35
|
+
readonly credits: CreditMethods;
|
|
33
36
|
readonly images: ImageMethods;
|
|
34
37
|
readonly configuration: ConfigurationMethods;
|
|
35
38
|
readonly certifications: CertificationMethods;
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { createCollectionMethods, createCompanyMethods } from './metadata.js';
|
|
|
5
5
|
import { createDiscoverMethods } from './discover.js';
|
|
6
6
|
import { createKeywordMethods, createNetworkMethods, createReviewMethods, createTrendingMethods, } from './explore.js';
|
|
7
7
|
import { createSearchMethods } from './search.js';
|
|
8
|
+
import { createCreditMethods } from './person-resources.js';
|
|
8
9
|
import { createCertificationMethods, createConfigurationMethods, createGenreMethods } from './reference.js';
|
|
9
10
|
import { validateFindResponse } from './validation.js';
|
|
10
11
|
export { TmdbError } from './errors.js';
|
|
@@ -22,6 +23,7 @@ export class Lumosovich {
|
|
|
22
23
|
networks;
|
|
23
24
|
tv;
|
|
24
25
|
people;
|
|
26
|
+
credits;
|
|
25
27
|
images;
|
|
26
28
|
configuration;
|
|
27
29
|
certifications;
|
|
@@ -55,6 +57,7 @@ export class Lumosovich {
|
|
|
55
57
|
this.networks = createNetworkMethods(http);
|
|
56
58
|
this.tv = createTvMethods(http);
|
|
57
59
|
this.people = createPersonMethods(http);
|
|
60
|
+
this.credits = createCreditMethods(http);
|
|
58
61
|
this.images = createImageMethods();
|
|
59
62
|
this.configuration = createConfigurationMethods(http);
|
|
60
63
|
this.certifications = createCertificationMethods(http);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { TmdbHttpClient } from './http.js';
|
|
2
|
+
import type { PersonResourceMethods, CreditMethods } from './person-types.js';
|
|
3
|
+
export declare function createPersonResourceMethods(http: TmdbHttpClient): PersonResourceMethods;
|
|
4
|
+
export declare function createCreditMethods(http: TmdbHttpClient): CreditMethods;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { pathId, positiveId } from './ids.js';
|
|
2
|
+
import { changeParameters } from './metadata.js';
|
|
3
|
+
import { metadataChecks, validateIdShape, validateLatestDetail, validateMovieChanges } from './metadata-validation.js';
|
|
4
|
+
import { validateSearchPage } from './validation.js';
|
|
5
|
+
import { validateCreditDetails, validatePersonCredits, validatePopularPeople, validateTaggedImages } from './person-validation.js';
|
|
6
|
+
export function createPersonResourceMethods(http) {
|
|
7
|
+
return {
|
|
8
|
+
async changeList(options = {}) {
|
|
9
|
+
return validateSearchPage(await http.get('person/changes', changeParameters(options), { includeLanguage: false }));
|
|
10
|
+
},
|
|
11
|
+
async changes(id, options = {}) {
|
|
12
|
+
const validId = positiveId(id);
|
|
13
|
+
return validateMovieChanges(await http.get(`person/${validId}/changes`, changeParameters(options), { includeLanguage: false }));
|
|
14
|
+
},
|
|
15
|
+
async combinedCredits(id, options = {}) {
|
|
16
|
+
const validId = positiveId(id);
|
|
17
|
+
return validatePersonCredits(await http.get(`person/${validId}/combined_credits`, {
|
|
18
|
+
language: options.language,
|
|
19
|
+
}), validId);
|
|
20
|
+
},
|
|
21
|
+
async externalIds(id) {
|
|
22
|
+
const validId = positiveId(id);
|
|
23
|
+
return validateIdShape(await http.get(`person/${validId}/external_ids`, {}, { includeLanguage: false }), validId, { imdb_id: metadataChecks.externalId, wikidata_id: metadataChecks.externalId });
|
|
24
|
+
},
|
|
25
|
+
async images(id) {
|
|
26
|
+
const validId = positiveId(id);
|
|
27
|
+
return validateIdShape(await http.get(`person/${validId}/images`, {}, { includeLanguage: false }), validId, { profiles: metadataChecks.images });
|
|
28
|
+
},
|
|
29
|
+
async latest() {
|
|
30
|
+
return validateLatestDetail(await http.get('person/latest', {}, { includeLanguage: false }), 'name');
|
|
31
|
+
},
|
|
32
|
+
async movieCredits(id, options = {}) {
|
|
33
|
+
const validId = positiveId(id);
|
|
34
|
+
return validatePersonCredits(await http.get(`person/${validId}/movie_credits`, {
|
|
35
|
+
language: options.language,
|
|
36
|
+
}), validId);
|
|
37
|
+
},
|
|
38
|
+
async popular(options = {}) {
|
|
39
|
+
if (options.page !== undefined && (!Number.isSafeInteger(options.page) || options.page < 1)) {
|
|
40
|
+
throw new TypeError('page must be a positive integer');
|
|
41
|
+
}
|
|
42
|
+
return validatePopularPeople(await http.get('person/popular', {
|
|
43
|
+
language: options.language, page: options.page,
|
|
44
|
+
}));
|
|
45
|
+
},
|
|
46
|
+
async taggedImages(id, options = {}) {
|
|
47
|
+
const validId = positiveId(id);
|
|
48
|
+
if (options.page !== undefined && (!Number.isSafeInteger(options.page) || options.page < 1)) {
|
|
49
|
+
throw new TypeError('page must be a positive integer');
|
|
50
|
+
}
|
|
51
|
+
return validateTaggedImages(await http.get(`person/${validId}/tagged_images`, { page: options.page }, { includeLanguage: false }), validId);
|
|
52
|
+
},
|
|
53
|
+
async translations(id) {
|
|
54
|
+
const validId = positiveId(id);
|
|
55
|
+
return validateIdShape(await http.get(`person/${validId}/translations`, {}, { includeLanguage: false }), validId, { translations: metadataChecks.translations });
|
|
56
|
+
},
|
|
57
|
+
async tvCredits(id, options = {}) {
|
|
58
|
+
const validId = positiveId(id);
|
|
59
|
+
return validatePersonCredits(await http.get(`person/${validId}/tv_credits`, {
|
|
60
|
+
language: options.language,
|
|
61
|
+
}), validId);
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function createCreditMethods(http) {
|
|
66
|
+
return {
|
|
67
|
+
async get(creditId, options = {}) {
|
|
68
|
+
const id = pathId(creditId, 'credit ID');
|
|
69
|
+
return validateCreditDetails(await http.get(`credit/${encodeURIComponent(id)}`, { language: options.language }), id);
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { ImageAsset, PersonCredit, PersonDetails } from './detail-types.js';
|
|
2
|
+
import type { MovieChangeListOptions } from './catalog-types.js';
|
|
3
|
+
import type { MovieChangesOptions, MovieChangesResponse, TranslationsResponse } from './metadata-types.js';
|
|
4
|
+
import type { LanguageOptions } from './reference-types.js';
|
|
5
|
+
import type { PageOptions, SearchPage, TmdbId } from './types.js';
|
|
6
|
+
export type PersonChangeListOptions = MovieChangeListOptions;
|
|
7
|
+
export type PersonChangesOptions = MovieChangesOptions;
|
|
8
|
+
export type PersonChangesResponse = MovieChangesResponse;
|
|
9
|
+
export type PersonTranslationsResponse = TranslationsResponse;
|
|
10
|
+
export type PersonChangeListPage = SearchPage<{
|
|
11
|
+
id: TmdbId;
|
|
12
|
+
adult?: boolean;
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
}>;
|
|
15
|
+
export interface PersonPopularHit {
|
|
16
|
+
id: TmdbId;
|
|
17
|
+
name: string;
|
|
18
|
+
known_for?: Array<Record<string, unknown>>;
|
|
19
|
+
profile_path?: string | null;
|
|
20
|
+
[key: string]: unknown;
|
|
21
|
+
}
|
|
22
|
+
export type PersonPopularPage = SearchPage<PersonPopularHit>;
|
|
23
|
+
export interface PersonCreditsResponse {
|
|
24
|
+
id: TmdbId;
|
|
25
|
+
cast: PersonCredit[];
|
|
26
|
+
crew: PersonCredit[];
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
export interface PersonExternalIdsResponse {
|
|
30
|
+
id: TmdbId;
|
|
31
|
+
imdb_id?: string | null;
|
|
32
|
+
wikidata_id?: string | null;
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
export interface PersonImagesResponse {
|
|
36
|
+
id: TmdbId;
|
|
37
|
+
profiles: ImageAsset[];
|
|
38
|
+
[key: string]: unknown;
|
|
39
|
+
}
|
|
40
|
+
export interface PersonTaggedImage extends ImageAsset {
|
|
41
|
+
id: string;
|
|
42
|
+
image_type: string;
|
|
43
|
+
media_type: string;
|
|
44
|
+
media: Record<string, unknown>;
|
|
45
|
+
}
|
|
46
|
+
export interface PersonTaggedImagesPage {
|
|
47
|
+
id: TmdbId;
|
|
48
|
+
page: number;
|
|
49
|
+
results: PersonTaggedImage[];
|
|
50
|
+
total_pages: number;
|
|
51
|
+
total_results: number;
|
|
52
|
+
[key: string]: unknown;
|
|
53
|
+
}
|
|
54
|
+
export interface CreditDetails {
|
|
55
|
+
id: string;
|
|
56
|
+
credit_type: string;
|
|
57
|
+
media_type: 'movie' | 'tv';
|
|
58
|
+
person: {
|
|
59
|
+
id: TmdbId;
|
|
60
|
+
name: string;
|
|
61
|
+
[key: string]: unknown;
|
|
62
|
+
};
|
|
63
|
+
media: {
|
|
64
|
+
id: TmdbId;
|
|
65
|
+
[key: string]: unknown;
|
|
66
|
+
};
|
|
67
|
+
department?: string;
|
|
68
|
+
job?: string;
|
|
69
|
+
[key: string]: unknown;
|
|
70
|
+
}
|
|
71
|
+
export interface CreditMethods {
|
|
72
|
+
get(creditId: string, options?: LanguageOptions): Promise<CreditDetails>;
|
|
73
|
+
}
|
|
74
|
+
export interface PersonResourceMethods {
|
|
75
|
+
changeList(options?: PersonChangeListOptions): Promise<PersonChangeListPage>;
|
|
76
|
+
changes(id: TmdbId, options?: PersonChangesOptions): Promise<PersonChangesResponse>;
|
|
77
|
+
combinedCredits(id: TmdbId, options?: LanguageOptions): Promise<PersonCreditsResponse>;
|
|
78
|
+
externalIds(id: TmdbId): Promise<PersonExternalIdsResponse>;
|
|
79
|
+
images(id: TmdbId): Promise<PersonImagesResponse>;
|
|
80
|
+
latest(): Promise<PersonDetails>;
|
|
81
|
+
movieCredits(id: TmdbId, options?: LanguageOptions): Promise<PersonCreditsResponse>;
|
|
82
|
+
popular(options?: PageOptions & LanguageOptions): Promise<PersonPopularPage>;
|
|
83
|
+
taggedImages(id: TmdbId, options?: PageOptions): Promise<PersonTaggedImagesPage>;
|
|
84
|
+
translations(id: TmdbId): Promise<PersonTranslationsResponse>;
|
|
85
|
+
tvCredits(id: TmdbId, options?: LanguageOptions): Promise<PersonCreditsResponse>;
|
|
86
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CreditDetails, PersonTaggedImagesPage } from './person-types.js';
|
|
2
|
+
export declare function validatePersonCredits<T>(value: unknown, id: number): T;
|
|
3
|
+
export declare function validatePopularPeople<T>(value: unknown): T;
|
|
4
|
+
export declare function validateTaggedImages(value: unknown, id: number): PersonTaggedImagesPage;
|
|
5
|
+
export declare function validateCreditDetails(value: unknown, id: string): CreditDetails;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { invalidResponse, isRecord, validateSearchPage } from './validation.js';
|
|
2
|
+
import { metadataChecks, validateIdShape } from './metadata-validation.js';
|
|
3
|
+
const positiveId = (value) => Number.isSafeInteger(value) && Number(value) > 0;
|
|
4
|
+
const count = (value) => Number.isSafeInteger(value) && Number(value) >= 0;
|
|
5
|
+
export function validatePersonCredits(value, id) {
|
|
6
|
+
return validateIdShape(value, id, {
|
|
7
|
+
cast: metadataChecks.identities,
|
|
8
|
+
crew: metadataChecks.identities,
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
export function validatePopularPeople(value) {
|
|
12
|
+
const page = validateSearchPage(value);
|
|
13
|
+
if (!page.results.every((person) => isRecord(person) && typeof person.name === 'string')) {
|
|
14
|
+
invalidResponse();
|
|
15
|
+
}
|
|
16
|
+
return page;
|
|
17
|
+
}
|
|
18
|
+
export function validateTaggedImages(value, id) {
|
|
19
|
+
if (!isRecord(value) || value.id !== id || !count(value.page) ||
|
|
20
|
+
!count(value.total_pages) || !count(value.total_results) ||
|
|
21
|
+
!Array.isArray(value.results) || !value.results.every((image) => isRecord(image) && typeof image.id === 'string' && !!image.id &&
|
|
22
|
+
typeof image.file_path === 'string' &&
|
|
23
|
+
typeof image.media_type === 'string' && !!image.media_type &&
|
|
24
|
+
typeof image.image_type === 'string' && isRecord(image.media) &&
|
|
25
|
+
positiveId(image.media.id))) {
|
|
26
|
+
invalidResponse();
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
export function validateCreditDetails(value, id) {
|
|
31
|
+
if (!isRecord(value) || value.id !== id ||
|
|
32
|
+
typeof value.credit_type !== 'string' ||
|
|
33
|
+
!['movie', 'tv'].includes(String(value.media_type)) ||
|
|
34
|
+
!isRecord(value.person) || !positiveId(value.person.id) ||
|
|
35
|
+
typeof value.person.name !== 'string' ||
|
|
36
|
+
!isRecord(value.media) || !positiveId(value.media.id)) {
|
|
37
|
+
invalidResponse();
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|