@media-engine/providers 0.1.0 → 1.0.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 (214) hide show
  1. package/README.md +149 -242
  2. package/README.ru.md +204 -0
  3. package/dist/aniliberty-streaming/client.d.ts +33 -0
  4. package/dist/aniliberty-streaming/client.js +188 -0
  5. package/dist/aniliberty-streaming/client.js.map +1 -0
  6. package/dist/aniliberty-streaming/config.d.ts +24 -0
  7. package/dist/aniliberty-streaming/config.js +61 -0
  8. package/dist/aniliberty-streaming/config.js.map +1 -0
  9. package/dist/aniliberty-streaming/index.d.ts +4 -0
  10. package/dist/aniliberty-streaming/index.js +45 -0
  11. package/dist/aniliberty-streaming/index.js.map +1 -0
  12. package/dist/aniliberty-streaming/mapping.d.ts +3 -0
  13. package/dist/aniliberty-streaming/mapping.js +87 -0
  14. package/dist/aniliberty-streaming/mapping.js.map +1 -0
  15. package/dist/aniliberty-streaming/matching.d.ts +4 -0
  16. package/dist/aniliberty-streaming/matching.js +44 -0
  17. package/dist/aniliberty-streaming/matching.js.map +1 -0
  18. package/dist/anilist/graphql.d.ts +2 -0
  19. package/dist/anilist/graphql.js +135 -0
  20. package/dist/anilist/graphql.js.map +1 -0
  21. package/dist/anilist/index.js +11 -6
  22. package/dist/anilist/index.js.map +1 -1
  23. package/dist/bitsearch-torrent/client.d.ts +19 -0
  24. package/dist/bitsearch-torrent/client.js +181 -0
  25. package/dist/bitsearch-torrent/client.js.map +1 -0
  26. package/dist/bitsearch-torrent/config.d.ts +26 -0
  27. package/dist/bitsearch-torrent/config.js +74 -0
  28. package/dist/bitsearch-torrent/config.js.map +1 -0
  29. package/dist/bitsearch-torrent/index.d.ts +4 -0
  30. package/dist/bitsearch-torrent/index.js +35 -0
  31. package/dist/bitsearch-torrent/index.js.map +1 -0
  32. package/dist/bitsearch-torrent/mapping.d.ts +3 -0
  33. package/dist/bitsearch-torrent/mapping.js +53 -0
  34. package/dist/bitsearch-torrent/mapping.js.map +1 -0
  35. package/dist/bitsearch-torrent/matching.d.ts +3 -0
  36. package/dist/bitsearch-torrent/matching.js +13 -0
  37. package/dist/bitsearch-torrent/matching.js.map +1 -0
  38. package/dist/bitsearch-torrent/quota.d.ts +9 -0
  39. package/dist/bitsearch-torrent/quota.js +53 -0
  40. package/dist/bitsearch-torrent/quota.js.map +1 -0
  41. package/dist/cinemeta/index.js +53 -35
  42. package/dist/cinemeta/index.js.map +1 -1
  43. package/dist/ddbb-streaming/client.d.ts +24 -0
  44. package/dist/ddbb-streaming/client.js +98 -0
  45. package/dist/ddbb-streaming/client.js.map +1 -0
  46. package/dist/ddbb-streaming/config.d.ts +31 -0
  47. package/dist/ddbb-streaming/config.js +67 -0
  48. package/dist/ddbb-streaming/config.js.map +1 -0
  49. package/dist/ddbb-streaming/index.d.ts +4 -0
  50. package/dist/ddbb-streaming/index.js +53 -0
  51. package/dist/ddbb-streaming/index.js.map +1 -0
  52. package/dist/ddbb-streaming/mapping.d.ts +8 -0
  53. package/dist/ddbb-streaming/mapping.js +164 -0
  54. package/dist/ddbb-streaming/mapping.js.map +1 -0
  55. package/dist/ddbb-streaming/validation.d.ts +3 -0
  56. package/dist/ddbb-streaming/validation.js +84 -0
  57. package/dist/ddbb-streaming/validation.js.map +1 -0
  58. package/dist/experimental-streaming/index.js +55 -0
  59. package/dist/experimental-streaming/index.js.map +1 -1
  60. package/dist/flixhq-streaming/client.d.ts +12 -0
  61. package/dist/flixhq-streaming/client.js +103 -0
  62. package/dist/flixhq-streaming/client.js.map +1 -0
  63. package/dist/flixhq-streaming/index.d.ts +2 -2
  64. package/dist/flixhq-streaming/index.js +67 -106
  65. package/dist/flixhq-streaming/index.js.map +1 -1
  66. package/dist/imdb-dataset/index.d.ts +20 -5
  67. package/dist/imdb-dataset/index.js +83 -197
  68. package/dist/imdb-dataset/index.js.map +1 -1
  69. package/dist/imdb-dataset/memory-storage.d.ts +7 -0
  70. package/dist/imdb-dataset/memory-storage.js +168 -0
  71. package/dist/imdb-dataset/memory-storage.js.map +1 -0
  72. package/dist/imdb-dataset/sqlite-import.d.ts +24 -0
  73. package/dist/imdb-dataset/sqlite-import.js +298 -0
  74. package/dist/imdb-dataset/sqlite-import.js.map +1 -0
  75. package/dist/imdb-dataset/sqlite-runtime.d.ts +3 -0
  76. package/dist/imdb-dataset/sqlite-runtime.js +11 -0
  77. package/dist/imdb-dataset/sqlite-runtime.js.map +1 -0
  78. package/dist/imdb-dataset/sqlite-schema.d.ts +6 -0
  79. package/dist/imdb-dataset/sqlite-schema.js +88 -0
  80. package/dist/imdb-dataset/sqlite-schema.js.map +1 -0
  81. package/dist/imdb-dataset/sqlite-storage.d.ts +12 -0
  82. package/dist/imdb-dataset/sqlite-storage.js +208 -0
  83. package/dist/imdb-dataset/sqlite-storage.js.map +1 -0
  84. package/dist/imdb-dataset/storage.d.ts +33 -0
  85. package/dist/imdb-dataset/storage.js +2 -0
  86. package/dist/imdb-dataset/storage.js.map +1 -0
  87. package/dist/index.d.ts +7 -0
  88. package/dist/index.js +7 -0
  89. package/dist/index.js.map +1 -1
  90. package/dist/jacred-torrent/client.d.ts +24 -0
  91. package/dist/jacred-torrent/client.js +254 -0
  92. package/dist/jacred-torrent/client.js.map +1 -0
  93. package/dist/jacred-torrent/config.d.ts +24 -0
  94. package/dist/jacred-torrent/config.js +70 -0
  95. package/dist/jacred-torrent/config.js.map +1 -0
  96. package/dist/jacred-torrent/index.d.ts +4 -0
  97. package/dist/jacred-torrent/index.js +45 -0
  98. package/dist/jacred-torrent/index.js.map +1 -0
  99. package/dist/jacred-torrent/mapping.d.ts +3 -0
  100. package/dist/jacred-torrent/mapping.js +129 -0
  101. package/dist/jacred-torrent/mapping.js.map +1 -0
  102. package/dist/jacred-torrent/matching.d.ts +3 -0
  103. package/dist/jacred-torrent/matching.js +19 -0
  104. package/dist/jacred-torrent/matching.js.map +1 -0
  105. package/dist/kinobd/index.js +15 -33
  106. package/dist/kinobd/index.js.map +1 -1
  107. package/dist/kinobd-streaming/availability.d.ts +3 -0
  108. package/dist/kinobd-streaming/availability.js +179 -0
  109. package/dist/kinobd-streaming/availability.js.map +1 -0
  110. package/dist/kinobd-streaming/candidates.d.ts +32 -0
  111. package/dist/kinobd-streaming/candidates.js +282 -0
  112. package/dist/kinobd-streaming/candidates.js.map +1 -0
  113. package/dist/kinobd-streaming/config.d.ts +64 -0
  114. package/dist/kinobd-streaming/config.js +129 -0
  115. package/dist/kinobd-streaming/config.js.map +1 -0
  116. package/dist/kinobd-streaming/index.d.ts +3 -30
  117. package/dist/kinobd-streaming/index.js +2 -904
  118. package/dist/kinobd-streaming/index.js.map +1 -1
  119. package/dist/kinobd-streaming/players.d.ts +24 -0
  120. package/dist/kinobd-streaming/players.js +270 -0
  121. package/dist/kinobd-streaming/players.js.map +1 -0
  122. package/dist/kinobd-streaming/request-budget.d.ts +15 -0
  123. package/dist/kinobd-streaming/request-budget.js +61 -0
  124. package/dist/kinobd-streaming/request-budget.js.map +1 -0
  125. package/dist/kinobd-streaming/validation.d.ts +11 -0
  126. package/dist/kinobd-streaming/validation.js +170 -0
  127. package/dist/kinobd-streaming/validation.js.map +1 -0
  128. package/dist/magnetz-torrent/client.d.ts +16 -0
  129. package/dist/magnetz-torrent/client.js +235 -0
  130. package/dist/magnetz-torrent/client.js.map +1 -0
  131. package/dist/magnetz-torrent/config.d.ts +27 -0
  132. package/dist/magnetz-torrent/config.js +73 -0
  133. package/dist/magnetz-torrent/config.js.map +1 -0
  134. package/dist/magnetz-torrent/index.d.ts +4 -0
  135. package/dist/magnetz-torrent/index.js +35 -0
  136. package/dist/magnetz-torrent/index.js.map +1 -0
  137. package/dist/magnetz-torrent/mapping.d.ts +3 -0
  138. package/dist/magnetz-torrent/mapping.js +52 -0
  139. package/dist/magnetz-torrent/mapping.js.map +1 -0
  140. package/dist/magnetz-torrent/matching.d.ts +3 -0
  141. package/dist/magnetz-torrent/matching.js +5 -0
  142. package/dist/magnetz-torrent/matching.js.map +1 -0
  143. package/dist/magnetz-torrent/request-gate.d.ts +9 -0
  144. package/dist/magnetz-torrent/request-gate.js +48 -0
  145. package/dist/magnetz-torrent/request-gate.js.map +1 -0
  146. package/dist/package-version.d.ts +2 -0
  147. package/dist/package-version.js +5 -0
  148. package/dist/package-version.js.map +1 -0
  149. package/dist/shared/abort.d.ts +3 -0
  150. package/dist/shared/abort.js +30 -0
  151. package/dist/shared/abort.js.map +1 -0
  152. package/dist/shared/http.d.ts +13 -2
  153. package/dist/shared/http.js +77 -75
  154. package/dist/shared/http.js.map +1 -1
  155. package/dist/shared/index.d.ts +2 -0
  156. package/dist/shared/index.js +2 -0
  157. package/dist/shared/index.js.map +1 -1
  158. package/dist/shared/mapping.d.ts +5 -0
  159. package/dist/shared/mapping.js +32 -0
  160. package/dist/shared/mapping.js.map +1 -0
  161. package/dist/shared/options.d.ts +1 -0
  162. package/dist/shared/options.js +10 -0
  163. package/dist/shared/options.js.map +1 -0
  164. package/dist/shared/output-url.d.ts +2 -0
  165. package/dist/shared/output-url.js +50 -0
  166. package/dist/shared/output-url.js.map +1 -0
  167. package/dist/shared/rate-limit.d.ts +11 -0
  168. package/dist/shared/rate-limit.js +52 -0
  169. package/dist/shared/rate-limit.js.map +1 -0
  170. package/dist/shared/response-body.d.ts +6 -0
  171. package/dist/shared/response-body.js +109 -0
  172. package/dist/shared/response-body.js.map +1 -0
  173. package/dist/shared/retry.d.ts +10 -0
  174. package/dist/shared/retry.js +31 -0
  175. package/dist/shared/retry.js.map +1 -0
  176. package/dist/shared/safe-fetch.d.ts +14 -0
  177. package/dist/shared/safe-fetch.js +274 -0
  178. package/dist/shared/safe-fetch.js.map +1 -0
  179. package/dist/shared/torrent-release-matching.d.ts +7 -0
  180. package/dist/shared/torrent-release-matching.js +143 -0
  181. package/dist/shared/torrent-release-matching.js.map +1 -0
  182. package/dist/shared/torrent-release-metadata.d.ts +4 -0
  183. package/dist/shared/torrent-release-metadata.js +95 -0
  184. package/dist/shared/torrent-release-metadata.js.map +1 -0
  185. package/dist/shikimori/index.js +19 -11
  186. package/dist/shikimori/index.js.map +1 -1
  187. package/dist/tvmaze/index.d.ts +11 -0
  188. package/dist/tvmaze/index.js +274 -0
  189. package/dist/tvmaze/index.js.map +1 -0
  190. package/dist/wikidata/cache.d.ts +11 -0
  191. package/dist/wikidata/cache.js +30 -0
  192. package/dist/wikidata/cache.js.map +1 -0
  193. package/dist/wikidata/candidates.d.ts +12 -0
  194. package/dist/wikidata/candidates.js +67 -0
  195. package/dist/wikidata/candidates.js.map +1 -0
  196. package/dist/wikidata/client.d.ts +40 -0
  197. package/dist/wikidata/client.js +224 -0
  198. package/dist/wikidata/client.js.map +1 -0
  199. package/dist/wikidata/index.d.ts +3 -0
  200. package/dist/wikidata/index.js +34 -111
  201. package/dist/wikidata/index.js.map +1 -1
  202. package/dist/yts-torrent/client.d.ts +25 -0
  203. package/dist/yts-torrent/client.js +163 -0
  204. package/dist/yts-torrent/client.js.map +1 -0
  205. package/dist/yts-torrent/config.d.ts +22 -0
  206. package/dist/yts-torrent/config.js +57 -0
  207. package/dist/yts-torrent/config.js.map +1 -0
  208. package/dist/yts-torrent/index.d.ts +4 -0
  209. package/dist/yts-torrent/index.js +42 -0
  210. package/dist/yts-torrent/index.js.map +1 -0
  211. package/dist/yts-torrent/mapping.d.ts +4 -0
  212. package/dist/yts-torrent/mapping.js +107 -0
  213. package/dist/yts-torrent/mapping.js.map +1 -0
  214. package/package.json +23 -6
package/README.md CHANGED
@@ -1,295 +1,202 @@
1
1
  # @media-engine/providers
2
2
 
3
- Provider package for Media Engine.
3
+ **English** | [Русский](https://github.com/Yaneart/media-engine/blob/main/packages/providers/README.ru.md)
4
4
 
5
- This package contains no-token metadata provider factories such as KinoBD, Cinemeta, Shikimori, AniList, Wikidata, and local IMDb datasets, plus no-token KinoBD and FlixHQ streaming providers and a local experimental provider.
5
+ Ready-to-use data sources for Media Engine.
6
6
 
7
- The package depends on `@media-engine/core` for provider contracts and normalized media types. Core must not import this package.
8
-
9
- ## Install
7
+ Install this package when you do not want to write your own provider adapters.
10
8
 
11
9
  ```bash
12
10
  npm install @media-engine/core @media-engine/providers
13
11
  ```
14
12
 
15
- Use this package from server-side or trusted application code. Do not expose provider tokens in browser bundles.
16
-
17
- Current structure:
18
-
19
- ```txt
20
- src/
21
- shared/
22
- kinobd/
23
- cinemeta/
24
- shikimori/
25
- anilist/
26
- wikidata/
27
- imdb-dataset/
28
- experimental-streaming/
29
- kinobd-streaming/
30
- flixhq-streaming/
31
- index.ts
32
- ```
33
-
34
- No API keys or environment reads are stored in this package. Applications pass provider secrets from the outside.
35
-
36
- Streaming providers in this package return normalized embed/player access metadata. They do not make Media Engine a streaming service, do not host video, and do not extract direct video files by default. Review each upstream source's usage rules before enabling a provider in a product.
37
-
38
- ## KinoBD Provider
39
-
40
- `kinobdProvider` creates a no-token metadata provider for movies and series through the public KinoBD API used by ReYohoho-style clients.
13
+ ## A small setup
41
14
 
42
15
  ```ts
43
16
  import { MediaEngine } from "@media-engine/core";
44
- import { kinobdProvider } from "@media-engine/providers";
45
-
46
- const engine = new MediaEngine({
47
- providers: [kinobdProvider()],
17
+ import {
18
+ aniListProvider,
19
+ ddbbStreamingProvider,
20
+ flixHqStreamingProvider,
21
+ kinobdProvider,
22
+ kinobdStreamingProvider,
23
+ shikimoriProvider,
24
+ tvMazeProvider,
25
+ } from "@media-engine/providers";
26
+
27
+ const media = new MediaEngine({
28
+ providers: [kinobdProvider(), shikimoriProvider(), aniListProvider(), tvMazeProvider()],
48
29
  });
49
- ```
50
-
51
- Supported data:
52
30
 
53
- - title search for movies and series;
54
- - IMDb and Kinopoisk ID lookup;
55
- - movie and series details;
56
- - posters, Kinopoisk ratings, IMDb ratings, genres, countries, and persons when available;
57
- - configurable `imageLimit` and `personLimit` for details payloads.
58
-
59
- KinoBD is the first no-token movie and series provider for the local API stand because it returns practical Russian metadata, Kinopoisk IDs, IMDb IDs, ratings, and posters without requiring a user token.
60
-
61
- ## Cinemeta Provider
62
-
63
- `cinemetaProvider` creates a no-token metadata provider for movies and series through the public Cinemeta/Stremio metadata API.
64
-
65
- ```ts
66
- import { MediaEngine } from "@media-engine/core";
67
- import { cinemetaProvider } from "@media-engine/providers";
68
-
69
- const engine = new MediaEngine({
70
- providers: [cinemetaProvider()],
71
- });
31
+ const result = await media.search({ title: "One Piece" });
72
32
  ```
73
33
 
74
- Supported data:
34
+ Add only the providers that make sense for your application. Media Engine will call compatible ones and merge matching answers.
75
35
 
76
- - title search for movies and series;
77
- - IMDb ID lookup;
78
- - movie and series details;
79
- - posters, backdrops, IMDb ratings, genres, cast, writers, and directors when available;
80
- - configurable `imageLimit`, `personLimit`, and `enrichSearchLimit`.
36
+ ## Available metadata sources
81
37
 
82
- Cinemeta is a secondary no-token movie and series provider. Its results are merged with KinoBD and Wikidata to improve metadata completeness without application secrets.
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.
83
45
 
84
- ## Shikimori Provider
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.
85
47
 
86
- `shikimoriProvider` creates a metadata provider for anime.
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).
87
49
 
88
- ```ts
89
- import { MediaEngine } from "@media-engine/core";
90
- import { shikimoriProvider } from "@media-engine/providers";
91
-
92
- const engine = new MediaEngine({
93
- providers: [
94
- shikimoriProvider({
95
- userAgent: "MyApp/1.0.0",
96
- }),
97
- ],
98
- });
99
- ```
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.
100
51
 
101
- Supported data:
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.
102
53
 
103
- - title search for anime;
104
- - Shikimori ID lookup;
105
- - anime details;
106
- - posters, screenshots, ratings, genres, persons, episodes, and alternative titles;
107
- - Shikimori and MyAnimeList external IDs in normalized results.
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.
108
55
 
109
- The provider does not store API keys or read environment variables. Tests use mock `fetch` implementations and do not call the real Shikimori API.
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.
110
57
 
111
- ## AniList Provider
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`.
112
59
 
113
- `aniListProvider` adds public no-token anime search and details through AniList GraphQL. It complements Shikimori with English and international title aliases, AniList/MyAnimeList IDs, popularity counts, ratings, posters, and genres.
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.
114
63
 
115
- ```ts
116
- import { aniListProvider } from "@media-engine/providers";
117
-
118
- const engine = new MediaEngine({
119
- providers: [aniListProvider()],
120
- });
121
- ```
64
+ ## Player sources
122
65
 
123
- Public metadata requests do not require OAuth. The provider excludes adult results by default and can be configured with `includeAdult: true` when appropriate for the host application.
124
-
125
- ## Wikidata Provider
126
-
127
- `wikidataProvider` creates a no-token metadata provider for basic movie and series search.
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.
128
71
 
129
72
  ```ts
130
- import { MediaEngine } from "@media-engine/core";
131
- import { wikidataProvider } from "@media-engine/providers";
132
-
133
- const engine = new MediaEngine({
134
- providers: [wikidataProvider()],
73
+ const media = new MediaEngine({
74
+ streamingProviders: [
75
+ kinobdStreamingProvider(),
76
+ flixHqStreamingProvider(),
77
+ ],
135
78
  });
136
- ```
137
-
138
- Supported data:
139
-
140
- - title search for movies and series;
141
- - IMDb ID lookup through Wikidata;
142
- - basic details with title, description, release date, image, and IMDb ID when present.
143
79
 
144
- Wikidata is a free metadata source whose results are merged with KinoBD and Cinemeta. It is less complete than a dedicated movie database and should be treated as one enrichment source rather than the only source.
145
-
146
- ## IMDb Dataset Provider
147
-
148
- `imdbDatasetProvider` creates a local parser-backed provider for official IMDb non-commercial TSV datasets. It does not call imdb.com pages, does not use an unofficial API, and does not scrape.
149
-
150
- ```ts
151
- import { imdbDatasetProvider } from "@media-engine/providers";
152
-
153
- const provider = imdbDatasetProvider({
154
- titleBasicsTsv: titleBasicsFileContent,
155
- titleRatingsTsv: titleRatingsFileContent,
80
+ const result = await media.getAvailability({
81
+ type: "series",
82
+ title: "Game of Thrones",
83
+ seasonNumber: 1,
84
+ episodeNumber: 1,
156
85
  });
157
86
  ```
158
87
 
159
- Supported data:
160
-
161
- - title search for movies and series;
162
- - IMDb ID lookup;
163
- - basic details from `title.basics.tsv`;
164
- - IMDb ratings from `title.ratings.tsv` when provided.
165
-
166
- Before using this provider, download the official IMDb datasets and verify that your use complies with IMDb's non-commercial dataset terms.
167
-
168
- ## Experimental Streaming Provider
88
+ These are third-party player targets, not videos hosted by Media Engine. Availability depends on the upstream source and the user's environment.
169
89
 
170
- `experimentalStreamingProvider` creates a configured streaming provider for local architecture validation. It does not scrape websites and does not call a real streaming API. Applications pass already allowed embed or external player URLs from the outside.
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`.
171
96
 
172
97
  ```ts
173
- import { experimentalStreamingProvider } from "@media-engine/providers";
174
-
175
- const provider = experimentalStreamingProvider({
176
- name: "local-embed",
177
- entries: [
178
- {
179
- type: "anime",
180
- title: "Example Anime",
181
- ids: {
182
- shikimori: "20",
183
- },
184
- episodes: [
185
- {
186
- absoluteEpisodeNumber: 1,
187
- options: [
188
- {
189
- id: "example-episode-1",
190
- player: {
191
- kind: "embed",
192
- label: "Embed Player",
193
- },
194
- translation: {
195
- title: "AniDUB",
196
- type: "dub",
197
- language: "ru",
198
- },
199
- quality: {
200
- label: "720p",
201
- height: 720,
202
- },
203
- access: {
204
- url: "https://example.test/embed/episode-1",
205
- },
206
- availability: "available",
207
- },
208
- ],
209
- },
210
- ],
211
- },
98
+ const media = new MediaEngine({
99
+ streamingProviders: [
100
+ kinobdStreamingProvider(),
101
+ flixHqStreamingProvider(),
102
+ ddbbStreamingProvider(), // explicit opt-in
103
+ aniLibertyStreamingProvider(), // explicit opt-in
212
104
  ],
213
105
  });
214
106
  ```
215
107
 
216
- Supported behavior:
217
-
218
- - lookup by configured external IDs;
219
- - exact normalized title lookup when IDs are absent;
220
- - movie-level and episode-level stream options;
221
- - multiple player, translation, and quality options for one item or episode;
222
- - provider filtering through `StreamQuery.providers`.
223
-
224
- Use this provider only for experiments, tests, and UI wiring. A real provider such as Kodik should be implemented separately only after its API/embed usage rules are documented and allowed.
225
-
226
- ## KinoBD Streaming Provider
227
-
228
- `kinobdStreamingProvider` creates a no-token streaming provider for ReYohoho-style iframe player availability. It calls KinoBD-style player endpoints and returns normalized `StreamOption` values with embed URLs, provider labels, translations, and quality labels.
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.
229
167
 
230
168
  ```ts
231
- import { MediaEngine } from "@media-engine/core";
232
- import { kinobdStreamingProvider } from "@media-engine/providers";
233
-
234
- const engine = new MediaEngine({
235
- streamingProviders: [kinobdStreamingProvider()],
236
- });
237
-
238
- const availability = await engine.getAvailability({
239
- type: "movie",
240
- ids: {
241
- kinopoisk: "258687",
169
+ const media = new MediaEngine({
170
+ torrentProviders: [
171
+ ytsTorrentProvider(),
172
+ jacRedTorrentProvider(),
173
+ bitsearchTorrentProvider(),
174
+ magnetzTorrentProvider(),
175
+ ],
176
+ providerTimeouts: {
177
+ "yts-torrent": 15_000,
178
+ "jacred-torrent": 20_000,
179
+ "bitsearch-torrent": 15_000,
180
+ "magnetz-torrent": 15_000,
242
181
  },
243
182
  });
244
- ```
245
-
246
- Supported behavior:
247
-
248
- - movie and series lookup through `/api/player/search` and `/playerdata`;
249
- - anime fallback lookup by resolving a Shikimori ID through Shikimori's public API and searching KinoBD players by title;
250
- - optional anime cache lookup through a configured `animeCacheBaseUrl` with `/cache_shiki` when an application has an allowed backend for it;
251
- - player aggregation for the known KinoBD/ReYohoho embeddable player list, including Collaps, Vibix, Alloha, Kodik, KinoTochka, FlixCDN, Ashdi, Turbo, VideoCDN, Bazon, UStore, Pleer, VideoSpider, Iframe, Moonwalk, HDVB, CDNMovies, Lookbase, Kholobok, VideoAPI, Voidboost, Videoseed, and VK keys when upstream returns them;
252
- - fallback to player iframe candidates from `/api/player/search` when `/playerdata` is unavailable or returns no usable iframe options;
253
- - normalized embed player options with translation and quality metadata;
254
- - best-effort translation type and language inference for labels such as Russian dubbing, Ukrainian dubbing, English subtitles, and known Russian voiceover teams including AlexFilm, HDrezka Studio, LE-Production, Shachiburi, LostFilm, AniDUB, AniLibria, and 2x2;
255
- - best-effort filtering of clearly broken player pages, including HTTP 404/410/5xx and known unavailable-player HTML markers; live player page validation is bounded through `playerValidationLimit` and `playerValidationTimeoutMs`;
256
- - noisy external-only or non-playback keys such as `ia`, `ext`, `netflix`, `nf`, `torrent`, `trailer`, `trailer_local`, and `youtube` are excluded from requests and filtered from upstream responses;
257
- - provider filtering through `StreamQuery.providers`.
258
-
259
- This provider does not use a Kodik API token and does not extract direct video files. It returns player/embed URLs for the application UI to render.
260
-
261
- For live source-filter audits, pass `onPlayerAudit`. The callback reports discovered and shown player labels plus filtered labels with stable reasons such as `provider_not_allowed`, `missing_iframe`, `known_broken_url`, and `player_validation_failed`. Callback failures are isolated from normal availability behavior.
262
-
263
- ## FlixHQ Streaming Provider
264
-
265
- `flixHqStreamingProvider` discovers international movie embeds and explicitly requested series episodes without user credentials.
266
183
 
267
- ```ts
268
- import { MediaEngine } from "@media-engine/core";
269
- import { flixHqStreamingProvider } from "@media-engine/providers";
270
-
271
- const engine = new MediaEngine({
272
- streamingProviders: [flixHqStreamingProvider()],
273
- });
274
-
275
- const availability = await engine.getAvailability({
276
- type: "series",
277
- title: "House of the Dragon",
278
- year: 2022,
279
- seasonNumber: 2,
280
- episodeNumber: 3,
184
+ const torrents = await media.discoverTorrents({
185
+ type: "movie",
186
+ title: "Inception",
187
+ year: 2010,
188
+ ids: { imdb: "tt1375666" },
281
189
  });
282
190
  ```
283
191
 
284
- The provider validates discovered embeds with bounded requests and normalizes public `sub.info` subtitle tracks. If upstream explicitly returns an HLS or MP4 URL, it also normalizes the kind, advertised quality, and unambiguous expiry metadata. It does not reverse-engineer protected embed streams. Series lookup requires both season and episode numbers; anime is intentionally unsupported to avoid matching live-action adaptations.
285
-
286
- ## Shared Utilities
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.
287
197
 
288
- `src/shared` contains provider-side helpers used by future concrete providers:
198
+ Provider options, limitations, and safety rules are summarized in the [provider guide](https://github.com/Yaneart/media-engine/blob/main/docs/providers.md).
289
199
 
290
- - `fetchJson`;
291
- - `parseJsonResponse`;
292
- - `mapProviderHttpError`;
293
- - `mapHttpStatusToProviderErrorCode`.
200
+ ## License
294
201
 
295
- These helpers map HTTP, JSON parsing, network, timeout, and rate-limit failures into `ProviderError` from `@media-engine/core`. `fetchJson` retries retryable provider failures with a short backoff by default.
202
+ MIT