nekostream 2026.0.1
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 +30 -0
- package/bin/nekostream.js +4 -0
- package/dist/discord.js +144 -0
- package/dist/fetch-avs.js +22 -0
- package/dist/index.js +808 -0
- package/dist/player.js +37 -0
- package/dist/prompts-wrapper.js +81 -0
- package/dist/providers.js +35 -0
- package/dist/scrapers/anilist-api.js +516 -0
- package/dist/scrapers/anilist.js +82 -0
- package/dist/scrapers/auth-service.js +1245 -0
- package/dist/scrapers/base.js +41 -0
- package/dist/scrapers/crawler.js +301 -0
- package/dist/scrapers/external-api.js +68 -0
- package/dist/scrapers/fingerprint.js +240 -0
- package/dist/scrapers/interceptor.js +288 -0
- package/dist/scrapers/jikan-api.js +60 -0
- package/dist/scrapers/providers/anime47.js +941 -0
- package/dist/scrapers/providers/animehay.js +640 -0
- package/dist/scrapers/providers/animevietsub.js +1455 -0
- package/dist/storage.js +215 -0
- package/dist/test-a47-eps.js +69 -0
- package/dist/test-a47-real.js +56 -0
- package/dist/test-a47.js +8 -0
- package/dist/ui.js +187 -0
- package/isolate.css +115 -0
- package/isolate.js +178 -0
- package/package.json +60 -0
- package/player-main.js +225 -0
- package/player.html +376 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared AniList GraphQL utility for image enrichment.
|
|
4
|
+
*
|
|
5
|
+
* Provides high-quality cover images (coverImage.extraLarge ~475px wide)
|
|
6
|
+
* and banner images (bannerImage ~1900×400) by matching anime titles
|
|
7
|
+
* against the AniList API. Results are cached in-memory per process lifetime.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* import { enrichWithAniList } from '../anilist'
|
|
11
|
+
* const { cover, banner } = await enrichWithAniList(title)
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.enrichWithAniList = enrichWithAniList;
|
|
15
|
+
const ANILIST_ENDPOINT = 'https://graphql.anilist.co';
|
|
16
|
+
// In-memory cache keyed by normalised title — avoids redundant API calls
|
|
17
|
+
// when multiple episodes/detail requests fire for the same show.
|
|
18
|
+
const cache = new Map();
|
|
19
|
+
function normalizeTitleForSearch(title) {
|
|
20
|
+
return title
|
|
21
|
+
.replace(/\s*\(?\d{4}\)?$/, '') // strip trailing year
|
|
22
|
+
.replace(/\s*(Phần|Mùa|Season|Part)\s*\d+/i, '') // strip season suffix
|
|
23
|
+
.replace(/\s+/g, ' ')
|
|
24
|
+
.trim();
|
|
25
|
+
}
|
|
26
|
+
const GQL_QUERY = `
|
|
27
|
+
query ($search: String) {
|
|
28
|
+
Media(search: $search, type: ANIME, sort: SEARCH_MATCH) {
|
|
29
|
+
id
|
|
30
|
+
coverImage { extraLarge }
|
|
31
|
+
bannerImage
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
`.trim();
|
|
35
|
+
/**
|
|
36
|
+
* Fetch AniList image data for an anime by title.
|
|
37
|
+
* Non-throwing — returns empty object on any network or parse error.
|
|
38
|
+
*/
|
|
39
|
+
async function enrichWithAniList(rawTitle, timeoutMs = 8000) {
|
|
40
|
+
const title = normalizeTitleForSearch(rawTitle);
|
|
41
|
+
if (!title)
|
|
42
|
+
return {};
|
|
43
|
+
const cached = cache.get(title);
|
|
44
|
+
if (cached !== undefined)
|
|
45
|
+
return cached;
|
|
46
|
+
const controller = new AbortController();
|
|
47
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
48
|
+
try {
|
|
49
|
+
const response = await fetch(ANILIST_ENDPOINT, {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
headers: {
|
|
52
|
+
'Content-Type': 'application/json',
|
|
53
|
+
Accept: 'application/json',
|
|
54
|
+
},
|
|
55
|
+
body: JSON.stringify({ query: GQL_QUERY, variables: { search: title } }),
|
|
56
|
+
signal: controller.signal,
|
|
57
|
+
});
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
// AniList rate-limits with 429 — don't cache, just return empty
|
|
60
|
+
if (response.status === 429)
|
|
61
|
+
return {};
|
|
62
|
+
cache.set(title, {});
|
|
63
|
+
return {};
|
|
64
|
+
}
|
|
65
|
+
const json = await response.json();
|
|
66
|
+
const media = json?.data?.Media;
|
|
67
|
+
const result = {
|
|
68
|
+
cover: media?.coverImage?.extraLarge || undefined,
|
|
69
|
+
banner: media?.bannerImage || undefined,
|
|
70
|
+
anilistId: media?.id || undefined,
|
|
71
|
+
};
|
|
72
|
+
cache.set(title, result);
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Timeout / network error — do not cache so next attempt can retry
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
clearTimeout(timer);
|
|
81
|
+
}
|
|
82
|
+
}
|