better-ani-scraped 1.4.0 → 1.5.0
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 +83 -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_getVideoUrlFromEmbed.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/package.json +1 -1
- package/scrapers/animesama.js +148 -104
- 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,27 @@ 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
|
+
title: string,
|
|
173
|
+
url: string,
|
|
174
|
+
}
|
|
175
|
+
...
|
|
176
|
+
]
|
|
177
|
+
```
|
|
142
178
|
|
|
143
179
|
---
|
|
144
180
|
|
|
@@ -150,20 +186,28 @@ Scrapes the latest released episodes, optionally filtered by language.
|
|
|
150
186
|
- **Returns:**
|
|
151
187
|
Array of episode objects:
|
|
152
188
|
```js
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
189
|
+
[
|
|
190
|
+
{
|
|
191
|
+
title: string,
|
|
192
|
+
url: string,
|
|
193
|
+
cover: string,
|
|
194
|
+
language: string,
|
|
195
|
+
episode: string
|
|
196
|
+
}
|
|
197
|
+
...
|
|
198
|
+
]
|
|
160
199
|
```
|
|
161
200
|
|
|
162
201
|
---
|
|
163
202
|
|
|
164
|
-
### `animesama.getRandomAnime()`
|
|
203
|
+
### `animesama.getRandomAnime(wantedLanguages = ["vostfr", "vf", "vastfr"], wantedTypes = ["Anime", "Film"], maxAttempts = null, attempt = 0)`
|
|
165
204
|
Fetches a random anime from the catalogue.
|
|
166
205
|
|
|
206
|
+
- **Parameters:**
|
|
207
|
+
- `wantedLanguages` *(string[])*: Language videos to get.
|
|
208
|
+
- `wantedTypes` *(string[])*: Types videos to get.
|
|
209
|
+
- `maxAttempts` *(number|null)* The number of attempts of the function. If null, retry until a result is obtained.
|
|
210
|
+
- `attempt` *(number)* Current number of attempts (leave empty).
|
|
167
211
|
- **Returns:**
|
|
168
212
|
An anime object:
|
|
169
213
|
```js
|
|
@@ -178,18 +222,8 @@ Fetches a random anime from the catalogue.
|
|
|
178
222
|
|
|
179
223
|
---
|
|
180
224
|
|
|
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
225
|
|
|
192
|
-
## `
|
|
226
|
+
## `AnimeScraper("animepahe")` methods
|
|
193
227
|
|
|
194
228
|
- [searchAnime](#animepahesearchanimequery)
|
|
195
229
|
|
|
@@ -204,13 +238,13 @@ Searches for anime titles that match the given query.
|
|
|
204
238
|
```js
|
|
205
239
|
[
|
|
206
240
|
{
|
|
207
|
-
id:
|
|
241
|
+
id: number,
|
|
208
242
|
title: string,
|
|
209
243
|
type: string,
|
|
210
|
-
episodes:
|
|
244
|
+
episodes: number,
|
|
211
245
|
status: string,
|
|
212
246
|
season: string,
|
|
213
|
-
year:
|
|
247
|
+
year: number,
|
|
214
248
|
score: float,
|
|
215
249
|
session: string,
|
|
216
250
|
cover: string,
|
|
@@ -222,7 +256,7 @@ Searches for anime titles that match the given query.
|
|
|
222
256
|
|
|
223
257
|
---
|
|
224
258
|
|
|
225
|
-
## `
|
|
259
|
+
## `AnimeScraper("crunchyroll")` methods
|
|
226
260
|
|
|
227
261
|
- [searchAnime](#crunchyrollsearchanimequery-limit--10)
|
|
228
262
|
- [getEpisodeInfo](#crunchyrollgetepisodeinfoanimeurl-seasontitle)
|
|
@@ -268,7 +302,7 @@ Extracts information from all episodes of a season of an anime.
|
|
|
268
302
|
```
|
|
269
303
|
---
|
|
270
304
|
|
|
271
|
-
##
|
|
305
|
+
## Utility functions
|
|
272
306
|
|
|
273
307
|
- [getVideoUrlFromEmbed](#getvideourlfromembedsource-embedurl)
|
|
274
308
|
|
|
@@ -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,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);
|
|
@@ -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
|
+
|
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,96 @@ 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);
|
|
339
|
+
const isWanted = (text, list) =>
|
|
340
|
+
list.some(item => text.toLowerCase().includes(item.toLowerCase()));
|
|
325
341
|
|
|
326
|
-
|
|
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);
|
|
327
346
|
|
|
328
|
-
|
|
329
|
-
// console.log("No more anime found, stopping.");
|
|
330
|
-
break;
|
|
331
|
-
}
|
|
347
|
+
const containers = $("div.shrink-0.m-3.rounded.border-2");
|
|
332
348
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
349
|
+
containers.each((_, el) => {
|
|
350
|
+
const anchor = $(el).find("a");
|
|
351
|
+
const title = anchor.find("h1").text().trim();
|
|
352
|
+
const link = anchor.attr("href");
|
|
337
353
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
.first()
|
|
342
|
-
.text();
|
|
354
|
+
const tagText = anchor.find("p").filter((_, p) =>
|
|
355
|
+
isWanted($(p).text(), wantedTypes)
|
|
356
|
+
).first().text();
|
|
343
357
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
}
|
|
348
|
-
});
|
|
358
|
+
const languageText = anchor.find("p").filter((_, p) =>
|
|
359
|
+
isWanted($(p).text(), wantedLanguages)
|
|
360
|
+
).first().text();
|
|
349
361
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
const uniqueLinks = animeLinks.filter(
|
|
356
|
-
(item, index, self) => index === self.findIndex((i) => i.url === item.url)
|
|
357
|
-
);
|
|
362
|
+
if (title && link && tagText && languageText) {
|
|
363
|
+
const fullUrl = link.startsWith("http") ? link : `${BASE_URL}${link}`;
|
|
364
|
+
animeLinks.push({ title, url: fullUrl });
|
|
365
|
+
}
|
|
366
|
+
});
|
|
358
367
|
|
|
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
|
-
}
|
|
368
|
+
return containers.length > 0;
|
|
369
|
+
};
|
|
371
370
|
|
|
372
|
-
|
|
373
|
-
|
|
371
|
+
const enrichWithSeasons = async (list) => {
|
|
372
|
+
for (const anime of list) {
|
|
373
|
+
try {
|
|
374
|
+
const seasons = await getSeasons(anime.url);
|
|
375
|
+
anime.seasons = Array.isArray(seasons) ? seasons : [];
|
|
376
|
+
} catch (err) {
|
|
377
|
+
console.warn(`⚠️ Failed to fetch seasons for ${anime.title}: ${err.message}`);
|
|
378
|
+
anime.seasons = [];
|
|
374
379
|
}
|
|
380
|
+
await new Promise(r => setTimeout(r, 300));
|
|
375
381
|
}
|
|
382
|
+
};
|
|
376
383
|
|
|
377
|
-
|
|
378
|
-
|
|
384
|
+
try {
|
|
385
|
+
if (page) {
|
|
386
|
+
await fetchPage(page);
|
|
387
|
+
if (get_seasons) await enrichWithSeasons(animeLinks);
|
|
388
|
+
return animeLinks;
|
|
389
|
+
} else {
|
|
390
|
+
let currentPage = 1;
|
|
391
|
+
while (await fetchPage(currentPage++)) {
|
|
392
|
+
await new Promise(r => setTimeout(r, 300));
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Dédupliquer les URLs
|
|
396
|
+
const uniqueLinks = [...new Map(animeLinks.map(item => [item.url, item])).values()];
|
|
397
|
+
if (get_seasons) await enrichWithSeasons(uniqueLinks);
|
|
398
|
+
|
|
399
|
+
fs.writeFileSync(output, JSON.stringify(uniqueLinks, null, 2), "utf-8");
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
379
402
|
} catch (err) {
|
|
380
|
-
console.error("
|
|
403
|
+
console.error("🔥 Erreur surpuissante détectée :", err.message);
|
|
381
404
|
return false;
|
|
382
405
|
}
|
|
383
406
|
}
|
|
@@ -424,13 +447,21 @@ export async function getLatestEpisodes(languageFilter = null) {
|
|
|
424
447
|
}
|
|
425
448
|
}
|
|
426
449
|
|
|
427
|
-
export async function getRandomAnime(
|
|
450
|
+
export async function getRandomAnime(
|
|
451
|
+
wantedLanguages = ["vostfr", "vf", "vastfr"],
|
|
452
|
+
wantedTypes = ["Anime", "Film"],
|
|
453
|
+
maxAttempts = null,
|
|
454
|
+
attempt = 0
|
|
455
|
+
) {
|
|
428
456
|
try {
|
|
429
457
|
const res = await axios.get(
|
|
430
|
-
`${CATALOGUE_URL}/?
|
|
458
|
+
`${CATALOGUE_URL}/?search=&random=1`,
|
|
431
459
|
{ headers: getHeaders(CATALOGUE_URL) }
|
|
432
460
|
);
|
|
461
|
+
|
|
433
462
|
const $ = cheerio.load(res.data);
|
|
463
|
+
const isWanted = (text, list) =>
|
|
464
|
+
list.some(item => text.toLowerCase().includes(item.toLowerCase()));
|
|
434
465
|
|
|
435
466
|
const container = $("div.shrink-0.m-3.rounded.border-2").first();
|
|
436
467
|
const anchor = container.find("a");
|
|
@@ -463,7 +494,15 @@ export async function getRandomAnime() {
|
|
|
463
494
|
.filter(Boolean)
|
|
464
495
|
: [];
|
|
465
496
|
|
|
466
|
-
|
|
497
|
+
const tagText = anchor.find("p").filter((_, p) =>
|
|
498
|
+
isWanted($(p).text(), wantedTypes)
|
|
499
|
+
).first().text();
|
|
500
|
+
|
|
501
|
+
const languageText = anchor.find("p").filter((_, p) =>
|
|
502
|
+
isWanted($(p).text(), wantedLanguages)
|
|
503
|
+
).first().text();
|
|
504
|
+
|
|
505
|
+
if (title && link && tagText && languageText) {
|
|
467
506
|
return {
|
|
468
507
|
title,
|
|
469
508
|
altTitles,
|
|
@@ -472,10 +511,15 @@ export async function getRandomAnime() {
|
|
|
472
511
|
cover,
|
|
473
512
|
};
|
|
474
513
|
} else {
|
|
475
|
-
|
|
514
|
+
if (maxAttempts === null || attempt < maxAttempts) {
|
|
515
|
+
return await getRandomAnime(wantedLanguages, wantedTypes, maxAttempts, attempt + 1);
|
|
516
|
+
} else {
|
|
517
|
+
throw new Error("Max attempts reached without finding a valid anime.");
|
|
518
|
+
}
|
|
476
519
|
}
|
|
477
520
|
} catch (err) {
|
|
478
521
|
console.error("Failed to fetch random anime:", err.message);
|
|
479
522
|
return null;
|
|
480
523
|
}
|
|
481
524
|
}
|
|
525
|
+
|
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
|
-
|