better-ani-scraped 1.6.6 → 1.6.81
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.
|
@@ -3,7 +3,7 @@ import { AnimeScraper } from "../../index.js"; // REPLACE BY "from 'better-ani-s
|
|
|
3
3
|
const main = async () => {
|
|
4
4
|
const animesama = new AnimeScraper('animesama');
|
|
5
5
|
|
|
6
|
-
const search = await animesama.searchAnime("
|
|
6
|
+
const search = await animesama.searchAnime("gachiakuta", 100, [], ["Anime", "Film", "Autres", "Scans"]);
|
|
7
7
|
console.log("Search Results:", search);
|
|
8
8
|
};
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ import { getVideoUrlFromEmbed } from "../../index.js"; // REPLACE BY "from 'bett
|
|
|
3
3
|
const main = async () => {
|
|
4
4
|
const embedUrlSibnet = "https://video.sibnet.ru/shell.php?videoid=4291083";
|
|
5
5
|
const embedUrlSendvid = "https://sendvid.com/embed/4vzpcb0q";
|
|
6
|
-
const embedUrlVidmoly = "https://vidmoly.to/embed-
|
|
6
|
+
const embedUrlVidmoly = "https://vidmoly.to/embed-rvqrwg5zk37w.html";
|
|
7
7
|
const embedUrlOneupload = "https://oneupload.net/embed-axdrxh1y3p37.html";
|
|
8
8
|
|
|
9
9
|
const videoUrlSibnet = await getVideoUrlFromEmbed("sibnet", embedUrlSibnet)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "better-ani-scraped",
|
|
3
|
-
"version": "1.6.
|
|
4
|
-
"description": "Scrape anime data from different sources (only anime-sama.fr for the moment)",
|
|
3
|
+
"version": "1.6.81",
|
|
4
|
+
"description": "Scrape anime data from different sources (only anime-sama.fr, animepahe and crunchyroll for the moment)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1"
|
package/scrapers/animesama.js
CHANGED
|
@@ -36,22 +36,32 @@ async function ensureChromiumInstalled(customPath) {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
function getHeaders(referer = BASE_URL) {
|
|
39
|
+
const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ' + '(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36';
|
|
39
40
|
return {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
headers: {
|
|
42
|
+
"User-Agent": userAgent,
|
|
43
|
+
"Accept-Language": "fr-FR,fr;q=0.9,en;q=0.8",
|
|
44
|
+
"Referer": referer,
|
|
45
|
+
},
|
|
46
|
+
userAgent
|
|
43
47
|
};
|
|
44
48
|
}
|
|
45
49
|
|
|
50
|
+
|
|
51
|
+
|
|
46
52
|
export async function searchAnime(
|
|
47
53
|
query,
|
|
48
54
|
limit = 10,
|
|
49
|
-
wantedLanguages =
|
|
50
|
-
wantedTypes =
|
|
55
|
+
wantedLanguages = null,
|
|
56
|
+
wantedTypes = null,
|
|
51
57
|
page = null
|
|
52
58
|
) {
|
|
59
|
+
const languages = Array.isArray(wantedLanguages) ? wantedLanguages : ["vostfr", "vf", "vastfr"];
|
|
60
|
+
const types = Array.isArray(wantedTypes) ? wantedTypes : ["Anime", "Film"];
|
|
61
|
+
|
|
62
|
+
const { headers } = getHeaders(CATALOGUE_URL);
|
|
53
63
|
const isWanted = (text, list) =>
|
|
54
|
-
list.some(item => text.toLowerCase().includes(item.toLowerCase()));
|
|
64
|
+
list.length === 0 || list.some(item => text.toLowerCase().includes(item.toLowerCase()));
|
|
55
65
|
|
|
56
66
|
const results = [];
|
|
57
67
|
|
|
@@ -61,7 +71,7 @@ export async function searchAnime(
|
|
|
61
71
|
? `${CATALOGUE_URL}/?search=${encodeURIComponent(query)}`
|
|
62
72
|
: `${CATALOGUE_URL}/?search=${encodeURIComponent(query)}&page=${pageNum}`;
|
|
63
73
|
|
|
64
|
-
const res = await axios.get(url, { headers:
|
|
74
|
+
const res = await axios.get(url, { headers: headers });
|
|
65
75
|
const $ = cheerio.load(res.data);
|
|
66
76
|
|
|
67
77
|
const containers = $("a.flex.divide-x");
|
|
@@ -76,11 +86,11 @@ export async function searchAnime(
|
|
|
76
86
|
const cover = anchor.find("img").first().attr("src");
|
|
77
87
|
|
|
78
88
|
const tagText = anchor.find("p").filter((_, p) =>
|
|
79
|
-
isWanted($(p).text(),
|
|
89
|
+
isWanted($(p).text(), types)
|
|
80
90
|
).first().text();
|
|
81
91
|
|
|
82
92
|
const languageText = anchor.find("p").filter((_, p) =>
|
|
83
|
-
isWanted($(p).text(),
|
|
93
|
+
isWanted($(p).text(), languages)
|
|
84
94
|
).first().text();
|
|
85
95
|
|
|
86
96
|
const altTitles = altRaw
|
|
@@ -92,7 +102,10 @@ export async function searchAnime(
|
|
|
92
102
|
? genreRaw.split(",").map((g) => g.trim()).filter(Boolean)
|
|
93
103
|
: [];
|
|
94
104
|
|
|
95
|
-
|
|
105
|
+
const hasValidType = types.length === 0 || tagText;
|
|
106
|
+
const hasValidLanguage = languages.length === 0 || languageText;
|
|
107
|
+
|
|
108
|
+
if (title && link && hasValidType && hasValidLanguage) {
|
|
96
109
|
results.push({
|
|
97
110
|
title,
|
|
98
111
|
altTitles,
|
|
@@ -119,7 +132,9 @@ export async function searchAnime(
|
|
|
119
132
|
}
|
|
120
133
|
|
|
121
134
|
export async function getSeasons(animeUrl, languagePriority = ["vostfr", "vf", "va", "vkr", "vcn", "vqc", "vf1", "vf2"]) {
|
|
122
|
-
const
|
|
135
|
+
const { headersCatalog } = getHeaders(CATALOGUE_URL);
|
|
136
|
+
const { headersAnime } = getHeaders(animeUrl);
|
|
137
|
+
const res = await axios.get(animeUrl, { headers: headersCatalog });
|
|
123
138
|
const html = res.data;
|
|
124
139
|
|
|
125
140
|
const mainAnimeOnly = html.split("Anime Version Kai")[0];
|
|
@@ -149,19 +164,19 @@ export async function getSeasons(animeUrl, languagePriority = ["vostfr", "vf", "
|
|
|
149
164
|
const href = match[2].split("/")[0];
|
|
150
165
|
const fullUrl = `${CATALOGUE_URL}/${animeName}/${href}/${language}`;
|
|
151
166
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
} catch (err) {
|
|
161
|
-
// Ignore invalid URLs
|
|
167
|
+
try {
|
|
168
|
+
const check = await axios.head(fullUrl, {
|
|
169
|
+
headers: headersAnime,
|
|
170
|
+
});
|
|
171
|
+
if (check.status === 200) {
|
|
172
|
+
languageAvailable = true;
|
|
173
|
+
seasons.push({ title, url: fullUrl });
|
|
162
174
|
}
|
|
175
|
+
} catch (err) {
|
|
176
|
+
// Ignore missing URLs
|
|
163
177
|
}
|
|
164
178
|
}
|
|
179
|
+
}
|
|
165
180
|
|
|
166
181
|
if (languageAvailable) {
|
|
167
182
|
return { language, seasons };
|
|
@@ -173,6 +188,7 @@ export async function getSeasons(animeUrl, languagePriority = ["vostfr", "vf", "
|
|
|
173
188
|
|
|
174
189
|
|
|
175
190
|
export async function getEpisodeTitles(seasonUrl, customChromiumPath) {
|
|
191
|
+
const { headers, userAgent } = getHeaders(seasonUrl);
|
|
176
192
|
let browser;
|
|
177
193
|
try {
|
|
178
194
|
const puppeteer = await import('puppeteer');
|
|
@@ -181,11 +197,15 @@ export async function getEpisodeTitles(seasonUrl, customChromiumPath) {
|
|
|
181
197
|
browser = await puppeteer.launch({
|
|
182
198
|
headless: true,
|
|
183
199
|
executablePath,
|
|
184
|
-
args: [
|
|
200
|
+
args: [
|
|
201
|
+
'--no-sandbox',
|
|
202
|
+
'--disable-setuid-sandbox',
|
|
203
|
+
]
|
|
204
|
+
|
|
185
205
|
});
|
|
186
206
|
|
|
187
207
|
const page = await browser.newPage();
|
|
188
|
-
|
|
208
|
+
await page.setExtraHTTPHeaders(headers);
|
|
189
209
|
await page.setRequestInterception(true);
|
|
190
210
|
page.on('request', (req) => {
|
|
191
211
|
const blocked = ['image', 'stylesheet', 'font', 'media'];
|
|
@@ -195,9 +215,13 @@ export async function getEpisodeTitles(seasonUrl, customChromiumPath) {
|
|
|
195
215
|
req.continue();
|
|
196
216
|
}
|
|
197
217
|
});
|
|
198
|
-
|
|
218
|
+
await page.setUserAgent(userAgent);
|
|
219
|
+
await page.evaluateOnNewDocument(() => {
|
|
220
|
+
Object.defineProperty(navigator, 'webdriver', { get: () => false });
|
|
221
|
+
});
|
|
199
222
|
await page.goto(seasonUrl, { waitUntil: 'domcontentloaded' });
|
|
200
223
|
await page.waitForSelector('#selectEpisodes');
|
|
224
|
+
|
|
201
225
|
|
|
202
226
|
const titres = await page.$$eval('#selectEpisodes option', options =>
|
|
203
227
|
options.map(o => o.textContent.trim())
|
|
@@ -220,8 +244,10 @@ export async function getEmbed(
|
|
|
220
244
|
includeInfo = false,
|
|
221
245
|
customChromiumPath
|
|
222
246
|
) {
|
|
247
|
+
const { headersSplit } = getHeaders(seasonUrl.split("/").slice(0, 5).join("/"));
|
|
248
|
+
const { headers } = getHeaders(seasonUrl);
|
|
223
249
|
const res = await axios.get(seasonUrl, {
|
|
224
|
-
headers:
|
|
250
|
+
headers: headersSplit,
|
|
225
251
|
});
|
|
226
252
|
|
|
227
253
|
const $ = cheerio.load(res.data);
|
|
@@ -239,7 +265,7 @@ export async function getEmbed(
|
|
|
239
265
|
: seasonUrl + "/" + scriptTag;
|
|
240
266
|
|
|
241
267
|
const episodesJs = await axios
|
|
242
|
-
.get(scriptUrl, { headers:
|
|
268
|
+
.get(scriptUrl, { headers: headers })
|
|
243
269
|
.then((r) => r.data);
|
|
244
270
|
|
|
245
271
|
const matches = [...episodesJs.matchAll(/var\s+(eps\d+)\s*=\s*(\[[^\]]+\])/g)];
|
|
@@ -296,13 +322,13 @@ export async function getEmbed(
|
|
|
296
322
|
if (selectedUrl) break;
|
|
297
323
|
}
|
|
298
324
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
325
|
+
finalEmbeds.push({
|
|
326
|
+
title: null,
|
|
327
|
+
url: selectedUrl || null,
|
|
328
|
+
host: selectedHost || null
|
|
329
|
+
});
|
|
305
330
|
}
|
|
331
|
+
}
|
|
306
332
|
|
|
307
333
|
const titles = await getEpisodeTitles(seasonUrl, customChromiumPath);
|
|
308
334
|
finalEmbeds.forEach((embed, i) => {
|
|
@@ -325,7 +351,8 @@ export async function getEmbed(
|
|
|
325
351
|
|
|
326
352
|
|
|
327
353
|
export async function getAnimeInfo(animeUrl) {
|
|
328
|
-
const
|
|
354
|
+
const { headers } = getHeaders(CATALOGUE_URL);
|
|
355
|
+
const res = await axios.get(animeUrl, { headers: headers });
|
|
329
356
|
const $ = cheerio.load(res.data);
|
|
330
357
|
|
|
331
358
|
const cover = $("#coverOeuvre").attr("src");
|
|
@@ -361,6 +388,7 @@ export async function getAvailableLanguages(
|
|
|
361
388
|
wantedLanguages = ["vostfr", "vf", "va", "vkr", "vcn", "vqc", "vf1", "vf2"],
|
|
362
389
|
numberEpisodes = false
|
|
363
390
|
) {
|
|
391
|
+
const { headers } = getHeaders(CATALOGUE_URL);
|
|
364
392
|
const languageLinks = [];
|
|
365
393
|
|
|
366
394
|
// Iterate over each possible language and check if the page exists
|
|
@@ -368,7 +396,7 @@ export async function getAvailableLanguages(
|
|
|
368
396
|
const languageUrl = seasonUrl.split('/').map((s, i) => i === 6 ? language : s).join('/');
|
|
369
397
|
try {
|
|
370
398
|
const res = await axios.get(languageUrl, {
|
|
371
|
-
headers:
|
|
399
|
+
headers: headers,
|
|
372
400
|
});
|
|
373
401
|
if (res.status === 200) {
|
|
374
402
|
if (numberEpisodes){
|
|
@@ -394,6 +422,7 @@ export async function getAllAnime(
|
|
|
394
422
|
output = "anime_list.json",
|
|
395
423
|
get_seasons = false
|
|
396
424
|
) {
|
|
425
|
+
const { headers } = getHeaders(CATALOGUE_URL);
|
|
397
426
|
let animeLinks = [];
|
|
398
427
|
|
|
399
428
|
const isWanted = (text, list) =>
|
|
@@ -401,7 +430,7 @@ export async function getAllAnime(
|
|
|
401
430
|
|
|
402
431
|
const fetchPage = async (pageNum) => {
|
|
403
432
|
const url = pageNum === 1 ? CATALOGUE_URL : `${CATALOGUE_URL}?page=${pageNum}`;
|
|
404
|
-
const res = await axios.get(url, { headers:
|
|
433
|
+
const res = await axios.get(url, { headers: headers });
|
|
405
434
|
const $ = cheerio.load(res.data);
|
|
406
435
|
|
|
407
436
|
const containers = $("div.shrink-0.m-3.rounded.border-2");
|
|
@@ -480,7 +509,8 @@ export async function getAllAnime(
|
|
|
480
509
|
|
|
481
510
|
export async function getLatestEpisodes(languageFilter = null) {
|
|
482
511
|
try {
|
|
483
|
-
const
|
|
512
|
+
const { headers } = getHeaders(BASE_URL);
|
|
513
|
+
const res = await axios.get(BASE_URL, { headers: headers });
|
|
484
514
|
const $ = cheerio.load(res.data);
|
|
485
515
|
|
|
486
516
|
const container = $("#containerAjoutsAnimes");
|
|
@@ -492,7 +522,7 @@ export async function getLatestEpisodes(languageFilter = null) {
|
|
|
492
522
|
const cover = $(el).find("img").attr("src");
|
|
493
523
|
|
|
494
524
|
const buttons = $(el).find("button");
|
|
495
|
-
const language = $(buttons[0]).text().trim().toLowerCase();
|
|
525
|
+
const language = $(buttons[0]).text().trim().toLowerCase();
|
|
496
526
|
const episode = $(buttons[1]).text().trim();
|
|
497
527
|
|
|
498
528
|
if (
|
|
@@ -526,10 +556,11 @@ export async function getRandomAnime(
|
|
|
526
556
|
maxAttempts = null,
|
|
527
557
|
attempt = 0
|
|
528
558
|
) {
|
|
559
|
+
const { headers } = getHeaders(CATALOGUE_URL);
|
|
529
560
|
try {
|
|
530
561
|
const res = await axios.get(
|
|
531
562
|
`${CATALOGUE_URL}/?search=&random=1`,
|
|
532
|
-
{ headers:
|
|
563
|
+
{ headers:headers }
|
|
533
564
|
);
|
|
534
565
|
|
|
535
566
|
const $ = cheerio.load(res.data);
|
package/utils/extractVideoUrl.js
CHANGED
|
@@ -53,6 +53,9 @@ export async function getSendvidVideo(embedUrl) {
|
|
|
53
53
|
|
|
54
54
|
export async function getVidmolyOrOneuploadVideo(embedUrl) {
|
|
55
55
|
try {
|
|
56
|
+
if (embedUrl.includes("vidmoly.to/")) {
|
|
57
|
+
embedUrl = embedUrl.replace("vidmoly.to/", "vidmoly.net/");
|
|
58
|
+
}
|
|
56
59
|
console.log(embedUrl)
|
|
57
60
|
const { data } = await axios.get(embedUrl, {
|
|
58
61
|
headers: getHeaders(embedUrl),
|