@media-engine/providers 1.0.0 → 1.2.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 -21
- package/README.md +67 -135
- package/README.ru.md +73 -139
- package/dist/filmix-streaming/client.d.ts +36 -0
- package/dist/filmix-streaming/client.js +241 -0
- package/dist/filmix-streaming/client.js.map +1 -0
- package/dist/filmix-streaming/config.d.ts +42 -0
- package/dist/filmix-streaming/config.js +93 -0
- package/dist/filmix-streaming/config.js.map +1 -0
- package/dist/filmix-streaming/index.d.ts +4 -0
- package/dist/filmix-streaming/index.js +48 -0
- package/dist/filmix-streaming/index.js.map +1 -0
- package/dist/filmix-streaming/mapping.d.ts +3 -0
- package/dist/filmix-streaming/mapping.js +109 -0
- package/dist/filmix-streaming/mapping.js.map +1 -0
- package/dist/filmix-streaming/matching.d.ts +4 -0
- package/dist/filmix-streaming/matching.js +41 -0
- package/dist/filmix-streaming/matching.js.map +1 -0
- package/dist/imdb-dataset/sqlite-import.js +5 -2
- package/dist/imdb-dataset/sqlite-import.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/package-version.d.ts +2 -2
- package/dist/package-version.js +1 -1
- package/dist/rutube-streaming/client.d.ts +18 -0
- package/dist/rutube-streaming/client.js +106 -0
- package/dist/rutube-streaming/client.js.map +1 -0
- package/dist/rutube-streaming/config.d.ts +26 -0
- package/dist/rutube-streaming/config.js +57 -0
- package/dist/rutube-streaming/config.js.map +1 -0
- package/dist/rutube-streaming/index.d.ts +4 -0
- package/dist/rutube-streaming/index.js +38 -0
- package/dist/rutube-streaming/index.js.map +1 -0
- package/dist/rutube-streaming/mapping.d.ts +4 -0
- package/dist/rutube-streaming/mapping.js +32 -0
- package/dist/rutube-streaming/mapping.js.map +1 -0
- package/dist/rutube-streaming/matching.d.ts +2 -0
- package/dist/rutube-streaming/matching.js +37 -0
- package/dist/rutube-streaming/matching.js.map +1 -0
- package/dist/shared/safe-fetch.d.ts +2 -0
- package/dist/shared/safe-fetch.js +29 -3
- package/dist/shared/safe-fetch.js.map +1 -1
- package/dist/veoveo-streaming/client.d.ts +28 -0
- package/dist/veoveo-streaming/client.js +212 -0
- package/dist/veoveo-streaming/client.js.map +1 -0
- package/dist/veoveo-streaming/config.d.ts +32 -0
- package/dist/veoveo-streaming/config.js +67 -0
- package/dist/veoveo-streaming/config.js.map +1 -0
- package/dist/veoveo-streaming/index.d.ts +4 -0
- package/dist/veoveo-streaming/index.js +46 -0
- package/dist/veoveo-streaming/index.js.map +1 -0
- package/dist/veoveo-streaming/mapping.d.ts +3 -0
- package/dist/veoveo-streaming/mapping.js +121 -0
- package/dist/veoveo-streaming/mapping.js.map +1 -0
- package/dist/videohub-streaming/client.d.ts +35 -0
- package/dist/videohub-streaming/client.js +239 -0
- package/dist/videohub-streaming/client.js.map +1 -0
- package/dist/videohub-streaming/config.d.ts +34 -0
- package/dist/videohub-streaming/config.js +73 -0
- package/dist/videohub-streaming/config.js.map +1 -0
- package/dist/videohub-streaming/index.d.ts +4 -0
- package/dist/videohub-streaming/index.js +59 -0
- package/dist/videohub-streaming/index.js.map +1 -0
- package/dist/videohub-streaming/mapping.d.ts +3 -0
- package/dist/videohub-streaming/mapping.js +100 -0
- package/dist/videohub-streaming/mapping.js.map +1 -0
- package/package.json +7 -2
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type MediaAvailability, type ProviderContext } from "@media-engine/core";
|
|
2
|
+
import type { VideoHubStreamingConfig } from "./config.js";
|
|
3
|
+
export interface VideoHubPlaylistItem {
|
|
4
|
+
vkId: string;
|
|
5
|
+
seasonNumber?: number;
|
|
6
|
+
episodeNumber?: number;
|
|
7
|
+
absoluteEpisodeNumber?: number;
|
|
8
|
+
voiceStudio?: string;
|
|
9
|
+
voiceType?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface VideoHubPlaylist {
|
|
12
|
+
title?: string;
|
|
13
|
+
isSerial: boolean;
|
|
14
|
+
items: VideoHubPlaylistItem[];
|
|
15
|
+
}
|
|
16
|
+
export interface VideoHubMp4Source {
|
|
17
|
+
url: string;
|
|
18
|
+
label: string;
|
|
19
|
+
height?: number;
|
|
20
|
+
}
|
|
21
|
+
export interface ResolvedVideoHubItem extends VideoHubPlaylistItem {
|
|
22
|
+
sources: VideoHubMp4Source[];
|
|
23
|
+
sourceUrl: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function resolveVideoHubKinopoiskId(query: MediaAvailability["query"]): string | undefined;
|
|
26
|
+
export declare function loadVideoHubPlaylist(config: VideoHubStreamingConfig, kinopoiskId: string, context: ProviderContext, playbackUserAgent: string): Promise<{
|
|
27
|
+
playlist: VideoHubPlaylist;
|
|
28
|
+
sourceUrl: string;
|
|
29
|
+
}>;
|
|
30
|
+
export declare function resolveVideoHubItems(config: VideoHubStreamingConfig, playlist: VideoHubPlaylist, query: MediaAvailability["query"], context: ProviderContext, playbackUserAgent: string): Promise<ResolvedVideoHubItem[]>;
|
|
31
|
+
export declare function createVideoHubPlaylistUrl(baseUrl: string, kinopoiskId: string): URL;
|
|
32
|
+
export declare function createVideoHubVideoUrl(baseUrl: string, vkId: string): URL;
|
|
33
|
+
export declare function parseVideoHubPlaylist(provider: string, value: unknown, itemLimit: number): VideoHubPlaylist;
|
|
34
|
+
export declare function parseVideoHubSources(provider: string, value: unknown): VideoHubMp4Source[];
|
|
35
|
+
export declare function selectVideoHubPlaylistItems(playlist: VideoHubPlaylist, query: MediaAvailability["query"]): VideoHubPlaylistItem[];
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { ProviderError } from "@media-engine/core";
|
|
2
|
+
import { fetchJson, normalizeProviderOutputUrl } from "../shared/index.js";
|
|
3
|
+
import { rethrowIfProviderAborted } from "../shared/abort.js";
|
|
4
|
+
const PLAYLIST_PUBLICATION_ID = "12";
|
|
5
|
+
const MAX_TITLE_LENGTH = 500;
|
|
6
|
+
const MAX_TRANSLATION_LENGTH = 200;
|
|
7
|
+
const MP4_SOURCE_FIELDS = [
|
|
8
|
+
{ key: "mpeg4kUrl", label: "4K", height: 2160 },
|
|
9
|
+
{ key: "mpeg2kUrl", label: "2K" },
|
|
10
|
+
{ key: "mpegQhdUrl", label: "1440p", height: 1440 },
|
|
11
|
+
{ key: "mpegFullHdUrl", label: "1080p", height: 1080 },
|
|
12
|
+
{ key: "mpegHighUrl", label: "720p", height: 720 },
|
|
13
|
+
{ key: "mpegMediumUrl", label: "480p", height: 480 },
|
|
14
|
+
{ key: "mpegLowUrl", label: "360p", height: 360 },
|
|
15
|
+
{ key: "mpegLowestUrl", label: "240p", height: 240 },
|
|
16
|
+
{ key: "mpegTinyUrl", label: "144p", height: 144 },
|
|
17
|
+
];
|
|
18
|
+
export function resolveVideoHubKinopoiskId(query) {
|
|
19
|
+
const kinopoisk = query.ids?.kinopoisk ?? query.kinopoisk;
|
|
20
|
+
return kinopoisk && /^[1-9]\d{0,11}$/u.test(kinopoisk) ? kinopoisk : undefined;
|
|
21
|
+
}
|
|
22
|
+
export async function loadVideoHubPlaylist(config, kinopoiskId, context, playbackUserAgent) {
|
|
23
|
+
const url = createVideoHubPlaylistUrl(config.baseUrl, kinopoiskId);
|
|
24
|
+
const payload = await fetchJson({
|
|
25
|
+
provider: config.name,
|
|
26
|
+
url,
|
|
27
|
+
context,
|
|
28
|
+
fetch: config.fetch,
|
|
29
|
+
rateLimitGate: config.rateLimitGate,
|
|
30
|
+
maxRetries: 0,
|
|
31
|
+
maxResponseBytes: config.maxPlaylistResponseBytes,
|
|
32
|
+
init: { headers: createHeaders(playbackUserAgent) },
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
playlist: parseVideoHubPlaylist(config.name, payload, config.playlistItemLimit),
|
|
36
|
+
sourceUrl: url.href,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function createVideoLookupContext(config, context) {
|
|
40
|
+
return {
|
|
41
|
+
...context,
|
|
42
|
+
timeoutMs: context.timeoutMs === undefined
|
|
43
|
+
? config.videoLookupTimeoutMs
|
|
44
|
+
: Math.min(context.timeoutMs, config.videoLookupTimeoutMs),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export async function resolveVideoHubItems(config, playlist, query, context, playbackUserAgent) {
|
|
48
|
+
const selected = selectVideoHubPlaylistItems(playlist, query).slice(0, config.videoLookupLimit);
|
|
49
|
+
if (selected.length === 0)
|
|
50
|
+
return [];
|
|
51
|
+
const resolved = new Array(selected.length);
|
|
52
|
+
let nextIndex = 0;
|
|
53
|
+
let firstError;
|
|
54
|
+
const worker = async () => {
|
|
55
|
+
while (nextIndex < selected.length) {
|
|
56
|
+
const index = nextIndex;
|
|
57
|
+
nextIndex += 1;
|
|
58
|
+
const item = selected[index];
|
|
59
|
+
try {
|
|
60
|
+
const result = await loadVideoHubSources(config, item.vkId, context, playbackUserAgent);
|
|
61
|
+
if (result.sources.length > 0)
|
|
62
|
+
resolved[index] = { ...item, ...result };
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
rethrowIfProviderAborted(context, error);
|
|
66
|
+
firstError ??= error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
await Promise.all(Array.from({ length: Math.min(config.videoLookupConcurrency, selected.length) }, async () => worker()));
|
|
71
|
+
const available = resolved.filter((item) => item !== undefined);
|
|
72
|
+
if (available.length === 0 && firstError !== undefined)
|
|
73
|
+
throw firstError;
|
|
74
|
+
return available;
|
|
75
|
+
}
|
|
76
|
+
export function createVideoHubPlaylistUrl(baseUrl, kinopoiskId) {
|
|
77
|
+
const url = new URL("/api/v1/player/sv/playlist", `${baseUrl}/`);
|
|
78
|
+
url.searchParams.set("pub", PLAYLIST_PUBLICATION_ID);
|
|
79
|
+
url.searchParams.set("aggr", "kp");
|
|
80
|
+
url.searchParams.set("id", kinopoiskId);
|
|
81
|
+
return url;
|
|
82
|
+
}
|
|
83
|
+
export function createVideoHubVideoUrl(baseUrl, vkId) {
|
|
84
|
+
return new URL(`/api/v1/player/sv/video/${vkId}`, `${baseUrl}/`);
|
|
85
|
+
}
|
|
86
|
+
export function parseVideoHubPlaylist(provider, value, itemLimit) {
|
|
87
|
+
if (!isRecord(value) || typeof value.isSerial !== "boolean" || !Array.isArray(value.items)) {
|
|
88
|
+
throw invalidResponse(provider, "playlist");
|
|
89
|
+
}
|
|
90
|
+
const isSerial = value.isSerial;
|
|
91
|
+
const items = value.items.slice(0, itemLimit).flatMap((entry) => {
|
|
92
|
+
const item = parsePlaylistItem(entry, isSerial);
|
|
93
|
+
return item ? [item] : [];
|
|
94
|
+
});
|
|
95
|
+
if (value.items.length > 0 && items.length === 0)
|
|
96
|
+
throw invalidResponse(provider, "playlist");
|
|
97
|
+
const title = readString(value.titleName, MAX_TITLE_LENGTH);
|
|
98
|
+
return {
|
|
99
|
+
...(title ? { title } : {}),
|
|
100
|
+
isSerial,
|
|
101
|
+
items,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export function parseVideoHubSources(provider, value) {
|
|
105
|
+
if (!isRecord(value) || !isRecord(value.sources))
|
|
106
|
+
throw invalidResponse(provider, "video");
|
|
107
|
+
const sources = [];
|
|
108
|
+
const seenUrls = new Set();
|
|
109
|
+
for (const field of MP4_SOURCE_FIELDS) {
|
|
110
|
+
const rawUrl = value.sources[field.key];
|
|
111
|
+
if (typeof rawUrl !== "string")
|
|
112
|
+
continue;
|
|
113
|
+
const url = normalizeHttpsOutputUrl(rawUrl);
|
|
114
|
+
if (!url || seenUrls.has(url))
|
|
115
|
+
continue;
|
|
116
|
+
seenUrls.add(url);
|
|
117
|
+
sources.push({
|
|
118
|
+
url,
|
|
119
|
+
label: field.label,
|
|
120
|
+
...("height" in field ? { height: field.height } : {}),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
return sources;
|
|
124
|
+
}
|
|
125
|
+
export function selectVideoHubPlaylistItems(playlist, query) {
|
|
126
|
+
if (query.type === "movie")
|
|
127
|
+
return playlist.isSerial ? [] : playlist.items;
|
|
128
|
+
if (!playlist.isSerial)
|
|
129
|
+
return [];
|
|
130
|
+
const items = query.type === "anime" ? addAbsoluteEpisodeNumbers(playlist.items) : playlist.items;
|
|
131
|
+
return items.filter((item) => {
|
|
132
|
+
if (query.seasonNumber !== undefined && item.seasonNumber !== query.seasonNumber) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
if (query.episodeNumber !== undefined && item.episodeNumber !== query.episodeNumber) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
return (query.absoluteEpisodeNumber === undefined ||
|
|
139
|
+
item.absoluteEpisodeNumber === query.absoluteEpisodeNumber);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
function addAbsoluteEpisodeNumbers(items) {
|
|
143
|
+
const episodeKeys = [
|
|
144
|
+
...new Set(items.flatMap((item) => {
|
|
145
|
+
if (item.seasonNumber === undefined || item.episodeNumber === undefined)
|
|
146
|
+
return [];
|
|
147
|
+
return [`${item.seasonNumber}:${item.episodeNumber}`];
|
|
148
|
+
})),
|
|
149
|
+
].sort(compareEpisodeKeys);
|
|
150
|
+
const absoluteByEpisode = new Map(episodeKeys.map((key, index) => [key, index + 1]));
|
|
151
|
+
return items.flatMap((item) => {
|
|
152
|
+
if (item.seasonNumber === undefined || item.episodeNumber === undefined)
|
|
153
|
+
return [];
|
|
154
|
+
const absoluteEpisodeNumber = absoluteByEpisode.get(`${item.seasonNumber}:${item.episodeNumber}`);
|
|
155
|
+
return absoluteEpisodeNumber === undefined ? [] : [{ ...item, absoluteEpisodeNumber }];
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function compareEpisodeKeys(left, right) {
|
|
159
|
+
const [leftSeason = 0, leftEpisode = 0] = left.split(":").map(Number);
|
|
160
|
+
const [rightSeason = 0, rightEpisode = 0] = right.split(":").map(Number);
|
|
161
|
+
return leftSeason - rightSeason || leftEpisode - rightEpisode;
|
|
162
|
+
}
|
|
163
|
+
async function loadVideoHubSources(config, vkId, context, playbackUserAgent) {
|
|
164
|
+
const url = createVideoHubVideoUrl(config.baseUrl, vkId);
|
|
165
|
+
const payload = await fetchJson({
|
|
166
|
+
provider: config.name,
|
|
167
|
+
url,
|
|
168
|
+
context: createVideoLookupContext(config, context),
|
|
169
|
+
fetch: config.fetch,
|
|
170
|
+
rateLimitGate: config.rateLimitGate,
|
|
171
|
+
maxRetries: 0,
|
|
172
|
+
maxResponseBytes: config.maxVideoResponseBytes,
|
|
173
|
+
init: { headers: createHeaders(playbackUserAgent) },
|
|
174
|
+
});
|
|
175
|
+
return {
|
|
176
|
+
sources: parseVideoHubSources(config.name, payload),
|
|
177
|
+
sourceUrl: url.href,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function parsePlaylistItem(value, isSerial) {
|
|
181
|
+
if (!isRecord(value))
|
|
182
|
+
return undefined;
|
|
183
|
+
const vkId = readIdentifier(value.vkId);
|
|
184
|
+
if (!vkId)
|
|
185
|
+
return undefined;
|
|
186
|
+
const seasonNumber = isSerial ? readPositiveInteger(value.season) : undefined;
|
|
187
|
+
const episodeNumber = isSerial ? readPositiveInteger(value.episode) : undefined;
|
|
188
|
+
if (isSerial && (seasonNumber === undefined || episodeNumber === undefined))
|
|
189
|
+
return undefined;
|
|
190
|
+
const voiceStudio = readString(value.voiceStudio, MAX_TRANSLATION_LENGTH);
|
|
191
|
+
const voiceType = readString(value.voiceType, MAX_TRANSLATION_LENGTH);
|
|
192
|
+
return {
|
|
193
|
+
vkId,
|
|
194
|
+
...(seasonNumber !== undefined ? { seasonNumber } : {}),
|
|
195
|
+
...(episodeNumber !== undefined ? { episodeNumber } : {}),
|
|
196
|
+
...(voiceStudio ? { voiceStudio } : {}),
|
|
197
|
+
...(voiceType ? { voiceType } : {}),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
function createHeaders(userAgent) {
|
|
201
|
+
return {
|
|
202
|
+
Accept: "application/json",
|
|
203
|
+
"User-Agent": userAgent,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function normalizeHttpsOutputUrl(value) {
|
|
207
|
+
const normalized = normalizeProviderOutputUrl(value.trim());
|
|
208
|
+
if (!normalized)
|
|
209
|
+
return undefined;
|
|
210
|
+
return new URL(normalized).protocol === "https:" ? normalized : undefined;
|
|
211
|
+
}
|
|
212
|
+
function readIdentifier(value) {
|
|
213
|
+
if (typeof value === "number" && Number.isSafeInteger(value) && value > 0)
|
|
214
|
+
return String(value);
|
|
215
|
+
return typeof value === "string" && /^[1-9]\d{0,19}$/u.test(value.trim())
|
|
216
|
+
? value.trim()
|
|
217
|
+
: undefined;
|
|
218
|
+
}
|
|
219
|
+
function readPositiveInteger(value) {
|
|
220
|
+
return Number.isSafeInteger(value) && value > 0 ? value : undefined;
|
|
221
|
+
}
|
|
222
|
+
function readString(value, maxLength) {
|
|
223
|
+
if (typeof value !== "string")
|
|
224
|
+
return undefined;
|
|
225
|
+
const normalized = value.trim();
|
|
226
|
+
return normalized && normalized.length <= maxLength ? normalized : undefined;
|
|
227
|
+
}
|
|
228
|
+
function isRecord(value) {
|
|
229
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
230
|
+
}
|
|
231
|
+
function invalidResponse(provider, stage) {
|
|
232
|
+
return new ProviderError({
|
|
233
|
+
provider,
|
|
234
|
+
code: "PROVIDER_INVALID_RESPONSE",
|
|
235
|
+
message: `Provider "${provider}" returned an invalid VideoHUB ${stage} response.`,
|
|
236
|
+
retryable: false,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/videohub-streaming/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { StreamingProviderCapabilities } from "@media-engine/core";
|
|
2
|
+
import { ProviderRateLimitGate, type ProviderFetch } from "../shared/index.js";
|
|
3
|
+
export interface VideoHubStreamingProviderOptions {
|
|
4
|
+
name?: string;
|
|
5
|
+
version?: string;
|
|
6
|
+
baseUrl?: string;
|
|
7
|
+
fetch?: ProviderFetch;
|
|
8
|
+
maxPlaylistResponseBytes?: number;
|
|
9
|
+
maxVideoResponseBytes?: number;
|
|
10
|
+
playlistItemLimit?: number;
|
|
11
|
+
videoLookupLimit?: number;
|
|
12
|
+
videoLookupConcurrency?: number;
|
|
13
|
+
videoLookupTimeoutMs?: number;
|
|
14
|
+
linkTtlMs?: number;
|
|
15
|
+
userAgent?: string;
|
|
16
|
+
now?: () => number;
|
|
17
|
+
}
|
|
18
|
+
export interface VideoHubStreamingConfig {
|
|
19
|
+
name: string;
|
|
20
|
+
baseUrl: string;
|
|
21
|
+
fetch: ProviderFetch;
|
|
22
|
+
rateLimitGate: ProviderRateLimitGate;
|
|
23
|
+
maxPlaylistResponseBytes: number;
|
|
24
|
+
maxVideoResponseBytes: number;
|
|
25
|
+
playlistItemLimit: number;
|
|
26
|
+
videoLookupLimit: number;
|
|
27
|
+
videoLookupConcurrency: number;
|
|
28
|
+
videoLookupTimeoutMs: number;
|
|
29
|
+
linkTtlMs: number;
|
|
30
|
+
userAgent: string;
|
|
31
|
+
now: () => number;
|
|
32
|
+
}
|
|
33
|
+
export declare function createVideoHubConfig(options: VideoHubStreamingProviderOptions): VideoHubStreamingConfig;
|
|
34
|
+
export declare function createVideoHubCapabilities(): StreamingProviderCapabilities;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { MEDIA_ENGINE_DEFAULT_USER_AGENT } from "../package-version.js";
|
|
2
|
+
import { ProviderRateLimitGate } from "../shared/index.js";
|
|
3
|
+
import { resolveBoundedIntegerOption } from "../shared/options.js";
|
|
4
|
+
import { createHardenedProviderFetch } from "../shared/safe-fetch.js";
|
|
5
|
+
const DEFAULT_PROVIDER_NAME = "videohub-streaming";
|
|
6
|
+
const DEFAULT_BASE_URL = "https://plapi.cdnvideohub.com";
|
|
7
|
+
const DEFAULT_MAX_PLAYLIST_RESPONSE_BYTES = 2 * 1024 * 1024;
|
|
8
|
+
const DEFAULT_MAX_VIDEO_RESPONSE_BYTES = 256 * 1024;
|
|
9
|
+
const DEFAULT_PLAYLIST_ITEM_LIMIT = 1_000;
|
|
10
|
+
const DEFAULT_VIDEO_LOOKUP_LIMIT = 8;
|
|
11
|
+
const DEFAULT_VIDEO_LOOKUP_CONCURRENCY = 4;
|
|
12
|
+
const DEFAULT_VIDEO_LOOKUP_TIMEOUT_MS = 15_000;
|
|
13
|
+
const DEFAULT_LINK_TTL_MS = 5 * 60_000;
|
|
14
|
+
const DEFAULT_ADDRESS_ATTEMPT_TIMEOUT_MS = 3_500;
|
|
15
|
+
export function createVideoHubConfig(options) {
|
|
16
|
+
const name = normalizeProviderName(options.name ?? DEFAULT_PROVIDER_NAME);
|
|
17
|
+
return {
|
|
18
|
+
name,
|
|
19
|
+
baseUrl: normalizeBaseUrl(options.baseUrl ?? DEFAULT_BASE_URL),
|
|
20
|
+
fetch: options.fetch ??
|
|
21
|
+
createHardenedProviderFetch({
|
|
22
|
+
provider: name,
|
|
23
|
+
maxRedirects: 2,
|
|
24
|
+
addressAttemptTimeoutMs: DEFAULT_ADDRESS_ATTEMPT_TIMEOUT_MS,
|
|
25
|
+
}),
|
|
26
|
+
rateLimitGate: new ProviderRateLimitGate(),
|
|
27
|
+
maxPlaylistResponseBytes: resolveBoundedIntegerOption(options.maxPlaylistResponseBytes, DEFAULT_MAX_PLAYLIST_RESPONSE_BYTES, "VideoHUB streaming maxPlaylistResponseBytes", 1_024, 16 * 1024 * 1024),
|
|
28
|
+
maxVideoResponseBytes: resolveBoundedIntegerOption(options.maxVideoResponseBytes, DEFAULT_MAX_VIDEO_RESPONSE_BYTES, "VideoHUB streaming maxVideoResponseBytes", 1_024, 4 * 1024 * 1024),
|
|
29
|
+
playlistItemLimit: resolveBoundedIntegerOption(options.playlistItemLimit, DEFAULT_PLAYLIST_ITEM_LIMIT, "VideoHUB streaming playlistItemLimit", 1, 5_000),
|
|
30
|
+
videoLookupLimit: resolveBoundedIntegerOption(options.videoLookupLimit, DEFAULT_VIDEO_LOOKUP_LIMIT, "VideoHUB streaming videoLookupLimit", 1, 32),
|
|
31
|
+
videoLookupConcurrency: resolveBoundedIntegerOption(options.videoLookupConcurrency, DEFAULT_VIDEO_LOOKUP_CONCURRENCY, "VideoHUB streaming videoLookupConcurrency", 1, 8),
|
|
32
|
+
videoLookupTimeoutMs: resolveBoundedIntegerOption(options.videoLookupTimeoutMs, DEFAULT_VIDEO_LOOKUP_TIMEOUT_MS, "VideoHUB streaming videoLookupTimeoutMs", 500, 15_000),
|
|
33
|
+
linkTtlMs: resolveBoundedIntegerOption(options.linkTtlMs, DEFAULT_LINK_TTL_MS, "VideoHUB streaming linkTtlMs", 30_000, 60 * 60_000),
|
|
34
|
+
userAgent: options.userAgent?.trim() || MEDIA_ENGINE_DEFAULT_USER_AGENT,
|
|
35
|
+
now: options.now ?? Date.now,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export function createVideoHubCapabilities() {
|
|
39
|
+
return {
|
|
40
|
+
mediaTypes: ["movie", "series", "anime"],
|
|
41
|
+
lookup: {
|
|
42
|
+
byTitle: false,
|
|
43
|
+
byExternalIds: ["kinopoisk"],
|
|
44
|
+
byEpisode: true,
|
|
45
|
+
},
|
|
46
|
+
features: ["mp4", "translations", "qualities", "episode_mapping", "headers"],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function normalizeProviderName(value) {
|
|
50
|
+
const name = value.trim();
|
|
51
|
+
if (!name)
|
|
52
|
+
throw new TypeError("VideoHUB streaming provider name is required.");
|
|
53
|
+
return name;
|
|
54
|
+
}
|
|
55
|
+
function normalizeBaseUrl(value) {
|
|
56
|
+
let url;
|
|
57
|
+
try {
|
|
58
|
+
url = new URL(value.trim());
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw new TypeError("VideoHUB streaming baseUrl must be a valid HTTPS URL.", {
|
|
62
|
+
cause: error,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (url.protocol !== "https:" || url.username !== "" || url.password !== "") {
|
|
66
|
+
throw new TypeError("VideoHUB streaming baseUrl must be a credential-free HTTPS URL.");
|
|
67
|
+
}
|
|
68
|
+
url.pathname = "/";
|
|
69
|
+
url.search = "";
|
|
70
|
+
url.hash = "";
|
|
71
|
+
return url.href.replace(/\/$/u, "");
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/videohub-streaming/config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,+BAA+B,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAsB,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAEtE,MAAM,qBAAqB,GAAG,oBAAoB,CAAC;AACnD,MAAM,gBAAgB,GAAG,+BAA+B,CAAC;AACzD,MAAM,mCAAmC,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAC5D,MAAM,gCAAgC,GAAG,GAAG,GAAG,IAAI,CAAC;AACpD,MAAM,2BAA2B,GAAG,KAAK,CAAC;AAC1C,MAAM,0BAA0B,GAAG,CAAC,CAAC;AACrC,MAAM,gCAAgC,GAAG,CAAC,CAAC;AAC3C,MAAM,+BAA+B,GAAG,MAAM,CAAC;AAC/C,MAAM,mBAAmB,GAAG,CAAC,GAAG,MAAM,CAAC;AACvC,MAAM,kCAAkC,GAAG,KAAK,CAAC;AAkCjD,MAAM,UAAU,oBAAoB,CAClC,OAAyC;IAEzC,MAAM,IAAI,GAAG,qBAAqB,CAAC,OAAO,CAAC,IAAI,IAAI,qBAAqB,CAAC,CAAC;IAE1E,OAAO;QACL,IAAI;QACJ,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC;QAC9D,KAAK,EACH,OAAO,CAAC,KAAK;YACb,2BAA2B,CAAC;gBAC1B,QAAQ,EAAE,IAAI;gBACd,YAAY,EAAE,CAAC;gBACf,uBAAuB,EAAE,kCAAkC;aAC5D,CAAC;QACJ,aAAa,EAAE,IAAI,qBAAqB,EAAE;QAC1C,wBAAwB,EAAE,2BAA2B,CACnD,OAAO,CAAC,wBAAwB,EAChC,mCAAmC,EACnC,6CAA6C,EAC7C,KAAK,EACL,EAAE,GAAG,IAAI,GAAG,IAAI,CACjB;QACD,qBAAqB,EAAE,2BAA2B,CAChD,OAAO,CAAC,qBAAqB,EAC7B,gCAAgC,EAChC,0CAA0C,EAC1C,KAAK,EACL,CAAC,GAAG,IAAI,GAAG,IAAI,CAChB;QACD,iBAAiB,EAAE,2BAA2B,CAC5C,OAAO,CAAC,iBAAiB,EACzB,2BAA2B,EAC3B,sCAAsC,EACtC,CAAC,EACD,KAAK,CACN;QACD,gBAAgB,EAAE,2BAA2B,CAC3C,OAAO,CAAC,gBAAgB,EACxB,0BAA0B,EAC1B,qCAAqC,EACrC,CAAC,EACD,EAAE,CACH;QACD,sBAAsB,EAAE,2BAA2B,CACjD,OAAO,CAAC,sBAAsB,EAC9B,gCAAgC,EAChC,2CAA2C,EAC3C,CAAC,EACD,CAAC,CACF;QACD,oBAAoB,EAAE,2BAA2B,CAC/C,OAAO,CAAC,oBAAoB,EAC5B,+BAA+B,EAC/B,yCAAyC,EACzC,GAAG,EACH,MAAM,CACP;QACD,SAAS,EAAE,2BAA2B,CACpC,OAAO,CAAC,SAAS,EACjB,mBAAmB,EACnB,8BAA8B,EAC9B,MAAM,EACN,EAAE,GAAG,MAAM,CACZ;QACD,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,+BAA+B;QACvE,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG;KAC7B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO;QACL,UAAU,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC;QACxC,MAAM,EAAE;YACN,OAAO,EAAE,KAAK;YACd,aAAa,EAAE,CAAC,WAAW,CAAC;YAC5B,SAAS,EAAE,IAAI;SAChB;QACD,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,iBAAiB,EAAE,SAAS,CAAC;KAC7E,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAa;IAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC1B,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,SAAS,CAAC,+CAA+C,CAAC,CAAC;IAChF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAa;IACrC,IAAI,GAAQ,CAAC;IAEb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,SAAS,CAAC,uDAAuD,EAAE;YAC3E,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;IACL,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,EAAE,CAAC;QAC5E,MAAM,IAAI,SAAS,CAAC,iEAAiE,CAAC,CAAC;IACzF,CAAC;IAED,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC;IACnB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;IAChB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;IACd,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { StreamingProvider } from "@media-engine/core";
|
|
2
|
+
import { type VideoHubStreamingProviderOptions } from "./config.js";
|
|
3
|
+
export type { VideoHubStreamingProviderOptions } from "./config.js";
|
|
4
|
+
export declare function videoHubStreamingProvider(options?: VideoHubStreamingProviderOptions): StreamingProvider;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { rethrowIfProviderAborted } from "../shared/abort.js";
|
|
2
|
+
import { loadVideoHubPlaylist, resolveVideoHubItems, resolveVideoHubKinopoiskId, } from "./client.js";
|
|
3
|
+
import { createVideoHubCapabilities, createVideoHubConfig, } from "./config.js";
|
|
4
|
+
import { mapVideoHubAvailability } from "./mapping.js";
|
|
5
|
+
export function videoHubStreamingProvider(options = {}) {
|
|
6
|
+
const config = createVideoHubConfig(options);
|
|
7
|
+
return {
|
|
8
|
+
name: config.name,
|
|
9
|
+
version: options.version,
|
|
10
|
+
kind: "streaming",
|
|
11
|
+
capabilities: createVideoHubCapabilities(),
|
|
12
|
+
availabilityDependsOnPlaybackUserAgent: true,
|
|
13
|
+
async getAvailability(query, context) {
|
|
14
|
+
if (query.providers && !query.providers.includes(config.name))
|
|
15
|
+
return null;
|
|
16
|
+
if (!canResolveQuery(query))
|
|
17
|
+
return null;
|
|
18
|
+
const kinopoiskId = resolveVideoHubKinopoiskId(query);
|
|
19
|
+
if (!kinopoiskId)
|
|
20
|
+
return null;
|
|
21
|
+
const playbackUserAgent = resolvePlaybackUserAgent(context, config.userAgent);
|
|
22
|
+
try {
|
|
23
|
+
const { playlist, sourceUrl } = await loadVideoHubPlaylist(config, kinopoiskId, context, playbackUserAgent);
|
|
24
|
+
if ((query.type !== "movie") !== playlist.isSerial)
|
|
25
|
+
return null;
|
|
26
|
+
const items = await resolveVideoHubItems(config, playlist, query, context, playbackUserAgent);
|
|
27
|
+
return mapVideoHubAvailability(config.name, kinopoiskId, playlist.title, items, query, sourceUrl, config.now(), config.linkTtlMs, playbackUserAgent);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
rethrowIfProviderAborted(context, error);
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function resolvePlaybackUserAgent(context, fallback) {
|
|
37
|
+
const value = context.playbackUserAgent?.trim();
|
|
38
|
+
return value && value.length <= 512 && !/[\u0000-\u001f\u007f]/u.test(value) ? value : fallback;
|
|
39
|
+
}
|
|
40
|
+
function canResolveQuery(query) {
|
|
41
|
+
if (query.type === "movie") {
|
|
42
|
+
return (query.seasonNumber === undefined &&
|
|
43
|
+
query.episodeNumber === undefined &&
|
|
44
|
+
query.absoluteEpisodeNumber === undefined);
|
|
45
|
+
}
|
|
46
|
+
const hasSeason = isPositiveInteger(query.seasonNumber);
|
|
47
|
+
const hasEpisode = isPositiveInteger(query.episodeNumber);
|
|
48
|
+
const hasAbsoluteEpisode = isPositiveInteger(query.absoluteEpisodeNumber);
|
|
49
|
+
if (query.type === "series") {
|
|
50
|
+
return hasSeason && hasEpisode && query.absoluteEpisodeNumber === undefined;
|
|
51
|
+
}
|
|
52
|
+
if (query.type !== "anime" || hasSeason !== hasEpisode)
|
|
53
|
+
return false;
|
|
54
|
+
return hasAbsoluteEpisode || (hasSeason && hasEpisode);
|
|
55
|
+
}
|
|
56
|
+
function isPositiveInteger(value) {
|
|
57
|
+
return Number.isInteger(value) && (value ?? 0) > 0;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/videohub-streaming/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { MediaAvailability } from "@media-engine/core";
|
|
2
|
+
import type { ResolvedVideoHubItem } from "./client.js";
|
|
3
|
+
export declare function mapVideoHubAvailability(provider: string, kinopoiskId: string, playlistTitle: string | undefined, items: ResolvedVideoHubItem[], query: MediaAvailability["query"], sourceUrl: string, now: number, linkTtlMs: number, playbackUserAgent: string): MediaAvailability | null;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
export function mapVideoHubAvailability(provider, kinopoiskId, playlistTitle, items, query, sourceUrl, now, linkTtlMs, playbackUserAgent) {
|
|
2
|
+
const expiresAt = new Date(now + linkTtlMs).toISOString();
|
|
3
|
+
const options = uniqueOptions(items.flatMap((item) => item.sources.map((source) => createOption(provider, kinopoiskId, item, source, query, expiresAt, playbackUserAgent))));
|
|
4
|
+
if (options.length === 0)
|
|
5
|
+
return null;
|
|
6
|
+
const episode = items[0] ? createEpisodeRef(items[0], query) : undefined;
|
|
7
|
+
const episodes = episode
|
|
8
|
+
? [
|
|
9
|
+
{
|
|
10
|
+
...episode,
|
|
11
|
+
options,
|
|
12
|
+
},
|
|
13
|
+
]
|
|
14
|
+
: undefined;
|
|
15
|
+
const ids = { ...query.ids, kinopoisk: kinopoiskId };
|
|
16
|
+
return {
|
|
17
|
+
query,
|
|
18
|
+
item: {
|
|
19
|
+
type: query.type,
|
|
20
|
+
title: playlistTitle ?? query.title,
|
|
21
|
+
year: query.year,
|
|
22
|
+
ids,
|
|
23
|
+
},
|
|
24
|
+
...(episodes ? { episodes } : {}),
|
|
25
|
+
options,
|
|
26
|
+
sourceProviders: [{ provider, url: sourceUrl, ids }],
|
|
27
|
+
checkedAt: new Date(now).toISOString(),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function createOption(provider, kinopoiskId, item, source, query, expiresAt, playbackUserAgent) {
|
|
31
|
+
const episode = createEpisodeRef(item, query);
|
|
32
|
+
const translation = createTranslation(item.voiceStudio, item.voiceType);
|
|
33
|
+
const episodeKey = createEpisodeKey(episode, query.type);
|
|
34
|
+
return {
|
|
35
|
+
id: `${provider}:${kinopoiskId}${episodeKey}:${item.vkId}:${source.label}`,
|
|
36
|
+
provider,
|
|
37
|
+
player: {
|
|
38
|
+
kind: "mp4",
|
|
39
|
+
label: "VideoHUB",
|
|
40
|
+
providerPlayerId: `${item.vkId}${episodeKey}`,
|
|
41
|
+
},
|
|
42
|
+
translation,
|
|
43
|
+
quality: {
|
|
44
|
+
label: source.label,
|
|
45
|
+
...(source.height !== undefined ? { height: source.height } : {}),
|
|
46
|
+
},
|
|
47
|
+
...(episode ? { episode } : {}),
|
|
48
|
+
access: { url: source.url, headers: { "User-Agent": playbackUserAgent } },
|
|
49
|
+
availability: "available",
|
|
50
|
+
expiresAt,
|
|
51
|
+
sourceUrl: item.sourceUrl,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function createEpisodeRef(item, query) {
|
|
55
|
+
if (query.type === "movie")
|
|
56
|
+
return undefined;
|
|
57
|
+
return {
|
|
58
|
+
...(item.seasonNumber !== undefined ? { seasonNumber: item.seasonNumber } : {}),
|
|
59
|
+
...(item.episodeNumber !== undefined ? { episodeNumber: item.episodeNumber } : {}),
|
|
60
|
+
...(query.type === "anime" && item.absoluteEpisodeNumber !== undefined
|
|
61
|
+
? { absoluteEpisodeNumber: item.absoluteEpisodeNumber }
|
|
62
|
+
: {}),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function createEpisodeKey(episode, type) {
|
|
66
|
+
if (!episode)
|
|
67
|
+
return "";
|
|
68
|
+
if (type === "series")
|
|
69
|
+
return `:${episode.seasonNumber}:${episode.episodeNumber}`;
|
|
70
|
+
return `:a:${episode.absoluteEpisodeNumber}:s:${episode.seasonNumber}:e:${episode.episodeNumber}`;
|
|
71
|
+
}
|
|
72
|
+
function createTranslation(voiceStudio, voiceType) {
|
|
73
|
+
const title = voiceStudio || voiceType || "VideoHUB";
|
|
74
|
+
const normalizedType = (voiceType ?? title).toLocaleLowerCase();
|
|
75
|
+
const type = normalizedType.includes("субтит")
|
|
76
|
+
? "subtitles"
|
|
77
|
+
: normalizedType.includes("дубляж")
|
|
78
|
+
? "dub"
|
|
79
|
+
: normalizedType.includes("голос")
|
|
80
|
+
? "voiceover"
|
|
81
|
+
: normalizedType.includes("оригинал")
|
|
82
|
+
? "original"
|
|
83
|
+
: "unknown";
|
|
84
|
+
return {
|
|
85
|
+
title,
|
|
86
|
+
type,
|
|
87
|
+
...(voiceStudio ? { team: voiceStudio } : {}),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function uniqueOptions(options) {
|
|
91
|
+
const seen = new Set();
|
|
92
|
+
return options.filter((option) => {
|
|
93
|
+
const key = `${option.translation?.title ?? ""}\u0000${option.quality?.label ?? ""}\u0000${option.access.url}`;
|
|
94
|
+
if (seen.has(key))
|
|
95
|
+
return false;
|
|
96
|
+
seen.add(key);
|
|
97
|
+
return true;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=mapping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapping.js","sourceRoot":"","sources":["../../src/videohub-streaming/mapping.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,uBAAuB,CACrC,QAAgB,EAChB,WAAmB,EACnB,aAAiC,EACjC,KAA6B,EAC7B,KAAiC,EACjC,SAAiB,EACjB,GAAW,EACX,SAAiB,EACjB,iBAAyB;IAEzB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;IAC1D,MAAM,OAAO,GAAG,aAAa,CAC3B,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CACrB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAC1B,YAAY,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,iBAAiB,CAAC,CACvF,CACF,CACF,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACzE,MAAM,QAAQ,GAA4C,OAAO;QAC/D,CAAC,CAAC;YACE;gBACE,GAAG,OAAO;gBACV,OAAO;aACR;SACF;QACH,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,GAAG,GAAG,EAAE,GAAG,KAAK,CAAC,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;IAErD,OAAO;QACL,KAAK;QACL,IAAI,EAAE;YACJ,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,aAAa,IAAI,KAAK,CAAC,KAAK;YACnC,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,GAAG;SACJ;QACD,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjC,OAAO;QACP,eAAe,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;QACpD,SAAS,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE;KACvC,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CACnB,QAAgB,EAChB,WAAmB,EACnB,IAA0B,EAC1B,MAAyB,EACzB,KAAiC,EACjC,SAAiB,EACjB,iBAAyB;IAEzB,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,iBAAiB,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACxE,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAEzD,OAAO;QACL,EAAE,EAAE,GAAG,QAAQ,IAAI,WAAW,GAAG,UAAU,IAAI,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE;QAC1E,QAAQ;QACR,MAAM,EAAE;YACN,IAAI,EAAE,KAAK;YACX,KAAK,EAAE,UAAU;YACjB,gBAAgB,EAAE,GAAG,IAAI,CAAC,IAAI,GAAG,UAAU,EAAE;SAC9C;QACD,WAAW;QACX,OAAO,EAAE;YACP,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClE;QACD,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/B,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,iBAAiB,EAAE,EAAE;QACzE,YAAY,EAAE,WAAW;QACzB,SAAS;QACT,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CACvB,IAA0B,EAC1B,KAAiC;IAEjC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC;IAE7C,OAAO;QACL,GAAG,CAAC,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/E,GAAG,CAAC,IAAI,CAAC,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClF,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,qBAAqB,KAAK,SAAS;YACpE,CAAC,CAAC,EAAE,qBAAqB,EAAE,IAAI,CAAC,qBAAqB,EAAE;YACvD,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CACvB,OAAgC,EAChC,IAAwC;IAExC,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IACxB,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAClF,OAAO,MAAM,OAAO,CAAC,qBAAqB,MAAM,OAAO,CAAC,YAAY,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC;AACpG,CAAC;AAED,SAAS,iBAAiB,CAAC,WAAoB,EAAE,SAAkB;IACjE,MAAM,KAAK,GAAG,WAAW,IAAI,SAAS,IAAI,UAAU,CAAC;IACrD,MAAM,cAAc,GAAG,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC,iBAAiB,EAAE,CAAC;IAChE,MAAM,IAAI,GAA4B,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACrE,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACjC,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAChC,CAAC,CAAC,WAAW;gBACb,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,UAAU,CAAC;oBACnC,CAAC,CAAC,UAAU;oBACZ,CAAC,CAAC,SAAS,CAAC;IAEpB,OAAO;QACL,KAAK;QACL,IAAI;QACJ,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9C,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,OAAuB;IAC5C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE;QAC/B,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE,SAAS,MAAM,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,SAAS,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;QAC/G,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QAChC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@media-engine/providers",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Provider implementations for Media Engine.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/Yaneart/media-engine#readme",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"anime",
|
|
21
21
|
"aniliberty",
|
|
22
22
|
"ddbb",
|
|
23
|
+
"filmix",
|
|
23
24
|
"hls",
|
|
24
25
|
"kinobd",
|
|
25
26
|
"cinemeta",
|
|
@@ -30,8 +31,12 @@
|
|
|
30
31
|
"anilist",
|
|
31
32
|
"bitsearch",
|
|
32
33
|
"tvmaze",
|
|
34
|
+
"veoveo",
|
|
35
|
+
"videohub",
|
|
33
36
|
"wikidata",
|
|
34
37
|
"no-token",
|
|
38
|
+
"mp4",
|
|
39
|
+
"rutube",
|
|
35
40
|
"torrent",
|
|
36
41
|
"yts"
|
|
37
42
|
],
|
|
@@ -65,7 +70,7 @@
|
|
|
65
70
|
"access": "public"
|
|
66
71
|
},
|
|
67
72
|
"dependencies": {
|
|
68
|
-
"@media-engine/core": "1.
|
|
73
|
+
"@media-engine/core": "1.2.0"
|
|
69
74
|
},
|
|
70
75
|
"scripts": {
|
|
71
76
|
"clean": "node ../../scripts/clean-package-dist.mjs",
|