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("a", 100, ["vostfr", "vf", "vastfr"], ["Anime", "Film"], 2);
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-vt374ef2joph.html";
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.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"
@@ -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
- "User-Agent": "Mozilla/5.0",
41
- "Accept-Language": "fr-FR,fr;q=0.9,en;q=0.8",
42
- Referer: referer,
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 = ["vostfr", "vf", "vastfr"],
50
- wantedTypes = ["Anime", "Film"],
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: getHeaders(CATALOGUE_URL) });
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(), wantedTypes)
89
+ isWanted($(p).text(), types)
80
90
  ).first().text();
81
91
 
82
92
  const languageText = anchor.find("p").filter((_, p) =>
83
- isWanted($(p).text(), wantedLanguages)
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
- if (title && link && tagText && languageText) {
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 res = await axios.get(animeUrl, { headers: getHeaders(CATALOGUE_URL) });
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
- try {
153
- const check = await axios.head(fullUrl, {
154
- headers: getHeaders(animeUrl),
155
- });
156
- if (check.status === 200) {
157
- languageAvailable = true;
158
- seasons.push({ title, url: fullUrl });
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: ['--no-sandbox', '--disable-setuid-sandbox'],
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: getHeaders(seasonUrl.split("/").slice(0, 5).join("/")),
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: getHeaders(seasonUrl) })
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
- finalEmbeds.push({
300
- title: null, // à remplir plus tard
301
- url: selectedUrl || null,
302
- host: selectedHost || null,
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 res = await axios.get(animeUrl, { headers: getHeaders(CATALOGUE_URL) });
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: getHeaders(CATALOGUE_URL),
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: getHeaders(CATALOGUE_URL) });
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 res = await axios.get(BASE_URL, { headers: getHeaders() });
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(); // Normalisation
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: getHeaders(CATALOGUE_URL) }
563
+ { headers:headers }
533
564
  );
534
565
 
535
566
  const $ = cheerio.load(res.data);
@@ -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),