tmdb-kit 1.0.0 → 1.1.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 +293 -198
- package/dist/cli.js +3132 -0
- package/dist/client.d.cts +63 -0
- package/dist/client.d.ts +63 -0
- package/dist/errors.d.cts +74 -0
- package/dist/errors.d.ts +74 -0
- package/dist/http.d.cts +80 -0
- package/dist/http.d.ts +80 -0
- package/dist/index.cjs +747 -768
- package/dist/index.cjs.map +23 -1
- package/dist/index.d.cts +8 -783
- package/dist/index.d.ts +8 -783
- package/dist/index.js +707 -745
- package/dist/index.js.map +23 -1
- package/dist/query.d.cts +77 -0
- package/dist/query.d.ts +77 -0
- package/dist/resources/configuration.d.cts +17 -0
- package/dist/resources/configuration.d.ts +17 -0
- package/dist/resources/genres.d.cts +13 -0
- package/dist/resources/genres.d.ts +13 -0
- package/dist/resources/images.d.cts +17 -0
- package/dist/resources/images.d.ts +17 -0
- package/dist/resources/movies.d.cts +21 -0
- package/dist/resources/movies.d.ts +21 -0
- package/dist/resources/people.d.cts +14 -0
- package/dist/resources/people.d.ts +14 -0
- package/dist/resources/search.d.cts +15 -0
- package/dist/resources/search.d.ts +15 -0
- package/dist/resources/trending.d.cts +23 -0
- package/dist/resources/trending.d.ts +23 -0
- package/dist/resources/tv.d.cts +22 -0
- package/dist/resources/tv.d.ts +22 -0
- package/dist/search-guards.d.cts +32 -0
- package/dist/search-guards.d.ts +32 -0
- package/dist/types.d.cts +452 -0
- package/dist/types.d.ts +452 -0
- package/package.json +26 -19
package/dist/index.js
CHANGED
|
@@ -1,798 +1,760 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
* The SDK does NOT retry automatically — that decision is left to the
|
|
64
|
-
* caller, since retry policies vary widely. Inspect `retryAfter` to
|
|
65
|
-
* implement your own backoff.
|
|
66
|
-
*/
|
|
67
|
-
var TMDBRateLimitError = class extends TMDBResponseError {
|
|
68
|
-
retryAfter;
|
|
69
|
-
constructor(message, options) {
|
|
70
|
-
super(message, options);
|
|
71
|
-
this.name = "TMDBRateLimitError";
|
|
72
|
-
this.retryAfter = options.retryAfter;
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
/**
|
|
76
|
-
* Create the appropriate error instance for a non-2xx TMDB response.
|
|
77
|
-
*
|
|
78
|
-
* Returns a {@link TMDBRateLimitError} when the status is 429, otherwise
|
|
79
|
-
* a generic {@link TMDBResponseError}. The error message is extracted from
|
|
80
|
-
* the TMDB `status_message` field when available.
|
|
81
|
-
*/
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
class TMDBError extends Error {
|
|
3
|
+
constructor(message, options) {
|
|
4
|
+
super(message, options);
|
|
5
|
+
this.name = "TMDBError";
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
class TMDBRequestError extends TMDBError {
|
|
10
|
+
constructor(message, options) {
|
|
11
|
+
super(message, options);
|
|
12
|
+
this.name = "TMDBRequestError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class TMDBResponseError extends TMDBError {
|
|
17
|
+
body;
|
|
18
|
+
headers;
|
|
19
|
+
requestId;
|
|
20
|
+
status;
|
|
21
|
+
statusCode;
|
|
22
|
+
statusMessage;
|
|
23
|
+
statusText;
|
|
24
|
+
url;
|
|
25
|
+
constructor(message, options) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = "TMDBResponseError";
|
|
28
|
+
this.body = options.body;
|
|
29
|
+
this.headers = options.headers;
|
|
30
|
+
this.requestId = options.headers.get("x-request-id");
|
|
31
|
+
this.status = options.status;
|
|
32
|
+
this.statusText = options.statusText;
|
|
33
|
+
this.url = options.url;
|
|
34
|
+
const body = isErrorResponseBody(options.body) ? options.body : undefined;
|
|
35
|
+
this.statusCode = body?.status_code;
|
|
36
|
+
this.statusMessage = body?.status_message;
|
|
37
|
+
}
|
|
38
|
+
get isRateLimit() {
|
|
39
|
+
return this.status === 429;
|
|
40
|
+
}
|
|
41
|
+
get isNotFound() {
|
|
42
|
+
return this.status === 404;
|
|
43
|
+
}
|
|
44
|
+
get isUnauthorized() {
|
|
45
|
+
return this.status === 401;
|
|
46
|
+
}
|
|
47
|
+
get isForbidden() {
|
|
48
|
+
return this.status === 403;
|
|
49
|
+
}
|
|
50
|
+
get isServerError() {
|
|
51
|
+
return this.status >= 500 && this.status < 600;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class TMDBRateLimitError extends TMDBResponseError {
|
|
56
|
+
retryAfter;
|
|
57
|
+
constructor(message, options) {
|
|
58
|
+
super(message, options);
|
|
59
|
+
this.name = "TMDBRateLimitError";
|
|
60
|
+
this.retryAfter = options.retryAfter;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
82
63
|
function createResponseError(options) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
* Falls back to 1 second when the header is missing or unparseable.
|
|
94
|
-
*/
|
|
64
|
+
const body = isErrorResponseBody(options.body) ? options.body : undefined;
|
|
65
|
+
const message = body?.status_message ?? `${options.status} ${options.statusText}`.trim();
|
|
66
|
+
if (options.status === 429) {
|
|
67
|
+
return new TMDBRateLimitError(message, {
|
|
68
|
+
...options,
|
|
69
|
+
retryAfter: parseRetryAfter(options.headers.get("retry-after"))
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return new TMDBResponseError(message, options);
|
|
73
|
+
}
|
|
95
74
|
function parseRetryAfter(value) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
75
|
+
if (value === null || value === undefined) {
|
|
76
|
+
return 1;
|
|
77
|
+
}
|
|
78
|
+
const trimmed = value.trim();
|
|
79
|
+
if (trimmed === "") {
|
|
80
|
+
return 1;
|
|
81
|
+
}
|
|
82
|
+
const seconds = Number(trimmed);
|
|
83
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
84
|
+
return seconds;
|
|
85
|
+
}
|
|
86
|
+
const date = Date.parse(trimmed);
|
|
87
|
+
if (Number.isFinite(date)) {
|
|
88
|
+
const deltaMs = date - Date.now();
|
|
89
|
+
return Math.max(1, Math.ceil(deltaMs / 1000));
|
|
90
|
+
}
|
|
91
|
+
return 1;
|
|
92
|
+
}
|
|
109
93
|
function isErrorResponseBody(value) {
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
* - Arrays are joined with commas (TMDB convention).
|
|
117
|
-
* - All values are converted to strings.
|
|
118
|
-
*/
|
|
94
|
+
return typeof value === "object" && value !== null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/query.ts
|
|
98
|
+
var DEFAULT_API_BASE_URL = "https://api.themoviedb.org/3";
|
|
99
|
+
var DEFAULT_IMAGE_BASE_URL = "https://image.tmdb.org/t/p";
|
|
119
100
|
function appendQuery(url, query) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
*
|
|
132
|
-
* If `query.language` is set it takes precedence; otherwise the client's
|
|
133
|
-
* default language is used.
|
|
134
|
-
*/
|
|
101
|
+
for (const [key, value] of Object.entries(query)) {
|
|
102
|
+
if (value === undefined || value === null) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (Array.isArray(value)) {
|
|
106
|
+
url.searchParams.set(key, value.map(String).join(","));
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
url.searchParams.set(key, String(value));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
135
112
|
function withLanguage(defaults, query) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Merge language and region defaults for list endpoints.
|
|
144
|
-
*
|
|
145
|
-
* Combines {@link withLanguage} with region fallback from client defaults.
|
|
146
|
-
*/
|
|
113
|
+
const language = typeof query.language === "string" ? query.language : defaults.language;
|
|
114
|
+
return {
|
|
115
|
+
...query,
|
|
116
|
+
language
|
|
117
|
+
};
|
|
118
|
+
}
|
|
147
119
|
function withListDefaults(defaults, query) {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Convert a string or string array to a comma-separated list.
|
|
156
|
-
*
|
|
157
|
-
* Returns `undefined` if the input is `undefined` (skips the parameter).
|
|
158
|
-
* TMDB uses comma-separated values for multi-value query parameters.
|
|
159
|
-
*/
|
|
120
|
+
const region = typeof query.region === "string" ? query.region : defaults.region;
|
|
121
|
+
return {
|
|
122
|
+
...withLanguage(defaults, query),
|
|
123
|
+
region
|
|
124
|
+
};
|
|
125
|
+
}
|
|
160
126
|
function toCommaList(value) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
*
|
|
167
|
-
* @throws {TMDBRequestError} If `value` is not a positive integer.
|
|
168
|
-
*/
|
|
127
|
+
if (value === undefined) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
return typeof value === "string" ? value : value.join(",");
|
|
131
|
+
}
|
|
169
132
|
function toId(value, name) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
*
|
|
176
|
-
* @throws {TMDBRequestError} If the query is empty after trimming.
|
|
177
|
-
*/
|
|
133
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
134
|
+
throw new TMDBRequestError(`${name} must be a positive integer`);
|
|
135
|
+
}
|
|
136
|
+
return String(value);
|
|
137
|
+
}
|
|
178
138
|
function toSearchQuery(value) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
*
|
|
186
|
-
* @throws {TMDBRequestError} If `value` is not `"day"` or `"week"`.
|
|
187
|
-
*/
|
|
139
|
+
const query = value.trim();
|
|
140
|
+
if (query.length === 0) {
|
|
141
|
+
throw new TMDBRequestError("search query must not be empty");
|
|
142
|
+
}
|
|
143
|
+
return query;
|
|
144
|
+
}
|
|
188
145
|
function toTimeWindow(value) {
|
|
189
|
-
|
|
190
|
-
|
|
146
|
+
if (value !== "day" && value !== "week") {
|
|
147
|
+
throw new TMDBRequestError('timeWindow must be either "day" or "week"');
|
|
148
|
+
}
|
|
149
|
+
return value;
|
|
191
150
|
}
|
|
192
|
-
/**
|
|
193
|
-
* Build a full TMDB image URL from the path returned by API payloads.
|
|
194
|
-
* Returns null for nullish image paths so UI code can branch naturally.
|
|
195
|
-
*/
|
|
196
151
|
function buildImageUrl(path, size = "original", options = {}) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
152
|
+
if (path === undefined || path === null || path.trim() === "") {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl ?? DEFAULT_IMAGE_BASE_URL);
|
|
156
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
157
|
+
const url = `${baseUrl}/${size}${normalizedPath}`;
|
|
158
|
+
return options.transform ? options.transform(url) : url;
|
|
200
159
|
}
|
|
201
|
-
/**
|
|
202
|
-
* Strip trailing slashes from a base URL to ensure consistent path joining.
|
|
203
|
-
*/
|
|
204
160
|
function normalizeBaseUrl(baseUrl) {
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
* text for certain error conditions).
|
|
294
|
-
*/
|
|
161
|
+
return baseUrl.replace(/\/+$/, "");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/http.ts
|
|
165
|
+
class TMDBHttpClient {
|
|
166
|
+
defaults;
|
|
167
|
+
imageTransform;
|
|
168
|
+
#apiKey;
|
|
169
|
+
#accessToken;
|
|
170
|
+
#baseUrl;
|
|
171
|
+
#fetch;
|
|
172
|
+
#headers;
|
|
173
|
+
constructor(options) {
|
|
174
|
+
const accessToken = normalizeSecret("accessToken" in options ? options.accessToken : undefined);
|
|
175
|
+
const apiKey = normalizeSecret("apiKey" in options ? options.apiKey : undefined);
|
|
176
|
+
if (Boolean(accessToken) === Boolean(apiKey)) {
|
|
177
|
+
throw new TMDBRequestError("Provide exactly one of accessToken or apiKey");
|
|
178
|
+
}
|
|
179
|
+
this.#accessToken = accessToken;
|
|
180
|
+
this.#apiKey = apiKey;
|
|
181
|
+
this.#baseUrl = normalizeBaseUrl(options.baseUrl ?? DEFAULT_API_BASE_URL);
|
|
182
|
+
this.#fetch = options.fetch;
|
|
183
|
+
this.#headers = options.headers;
|
|
184
|
+
this.defaults = {
|
|
185
|
+
imageBaseUrl: normalizeBaseUrl(options.imageBaseUrl ?? DEFAULT_IMAGE_BASE_URL),
|
|
186
|
+
language: options.defaultLanguage,
|
|
187
|
+
region: options.defaultRegion
|
|
188
|
+
};
|
|
189
|
+
this.imageTransform = options.images?.transform;
|
|
190
|
+
}
|
|
191
|
+
async get(path, options = {}) {
|
|
192
|
+
const url = this.#createUrl(path, options.query ?? {});
|
|
193
|
+
const headers = this.#createHeaders(options.headers);
|
|
194
|
+
const fetchImpl = this.#resolveFetch();
|
|
195
|
+
let response;
|
|
196
|
+
try {
|
|
197
|
+
response = await fetchImpl(url, {
|
|
198
|
+
headers,
|
|
199
|
+
method: "GET",
|
|
200
|
+
signal: options.signal
|
|
201
|
+
});
|
|
202
|
+
} catch (error) {
|
|
203
|
+
throw new TMDBRequestError(`TMDB request failed: ${String(error)}`, { cause: error });
|
|
204
|
+
}
|
|
205
|
+
const body = await readJson(response);
|
|
206
|
+
if (!response.ok) {
|
|
207
|
+
throw createResponseError({
|
|
208
|
+
body,
|
|
209
|
+
headers: response.headers,
|
|
210
|
+
status: response.status,
|
|
211
|
+
statusText: response.statusText,
|
|
212
|
+
url
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return body;
|
|
216
|
+
}
|
|
217
|
+
#resolveFetch() {
|
|
218
|
+
if (this.#fetch !== undefined) {
|
|
219
|
+
return this.#fetch;
|
|
220
|
+
}
|
|
221
|
+
const globalFetch = globalThis.fetch;
|
|
222
|
+
if (typeof globalFetch !== "function") {
|
|
223
|
+
throw new TMDBRequestError("No fetch implementation found. Pass options.fetch in this runtime.");
|
|
224
|
+
}
|
|
225
|
+
return globalFetch.bind(globalThis);
|
|
226
|
+
}
|
|
227
|
+
#createHeaders(headersInit) {
|
|
228
|
+
const headers = new Headers(this.#headers);
|
|
229
|
+
const requestHeaders = new Headers(headersInit);
|
|
230
|
+
headers.set("Accept", "application/json");
|
|
231
|
+
for (const [key, value] of requestHeaders) {
|
|
232
|
+
headers.set(key, value);
|
|
233
|
+
}
|
|
234
|
+
if (this.#accessToken !== undefined) {
|
|
235
|
+
headers.set("Authorization", `Bearer ${this.#accessToken}`);
|
|
236
|
+
}
|
|
237
|
+
return headers;
|
|
238
|
+
}
|
|
239
|
+
#createUrl(path, query) {
|
|
240
|
+
const relativePath = path.replace(/^\/+/, "");
|
|
241
|
+
const url = new URL(relativePath, `${this.#baseUrl}/`);
|
|
242
|
+
appendQuery(url, {
|
|
243
|
+
...query,
|
|
244
|
+
api_key: this.#apiKey
|
|
245
|
+
});
|
|
246
|
+
return url.toString();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
295
249
|
async function readJson(response) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
* strings as undefined (not provided).
|
|
307
|
-
*/
|
|
250
|
+
const text = await response.text();
|
|
251
|
+
if (text.length === 0) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
return JSON.parse(text);
|
|
256
|
+
} catch {
|
|
257
|
+
return text;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
308
260
|
function normalizeSecret(value) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
}
|
|
433
|
-
|
|
261
|
+
const secret = value?.trim();
|
|
262
|
+
return secret === "" ? undefined : secret;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// src/resources/configuration.ts
|
|
266
|
+
class ConfigurationResource {
|
|
267
|
+
#transport;
|
|
268
|
+
constructor(transport) {
|
|
269
|
+
this.#transport = transport;
|
|
270
|
+
}
|
|
271
|
+
details() {
|
|
272
|
+
return this.#transport.get("/configuration");
|
|
273
|
+
}
|
|
274
|
+
countries() {
|
|
275
|
+
return this.#transport.get("/configuration/countries");
|
|
276
|
+
}
|
|
277
|
+
jobs() {
|
|
278
|
+
return this.#transport.get("/configuration/jobs");
|
|
279
|
+
}
|
|
280
|
+
languages() {
|
|
281
|
+
return this.#transport.get("/configuration/languages");
|
|
282
|
+
}
|
|
283
|
+
primaryTranslations() {
|
|
284
|
+
return this.#transport.get("/configuration/primary_translations");
|
|
285
|
+
}
|
|
286
|
+
timezones() {
|
|
287
|
+
return this.#transport.get("/configuration/timezones");
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// src/resources/genres.ts
|
|
292
|
+
class GenresResource {
|
|
293
|
+
#transport;
|
|
294
|
+
constructor(transport) {
|
|
295
|
+
this.#transport = transport;
|
|
296
|
+
}
|
|
297
|
+
movies(options = {}) {
|
|
298
|
+
return this.#transport.get("/genre/movie/list", {
|
|
299
|
+
query: withLanguage(this.#transport.defaults, {
|
|
300
|
+
language: options.language
|
|
301
|
+
})
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
tv(options = {}) {
|
|
305
|
+
return this.#transport.get("/genre/tv/list", {
|
|
306
|
+
query: withLanguage(this.#transport.defaults, {
|
|
307
|
+
language: options.language
|
|
308
|
+
})
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// src/resources/images.ts
|
|
314
|
+
class ImagesHelper {
|
|
315
|
+
#transport;
|
|
316
|
+
#transform;
|
|
317
|
+
constructor(transport, transform) {
|
|
318
|
+
this.#transport = transport;
|
|
319
|
+
this.#transform = transform;
|
|
320
|
+
}
|
|
321
|
+
url(path, size = "original", options = {}) {
|
|
322
|
+
return buildImageUrl(path, size, {
|
|
323
|
+
baseUrl: this.#transport.defaults.imageBaseUrl,
|
|
324
|
+
transform: options.transform ?? this.#transform
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// src/resources/movies.ts
|
|
330
|
+
class MoviesResource {
|
|
331
|
+
#transport;
|
|
332
|
+
constructor(transport) {
|
|
333
|
+
this.#transport = transport;
|
|
334
|
+
}
|
|
335
|
+
popular(options = {}) {
|
|
336
|
+
return this.#transport.get("/movie/popular", {
|
|
337
|
+
query: movieListQuery(this.#transport, options)
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
topRated(options = {}) {
|
|
341
|
+
return this.#transport.get("/movie/top_rated", {
|
|
342
|
+
query: movieListQuery(this.#transport, options)
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
nowPlaying(options = {}) {
|
|
346
|
+
return this.#transport.get("/movie/now_playing", {
|
|
347
|
+
query: movieListQuery(this.#transport, options)
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
upcoming(options = {}) {
|
|
351
|
+
return this.#transport.get("/movie/upcoming", {
|
|
352
|
+
query: movieListQuery(this.#transport, options)
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
details(movieId, options = {}) {
|
|
356
|
+
return this.#transport.get(`/movie/${toId(movieId, "movieId")}`, {
|
|
357
|
+
query: withLanguage(this.#transport.defaults, {
|
|
358
|
+
append_to_response: toCommaList(options.appendToResponse),
|
|
359
|
+
language: options.language
|
|
360
|
+
})
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
credits(movieId, options = {}) {
|
|
364
|
+
return this.#transport.get(`/movie/${toId(movieId, "movieId")}/credits`, {
|
|
365
|
+
query: withLanguage(this.#transport.defaults, {
|
|
366
|
+
language: options.language
|
|
367
|
+
})
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
images(movieId, options = {}) {
|
|
371
|
+
return this.#transport.get(`/movie/${toId(movieId, "movieId")}/images`, {
|
|
372
|
+
query: withLanguage(this.#transport.defaults, {
|
|
373
|
+
include_image_language: toCommaList(options.includeImageLanguage),
|
|
374
|
+
language: options.language
|
|
375
|
+
})
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
recommendations(movieId, options = {}) {
|
|
379
|
+
return this.#transport.get(`/movie/${toId(movieId, "movieId")}/recommendations`, {
|
|
380
|
+
query: movieListQuery(this.#transport, options)
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
similar(movieId, options = {}) {
|
|
384
|
+
return this.#transport.get(`/movie/${toId(movieId, "movieId")}/similar`, {
|
|
385
|
+
query: movieListQuery(this.#transport, options)
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
videos(movieId, options = {}) {
|
|
389
|
+
return this.#transport.get(`/movie/${toId(movieId, "movieId")}/videos`, {
|
|
390
|
+
query: withLanguage(this.#transport.defaults, {
|
|
391
|
+
language: options.language
|
|
392
|
+
})
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
434
396
|
function movieListQuery(transport, options) {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
}
|
|
460
|
-
|
|
397
|
+
return withListDefaults(transport.defaults, {
|
|
398
|
+
language: options.language,
|
|
399
|
+
page: options.page,
|
|
400
|
+
region: options.region
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// src/resources/people.ts
|
|
405
|
+
class PeopleResource {
|
|
406
|
+
#transport;
|
|
407
|
+
constructor(transport) {
|
|
408
|
+
this.#transport = transport;
|
|
409
|
+
}
|
|
410
|
+
popular(options = {}) {
|
|
411
|
+
return this.#transport.get("/person/popular", {
|
|
412
|
+
query: peopleListQuery(this.#transport, options)
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
details(personId, options = {}) {
|
|
416
|
+
return this.#transport.get(`/person/${toId(personId, "personId")}`, {
|
|
417
|
+
query: withLanguage(this.#transport.defaults, {
|
|
418
|
+
language: options.language
|
|
419
|
+
})
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
combinedCredits(personId, options = {}) {
|
|
423
|
+
return this.#transport.get(`/person/${toId(personId, "personId")}/combined_credits`, {
|
|
424
|
+
query: withLanguage(this.#transport.defaults, {
|
|
425
|
+
language: options.language
|
|
426
|
+
})
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
}
|
|
461
430
|
function peopleListQuery(transport, options) {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
431
|
+
return withLanguage(transport.defaults, {
|
|
432
|
+
language: options.language,
|
|
433
|
+
page: options.page
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// src/resources/search.ts
|
|
438
|
+
class SearchResource {
|
|
439
|
+
#transport;
|
|
440
|
+
constructor(transport) {
|
|
441
|
+
this.#transport = transport;
|
|
442
|
+
}
|
|
443
|
+
movies(query, options = {}) {
|
|
444
|
+
return this.#transport.get("/search/movie", {
|
|
445
|
+
query: movieSearchQuery(this.#transport, query, options)
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
tv(query, options = {}) {
|
|
449
|
+
return this.#transport.get("/search/tv", {
|
|
450
|
+
query: tvSearchQuery(this.#transport, query, options)
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
people(query, options = {}) {
|
|
454
|
+
return this.#transport.get("/search/person", {
|
|
455
|
+
query: commonSearchQuery(this.#transport, query, options)
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
async multi(query, options = {}) {
|
|
459
|
+
const response = await this.#transport.get("/search/multi", {
|
|
460
|
+
query: commonSearchQuery(this.#transport, query, options)
|
|
461
|
+
});
|
|
462
|
+
const excluded = options.exclude;
|
|
463
|
+
if (excluded === undefined || excluded.length === 0) {
|
|
464
|
+
return response;
|
|
465
|
+
}
|
|
466
|
+
const excludedSet = new Set(excluded);
|
|
467
|
+
return {
|
|
468
|
+
...response,
|
|
469
|
+
results: response.results.filter((result) => !excludedSet.has(result.media_type))
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
}
|
|
500
473
|
function movieSearchQuery(transport, query, options) {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
}
|
|
511
|
-
/** Build query parameters for TV search. */
|
|
474
|
+
return withListDefaults(transport.defaults, {
|
|
475
|
+
include_adult: options.includeAdult,
|
|
476
|
+
language: options.language,
|
|
477
|
+
page: options.page,
|
|
478
|
+
primary_release_year: options.primaryReleaseYear,
|
|
479
|
+
query: toSearchQuery(query),
|
|
480
|
+
region: options.region,
|
|
481
|
+
year: options.year
|
|
482
|
+
});
|
|
483
|
+
}
|
|
512
484
|
function tvSearchQuery(transport, query, options) {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
}
|
|
522
|
-
/** Build query parameters for person and multi-search. */
|
|
485
|
+
return withLanguage(transport.defaults, {
|
|
486
|
+
first_air_date_year: options.firstAirDateYear,
|
|
487
|
+
include_adult: options.includeAdult,
|
|
488
|
+
language: options.language,
|
|
489
|
+
page: options.page,
|
|
490
|
+
query: toSearchQuery(query),
|
|
491
|
+
year: options.year
|
|
492
|
+
});
|
|
493
|
+
}
|
|
523
494
|
function commonSearchQuery(transport, query, options) {
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
}
|
|
611
|
-
|
|
495
|
+
return withLanguage(transport.defaults, {
|
|
496
|
+
include_adult: options.includeAdult,
|
|
497
|
+
language: options.language,
|
|
498
|
+
page: options.page,
|
|
499
|
+
query: toSearchQuery(query)
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// src/resources/trending.ts
|
|
504
|
+
class TrendingResource {
|
|
505
|
+
#transport;
|
|
506
|
+
constructor(transport) {
|
|
507
|
+
this.#transport = transport;
|
|
508
|
+
}
|
|
509
|
+
all(timeWindow = "day", options = {}) {
|
|
510
|
+
return this.#transport.get(`/trending/all/${toTimeWindow(timeWindow)}`, {
|
|
511
|
+
query: withLanguage(this.#transport.defaults, {
|
|
512
|
+
language: options.language,
|
|
513
|
+
page: options.page
|
|
514
|
+
})
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
movies(timeWindow = "day", options = {}) {
|
|
518
|
+
return this.#transport.get(`/trending/movie/${toTimeWindow(timeWindow)}`, {
|
|
519
|
+
query: withLanguage(this.#transport.defaults, {
|
|
520
|
+
language: options.language,
|
|
521
|
+
page: options.page
|
|
522
|
+
})
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
tv(timeWindow = "day", options = {}) {
|
|
526
|
+
return this.#transport.get(`/trending/tv/${toTimeWindow(timeWindow)}`, {
|
|
527
|
+
query: withLanguage(this.#transport.defaults, {
|
|
528
|
+
language: options.language,
|
|
529
|
+
page: options.page
|
|
530
|
+
})
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
people(timeWindow = "day", options = {}) {
|
|
534
|
+
return this.#transport.get(`/trending/person/${toTimeWindow(timeWindow)}`, {
|
|
535
|
+
query: withLanguage(this.#transport.defaults, {
|
|
536
|
+
language: options.language,
|
|
537
|
+
page: options.page
|
|
538
|
+
})
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// src/resources/tv.ts
|
|
544
|
+
class TVResource {
|
|
545
|
+
#transport;
|
|
546
|
+
constructor(transport) {
|
|
547
|
+
this.#transport = transport;
|
|
548
|
+
}
|
|
549
|
+
popular(options = {}) {
|
|
550
|
+
return this.#transport.get("/tv/popular", {
|
|
551
|
+
query: tvListQuery(this.#transport, options)
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
topRated(options = {}) {
|
|
555
|
+
return this.#transport.get("/tv/top_rated", {
|
|
556
|
+
query: tvListQuery(this.#transport, options)
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
airingToday(options = {}) {
|
|
560
|
+
return this.#transport.get("/tv/airing_today", {
|
|
561
|
+
query: tvListQuery(this.#transport, options)
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
onTheAir(options = {}) {
|
|
565
|
+
return this.#transport.get("/tv/on_the_air", {
|
|
566
|
+
query: tvListQuery(this.#transport, options)
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
details(seriesId, options = {}) {
|
|
570
|
+
return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}`, {
|
|
571
|
+
query: withLanguage(this.#transport.defaults, {
|
|
572
|
+
append_to_response: toCommaList(options.appendToResponse),
|
|
573
|
+
language: options.language
|
|
574
|
+
})
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
credits(seriesId, options = {}) {
|
|
578
|
+
return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/credits`, {
|
|
579
|
+
query: withLanguage(this.#transport.defaults, {
|
|
580
|
+
language: options.language
|
|
581
|
+
})
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
images(seriesId, options = {}) {
|
|
585
|
+
return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/images`, {
|
|
586
|
+
query: withLanguage(this.#transport.defaults, {
|
|
587
|
+
include_image_language: toCommaList(options.includeImageLanguage),
|
|
588
|
+
language: options.language
|
|
589
|
+
})
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
recommendations(seriesId, options = {}) {
|
|
593
|
+
return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/recommendations`, {
|
|
594
|
+
query: tvListQuery(this.#transport, options)
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
similar(seriesId, options = {}) {
|
|
598
|
+
return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/similar`, {
|
|
599
|
+
query: tvListQuery(this.#transport, options)
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
videos(seriesId, options = {}) {
|
|
603
|
+
return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/videos`, {
|
|
604
|
+
query: withLanguage(this.#transport.defaults, {
|
|
605
|
+
language: options.language
|
|
606
|
+
})
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
seasonDetails(seriesId, seasonNumber, options = {}) {
|
|
610
|
+
return this.#transport.get(`/tv/${toId(seriesId, "seriesId")}/season/${toId(seasonNumber, "seasonNumber")}`, {
|
|
611
|
+
query: withLanguage(this.#transport.defaults, {
|
|
612
|
+
append_to_response: toCommaList(options.appendToResponse),
|
|
613
|
+
language: options.language
|
|
614
|
+
})
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
}
|
|
612
618
|
function tvListQuery(transport, options) {
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
this.movies = new MoviesResource(this.#transport);
|
|
649
|
-
this.people = new PeopleResource(this.#transport);
|
|
650
|
-
this.search = new SearchResource(this.#transport);
|
|
651
|
-
this.trending = new TrendingResource(this.#transport);
|
|
652
|
-
this.tv = new TVResource(this.#transport);
|
|
653
|
-
}
|
|
654
|
-
/**
|
|
655
|
-
* Make a raw GET request to any TMDB endpoint.
|
|
656
|
-
*
|
|
657
|
-
* This is an escape hatch for endpoints not covered by the typed resource
|
|
658
|
-
* helpers. The `path` should be relative to the API base URL (e.g.
|
|
659
|
-
* `/movie/{id}/credits`). Response is parsed as JSON and cast to `T`.
|
|
660
|
-
*
|
|
661
|
-
* @param path - API path relative to the base URL (e.g. `/movie/123`)
|
|
662
|
-
* @param options - Optional request-level overrides (headers, query, signal)
|
|
663
|
-
* @returns Parsed JSON response typed as `T`
|
|
664
|
-
*/
|
|
665
|
-
request(path, options) {
|
|
666
|
-
return this.#transport.get(path, options);
|
|
667
|
-
}
|
|
668
|
-
};
|
|
669
|
-
/**
|
|
670
|
-
* Create a new {@link TMDBClient} instance.
|
|
671
|
-
*
|
|
672
|
-
* @example
|
|
673
|
-
* ```ts
|
|
674
|
-
* const tmdb = createTMDB({ accessToken: 'YOUR_TOKEN' })
|
|
675
|
-
* const { results } = await tmdb.search.movies('Inception')
|
|
676
|
-
* ```
|
|
677
|
-
*
|
|
678
|
-
* @param options - Authentication and configuration options
|
|
679
|
-
* @returns A configured TMDBClient ready to make API calls
|
|
680
|
-
*/
|
|
619
|
+
return withLanguage(transport.defaults, {
|
|
620
|
+
language: options.language,
|
|
621
|
+
page: options.page
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// src/client.ts
|
|
626
|
+
class TMDBClient {
|
|
627
|
+
configuration;
|
|
628
|
+
genres;
|
|
629
|
+
images;
|
|
630
|
+
movies;
|
|
631
|
+
people;
|
|
632
|
+
search;
|
|
633
|
+
trending;
|
|
634
|
+
tv;
|
|
635
|
+
#transport;
|
|
636
|
+
constructor(options) {
|
|
637
|
+
const { transport, images, ...httpOptions } = options;
|
|
638
|
+
const fallbackTransform = images?.transform;
|
|
639
|
+
const builtInClient = transport === undefined ? new TMDBHttpClient({ ...httpOptions, images }) : undefined;
|
|
640
|
+
this.#transport = builtInClient ?? transport;
|
|
641
|
+
this.configuration = new ConfigurationResource(this.#transport);
|
|
642
|
+
this.genres = new GenresResource(this.#transport);
|
|
643
|
+
this.images = new ImagesHelper(this.#transport, builtInClient ? builtInClient.imageTransform : fallbackTransform);
|
|
644
|
+
this.movies = new MoviesResource(this.#transport);
|
|
645
|
+
this.people = new PeopleResource(this.#transport);
|
|
646
|
+
this.search = new SearchResource(this.#transport);
|
|
647
|
+
this.trending = new TrendingResource(this.#transport);
|
|
648
|
+
this.tv = new TVResource(this.#transport);
|
|
649
|
+
}
|
|
650
|
+
request(path, options) {
|
|
651
|
+
return this.#transport.get(path, options);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
681
654
|
function createTMDB(options) {
|
|
682
|
-
|
|
655
|
+
return new TMDBClient(options);
|
|
683
656
|
}
|
|
684
|
-
|
|
685
|
-
//#region src/search-guards.ts
|
|
657
|
+
// src/search-guards.ts
|
|
686
658
|
function isMovieSearchResult(result) {
|
|
687
|
-
|
|
659
|
+
return isObjectWithMediaType(result, "movie");
|
|
688
660
|
}
|
|
689
661
|
function isTVSearchResult(result) {
|
|
690
|
-
|
|
662
|
+
return isObjectWithMediaType(result, "tv");
|
|
691
663
|
}
|
|
692
664
|
function isPersonSearchResult(result) {
|
|
693
|
-
|
|
665
|
+
return isObjectWithMediaType(result, "person");
|
|
694
666
|
}
|
|
695
667
|
function isMovie(result) {
|
|
696
|
-
|
|
668
|
+
return isObjectWithMediaType(result, "movie");
|
|
697
669
|
}
|
|
698
670
|
function isTV(result) {
|
|
699
|
-
|
|
671
|
+
return isObjectWithMediaType(result, "tv");
|
|
700
672
|
}
|
|
701
673
|
function isPerson(result) {
|
|
702
|
-
|
|
674
|
+
return isObjectWithMediaType(result, "person");
|
|
703
675
|
}
|
|
704
|
-
/** Internal helper: check if a value is an object with a matching `media_type` field. */
|
|
705
676
|
function isObjectWithMediaType(value, mediaType) {
|
|
706
|
-
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
* canonical list lets callers:
|
|
715
|
-
*
|
|
716
|
-
* - iterate over the set to build a size picker
|
|
717
|
-
* - validate user-supplied sizes with `isKnownBackdropSize(...)` etc.
|
|
718
|
-
* - type a variable as a "known" size without giving up the
|
|
719
|
-
* `(string & {})` escape hatch for forward-compatibility
|
|
720
|
-
*
|
|
721
|
-
* If TMDB publishes a new size, the SDK will still accept it at runtime
|
|
722
|
-
* (every helper is `(string & {})` permissive), but you will need to
|
|
723
|
-
* add the literal to these constants to get autocomplete on it.
|
|
724
|
-
*/
|
|
725
|
-
const KNOWN_BACKDROP_SIZES = Object.freeze([
|
|
726
|
-
"w300",
|
|
727
|
-
"w780",
|
|
728
|
-
"w1280",
|
|
729
|
-
"original"
|
|
677
|
+
return typeof value === "object" && value !== null && "media_type" in value && value.media_type === mediaType;
|
|
678
|
+
}
|
|
679
|
+
// src/types.ts
|
|
680
|
+
var KNOWN_BACKDROP_SIZES = Object.freeze([
|
|
681
|
+
"w300",
|
|
682
|
+
"w780",
|
|
683
|
+
"w1280",
|
|
684
|
+
"original"
|
|
730
685
|
]);
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
"original"
|
|
686
|
+
var KNOWN_LOGO_SIZES = Object.freeze(["w45", "w92", "w154", "w185", "w300", "w500", "original"]);
|
|
687
|
+
var KNOWN_POSTER_SIZES = Object.freeze(["w92", "w154", "w185", "w342", "w500", "w780", "original"]);
|
|
688
|
+
var KNOWN_PROFILE_SIZES = Object.freeze([
|
|
689
|
+
"w45",
|
|
690
|
+
"w185",
|
|
691
|
+
"h632",
|
|
692
|
+
"original"
|
|
739
693
|
]);
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
"w500",
|
|
746
|
-
"w780",
|
|
747
|
-
"original"
|
|
694
|
+
var KNOWN_STILL_SIZES = Object.freeze([
|
|
695
|
+
"w92",
|
|
696
|
+
"w185",
|
|
697
|
+
"w300",
|
|
698
|
+
"original"
|
|
748
699
|
]);
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
700
|
+
var KNOWN_IMAGE_SIZES = Object.freeze([
|
|
701
|
+
...KNOWN_BACKDROP_SIZES,
|
|
702
|
+
...KNOWN_LOGO_SIZES,
|
|
703
|
+
...KNOWN_POSTER_SIZES,
|
|
704
|
+
...KNOWN_PROFILE_SIZES,
|
|
705
|
+
...KNOWN_STILL_SIZES
|
|
754
706
|
]);
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
/** Union of every documented image size. */
|
|
762
|
-
const KNOWN_IMAGE_SIZES = Object.freeze([
|
|
763
|
-
...KNOWN_BACKDROP_SIZES,
|
|
764
|
-
...KNOWN_LOGO_SIZES,
|
|
765
|
-
...KNOWN_POSTER_SIZES,
|
|
766
|
-
...KNOWN_PROFILE_SIZES,
|
|
767
|
-
...KNOWN_STILL_SIZES
|
|
768
|
-
]);
|
|
769
|
-
/** O(1) membership check backed by a Set. */
|
|
770
|
-
const KNOWN_BACKDROP_SET = new Set(KNOWN_BACKDROP_SIZES);
|
|
771
|
-
const KNOWN_LOGO_SET = new Set(KNOWN_LOGO_SIZES);
|
|
772
|
-
const KNOWN_POSTER_SET = new Set(KNOWN_POSTER_SIZES);
|
|
773
|
-
const KNOWN_PROFILE_SET = new Set(KNOWN_PROFILE_SIZES);
|
|
774
|
-
const KNOWN_STILL_SET = new Set(KNOWN_STILL_SIZES);
|
|
775
|
-
const KNOWN_IMAGE_SET = new Set(KNOWN_IMAGE_SIZES);
|
|
707
|
+
var KNOWN_BACKDROP_SET = new Set(KNOWN_BACKDROP_SIZES);
|
|
708
|
+
var KNOWN_LOGO_SET = new Set(KNOWN_LOGO_SIZES);
|
|
709
|
+
var KNOWN_POSTER_SET = new Set(KNOWN_POSTER_SIZES);
|
|
710
|
+
var KNOWN_PROFILE_SET = new Set(KNOWN_PROFILE_SIZES);
|
|
711
|
+
var KNOWN_STILL_SET = new Set(KNOWN_STILL_SIZES);
|
|
712
|
+
var KNOWN_IMAGE_SET = new Set(KNOWN_IMAGE_SIZES);
|
|
776
713
|
function isKnownBackdropSize(value) {
|
|
777
|
-
|
|
714
|
+
return KNOWN_BACKDROP_SET.has(value);
|
|
778
715
|
}
|
|
779
716
|
function isKnownLogoSize(value) {
|
|
780
|
-
|
|
717
|
+
return KNOWN_LOGO_SET.has(value);
|
|
781
718
|
}
|
|
782
719
|
function isKnownPosterSize(value) {
|
|
783
|
-
|
|
720
|
+
return KNOWN_POSTER_SET.has(value);
|
|
784
721
|
}
|
|
785
722
|
function isKnownProfileSize(value) {
|
|
786
|
-
|
|
723
|
+
return KNOWN_PROFILE_SET.has(value);
|
|
787
724
|
}
|
|
788
725
|
function isKnownStillSize(value) {
|
|
789
|
-
|
|
726
|
+
return KNOWN_STILL_SET.has(value);
|
|
790
727
|
}
|
|
791
|
-
/** True if `value` is in any documented size set. */
|
|
792
728
|
function isKnownImageSize(value) {
|
|
793
|
-
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
|
|
729
|
+
return KNOWN_IMAGE_SET.has(value);
|
|
730
|
+
}
|
|
731
|
+
export {
|
|
732
|
+
KNOWN_BACKDROP_SIZES,
|
|
733
|
+
KNOWN_IMAGE_SIZES,
|
|
734
|
+
KNOWN_LOGO_SIZES,
|
|
735
|
+
KNOWN_POSTER_SIZES,
|
|
736
|
+
KNOWN_PROFILE_SIZES,
|
|
737
|
+
KNOWN_STILL_SIZES,
|
|
738
|
+
TMDBClient,
|
|
739
|
+
TMDBError,
|
|
740
|
+
TMDBRateLimitError,
|
|
741
|
+
TMDBRequestError,
|
|
742
|
+
TMDBResponseError,
|
|
743
|
+
buildImageUrl,
|
|
744
|
+
createTMDB,
|
|
745
|
+
isKnownBackdropSize,
|
|
746
|
+
isKnownImageSize,
|
|
747
|
+
isKnownLogoSize,
|
|
748
|
+
isKnownPosterSize,
|
|
749
|
+
isKnownProfileSize,
|
|
750
|
+
isKnownStillSize,
|
|
751
|
+
isMovie,
|
|
752
|
+
isMovieSearchResult,
|
|
753
|
+
isPerson,
|
|
754
|
+
isPersonSearchResult,
|
|
755
|
+
isTV,
|
|
756
|
+
isTVSearchResult
|
|
757
|
+
};
|
|
797
758
|
|
|
798
|
-
//#
|
|
759
|
+
//# debugId=00B61D5405D17A8964756E2164756E21
|
|
760
|
+
//# sourceMappingURL=index.js.map
|