@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
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import { fetchJson } from "../shared/index.js";
|
|
2
|
+
const PROVIDER_NAME = "cinemeta";
|
|
3
|
+
const DEFAULT_BASE_URL = "https://v3-cinemeta.strem.io";
|
|
4
|
+
const DEFAULT_SEARCH_LIMIT = 10;
|
|
5
|
+
const DEFAULT_ENRICH_SEARCH_LIMIT = 5;
|
|
6
|
+
const DEFAULT_IMAGE_LIMIT = 10;
|
|
7
|
+
const DEFAULT_PERSON_LIMIT = 30;
|
|
8
|
+
// Creates a no-token movie and series provider backed by the public Cinemeta addon API.
|
|
9
|
+
// Создает no-token provider фильмов и сериалов на публичном Cinemeta addon API.
|
|
10
|
+
export function cinemetaProvider(options = {}) {
|
|
11
|
+
const config = createCinemetaConfig(options);
|
|
12
|
+
return {
|
|
13
|
+
name: PROVIDER_NAME,
|
|
14
|
+
version: options.version,
|
|
15
|
+
kind: "metadata",
|
|
16
|
+
capabilities: {
|
|
17
|
+
mediaTypes: ["movie", "series"],
|
|
18
|
+
search: {
|
|
19
|
+
byTitle: true,
|
|
20
|
+
byExternalIds: ["imdb"],
|
|
21
|
+
},
|
|
22
|
+
details: {
|
|
23
|
+
byExternalIds: ["imdb"],
|
|
24
|
+
},
|
|
25
|
+
features: ["posters", "backdrops", "ratings", "genres", "persons"],
|
|
26
|
+
},
|
|
27
|
+
async search(query, context) {
|
|
28
|
+
return searchCinemeta(config, query, context);
|
|
29
|
+
},
|
|
30
|
+
async getDetails(query, context) {
|
|
31
|
+
return getCinemetaDetails(config, query, context);
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// Builds provider config from public options.
|
|
36
|
+
// Собирает конфигурацию provider из публичных options.
|
|
37
|
+
function createCinemetaConfig(options) {
|
|
38
|
+
return {
|
|
39
|
+
baseUrl: trimTrailingSlash(options.baseUrl ?? DEFAULT_BASE_URL),
|
|
40
|
+
fetch: options.fetch,
|
|
41
|
+
searchLimit: options.searchLimit ?? DEFAULT_SEARCH_LIMIT,
|
|
42
|
+
enrichSearchLimit: options.enrichSearchLimit ?? DEFAULT_ENRICH_SEARCH_LIMIT,
|
|
43
|
+
imageLimit: options.imageLimit ?? DEFAULT_IMAGE_LIMIT,
|
|
44
|
+
personLimit: options.personLimit ?? DEFAULT_PERSON_LIMIT,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// Searches Cinemeta catalog by title or IMDb ID.
|
|
48
|
+
// Ищет в Cinemeta catalog по названию или IMDb ID.
|
|
49
|
+
async function searchCinemeta(config, query, context) {
|
|
50
|
+
if (query.type === "anime") {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
if (query.ids?.imdb) {
|
|
54
|
+
const details = await getDetailsByImdbId(config, query.ids.imdb, query.type, context);
|
|
55
|
+
return details ? [detailsToSearchResult(details, context.debug)] : [];
|
|
56
|
+
}
|
|
57
|
+
if (!query.title?.trim()) {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
const types = query.type ? [query.type] : ["movie", "series"];
|
|
61
|
+
const results = await Promise.all(types.map(async (type) => searchCatalogType(config, type, query, context)));
|
|
62
|
+
return results.flat().sort((left, right) => (right.confidence ?? 0) - (left.confidence ?? 0));
|
|
63
|
+
}
|
|
64
|
+
// Loads Cinemeta details by IMDb ID.
|
|
65
|
+
// Загружает Cinemeta details по IMDb ID.
|
|
66
|
+
async function getCinemetaDetails(config, query, context) {
|
|
67
|
+
if (!query.ids?.imdb) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const details = await getDetailsByImdbId(config, query.ids.imdb, query.type, context);
|
|
71
|
+
return details
|
|
72
|
+
? {
|
|
73
|
+
provider: PROVIDER_NAME,
|
|
74
|
+
details,
|
|
75
|
+
source: createProviderSource(details.ids),
|
|
76
|
+
raw: context.debug ? details : undefined,
|
|
77
|
+
confidence: 1,
|
|
78
|
+
}
|
|
79
|
+
: null;
|
|
80
|
+
}
|
|
81
|
+
// Searches one Cinemeta catalog type.
|
|
82
|
+
// Ищет один тип Cinemeta catalog.
|
|
83
|
+
async function searchCatalogType(config, type, query, context) {
|
|
84
|
+
const url = new URL(`${config.baseUrl}/catalog/${toCinemetaType(type)}/top/search=${encodeURIComponent(query.title ?? "")}.json`);
|
|
85
|
+
const response = await requestJson(config, url, context);
|
|
86
|
+
const items = (response.metas ?? [])
|
|
87
|
+
.map((meta) => mapMetaToItem(meta, type))
|
|
88
|
+
.filter((item) => item !== undefined)
|
|
89
|
+
.filter((item) => query.year === undefined || item.year === query.year)
|
|
90
|
+
.slice(0, query.limit ?? config.searchLimit);
|
|
91
|
+
const enrichedItems = shouldEnrichSearchItems(query)
|
|
92
|
+
? await enrichSearchItems(config, type, items, context)
|
|
93
|
+
: items;
|
|
94
|
+
return enrichedItems.map((item) => createSearchResult(item, context.debug));
|
|
95
|
+
}
|
|
96
|
+
// Keeps broad title-only search responsive by avoiding extra per-item meta requests.
|
|
97
|
+
// Сохраняет быстрым широкий title-only поиск, избегая дополнительных meta-запросов на каждый item.
|
|
98
|
+
function shouldEnrichSearchItems(query) {
|
|
99
|
+
return query.year !== undefined || Boolean(query.ids?.imdb);
|
|
100
|
+
}
|
|
101
|
+
// Enriches top search candidates with meta details when catalog search is sparse.
|
|
102
|
+
// Обогащает верхние search-кандидаты meta-деталями, когда catalog search возвращает мало данных.
|
|
103
|
+
async function enrichSearchItems(config, type, items, context) {
|
|
104
|
+
const enriched = await Promise.all(items.map(async (item, index) => {
|
|
105
|
+
if (index >= config.enrichSearchLimit || !item.ids?.imdb || hasSearchQuality(item)) {
|
|
106
|
+
return item;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
const details = await getDetailsByImdbId(config, item.ids.imdb, type, context);
|
|
110
|
+
return details ? detailsToItem(details) : item;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return item;
|
|
114
|
+
}
|
|
115
|
+
}));
|
|
116
|
+
return enriched;
|
|
117
|
+
}
|
|
118
|
+
// Checks whether a catalog item already has enough data for ranking and display.
|
|
119
|
+
// Проверяет, достаточно ли данных catalog item для ранжирования и отображения.
|
|
120
|
+
function hasSearchQuality(item) {
|
|
121
|
+
return Boolean(item.ratings?.length && item.description && item.genres?.length);
|
|
122
|
+
}
|
|
123
|
+
// Normalizes a title enough to decide whether it is broad or specific.
|
|
124
|
+
// Нормализует title достаточно для решения, широкий это запрос или конкретный.
|
|
125
|
+
// Loads one Cinemeta meta document.
|
|
126
|
+
// Загружает один Cinemeta meta document.
|
|
127
|
+
async function getDetailsByImdbId(config, imdbId, type, context) {
|
|
128
|
+
const types = type === "movie" || type === "series"
|
|
129
|
+
? [type]
|
|
130
|
+
: type === "anime"
|
|
131
|
+
? ["series"]
|
|
132
|
+
: ["movie", "series"];
|
|
133
|
+
const loadType = async (currentType) => {
|
|
134
|
+
const url = new URL(`${config.baseUrl}/meta/${toCinemetaType(currentType)}/${imdbId}.json`);
|
|
135
|
+
const response = await requestJson(config, url, context);
|
|
136
|
+
return response.meta ? metaToDetails(config, response.meta, currentType) : null;
|
|
137
|
+
};
|
|
138
|
+
if (types.length === 1) {
|
|
139
|
+
return loadType(types[0]);
|
|
140
|
+
}
|
|
141
|
+
const results = await Promise.all(types.map((currentType) => loadType(currentType).catch(() => null)));
|
|
142
|
+
return results.find((details) => details !== null) ?? null;
|
|
143
|
+
}
|
|
144
|
+
// Maps Cinemeta summary into compact MediaItem.
|
|
145
|
+
// Мапит Cinemeta summary в compact MediaItem.
|
|
146
|
+
function mapMetaToItem(meta, type) {
|
|
147
|
+
const imdbId = meta.imdb_id ?? meta.id;
|
|
148
|
+
const title = meta.name;
|
|
149
|
+
if (!imdbId || !title) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
const ids = createIds(meta, imdbId);
|
|
153
|
+
return {
|
|
154
|
+
id: `${PROVIDER_NAME}-${type}-${imdbId}`,
|
|
155
|
+
type,
|
|
156
|
+
title,
|
|
157
|
+
year: getYear(meta.releaseInfo),
|
|
158
|
+
description: meta.description,
|
|
159
|
+
poster: createImage(meta.poster, "poster"),
|
|
160
|
+
backdrop: createImage(meta.background, "backdrop"),
|
|
161
|
+
genres: mapGenres(meta.genre ?? meta.genres),
|
|
162
|
+
ratings: mapRating(meta.imdbRating),
|
|
163
|
+
ids,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// Converts Cinemeta meta details into movie or series details.
|
|
167
|
+
// Преобразует Cinemeta meta details в movie или series details.
|
|
168
|
+
function metaToDetails(config, meta, type) {
|
|
169
|
+
const item = mapMetaToItem(meta, type);
|
|
170
|
+
if (!item) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
const detailsBase = {
|
|
174
|
+
...item,
|
|
175
|
+
runtimeMinutes: parseRuntime(meta.runtime),
|
|
176
|
+
countries: parseList(meta.country),
|
|
177
|
+
images: [item.poster, item.backdrop]
|
|
178
|
+
.filter((image) => Boolean(image))
|
|
179
|
+
.slice(0, config.imageLimit),
|
|
180
|
+
persons: mapPersons(meta, config.personLimit),
|
|
181
|
+
sourceProviders: [createProviderSource(item.ids)],
|
|
182
|
+
};
|
|
183
|
+
return type === "series"
|
|
184
|
+
? {
|
|
185
|
+
...detailsBase,
|
|
186
|
+
type: "series",
|
|
187
|
+
status: mapStatus(meta.status),
|
|
188
|
+
episodesCount: countSeriesEpisodes(meta.videos),
|
|
189
|
+
seasonsCount: countSeriesSeasons(meta.videos),
|
|
190
|
+
}
|
|
191
|
+
: { ...detailsBase, type: "movie" };
|
|
192
|
+
}
|
|
193
|
+
// Creates a provider search result with source attribution.
|
|
194
|
+
// Создает provider search result с source attribution.
|
|
195
|
+
function createSearchResult(item, debug) {
|
|
196
|
+
return {
|
|
197
|
+
provider: PROVIDER_NAME,
|
|
198
|
+
item,
|
|
199
|
+
source: createProviderSource(item.ids),
|
|
200
|
+
raw: debug ? item : undefined,
|
|
201
|
+
confidence: item.ids?.imdb ? 0.95 : 0.8,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
// Converts details back to a search result for IMDb ID search.
|
|
205
|
+
// Преобразует details обратно в search result для поиска по IMDb ID.
|
|
206
|
+
function detailsToSearchResult(details, debug) {
|
|
207
|
+
return createSearchResult(detailsToItem(details), debug);
|
|
208
|
+
}
|
|
209
|
+
// Converts details into the compact search item shape.
|
|
210
|
+
// Преобразует details в компактную форму search item.
|
|
211
|
+
function detailsToItem(details) {
|
|
212
|
+
return {
|
|
213
|
+
id: details.id,
|
|
214
|
+
type: details.type,
|
|
215
|
+
title: details.title,
|
|
216
|
+
year: details.year,
|
|
217
|
+
description: details.description,
|
|
218
|
+
poster: details.poster,
|
|
219
|
+
backdrop: details.backdrop,
|
|
220
|
+
genres: details.genres,
|
|
221
|
+
ratings: details.ratings,
|
|
222
|
+
ids: details.ids,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
// Creates normalized external IDs from Cinemeta IDs.
|
|
226
|
+
// Создает normalized external IDs из Cinemeta IDs.
|
|
227
|
+
function createIds(meta, imdbId) {
|
|
228
|
+
return {
|
|
229
|
+
imdb: imdbId,
|
|
230
|
+
tmdb: meta.moviedb_id ? String(meta.moviedb_id) : undefined,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
// Creates source attribution for Cinemeta results.
|
|
234
|
+
// Создает source attribution для результатов Cinemeta.
|
|
235
|
+
function createProviderSource(ids) {
|
|
236
|
+
return {
|
|
237
|
+
provider: PROVIDER_NAME,
|
|
238
|
+
ids,
|
|
239
|
+
url: ids?.imdb ? `https://www.imdb.com/title/${ids.imdb}/` : undefined,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
// Maps genre labels into normalized genre objects.
|
|
243
|
+
// Мапит genre labels в normalized genre objects.
|
|
244
|
+
function mapGenres(genres) {
|
|
245
|
+
return genres?.map((genre) => ({
|
|
246
|
+
name: genre,
|
|
247
|
+
source: PROVIDER_NAME,
|
|
248
|
+
}));
|
|
249
|
+
}
|
|
250
|
+
// Maps IMDb rating from Cinemeta into normalized rating.
|
|
251
|
+
// Мапит IMDb rating из Cinemeta в normalized rating.
|
|
252
|
+
function mapRating(value) {
|
|
253
|
+
const parsed = value ? Number(value) : undefined;
|
|
254
|
+
return parsed && Number.isFinite(parsed)
|
|
255
|
+
? [
|
|
256
|
+
{
|
|
257
|
+
source: "imdb",
|
|
258
|
+
value: parsed,
|
|
259
|
+
max: 10,
|
|
260
|
+
},
|
|
261
|
+
]
|
|
262
|
+
: undefined;
|
|
263
|
+
}
|
|
264
|
+
// Maps simple people arrays into normalized persons.
|
|
265
|
+
// Мапит простые people arrays в normalized persons.
|
|
266
|
+
function mapPersons(meta, limit) {
|
|
267
|
+
const directors = (meta.director ?? []).map((name) => ({
|
|
268
|
+
person: { name },
|
|
269
|
+
roles: ["director"],
|
|
270
|
+
}));
|
|
271
|
+
const writers = (meta.writer ?? []).map((name) => ({
|
|
272
|
+
person: { name },
|
|
273
|
+
roles: ["writer"],
|
|
274
|
+
}));
|
|
275
|
+
const actors = (meta.cast ?? []).map((name, order) => ({
|
|
276
|
+
person: { name },
|
|
277
|
+
roles: ["actor"],
|
|
278
|
+
order,
|
|
279
|
+
}));
|
|
280
|
+
const persons = [...directors, ...writers, ...actors].slice(0, limit);
|
|
281
|
+
return persons.length ? persons : undefined;
|
|
282
|
+
}
|
|
283
|
+
function createImage(url, type) {
|
|
284
|
+
return url
|
|
285
|
+
? {
|
|
286
|
+
url,
|
|
287
|
+
type,
|
|
288
|
+
source: PROVIDER_NAME,
|
|
289
|
+
}
|
|
290
|
+
: undefined;
|
|
291
|
+
}
|
|
292
|
+
// Requests JSON through the shared provider HTTP helper.
|
|
293
|
+
// Запрашивает JSON через общий provider HTTP helper.
|
|
294
|
+
function requestJson(config, url, context) {
|
|
295
|
+
return fetchJson({
|
|
296
|
+
provider: PROVIDER_NAME,
|
|
297
|
+
url,
|
|
298
|
+
context,
|
|
299
|
+
fetch: config.fetch,
|
|
300
|
+
init: {
|
|
301
|
+
headers: {
|
|
302
|
+
accept: "application/json",
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
// Converts normalized media type to Cinemeta route type.
|
|
308
|
+
// Конвертирует normalized media type в Cinemeta route type.
|
|
309
|
+
function toCinemetaType(type) {
|
|
310
|
+
return type;
|
|
311
|
+
}
|
|
312
|
+
// Extracts the first four-digit year from Cinemeta release info.
|
|
313
|
+
// Достает первый четырехзначный год из Cinemeta release info.
|
|
314
|
+
function getYear(value) {
|
|
315
|
+
const match = value?.match(/\d{4}/);
|
|
316
|
+
return match ? Number(match[0]) : undefined;
|
|
317
|
+
}
|
|
318
|
+
// Parses the first runtime number from Cinemeta runtime text.
|
|
319
|
+
// Парсит первое число runtime из Cinemeta runtime text.
|
|
320
|
+
function parseRuntime(runtime) {
|
|
321
|
+
const match = runtime?.match(/\d+/);
|
|
322
|
+
return match ? Number(match[0]) : undefined;
|
|
323
|
+
}
|
|
324
|
+
// Splits comma-separated Cinemeta values into normalized strings.
|
|
325
|
+
// Разбивает comma-separated Cinemeta values в normalized strings.
|
|
326
|
+
function parseList(value) {
|
|
327
|
+
return value
|
|
328
|
+
?.split(",")
|
|
329
|
+
.map((entry) => entry.trim())
|
|
330
|
+
.filter(Boolean);
|
|
331
|
+
}
|
|
332
|
+
// Maps Cinemeta lifecycle status into the core status vocabulary.
|
|
333
|
+
// Мапит lifecycle status Cinemeta в словарь status из core.
|
|
334
|
+
function mapStatus(status) {
|
|
335
|
+
switch (status?.toLowerCase()) {
|
|
336
|
+
case "ended":
|
|
337
|
+
return "ended";
|
|
338
|
+
case "returning series":
|
|
339
|
+
return "ongoing";
|
|
340
|
+
case "in production":
|
|
341
|
+
return "in_production";
|
|
342
|
+
case "planned":
|
|
343
|
+
case "pilot":
|
|
344
|
+
return "announced";
|
|
345
|
+
case "canceled":
|
|
346
|
+
case "cancelled":
|
|
347
|
+
return "canceled";
|
|
348
|
+
default:
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
// Counts regular series episodes while ignoring specials from season 0.
|
|
353
|
+
// Считает обычные эпизоды сериала, игнорируя specials из season 0.
|
|
354
|
+
function countSeriesEpisodes(videos) {
|
|
355
|
+
const count = videos?.filter((video) => isRegularEpisode(video)).length ?? 0;
|
|
356
|
+
return count > 0 ? count : undefined;
|
|
357
|
+
}
|
|
358
|
+
// Counts seasons that contain regular episodes.
|
|
359
|
+
// Считает сезоны, в которых есть обычные эпизоды.
|
|
360
|
+
function countSeriesSeasons(videos) {
|
|
361
|
+
const seasons = new Set(videos
|
|
362
|
+
?.filter((video) => isRegularEpisode(video))
|
|
363
|
+
.map((video) => video.season)
|
|
364
|
+
.filter((season) => typeof season === "number" && season > 0));
|
|
365
|
+
return seasons.size > 0 ? seasons.size : undefined;
|
|
366
|
+
}
|
|
367
|
+
// Checks whether a Cinemeta video is a regular numbered episode.
|
|
368
|
+
// Проверяет, является ли Cinemeta video обычным номерным эпизодом.
|
|
369
|
+
function isRegularEpisode(video) {
|
|
370
|
+
return (typeof video.season === "number" &&
|
|
371
|
+
video.season > 0 &&
|
|
372
|
+
(typeof video.number === "number" || typeof video.episode === "number"));
|
|
373
|
+
}
|
|
374
|
+
// Removes trailing slashes so URL paths are built consistently.
|
|
375
|
+
// Убирает trailing slashes, чтобы URL paths собирались одинаково.
|
|
376
|
+
function trimTrailingSlash(value) {
|
|
377
|
+
return value.replace(/\/+$/, "");
|
|
378
|
+
}
|
|
379
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cinemeta/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ExternalIds, MediaType, StreamEpisodeRef, StreamOption, StreamingProvider } from "@media-engine/core";
|
|
2
|
+
export interface ExperimentalStreamingProviderOptions {
|
|
3
|
+
name?: string;
|
|
4
|
+
version?: string;
|
|
5
|
+
entries: ExperimentalStreamingEntry[];
|
|
6
|
+
}
|
|
7
|
+
export interface ExperimentalStreamingEntry {
|
|
8
|
+
type: MediaType;
|
|
9
|
+
title?: string;
|
|
10
|
+
originalTitle?: string;
|
|
11
|
+
year?: number;
|
|
12
|
+
ids?: ExternalIds;
|
|
13
|
+
sourceUrl?: string;
|
|
14
|
+
options?: ExperimentalStreamOptionInput[];
|
|
15
|
+
episodes?: ExperimentalStreamingEpisode[];
|
|
16
|
+
}
|
|
17
|
+
export interface ExperimentalStreamingEpisode extends StreamEpisodeRef {
|
|
18
|
+
title?: string;
|
|
19
|
+
options: ExperimentalStreamOptionInput[];
|
|
20
|
+
}
|
|
21
|
+
export type ExperimentalStreamOptionInput = Omit<StreamOption, "provider"> & {
|
|
22
|
+
provider?: string;
|
|
23
|
+
};
|
|
24
|
+
export declare function experimentalStreamingProvider(options: ExperimentalStreamingProviderOptions): StreamingProvider;
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
const DEFAULT_PROVIDER_NAME = "experimental-streaming";
|
|
2
|
+
const EXTERNAL_ID_SOURCES = [
|
|
3
|
+
"imdb",
|
|
4
|
+
"tmdb",
|
|
5
|
+
"kinopoisk",
|
|
6
|
+
"shikimori",
|
|
7
|
+
"myAnimeList",
|
|
8
|
+
"aniList",
|
|
9
|
+
"worldArt",
|
|
10
|
+
];
|
|
11
|
+
// Creates a configured streaming provider for architecture validation.
|
|
12
|
+
// Создает настроенный streaming-провайдер для проверки архитектуры.
|
|
13
|
+
export function experimentalStreamingProvider(options) {
|
|
14
|
+
const name = normalizeProviderName(options.name ?? DEFAULT_PROVIDER_NAME);
|
|
15
|
+
const entries = options.entries.map(normalizeEntry);
|
|
16
|
+
const capabilities = createCapabilities(entries);
|
|
17
|
+
return {
|
|
18
|
+
name,
|
|
19
|
+
version: options.version,
|
|
20
|
+
kind: "streaming",
|
|
21
|
+
capabilities,
|
|
22
|
+
async getAvailability(query, context) {
|
|
23
|
+
return getExperimentalAvailability(name, entries, query, context);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
// Validates and normalizes provider name.
|
|
28
|
+
// Проверяет и нормализует имя провайдера.
|
|
29
|
+
function normalizeProviderName(name) {
|
|
30
|
+
const normalized = name.trim();
|
|
31
|
+
if (!normalized) {
|
|
32
|
+
throw new TypeError("Experimental streaming provider name is required.");
|
|
33
|
+
}
|
|
34
|
+
return normalized;
|
|
35
|
+
}
|
|
36
|
+
// Adds lookup helpers without changing the public entry shape.
|
|
37
|
+
// Добавляет lookup helpers без изменения публичной формы записи.
|
|
38
|
+
function normalizeEntry(entry) {
|
|
39
|
+
return {
|
|
40
|
+
...entry,
|
|
41
|
+
titleKey: entry.title ? normalizeTitle(entry.title) : undefined,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// Builds safe capabilities from configured entries.
|
|
45
|
+
// Собирает безопасные capabilities из настроенных записей.
|
|
46
|
+
function createCapabilities(entries) {
|
|
47
|
+
return {
|
|
48
|
+
mediaTypes: unique(entries.map((entry) => entry.type)),
|
|
49
|
+
lookup: {
|
|
50
|
+
byTitle: entries.some((entry) => Boolean(entry.title)),
|
|
51
|
+
byExternalIds: collectExternalIdSources(entries),
|
|
52
|
+
byEpisode: entries.some((entry) => Boolean(entry.episodes?.length) ||
|
|
53
|
+
Boolean(entry.options?.some((option) => hasEpisodeRef(option.episode)))),
|
|
54
|
+
},
|
|
55
|
+
features: ["embed", "external", "translations", "subtitles", "qualities", "episode_mapping"],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
// Resolves availability for a single stream query.
|
|
59
|
+
// Получает доступность для одного stream-запроса.
|
|
60
|
+
async function getExperimentalAvailability(providerName, entries, query, context) {
|
|
61
|
+
if (query.providers && !query.providers.includes(providerName)) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
const entry = entries.find((candidate) => matchesEntry(candidate, query));
|
|
65
|
+
if (!entry) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
if (context.signal?.aborted) {
|
|
69
|
+
throw context.signal.reason;
|
|
70
|
+
}
|
|
71
|
+
const episodes = filterEpisodes(providerName, entry, query);
|
|
72
|
+
const topLevelOptions = filterTopLevelOptions(providerName, entry, query);
|
|
73
|
+
const episodeOptions = episodes.flatMap((episode) => episode.options);
|
|
74
|
+
const options = [...topLevelOptions, ...episodeOptions];
|
|
75
|
+
return {
|
|
76
|
+
query,
|
|
77
|
+
item: {
|
|
78
|
+
type: entry.type,
|
|
79
|
+
title: entry.title,
|
|
80
|
+
originalTitle: entry.originalTitle,
|
|
81
|
+
year: entry.year,
|
|
82
|
+
ids: entry.ids,
|
|
83
|
+
},
|
|
84
|
+
episodes: episodes.length > 0 ? episodes : undefined,
|
|
85
|
+
options,
|
|
86
|
+
sourceProviders: [
|
|
87
|
+
{
|
|
88
|
+
provider: providerName,
|
|
89
|
+
ids: entry.ids,
|
|
90
|
+
url: entry.sourceUrl,
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
checkedAt: new Date().toISOString(),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// Checks whether a configured entry can answer the query.
|
|
97
|
+
// Проверяет, может ли настроенная запись ответить на запрос.
|
|
98
|
+
function matchesEntry(entry, query) {
|
|
99
|
+
if (entry.type !== query.type) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
if (matchesAnyExternalId(entry.ids, query.ids)) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
if (!entry.titleKey || !query.title) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
return entry.titleKey === normalizeTitle(query.title) && matchesYear(entry.year, query.year);
|
|
109
|
+
}
|
|
110
|
+
// Filters episode blocks for an episode-aware query.
|
|
111
|
+
// Фильтрует блоки эпизодов для episode-aware запроса.
|
|
112
|
+
function filterEpisodes(providerName, entry, query) {
|
|
113
|
+
return (entry.episodes ?? [])
|
|
114
|
+
.filter((episode) => matchesEpisode(episode, query))
|
|
115
|
+
.map((episode) => ({
|
|
116
|
+
seasonNumber: episode.seasonNumber,
|
|
117
|
+
episodeNumber: episode.episodeNumber,
|
|
118
|
+
absoluteEpisodeNumber: episode.absoluteEpisodeNumber,
|
|
119
|
+
title: episode.title,
|
|
120
|
+
options: episode.options.map((option) => normalizeOption(providerName, option, episode)),
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
// Filters top-level options and keeps only requested episode options when needed.
|
|
124
|
+
// Фильтрует верхнеуровневые варианты и оставляет варианты нужного эпизода при запросе.
|
|
125
|
+
function filterTopLevelOptions(providerName, entry, query) {
|
|
126
|
+
return (entry.options ?? [])
|
|
127
|
+
.filter((option) => matchesEpisode(option.episode, query))
|
|
128
|
+
.map((option) => normalizeOption(providerName, option, option.episode));
|
|
129
|
+
}
|
|
130
|
+
// Fills provider and episode fields on a stream option.
|
|
131
|
+
// Заполняет provider и episode поля в stream-варианте.
|
|
132
|
+
function normalizeOption(providerName, option, episode) {
|
|
133
|
+
return {
|
|
134
|
+
...option,
|
|
135
|
+
provider: option.provider ?? providerName,
|
|
136
|
+
episode: option.episode ?? episode,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
// Checks exact external ID overlap between entry and query.
|
|
140
|
+
// Проверяет точное пересечение внешних ID между записью и запросом.
|
|
141
|
+
function matchesAnyExternalId(entryIds, queryIds) {
|
|
142
|
+
if (!entryIds || !queryIds) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
return EXTERNAL_ID_SOURCES.some((source) => entryIds[source] !== undefined && entryIds[source] === queryIds[source]);
|
|
146
|
+
}
|
|
147
|
+
// Checks whether years are compatible when both sides provide them.
|
|
148
|
+
// Проверяет совместимость годов, если обе стороны их передали.
|
|
149
|
+
function matchesYear(entryYear, queryYear) {
|
|
150
|
+
return entryYear === undefined || queryYear === undefined || entryYear === queryYear;
|
|
151
|
+
}
|
|
152
|
+
// Checks whether an episode reference matches the episode fields from query.
|
|
153
|
+
// Проверяет, совпадает ли ссылка на эпизод с episode-полями запроса.
|
|
154
|
+
function matchesEpisode(episode, query) {
|
|
155
|
+
if (!hasEpisodeQuery(query)) {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
if (!episode) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
return (matchesOptionalNumber(episode.seasonNumber, query.seasonNumber) &&
|
|
162
|
+
matchesOptionalNumber(episode.episodeNumber, query.episodeNumber) &&
|
|
163
|
+
matchesOptionalNumber(episode.absoluteEpisodeNumber, query.absoluteEpisodeNumber));
|
|
164
|
+
}
|
|
165
|
+
// Checks whether query contains episode targeting fields.
|
|
166
|
+
// Проверяет, содержит ли query поля выбора эпизода.
|
|
167
|
+
function hasEpisodeQuery(query) {
|
|
168
|
+
return (query.seasonNumber !== undefined ||
|
|
169
|
+
query.episodeNumber !== undefined ||
|
|
170
|
+
query.absoluteEpisodeNumber !== undefined);
|
|
171
|
+
}
|
|
172
|
+
// Checks whether an option or configured episode has any episode reference.
|
|
173
|
+
// Проверяет, есть ли у варианта или настроенного эпизода ссылка на эпизод.
|
|
174
|
+
function hasEpisodeRef(episode) {
|
|
175
|
+
return (episode?.seasonNumber !== undefined ||
|
|
176
|
+
episode?.episodeNumber !== undefined ||
|
|
177
|
+
episode?.absoluteEpisodeNumber !== undefined);
|
|
178
|
+
}
|
|
179
|
+
// Matches optional numeric fields strictly when query value exists.
|
|
180
|
+
// Строго сравнивает опциональные числовые поля, если query значение есть.
|
|
181
|
+
function matchesOptionalNumber(value, queryValue) {
|
|
182
|
+
return queryValue === undefined || value === queryValue;
|
|
183
|
+
}
|
|
184
|
+
// Collects external ID sources present in configured entries.
|
|
185
|
+
// Собирает источники внешних ID из настроенных записей.
|
|
186
|
+
function collectExternalIdSources(entries) {
|
|
187
|
+
return EXTERNAL_ID_SOURCES.filter((source) => entries.some((entry) => entry.ids?.[source] !== undefined));
|
|
188
|
+
}
|
|
189
|
+
// Normalizes titles for exact configured-title lookup.
|
|
190
|
+
// Нормализует названия для точного поиска по настроенному title.
|
|
191
|
+
function normalizeTitle(title) {
|
|
192
|
+
return title.trim().toLocaleLowerCase().replace(/\s+/g, " ");
|
|
193
|
+
}
|
|
194
|
+
// Keeps array values unique while preserving order.
|
|
195
|
+
// Оставляет уникальные значения массива с сохранением порядка.
|
|
196
|
+
function unique(values) {
|
|
197
|
+
return [...new Set(values)];
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/experimental-streaming/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { StreamEpisodeRef, StreamingProvider, SubtitleTrack } from "@media-engine/core";
|
|
2
|
+
import { type ProviderFetch } from "../shared/index.js";
|
|
3
|
+
export interface FlixHqStreamingProviderOptions {
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
version?: string;
|
|
7
|
+
fetch?: ProviderFetch;
|
|
8
|
+
maxHtmlBytes?: number;
|
|
9
|
+
playerLimit?: number;
|
|
10
|
+
playerValidationConcurrency?: number;
|
|
11
|
+
playerValidationTimeoutMs?: number;
|
|
12
|
+
playerValidationMaxBytes?: number;
|
|
13
|
+
subtitleInfoMaxBytes?: number;
|
|
14
|
+
userAgent?: string;
|
|
15
|
+
}
|
|
16
|
+
interface SearchCandidate {
|
|
17
|
+
mediaUrl: string;
|
|
18
|
+
title: string;
|
|
19
|
+
year?: number;
|
|
20
|
+
type: "movie" | "series";
|
|
21
|
+
}
|
|
22
|
+
interface EpisodeCandidate extends StreamEpisodeRef {
|
|
23
|
+
url: string;
|
|
24
|
+
title?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare function flixHqStreamingProvider(options?: FlixHqStreamingProviderOptions): StreamingProvider;
|
|
27
|
+
export declare function parseSubtitleInfo(value: string): SubtitleTrack[];
|
|
28
|
+
export declare function parseSearchCandidates(html: string): SearchCandidate[];
|
|
29
|
+
export declare function parseEpisodes(html: string): EpisodeCandidate[];
|
|
30
|
+
export {};
|