@media-engine/providers 0.1.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +132 -3
- package/README.ru.md +134 -3
- package/dist/aniliberty-streaming/client.d.ts +33 -0
- package/dist/aniliberty-streaming/client.js +188 -0
- package/dist/aniliberty-streaming/client.js.map +1 -0
- package/dist/aniliberty-streaming/config.d.ts +24 -0
- package/dist/aniliberty-streaming/config.js +61 -0
- package/dist/aniliberty-streaming/config.js.map +1 -0
- package/dist/aniliberty-streaming/index.d.ts +4 -0
- package/dist/aniliberty-streaming/index.js +45 -0
- package/dist/aniliberty-streaming/index.js.map +1 -0
- package/dist/aniliberty-streaming/mapping.d.ts +3 -0
- package/dist/aniliberty-streaming/mapping.js +87 -0
- package/dist/aniliberty-streaming/mapping.js.map +1 -0
- package/dist/aniliberty-streaming/matching.d.ts +4 -0
- package/dist/aniliberty-streaming/matching.js +44 -0
- package/dist/aniliberty-streaming/matching.js.map +1 -0
- package/dist/anilist/graphql.d.ts +2 -0
- package/dist/anilist/graphql.js +135 -0
- package/dist/anilist/graphql.js.map +1 -0
- package/dist/anilist/index.js +8 -6
- package/dist/anilist/index.js.map +1 -1
- package/dist/bitsearch-torrent/client.d.ts +19 -0
- package/dist/bitsearch-torrent/client.js +181 -0
- package/dist/bitsearch-torrent/client.js.map +1 -0
- package/dist/bitsearch-torrent/config.d.ts +26 -0
- package/dist/bitsearch-torrent/config.js +74 -0
- package/dist/bitsearch-torrent/config.js.map +1 -0
- package/dist/bitsearch-torrent/index.d.ts +4 -0
- package/dist/bitsearch-torrent/index.js +35 -0
- package/dist/bitsearch-torrent/index.js.map +1 -0
- package/dist/bitsearch-torrent/mapping.d.ts +3 -0
- package/dist/bitsearch-torrent/mapping.js +53 -0
- package/dist/bitsearch-torrent/mapping.js.map +1 -0
- package/dist/bitsearch-torrent/matching.d.ts +3 -0
- package/dist/bitsearch-torrent/matching.js +13 -0
- package/dist/bitsearch-torrent/matching.js.map +1 -0
- package/dist/bitsearch-torrent/quota.d.ts +9 -0
- package/dist/bitsearch-torrent/quota.js +53 -0
- package/dist/bitsearch-torrent/quota.js.map +1 -0
- package/dist/cinemeta/index.js +37 -12
- package/dist/cinemeta/index.js.map +1 -1
- package/dist/ddbb-streaming/client.d.ts +24 -0
- package/dist/ddbb-streaming/client.js +98 -0
- package/dist/ddbb-streaming/client.js.map +1 -0
- package/dist/ddbb-streaming/config.d.ts +31 -0
- package/dist/ddbb-streaming/config.js +67 -0
- package/dist/ddbb-streaming/config.js.map +1 -0
- package/dist/ddbb-streaming/index.d.ts +4 -0
- package/dist/ddbb-streaming/index.js +53 -0
- package/dist/ddbb-streaming/index.js.map +1 -0
- package/dist/ddbb-streaming/mapping.d.ts +8 -0
- package/dist/ddbb-streaming/mapping.js +164 -0
- package/dist/ddbb-streaming/mapping.js.map +1 -0
- package/dist/ddbb-streaming/validation.d.ts +3 -0
- package/dist/ddbb-streaming/validation.js +84 -0
- package/dist/ddbb-streaming/validation.js.map +1 -0
- package/dist/experimental-streaming/index.js +55 -0
- package/dist/experimental-streaming/index.js.map +1 -1
- package/dist/flixhq-streaming/client.d.ts +12 -0
- package/dist/flixhq-streaming/client.js +103 -0
- package/dist/flixhq-streaming/client.js.map +1 -0
- package/dist/flixhq-streaming/index.d.ts +2 -2
- package/dist/flixhq-streaming/index.js +58 -104
- package/dist/flixhq-streaming/index.js.map +1 -1
- package/dist/imdb-dataset/index.d.ts +20 -5
- package/dist/imdb-dataset/index.js +82 -184
- package/dist/imdb-dataset/index.js.map +1 -1
- package/dist/imdb-dataset/memory-storage.d.ts +7 -0
- package/dist/imdb-dataset/memory-storage.js +168 -0
- package/dist/imdb-dataset/memory-storage.js.map +1 -0
- package/dist/imdb-dataset/sqlite-import.d.ts +24 -0
- package/dist/imdb-dataset/sqlite-import.js +298 -0
- package/dist/imdb-dataset/sqlite-import.js.map +1 -0
- package/dist/imdb-dataset/sqlite-runtime.d.ts +3 -0
- package/dist/imdb-dataset/sqlite-runtime.js +11 -0
- package/dist/imdb-dataset/sqlite-runtime.js.map +1 -0
- package/dist/imdb-dataset/sqlite-schema.d.ts +6 -0
- package/dist/imdb-dataset/sqlite-schema.js +88 -0
- package/dist/imdb-dataset/sqlite-schema.js.map +1 -0
- package/dist/imdb-dataset/sqlite-storage.d.ts +12 -0
- package/dist/imdb-dataset/sqlite-storage.js +208 -0
- package/dist/imdb-dataset/sqlite-storage.js.map +1 -0
- package/dist/imdb-dataset/storage.d.ts +33 -0
- package/dist/imdb-dataset/storage.js +2 -0
- package/dist/imdb-dataset/storage.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/jacred-torrent/client.d.ts +24 -0
- package/dist/jacred-torrent/client.js +254 -0
- package/dist/jacred-torrent/client.js.map +1 -0
- package/dist/jacred-torrent/config.d.ts +24 -0
- package/dist/jacred-torrent/config.js +70 -0
- package/dist/jacred-torrent/config.js.map +1 -0
- package/dist/jacred-torrent/index.d.ts +4 -0
- package/dist/jacred-torrent/index.js +45 -0
- package/dist/jacred-torrent/index.js.map +1 -0
- package/dist/jacred-torrent/mapping.d.ts +3 -0
- package/dist/jacred-torrent/mapping.js +129 -0
- package/dist/jacred-torrent/mapping.js.map +1 -0
- package/dist/jacred-torrent/matching.d.ts +3 -0
- package/dist/jacred-torrent/matching.js +19 -0
- package/dist/jacred-torrent/matching.js.map +1 -0
- package/dist/kinobd/index.js +5 -6
- package/dist/kinobd/index.js.map +1 -1
- package/dist/kinobd-streaming/availability.js +52 -29
- package/dist/kinobd-streaming/availability.js.map +1 -1
- package/dist/kinobd-streaming/candidates.d.ts +3 -2
- package/dist/kinobd-streaming/candidates.js +89 -37
- package/dist/kinobd-streaming/candidates.js.map +1 -1
- package/dist/kinobd-streaming/config.d.ts +15 -0
- package/dist/kinobd-streaming/config.js +21 -17
- package/dist/kinobd-streaming/config.js.map +1 -1
- package/dist/kinobd-streaming/index.d.ts +1 -1
- package/dist/kinobd-streaming/index.js.map +1 -1
- package/dist/kinobd-streaming/players.d.ts +2 -1
- package/dist/kinobd-streaming/players.js +7 -7
- package/dist/kinobd-streaming/players.js.map +1 -1
- package/dist/kinobd-streaming/request-budget.d.ts +15 -0
- package/dist/kinobd-streaming/request-budget.js +61 -0
- package/dist/kinobd-streaming/request-budget.js.map +1 -0
- package/dist/kinobd-streaming/validation.d.ts +5 -3
- package/dist/kinobd-streaming/validation.js +78 -49
- package/dist/kinobd-streaming/validation.js.map +1 -1
- package/dist/magnetz-torrent/client.d.ts +16 -0
- package/dist/magnetz-torrent/client.js +235 -0
- package/dist/magnetz-torrent/client.js.map +1 -0
- package/dist/magnetz-torrent/config.d.ts +27 -0
- package/dist/magnetz-torrent/config.js +73 -0
- package/dist/magnetz-torrent/config.js.map +1 -0
- package/dist/magnetz-torrent/index.d.ts +4 -0
- package/dist/magnetz-torrent/index.js +35 -0
- package/dist/magnetz-torrent/index.js.map +1 -0
- package/dist/magnetz-torrent/mapping.d.ts +3 -0
- package/dist/magnetz-torrent/mapping.js +52 -0
- package/dist/magnetz-torrent/mapping.js.map +1 -0
- package/dist/magnetz-torrent/matching.d.ts +3 -0
- package/dist/magnetz-torrent/matching.js +5 -0
- package/dist/magnetz-torrent/matching.js.map +1 -0
- package/dist/magnetz-torrent/request-gate.d.ts +9 -0
- package/dist/magnetz-torrent/request-gate.js +48 -0
- package/dist/magnetz-torrent/request-gate.js.map +1 -0
- package/dist/package-version.d.ts +2 -0
- package/dist/package-version.js +5 -0
- package/dist/package-version.js.map +1 -0
- package/dist/shared/abort.d.ts +1 -0
- package/dist/shared/abort.js +22 -0
- package/dist/shared/abort.js.map +1 -1
- package/dist/shared/http.d.ts +8 -2
- package/dist/shared/http.js +37 -67
- package/dist/shared/http.js.map +1 -1
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/mapping.js +3 -1
- package/dist/shared/mapping.js.map +1 -1
- package/dist/shared/output-url.d.ts +2 -0
- package/dist/shared/output-url.js +50 -0
- package/dist/shared/output-url.js.map +1 -0
- package/dist/shared/rate-limit.js +2 -18
- package/dist/shared/rate-limit.js.map +1 -1
- package/dist/shared/response-body.d.ts +6 -0
- package/dist/shared/response-body.js +109 -0
- package/dist/shared/response-body.js.map +1 -0
- package/dist/shared/safe-fetch.d.ts +14 -0
- package/dist/shared/safe-fetch.js +274 -0
- package/dist/shared/safe-fetch.js.map +1 -0
- package/dist/shared/torrent-release-matching.d.ts +7 -0
- package/dist/shared/torrent-release-matching.js +143 -0
- package/dist/shared/torrent-release-matching.js.map +1 -0
- package/dist/shared/torrent-release-metadata.d.ts +4 -0
- package/dist/shared/torrent-release-metadata.js +95 -0
- package/dist/shared/torrent-release-metadata.js.map +1 -0
- package/dist/shikimori/index.js +4 -7
- package/dist/shikimori/index.js.map +1 -1
- package/dist/tvmaze/index.d.ts +11 -0
- package/dist/tvmaze/index.js +274 -0
- package/dist/tvmaze/index.js.map +1 -0
- package/dist/wikidata/cache.d.ts +11 -0
- package/dist/wikidata/cache.js +30 -0
- package/dist/wikidata/cache.js.map +1 -0
- package/dist/wikidata/candidates.d.ts +12 -0
- package/dist/wikidata/candidates.js +67 -0
- package/dist/wikidata/candidates.js.map +1 -0
- package/dist/wikidata/client.d.ts +40 -0
- package/dist/wikidata/client.js +224 -0
- package/dist/wikidata/client.js.map +1 -0
- package/dist/wikidata/index.d.ts +3 -0
- package/dist/wikidata/index.js +30 -104
- package/dist/wikidata/index.js.map +1 -1
- package/dist/yts-torrent/client.d.ts +25 -0
- package/dist/yts-torrent/client.js +163 -0
- package/dist/yts-torrent/client.js.map +1 -0
- package/dist/yts-torrent/config.d.ts +22 -0
- package/dist/yts-torrent/config.js +57 -0
- package/dist/yts-torrent/config.js.map +1 -0
- package/dist/yts-torrent/index.d.ts +4 -0
- package/dist/yts-torrent/index.js +42 -0
- package/dist/yts-torrent/index.js.map +1 -0
- package/dist/yts-torrent/mapping.d.ts +4 -0
- package/dist/yts-torrent/mapping.js +107 -0
- package/dist/yts-torrent/mapping.js.map +1 -0
- package/package.json +18 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/ddbb-streaming/validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizeProviderOutputUrl } from "../shared/index.js";
|
|
1
2
|
const DEFAULT_PROVIDER_NAME = "experimental-streaming";
|
|
2
3
|
const EXTERNAL_ID_SOURCES = [
|
|
3
4
|
"imdb",
|
|
@@ -38,9 +39,63 @@ function normalizeProviderName(name) {
|
|
|
38
39
|
function normalizeEntry(entry) {
|
|
39
40
|
return {
|
|
40
41
|
...entry,
|
|
42
|
+
sourceUrl: normalizeProviderOutputUrl(entry.sourceUrl),
|
|
43
|
+
options: entry.options?.flatMap((option) => {
|
|
44
|
+
const normalized = normalizeConfiguredOption(option);
|
|
45
|
+
return normalized ? [normalized] : [];
|
|
46
|
+
}),
|
|
47
|
+
episodes: entry.episodes?.map((episode) => ({
|
|
48
|
+
...episode,
|
|
49
|
+
options: episode.options.flatMap((option) => {
|
|
50
|
+
const normalized = normalizeConfiguredOption(option);
|
|
51
|
+
return normalized ? [normalized] : [];
|
|
52
|
+
}),
|
|
53
|
+
})),
|
|
41
54
|
titleKey: entry.title ? normalizeTitle(entry.title) : undefined,
|
|
42
55
|
};
|
|
43
56
|
}
|
|
57
|
+
// Removes unsafe browser-facing URLs from one configured player option.
|
|
58
|
+
// Удаляет небезопасные browser-facing URL из настроенного player-варианта.
|
|
59
|
+
function normalizeConfiguredOption(option) {
|
|
60
|
+
const accessUrl = normalizeProviderOutputUrl(option.access.url);
|
|
61
|
+
if (!accessUrl) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
const referer = normalizeProviderOutputUrl(option.access.referer);
|
|
65
|
+
const sourceUrl = normalizeProviderOutputUrl(option.sourceUrl);
|
|
66
|
+
const subtitles = option.subtitles?.map((track) => ({
|
|
67
|
+
...track,
|
|
68
|
+
url: track.url ? normalizeProviderOutputUrl(track.url) : undefined,
|
|
69
|
+
}));
|
|
70
|
+
return {
|
|
71
|
+
...option,
|
|
72
|
+
access: {
|
|
73
|
+
...option.access,
|
|
74
|
+
url: accessUrl,
|
|
75
|
+
referer,
|
|
76
|
+
headers: normalizeUrlHeaders(option.access.headers),
|
|
77
|
+
},
|
|
78
|
+
sourceUrl,
|
|
79
|
+
subtitles,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function normalizeUrlHeaders(headers) {
|
|
83
|
+
if (!headers) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
const normalized = {};
|
|
87
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
88
|
+
if (name.toLowerCase() === "referer" || name.toLowerCase() === "origin") {
|
|
89
|
+
const url = normalizeProviderOutputUrl(value);
|
|
90
|
+
if (url)
|
|
91
|
+
normalized[name] = url;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
normalized[name] = value;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return Object.keys(normalized).length > 0 ? normalized : undefined;
|
|
98
|
+
}
|
|
44
99
|
// Builds safe capabilities from configured entries.
|
|
45
100
|
// Собирает безопасные capabilities из настроенных записей.
|
|
46
101
|
function createCapabilities(entries) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/experimental-streaming/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/experimental-streaming/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ProviderContext } from "@media-engine/core";
|
|
2
|
+
import { type ProviderFetch, type ProviderRateLimitGate } from "../shared/index.js";
|
|
3
|
+
export interface FlixHqHttpConfig {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
name: string;
|
|
6
|
+
fetch?: ProviderFetch;
|
|
7
|
+
rateLimitGate: ProviderRateLimitGate;
|
|
8
|
+
maxHtmlBytes: number;
|
|
9
|
+
userAgent: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function fetchFlixHqText(config: FlixHqHttpConfig, initialUrl: URL, context: ProviderContext, init?: RequestInit): Promise<string>;
|
|
12
|
+
export declare function normalizeFlixHqNavigationUrl(value: string | null | undefined, baseUrl: string | undefined): string | undefined;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { ProviderError } from "@media-engine/core";
|
|
2
|
+
import { deferProviderRateLimitFromResponse, mapProviderHttpError, mapHttpResponseToProviderError, normalizePublicHttpUrl, } from "../shared/index.js";
|
|
3
|
+
import { readBoundedResponseText } from "../shared/response-body.js";
|
|
4
|
+
const MAX_NAVIGATION_REDIRECTS = 3;
|
|
5
|
+
const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
|
|
6
|
+
// Reads only configured-origin FlixHQ pages; redirects are manual and origin-checked per hop.
|
|
7
|
+
// Читает только страницы configured origin FlixHQ с ручной проверкой каждого redirect hop.
|
|
8
|
+
export async function fetchFlixHqText(config, initialUrl, context, init = {}) {
|
|
9
|
+
const fetchImpl = config.fetch ?? fetch;
|
|
10
|
+
let url = assertSameOrigin(config, initialUrl);
|
|
11
|
+
const visited = new Set();
|
|
12
|
+
try {
|
|
13
|
+
for (let redirects = 0;; redirects += 1) {
|
|
14
|
+
if (visited.has(url.href)) {
|
|
15
|
+
throw createNavigationError(config.name, "redirect loop");
|
|
16
|
+
}
|
|
17
|
+
visited.add(url.href);
|
|
18
|
+
await config.rateLimitGate.wait(context.signal);
|
|
19
|
+
const response = await fetchImpl(url, {
|
|
20
|
+
...init,
|
|
21
|
+
headers: {
|
|
22
|
+
...createHeaders(config),
|
|
23
|
+
...Object.fromEntries(new Headers(init.headers).entries()),
|
|
24
|
+
},
|
|
25
|
+
redirect: "manual",
|
|
26
|
+
signal: context.signal,
|
|
27
|
+
});
|
|
28
|
+
deferProviderRateLimitFromResponse(config.rateLimitGate, response);
|
|
29
|
+
const location = REDIRECT_STATUSES.has(response.status)
|
|
30
|
+
? response.headers.get("location")
|
|
31
|
+
: null;
|
|
32
|
+
if (location) {
|
|
33
|
+
await cancelResponse(response);
|
|
34
|
+
if (redirects >= MAX_NAVIGATION_REDIRECTS) {
|
|
35
|
+
throw createNavigationError(config.name, "redirect limit exceeded");
|
|
36
|
+
}
|
|
37
|
+
url = assertSameOrigin(config, new URL(location, url));
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
throw mapHttpResponseToProviderError(config.name, response);
|
|
42
|
+
}
|
|
43
|
+
return await readBoundedResponseText(config.name, response, config.maxHtmlBytes, {
|
|
44
|
+
signal: context.signal,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
throw mapProviderHttpError(config.name, error);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export function normalizeFlixHqNavigationUrl(value, baseUrl) {
|
|
53
|
+
if (!value) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
if (!baseUrl) {
|
|
58
|
+
return normalizePublicHttpUrl(value);
|
|
59
|
+
}
|
|
60
|
+
const url = baseUrl ? new URL(value, baseUrl) : new URL(value);
|
|
61
|
+
if ((url.protocol !== "http:" && url.protocol !== "https:") ||
|
|
62
|
+
url.username !== "" ||
|
|
63
|
+
url.password !== "" ||
|
|
64
|
+
(baseUrl && url.origin !== new URL(baseUrl).origin)) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
return url.href;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async function cancelResponse(response) {
|
|
74
|
+
try {
|
|
75
|
+
await response.body?.cancel();
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Redirect cleanup must not hide the navigation policy result.
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function assertSameOrigin(config, url) {
|
|
82
|
+
if (normalizeFlixHqNavigationUrl(url.href, config.baseUrl) !== url.href) {
|
|
83
|
+
throw createNavigationError(config.name, "cross-origin navigation");
|
|
84
|
+
}
|
|
85
|
+
return url;
|
|
86
|
+
}
|
|
87
|
+
function createHeaders(config) {
|
|
88
|
+
return {
|
|
89
|
+
Accept: "text/html,application/json;q=0.9,*/*;q=0.8",
|
|
90
|
+
"User-Agent": config.userAgent,
|
|
91
|
+
Referer: `${config.baseUrl}/`,
|
|
92
|
+
"X-Requested-With": "XMLHttpRequest",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function createNavigationError(provider, reason) {
|
|
96
|
+
return new ProviderError({
|
|
97
|
+
provider,
|
|
98
|
+
code: "PROVIDER_INVALID_RESPONSE",
|
|
99
|
+
message: `Provider "${provider}" returned unsafe FlixHQ navigation (${reason}).`,
|
|
100
|
+
retryable: false,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/flixhq-streaming/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,6 +25,6 @@ interface EpisodeCandidate extends StreamEpisodeRef {
|
|
|
25
25
|
}
|
|
26
26
|
export declare function flixHqStreamingProvider(options?: FlixHqStreamingProviderOptions): StreamingProvider;
|
|
27
27
|
export declare function parseSubtitleInfo(value: string): SubtitleTrack[];
|
|
28
|
-
export declare function parseSearchCandidates(html: string): SearchCandidate[];
|
|
29
|
-
export declare function parseEpisodes(html: string): EpisodeCandidate[];
|
|
28
|
+
export declare function parseSearchCandidates(html: string, baseUrl?: string): SearchCandidate[];
|
|
29
|
+
export declare function parseEpisodes(html: string, baseUrl?: string): EpisodeCandidate[];
|
|
30
30
|
export {};
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MEDIA_ENGINE_DEFAULT_USER_AGENT } from "../package-version.js";
|
|
2
|
+
import { mapProviderHttpError, normalizeProviderOutputUrl, ProviderRateLimitGate, } from "../shared/index.js";
|
|
2
3
|
import { rethrowIfProviderAborted } from "../shared/abort.js";
|
|
4
|
+
import { readBoundedResponseText } from "../shared/response-body.js";
|
|
5
|
+
import { createHardenedProviderFetch } from "../shared/safe-fetch.js";
|
|
6
|
+
import { fetchFlixHqText, normalizeFlixHqNavigationUrl } from "./client.js";
|
|
3
7
|
const DEFAULT_BASE_URL = "https://flixhq.one";
|
|
4
8
|
const DEFAULT_PROVIDER_NAME = "flixhq-streaming";
|
|
5
9
|
const DEFAULT_MAX_HTML_BYTES = 1024 * 1024;
|
|
@@ -22,6 +26,7 @@ export function flixHqStreamingProvider(options = {}) {
|
|
|
22
26
|
};
|
|
23
27
|
}
|
|
24
28
|
function createConfig(options) {
|
|
29
|
+
const name = normalizeProviderName(options.name ?? DEFAULT_PROVIDER_NAME);
|
|
25
30
|
const maxHtmlBytes = options.maxHtmlBytes ?? DEFAULT_MAX_HTML_BYTES;
|
|
26
31
|
const playerLimit = options.playerLimit ?? DEFAULT_PLAYER_LIMIT;
|
|
27
32
|
const playerValidationConcurrency = options.playerValidationConcurrency ?? DEFAULT_PLAYER_VALIDATION_CONCURRENCY;
|
|
@@ -48,8 +53,9 @@ function createConfig(options) {
|
|
|
48
53
|
}
|
|
49
54
|
return {
|
|
50
55
|
baseUrl: normalizeBaseUrl(options.baseUrl ?? DEFAULT_BASE_URL),
|
|
51
|
-
name
|
|
56
|
+
name,
|
|
52
57
|
fetch: options.fetch,
|
|
58
|
+
externalFetch: options.fetch ?? createHardenedProviderFetch({ provider: name }),
|
|
53
59
|
rateLimitGate: new ProviderRateLimitGate(),
|
|
54
60
|
maxHtmlBytes,
|
|
55
61
|
playerLimit,
|
|
@@ -57,7 +63,7 @@ function createConfig(options) {
|
|
|
57
63
|
playerValidationTimeoutMs,
|
|
58
64
|
playerValidationMaxBytes,
|
|
59
65
|
subtitleInfoMaxBytes,
|
|
60
|
-
userAgent: options.userAgent?.trim() ||
|
|
66
|
+
userAgent: options.userAgent?.trim() || MEDIA_ENGINE_DEFAULT_USER_AGENT,
|
|
61
67
|
};
|
|
62
68
|
}
|
|
63
69
|
function createCapabilities() {
|
|
@@ -93,21 +99,21 @@ async function getFlixHqAvailability(config, query, context) {
|
|
|
93
99
|
}
|
|
94
100
|
const searchUrl = new URL("/search", config.baseUrl);
|
|
95
101
|
searchUrl.searchParams.set("keyword", query.title.trim());
|
|
96
|
-
const searchHtml = await
|
|
97
|
-
const candidate = selectBestCandidate(parseSearchCandidates(searchHtml), query);
|
|
102
|
+
const searchHtml = await fetchFlixHqText(config, searchUrl, context);
|
|
103
|
+
const candidate = selectBestCandidate(parseSearchCandidates(searchHtml, config.baseUrl), query);
|
|
98
104
|
if (!candidate) {
|
|
99
105
|
return emptyAvailability(query);
|
|
100
106
|
}
|
|
101
|
-
const mediaHtml = await
|
|
107
|
+
const mediaHtml = await fetchFlixHqText(config, new URL(candidate.mediaUrl), context);
|
|
102
108
|
const episode = candidate.type === "movie"
|
|
103
109
|
? { url: candidate.mediaUrl, title: candidate.title }
|
|
104
|
-
: selectEpisode(parseEpisodes(mediaHtml), query.seasonNumber ?? 1, query.episodeNumber ?? 1);
|
|
110
|
+
: selectEpisode(parseEpisodes(mediaHtml, config.baseUrl), query.seasonNumber ?? 1, query.episodeNumber ?? 1);
|
|
105
111
|
if (!episode) {
|
|
106
112
|
return emptyAvailability(query);
|
|
107
113
|
}
|
|
108
114
|
const playerHtml = episode.url === candidate.mediaUrl
|
|
109
115
|
? mediaHtml
|
|
110
|
-
: await
|
|
116
|
+
: await fetchFlixHqText(config, new URL(episode.url), context);
|
|
111
117
|
const token = findPlayerToken(playerHtml, candidate.type);
|
|
112
118
|
if (!token) {
|
|
113
119
|
return emptyAvailability(query);
|
|
@@ -129,19 +135,29 @@ async function getFlixHqAvailability(config, query, context) {
|
|
|
129
135
|
},
|
|
130
136
|
options,
|
|
131
137
|
episodes: [{ ...episode, options }],
|
|
132
|
-
sourceProviders: [
|
|
138
|
+
sourceProviders: [
|
|
139
|
+
{
|
|
140
|
+
provider: config.name,
|
|
141
|
+
url: normalizeProviderOutputUrl(candidate.mediaUrl),
|
|
142
|
+
ids: query.ids,
|
|
143
|
+
},
|
|
144
|
+
],
|
|
133
145
|
checkedAt: new Date().toISOString(),
|
|
134
146
|
};
|
|
135
147
|
}
|
|
136
148
|
async function filterUnavailablePlayers(config, options, context) {
|
|
137
149
|
const results = await mapWithConcurrency(options, config.playerValidationConcurrency, async (option) => ({
|
|
138
150
|
option,
|
|
139
|
-
|
|
151
|
+
outcome: await validatePlayer(config, option, context),
|
|
140
152
|
}));
|
|
141
|
-
return results
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
153
|
+
return results
|
|
154
|
+
.filter((result) => result.outcome !== "unavailable")
|
|
155
|
+
.map((result) => result.outcome === "unknown"
|
|
156
|
+
? { ...result.option, availability: "unknown" }
|
|
157
|
+
: result.option);
|
|
158
|
+
}
|
|
159
|
+
async function validatePlayer(config, option, context) {
|
|
160
|
+
const fetchImpl = config.externalFetch;
|
|
145
161
|
const controller = new AbortController();
|
|
146
162
|
const timeout = setTimeout(() => controller.abort(), config.playerValidationTimeoutMs);
|
|
147
163
|
const signal = context.signal
|
|
@@ -163,22 +179,25 @@ async function isPlayerUnavailable(config, option, context) {
|
|
|
163
179
|
},
|
|
164
180
|
signal,
|
|
165
181
|
});
|
|
166
|
-
if (response.status === 404 || response.status === 410
|
|
167
|
-
|
|
182
|
+
if (response.status === 404 || response.status === 410) {
|
|
183
|
+
await response.body?.cancel();
|
|
184
|
+
return "unavailable";
|
|
185
|
+
}
|
|
186
|
+
if (!response.ok && response.status !== 206) {
|
|
187
|
+
await response.body?.cancel();
|
|
188
|
+
return "unknown";
|
|
168
189
|
}
|
|
169
|
-
if (!response.ok && response.status !== 206)
|
|
170
|
-
return false;
|
|
171
190
|
if (isDirect) {
|
|
172
191
|
await response.body?.cancel();
|
|
173
|
-
return
|
|
192
|
+
return "available";
|
|
174
193
|
}
|
|
175
|
-
const html = await readBoundedResponseText(response, config.playerValidationMaxBytes);
|
|
176
|
-
return hasUnavailableMarker(html);
|
|
194
|
+
const html = await readBoundedResponseText(config.name, response, config.playerValidationMaxBytes, { signal, overflow: "truncate" });
|
|
195
|
+
return hasUnavailableMarker(html) ? "unavailable" : "available";
|
|
177
196
|
}
|
|
178
197
|
catch (error) {
|
|
179
198
|
rethrowIfProviderAborted(context, error);
|
|
180
199
|
// A validation timeout or transient network failure must not hide a discovered player.
|
|
181
|
-
return
|
|
200
|
+
return "unknown";
|
|
182
201
|
}
|
|
183
202
|
finally {
|
|
184
203
|
clearTimeout(timeout);
|
|
@@ -189,7 +208,7 @@ async function enrichPlayerOption(config, option, context) {
|
|
|
189
208
|
if (!subtitleInfoUrl)
|
|
190
209
|
return option;
|
|
191
210
|
try {
|
|
192
|
-
const response = await
|
|
211
|
+
const response = await config.externalFetch(subtitleInfoUrl, {
|
|
193
212
|
headers: {
|
|
194
213
|
Accept: "application/json",
|
|
195
214
|
"User-Agent": config.userAgent,
|
|
@@ -199,12 +218,9 @@ async function enrichPlayerOption(config, option, context) {
|
|
|
199
218
|
});
|
|
200
219
|
if (!response.ok)
|
|
201
220
|
return option;
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
return option;
|
|
206
|
-
}
|
|
207
|
-
const text = await readBoundedResponseText(response, config.subtitleInfoMaxBytes);
|
|
221
|
+
const text = await readBoundedResponseText(config.name, response, config.subtitleInfoMaxBytes, {
|
|
222
|
+
signal: context.signal,
|
|
223
|
+
});
|
|
208
224
|
const subtitles = parseSubtitleInfo(text);
|
|
209
225
|
return subtitles.length > 0 ? { ...option, subtitles } : option;
|
|
210
226
|
}
|
|
@@ -227,36 +243,6 @@ async function mapWithConcurrency(values, concurrency, mapper) {
|
|
|
227
243
|
await Promise.all(Array.from({ length: Math.min(concurrency, values.length) }, async () => worker()));
|
|
228
244
|
return results;
|
|
229
245
|
}
|
|
230
|
-
async function readBoundedResponseText(response, maxBytes) {
|
|
231
|
-
if (!response.body)
|
|
232
|
-
return "";
|
|
233
|
-
const reader = response.body.getReader();
|
|
234
|
-
const chunks = [];
|
|
235
|
-
let totalBytes = 0;
|
|
236
|
-
try {
|
|
237
|
-
while (totalBytes <= maxBytes) {
|
|
238
|
-
const { done, value } = await reader.read();
|
|
239
|
-
if (done)
|
|
240
|
-
break;
|
|
241
|
-
totalBytes += value.byteLength;
|
|
242
|
-
if (totalBytes > maxBytes) {
|
|
243
|
-
await reader.cancel();
|
|
244
|
-
break;
|
|
245
|
-
}
|
|
246
|
-
chunks.push(value);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
finally {
|
|
250
|
-
reader.releaseLock();
|
|
251
|
-
}
|
|
252
|
-
const body = new Uint8Array(chunks.reduce((size, chunk) => size + chunk.byteLength, 0));
|
|
253
|
-
let offset = 0;
|
|
254
|
-
for (const chunk of chunks) {
|
|
255
|
-
body.set(chunk, offset);
|
|
256
|
-
offset += chunk.byteLength;
|
|
257
|
-
}
|
|
258
|
-
return new TextDecoder().decode(body);
|
|
259
|
-
}
|
|
260
246
|
function hasUnavailableMarker(html) {
|
|
261
247
|
const normalized = normalizeTitle(html);
|
|
262
248
|
return (normalized.includes("video not found") ||
|
|
@@ -268,10 +254,9 @@ function hasUnavailableMarker(html) {
|
|
|
268
254
|
async function fetchPlayers(config, token, type, context) {
|
|
269
255
|
const body = new URLSearchParams();
|
|
270
256
|
body.set(type === "movie" ? "players" : "players_show", token);
|
|
271
|
-
const responseText = await
|
|
257
|
+
const responseText = await fetchFlixHqText(config, new URL("/ajax/ajax.php", config.baseUrl), context, {
|
|
272
258
|
method: "POST",
|
|
273
259
|
headers: {
|
|
274
|
-
...createHeaders(config),
|
|
275
260
|
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
|
276
261
|
},
|
|
277
262
|
body: body.toString(),
|
|
@@ -293,6 +278,8 @@ function mapPlayer(config, player, episode, index) {
|
|
|
293
278
|
const kind = inferPlayerKind(url);
|
|
294
279
|
const quality = inferQuality(label, url);
|
|
295
280
|
const expiresAt = inferExpiresAt(url);
|
|
281
|
+
const referer = normalizeProviderOutputUrl(`${config.baseUrl}/`);
|
|
282
|
+
const sourceUrl = normalizeProviderOutputUrl(episode.url);
|
|
296
283
|
return {
|
|
297
284
|
id: `${config.name}:${episode.seasonNumber ?? 0}:${episode.episodeNumber ?? 0}:${index + 1}`,
|
|
298
285
|
provider: config.name,
|
|
@@ -307,13 +294,12 @@ function mapPlayer(config, player, episode, index) {
|
|
|
307
294
|
},
|
|
308
295
|
access: {
|
|
309
296
|
url,
|
|
310
|
-
referer:
|
|
311
|
-
headers: { Referer: `${config.baseUrl}/` },
|
|
297
|
+
...(referer ? { referer, headers: { Referer: referer } } : {}),
|
|
312
298
|
},
|
|
313
299
|
availability: "available",
|
|
314
300
|
...(quality ? { quality } : {}),
|
|
315
301
|
...(expiresAt ? { expiresAt } : {}),
|
|
316
|
-
sourceUrl
|
|
302
|
+
sourceUrl,
|
|
317
303
|
};
|
|
318
304
|
}
|
|
319
305
|
export function parseSubtitleInfo(value) {
|
|
@@ -348,11 +334,11 @@ export function parseSubtitleInfo(value) {
|
|
|
348
334
|
}
|
|
349
335
|
return tracks;
|
|
350
336
|
}
|
|
351
|
-
export function parseSearchCandidates(html) {
|
|
337
|
+
export function parseSearchCandidates(html, baseUrl) {
|
|
352
338
|
const candidates = [];
|
|
353
339
|
const seen = new Set();
|
|
354
340
|
for (const anchor of parseAnchors(html)) {
|
|
355
|
-
const href =
|
|
341
|
+
const href = normalizeFlixHqNavigationUrl(getAttribute(anchor.attributes, "href"), baseUrl);
|
|
356
342
|
const type = href?.includes("/watch-movie/")
|
|
357
343
|
? "movie"
|
|
358
344
|
: href?.includes("/watch-series/")
|
|
@@ -370,9 +356,9 @@ export function parseSearchCandidates(html) {
|
|
|
370
356
|
}
|
|
371
357
|
return candidates;
|
|
372
358
|
}
|
|
373
|
-
export function parseEpisodes(html) {
|
|
359
|
+
export function parseEpisodes(html, baseUrl) {
|
|
374
360
|
return parseAnchors(html).flatMap((anchor) => {
|
|
375
|
-
const href =
|
|
361
|
+
const href = normalizeFlixHqNavigationUrl(getAttribute(anchor.attributes, "href"), baseUrl);
|
|
376
362
|
const match = href?.match(/\/s(\d+)-e(\d+)\/?$/i);
|
|
377
363
|
if (!href || !match)
|
|
378
364
|
return [];
|
|
@@ -430,41 +416,6 @@ function getAttribute(attributes, name) {
|
|
|
430
416
|
const expression = new RegExp(`(?:^|\\s)${escapedName}\\s*=\\s*(["'])(.*?)\\1`, "i");
|
|
431
417
|
return attributes.match(expression)?.[2];
|
|
432
418
|
}
|
|
433
|
-
async function fetchText(config, url, context, init = {}) {
|
|
434
|
-
const fetchImpl = config.fetch ?? fetch;
|
|
435
|
-
try {
|
|
436
|
-
await config.rateLimitGate.wait(context.signal);
|
|
437
|
-
const response = await fetchImpl(url, {
|
|
438
|
-
...init,
|
|
439
|
-
headers: init.headers ?? createHeaders(config),
|
|
440
|
-
signal: context.signal,
|
|
441
|
-
});
|
|
442
|
-
deferProviderRateLimitFromResponse(config.rateLimitGate, response);
|
|
443
|
-
if (!response.ok) {
|
|
444
|
-
throw mapHttpResponseToProviderError(config.name, response);
|
|
445
|
-
}
|
|
446
|
-
const declaredLength = Number(response.headers.get("content-length"));
|
|
447
|
-
if (Number.isFinite(declaredLength) && declaredLength > config.maxHtmlBytes) {
|
|
448
|
-
throw new Error(`Provider "${config.name}" returned an oversized response.`);
|
|
449
|
-
}
|
|
450
|
-
const body = await response.arrayBuffer();
|
|
451
|
-
if (body.byteLength > config.maxHtmlBytes) {
|
|
452
|
-
throw new Error(`Provider "${config.name}" returned an oversized response.`);
|
|
453
|
-
}
|
|
454
|
-
return new TextDecoder().decode(body);
|
|
455
|
-
}
|
|
456
|
-
catch (error) {
|
|
457
|
-
throw mapProviderHttpError(config.name, error);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
function createHeaders(config) {
|
|
461
|
-
return {
|
|
462
|
-
Accept: "text/html,application/json;q=0.9,*/*;q=0.8",
|
|
463
|
-
"User-Agent": config.userAgent,
|
|
464
|
-
Referer: `${config.baseUrl}/`,
|
|
465
|
-
"X-Requested-With": "XMLHttpRequest",
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
419
|
function isPlayerResponse(value) {
|
|
469
420
|
return typeof value === "object" && value !== null;
|
|
470
421
|
}
|
|
@@ -473,6 +424,9 @@ function normalizeBaseUrl(value) {
|
|
|
473
424
|
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
474
425
|
throw new TypeError("FlixHQ streaming baseUrl must use HTTP or HTTPS.");
|
|
475
426
|
}
|
|
427
|
+
if (url.username !== "" || url.password !== "") {
|
|
428
|
+
throw new TypeError("FlixHQ streaming baseUrl must not include credentials.");
|
|
429
|
+
}
|
|
476
430
|
return url.href.replace(/\/$/, "");
|
|
477
431
|
}
|
|
478
432
|
function normalizeProviderName(value) {
|
|
@@ -482,7 +436,7 @@ function normalizeProviderName(value) {
|
|
|
482
436
|
return name;
|
|
483
437
|
}
|
|
484
438
|
function normalizeHttpUrl(value) {
|
|
485
|
-
return
|
|
439
|
+
return normalizeProviderOutputUrl(value);
|
|
486
440
|
}
|
|
487
441
|
function findSubtitleInfoUrl(playerUrl) {
|
|
488
442
|
try {
|