better-ani-scraped 1.5.2 → 1.6.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/DOCUMENTATION.md CHANGED
@@ -30,7 +30,7 @@ const crunchyroll = new AnimeScraper('crunchyroll') //for Crunchyroll
30
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
- - [getEmbed](#animesamagetembedseasonurl-hostpriority--sibnet-vidmoly)
33
+ - [getEmbed](#animesamagetembedseasonurl-hostpriority--sendvid-sibnet-vidmoly-oneupload)
34
34
  - [getAnimeInfo](#animesamagetanimeinfoanimeurl)
35
35
  - [getAvailableLanguages](#animesamagetavailablelanguagesseasonurl-wantedlanguages--vostfr-vf-va-vkr-vcn-vqc-vf1-vf2-numberepisodes--false)
36
36
  - [getAllAnime](#animesamagetallanimewantedlanguages--vostfr-vf-vastfr-wantedtypes--anime-film-page--null-output--anime_listjson-get_seasons--false)
@@ -95,7 +95,7 @@ Fetches the names of all episodes in a season
95
95
 
96
96
  ---
97
97
 
98
- ### `animesama.getEmbed(seasonUrl, hostPriority = ["sibnet", "vidmoly"])`
98
+ ### `animesama.getEmbed(seasonUrl, hostPriority = ["sendvid", "sibnet", "vidmoly", "oneupload"])`
99
99
  Retrieves embed URLs for episodes, prioritizing by host.
100
100
 
101
101
  - **Parameters:**
@@ -108,6 +108,7 @@ Retrieves embed URLs for episodes, prioritizing by host.
108
108
  {
109
109
  title: string,
110
110
  url: string,
111
+ host: string,
111
112
  }
112
113
  ...
113
114
  ]
@@ -316,10 +317,14 @@ Extracts information from all episodes of a season of an anime.
316
317
  Retrieves the video URL of the source's embed.
317
318
 
318
319
  - **Parameters:**
319
- - `source` *(string)*: The embed source (only "sibnet" available at the moment)
320
+ - `source` *(string)*: The embed source (only "sibnet", "sendvid", "vidmoly" and "oneupload" available at the moment)
320
321
  - `embedUrl` *(string)*: The embed url of the given source.
321
322
  - **Returns:**
322
- A video URL as a string.
323
+ A video URL as a string :
324
+ - `sibnet`: mp4
325
+ - `sendvid`: mp4
326
+ - `vidmoly`: m3u8
327
+ - `oneupload`: m3u8
323
328
 
324
329
  ---
325
330
  ---
@@ -1,11 +1,22 @@
1
1
  import { getVideoUrlFromEmbed } from "../../index.js"; // REPLACE BY "from 'better-ani-scraped';"
2
2
 
3
3
  const main = async () => {
4
- const embedUrl = "https://video.sibnet.ru/shell.php?videoid=4291083";
5
-
6
- const videoUrl = await getVideoUrlFromEmbed("sibnet", embedUrl)
7
- console.log("Video URL:", videoUrl);
4
+ const embedUrlSibnet = "https://video.sibnet.ru/shell.php?videoid=4291083";
5
+ const embedUrlSendvid = "https://sendvid.com/embed/4vzpcb0q";
6
+ const embedUrlVidmoly = "https://vidmoly.to/embed-vt374ef2joph.html";
7
+ const embedUrlOneupload = "https://oneupload.net/embed-axdrxh1y3p37.html";
8
+
9
+ const videoUrlSibnet = await getVideoUrlFromEmbed("sibnet", embedUrlSibnet)
10
+ console.log("Video URL Sibnet:", videoUrlSibnet);
8
11
 
12
+ const videoUrlSendvid = await getVideoUrlFromEmbed("sendvid", embedUrlSendvid)
13
+ console.log("Video URL Sendvid:", videoUrlSendvid);
14
+
15
+ const videoUrlVidmoly = await getVideoUrlFromEmbed("vidmoly", embedUrlVidmoly)
16
+ console.log("Video URL Vidmoly:", videoUrlVidmoly);
17
+
18
+ const videoUrlOneupload = await getVideoUrlFromEmbed("oneupload", embedUrlOneupload)
19
+ console.log("Video URL Oneupload:", videoUrlOneupload);
9
20
  };
10
21
 
11
22
  main().catch(console.error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-ani-scraped",
3
- "version": "1.5.2",
3
+ "version": "1.6.1",
4
4
  "description": "Scrape anime data from different sources (only anime-sama.fr for the moment)",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -21,7 +21,7 @@
21
21
  "axios": "^1.8.4",
22
22
  "cheerio": "^1.0.0",
23
23
  "playwright": "^1.52.0",
24
- "puppeteer": "^24.7.2",
24
+ "puppeteer": "^24.8.1",
25
25
  "puppeteer-extra": "^3.3.6",
26
26
  "puppeteer-extra-plugin-stealth": "^2.11.2"
27
27
  },
@@ -215,7 +215,7 @@ export async function getEpisodeTitles(seasonUrl, customChromiumPath) {
215
215
  }
216
216
  }
217
217
 
218
- export async function getEmbed(seasonUrl, hostPriority = ["sibnet", "vidmoly"], customChromiumPath) {
218
+ export async function getEmbed(seasonUrl, hostPriority = ["sendvid", "sibnet", "vidmoly", "oneupload"], customChromiumPath) {
219
219
  const res = await axios.get(seasonUrl, {
220
220
  headers: getHeaders(seasonUrl.split("/").slice(0, 5).join("/")),
221
221
  });
@@ -249,25 +249,35 @@ export async function getEmbed(seasonUrl, hostPriority = ["sibnet", "vidmoly"],
249
249
 
250
250
  const maxEpisodes = Math.max(...episodeMatrix.map(arr => arr.length));
251
251
  const finalEmbeds = [];
252
- for (let i = 0; i < maxEpisodes; i++) {
253
- let selectedUrl = null;
254
- for (const host of hostPriority) {
255
- for (const arr of episodeMatrix) {
256
- if (i < arr.length && arr[i].includes(host)) {
257
- selectedUrl = arr[i];
258
- break;
259
- }
252
+ for (let i = 0; i < maxEpisodes; i++) {
253
+ let selectedUrl = null;
254
+ let selectedHost = null;
255
+
256
+ for (const host of hostPriority) {
257
+ for (const arr of episodeMatrix) {
258
+ if (i < arr.length && arr[i].includes(host)) {
259
+ selectedUrl = arr[i];
260
+ selectedHost = host;
261
+ break;
260
262
  }
261
- if (selectedUrl) break;
262
263
  }
263
- finalEmbeds.push(selectedUrl || null);
264
+ if (selectedUrl) break;
264
265
  }
265
266
 
266
- const titles = await getEpisodeTitles(seasonUrl, customChromiumPath);
267
- return finalEmbeds.map((url, i) => ({
268
- title: titles[i] || "Untitled",
269
- url,
270
- }));
267
+ finalEmbeds.push({
268
+ url: selectedUrl || null,
269
+ host: selectedHost || null
270
+ });
271
+ }
272
+
273
+ const titles = await getEpisodeTitles(seasonUrl, customChromiumPath);
274
+
275
+ return finalEmbeds.map((embed, i) => ({
276
+ title: titles[i] || null,
277
+ url: embed.url,
278
+ host: embed.host
279
+ }));
280
+
271
281
  }
272
282
 
273
283
  export async function getAnimeInfo(animeUrl) {
@@ -4,6 +4,12 @@ export async function getVideoUrlFromEmbed(source, embedUrl) {
4
4
  if (source === "sibnet") {
5
5
  return await extractor.getSibnetVideo(embedUrl);
6
6
  }
7
+ if (source === "sendvid") {
8
+ return await extractor.getSendvidVideo(embedUrl);
9
+ }
10
+ if (source === "vidmoly" || source === "oneupload" ) {
11
+ return await extractor.getVidmolyOrOneuploadVideo(embedUrl);
12
+ }
7
13
 
8
14
  throw new Error(`Unsupported embed source: ${source}`);
9
15
  }
@@ -1,67 +1,74 @@
1
1
  import axios from "axios";
2
2
  import * as cheerio from "cheerio";
3
3
 
4
- export async function getSibnetVideo(embedUrl) {
5
- let intermediaries = [];
6
- let realUrl = "";
7
-
8
- const getIntermediary = async () => {
9
- try {
10
- const { data } = await axios.get(embedUrl, { headers: getHeaders(embedUrl) });
11
- const $ = cheerio.load(data);
12
- const script = $("script")
13
- .toArray()
14
- .map((s) => $(s).html())
15
- .find((s) => s.includes("player.src"));
16
- const match = script?.match(/player\.src\(\[{src:\s*["']([^"']+)["']/);
17
- if (match) intermediaries.push(`https://video.sibnet.ru${match[1]}`);
18
- return !!match;
19
- } catch {
20
- return false;
21
- }
22
- };
23
4
 
24
- const followRedirection = async () => {
25
- if (!intermediaries.length) return false;
26
- try {
27
- const first = await axios.get(intermediaries[0], {
28
- headers: getHeaders(embedUrl),
29
- maxRedirects: 0,
30
- validateStatus: (s) => s >= 200 && s < 303,
31
- });
5
+ const getHeaders = (referer) => ({
6
+ Accept: "*/*",
7
+ Referer: referer,
8
+ "User-Agent":
9
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
10
+ });
11
+ export async function getSibnetVideo(embedUrl) {
12
+ try {
13
+ const { data } = await axios.get(embedUrl, {
14
+ headers: getHeaders(embedUrl),
15
+ });
16
+ const $ = cheerio.load(data);
17
+ const script = $("script")
18
+ .toArray()
19
+ .map((s) => $(s).html())
20
+ .find((s) => s.includes("player.src"));
21
+ const match = script?.match(/player\.src\(\[{src:\s*["']([^"']+)["']/);
22
+ if (!match || !match[1]) return null;
23
+ const intermediateUrl = `https://video.sibnet.ru${match[1]}`;
24
+ const res1 = await axios.get(intermediateUrl, {
25
+ headers: getHeaders(embedUrl),
26
+ maxRedirects: 0,
27
+ validateStatus: (s) => s >= 200 && s < 400,
28
+ });
29
+ const redirectUrl = res1.headers.location;
30
+ if (!redirectUrl) return null;
31
+ const finalUrl = redirectUrl.startsWith("http")
32
+ ? redirectUrl
33
+ : `https:${redirectUrl}`;
34
+ return finalUrl;
35
+ } catch (err) {
36
+ console.error("Erreur getSibnetVideo:", err.message);
37
+ return null;
38
+ }
39
+ }
32
40
 
33
- const redirect1 = correct(first.headers.location);
34
- intermediaries.push(redirect1);
41
+ export async function getSendvidVideo(embedUrl) {
42
+ try {
43
+ const { data } = await axios.get(embedUrl, {
44
+ headers: getHeaders(embedUrl),
45
+ });
46
+ const $ = cheerio.load(data);
47
+ const sourceTag = $("video source[type='video/mp4']").attr("src");
48
+ return sourceTag || null;
49
+ } catch (err) {
50
+ return null;
51
+ }
52
+ }
35
53
 
36
- const second = await axios.get(redirect1, {
37
- headers: getHeaders(intermediaries[0]),
38
- maxRedirects: 0,
39
- validateStatus: (s) => s >= 200 && s < 303,
40
- });
54
+ export async function getVidmolyOrOneuploadVideo(embedUrl) {
55
+ try {
56
+ const { data } = await axios.get(embedUrl, {
57
+ headers: getHeaders(embedUrl),
58
+ });
59
+ const $ = cheerio.load(data);
60
+ const scripts = $("script");
41
61
 
42
- realUrl =
43
- second.status === 302
44
- ? correct(second.headers.location)
45
- : second.status === 200
46
- ? intermediaries.pop()
47
- : "";
48
- return !!realUrl;
49
- } catch {
50
- return false;
62
+ for (let i = 0; i < scripts.length; i++) {
63
+ const content = $(scripts[i]).html();
64
+ const match = content && content.match(/file\s*:\s*"(https[^"]+\.m3u8[^"]*)"/);
65
+ if (match && match[1]) {
66
+ return match[1];
67
+ }
51
68
  }
52
- };
53
-
54
- const correct = (url) => (url.startsWith("https:") ? url : `https:${url}`);
55
-
56
- const getHeaders = (referer) => ({
57
- Accept: "*/*",
58
- Referer: referer,
59
- Range: "bytes=0-",
60
- "User-Agent":
61
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
62
- });
63
-
64
- return (await getIntermediary()) && (await followRedirection())
65
- ? realUrl
66
- : null;
69
+ return null;
70
+ } catch (err) {
71
+ console.error("Erreur getVidmolyVideo:", err.message);
72
+ return null;
73
+ }
67
74
  }