better-ani-scraped 1.4.0 → 1.5.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 +88 -49
- package/examples/animepahe/example_usage_searchAnime.js +10 -0
- package/examples/animesama/example_usage_getAllAnime.js +10 -0
- package/examples/animesama/example_usage_getAnimeInfo.js +11 -0
- package/examples/animesama/example_usage_getAvailableLanguages.js +11 -0
- package/examples/animesama/example_usage_getEmbed.js +11 -0
- package/examples/animesama/example_usage_getEpisodeTitles.js +11 -0
- package/examples/animesama/example_usage_getLatestEpisodes.js +10 -0
- package/examples/animesama/example_usage_getRandomAnime.js +10 -0
- package/examples/animesama/example_usage_getSeasons.js +11 -0
- package/examples/animesama/example_usage_searchAnime.js +10 -0
- package/examples/crunchyroll/example_usage_getEpisodeInfo.js +12 -0
- package/examples/crunchyroll/example_usage_searchAnime.js +11 -0
- package/examples/utility-functions/example_usage_getVideoUrlFromEmbed.js +11 -0
- package/package.json +1 -1
- package/scrapers/animesama.js +165 -108
- package/scrapers/scrapers.js +13 -12
- package/examples/example_usage_01.js +0 -23
- package/examples/example_usage_02.js +0 -14
- package/examples/example_usage_03.js +0 -9
- package/examples/example_usage_04.js +0 -13
- package/examples/example_usage_05.js +0 -13
package/DOCUMENTATION.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Ani-Scraped Documentation
|
|
1
|
+
# Better-Ani-Scraped Documentation
|
|
2
2
|
|
|
3
3
|
A set of utility functions for scraping anime data from multiple sources (only [anime-sama](https://anime-sama.fr) and [animepahe](https://animepahe.ru) available at the moment). This tool allows you to search for anime, retrieve information, get episodes, and more.
|
|
4
4
|
|
|
@@ -6,38 +6,45 @@ A set of utility functions for scraping anime data from multiple sources (only [
|
|
|
6
6
|
|
|
7
7
|
## Summary
|
|
8
8
|
- [Main class](#main-class)
|
|
9
|
-
- [`
|
|
10
|
-
- [`
|
|
11
|
-
- [`
|
|
12
|
-
- [
|
|
9
|
+
- [`AnimeScraper("animesama")` methods](#animescraperanimesama-methods)
|
|
10
|
+
- [`AnimeScraper("animepahe")` methods](#animescraperanimepahe-methods)
|
|
11
|
+
- [`AnimeScraper("crunchyroll")` methods](#animescrapercrunchyroll-methods)
|
|
12
|
+
- [Utility functions](#utility-functions)
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
## Main class
|
|
17
17
|
|
|
18
18
|
### `AnimeScraper(source)`
|
|
19
|
-
Creates a
|
|
19
|
+
Creates a scraper for the given source (only "animesama", "animepahe" and "crunchyroll" available at the moment).
|
|
20
|
+
```js
|
|
21
|
+
const animesama = new AnimeScraper('animesama') //for Anime Sama
|
|
22
|
+
const animepahe = new AnimeScraper('animepahe') //for Anime Pahe
|
|
23
|
+
const crunchyroll = new AnimeScraper('crunchyroll') //for Crunchyroll
|
|
24
|
+
```
|
|
20
25
|
|
|
21
26
|
---
|
|
22
27
|
|
|
23
|
-
## `
|
|
28
|
+
## `AnimeScraper("animesama")` methods
|
|
24
29
|
|
|
25
|
-
- [searchAnime](#animesamasearchanimequery-limit--10)
|
|
30
|
+
- [searchAnime](#animesamasearchanimequery-limit--10-wantedlanguages--vostfr-vf-vastfr-wantedtypes--anime-film)
|
|
26
31
|
- [getSeasons](#animesamagetseasonsanimeurl-language--vostfr)
|
|
27
|
-
- [
|
|
32
|
+
- [getEpisodeTitles](#animesamagetepisodetitlesseasonurl-customchromiumpath)
|
|
33
|
+
- [getEmbed](#animesamagetembedseasonurl-hostpriority--sibnet-vidmoly)
|
|
28
34
|
- [getAnimeInfo](#animesamagetanimeinfoanimeurl)
|
|
29
|
-
- [getAvailableLanguages](#animesamagetavailablelanguagesseasonurl-wantedlanguages--vostfr-vf-va-vkr-vcn-vqc)
|
|
30
|
-
- [getAllAnime](#
|
|
35
|
+
- [getAvailableLanguages](#animesamagetavailablelanguagesseasonurl-wantedlanguages--vostfr-vf-va-vkr-vcn-vqc-vf1-vf2-numberepisodes--false)
|
|
36
|
+
- [getAllAnime](#animesamagetallanimewantedlanguages--vostfr-vf-vastfr-wantedtypes--anime-film-page--null-output--anime_listjson-get_seasons--false)
|
|
31
37
|
- [getLatestEpisodes](#animesamagetlatestepisodeslanguagefilter--null)
|
|
32
|
-
- [getRandomAnime](#
|
|
33
|
-
- [getEpisodeTitles](#animesamagetepisodetitlesanimeurl-customChromiumPath)
|
|
38
|
+
- [getRandomAnime](#animesamagetrandomanimewantedlanguages--vostfr-vf-vastfr-wantedtypes--anime-film-maxattempts--null-attempt--0)
|
|
34
39
|
|
|
35
|
-
### `animesama.searchAnime(query, limit = 10)`
|
|
40
|
+
### `animesama.searchAnime(query, limit = 10, wantedLanguages = ["vostfr", "vf", "vastfr"], wantedTypes = ["Anime", "Film"])`
|
|
36
41
|
Searches for anime titles that match the given query.
|
|
37
42
|
|
|
38
43
|
- **Parameters:**
|
|
39
44
|
- `query` *(string)*: The search keyword.
|
|
40
45
|
- `limit` *(number)*: Maximum number of results to return (default: 10).
|
|
46
|
+
- `wantedLanguages` *(string[])*: Array of wanted languages.
|
|
47
|
+
- `wantedTypes` *(string[])*: Array of wanted types.
|
|
41
48
|
- **Returns:**
|
|
42
49
|
An array of anime objects:
|
|
43
50
|
```js
|
|
@@ -76,19 +83,34 @@ Fetches all available seasons of an anime in the specified language.
|
|
|
76
83
|
|
|
77
84
|
---
|
|
78
85
|
|
|
79
|
-
### `animesama.
|
|
86
|
+
### `animesama.getEpisodeTitles(seasonUrl, customChromiumPath)`
|
|
87
|
+
Fetches the names of all episodes in a season
|
|
88
|
+
|
|
89
|
+
- **Parameters:**
|
|
90
|
+
- `seasonUrl` *(string)*: URL of the anime’s season page.
|
|
91
|
+
- `customChromiumPath` *(string)*: Path of the Chromium folder
|
|
92
|
+
- **Returns:**
|
|
93
|
+
An array of episode titles.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
### `animesama.getEmbed(seasonUrl, hostPriority = ["sibnet", "vidmoly"])`
|
|
80
98
|
Retrieves embed URLs for episodes, prioritizing by host.
|
|
81
99
|
|
|
82
100
|
- **Parameters:**
|
|
83
|
-
- `
|
|
101
|
+
- `seasonUrl` *(string)*: URL of the anime’s season page.
|
|
84
102
|
- `hostPriority` *(string[])*: Array of preferred hostnames.
|
|
85
103
|
- **Returns:**
|
|
86
104
|
An array of embed video:
|
|
87
105
|
```js
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
106
|
+
[
|
|
107
|
+
{
|
|
108
|
+
title: string,
|
|
109
|
+
url: string,
|
|
110
|
+
}
|
|
111
|
+
...
|
|
112
|
+
]
|
|
113
|
+
|
|
92
114
|
```
|
|
93
115
|
---
|
|
94
116
|
|
|
@@ -111,19 +133,20 @@ Extracts basic information from an anime page.
|
|
|
111
133
|
|
|
112
134
|
---
|
|
113
135
|
|
|
114
|
-
### `animesama.getAvailableLanguages(seasonUrl, wantedLanguages = ["vostfr", "vf", "va", "vkr", "vcn", "vqc"])`
|
|
115
|
-
Checks which languages are available for a given anime season (
|
|
136
|
+
### `animesama.getAvailableLanguages(seasonUrl, wantedLanguages = ["vostfr", "vf", "va", "vkr", "vcn", "vqc", "vf1", "vf2"], numberEpisodes = false)`
|
|
137
|
+
Checks which languages are available for a given anime season (Avoid using `numberEpisodes = true`, as checking many languages significantly increases execution time).
|
|
116
138
|
|
|
117
139
|
- **Parameters:**
|
|
118
140
|
- `seasonUrl` *(string)*: The season anime URL.
|
|
119
141
|
- `wantedLanguages` *(string[])*: Language codes to check (e.g., ["vostfr", "vf", "va", ...]).
|
|
142
|
+
- `numberEpisodes` *(boolean)*: If `true`, also fetches the number of episodes in each language.
|
|
120
143
|
- **Returns:**
|
|
121
144
|
Array of objects containing available languages and their episode count:
|
|
122
145
|
```js
|
|
123
146
|
[
|
|
124
147
|
{
|
|
125
148
|
language: string,
|
|
126
|
-
episodeCount:
|
|
149
|
+
episodeCount: number //if numberEpisodes = true
|
|
127
150
|
}
|
|
128
151
|
...
|
|
129
152
|
]
|
|
@@ -131,14 +154,32 @@ Checks which languages are available for a given anime season (not recommended t
|
|
|
131
154
|
|
|
132
155
|
---
|
|
133
156
|
|
|
134
|
-
### `animesama.getAllAnime(output = "anime_list.json", get_seasons = false)`
|
|
157
|
+
### `animesama.getAllAnime(wantedLanguages = ["vostfr", "vf", "vastfr"], wantedTypes = ["Anime", "Film"], page = null, output = "anime_list.json", get_seasons = false)`
|
|
135
158
|
Fetches the full anime catalog, optionally including season information.
|
|
136
159
|
|
|
137
160
|
- **Parameters:**
|
|
161
|
+
- `wantedLanguages` *(string[])*: Language videos to get.
|
|
162
|
+
- `wantedTypes` *(string[])*: Types videos to get.
|
|
163
|
+
- `page` *(number)*: The catalog page number.
|
|
138
164
|
- `output` *(string)*: File name to save the result as JSON.
|
|
139
165
|
- `get_seasons` *(boolean)*: If `true`, also fetches seasons for each anime (very slow, ETA is still unknown).
|
|
140
166
|
- **Returns:**
|
|
141
|
-
`true` if successful, `false` otherwise.
|
|
167
|
+
if `page = null`, `true` if successful, `false` otherwise.
|
|
168
|
+
else, an array of anime objects :
|
|
169
|
+
```js
|
|
170
|
+
[
|
|
171
|
+
{
|
|
172
|
+
url: string,
|
|
173
|
+
title: string,
|
|
174
|
+
altTitles: string[],
|
|
175
|
+
cover: string,
|
|
176
|
+
genres: string[],
|
|
177
|
+
types: string[],
|
|
178
|
+
languages: string[],
|
|
179
|
+
}
|
|
180
|
+
...
|
|
181
|
+
]
|
|
182
|
+
```
|
|
142
183
|
|
|
143
184
|
---
|
|
144
185
|
|
|
@@ -150,20 +191,28 @@ Scrapes the latest released episodes, optionally filtered by language.
|
|
|
150
191
|
- **Returns:**
|
|
151
192
|
Array of episode objects:
|
|
152
193
|
```js
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
194
|
+
[
|
|
195
|
+
{
|
|
196
|
+
title: string,
|
|
197
|
+
url: string,
|
|
198
|
+
cover: string,
|
|
199
|
+
language: string,
|
|
200
|
+
episode: string
|
|
201
|
+
}
|
|
202
|
+
...
|
|
203
|
+
]
|
|
160
204
|
```
|
|
161
205
|
|
|
162
206
|
---
|
|
163
207
|
|
|
164
|
-
### `animesama.getRandomAnime()`
|
|
208
|
+
### `animesama.getRandomAnime(wantedLanguages = ["vostfr", "vf", "vastfr"], wantedTypes = ["Anime", "Film"], maxAttempts = null, attempt = 0)`
|
|
165
209
|
Fetches a random anime from the catalogue.
|
|
166
210
|
|
|
211
|
+
- **Parameters:**
|
|
212
|
+
- `wantedLanguages` *(string[])*: Language videos to get.
|
|
213
|
+
- `wantedTypes` *(string[])*: Types videos to get.
|
|
214
|
+
- `maxAttempts` *(number|null)* The number of attempts of the function. If null, retry until a result is obtained.
|
|
215
|
+
- `attempt` *(number)* Current number of attempts (leave empty).
|
|
167
216
|
- **Returns:**
|
|
168
217
|
An anime object:
|
|
169
218
|
```js
|
|
@@ -178,18 +227,8 @@ Fetches a random anime from the catalogue.
|
|
|
178
227
|
|
|
179
228
|
---
|
|
180
229
|
|
|
181
|
-
### `animesama.getEpisodeTitles(AnimeUrl, customChromiumPath)`
|
|
182
|
-
Fetches the names of all episodes in a season
|
|
183
|
-
|
|
184
|
-
- **Parameters:**
|
|
185
|
-
- `animeUrl` *(string)*: URL of the anime’s season/episode page.
|
|
186
|
-
- `animeUrl` *(string)*: Path of the Chromium folder
|
|
187
|
-
- **Returns:**
|
|
188
|
-
An array of episode titles.
|
|
189
|
-
|
|
190
|
-
---
|
|
191
230
|
|
|
192
|
-
## `
|
|
231
|
+
## `AnimeScraper("animepahe")` methods
|
|
193
232
|
|
|
194
233
|
- [searchAnime](#animepahesearchanimequery)
|
|
195
234
|
|
|
@@ -204,13 +243,13 @@ Searches for anime titles that match the given query.
|
|
|
204
243
|
```js
|
|
205
244
|
[
|
|
206
245
|
{
|
|
207
|
-
id:
|
|
246
|
+
id: number,
|
|
208
247
|
title: string,
|
|
209
248
|
type: string,
|
|
210
|
-
episodes:
|
|
249
|
+
episodes: number,
|
|
211
250
|
status: string,
|
|
212
251
|
season: string,
|
|
213
|
-
year:
|
|
252
|
+
year: number,
|
|
214
253
|
score: float,
|
|
215
254
|
session: string,
|
|
216
255
|
cover: string,
|
|
@@ -222,7 +261,7 @@ Searches for anime titles that match the given query.
|
|
|
222
261
|
|
|
223
262
|
---
|
|
224
263
|
|
|
225
|
-
## `
|
|
264
|
+
## `AnimeScraper("crunchyroll")` methods
|
|
226
265
|
|
|
227
266
|
- [searchAnime](#crunchyrollsearchanimequery-limit--10)
|
|
228
267
|
- [getEpisodeInfo](#crunchyrollgetepisodeinfoanimeurl-seasontitle)
|
|
@@ -268,7 +307,7 @@ Extracts information from all episodes of a season of an anime.
|
|
|
268
307
|
```
|
|
269
308
|
---
|
|
270
309
|
|
|
271
|
-
##
|
|
310
|
+
## Utility functions
|
|
272
311
|
|
|
273
312
|
- [getVideoUrlFromEmbed](#getvideourlfromembedsource-embedurl)
|
|
274
313
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AnimeScraper } from "../../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
+
|
|
3
|
+
const main = async () => {
|
|
4
|
+
const animepahe = new AnimeScraper('animepahe');
|
|
5
|
+
|
|
6
|
+
const search = await animepahe.searchAnime("86");
|
|
7
|
+
console.log("Search Results:", search);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AnimeScraper } from "../../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
+
|
|
3
|
+
const main = async () => {
|
|
4
|
+
const animesama = new AnimeScraper('animesama');
|
|
5
|
+
|
|
6
|
+
const catalogue = await animesama.getAllAnime(["vostfr", "vf", "vastfr"], ["Anime", "Film"], 2);
|
|
7
|
+
console.log(catalogue)
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AnimeScraper } from "../../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
+
|
|
3
|
+
const main = async () => {
|
|
4
|
+
const animesama = new AnimeScraper('animesama');
|
|
5
|
+
const animeUrl = "https://anime-sama.fr/catalogue/86-eighty-six/";
|
|
6
|
+
|
|
7
|
+
const animeInfo = await animesama.getAnimeInfo(animeUrl);
|
|
8
|
+
console.log(animeInfo);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AnimeScraper } from "../../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
+
|
|
3
|
+
const main = async () => {
|
|
4
|
+
const animesama = new AnimeScraper('animesama');
|
|
5
|
+
const seasonUrl = "https://anime-sama.fr/catalogue/86-eighty-six/saison1/vostfr/";
|
|
6
|
+
|
|
7
|
+
const animeLanguages = await animesama.getAvailableLanguages(seasonUrl, ["vostfr", "vf", "va", "vkr","vcn", "vqc", "vf1", "vf2"], false);
|
|
8
|
+
console.log(animeLanguages);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AnimeScraper } from "../../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
+
|
|
3
|
+
const main = async () => {
|
|
4
|
+
const animesama = new AnimeScraper('animesama');
|
|
5
|
+
const seasonUrl = "https://anime-sama.fr/catalogue/86-eighty-six/saison1/vostfr/";
|
|
6
|
+
|
|
7
|
+
const embeds = await animesama.getEmbed(seasonUrl, ["sibnet", "vidmoly"]);
|
|
8
|
+
console.log("Embed Links:", embeds);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AnimeScraper } from "../../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
+
|
|
3
|
+
const main = async () => {
|
|
4
|
+
const animesama = new AnimeScraper('animesama');
|
|
5
|
+
const seasonUrl = "https://anime-sama.fr/catalogue/86-eighty-six/saison1/vostfr/";
|
|
6
|
+
|
|
7
|
+
const episodeTitles = await animesama.getEpisodeTitles(seasonUrl);
|
|
8
|
+
console.log("Episode Titles:", episodeTitles);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AnimeScraper } from "../../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
+
|
|
3
|
+
const main = async () => {
|
|
4
|
+
const animesama = new AnimeScraper('animesama');
|
|
5
|
+
|
|
6
|
+
const new_episodes = await animesama.getLatestEpisodes(["vostfr", "vf"]);
|
|
7
|
+
console.log(new_episodes);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AnimeScraper } from "../../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
+
|
|
3
|
+
const main = async () => {
|
|
4
|
+
const animesama = new AnimeScraper('animesama');
|
|
5
|
+
|
|
6
|
+
const random_episode = await animesama.getRandomAnime(["vostfr", "vf", "vastfr"], ["Anime", "Film"], 10);
|
|
7
|
+
console.log(random_episode);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AnimeScraper, getVideoUrlFromEmbed } from "../../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
+
|
|
3
|
+
const main = async () => {
|
|
4
|
+
const animesama = new AnimeScraper('animesama');
|
|
5
|
+
const animeUrl = "https://anime-sama.fr/catalogue/86-eighty-six/";
|
|
6
|
+
|
|
7
|
+
const seasons = await animesama.getSeasons(animeUrl, "vostfr");
|
|
8
|
+
console.log("Seasons:", seasons);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AnimeScraper } from "../../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
+
|
|
3
|
+
const main = async () => {
|
|
4
|
+
const animesama = new AnimeScraper('animesama');
|
|
5
|
+
|
|
6
|
+
const search = await animesama.searchAnime("86", 3, ["vostfr", "vf", "vastfr"], ["Anime", "Film"]);
|
|
7
|
+
console.log("Search Results:", search);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AnimeScraper } from "../../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
+
|
|
3
|
+
const main = async () => {
|
|
4
|
+
const crunchyroll = new AnimeScraper('crunchyroll');
|
|
5
|
+
const animeUrl = "https://www.crunchyroll.com/fr/series/GVDHX8DM5/86-eighty-six/";
|
|
6
|
+
|
|
7
|
+
const episodeInfo = await crunchyroll.getEpisodeInfo(animeUrl, "S2")
|
|
8
|
+
console.log("Episode Info:", episodeInfo)
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
main().catch(console.error);
|
|
12
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AnimeScraper } from "../../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
+
|
|
3
|
+
const main = async () => {
|
|
4
|
+
const crunchyroll = new AnimeScraper('crunchyroll');
|
|
5
|
+
|
|
6
|
+
const search = await crunchyroll.searchAnime("86", 3);
|
|
7
|
+
console.log("Search Results:", search);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
main().catch(console.error);
|
|
11
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { getVideoUrlFromEmbed } from "../../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
+
|
|
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);
|
|
8
|
+
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
main().catch(console.error);
|
package/package.json
CHANGED
package/scrapers/animesama.js
CHANGED
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import * as cheerio from "cheerio";
|
|
3
3
|
import fs from "fs";
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { exec as execCallback } from 'child_process';
|
|
6
|
+
import { promisify } from 'util';
|
|
7
|
+
const execAsync = promisify(execCallback);
|
|
8
|
+
|
|
4
9
|
|
|
5
10
|
const BASE_URL = "https://anime-sama.fr";
|
|
6
11
|
const CATALOGUE_URL = `${BASE_URL}/catalogue`;
|
|
7
12
|
|
|
13
|
+
async function ensureChromiumInstalled(customPath) {
|
|
14
|
+
if (customPath) {
|
|
15
|
+
if (fs.existsSync(customPath)) {
|
|
16
|
+
console.log("customPath:", customPath);
|
|
17
|
+
return customPath;
|
|
18
|
+
} else {
|
|
19
|
+
console.log(`The custom path to Chromium is invalid : ${customPath}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const basePath = path.join(
|
|
23
|
+
process.env.HOME || process.env.USERPROFILE,
|
|
24
|
+
'.cache',
|
|
25
|
+
'puppeteer',
|
|
26
|
+
'chrome'
|
|
27
|
+
);
|
|
28
|
+
const chromiumPath = path.join(basePath, 'win64-135.0.7049.95', 'chrome-win64', 'chrome.exe');
|
|
29
|
+
|
|
30
|
+
if (!fs.existsSync(chromiumPath)) {
|
|
31
|
+
console.log("📦 Downloading Chromium 135.0.7049.95...");
|
|
32
|
+
await execAsync('npx puppeteer browsers install chrome@135.0.7049.95');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return chromiumPath;
|
|
36
|
+
}
|
|
37
|
+
|
|
8
38
|
function getHeaders(referer = BASE_URL) {
|
|
9
39
|
return {
|
|
10
40
|
"User-Agent": "Mozilla/5.0",
|
|
@@ -13,10 +43,17 @@ function getHeaders(referer = BASE_URL) {
|
|
|
13
43
|
};
|
|
14
44
|
}
|
|
15
45
|
|
|
16
|
-
export async function searchAnime(
|
|
17
|
-
|
|
46
|
+
export async function searchAnime(
|
|
47
|
+
query,
|
|
48
|
+
limit = 10,
|
|
49
|
+
wantedLanguages = ["vostfr", "vf", "vastfr"],
|
|
50
|
+
wantedTypes = ["Anime", "Film"]
|
|
51
|
+
) {
|
|
52
|
+
const url = `${CATALOGUE_URL}/?search=${encodeURIComponent(
|
|
18
53
|
query
|
|
19
54
|
)}`;
|
|
55
|
+
const isWanted = (text, list) =>
|
|
56
|
+
list.some(item => text.toLowerCase().includes(item.toLowerCase()));
|
|
20
57
|
const res = await axios.get(url, { headers: getHeaders(CATALOGUE_URL) });
|
|
21
58
|
const $ = cheerio.load(res.data);
|
|
22
59
|
const results = [];
|
|
@@ -34,6 +71,14 @@ export async function searchAnime(query, limit = 10) {
|
|
|
34
71
|
.trim();
|
|
35
72
|
const cover = anchor.find("img").first().attr("src");
|
|
36
73
|
|
|
74
|
+
const tagText = anchor.find("p").filter((_, p) =>
|
|
75
|
+
isWanted($(p).text(), wantedTypes)
|
|
76
|
+
).first().text();
|
|
77
|
+
|
|
78
|
+
const languageText = anchor.find("p").filter((_, p) =>
|
|
79
|
+
isWanted($(p).text(), wantedLanguages)
|
|
80
|
+
).first().text();
|
|
81
|
+
|
|
37
82
|
const altTitles = altRaw
|
|
38
83
|
? altRaw
|
|
39
84
|
.split(",")
|
|
@@ -53,7 +98,7 @@ export async function searchAnime(query, limit = 10) {
|
|
|
53
98
|
.filter(Boolean)
|
|
54
99
|
: [];
|
|
55
100
|
|
|
56
|
-
if (title && link) {
|
|
101
|
+
if (title && link && tagText && languageText) {
|
|
57
102
|
results.push({
|
|
58
103
|
title,
|
|
59
104
|
altTitles,
|
|
@@ -123,37 +168,7 @@ export async function getSeasons(animeUrl, language = "vostfr") {
|
|
|
123
168
|
return seasons;
|
|
124
169
|
}
|
|
125
170
|
|
|
126
|
-
|
|
127
|
-
import path from 'path';
|
|
128
|
-
import { exec as execCallback } from 'child_process';
|
|
129
|
-
import { promisify } from 'util';
|
|
130
|
-
const execAsync = promisify(execCallback);
|
|
131
|
-
|
|
132
|
-
async function ensureChromiumInstalled(customPath) {
|
|
133
|
-
if (customPath) {
|
|
134
|
-
if (fs.existsSync(customPath)) {
|
|
135
|
-
console.log("customPath:", customPath);
|
|
136
|
-
return customPath;
|
|
137
|
-
} else {
|
|
138
|
-
console.log(`The custom path to Chromium is invalid : ${customPath}`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
const basePath = path.join(
|
|
142
|
-
process.env.HOME || process.env.USERPROFILE,
|
|
143
|
-
'.cache',
|
|
144
|
-
'puppeteer',
|
|
145
|
-
'chrome'
|
|
146
|
-
);
|
|
147
|
-
const chromiumPath = path.join(basePath, 'win64-135.0.7049.95', 'chrome-win64', 'chrome.exe');
|
|
148
|
-
|
|
149
|
-
if (!fs.existsSync(chromiumPath)) {
|
|
150
|
-
console.log("📦 Downloading Chromium 135.0.7049.95...");
|
|
151
|
-
await execAsync('npx puppeteer browsers install chrome@135.0.7049.95');
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return chromiumPath;
|
|
155
|
-
}
|
|
156
|
-
export async function getEpisodeTitles(animeUrl, customChromiumPath) {
|
|
171
|
+
export async function getEpisodeTitles(seasonUrl, customChromiumPath) {
|
|
157
172
|
let browser;
|
|
158
173
|
try {
|
|
159
174
|
const puppeteer = await import('puppeteer');
|
|
@@ -177,7 +192,7 @@ export async function getEpisodeTitles(animeUrl, customChromiumPath) {
|
|
|
177
192
|
}
|
|
178
193
|
});
|
|
179
194
|
|
|
180
|
-
await page.goto(
|
|
195
|
+
await page.goto(seasonUrl, { waitUntil: 'domcontentloaded' });
|
|
181
196
|
await page.waitForSelector('#selectEpisodes');
|
|
182
197
|
|
|
183
198
|
const titres = await page.$$eval('#selectEpisodes option', options =>
|
|
@@ -194,22 +209,21 @@ export async function getEpisodeTitles(animeUrl, customChromiumPath) {
|
|
|
194
209
|
}
|
|
195
210
|
}
|
|
196
211
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
headers: getHeaders(animeUrl.split("/").slice(0, 5).join("/")),
|
|
212
|
+
export async function getEmbed(seasonUrl, hostPriority = ["sibnet", "vidmoly"], customChromiumPath) {
|
|
213
|
+
const res = await axios.get(seasonUrl, {
|
|
214
|
+
headers: getHeaders(seasonUrl.split("/").slice(0, 5).join("/")),
|
|
201
215
|
});
|
|
202
216
|
|
|
203
217
|
const $ = cheerio.load(res.data);
|
|
204
218
|
const scriptTag = $('script[src*="episodes.js"]').attr("src");
|
|
205
219
|
if (!scriptTag) throw new Error("No episodes script found");
|
|
206
220
|
|
|
207
|
-
const scriptUrl =
|
|
208
|
-
?
|
|
209
|
-
:
|
|
221
|
+
const scriptUrl = seasonUrl.endsWith("/")
|
|
222
|
+
? seasonUrl + scriptTag
|
|
223
|
+
: seasonUrl + "/" + scriptTag;
|
|
210
224
|
|
|
211
225
|
const episodesJs = await axios
|
|
212
|
-
.get(scriptUrl, { headers: getHeaders(
|
|
226
|
+
.get(scriptUrl, { headers: getHeaders(seasonUrl) })
|
|
213
227
|
.then((r) => r.data);
|
|
214
228
|
|
|
215
229
|
const matches = [
|
|
@@ -243,14 +257,13 @@ export async function getEmbed(animeUrl, hostPriority = ["vidmoly"], customChrom
|
|
|
243
257
|
finalEmbeds.push(selectedUrl || null);
|
|
244
258
|
}
|
|
245
259
|
|
|
246
|
-
const titles = await getEpisodeTitles(
|
|
260
|
+
const titles = await getEpisodeTitles(seasonUrl, customChromiumPath);
|
|
247
261
|
return finalEmbeds.map((url, i) => ({
|
|
248
262
|
title: titles[i] || "Untitled",
|
|
249
263
|
url,
|
|
250
264
|
}));
|
|
251
265
|
}
|
|
252
266
|
|
|
253
|
-
|
|
254
267
|
export async function getAnimeInfo(animeUrl) {
|
|
255
268
|
const res = await axios.get(animeUrl, { headers: getHeaders(CATALOGUE_URL) });
|
|
256
269
|
const $ = cheerio.load(res.data);
|
|
@@ -285,7 +298,8 @@ export async function getAnimeInfo(animeUrl) {
|
|
|
285
298
|
|
|
286
299
|
export async function getAvailableLanguages(
|
|
287
300
|
seasonUrl,
|
|
288
|
-
wantedLanguages = ["vostfr", "vf", "va", "vkr", "vcn", "vqc"]
|
|
301
|
+
wantedLanguages = ["vostfr", "vf", "va", "vkr", "vcn", "vqc", "vf1", "vf2"],
|
|
302
|
+
numberEpisodes = false
|
|
289
303
|
) {
|
|
290
304
|
const languageLinks = [];
|
|
291
305
|
|
|
@@ -297,87 +311,109 @@ export async function getAvailableLanguages(
|
|
|
297
311
|
headers: getHeaders(CATALOGUE_URL),
|
|
298
312
|
});
|
|
299
313
|
if (res.status === 200) {
|
|
300
|
-
|
|
301
|
-
|
|
314
|
+
if (numberEpisodes){
|
|
315
|
+
const episodeCount = (await getEmbed(languageUrl)).length;
|
|
316
|
+
languageLinks.push({ language: language.toUpperCase(), episodeCount: episodeCount });
|
|
317
|
+
} else {
|
|
318
|
+
languageLinks.push({ language: language.toUpperCase()});
|
|
319
|
+
}
|
|
320
|
+
|
|
302
321
|
}
|
|
303
322
|
} catch (error) {
|
|
304
323
|
// If an error occurs (like a 404), we skip that language
|
|
305
324
|
continue;
|
|
306
325
|
}
|
|
307
326
|
}
|
|
308
|
-
|
|
309
327
|
return languageLinks;
|
|
310
328
|
}
|
|
311
329
|
|
|
312
330
|
export async function getAllAnime(
|
|
331
|
+
wantedLanguages = ["vostfr", "vf", "vastfr"],
|
|
332
|
+
wantedTypes = ["Anime", "Film"],
|
|
333
|
+
page = null,
|
|
313
334
|
output = "anime_list.json",
|
|
314
335
|
get_seasons = false
|
|
315
336
|
) {
|
|
316
|
-
// BE CAREFUL, GET_SEASONS TAKES A VERY VERY LONG TIME TO FINISH
|
|
317
337
|
let animeLinks = [];
|
|
318
|
-
let page = 1;
|
|
319
338
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
const url = page === 1 ? CATALOGUE_URL : `${CATALOGUE_URL}?page=${page}`;
|
|
323
|
-
const res = await axios.get(url, { headers: getHeaders(CATALOGUE_URL) });
|
|
324
|
-
const $ = cheerio.load(res.data);
|
|
325
|
-
|
|
326
|
-
const containers = $("div.shrink-0.m-3.rounded.border-2");
|
|
339
|
+
const isWanted = (text, list) =>
|
|
340
|
+
list.some(item => text.toLowerCase().includes(item.toLowerCase()));
|
|
327
341
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
342
|
+
const fetchPage = async (pageNum) => {
|
|
343
|
+
const url = pageNum === 1 ? CATALOGUE_URL : `${CATALOGUE_URL}?page=${pageNum}`;
|
|
344
|
+
const res = await axios.get(url, { headers: getHeaders(CATALOGUE_URL) });
|
|
345
|
+
const $ = cheerio.load(res.data);
|
|
346
|
+
|
|
347
|
+
const containers = $("div.shrink-0.m-3.rounded.border-2");
|
|
348
|
+
|
|
349
|
+
containers.each((_, el) => {
|
|
350
|
+
const anchor = $(el).find("a");
|
|
351
|
+
const title = anchor.find("h1").text().trim();
|
|
352
|
+
const link = anchor.attr("href");
|
|
353
|
+
const img = anchor.find("img").attr("src");
|
|
354
|
+
|
|
355
|
+
const paragraphs = anchor.find("p").toArray().map(p => $(p).text().trim());
|
|
356
|
+
|
|
357
|
+
const altTitles = paragraphs[0] ? paragraphs[0].split(',').map(name => name.trim()) : [];
|
|
358
|
+
const genres = paragraphs[1] ? paragraphs[1].split(',').map(genre => genre.trim()) : [];
|
|
359
|
+
const type = paragraphs[2] ? paragraphs[2].split(',').map(t => t.trim()) : [];
|
|
360
|
+
const language = paragraphs[3] ? paragraphs[3].split(',').map(lang => lang.trim()) : [];
|
|
361
|
+
const filteredTypes = type.filter(t => isWanted(t, wantedTypes));
|
|
362
|
+
const filteredLanguages = language.filter(lang => isWanted(lang, wantedLanguages));
|
|
363
|
+
if (
|
|
364
|
+
title &&
|
|
365
|
+
link &&
|
|
366
|
+
filteredTypes.length > 0 &&
|
|
367
|
+
filteredLanguages.length > 0
|
|
368
|
+
) {
|
|
369
|
+
const fullUrl = link.startsWith("http") ? link : `${BASE_URL}${link}`;
|
|
370
|
+
animeLinks.push({
|
|
371
|
+
url: fullUrl,
|
|
372
|
+
title,
|
|
373
|
+
altTitles,
|
|
374
|
+
cover: img,
|
|
375
|
+
genres,
|
|
376
|
+
types: filteredTypes,
|
|
377
|
+
languages: filteredLanguages,
|
|
378
|
+
});
|
|
331
379
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
}
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
page++;
|
|
351
|
-
await new Promise((r) => setTimeout(r, 300));
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
return containers.length > 0;
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
const enrichWithSeasons = async (list) => {
|
|
386
|
+
for (const anime of list) {
|
|
387
|
+
try {
|
|
388
|
+
const seasons = await getSeasons(anime.url);
|
|
389
|
+
anime.seasons = Array.isArray(seasons) ? seasons : [];
|
|
390
|
+
} catch (err) {
|
|
391
|
+
console.warn(`⚠️ Failed to fetch seasons for ${anime.title}: ${err.message}`);
|
|
392
|
+
anime.seasons = [];
|
|
393
|
+
}
|
|
394
|
+
await new Promise(r => setTimeout(r, 300));
|
|
352
395
|
}
|
|
396
|
+
};
|
|
353
397
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
398
|
+
try {
|
|
399
|
+
if (page) {
|
|
400
|
+
await fetchPage(page);
|
|
401
|
+
if (get_seasons) await enrichWithSeasons(animeLinks);
|
|
402
|
+
return animeLinks;
|
|
403
|
+
} else {
|
|
404
|
+
let currentPage = 1;
|
|
405
|
+
while (await fetchPage(currentPage++)) {
|
|
406
|
+
await new Promise(r => setTimeout(r, 300));
|
|
407
|
+
}
|
|
358
408
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
for (let anime of uniqueLinks) {
|
|
362
|
-
try {
|
|
363
|
-
const seasons = await getSeasons(anime.url);
|
|
364
|
-
anime.seasons = Array.isArray(seasons) ? seasons : [];
|
|
365
|
-
} catch (err) {
|
|
366
|
-
console.warn(
|
|
367
|
-
`⚠️ Failed to fetch seasons for ${anime.name}: ${err.message}`
|
|
368
|
-
);
|
|
369
|
-
anime.seasons = [];
|
|
370
|
-
}
|
|
409
|
+
const uniqueLinks = [...new Map(animeLinks.map(item => [item.url, item])).values()];
|
|
410
|
+
if (get_seasons) await enrichWithSeasons(uniqueLinks);
|
|
371
411
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
}
|
|
412
|
+
fs.writeFileSync(output, JSON.stringify(uniqueLinks, null, 2), "utf-8");
|
|
413
|
+
return true;
|
|
375
414
|
}
|
|
376
|
-
|
|
377
|
-
fs.writeFileSync(output, JSON.stringify(uniqueLinks, null, 2), "utf-8");
|
|
378
|
-
return true;
|
|
379
415
|
} catch (err) {
|
|
380
|
-
console.error("
|
|
416
|
+
console.error("error :", err.message);
|
|
381
417
|
return false;
|
|
382
418
|
}
|
|
383
419
|
}
|
|
@@ -424,13 +460,21 @@ export async function getLatestEpisodes(languageFilter = null) {
|
|
|
424
460
|
}
|
|
425
461
|
}
|
|
426
462
|
|
|
427
|
-
export async function getRandomAnime(
|
|
463
|
+
export async function getRandomAnime(
|
|
464
|
+
wantedLanguages = ["vostfr", "vf", "vastfr"],
|
|
465
|
+
wantedTypes = ["Anime", "Film"],
|
|
466
|
+
maxAttempts = null,
|
|
467
|
+
attempt = 0
|
|
468
|
+
) {
|
|
428
469
|
try {
|
|
429
470
|
const res = await axios.get(
|
|
430
|
-
`${CATALOGUE_URL}/?
|
|
471
|
+
`${CATALOGUE_URL}/?search=&random=1`,
|
|
431
472
|
{ headers: getHeaders(CATALOGUE_URL) }
|
|
432
473
|
);
|
|
474
|
+
|
|
433
475
|
const $ = cheerio.load(res.data);
|
|
476
|
+
const isWanted = (text, list) =>
|
|
477
|
+
list.some(item => text.toLowerCase().includes(item.toLowerCase()));
|
|
434
478
|
|
|
435
479
|
const container = $("div.shrink-0.m-3.rounded.border-2").first();
|
|
436
480
|
const anchor = container.find("a");
|
|
@@ -463,7 +507,15 @@ export async function getRandomAnime() {
|
|
|
463
507
|
.filter(Boolean)
|
|
464
508
|
: [];
|
|
465
509
|
|
|
466
|
-
|
|
510
|
+
const tagText = anchor.find("p").filter((_, p) =>
|
|
511
|
+
isWanted($(p).text(), wantedTypes)
|
|
512
|
+
).first().text();
|
|
513
|
+
|
|
514
|
+
const languageText = anchor.find("p").filter((_, p) =>
|
|
515
|
+
isWanted($(p).text(), wantedLanguages)
|
|
516
|
+
).first().text();
|
|
517
|
+
|
|
518
|
+
if (title && link && tagText && languageText) {
|
|
467
519
|
return {
|
|
468
520
|
title,
|
|
469
521
|
altTitles,
|
|
@@ -472,10 +524,15 @@ export async function getRandomAnime() {
|
|
|
472
524
|
cover,
|
|
473
525
|
};
|
|
474
526
|
} else {
|
|
475
|
-
|
|
527
|
+
if (maxAttempts === null || attempt < maxAttempts) {
|
|
528
|
+
return await getRandomAnime(wantedLanguages, wantedTypes, maxAttempts, attempt + 1);
|
|
529
|
+
} else {
|
|
530
|
+
throw new Error("Max attempts reached without finding a valid anime.");
|
|
531
|
+
}
|
|
476
532
|
}
|
|
477
533
|
} catch (err) {
|
|
478
534
|
console.error("Failed to fetch random anime:", err.message);
|
|
479
535
|
return null;
|
|
480
536
|
}
|
|
481
537
|
}
|
|
538
|
+
|
package/scrapers/scrapers.js
CHANGED
|
@@ -33,9 +33,18 @@ export class AnimeScraper {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
async
|
|
36
|
+
async getEpisodeTitles(seasonUrl, ...rest) {
|
|
37
37
|
try {
|
|
38
|
-
return await this.source.
|
|
38
|
+
return await this.source.getEpisodeTitles(seasonUrl, ...rest);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error(`This scraper does not have the getEpisodeTitles function implemented or an error happened -> ${error}`);
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async getEmbed(seasonUrl, ...rest) {
|
|
46
|
+
try {
|
|
47
|
+
return await this.source.getEmbed(seasonUrl, ...rest);
|
|
39
48
|
} catch (error) {
|
|
40
49
|
console.error(`This scraper does not have the getEmbed function implemented or an error happened -> ${error}`);
|
|
41
50
|
return null;
|
|
@@ -78,23 +87,15 @@ export class AnimeScraper {
|
|
|
78
87
|
}
|
|
79
88
|
}
|
|
80
89
|
|
|
81
|
-
async getRandomAnime() {
|
|
90
|
+
async getRandomAnime(...rest) {
|
|
82
91
|
try {
|
|
83
|
-
return await this.source.getRandomAnime();
|
|
92
|
+
return await this.source.getRandomAnime(...rest);
|
|
84
93
|
} catch (error) {
|
|
85
94
|
console.error(`This scraper does not have the getRandomAnime function implemented or an error happened -> ${error}`);
|
|
86
95
|
return null;
|
|
87
96
|
}
|
|
88
97
|
}
|
|
89
98
|
|
|
90
|
-
async getEpisodeTitles(animeUrl, ...rest) {
|
|
91
|
-
try {
|
|
92
|
-
return await this.source.getEpisodeTitles(animeUrl, ...rest);
|
|
93
|
-
} catch (error) {
|
|
94
|
-
console.error(`This scraper does not have the getEpisodeTitles function implemented or an error happened -> ${error}`);
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
99
|
async getEpisodeInfo(animeUrl, ...rest) {
|
|
99
100
|
try {
|
|
100
101
|
return await this.source.getEpisodeInfo(animeUrl, ...rest);
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { AnimeScraper, getVideoUrlFromEmbed } from "../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
-
|
|
3
|
-
const main = async () => {
|
|
4
|
-
const scraper = new AnimeScraper('animesama');
|
|
5
|
-
|
|
6
|
-
const search = await scraper.searchAnime("86");
|
|
7
|
-
console.log("Search Results:", search);
|
|
8
|
-
|
|
9
|
-
const animeUrl = Object.values(search)[0].url;
|
|
10
|
-
const seasons = await scraper.getSeasons(animeUrl, "vostfr");
|
|
11
|
-
console.log("Seasons:", seasons);
|
|
12
|
-
|
|
13
|
-
const embeds = await scraper.getEmbed(seasons[0].url, [
|
|
14
|
-
"sibnet",
|
|
15
|
-
"vidmoly",
|
|
16
|
-
]);
|
|
17
|
-
console.log("Embed Links:", embeds);
|
|
18
|
-
|
|
19
|
-
const videoUrl = await getVideoUrlFromEmbed("sibnet", embeds[0].url)
|
|
20
|
-
console.log("Video URL:", videoUrl);
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
main().catch(console.error);
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { AnimeScraper } from "../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
-
|
|
3
|
-
const main = async () => {
|
|
4
|
-
const scraper = new AnimeScraper('animesama');
|
|
5
|
-
|
|
6
|
-
const animeUrl = "https://anime-sama.fr/catalogue/sword-art-online";
|
|
7
|
-
const animeInfo = await scraper.getAnimeInfo(animeUrl);
|
|
8
|
-
console.log(animeInfo);
|
|
9
|
-
|
|
10
|
-
const animeLanguages = await scraper.getAvailableLanguages(`${animeUrl}/saison1/vostfr`, ["vostfr", "vf"]);
|
|
11
|
-
console.log(animeLanguages);
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
main().catch(console.error);
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { AnimeScraper } from "../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
-
|
|
3
|
-
const main = async () => {
|
|
4
|
-
const scraper = new AnimeScraper('animesama');
|
|
5
|
-
|
|
6
|
-
await scraper.getAllAnime("output_anime_list.json", false);
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
main().catch(console.error);
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { AnimeScraper } from "../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
-
|
|
3
|
-
const main = async () => {
|
|
4
|
-
const scraper = new AnimeScraper('animesama');
|
|
5
|
-
|
|
6
|
-
const new_episodes = await scraper.getLatestEpisodes(["vostfr", "vf"]);
|
|
7
|
-
console.log(new_episodes);
|
|
8
|
-
|
|
9
|
-
const random_episode = await scraper.getRandomAnime();
|
|
10
|
-
console.log(random_episode);
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
main().catch(console.error);
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { AnimeScraper } from "../index.js"; // REPLACE BY "from 'better-ani-scraped';"
|
|
2
|
-
|
|
3
|
-
const main = async () => {
|
|
4
|
-
const scraper = new AnimeScraper('crunchyroll');
|
|
5
|
-
const search = await scraper.searchAnime("86");
|
|
6
|
-
console.log("Search Results:", search);
|
|
7
|
-
|
|
8
|
-
const episodeInfo = await scraper.getEpisodeInfo(search[0].url, "S2")
|
|
9
|
-
console.log("Episode Info:", episodeInfo)
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
main().catch(console.error);
|
|
13
|
-
|