@media-engine/providers 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.
Files changed (68) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +66 -135
  3. package/README.ru.md +72 -139
  4. package/dist/filmix-streaming/client.d.ts +36 -0
  5. package/dist/filmix-streaming/client.js +241 -0
  6. package/dist/filmix-streaming/client.js.map +1 -0
  7. package/dist/filmix-streaming/config.d.ts +42 -0
  8. package/dist/filmix-streaming/config.js +93 -0
  9. package/dist/filmix-streaming/config.js.map +1 -0
  10. package/dist/filmix-streaming/index.d.ts +4 -0
  11. package/dist/filmix-streaming/index.js +48 -0
  12. package/dist/filmix-streaming/index.js.map +1 -0
  13. package/dist/filmix-streaming/mapping.d.ts +3 -0
  14. package/dist/filmix-streaming/mapping.js +109 -0
  15. package/dist/filmix-streaming/mapping.js.map +1 -0
  16. package/dist/filmix-streaming/matching.d.ts +4 -0
  17. package/dist/filmix-streaming/matching.js +41 -0
  18. package/dist/filmix-streaming/matching.js.map +1 -0
  19. package/dist/imdb-dataset/sqlite-import.js +5 -2
  20. package/dist/imdb-dataset/sqlite-import.js.map +1 -1
  21. package/dist/index.d.ts +4 -0
  22. package/dist/index.js +4 -0
  23. package/dist/index.js.map +1 -1
  24. package/dist/package-version.d.ts +2 -2
  25. package/dist/package-version.js +1 -1
  26. package/dist/rutube-streaming/client.d.ts +18 -0
  27. package/dist/rutube-streaming/client.js +106 -0
  28. package/dist/rutube-streaming/client.js.map +1 -0
  29. package/dist/rutube-streaming/config.d.ts +26 -0
  30. package/dist/rutube-streaming/config.js +57 -0
  31. package/dist/rutube-streaming/config.js.map +1 -0
  32. package/dist/rutube-streaming/index.d.ts +4 -0
  33. package/dist/rutube-streaming/index.js +38 -0
  34. package/dist/rutube-streaming/index.js.map +1 -0
  35. package/dist/rutube-streaming/mapping.d.ts +4 -0
  36. package/dist/rutube-streaming/mapping.js +32 -0
  37. package/dist/rutube-streaming/mapping.js.map +1 -0
  38. package/dist/rutube-streaming/matching.d.ts +2 -0
  39. package/dist/rutube-streaming/matching.js +37 -0
  40. package/dist/rutube-streaming/matching.js.map +1 -0
  41. package/dist/shared/safe-fetch.d.ts +2 -0
  42. package/dist/shared/safe-fetch.js +29 -3
  43. package/dist/shared/safe-fetch.js.map +1 -1
  44. package/dist/veoveo-streaming/client.d.ts +28 -0
  45. package/dist/veoveo-streaming/client.js +212 -0
  46. package/dist/veoveo-streaming/client.js.map +1 -0
  47. package/dist/veoveo-streaming/config.d.ts +32 -0
  48. package/dist/veoveo-streaming/config.js +67 -0
  49. package/dist/veoveo-streaming/config.js.map +1 -0
  50. package/dist/veoveo-streaming/index.d.ts +4 -0
  51. package/dist/veoveo-streaming/index.js +46 -0
  52. package/dist/veoveo-streaming/index.js.map +1 -0
  53. package/dist/veoveo-streaming/mapping.d.ts +3 -0
  54. package/dist/veoveo-streaming/mapping.js +121 -0
  55. package/dist/veoveo-streaming/mapping.js.map +1 -0
  56. package/dist/videohub-streaming/client.d.ts +33 -0
  57. package/dist/videohub-streaming/client.js +208 -0
  58. package/dist/videohub-streaming/client.js.map +1 -0
  59. package/dist/videohub-streaming/config.d.ts +34 -0
  60. package/dist/videohub-streaming/config.js +73 -0
  61. package/dist/videohub-streaming/config.js.map +1 -0
  62. package/dist/videohub-streaming/index.d.ts +4 -0
  63. package/dist/videohub-streaming/index.js +53 -0
  64. package/dist/videohub-streaming/index.js.map +1 -0
  65. package/dist/videohub-streaming/mapping.d.ts +3 -0
  66. package/dist/videohub-streaming/mapping.js +84 -0
  67. package/dist/videohub-streaming/mapping.js.map +1 -0
  68. package/package.json +7 -2
package/LICENSE CHANGED
@@ -1,21 +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.
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 CHANGED
@@ -2,79 +2,66 @@
2
2
 
3
3
  **English** | [Русский](https://github.com/Yaneart/media-engine/blob/main/packages/providers/README.ru.md)
4
4
 
5
- Ready-to-use data sources for Media Engine.
5
+ Ready-to-use data sources for Media Engine. Install this package when you want to search real public
6
+ catalogs without writing provider adapters yourself.
6
7
 
7
- Install this package when you do not want to write your own provider adapters.
8
+ ## Install
8
9
 
9
10
  ```bash
10
11
  npm install @media-engine/core @media-engine/providers
11
12
  ```
12
13
 
13
- ## A small setup
14
+ The built-in providers do not need your API keys.
15
+
16
+ ## Search metadata
14
17
 
15
18
  ```ts
16
19
  import { MediaEngine } from "@media-engine/core";
17
20
  import {
18
21
  aniListProvider,
19
- ddbbStreamingProvider,
20
- flixHqStreamingProvider,
22
+ cinemetaProvider,
21
23
  kinobdProvider,
22
- kinobdStreamingProvider,
23
24
  shikimoriProvider,
24
- tvMazeProvider,
25
25
  } from "@media-engine/providers";
26
26
 
27
27
  const media = new MediaEngine({
28
- providers: [kinobdProvider(), shikimoriProvider(), aniListProvider(), tvMazeProvider()],
28
+ providers: [
29
+ kinobdProvider(),
30
+ cinemetaProvider(),
31
+ shikimoriProvider(),
32
+ aniListProvider(),
33
+ ],
29
34
  });
30
35
 
31
36
  const result = await media.search({ title: "One Piece" });
32
37
  ```
33
38
 
34
- Add only the providers that make sense for your application. Media Engine will call compatible ones and merge matching answers.
35
-
36
- ## Available metadata sources
37
-
38
- - `kinobdProvider()` — localized movie and series data;
39
- - `cinemetaProvider()` — IMDb-linked movie and series data;
40
- - `shikimoriProvider()` — anime search and details;
41
- - `aniListProvider()` — international anime titles, popularity, and artwork;
42
- - `tvMazeProvider()` — fallback IMDb-backed series identities and localized aliases;
43
- - `wikidataProvider()` — fallback structured identity and metadata enrichment;
44
- - `imdbDatasetProvider()` — local IMDb data supplied as small in-memory TSV fixtures or through an application-owned indexed storage adapter.
45
-
46
- None of these built-in providers needs your API key. TMDB IDs may appear in results, but this package does not call the TMDB API.
39
+ Connect only the sources your application needs. The engine calls suitable providers and merges
40
+ matching results for you.
47
41
 
48
- TVmaze data is licensed under CC BY-SA. The provider keeps a TVmaze show URL in source attribution; applications using TVmaze data should preserve and render that link. See the [TVmaze API licensing terms](https://www.tvmaze.com/api#licensing).
42
+ Available metadata providers:
49
43
 
50
- Wikidata fallback discovery loads at most three title-relevant entities through a selected-property query and caches entity/IMDb mappings for six hours in a 256-entry process-local LRU by default. `entityLimit` is bounded to 1–10, `cacheTtlMs` to 0–7 days, and `cacheMaxEntries` to 2–2048; a zero TTL disables this provider-local cache.
44
+ - `kinobdProvider()` and `cinemetaProvider()` for movies and series;
45
+ - `shikimoriProvider()` and `aniListProvider()` for anime;
46
+ - `tvMazeProvider()` and `wikidataProvider()` as additional identity sources;
47
+ - `imdbDatasetProvider()` for an IMDb dataset managed by your application.
51
48
 
52
- The backward-compatible IMDb TSV adapter parses the complete input into memory and is intended for small datasets and fixtures. Full-dataset integrations can inject the exported synchronous/asynchronous `ImdbDatasetStorage` contract, including a direct ID lookup and bounded normalized title search, without adding a database dependency for other package users.
49
+ TVmaze data requires attribution. Keep and display the TVmaze source link included in a result. See
50
+ the [TVmaze API license](https://www.tvmaze.com/api#licensing).
53
51
 
54
- An included persisted adapter can stream plain or gzip IMDb TSV files into a versioned, atomically replaced SQLite/FTS index. `buildImdbDatasetSqliteIndex()` creates it and `openImdbDatasetSqliteStorage()` opens it read-only for `imdbDatasetProvider({ storage })`. This optional path lazily uses built-in `node:sqlite` and requires Node.js 22.13 or newer; importing the package or using the small in-memory adapter keeps the Node.js 20 baseline.
52
+ The optional SQLite-backed IMDb dataset tools need Node.js 22.13 or newer. Everything else in the
53
+ package keeps the normal Node.js 20 baseline.
55
54
 
56
- Expected upstream failures are reported as typed `ProviderError` values, and shared HTTP errors expose their originating status through `getProviderHttpStatus`. An untyped Cinemeta IMDb lookup returns `null` only after both movie and series candidates confirm absence; a temporary branch outage remains retryable unless the other branch returned usable details. AniList similarly distinguishes GraphQL rate limits and server outages from validation errors or malformed payloads, allowing Media Engine to avoid caching incomplete metadata as a healthy response.
57
-
58
- Shared `fetchJson` calls stream at most 4 MiB by default before parsing and accept a positive `maxResponseBytes` override for provider-specific limits. A declared or chunked oversized body is cancelled and reported as the non-retryable `PROVIDER_RESPONSE_TOO_LARGE`; malformed JSON within the limit remains `PROVIDER_INVALID_RESPONSE`.
59
-
60
- Low-level adapters may supply a `ProviderHttpScheduler` through `FetchJsonOptions.scheduler` when
61
- they need deterministic control of retry and total-timeout timers, especially in tests. Normal
62
- provider calls omit it and use the platform timers.
63
-
64
- ## Player sources
65
-
66
- - `kinobdStreamingProvider()` — movie, series, and anime player options;
67
- - `flixHqStreamingProvider()` — international movie and selected series-episode options;
68
- - `ddbbStreamingProvider()` — opt-in Kinopoisk/IMDb lookup through an independent DDBB player route;
69
- - `aniLibertyStreamingProvider()` — opt-in exact title/year anime lookup with direct HLS episodes;
70
- - `experimentalStreamingProvider()` — data configured by your own application, useful in tests and UI work.
55
+ ## Find player options
71
56
 
72
57
  ```ts
58
+ import {
59
+ flixHqStreamingProvider,
60
+ kinobdStreamingProvider,
61
+ } from "@media-engine/providers";
62
+
73
63
  const media = new MediaEngine({
74
- streamingProviders: [
75
- kinobdStreamingProvider(),
76
- flixHqStreamingProvider(),
77
- ],
64
+ streamingProviders: [kinobdStreamingProvider(), flixHqStreamingProvider()],
78
65
  });
79
66
 
80
67
  const result = await media.getAvailability({
@@ -85,87 +72,38 @@ const result = await media.getAvailability({
85
72
  });
86
73
  ```
87
74
 
88
- These are third-party player targets, not videos hosted by Media Engine. Availability depends on the upstream source and the user's environment.
89
-
90
- The repository API enables `ddbbStreamingProvider()` after its repeated reliability/diversity
91
- checkpoint; direct package consumers still choose their own provider list explicitly. It accepts
92
- only Kinopoisk or IMDb IDs, returns generic movie/series/anime embeds, and does not claim exact
93
- season/episode mapping. Its diversity-first mapping keeps one main option per returned player before
94
- adding unique translation URLs. Missing nullable players produce no result; confirmed 404/410 or
95
- stable deletion markers are removed, while transient validation failures remain `unknown`.
75
+ The package also exports `ddbbStreamingProvider()`, `aniLibertyStreamingProvider()`,
76
+ `filmixStreamingProvider()`, `veoVeoStreamingProvider()`, `videoHubStreamingProvider()`,
77
+ `rutubeStreamingProvider()`, and
78
+ `experimentalStreamingProvider()`.
79
+ Add them explicitly when they fit your application. Filmix guest mode is capped at 480p and filters
80
+ known copyright/service placeholder videos. A user-owned device token raises the cap to 720p.
81
+ Authenticated mode requires an HTTPS `baseUrl` unless the application explicitly enables
82
+ `allowInsecureHttpToken` for a local compatibility test. That override sends the token without TLS
83
+ and must not be used in a public deployment. Returned CDN video URLs use HTTPS. VeoVeo uses DDBB only to resolve its
84
+ public content ID, discards the iframe token, and returns direct signed HTTPS HLS. VideoHUB uses a Kinopoisk ID and returns
85
+ short-lived direct MP4 qualities for movies or one exact series episode. Its links are bound to the
86
+ playback User-Agent and may also be bound to the requesting public IP. Pass the playback client's
87
+ exact User-Agent as `MediaEngineOperationOptions.playbackUserAgent`; the required value is retained
88
+ in each option's `access.headers` for non-browser clients.
89
+ Rutube performs a bounded exact title/year movie search and returns only Rutube's documented public
90
+ embed player. It does not expose or proxy Rutube media URLs and intentionally skips series.
91
+
92
+ These providers return third-party links or streams. Media Engine does not host the video, and an
93
+ external player may be unavailable in some countries, networks, or browsers.
94
+
95
+ ## Discover torrent releases
96
+
97
+ Torrent providers are always opt-in:
96
98
 
97
99
  ```ts
98
- const media = new MediaEngine({
99
- streamingProviders: [
100
- kinobdStreamingProvider(),
101
- flixHqStreamingProvider(),
102
- ddbbStreamingProvider(), // explicit opt-in
103
- aniLibertyStreamingProvider(), // explicit opt-in
104
- ],
105
- });
106
- ```
107
-
108
- The repository API also enables `aniLibertyStreamingProvider()` after that checkpoint. Because
109
- AniLiberty does not publish MAL, AniList, or Shikimori IDs for releases, the adapter requires both
110
- title and year, accepts only one exact normalized match, and revalidates the loaded release before
111
- returning streams. It supports generic episode maps and exact `absoluteEpisodeNumber` queries, but
112
- does not guess season/episode mappings. Each safe first-party 480p/720p/1080p URL is returned as
113
- direct HLS; release geo and copyright blocks are preserved as normalized availability states.
114
-
115
- Live player validation removes an option only after HTTP 404/410 or a stable deletion marker. Rate limits, server errors, network failures, and validation timeouts keep the discovered option with `availability: "unknown"`, allowing the engine to expose the degradation and retry it instead of caching a transiently reduced result.
116
-
117
- KinoBD bounds one availability lookup to 24 child HTTP attempts by default and validates at most eight discovered players through three workers. Public tuning remains bounded (`childRequestLimit` up to 64, `playerValidationLimit` up to 16, and `playerValidationConcurrency` up to 4). Nested iframe validation starts only when the fixed provider deadline can still grant a full validation window. `onPlayerAudit` receives additive `metrics` for discovered and validated players, limit/budget skips, transient unknown results, confirmed removals, and consumed child requests.
118
-
119
- FlixHQ site navigation cannot leave its configured origin, including through redirects. External player and subtitle checks resolve every A/AAAA answer, reject private, local, reserved, multicast, or mixed public/private destinations, validate every bounded redirect hop, and pin the connection to the approved address. A custom provider `fetch` is an explicit trusted transport injection intended for controlled tests or self-hosted environments; it is responsible for equivalent network policy.
120
-
121
- DDBB caps its JSON response, output option count, live validation count, validation concurrency,
122
- validation body size, and per-player timeout. Its default transport applies the same hardened DNS,
123
- redirect, and connection-pinning policy to the DDBB endpoint and returned players. A custom `fetch`
124
- is the same explicit trusted test/self-hosted boundary used by the other streaming providers. Options
125
- beyond the bounded validation count remain visible with `availability: "unknown"`; they are never
126
- presented as successfully checked. Alloha is represented by one main option because voiceovers can
127
- be switched inside that player; if no main iframe exists, at most one safe translation URL becomes
128
- the entry point. Other player families keep their distinct translation options.
129
-
130
- AniLiberty bounds search candidates, release episodes, JSON bytes, retries, and total provider time
131
- through the shared engine/provider controls. Its default transport uses the hardened DNS, redirect,
132
- and connection-pinning policy for API calls. Direct HLS targets still pass the shared browser-facing
133
- output URL policy; playback network policy remains the consuming application's responsibility.
134
-
135
- Before built-in providers expose artwork, player, or subtitle URLs, one output policy accepts only HTTP(S) targets without credentials, raw control characters, or literal local/private/reserved addresses. Valid paths and CDN query parameters, including expiring signatures, are preserved. This browser-facing check does not replace DNS validation or an application-owned media proxy.
136
-
137
- ## Torrent discovery sources
138
-
139
- `ytsTorrentProvider()` is an opt-in no-key movie source. It resolves an exact IMDb identity or one
140
- exact title/year match and returns normalized 720p/1080p/2160p-style magnet candidates with size,
141
- release metadata, and best-effort peer counts.
142
-
143
- `jacRedTorrentProvider()` is an opt-in no-key Russian/multilingual source for exact title/year
144
- movie, series, and anime lookup. It can filter a requested season, but intentionally returns no
145
- result for exact ordinary or absolute episode queries. Returned title, year, category, season,
146
- info hash, source URL, release metadata, and peer fields are bounded and revalidated. Each result
147
- also retains the bounded JacRed tracker ID as `catalogSource`; known values receive labels such as
148
- BitRu, RuTracker, RuTor, Kinozal, NNM-Club, and Knaben without implying a guaranteed audio
149
- language. Its
150
- `baseUrl` and `searchPath` are configurable because the live first-party route and published route
151
- currently differ.
152
-
153
- `bitsearchTorrentProvider()` is an opt-in no-key broad international source. It requires title and
154
- year, pins movie/TV/anime categories, and revalidates the exact release title, explicit year, media
155
- type, requested season, and requested ordinary or absolute episode before returning a candidate.
156
- It consumes only the documented bounded search response, remembers an exhausted anonymous quota
157
- from `X-RateLimit-*`, and emits one canonical magnet per validated info hash. The public anonymous
158
- tier is currently limited to 200 requests/day per IP, so applications should keep engine caching
159
- enabled and avoid speculative calls.
160
-
161
- `magnetzTorrentProvider()` is an opt-in no-key international meta-search source. It performs one
162
- bounded first-page search request, then revalidates exact title, year, season, and ordinary or
163
- absolute episode markers locally. It never fans out into per-result detail calls. The adapter emits
164
- one canonical magnet per validated info hash, preserves reported peer state and source attribution,
165
- and spaces request starts by one second because the live service has returned short burst 429s even
166
- while its rate-limit header still reported capacity.
100
+ import {
101
+ bitsearchTorrentProvider,
102
+ jacRedTorrentProvider,
103
+ magnetzTorrentProvider,
104
+ ytsTorrentProvider,
105
+ } from "@media-engine/providers";
167
106
 
168
- ```ts
169
107
  const media = new MediaEngine({
170
108
  torrentProviders: [
171
109
  ytsTorrentProvider(),
@@ -173,15 +111,9 @@ const media = new MediaEngine({
173
111
  bitsearchTorrentProvider(),
174
112
  magnetzTorrentProvider(),
175
113
  ],
176
- providerTimeouts: {
177
- "yts-torrent": 15_000,
178
- "jacred-torrent": 20_000,
179
- "bitsearch-torrent": 15_000,
180
- "magnetz-torrent": 15_000,
181
- },
182
114
  });
183
115
 
184
- const torrents = await media.discoverTorrents({
116
+ const result = await media.discoverTorrents({
185
117
  type: "movie",
186
118
  title: "Inception",
187
119
  year: 2010,
@@ -189,13 +121,12 @@ const torrents = await media.discoverTorrents({
189
121
  });
190
122
  ```
191
123
 
192
- The provider does not download torrent metadata, contact trackers, join a swarm, or play video.
193
- The completed multi-source checkpoint kept repository API defaults empty: Bitsearch has a small
194
- anonymous daily quota, Magnetz exposes burst-sensitive limits, and JacRed still has an occasional
195
- long timeout tail. Applications can opt into any subset explicitly and monitor it with
196
- `pnpm smoke:torrents`; package consumers remain in control of their own request budget.
124
+ Discovery only returns normalized candidates and their handoff data. It does not download torrent
125
+ metadata, contact trackers, join a swarm, or play a file.
197
126
 
198
- Provider options, limitations, and safety rules are summarized in the [provider guide](https://github.com/Yaneart/media-engine/blob/main/docs/providers.md).
127
+ Public sources can change, rate-limit requests, or go offline. Keep engine caching enabled and
128
+ expect occasional partial results. Provider-specific settings and safety boundaries are described in
129
+ the [provider guide](https://github.com/Yaneart/media-engine/blob/main/docs/providers.md).
199
130
 
200
131
  ## License
201
132
 
package/README.ru.md CHANGED
@@ -2,172 +2,111 @@
2
2
 
3
3
  [English](https://github.com/Yaneart/media-engine/blob/main/packages/providers/README.md) | **Русский**
4
4
 
5
- Готовые источники данных для Media Engine.
5
+ Это готовые источники данных для Media Engine. Установите пакет, если хотите искать в реальных
6
+ публичных каталогах и не писать адаптеры самостоятельно.
6
7
 
7
- Установите этот пакет, если не хотите писать собственные адаптеры провайдеров.
8
+ ## Установка
8
9
 
9
10
  ```bash
10
11
  npm install @media-engine/core @media-engine/providers
11
12
  ```
12
13
 
13
- ## Небольшой пример
14
+ Для встроенных провайдеров ваши API-ключи не нужны.
15
+
16
+ ## Поиск метаданных
14
17
 
15
18
  ```ts
16
19
  import { MediaEngine } from "@media-engine/core";
17
20
  import {
18
21
  aniListProvider,
19
- ddbbStreamingProvider,
20
- flixHqStreamingProvider,
22
+ cinemetaProvider,
21
23
  kinobdProvider,
22
- kinobdStreamingProvider,
23
24
  shikimoriProvider,
24
- tvMazeProvider,
25
25
  } from "@media-engine/providers";
26
26
 
27
27
  const media = new MediaEngine({
28
- providers: [kinobdProvider(), shikimoriProvider(), aniListProvider(), tvMazeProvider()],
28
+ providers: [
29
+ kinobdProvider(),
30
+ cinemetaProvider(),
31
+ shikimoriProvider(),
32
+ aniListProvider(),
33
+ ],
29
34
  });
30
35
 
31
36
  const result = await media.search({ title: "Ван-Пис" });
32
37
  ```
33
38
 
34
- Подключайте только те провайдеры, которые нужны вашему приложению. Media Engine сам вызовет подходящие и объединит совпадающие ответы.
35
-
36
- ## Провайдеры метаданных
37
-
38
- - `kinobdProvider()` — локализованные данные фильмов и сериалов;
39
- - `cinemetaProvider()` — данные фильмов и сериалов, связанные с IMDb;
40
- - `shikimoriProvider()` — поиск и детали аниме;
41
- - `aniListProvider()` — международные названия аниме, популярность и изображения;
42
- - `tvMazeProvider()` — резервные IMDb identity сериалов и локализованные aliases;
43
- - `wikidataProvider()` — резервная проверка identity и обогащение открытыми структурированными данными;
44
- - `imdbDatasetProvider()` — локальные данные IMDb в виде небольших in-memory TSV fixtures или через индексированный storage adapter приложения.
45
-
46
- Для встроенных провайдеров не нужен ваш API-ключ. TMDB ID может встретиться в результате, но сам пакет не обращается к TMDB API.
39
+ Подключайте только те источники, которые нужны вашему приложению. Движок сам вызовет подходящие
40
+ провайдеры и объединит совпадающие результаты.
47
41
 
48
- Данные TVmaze распространяются по лицензии CC BY-SA. Провайдер сохраняет ссылку на страницу сериала TVmaze в source attribution; приложению следует сохранять и показывать эту ссылку. См. [условия API TVmaze](https://www.tvmaze.com/api#licensing).
42
+ Готовые провайдеры метаданных:
49
43
 
50
- Резервный поиск Wikidata загружает не больше трёх релевантных title entities через selected-property запрос и по умолчанию кеширует entity/IMDb mappings на шесть часов в process-local LRU на 256 записей. `entityLimit` ограничен диапазоном 1–10, `cacheTtlMs` 0–7 дней, `cacheMaxEntries` — 2–2048; нулевой TTL отключает локальный cache провайдера.
44
+ - `kinobdProvider()` и `cinemetaProvider()` для фильмов и сериалов;
45
+ - `shikimoriProvider()` и `aniListProvider()` для аниме;
46
+ - `tvMazeProvider()` и `wikidataProvider()` как дополнительные источники идентичности;
47
+ - `imdbDatasetProvider()` для IMDb-датасета, которым управляет ваше приложение.
51
48
 
52
- Backward-compatible IMDb TSV adapter полностью разбирает входные строки в память и предназначен для небольших наборов и fixtures. Для полного датасета приложение может передать экспортируемый синхронный/асинхронный контракт `ImdbDatasetStorage` с прямым ID lookup и ограниченным поиском по нормализованному title; другим пользователям пакета database dependency не добавляется.
49
+ Данные TVmaze требуют указания источника. Сохраняйте и показывайте ссылку TVmaze, которая приходит
50
+ в результате. Подробности есть в [лицензии API TVmaze](https://www.tvmaze.com/api#licensing).
53
51
 
54
- Встроенный persisted adapter может потоково собрать plain или gzip IMDb TSV в версионированный SQLite/FTS index с атомарной заменой. `buildImdbDatasetSqliteIndex()` создаёт индекс, а `openImdbDatasetSqliteStorage()` открывает его read-only для `imdbDatasetProvider({ storage })`. Этот опциональный путь лениво использует встроенный `node:sqlite` и требует Node.js 22.13 или новее; импорт пакета и небольшой in-memory adapter сохраняют базовую совместимость с Node.js 20.
52
+ Опциональные инструменты для SQLite-индекса IMDb требуют Node.js 22.13 или новее. Для остального
53
+ пакета достаточно Node.js 20.
55
54
 
56
- Ожидаемые сбои внешних источников возвращаются как типизированные `ProviderError`, а исходный HTTP status доступен через `getProviderHttpStatus`. Cinemeta при IMDb-запросе без типа возвращает `null`, только когда отсутствие подтверждено и для фильма, и для сериала; временный сбой одной ветки остаётся retryable, если другая ветка не вернула пригодные детали. AniList также отличает GraphQL rate limit и сбой сервера от ошибок валидации или некорректного ответа, поэтому Media Engine не кеширует неполные метаданные как здоровый результат.
57
-
58
- Общий `fetchJson` по умолчанию читает потоково не больше 4 МиБ перед разбором JSON и принимает положительный `maxResponseBytes` для индивидуального лимита провайдера. Объявленное или фактическое превышение отменяет body и возвращает non-retryable `PROVIDER_RESPONSE_TOO_LARGE`; некорректный JSON в пределах лимита остаётся `PROVIDER_INVALID_RESPONSE`.
59
-
60
- Низкоуровневые адаптеры могут передать `ProviderHttpScheduler` через
61
- `FetchJsonOptions.scheduler`, когда нужен детерминированный контроль retry- и total-timeout
62
- таймеров, прежде всего в тестах. Обычные provider-вызовы не задают его и используют системные
63
- таймеры.
64
-
65
- ## Провайдеры плееров
66
-
67
- - `kinobdStreamingProvider()` — варианты плееров для фильмов, сериалов и аниме;
68
- - `flixHqStreamingProvider()` — международные варианты для фильмов и выбранных эпизодов сериалов;
69
- - `ddbbStreamingProvider()` — opt-in поиск по Kinopoisk/IMDb через независимый маршрут DDBB;
70
- - `aniLibertyStreamingProvider()` — opt-in точный поиск аниме по названию/году с прямыми HLS-сериями;
71
- - `experimentalStreamingProvider()` — данные, настроенные вашим приложением для тестов и разработки интерфейса.
55
+ ## Поиск вариантов просмотра
72
56
 
73
57
  ```ts
58
+ import {
59
+ flixHqStreamingProvider,
60
+ kinobdStreamingProvider,
61
+ } from "@media-engine/providers";
62
+
74
63
  const media = new MediaEngine({
75
- streamingProviders: [
76
- kinobdStreamingProvider(),
77
- flixHqStreamingProvider(),
78
- ],
64
+ streamingProviders: [kinobdStreamingProvider(), flixHqStreamingProvider()],
79
65
  });
80
66
 
81
67
  const result = await media.getAvailability({
82
68
  type: "series",
83
- title: "Game of Thrones",
69
+ title: "Игра престолов",
84
70
  seasonNumber: 1,
85
71
  episodeNumber: 1,
86
72
  });
87
73
  ```
88
74
 
89
- Это ссылки на сторонние плееры, а не видео, размещённые Media Engine. Доступность зависит от внешнего источника и окружения пользователя.
90
-
91
- API репозитория включает `ddbbStreamingProvider()` после повторного reliability/diversity
92
- checkpoint; прямые пользователи пакета по-прежнему явно выбирают собственный список провайдеров. Он
93
- принимает только ID Kinopoisk или IMDb, возвращает общие embed-плееры для фильмов/сериалов/anime и не
94
- заявляет точное сопоставление сезона/эпизода. Diversity-first mapping сначала сохраняет по одному
95
- основному варианту каждого возвращённого плеера, а затем добавляет уникальные translation URL.
96
- Nullable отсутствующие плееры дают пустой результат; подтверждённые 404/410 и устойчивые deletion
97
- markers удаляются, а transient ошибки проверки сохраняются как `unknown`.
75
+ Пакет также экспортирует `ddbbStreamingProvider()`, `aniLibertyStreamingProvider()`,
76
+ `filmixStreamingProvider()`, `veoVeoStreamingProvider()`, `videoHubStreamingProvider()`,
77
+ `rutubeStreamingProvider()` и
78
+ `experimentalStreamingProvider()`.
79
+ Подключайте их явно, если они
80
+ подходят вашему приложению. Гостевой режим Filmix ограничен 480p и отбрасывает известные заглушки о
81
+ блокировке и служебные видео. Собственный device token повышает предел до 720p. Для авторизации
82
+ обязателен HTTPS `baseUrl`, если приложение явно не включило `allowInsecureHttpToken` для локальной
83
+ проверки совместимости. Этот режим отправляет токен без TLS и не должен использоваться в публичном
84
+ развёртывании. Ссылки на видео CDN используют HTTPS. VeoVeo использует DDBB только для получения публичного
85
+ content ID, отбрасывает iframe-токен и возвращает прямой подписанный HTTPS HLS.
86
+ VideoHUB ищет по ID Кинопоиска, а для сериала требует точный сезон и серию. Он возвращает
87
+ короткоживущие прямые MP4 в нескольких качествах. Ссылки привязаны к User-Agent проигрывающего
88
+ клиента и могут быть привязаны к внешнему IP. Передавайте точный User-Agent клиента через
89
+ `MediaEngineOperationOptions.playbackUserAgent`; для небраузерных клиентов нужное значение также
90
+ сохраняется в `access.headers` каждого варианта.
91
+ Rutube выполняет ограниченный точный поиск фильма по названию и году и возвращает только
92
+ официальный публичный embed-плеер Rutube. Прямые media-URL не извлекаются и не проксируются;
93
+ сериалы намеренно не поддерживаются.
94
+
95
+ Эти провайдеры возвращают сторонние ссылки или потоки. Media Engine не хранит видео, а внешний
96
+ плеер может быть недоступен в конкретной стране, сети или браузере.
97
+
98
+ ## Поиск torrent-раздач
99
+
100
+ Torrent-провайдеры всегда подключаются явно:
98
101
 
99
102
  ```ts
100
- const media = new MediaEngine({
101
- streamingProviders: [
102
- kinobdStreamingProvider(),
103
- flixHqStreamingProvider(),
104
- ddbbStreamingProvider(), // явное opt-in подключение
105
- aniLibertyStreamingProvider(), // явное opt-in подключение
106
- ],
107
- });
108
- ```
109
-
110
- После того же checkpoint API репозитория включает и `aniLibertyStreamingProvider()`. AniLiberty не
111
- публикует для релизов MAL, AniList или Shikimori ID, поэтому адаптер требует одновременно название и
112
- год, принимает только одно точное нормализованное совпадение и повторно проверяет загруженный релиз
113
- перед возвратом потоков. Он поддерживает общую карту серий и точный `absoluteEpisodeNumber`, но не
114
- угадывает season/episode. Каждый безопасный first-party URL 480p/720p/1080p возвращается как прямой
115
- HLS, а географическая и copyright-блокировка релиза сохраняются в availability status.
116
-
117
- Live-проверка удаляет вариант плеера только после HTTP 404/410 или устойчивого маркера удаления. Rate limit, ошибка сервера, сетевой сбой или timeout проверки сохраняют найденный вариант с `availability: "unknown"`, чтобы engine показал деградацию и повторил проверку вместо кеширования временно урезанного результата.
118
-
119
- KinoBD по умолчанию ограничивает один availability lookup 24 дочерними HTTP-попытками и проверяет не больше восьми найденных плееров тремя workers. Публичная настройка также ограничена сверху (`childRequestLimit` до 64, `playerValidationLimit` до 16 и `playerValidationConcurrency` до 4). Вложенная iframe-проверка начинается, только если фиксированный deadline провайдера ещё позволяет выделить полное окно validation. Callback `onPlayerAudit` получает дополнительные `metrics`: найденные и проверенные плееры, пропуски по limit/budget, transient unknown, подтверждённые удаления и использованные дочерние запросы.
120
-
121
- Навигация по FlixHQ не может покинуть настроенный origin, в том числе через redirects. Для внешних player/subtitle проверяются все A/AAAA-адреса, отклоняются private, local, reserved, multicast и смешанные public/private назначения, каждый ограниченный redirect hop валидируется, а соединение закрепляется за проверенным адресом. Пользовательский provider `fetch` считается явно доверенной transport-инъекцией для контролируемых тестов или self-hosted окружений и должен обеспечивать эквивалентную сетевую политику.
122
-
123
- DDBB ограничивает размер JSON-ответа, количество output options и live validations, concurrency,
124
- размер validation body и timeout каждого плеера. Его default transport применяет ту же hardened
125
- политику DNS, redirects и connection pinning к endpoint DDBB и возвращённым плеерам. Пользовательский
126
- `fetch` остаётся явной доверенной границей для тестов/self-hosted окружений. Варианты за пределом
127
- ограниченного числа проверок остаются видимыми со статусом `availability: "unknown"` и никогда не
128
- показываются как успешно проверенные. Alloha представлен одним main option, потому что озвучку
129
- можно переключить внутри самого плеера; при отсутствии main iframe точкой входа становится не
130
- больше одного безопасного translation URL. Остальные семейства плееров сохраняют отдельные
131
- варианты переводов.
132
-
133
- AniLiberty ограничивает число search-кандидатов и эпизодов релиза, размер JSON, retry и общее время
134
- провайдера через общие engine/provider-механизмы. Default transport применяет hardened DNS,
135
- redirect и connection-pinning политику к API-вызовам. Прямые HLS-цели проходят общую browser-facing
136
- проверку URL; playback network policy остаётся ответственностью потребляющего приложения.
137
-
138
- Перед публикацией artwork, player или subtitle URL встроенные провайдеры применяют одну output-политику: разрешены только HTTP(S)-цели без credentials, исходных управляющих символов и literal local/private/reserved адресов. Валидные пути и CDN query-параметры, включая временные подписи, сохраняются. Эта browser-facing проверка не заменяет DNS-валидацию или media proxy приложения.
139
-
140
- ## Источники torrent discovery
141
-
142
- `ytsTorrentProvider()` — явно подключаемый no-key источник фильмов. Он принимает точный IMDb ID или
143
- одно точное совпадение названия и года и возвращает нормализованные magnet-кандидаты вроде
144
- 720p/1080p/2160p с размером, сведениями о релизе и best-effort счётчиками пиров.
145
-
146
- `jacRedTorrentProvider()` — явно подключаемый no-key русскоязычный/мультиязычный источник для
147
- точного поиска фильмов, сериалов и аниме по названию и году. Он умеет фильтровать указанный сезон,
148
- но намеренно не отвечает на запрос конкретной обычной или абсолютной серии. Название, год,
149
- категория, сезон, info hash, source URL, сведения о релизе и счётчики пиров ограничиваются и
150
- перепроверяются. Каждый результат также сохраняет ограниченный tracker ID JacRed в
151
- `catalogSource`; известные значения получают подписи BitRu, RuTracker, RuTor, Kinozal, NNM-Club и
152
- Knaben без ложной гарантии языка аудиодорожки. `baseUrl` и `searchPath` настраиваются, потому что фактический first-party маршрут
153
- сейчас отличается от опубликованного.
154
-
155
- `bitsearchTorrentProvider()` — явно подключаемый no-key источник с широким международным каталогом.
156
- Он требует название и год, закрепляет категории movie/TV/anime и перед возвратом кандидата заново
157
- проверяет точное название релиза, явно указанный год, тип медиа, запрошенный сезон и обычный или
158
- абсолютный номер эпизода. Провайдер читает только ограниченный search-ответ, запоминает исчерпание
159
- анонимной квоты из `X-RateLimit-*` и создаёт один канонический magnet на проверенный info hash.
160
- Публичная анонимная квота сейчас составляет 200 запросов в сутки на IP, поэтому приложению следует
161
- оставлять engine cache включённым и не выполнять speculative-вызовы.
162
-
163
- `magnetzTorrentProvider()` — явно подключаемый no-key международный meta-search источник. Он делает
164
- один ограниченный запрос первой страницы, затем локально перепроверяет точное название, год, сезон
165
- и маркеры обычного или абсолютного эпизода. Провайдер не запускает отдельные detail-запросы для
166
- каждого результата, создаёт один канонический magnet на проверенный info hash, сохраняет фактические
167
- peer-счётчики и attribution и выдерживает секунду между началами запросов: live-сервис возвращал
168
- короткие burst-429 даже при ненулевом остатке в rate-limit header.
103
+ import {
104
+ bitsearchTorrentProvider,
105
+ jacRedTorrentProvider,
106
+ magnetzTorrentProvider,
107
+ ytsTorrentProvider,
108
+ } from "@media-engine/providers";
169
109
 
170
- ```ts
171
110
  const media = new MediaEngine({
172
111
  torrentProviders: [
173
112
  ytsTorrentProvider(),
@@ -175,29 +114,23 @@ const media = new MediaEngine({
175
114
  bitsearchTorrentProvider(),
176
115
  magnetzTorrentProvider(),
177
116
  ],
178
- providerTimeouts: {
179
- "yts-torrent": 15_000,
180
- "jacred-torrent": 20_000,
181
- "bitsearch-torrent": 15_000,
182
- "magnetz-torrent": 15_000,
183
- },
184
117
  });
185
118
 
186
- const torrents = await media.discoverTorrents({
119
+ const result = await media.discoverTorrents({
187
120
  type: "movie",
188
- title: "Inception",
121
+ title: "Начало",
189
122
  year: 2010,
190
123
  ids: { imdb: "tt1375666" },
191
124
  });
192
125
  ```
193
126
 
194
- Провайдер не загружает torrent metadata, не обращается к trackers, не подключается к swarm и не
195
- воспроизводит видео. После общего multi-source checkpoint torrent-провайдеры остались выключенными
196
- в API defaults: у Bitsearch небольшая суточная анонимная квота, Magnetz чувствителен к burst-нагрузке,
197
- а у JacRed сохраняется редкий длинный timeout tail. Приложение явно выбирает нужное подмножество и
198
- может контролировать его командой `pnpm smoke:torrents`, сохраняя собственный request budget.
127
+ Поиск только возвращает список кандидатов и данные для дальнейшей передачи. Он не загружает
128
+ torrent metadata, не обращается к trackers, не подключается к раздаче и не воспроизводит файл.
199
129
 
200
- Настройки, ограничения и правила безопасности кратко описаны в [документации провайдеров](https://github.com/Yaneart/media-engine/blob/main/docs/providers.md).
130
+ Публичные источники могут меняться, ограничивать запросы или временно не работать. Оставляйте кэш
131
+ движка включённым и будьте готовы к частичным результатам. Настройки и границы безопасности каждого
132
+ источника описаны в
133
+ [документации провайдеров](https://github.com/Yaneart/media-engine/blob/main/docs/providers.md).
201
134
 
202
135
  ## Лицензия
203
136