@media-engine/providers 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/anilist/index.d.ts +9 -0
- package/dist/anilist/index.js +279 -0
- package/dist/anilist/index.js.map +1 -0
- package/dist/cinemeta/index.d.ts +12 -0
- package/dist/cinemeta/index.js +379 -0
- package/dist/cinemeta/index.js.map +1 -0
- package/dist/experimental-streaming/index.d.ts +24 -0
- package/dist/experimental-streaming/index.js +199 -0
- package/dist/experimental-streaming/index.js.map +1 -0
- package/dist/flixhq-streaming/index.d.ts +30 -0
- package/dist/flixhq-streaming/index.js +625 -0
- package/dist/flixhq-streaming/index.js.map +1 -0
- package/dist/imdb-dataset/index.d.ts +9 -0
- package/dist/imdb-dataset/index.js +307 -0
- package/dist/imdb-dataset/index.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/kinobd/index.d.ts +11 -0
- package/dist/kinobd/index.js +405 -0
- package/dist/kinobd/index.js.map +1 -0
- package/dist/kinobd-streaming/index.d.ts +31 -0
- package/dist/kinobd-streaming/index.js +919 -0
- package/dist/kinobd-streaming/index.js.map +1 -0
- package/dist/shared/http.d.ts +17 -0
- package/dist/shared/http.js +264 -0
- package/dist/shared/http.js.map +1 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +2 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shikimori/index.d.ts +12 -0
- package/dist/shikimori/index.js +457 -0
- package/dist/shikimori/index.js.map +1 -0
- package/dist/wikidata/index.d.ts +12 -0
- package/dist/wikidata/index.js +356 -0
- package/dist/wikidata/index.js.map +1 -0
- package/package.json +62 -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/providers
|
|
2
|
+
|
|
3
|
+
Provider package for Media Engine.
|
|
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.
|
|
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
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @media-engine/core @media-engine/providers
|
|
13
|
+
```
|
|
14
|
+
|
|
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.
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { MediaEngine } from "@media-engine/core";
|
|
44
|
+
import { kinobdProvider } from "@media-engine/providers";
|
|
45
|
+
|
|
46
|
+
const engine = new MediaEngine({
|
|
47
|
+
providers: [kinobdProvider()],
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Supported data:
|
|
52
|
+
|
|
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
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Supported data:
|
|
75
|
+
|
|
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`.
|
|
81
|
+
|
|
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.
|
|
83
|
+
|
|
84
|
+
## Shikimori Provider
|
|
85
|
+
|
|
86
|
+
`shikimoriProvider` creates a metadata provider for anime.
|
|
87
|
+
|
|
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
|
+
```
|
|
100
|
+
|
|
101
|
+
Supported data:
|
|
102
|
+
|
|
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.
|
|
108
|
+
|
|
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.
|
|
110
|
+
|
|
111
|
+
## AniList Provider
|
|
112
|
+
|
|
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.
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { aniListProvider } from "@media-engine/providers";
|
|
117
|
+
|
|
118
|
+
const engine = new MediaEngine({
|
|
119
|
+
providers: [aniListProvider()],
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
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.
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import { MediaEngine } from "@media-engine/core";
|
|
131
|
+
import { wikidataProvider } from "@media-engine/providers";
|
|
132
|
+
|
|
133
|
+
const engine = new MediaEngine({
|
|
134
|
+
providers: [wikidataProvider()],
|
|
135
|
+
});
|
|
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
|
+
|
|
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,
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
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
|
|
169
|
+
|
|
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.
|
|
171
|
+
|
|
172
|
+
```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
|
+
},
|
|
212
|
+
],
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
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.
|
|
229
|
+
|
|
230
|
+
```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",
|
|
242
|
+
},
|
|
243
|
+
});
|
|
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
|
+
|
|
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,
|
|
281
|
+
});
|
|
282
|
+
```
|
|
283
|
+
|
|
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
|
|
287
|
+
|
|
288
|
+
`src/shared` contains provider-side helpers used by future concrete providers:
|
|
289
|
+
|
|
290
|
+
- `fetchJson`;
|
|
291
|
+
- `parseJsonResponse`;
|
|
292
|
+
- `mapProviderHttpError`;
|
|
293
|
+
- `mapHttpStatusToProviderErrorCode`.
|
|
294
|
+
|
|
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.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MediaProvider } from "@media-engine/core";
|
|
2
|
+
import { type ProviderFetch } from "../shared/index.js";
|
|
3
|
+
export interface AniListProviderOptions {
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
fetch?: ProviderFetch;
|
|
6
|
+
searchLimit?: number;
|
|
7
|
+
includeAdult?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function aniListProvider(options?: AniListProviderOptions): MediaProvider;
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { fetchJson } from "../shared/index.js";
|
|
2
|
+
const PROVIDER_NAME = "anilist";
|
|
3
|
+
const DEFAULT_BASE_URL = "https://graphql.anilist.co";
|
|
4
|
+
const DEFAULT_SEARCH_LIMIT = 10;
|
|
5
|
+
const MEDIA_FIELDS = `
|
|
6
|
+
id idMal title { romaji english native } synonyms format status episodes duration
|
|
7
|
+
startDate { year month day } endDate { year month day }
|
|
8
|
+
description(asHtml: false) averageScore popularity isAdult countryOfOrigin
|
|
9
|
+
coverImage { extraLarge large } genres siteUrl
|
|
10
|
+
`;
|
|
11
|
+
// Creates a public no-token AniList anime metadata provider.
|
|
12
|
+
// Создает публичный no-token AniList anime metadata provider.
|
|
13
|
+
export function aniListProvider(options = {}) {
|
|
14
|
+
const config = {
|
|
15
|
+
baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,
|
|
16
|
+
fetch: options.fetch,
|
|
17
|
+
searchLimit: options.searchLimit ?? DEFAULT_SEARCH_LIMIT,
|
|
18
|
+
includeAdult: options.includeAdult ?? false,
|
|
19
|
+
};
|
|
20
|
+
if (!Number.isInteger(config.searchLimit) || config.searchLimit <= 0 || config.searchLimit > 50) {
|
|
21
|
+
throw new RangeError("AniList searchLimit must be an integer between 1 and 50.");
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
name: PROVIDER_NAME,
|
|
25
|
+
kind: "metadata",
|
|
26
|
+
capabilities: {
|
|
27
|
+
mediaTypes: ["anime"],
|
|
28
|
+
search: { byTitle: true, byExternalIds: ["aniList", "myAnimeList"] },
|
|
29
|
+
details: { byExternalIds: ["aniList", "myAnimeList"] },
|
|
30
|
+
features: ["posters", "ratings", "genres"],
|
|
31
|
+
},
|
|
32
|
+
search: (query, context) => searchAniList(config, query, context),
|
|
33
|
+
getDetails: (query, context) => getAniListDetails(config, query, context),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async function searchAniList(config, query, context) {
|
|
37
|
+
if (query.type && query.type !== "anime")
|
|
38
|
+
return [];
|
|
39
|
+
if (query.ids?.aniList || query.ids?.myAnimeList) {
|
|
40
|
+
const details = await loadDetails(config, query.ids, context);
|
|
41
|
+
return details ? [toSearchResult(details, context.debug)] : [];
|
|
42
|
+
}
|
|
43
|
+
if (!query.title?.trim())
|
|
44
|
+
return [];
|
|
45
|
+
const response = await request(config, `query ($search: String!, $perPage: Int!, $isAdult: Boolean) {
|
|
46
|
+
Page(page: 1, perPage: $perPage) {
|
|
47
|
+
media(search: $search, type: ANIME, isAdult: $isAdult, sort: [SEARCH_MATCH, POPULARITY_DESC]) { ${MEDIA_FIELDS} }
|
|
48
|
+
}
|
|
49
|
+
}`, {
|
|
50
|
+
search: query.title,
|
|
51
|
+
perPage: Math.min(query.limit ?? config.searchLimit, 50),
|
|
52
|
+
isAdult: config.includeAdult ? undefined : false,
|
|
53
|
+
}, context);
|
|
54
|
+
return (response.data?.Page?.media ?? [])
|
|
55
|
+
.map(mapMediaItem)
|
|
56
|
+
.filter((item) => item !== undefined)
|
|
57
|
+
.filter((item) => query.year === undefined || item.year === query.year)
|
|
58
|
+
.map((item) => toSearchResult(item, context.debug));
|
|
59
|
+
}
|
|
60
|
+
async function getAniListDetails(config, query, context) {
|
|
61
|
+
if (query.type && query.type !== "anime")
|
|
62
|
+
return null;
|
|
63
|
+
const details = await loadDetails(config, query.ids ?? {}, context);
|
|
64
|
+
return details
|
|
65
|
+
? {
|
|
66
|
+
provider: PROVIDER_NAME,
|
|
67
|
+
details,
|
|
68
|
+
confidence: 1,
|
|
69
|
+
source: createSource(details.ids),
|
|
70
|
+
raw: context.debug ? details : undefined,
|
|
71
|
+
}
|
|
72
|
+
: null;
|
|
73
|
+
}
|
|
74
|
+
async function loadDetails(config, ids, context) {
|
|
75
|
+
if (!ids.aniList && !ids.myAnimeList)
|
|
76
|
+
return null;
|
|
77
|
+
const response = await request(config, `query ($id: Int, $idMal: Int) { Media(id: $id, idMal: $idMal, type: ANIME) { ${MEDIA_FIELDS} } }`, {
|
|
78
|
+
id: ids.aniList ? Number(ids.aniList) : undefined,
|
|
79
|
+
idMal: !ids.aniList && ids.myAnimeList ? Number(ids.myAnimeList) : undefined,
|
|
80
|
+
}, context);
|
|
81
|
+
const media = response.data?.Media;
|
|
82
|
+
const item = media ? mapMediaItem(media) : undefined;
|
|
83
|
+
return item && media ? mapDetails(item, media) : null;
|
|
84
|
+
}
|
|
85
|
+
function mapMediaItem(media) {
|
|
86
|
+
if (!media.id || (!media.title?.romaji && !media.title?.english))
|
|
87
|
+
return undefined;
|
|
88
|
+
const englishTitle = normalizeText(media.title.english);
|
|
89
|
+
const romajiTitle = normalizeText(media.title.romaji);
|
|
90
|
+
const title = englishTitle || romajiTitle;
|
|
91
|
+
if (!title)
|
|
92
|
+
return undefined;
|
|
93
|
+
const candidates = [
|
|
94
|
+
romajiTitle,
|
|
95
|
+
englishTitle,
|
|
96
|
+
normalizeText(media.title.native),
|
|
97
|
+
...(media.synonyms ?? []),
|
|
98
|
+
]
|
|
99
|
+
.map((value) => normalizeText(value))
|
|
100
|
+
.filter((value) => Boolean(value));
|
|
101
|
+
const alternativeTitles = [...new Set(candidates)].filter((value) => value !== title);
|
|
102
|
+
const releaseDate = formatDate(media.startDate);
|
|
103
|
+
return {
|
|
104
|
+
id: `${PROVIDER_NAME}-anime-${media.id}`,
|
|
105
|
+
type: "anime",
|
|
106
|
+
title,
|
|
107
|
+
originalTitle: romajiTitle,
|
|
108
|
+
alternativeTitles: alternativeTitles.length ? alternativeTitles : undefined,
|
|
109
|
+
year: media.startDate?.year ?? undefined,
|
|
110
|
+
releaseDate,
|
|
111
|
+
description: normalizeText(media.description),
|
|
112
|
+
poster: mapPoster(media.coverImage),
|
|
113
|
+
genres: mapGenres(media.genres),
|
|
114
|
+
ratings: mapRating(media),
|
|
115
|
+
ids: { aniList: String(media.id), myAnimeList: media.idMal ? String(media.idMal) : undefined },
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
// Converts AniList's lightweight HTML descriptions into plain public text.
|
|
119
|
+
// Преобразует HTML-описания AniList в обычный публичный текст.
|
|
120
|
+
function normalizeText(value) {
|
|
121
|
+
const decoded = repairMojibake(value?.trim());
|
|
122
|
+
const normalized = decoded
|
|
123
|
+
?.replace(/<br\s*\/?>/gi, "\n")
|
|
124
|
+
.replace(/<[^>]+>/g, "")
|
|
125
|
+
.replace(/ /gi, " ")
|
|
126
|
+
.replace(/&/gi, "&")
|
|
127
|
+
.replace(/</gi, "<")
|
|
128
|
+
.replace(/>/gi, ">")
|
|
129
|
+
.replace(/"/gi, '"')
|
|
130
|
+
.replace(/'/gi, "'")
|
|
131
|
+
.replace(/&#(\d+);/g, (_match, code) => String.fromCodePoint(Number(code)))
|
|
132
|
+
.replace(/&#x([\da-f]+);/gi, (_match, code) => String.fromCodePoint(Number.parseInt(code, 16)))
|
|
133
|
+
.replace(/[ \t]+\n/g, "\n")
|
|
134
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
135
|
+
.trim();
|
|
136
|
+
return normalized && !normalized.includes("\uFFFD") ? normalized : undefined;
|
|
137
|
+
}
|
|
138
|
+
// Repairs the common case where UTF-8 bytes were decoded as Latin-1 upstream.
|
|
139
|
+
function repairMojibake(value) {
|
|
140
|
+
if (!value || !/[ÃÂâ]/u.test(value))
|
|
141
|
+
return value;
|
|
142
|
+
const windows1252Bytes = new Map([
|
|
143
|
+
["€", 0x80],
|
|
144
|
+
["‚", 0x82],
|
|
145
|
+
["ƒ", 0x83],
|
|
146
|
+
["„", 0x84],
|
|
147
|
+
["…", 0x85],
|
|
148
|
+
["†", 0x86],
|
|
149
|
+
["‡", 0x87],
|
|
150
|
+
["ˆ", 0x88],
|
|
151
|
+
["‰", 0x89],
|
|
152
|
+
["Š", 0x8a],
|
|
153
|
+
["‹", 0x8b],
|
|
154
|
+
["Œ", 0x8c],
|
|
155
|
+
["Ž", 0x8e],
|
|
156
|
+
["‘", 0x91],
|
|
157
|
+
["’", 0x92],
|
|
158
|
+
["“", 0x93],
|
|
159
|
+
["”", 0x94],
|
|
160
|
+
["•", 0x95],
|
|
161
|
+
["–", 0x96],
|
|
162
|
+
["—", 0x97],
|
|
163
|
+
["˜", 0x98],
|
|
164
|
+
["™", 0x99],
|
|
165
|
+
["š", 0x9a],
|
|
166
|
+
["›", 0x9b],
|
|
167
|
+
["œ", 0x9c],
|
|
168
|
+
["ž", 0x9e],
|
|
169
|
+
["Ÿ", 0x9f],
|
|
170
|
+
]);
|
|
171
|
+
const bytes = Uint8Array.from(value, (character) => windows1252Bytes.get(character) ?? character.charCodeAt(0));
|
|
172
|
+
const repaired = new TextDecoder("utf-8", { fatal: true });
|
|
173
|
+
try {
|
|
174
|
+
return repaired.decode(bytes);
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return value;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function mapDetails(item, media) {
|
|
181
|
+
return {
|
|
182
|
+
...item,
|
|
183
|
+
type: "anime",
|
|
184
|
+
status: mapStatus(media.status),
|
|
185
|
+
runtimeMinutes: media.duration ?? undefined,
|
|
186
|
+
countries: media.countryOfOrigin ? [media.countryOfOrigin] : undefined,
|
|
187
|
+
languages: media.countryOfOrigin === "JP" ? ["ja"] : undefined,
|
|
188
|
+
sourceProviders: [createSource(item.ids)],
|
|
189
|
+
animeKind: mapKind(media.format),
|
|
190
|
+
episodesCount: media.episodes ?? undefined,
|
|
191
|
+
airedOn: formatDate(media.startDate),
|
|
192
|
+
releasedOn: formatDate(media.endDate),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function toSearchResult(item, debug) {
|
|
196
|
+
return {
|
|
197
|
+
provider: PROVIDER_NAME,
|
|
198
|
+
item,
|
|
199
|
+
confidence: 1,
|
|
200
|
+
source: createSource(item.ids),
|
|
201
|
+
raw: debug ? item : undefined,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function createSource(ids) {
|
|
205
|
+
return {
|
|
206
|
+
provider: PROVIDER_NAME,
|
|
207
|
+
ids,
|
|
208
|
+
url: ids?.aniList ? `https://anilist.co/anime/${ids.aniList}` : undefined,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function mapPoster(image) {
|
|
212
|
+
const url = image?.extraLarge ?? image?.large;
|
|
213
|
+
return url ? { url, type: "poster", source: PROVIDER_NAME } : undefined;
|
|
214
|
+
}
|
|
215
|
+
function mapGenres(values) {
|
|
216
|
+
return values?.length ? values.map((name) => ({ name, source: PROVIDER_NAME })) : undefined;
|
|
217
|
+
}
|
|
218
|
+
function mapRating(media) {
|
|
219
|
+
return media.averageScore
|
|
220
|
+
? [
|
|
221
|
+
{
|
|
222
|
+
source: "aniList",
|
|
223
|
+
value: media.averageScore,
|
|
224
|
+
max: 100,
|
|
225
|
+
votes: media.popularity ?? undefined,
|
|
226
|
+
},
|
|
227
|
+
]
|
|
228
|
+
: undefined;
|
|
229
|
+
}
|
|
230
|
+
function mapStatus(status) {
|
|
231
|
+
if (status === "RELEASING")
|
|
232
|
+
return "ongoing";
|
|
233
|
+
if (status === "FINISHED")
|
|
234
|
+
return "ended";
|
|
235
|
+
if (status === "NOT_YET_RELEASED")
|
|
236
|
+
return "announced";
|
|
237
|
+
if (status === "CANCELLED")
|
|
238
|
+
return "canceled";
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
function mapKind(format) {
|
|
242
|
+
if (format === "TV" || format === "TV_SHORT")
|
|
243
|
+
return "tv";
|
|
244
|
+
if (format === "MOVIE")
|
|
245
|
+
return "movie";
|
|
246
|
+
if (format === "OVA")
|
|
247
|
+
return "ova";
|
|
248
|
+
if (format === "ONA")
|
|
249
|
+
return "ona";
|
|
250
|
+
if (format === "SPECIAL")
|
|
251
|
+
return "special";
|
|
252
|
+
if (format === "MUSIC")
|
|
253
|
+
return "music";
|
|
254
|
+
return format ? "unknown" : undefined;
|
|
255
|
+
}
|
|
256
|
+
function formatDate(date) {
|
|
257
|
+
if (!date?.year)
|
|
258
|
+
return undefined;
|
|
259
|
+
return [date.year, date.month ?? 1, date.day ?? 1]
|
|
260
|
+
.map((value, index) => (index ? String(value).padStart(2, "0") : String(value)))
|
|
261
|
+
.join("-");
|
|
262
|
+
}
|
|
263
|
+
async function request(config, query, variables, context) {
|
|
264
|
+
const response = await fetchJson({
|
|
265
|
+
provider: PROVIDER_NAME,
|
|
266
|
+
url: config.baseUrl,
|
|
267
|
+
context,
|
|
268
|
+
fetch: config.fetch,
|
|
269
|
+
init: {
|
|
270
|
+
method: "POST",
|
|
271
|
+
headers: { Accept: "application/json", "Content-Type": "application/json" },
|
|
272
|
+
body: JSON.stringify({ query, variables }),
|
|
273
|
+
},
|
|
274
|
+
});
|
|
275
|
+
if (response.errors?.length)
|
|
276
|
+
throw new Error(response.errors[0]?.message ?? "AniList GraphQL error.");
|
|
277
|
+
return response;
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/anilist/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type MediaProvider } from "@media-engine/core";
|
|
2
|
+
import { type ProviderFetch } from "../shared/index.js";
|
|
3
|
+
export interface CinemetaProviderOptions {
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
fetch?: ProviderFetch;
|
|
6
|
+
version?: string;
|
|
7
|
+
searchLimit?: number;
|
|
8
|
+
enrichSearchLimit?: number;
|
|
9
|
+
imageLimit?: number;
|
|
10
|
+
personLimit?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function cinemetaProvider(options?: CinemetaProviderOptions): MediaProvider;
|