R-Kentaren commited on
Commit
809cb4d
·
verified ·
1 Parent(s): ab3c2ca

Create anime/my-anime-list.js

Browse files
Files changed (1) hide show
  1. anime/my-anime-list.js +885 -0
anime/my-anime-list.js ADDED
@@ -0,0 +1,885 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const axios = require('axios');
2
+
3
+ const cheerio = require('cheerio');
4
+
5
+
6
+
7
+ class MAL {
8
+
9
+ topAnime = async function () {
10
+
11
+ try {
12
+
13
+ const { data } = await axios.get('https://myanimelist.net/topanime.php');
14
+
15
+ const $ = cheerio.load(data);
16
+
17
+ const animeList = [];
18
+
19
+
20
+
21
+ $('.ranking-list').each((_, element) => {
22
+
23
+ const rank = $(element).find('.rank').text().trim();
24
+
25
+ const title = $(element).find('.title h3 a').text().trim();
26
+
27
+ const url = $(element).find('.title h3 a').attr('href');
28
+
29
+ const score = $(element).find('.score span').text().trim();
30
+
31
+ const cover = $(element).find('.title img').attr('data-src');
32
+
33
+ const type = $(element).find('.information').text().split('\n')[1].trim();
34
+
35
+ const release = $(element).find('.information').text().split('\n')[2].trim();
36
+
37
+ const members = $(element).find('.information').text().split('\n')[3].trim();
38
+
39
+
40
+
41
+ animeList.push({
42
+
43
+ rank,
44
+
45
+ title,
46
+
47
+ score,
48
+
49
+ type,
50
+
51
+ release,
52
+
53
+ members,
54
+
55
+ cover,
56
+
57
+ url
58
+
59
+ });
60
+
61
+ });
62
+
63
+
64
+
65
+ return animeList;
66
+
67
+ } catch (error) {
68
+
69
+ throw new Error(error.message);
70
+
71
+ }
72
+
73
+ }
74
+
75
+
76
+
77
+ seasonalAnime = async function (season, type) {
78
+
79
+ try {
80
+
81
+ const valid = {
82
+
83
+ seasons: ['fall', 'spring', 'winter', 'summer'],
84
+
85
+ types: {
86
+
87
+ 'tv-new': 'TV (New)',
88
+
89
+ 'tv-continuing': 'TV (Continuing)',
90
+
91
+ 'ona': 'ONA',
92
+
93
+ 'ova': 'OVA',
94
+
95
+ 'movie': 'Movie',
96
+
97
+ 'special': 'Special'
98
+
99
+ }
100
+
101
+ };
102
+
103
+
104
+
105
+ if (!valid.types[type]) throw new Error(`Available types: ${Object.keys(valid.types).join(', ')}`);
106
+
107
+ if (!valid.seasons.includes(season)) throw new Error(`Available seasons: ${valid.seasons.join(', ')}`);
108
+
109
+
110
+
111
+ const { data } = await axios.get(`https://myanimelist.net/anime/season/2024/${season}`);
112
+
113
+ const $ = cheerio.load(data);
114
+
115
+ const animeList = [];
116
+
117
+
118
+
119
+ $('.seasonal-anime-list').each((_, list) => {
120
+
121
+ const typeTxt = $(list).find('.anime-header').text().trim();
122
+
123
+
124
+
125
+ $(list).find('.js-seasonal-anime').each((_, element) => {
126
+
127
+ const title = $(element).find('.h2_anime_title > a').text().trim();
128
+
129
+ const url = $(element).find('.h2_anime_title > a').attr('href');
130
+
131
+ const cover = $(element).find('.image > a > img').attr('src') || $(element).find('.image > a > img').attr('data-src');
132
+
133
+ const score = $(element).find('.js-score').text().trim();
134
+
135
+ const members = $(element).find('.js-members').text().trim();
136
+
137
+ const formattedMembers = Number(members.replace(/\D/g, '')).toLocaleString('en-US');
138
+
139
+
140
+
141
+ const infoDiv = $(element).find('.info');
142
+
143
+ const releaseDate = infoDiv.find('.item:first-child').text().trim();
144
+
145
+ const totalEps = infoDiv.find('.item:nth-child(2) span:first-child').text().trim();
146
+
147
+ const duration = infoDiv.find('.item:nth-child(2) span:nth-child(2)').text().trim();
148
+
149
+ const totalEpsWithDuration = `${totalEps}, ${duration}`;
150
+
151
+
152
+
153
+ const synopsis = $(element).find('.synopsis p').text().trim();
154
+
155
+
156
+
157
+ const studio = $(element).find('.property:contains("Studio") .item').text().trim();
158
+
159
+ const source = $(element).find('.property:contains("Source") .item').text().trim();
160
+
161
+ const themes = $(element).find('.property:contains("Themes") .item').map((_, theme) => $(theme).text().trim()).get().join(', ');
162
+
163
+ const genres = $(element).find('.genres .genre a').map((_, g) => $(g).text().trim()).get().join(', ');
164
+
165
+
166
+
167
+ animeList.push({
168
+
169
+ title,
170
+
171
+ type: typeTxt || 'Unknown',
172
+
173
+ url,
174
+
175
+ cover,
176
+
177
+ stats: {
178
+
179
+ score: score || 'N/A',
180
+
181
+ members: formattedMembers || 'N/A'
182
+
183
+ },
184
+
185
+ details: {
186
+
187
+ releaseDate: releaseDate || 'Unknown',
188
+
189
+ totalEpisodes: totalEpsWithDuration || 'Unknown',
190
+
191
+ studio: studio || 'Unknown',
192
+
193
+ source: source || 'Unknown'
194
+
195
+ },
196
+
197
+ tags: {
198
+
199
+ themes: themes || 'None',
200
+
201
+ genres: genres || 'None'
202
+
203
+ },
204
+
205
+ synopsis: synopsis
206
+
207
+ });
208
+
209
+ });
210
+
211
+ });
212
+
213
+
214
+
215
+ return animeList.filter(obj => obj.type === valid.types[type]);
216
+
217
+ } catch (error) {
218
+
219
+ throw new Error(error.message);
220
+
221
+ }
222
+
223
+ }
224
+
225
+
226
+
227
+ animeSearch = async function (query) {
228
+
229
+ try {
230
+
231
+ if (!query) throw new Error('Query is required');
232
+
233
+
234
+
235
+ const { data } = await axios.get(`https://myanimelist.net/anime.php?q=${query}&cat=anime`);
236
+
237
+ const $ = cheerio.load(data);
238
+
239
+ const animeList = [];
240
+
241
+
242
+
243
+ $('table tbody tr').each((_, element) => {
244
+
245
+ const cover = $(element).find('td:nth-child(1) img').attr('data-src') || $(element).find('td:nth-child(1) img').attr('src');
246
+
247
+ const title = $(element).find('td:nth-child(2) strong').text().trim();
248
+
249
+ const url = $(element).find('td:nth-child(2) a').attr('href');
250
+
251
+ const type = $(element).find('td:nth-child(3)').text().trim();
252
+
253
+ const episodes = $(element).find('td:nth-child(4)').text().trim();
254
+
255
+ const score = $(element).find('td:nth-child(5)').text().trim();
256
+
257
+ const description = $(element).find('td:nth-child(2) .pt4').text().replace('read more.', '').trim() || 'No Desc'
258
+
259
+
260
+
261
+ if (title && url) {
262
+
263
+ animeList.push({
264
+
265
+ title,
266
+
267
+ description,
268
+
269
+ type,
270
+
271
+ episodes,
272
+
273
+ score,
274
+
275
+ cover,
276
+
277
+ url
278
+
279
+ });
280
+
281
+ }
282
+
283
+ });
284
+
285
+
286
+
287
+ return animeList;
288
+
289
+ } catch (error) {
290
+
291
+ throw new Error(error.message);
292
+
293
+ }
294
+
295
+ }
296
+
297
+
298
+
299
+ mangaSearch = async function (query) {
300
+
301
+ try {
302
+
303
+ if (!query) throw new Error('Query is required');
304
+
305
+
306
+
307
+ const { data } = await axios.get(`https://myanimelist.net/manga.php?q=${query}&cat=manga`);
308
+
309
+ const $ = cheerio.load(data);
310
+
311
+ const animeList = [];
312
+
313
+
314
+
315
+ $('table tbody tr').each((_, element) => {
316
+
317
+ const cover = $(element).find('td:nth-child(1) img').attr('data-src') || $(element).find('td:nth-child(1) img').attr('src');
318
+
319
+ const title = $(element).find('td:nth-child(2) strong').text().trim();
320
+
321
+ const url = $(element).find('td:nth-child(2) a').attr('href');
322
+
323
+ const type = $(element).find('td:nth-child(3)').text().trim();
324
+
325
+ const vol = $(element).find('td:nth-child(4)').text().trim();
326
+
327
+ const score = $(element).find('td:nth-child(5)').text().trim();
328
+
329
+ const description = $(element).find('td:nth-child(2) .pt4').text().replace('read more.', '').trim() || 'No Desc'
330
+
331
+
332
+
333
+ if (title && url) {
334
+
335
+ animeList.push({
336
+
337
+ title,
338
+
339
+ description,
340
+
341
+ type,
342
+
343
+ vol,
344
+
345
+ score,
346
+
347
+ cover,
348
+
349
+ url
350
+
351
+ });
352
+
353
+ }
354
+
355
+ });
356
+
357
+
358
+
359
+ return animeList;
360
+
361
+ } catch (error) {
362
+
363
+ throw new Error(error.message);
364
+
365
+ }
366
+
367
+ }
368
+
369
+
370
+
371
+ charaSearch = async function (query) {
372
+
373
+ try {
374
+
375
+ if (!query) throw new Error('Query is required');
376
+
377
+
378
+
379
+ const { data } = await axios.get(`https://myanimelist.net/character.php?q=${query}&cat=character`);
380
+
381
+ const $ = cheerio.load(data);
382
+
383
+ const characterData = [];
384
+
385
+
386
+
387
+ $('table tbody tr').each((_, element) => {
388
+
389
+ const cover = $(element).find('td .picSurround img').attr('data-src') || $(element).find('td .picSurround img').attr('src');
390
+
391
+ const nameElement = $(element).find('td:nth-child(2) a');
392
+
393
+ const name = nameElement.text().trim();
394
+
395
+ const url = nameElement.attr('href') || '';
396
+
397
+
398
+
399
+ const animeList = [];
400
+
401
+ const mangaList = [];
402
+
403
+
404
+
405
+ $(element).find('td small a[href*="/anime/"]').each((_, anime) => {
406
+
407
+ animeList.push({
408
+
409
+ title: $(anime).text().trim(),
410
+
411
+ url: `https://myanimelist.net${$(anime).attr('href')}`
412
+
413
+ });
414
+
415
+ });
416
+
417
+
418
+
419
+ $(element).find('td small a[href*="/manga/"]').each((_, manga) => {
420
+
421
+ mangaList.push({
422
+
423
+ title: $(manga).text().trim(),
424
+
425
+ url: `https://myanimelist.net${$(manga).attr('href')}`
426
+
427
+ });
428
+
429
+ });
430
+
431
+
432
+
433
+ if (name && url) {
434
+
435
+ characterData.push({
436
+
437
+ name,
438
+
439
+ anime: animeList,
440
+
441
+ manga: mangaList,
442
+
443
+ cover,
444
+
445
+ url
446
+
447
+ });
448
+
449
+ }
450
+
451
+ });
452
+
453
+
454
+
455
+ return characterData;
456
+
457
+ } catch (error) {
458
+
459
+ throw new Error(error.message);
460
+
461
+ }
462
+
463
+ }
464
+
465
+
466
+
467
+ animeDetail = async function (url) {
468
+
469
+ try {
470
+
471
+ if (!url.includes('myanimelist.net/anime')) throw new Error('Invalid url');
472
+
473
+
474
+
475
+ const { data } = await axios.get(url);
476
+
477
+ const $ = cheerio.load(data);
478
+
479
+
480
+
481
+ const title = $("h1.title-name").text().trim();
482
+
483
+ const cover = $(".leftside img").attr("data-src");
484
+
485
+ const synopsis = $(".js-scrollfix-bottom-rel").find("p").first().text().trim();
486
+
487
+ const background = $('td.pb24:contains("Background")').contents().map(function() {
488
+
489
+ if (this.type === 'text') {
490
+
491
+ return $(this).text();
492
+
493
+ } else if (this.name === 'i') {
494
+
495
+ return $(this).text();
496
+
497
+ }
498
+
499
+ }).get().join('').trim();
500
+
501
+
502
+
503
+ const alternativeTitles = {
504
+
505
+ synonyms: $('.spaceit_pad:contains("Synonyms")').contents().not('span').text().trim(),
506
+
507
+ japanese: $('.spaceit_pad:contains("Japanese")').contents().not('span').text().trim(),
508
+
509
+ english: $('.spaceit_pad:contains("English")').contents().not('span').text().trim(),
510
+
511
+ };
512
+
513
+
514
+
515
+ const information = {
516
+
517
+ type: $('.spaceit_pad:contains("Type") a').text().trim(),
518
+
519
+ episodes: $('.spaceit_pad:contains("Episodes")').contents().not('span').text().trim(),
520
+
521
+ status: $('.spaceit_pad:contains("Status")').contents().not('span').text().trim(),
522
+
523
+ aired: $('.spaceit_pad:contains("Aired")').contents().not('span').text().trim(),
524
+
525
+ premiered: $('.spaceit_pad:contains("Premiered")').contents().not('span').text().trim(),
526
+
527
+ broadcast: $('.spaceit_pad:contains("Broadcast")').contents().not('span').text().trim(),
528
+
529
+ producers: $("span:contains('Producers:')").nextAll("a").map((i, el) => $(el).text().trim()).get().join(', ') || 'Unknown',
530
+
531
+ licensors: $("span:contains('Licensors:')").nextAll("a").map((i, el) => $(el).text().trim()).get().join(', ') || 'Unknown',
532
+
533
+ studios: $("span:contains('Studios:')").nextAll("a").map((i, el) => $(el).text().trim()).get().join(', ') || 'Unknown',
534
+
535
+ source: $('.spaceit_pad:contains("Source")').contents().not('span').text().trim(),
536
+
537
+ genres: $("span:contains('Genres:')").nextAll("a").map((i, el) => $(el).text().trim()).get().join(', ') || 'None',
538
+
539
+ themes: $("span:contains('Themes:')").nextAll("a").map((i, el) => $(el).text().trim()).get().join(', ') || 'None',
540
+
541
+ demographic: $("span:contains('Demographic:')").nextAll("a").map((i, el) => $(el).text().trim()).get().join(', ') || 'None',
542
+
543
+ duration: $('.spaceit_pad:contains("Duration")').contents().not('span').text().trim(),
544
+
545
+ rating: $('.spaceit_pad:contains("Rating")').contents().not('span').text().trim(),
546
+
547
+ };
548
+
549
+
550
+
551
+ const element = $('.spaceit_pad').filter((_, el) => {
552
+
553
+ return $(el).find('span.dark_text').text().trim() === 'Ranked:';
554
+
555
+ });
556
+
557
+ const rankedText = element.contents().filter((_, el) => el.type === 'text').text().trim();
558
+
559
+
560
+
561
+ const statistics = {
562
+
563
+ score: $('span[itemprop="ratingValue"]').text().trim(),
564
+
565
+ ranked: rankedText,
566
+
567
+ popularity: $('.spaceit_pad:contains("Popularity")').contents().not('span').text().trim(),
568
+
569
+ members: $('.spaceit_pad:contains("Members")').contents().not('span').text().trim(),
570
+
571
+ favorites: $('.spaceit_pad:contains("Favorites")').contents().not('span').text().trim(),
572
+
573
+ };
574
+
575
+
576
+
577
+ const externalLinks = $(".external_urls a").map((i, el) => {
578
+
579
+ const name = $(el).find(".caption").text().trim();
580
+
581
+ const url = $(el).attr("href");
582
+
583
+ if (name && url) {
584
+
585
+ return { name, url };
586
+
587
+ }
588
+
589
+ }).get()
590
+
591
+
592
+
593
+ return {
594
+
595
+ title,
596
+
597
+ synopsis,
598
+
599
+ background,
600
+
601
+ alternativeTitles,
602
+
603
+ information,
604
+
605
+ statistics,
606
+
607
+ externalLinks,
608
+
609
+ cover,
610
+
611
+ url: url
612
+
613
+ };
614
+
615
+ } catch (error) {
616
+
617
+ throw new Error(error.message);
618
+
619
+ }
620
+
621
+ }
622
+
623
+
624
+
625
+ mangaDetail = async function (url) {
626
+
627
+ try {
628
+
629
+ if (!url.includes('myanimelist.net/manga')) throw new Error('Invalid url');
630
+
631
+
632
+
633
+ const { data } = await axios.get(url);
634
+
635
+ const $ = cheerio.load(data);
636
+
637
+
638
+
639
+ const title = $('span.h1-title span[itemprop="name"]').text().trim();
640
+
641
+ const cover = $(".leftside img").attr("data-src");
642
+
643
+ const synopsis = $('span[itemprop="description"]').text().trim();
644
+
645
+ const background = $('td.pb24:contains("Background")').contents().map(function() {
646
+
647
+ if (this.type === 'text') {
648
+
649
+ return $(this).text();
650
+
651
+ } else if (this.name === 'i') {
652
+
653
+ return $(this).text();
654
+
655
+ }
656
+
657
+ }).get().join('').trim();
658
+
659
+
660
+
661
+ const alternativeTitles = {
662
+
663
+ synonyms: $('.spaceit_pad:contains("Synonyms")').contents().not('span').text().trim(),
664
+
665
+ japanese: $('.spaceit_pad:contains("Japanese")').contents().not('span').text().trim(),
666
+
667
+ english: $('.spaceit_pad:contains("English")').contents().not('span').text().trim(),
668
+
669
+ };
670
+
671
+
672
+
673
+ const information = {
674
+
675
+ type: $('.spaceit_pad:contains("Type") a').text().trim(),
676
+
677
+ volumes: $('.spaceit_pad:contains("Volumes")').contents().not('span').text().trim(),
678
+
679
+ chapters: $('.spaceit_pad:contains("Chapters")').contents().not('span').text().trim(),
680
+
681
+ status: $('.spaceit_pad:contains("Status")').contents().not('span').text().trim(),
682
+
683
+ published: $('.spaceit_pad:contains("Published")').contents().not('span').text().trim(),
684
+
685
+ genres: $("span:contains('Genres:')").nextAll("a").map((i, el) => $(el).text().trim()).get().join(', ') || 'None',
686
+
687
+ themes: $("span:contains('Themes:')").nextAll("a").map((i, el) => $(el).text().trim()).get().join(', ') || 'None',
688
+
689
+ demographic: $("span:contains('Demographic:')").nextAll("a").map((i, el) => $(el).text().trim()).get().join(', ') || 'None',
690
+
691
+ serialization: $("span:contains('Serialization:')").nextAll("a").map((i, el) => $(el).text().trim()).get().join(', ') || 'None',
692
+
693
+ authors: $("span:contains('Authors:')").nextAll("a").map((i, el) => $(el).text().trim()).get().join(', ') || 'Unknown',
694
+
695
+ };
696
+
697
+
698
+
699
+ const element = $('.spaceit_pad').filter((_, el) => {
700
+
701
+ return $(el).find('span.dark_text').text().trim() === 'Ranked:';
702
+
703
+ });
704
+
705
+ const rankedText = element.contents().filter((_, el) => el.type === 'text').text().trim();
706
+
707
+
708
+
709
+ const statistics = {
710
+
711
+ score: $('span[itemprop="ratingValue"]').text().trim(),
712
+
713
+ ranked: rankedText,
714
+
715
+ popularity: $('.spaceit_pad:contains("Popularity")').contents().not('span').text().trim(),
716
+
717
+ members: $('.spaceit_pad:contains("Members")').contents().not('span').text().trim(),
718
+
719
+ favorites: $('.spaceit_pad:contains("Favorites")').contents().not('span').text().trim(),
720
+
721
+ };
722
+
723
+
724
+
725
+ const externalLinks = $(".external_urls a").map((i, el) => {
726
+
727
+ const name = $(el).find(".caption").text().trim();
728
+
729
+ const url = $(el).attr("href");
730
+
731
+ if (name && url) {
732
+
733
+ return { name, url };
734
+
735
+ }
736
+
737
+ }).get()
738
+
739
+
740
+
741
+ return {
742
+
743
+ title,
744
+
745
+ synopsis,
746
+
747
+ background,
748
+
749
+ alternativeTitles,
750
+
751
+ information,
752
+
753
+ statistics,
754
+
755
+ externalLinks,
756
+
757
+ cover,
758
+
759
+ url: url
760
+
761
+ };
762
+
763
+ } catch (error) {
764
+
765
+ throw new Error(error.message);
766
+
767
+ }
768
+
769
+ }
770
+
771
+
772
+
773
+ charaDetail = async function (url) {
774
+
775
+ try {
776
+
777
+ if (!url.includes('myanimelist.net/character')) throw new Error('Invalid url');
778
+
779
+
780
+
781
+ const { data } = await axios.get(url);
782
+
783
+ const $ = cheerio.load(data);
784
+
785
+
786
+
787
+ const name = $('h2.normal_header').first().text().trim();
788
+
789
+ const description = $('h2.normal_header').closest('td').clone().children().remove().end().text().trim();
790
+
791
+ const cover = $('img.portrait-225x350').attr('data-src') || $('img.portrait-225x350').attr('src');
792
+
793
+
794
+
795
+ const animeography = [];
796
+
797
+ $('td.borderClass').each((i, el) => {
798
+
799
+ const animeTitle = $(el).find('a[href*="https://myanimelist.net/anime/"]').text().trim()
800
+
801
+ const animeLink = $(el).find('a[href*="https://myanimelist.net/anime/"]').attr('href')
802
+
803
+ if (animeTitle && animeLink) {
804
+
805
+ animeography.push({ title: animeTitle, url: animeLink });
806
+
807
+ }
808
+
809
+ });
810
+
811
+
812
+
813
+ const mangaography = [];
814
+
815
+ $('td.borderClass').each((i, el) => {
816
+
817
+ const mangaTitle = $(el).find('a[href*="https://myanimelist.net/manga/"]').text().trim()
818
+
819
+ const mangaLink = $(el).find('a[href*="https://myanimelist.net/manga/"]').attr('href')
820
+
821
+ if (mangaTitle && mangaLink) {
822
+
823
+ mangaography.push({ title: mangaTitle, url: mangaLink });
824
+
825
+ }
826
+
827
+ });
828
+
829
+
830
+
831
+ const voiceActors = [];
832
+
833
+ $('div.voice_actor').find('tr').each((i, el) => {
834
+
835
+ const vaName = $(el).find('td:nth-child(2) a').text().trim();
836
+
837
+ const vaImage = $(el).find('td:nth-child(1) img').attr('data-src') || $(el).find('td:nth-child(1) img').attr('src');
838
+
839
+ const vaRole = $(el).find('td:nth-child(3)').text().trim();
840
+
841
+ if (vaName && vaImage) {
842
+
843
+ voiceActors.push({ name: vaName, role: vaRole, image: vaImage });
844
+
845
+ }
846
+
847
+ });
848
+
849
+
850
+
851
+ return {
852
+
853
+ name,
854
+
855
+ description,
856
+
857
+ cover,
858
+
859
+ animeography,
860
+
861
+ mangaography,
862
+
863
+ voiceActors
864
+
865
+ };
866
+
867
+ } catch (error) {
868
+
869
+ throw new Error(error.message);
870
+
871
+ }
872
+
873
+ };
874
+
875
+ }
876
+
877
+
878
+
879
+ // Usage:
880
+
881
+ const m = new MAL();
882
+
883
+ const resp = await m.topAnime();
884
+
885
+ console.log(resp);