@media-engine/core 0.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/LICENSE +21 -0
- package/README.md +295 -0
- package/dist/cache/index.d.ts +2 -0
- package/dist/cache/index.js +2 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/memory.d.ts +19 -0
- package/dist/cache/memory.js +83 -0
- package/dist/cache/memory.js.map +1 -0
- package/dist/cache/types.d.ts +9 -0
- package/dist/cache/types.js +2 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/details/index.d.ts +1 -0
- package/dist/details/index.js +2 -0
- package/dist/details/index.js.map +1 -0
- package/dist/details/types.d.ts +19 -0
- package/dist/details/types.js +2 -0
- package/dist/details/types.js.map +1 -0
- package/dist/engine/engine.d.ts +29 -0
- package/dist/engine/engine.js +1007 -0
- package/dist/engine/engine.js.map +1 -0
- package/dist/engine/index.d.ts +2 -0
- package/dist/engine/index.js +2 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/types.d.ts +13 -0
- package/dist/engine/types.js +2 -0
- package/dist/engine/types.js.map +1 -0
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/errors/types.d.ts +27 -0
- package/dist/errors/types.js +77 -0
- package/dist/errors/types.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/media/index.d.ts +1 -0
- package/dist/media/index.js +2 -0
- package/dist/media/index.js.map +1 -0
- package/dist/media/types.d.ts +136 -0
- package/dist/media/types.js +2 -0
- package/dist/media/types.js.map +1 -0
- package/dist/merge/index.d.ts +2 -0
- package/dist/merge/index.js +2 -0
- package/dist/merge/index.js.map +1 -0
- package/dist/merge/strategy.d.ts +8 -0
- package/dist/merge/strategy.js +1168 -0
- package/dist/merge/strategy.js.map +1 -0
- package/dist/merge/types.d.ts +18 -0
- package/dist/merge/types.js +2 -0
- package/dist/merge/types.js.map +1 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.js +2 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/registry.d.ts +9 -0
- package/dist/providers/registry.js +92 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/types.d.ts +63 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/response/index.d.ts +1 -0
- package/dist/response/index.js +2 -0
- package/dist/response/index.js.map +1 -0
- package/dist/response/types.d.ts +32 -0
- package/dist/response/types.js +2 -0
- package/dist/response/types.js.map +1 -0
- package/dist/search/index.d.ts +1 -0
- package/dist/search/index.js +2 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/types.d.ts +26 -0
- package/dist/search/types.js +2 -0
- package/dist/search/types.js.map +1 -0
- package/dist/streaming/index.d.ts +1 -0
- package/dist/streaming/index.js +2 -0
- package/dist/streaming/index.js.map +1 -0
- package/dist/streaming/types.d.ts +126 -0
- package/dist/streaming/types.js +2 -0
- package/dist/streaming/types.js.map +1 -0
- package/dist/testing/fixtures.d.ts +4 -0
- package/dist/testing/fixtures.js +101 -0
- package/dist/testing/fixtures.js.map +1 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +3 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/providers.d.ts +26 -0
- package/dist/testing/providers.js +147 -0
- package/dist/testing/providers.js.map +1 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Media Engine contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
# @media-engine/core
|
|
2
|
+
|
|
3
|
+
Core TypeScript package for Media Engine.
|
|
4
|
+
|
|
5
|
+
It owns the framework-independent engine, public media types, provider contracts, streaming provider contracts, provider registry, merge strategy, cache interface, error model, and testing utilities.
|
|
6
|
+
|
|
7
|
+
Core does not import concrete providers and does not read API keys from the environment. Providers are passed in from the outside.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @media-engine/core
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Basic Usage
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { MediaEngine, createMockProvider } from "@media-engine/core";
|
|
19
|
+
|
|
20
|
+
const media = new MediaEngine({
|
|
21
|
+
providers: [createMockProvider()],
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const response = await media.search({
|
|
25
|
+
title: "Interstellar",
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
console.log(response.results[0]?.item.title);
|
|
29
|
+
console.log(response.meta.providers.successful);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage With Mock Provider
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import {
|
|
36
|
+
MediaEngine,
|
|
37
|
+
createDetailsResult,
|
|
38
|
+
createMockProvider,
|
|
39
|
+
createSearchResult,
|
|
40
|
+
sampleMovie,
|
|
41
|
+
} from "@media-engine/core";
|
|
42
|
+
|
|
43
|
+
const mockProvider = createMockProvider({
|
|
44
|
+
name: "local-fixture",
|
|
45
|
+
searchResults: [createSearchResult("local-fixture", sampleMovie)],
|
|
46
|
+
detailsResult: createDetailsResult("local-fixture", sampleMovie),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const media = new MediaEngine({
|
|
50
|
+
providers: [mockProvider],
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const search = await media.search({
|
|
54
|
+
imdb: "tt0816692",
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const details = await media.getDetails({
|
|
58
|
+
imdb: "tt0816692",
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
console.log(search.results.length);
|
|
62
|
+
console.log(details.details?.title);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Provider Contract Overview
|
|
66
|
+
|
|
67
|
+
A provider is a small object that implements the `MediaProvider` contract:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import type { MediaProvider } from "@media-engine/core";
|
|
71
|
+
|
|
72
|
+
export const provider: MediaProvider = {
|
|
73
|
+
name: "example",
|
|
74
|
+
kind: "metadata",
|
|
75
|
+
capabilities: {
|
|
76
|
+
mediaTypes: ["movie", "series", "anime"],
|
|
77
|
+
search: {
|
|
78
|
+
byTitle: true,
|
|
79
|
+
byExternalIds: ["imdb", "tmdb"],
|
|
80
|
+
},
|
|
81
|
+
details: {
|
|
82
|
+
byExternalIds: ["imdb", "tmdb"],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
async search(query, context) {
|
|
86
|
+
return [];
|
|
87
|
+
},
|
|
88
|
+
async getDetails(query, context) {
|
|
89
|
+
return null;
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`capabilities` tell the engine when a provider can be selected. `search` returns normalized provider search results. `getDetails` is optional; providers without it are skipped by `MediaEngine.getDetails`.
|
|
95
|
+
|
|
96
|
+
Provider methods receive a `context` with `signal`, `timeoutMs`, `debug`, and `language`. Providers should respect `context.signal` when they perform slow work.
|
|
97
|
+
|
|
98
|
+
Applications can bound slower optional providers independently while keeping a global upper limit:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
const media = new MediaEngine({
|
|
102
|
+
providers,
|
|
103
|
+
timeoutMs: 5_000,
|
|
104
|
+
providerTimeouts: {
|
|
105
|
+
cinemeta: 2_500,
|
|
106
|
+
wikidata: 2_500,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The effective timeout is the smaller of `timeoutMs` and the matching `providerTimeouts` value.
|
|
112
|
+
|
|
113
|
+
## Streaming Availability Contract
|
|
114
|
+
|
|
115
|
+
Streaming availability is separate from metadata search and details. Configure streaming providers through `streamingProviders` and call `getAvailability` with a media or episode identity.
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { MediaEngine, createMockProvider } from "@media-engine/core";
|
|
119
|
+
import type { StreamingProvider } from "@media-engine/core";
|
|
120
|
+
|
|
121
|
+
const streamingProvider: StreamingProvider = {
|
|
122
|
+
name: "example-streaming",
|
|
123
|
+
kind: "streaming",
|
|
124
|
+
capabilities: {
|
|
125
|
+
mediaTypes: ["movie", "series", "anime"],
|
|
126
|
+
lookup: {
|
|
127
|
+
byTitle: true,
|
|
128
|
+
byExternalIds: ["imdb"],
|
|
129
|
+
byEpisode: true,
|
|
130
|
+
},
|
|
131
|
+
features: ["embed", "translations", "qualities"],
|
|
132
|
+
},
|
|
133
|
+
async getAvailability(query) {
|
|
134
|
+
return {
|
|
135
|
+
query,
|
|
136
|
+
options: [],
|
|
137
|
+
sourceProviders: [{ provider: "example-streaming" }],
|
|
138
|
+
checkedAt: new Date().toISOString(),
|
|
139
|
+
};
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const media = new MediaEngine({
|
|
144
|
+
providers: [createMockProvider()],
|
|
145
|
+
streamingProviders: [streamingProvider],
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const availability = await media.getAvailability({
|
|
149
|
+
type: "movie",
|
|
150
|
+
imdb: "tt0816692",
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Core does not decide whether a third-party player source is appropriate for a product. Concrete streaming providers must document their own source rules and expose only safe access URLs.
|
|
155
|
+
|
|
156
|
+
## Search Response Example
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import { MediaEngine, createSuccessProvider } from "@media-engine/core";
|
|
160
|
+
|
|
161
|
+
const media = new MediaEngine({
|
|
162
|
+
providers: [createSuccessProvider()],
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const response = await media.search({
|
|
166
|
+
title: "Interstellar",
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Shape:
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
{
|
|
174
|
+
query: {
|
|
175
|
+
title: "Interstellar",
|
|
176
|
+
},
|
|
177
|
+
results: [
|
|
178
|
+
{
|
|
179
|
+
item: {
|
|
180
|
+
id: "sample-movie-interstellar",
|
|
181
|
+
type: "movie",
|
|
182
|
+
title: "Interstellar",
|
|
183
|
+
year: 2014,
|
|
184
|
+
},
|
|
185
|
+
score: 0.5,
|
|
186
|
+
sources: [
|
|
187
|
+
{
|
|
188
|
+
provider: "success-provider",
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
meta: {
|
|
194
|
+
providers: {
|
|
195
|
+
requested: ["success-provider"],
|
|
196
|
+
successful: ["success-provider"],
|
|
197
|
+
failed: [],
|
|
198
|
+
},
|
|
199
|
+
cached: false,
|
|
200
|
+
tookMs: 1,
|
|
201
|
+
},
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
`score`, `tookMs`, and optional fields can vary with the provider result and merge strategy.
|
|
206
|
+
|
|
207
|
+
## Details Response Example
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
import { MediaEngine, createSuccessProvider } from "@media-engine/core";
|
|
211
|
+
|
|
212
|
+
const media = new MediaEngine({
|
|
213
|
+
providers: [createSuccessProvider()],
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const response = await media.getDetails({
|
|
217
|
+
imdb: "tt0816692",
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Shape:
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
{
|
|
225
|
+
query: {
|
|
226
|
+
imdb: "tt0816692",
|
|
227
|
+
ids: {
|
|
228
|
+
imdb: "tt0816692",
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
details: {
|
|
232
|
+
id: "sample-movie-interstellar",
|
|
233
|
+
type: "movie",
|
|
234
|
+
title: "Interstellar",
|
|
235
|
+
year: 2014,
|
|
236
|
+
},
|
|
237
|
+
meta: {
|
|
238
|
+
providers: {
|
|
239
|
+
requested: ["success-provider"],
|
|
240
|
+
successful: ["success-provider"],
|
|
241
|
+
failed: [],
|
|
242
|
+
},
|
|
243
|
+
cached: false,
|
|
244
|
+
tookMs: 1,
|
|
245
|
+
},
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
If selected providers return no details, `details` is `null`.
|
|
250
|
+
|
|
251
|
+
## Availability Response Example
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
import { MediaEngine, createSuccessProvider } from "@media-engine/core";
|
|
255
|
+
|
|
256
|
+
const media = new MediaEngine({
|
|
257
|
+
providers: [createSuccessProvider()],
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
const response = await media.getAvailability({
|
|
261
|
+
type: "movie",
|
|
262
|
+
imdb: "tt0816692",
|
|
263
|
+
});
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
When no streaming providers are configured, `options` is empty and `sourceProviders` is empty. Provider failures are exposed through response metadata when configured providers fail.
|
|
267
|
+
|
|
268
|
+
## Bounded Memory Cache
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
import { MediaEngine, MemoryCache } from "@media-engine/core";
|
|
272
|
+
|
|
273
|
+
const media = new MediaEngine({
|
|
274
|
+
cache: new MemoryCache({
|
|
275
|
+
defaultTtlMs: 5 * 60_000,
|
|
276
|
+
maxEntries: 500,
|
|
277
|
+
}),
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
`defaultTtlMs` applies when a cache write does not specify its own TTL. `maxEntries` bounds memory usage and evicts the least-recently-used entry when full.
|
|
282
|
+
|
|
283
|
+
## Testing Utilities
|
|
284
|
+
|
|
285
|
+
The core package exports deterministic helpers for tests and examples:
|
|
286
|
+
|
|
287
|
+
- `createMockProvider`;
|
|
288
|
+
- `createSuccessProvider`;
|
|
289
|
+
- `createFailingProvider`;
|
|
290
|
+
- `createTimeoutProvider`;
|
|
291
|
+
- `sampleMovie`;
|
|
292
|
+
- `sampleSeries`;
|
|
293
|
+
- `sampleAnime`.
|
|
294
|
+
|
|
295
|
+
These helpers do not call real APIs and do not require API keys.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Cache, CacheSetOptions } from "./types.js";
|
|
2
|
+
export interface MemoryCacheOptions {
|
|
3
|
+
now?: () => number;
|
|
4
|
+
defaultTtlMs?: number;
|
|
5
|
+
maxEntries?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class MemoryCache implements Cache {
|
|
8
|
+
private readonly entries;
|
|
9
|
+
private readonly now;
|
|
10
|
+
private readonly defaultTtlMs?;
|
|
11
|
+
private readonly maxEntries?;
|
|
12
|
+
constructor(options?: MemoryCacheOptions);
|
|
13
|
+
get<T>(key: string): T | undefined;
|
|
14
|
+
set<T>(key: string, value: T, options?: CacheSetOptions): void;
|
|
15
|
+
delete(key: string): void;
|
|
16
|
+
clear(): void;
|
|
17
|
+
private isExpired;
|
|
18
|
+
private evictOverflow;
|
|
19
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Simple synchronous in-memory cache with optional TTL support.
|
|
2
|
+
// Простой синхронный in-memory cache с опциональной поддержкой TTL.
|
|
3
|
+
export class MemoryCache {
|
|
4
|
+
entries = new Map();
|
|
5
|
+
now;
|
|
6
|
+
defaultTtlMs;
|
|
7
|
+
maxEntries;
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
if (options.maxEntries !== undefined &&
|
|
10
|
+
(!Number.isInteger(options.maxEntries) || options.maxEntries <= 0)) {
|
|
11
|
+
throw new TypeError("MemoryCache maxEntries must be a positive integer.");
|
|
12
|
+
}
|
|
13
|
+
this.now = options.now ?? Date.now;
|
|
14
|
+
this.defaultTtlMs = options.defaultTtlMs;
|
|
15
|
+
this.maxEntries = options.maxEntries;
|
|
16
|
+
}
|
|
17
|
+
// Reads a cached value and removes it when it has expired.
|
|
18
|
+
// Читает значение из cache и удаляет его, если срок истек.
|
|
19
|
+
get(key) {
|
|
20
|
+
const entry = this.entries.get(key);
|
|
21
|
+
if (!entry) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
if (this.isExpired(entry)) {
|
|
25
|
+
this.entries.delete(key);
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
if (this.maxEntries !== undefined) {
|
|
29
|
+
this.entries.delete(key);
|
|
30
|
+
this.entries.set(key, entry);
|
|
31
|
+
}
|
|
32
|
+
return cloneCacheValue(entry.value);
|
|
33
|
+
}
|
|
34
|
+
// Stores a value with an optional TTL in milliseconds.
|
|
35
|
+
// Сохраняет значение с опциональным TTL в миллисекундах.
|
|
36
|
+
set(key, value, options = {}) {
|
|
37
|
+
const ttlMs = options.ttlMs ?? this.defaultTtlMs;
|
|
38
|
+
const expiresAt = ttlMs === undefined || ttlMs < 0 ? undefined : this.now() + ttlMs;
|
|
39
|
+
this.entries.delete(key);
|
|
40
|
+
this.entries.set(key, { value: cloneCacheValue(value), expiresAt });
|
|
41
|
+
this.evictOverflow();
|
|
42
|
+
}
|
|
43
|
+
// Removes one cache entry by key.
|
|
44
|
+
// Удаляет одну запись cache по ключу.
|
|
45
|
+
delete(key) {
|
|
46
|
+
this.entries.delete(key);
|
|
47
|
+
}
|
|
48
|
+
// Removes all cache entries.
|
|
49
|
+
// Удаляет все записи cache.
|
|
50
|
+
clear() {
|
|
51
|
+
this.entries.clear();
|
|
52
|
+
}
|
|
53
|
+
// Checks whether one cache entry is expired at the current time.
|
|
54
|
+
// Проверяет, истекла ли одна запись cache к текущему времени.
|
|
55
|
+
isExpired(entry) {
|
|
56
|
+
return entry.expiresAt !== undefined && entry.expiresAt <= this.now();
|
|
57
|
+
}
|
|
58
|
+
// Evicts expired entries first, then least-recently-used entries until the bound is met.
|
|
59
|
+
// Сначала удаляет истекшие записи, затем давно не использованные до соблюдения лимита.
|
|
60
|
+
evictOverflow() {
|
|
61
|
+
if (this.maxEntries === undefined || this.entries.size <= this.maxEntries) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
for (const [key, entry] of this.entries) {
|
|
65
|
+
if (this.isExpired(entry)) {
|
|
66
|
+
this.entries.delete(key);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
while (this.entries.size > this.maxEntries) {
|
|
70
|
+
const oldestKey = this.entries.keys().next().value;
|
|
71
|
+
if (oldestKey === undefined) {
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
this.entries.delete(oldestKey);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Keeps callers from mutating values stored by the shared in-memory cache.
|
|
79
|
+
// Не позволяет вызывающему коду изменять значения внутри общего memory cache.
|
|
80
|
+
function cloneCacheValue(value) {
|
|
81
|
+
return structuredClone(value);
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/cache/memory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface CacheSetOptions {
|
|
2
|
+
ttlMs?: number;
|
|
3
|
+
}
|
|
4
|
+
export interface Cache {
|
|
5
|
+
get<T>(key: string): Promise<T | undefined> | T | undefined;
|
|
6
|
+
set<T>(key: string, value: T, options?: CacheSetOptions): Promise<void> | void;
|
|
7
|
+
delete(key: string): Promise<void> | void;
|
|
8
|
+
clear(): Promise<void> | void;
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cache/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type * from "./types.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/details/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ExternalIds, MediaDetails, MediaType } from "../media/index.js";
|
|
2
|
+
import type { ResponseMeta } from "../response/index.js";
|
|
3
|
+
export interface DetailsQuery {
|
|
4
|
+
id?: string;
|
|
5
|
+
ids?: ExternalIds;
|
|
6
|
+
imdb?: string;
|
|
7
|
+
tmdb?: string;
|
|
8
|
+
kinopoisk?: string;
|
|
9
|
+
shikimori?: string;
|
|
10
|
+
myAnimeList?: string;
|
|
11
|
+
aniList?: string;
|
|
12
|
+
type?: MediaType;
|
|
13
|
+
language?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface DetailsResponse {
|
|
16
|
+
query: DetailsQuery;
|
|
17
|
+
details: MediaDetails | null;
|
|
18
|
+
meta: ResponseMeta;
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/details/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Cache } from "../cache/index.js";
|
|
2
|
+
import type { DetailsQuery, DetailsResponse } from "../details/index.js";
|
|
3
|
+
import { type MergeStrategy } from "../merge/index.js";
|
|
4
|
+
import { ProviderRegistry, type ProviderInfo } from "../providers/index.js";
|
|
5
|
+
import type { SearchQuery, SearchResponse } from "../search/index.js";
|
|
6
|
+
import type { MediaAvailability, StreamQuery, StreamingProviderInfo } from "../streaming/index.js";
|
|
7
|
+
import type { MediaEngineOptions } from "./types.js";
|
|
8
|
+
export declare class MediaEngine {
|
|
9
|
+
private readonly registry;
|
|
10
|
+
private readonly streamingProviders;
|
|
11
|
+
private readonly cache?;
|
|
12
|
+
private readonly mergeStrategy;
|
|
13
|
+
private readonly timeoutMs?;
|
|
14
|
+
private readonly providerTimeouts;
|
|
15
|
+
private readonly debug;
|
|
16
|
+
constructor(options?: MediaEngineOptions);
|
|
17
|
+
getProviders(): ProviderInfo[];
|
|
18
|
+
getStreamingProviders(): StreamingProviderInfo[];
|
|
19
|
+
search(query: SearchQuery): Promise<SearchResponse>;
|
|
20
|
+
getDetails(query: DetailsQuery): Promise<DetailsResponse>;
|
|
21
|
+
getAvailability(query: StreamQuery): Promise<MediaAvailability>;
|
|
22
|
+
protected get providerRegistry(): ProviderRegistry;
|
|
23
|
+
protected get engineCache(): Cache | undefined;
|
|
24
|
+
protected get engineMergeStrategy(): MergeStrategy;
|
|
25
|
+
protected get engineTimeoutMs(): number | undefined;
|
|
26
|
+
private getProviderTimeoutMs;
|
|
27
|
+
private loadSearchPoster;
|
|
28
|
+
protected get engineDebug(): boolean;
|
|
29
|
+
}
|