better-ani-scraped 1.5.0 → 1.5.2
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/DOCUMENTATION.md
CHANGED
|
@@ -27,7 +27,7 @@ const crunchyroll = new AnimeScraper('crunchyroll') //for Crunchyroll
|
|
|
27
27
|
|
|
28
28
|
## `AnimeScraper("animesama")` methods
|
|
29
29
|
|
|
30
|
-
- [searchAnime](#animesamasearchanimequery-limit--10-wantedlanguages--vostfr-vf-vastfr-wantedtypes--anime-film)
|
|
30
|
+
- [searchAnime](#animesamasearchanimequery-limit--10-wantedlanguages--vostfr-vf-vastfr-wantedtypes--anime-film-page--null)
|
|
31
31
|
- [getSeasons](#animesamagetseasonsanimeurl-language--vostfr)
|
|
32
32
|
- [getEpisodeTitles](#animesamagetepisodetitlesseasonurl-customchromiumpath)
|
|
33
33
|
- [getEmbed](#animesamagetembedseasonurl-hostpriority--sibnet-vidmoly)
|
|
@@ -37,7 +37,7 @@ const crunchyroll = new AnimeScraper('crunchyroll') //for Crunchyroll
|
|
|
37
37
|
- [getLatestEpisodes](#animesamagetlatestepisodeslanguagefilter--null)
|
|
38
38
|
- [getRandomAnime](#animesamagetrandomanimewantedlanguages--vostfr-vf-vastfr-wantedtypes--anime-film-maxattempts--null-attempt--0)
|
|
39
39
|
|
|
40
|
-
### `animesama.searchAnime(query, limit = 10, wantedLanguages = ["vostfr", "vf", "vastfr"], wantedTypes = ["Anime", "Film"])`
|
|
40
|
+
### `animesama.searchAnime(query, limit = 10, wantedLanguages = ["vostfr", "vf", "vastfr"], wantedTypes = ["Anime", "Film"], page = null)`
|
|
41
41
|
Searches for anime titles that match the given query.
|
|
42
42
|
|
|
43
43
|
- **Parameters:**
|
|
@@ -45,6 +45,7 @@ Searches for anime titles that match the given query.
|
|
|
45
45
|
- `limit` *(number)*: Maximum number of results to return (default: 10).
|
|
46
46
|
- `wantedLanguages` *(string[])*: Array of wanted languages.
|
|
47
47
|
- `wantedTypes` *(string[])*: Array of wanted types.
|
|
48
|
+
- `page` *(number)*: The catalog page number.
|
|
48
49
|
- **Returns:**
|
|
49
50
|
An array of anime objects:
|
|
50
51
|
```js
|
|
@@ -169,8 +170,13 @@ Fetches the full anime catalog, optionally including season information.
|
|
|
169
170
|
```js
|
|
170
171
|
[
|
|
171
172
|
{
|
|
172
|
-
title: string,
|
|
173
173
|
url: string,
|
|
174
|
+
title: string,
|
|
175
|
+
altTitles: string[],
|
|
176
|
+
cover: string,
|
|
177
|
+
genres: string[],
|
|
178
|
+
types: string[],
|
|
179
|
+
languages: string[],
|
|
174
180
|
}
|
|
175
181
|
...
|
|
176
182
|
]
|
|
@@ -302,7 +308,7 @@ Extracts information from all episodes of a season of an anime.
|
|
|
302
308
|
```
|
|
303
309
|
---
|
|
304
310
|
|
|
305
|
-
## Utility functions
|
|
311
|
+
## Utility functions
|
|
306
312
|
|
|
307
313
|
- [getVideoUrlFromEmbed](#getvideourlfromembedsource-embedurl)
|
|
308
314
|
|
|
@@ -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("a", 100, ["vostfr", "vf", "vastfr"], ["Anime", "Film"], 2);
|
|
7
7
|
console.log("Search Results:", search);
|
|
8
8
|
};
|
|
9
9
|
|
package/package.json
CHANGED
package/scrapers/animesama.js
CHANGED
|
@@ -47,67 +47,73 @@ export async function searchAnime(
|
|
|
47
47
|
query,
|
|
48
48
|
limit = 10,
|
|
49
49
|
wantedLanguages = ["vostfr", "vf", "vastfr"],
|
|
50
|
-
wantedTypes = ["Anime", "Film"]
|
|
50
|
+
wantedTypes = ["Anime", "Film"],
|
|
51
|
+
page = null
|
|
51
52
|
) {
|
|
52
|
-
const url = `${CATALOGUE_URL}/?search=${encodeURIComponent(
|
|
53
|
-
query
|
|
54
|
-
)}`;
|
|
55
53
|
const isWanted = (text, list) =>
|
|
56
54
|
list.some(item => text.toLowerCase().includes(item.toLowerCase()));
|
|
57
|
-
|
|
58
|
-
const $ = cheerio.load(res.data);
|
|
55
|
+
|
|
59
56
|
const results = [];
|
|
60
57
|
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
const fetchPage = async (pageNum) => {
|
|
59
|
+
const url =
|
|
60
|
+
pageNum === 1
|
|
61
|
+
? `${CATALOGUE_URL}/?search=${encodeURIComponent(query)}`
|
|
62
|
+
: `${CATALOGUE_URL}/?search=${encodeURIComponent(query)}&page=${pageNum}`;
|
|
63
63
|
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
const title = anchor.find("h1").first().text().trim();
|
|
67
|
-
const altRaw = anchor
|
|
68
|
-
.find("p.text-xs.opacity-40.italic")
|
|
69
|
-
.first()
|
|
70
|
-
.text()
|
|
71
|
-
.trim();
|
|
72
|
-
const cover = anchor.find("img").first().attr("src");
|
|
64
|
+
const res = await axios.get(url, { headers: getHeaders(CATALOGUE_URL) });
|
|
65
|
+
const $ = cheerio.load(res.data);
|
|
73
66
|
|
|
74
|
-
const
|
|
75
|
-
isWanted($(p).text(), wantedTypes)
|
|
76
|
-
).first().text();
|
|
67
|
+
const containers = $("a.flex.divide-x");
|
|
77
68
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
).first().text();
|
|
69
|
+
containers.each((_, el) => {
|
|
70
|
+
if (results.length >= limit) return false;
|
|
81
71
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
: [];
|
|
72
|
+
const anchor = $(el);
|
|
73
|
+
const link = anchor.attr("href");
|
|
74
|
+
const title = anchor.find("h1").first().text().trim();
|
|
75
|
+
const altRaw = anchor.find("p.text-xs.opacity-40.italic").first().text().trim();
|
|
76
|
+
const cover = anchor.find("img").first().attr("src");
|
|
88
77
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
.first()
|
|
92
|
-
.text()
|
|
93
|
-
.trim();
|
|
94
|
-
const genres = genreRaw
|
|
95
|
-
? genreRaw
|
|
96
|
-
.split(",")
|
|
97
|
-
.map((g) => g.trim())
|
|
98
|
-
.filter(Boolean)
|
|
99
|
-
: [];
|
|
78
|
+
const tagText = anchor.find("p").filter((_, p) =>
|
|
79
|
+
isWanted($(p).text(), wantedTypes)
|
|
80
|
+
).first().text();
|
|
100
81
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
82
|
+
const languageText = anchor.find("p").filter((_, p) =>
|
|
83
|
+
isWanted($(p).text(), wantedLanguages)
|
|
84
|
+
).first().text();
|
|
85
|
+
|
|
86
|
+
const altTitles = altRaw
|
|
87
|
+
? altRaw.split(",").map((t) => t.trim()).filter(Boolean)
|
|
88
|
+
: [];
|
|
89
|
+
|
|
90
|
+
const genreRaw = anchor.find("p.text-xs.font-medium.text-gray-300").first().text().trim();
|
|
91
|
+
const genres = genreRaw
|
|
92
|
+
? genreRaw.split(",").map((g) => g.trim()).filter(Boolean)
|
|
93
|
+
: [];
|
|
94
|
+
|
|
95
|
+
if (title && link && tagText && languageText) {
|
|
96
|
+
results.push({
|
|
97
|
+
title,
|
|
98
|
+
altTitles,
|
|
99
|
+
genres,
|
|
100
|
+
url: link.startsWith("http") ? link : `${CATALOGUE_URL}${link}`,
|
|
101
|
+
cover,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
return containers.length > 0;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
if (page) {
|
|
110
|
+
await fetchPage(page);
|
|
111
|
+
} else {
|
|
112
|
+
let currentPage = 1;
|
|
113
|
+
while (await fetchPage(currentPage++) && results.length < limit) {
|
|
114
|
+
await new Promise((res) => setTimeout(res, 300));
|
|
109
115
|
}
|
|
110
|
-
}
|
|
116
|
+
}
|
|
111
117
|
|
|
112
118
|
return results;
|
|
113
119
|
}
|
|
@@ -343,31 +349,45 @@ export async function getAllAnime(
|
|
|
343
349
|
const url = pageNum === 1 ? CATALOGUE_URL : `${CATALOGUE_URL}?page=${pageNum}`;
|
|
344
350
|
const res = await axios.get(url, { headers: getHeaders(CATALOGUE_URL) });
|
|
345
351
|
const $ = cheerio.load(res.data);
|
|
346
|
-
|
|
352
|
+
|
|
347
353
|
const containers = $("div.shrink-0.m-3.rounded.border-2");
|
|
348
|
-
|
|
354
|
+
|
|
349
355
|
containers.each((_, el) => {
|
|
350
356
|
const anchor = $(el).find("a");
|
|
351
357
|
const title = anchor.find("h1").text().trim();
|
|
352
358
|
const link = anchor.attr("href");
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
359
|
+
const img = anchor.find("img").attr("src");
|
|
360
|
+
|
|
361
|
+
const paragraphs = anchor.find("p").toArray().map(p => $(p).text().trim());
|
|
362
|
+
|
|
363
|
+
const altTitles = paragraphs[0] ? paragraphs[0].split(',').map(name => name.trim()) : [];
|
|
364
|
+
const genres = paragraphs[1] ? paragraphs[1].split(',').map(genre => genre.trim()) : [];
|
|
365
|
+
const type = paragraphs[2] ? paragraphs[2].split(',').map(t => t.trim()) : [];
|
|
366
|
+
const language = paragraphs[3] ? paragraphs[3].split(',').map(lang => lang.trim()) : [];
|
|
367
|
+
const filteredTypes = type.filter(t => isWanted(t, wantedTypes));
|
|
368
|
+
const filteredLanguages = language.filter(lang => isWanted(lang, wantedLanguages));
|
|
369
|
+
if (
|
|
370
|
+
title &&
|
|
371
|
+
link &&
|
|
372
|
+
filteredTypes.length > 0 &&
|
|
373
|
+
filteredLanguages.length > 0
|
|
374
|
+
) {
|
|
363
375
|
const fullUrl = link.startsWith("http") ? link : `${BASE_URL}${link}`;
|
|
364
|
-
animeLinks.push({
|
|
376
|
+
animeLinks.push({
|
|
377
|
+
url: fullUrl,
|
|
378
|
+
title,
|
|
379
|
+
altTitles,
|
|
380
|
+
cover: img,
|
|
381
|
+
genres,
|
|
382
|
+
types: filteredTypes,
|
|
383
|
+
languages: filteredLanguages,
|
|
384
|
+
});
|
|
365
385
|
}
|
|
366
386
|
});
|
|
367
|
-
|
|
387
|
+
|
|
368
388
|
return containers.length > 0;
|
|
369
389
|
};
|
|
370
|
-
|
|
390
|
+
|
|
371
391
|
const enrichWithSeasons = async (list) => {
|
|
372
392
|
for (const anime of list) {
|
|
373
393
|
try {
|
|
@@ -392,7 +412,6 @@ export async function getAllAnime(
|
|
|
392
412
|
await new Promise(r => setTimeout(r, 300));
|
|
393
413
|
}
|
|
394
414
|
|
|
395
|
-
// Dédupliquer les URLs
|
|
396
415
|
const uniqueLinks = [...new Map(animeLinks.map(item => [item.url, item])).values()];
|
|
397
416
|
if (get_seasons) await enrichWithSeasons(uniqueLinks);
|
|
398
417
|
|
|
@@ -400,7 +419,7 @@ export async function getAllAnime(
|
|
|
400
419
|
return true;
|
|
401
420
|
}
|
|
402
421
|
} catch (err) {
|
|
403
|
-
console.error("
|
|
422
|
+
console.error("error :", err.message);
|
|
404
423
|
return false;
|
|
405
424
|
}
|
|
406
425
|
}
|
|
File without changes
|