@tiktikimelbo7/extensions
Version:
Nodejs library that provides high-level APIs for obtaining information on various entertainment media such as books, movies, comic books, anime, manga, and so on.
704 lines (703 loc) • 122 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
const axios_1 = __importDefault(require("axios"));
const models_1 = require("../../models");
const utils_1 = require("../../utils");
const gogoanime_1 = __importDefault(require("../../providers/anime/gogoanime"));
const enime_1 = __importDefault(require("../anime/enime"));
const zoro_1 = __importDefault(require("../anime/zoro"));
const mangasee123_1 = __importDefault(require("../manga/mangasee123"));
const crunchyroll_1 = __importDefault(require("../anime/crunchyroll"));
const bilibili_1 = __importDefault(require("../anime/bilibili"));
const _9anime_1 = __importDefault(require("../anime/9anime"));
const utils_2 = require("../../utils/utils");
class Anilist extends models_1.AnimeParser {
/**
* This class maps anilist to kitsu with any other anime provider.
* kitsu is used for episode images, titles and description.
* @param provider anime provider (optional) default: Gogoanime
* @param proxyConfig proxy config (optional)
* @param adapter axios adapter (optional)
*/
constructor(provider, proxyConfig, adapter) {
super(proxyConfig, adapter);
this.proxyConfig = proxyConfig;
this.name = 'Anilist';
this.baseUrl = 'https://anilist.co';
this.logo = 'https://upload.wikimedia.org/wikipedia/commons/6/61/AniList_logo.svg';
this.classPath = 'META.Anilist';
this.anilistGraphqlUrl = 'https://graphql.anilist.co';
this.kitsuGraphqlUrl = 'https://kitsu.io/api/graphql';
this.malSyncUrl = 'https://api.malsync.moe';
this.enimeUrl = 'https://api.enime.moe';
/**
* @param query Search query
* @param page Page number (optional)
* @param perPage Number of results per page (optional) (default: 15) (max: 50)
*/
this.search = async (query, page = 1, perPage = 15) => {
var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
const options = {
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
query: (0, utils_1.anilistSearchQuery)(query, page, perPage),
};
try {
let { data, status } = await this.client.post(this.anilistGraphqlUrl, options, {
validateStatus: () => true,
});
if (status >= 500 || status == 429)
data = await new enime_1.default().rawSearch(query, page, perPage);
const res = {
currentPage: (_d = (_c = (_b = data.data.Page) === null || _b === void 0 ? void 0 : _b.pageInfo) === null || _c === void 0 ? void 0 : _c.currentPage) !== null && _d !== void 0 ? _d : (_e = data.meta) === null || _e === void 0 ? void 0 : _e.currentPage,
hasNextPage: (_h = (_g = (_f = data.data.Page) === null || _f === void 0 ? void 0 : _f.pageInfo) === null || _g === void 0 ? void 0 : _g.hasNextPage) !== null && _h !== void 0 ? _h : ((_j = data.meta) === null || _j === void 0 ? void 0 : _j.currentPage) != ((_k = data.meta) === null || _k === void 0 ? void 0 : _k.lastPage),
results: (_p = (_o = (_m = (_l = data.data) === null || _l === void 0 ? void 0 : _l.Page) === null || _m === void 0 ? void 0 : _m.media) === null || _o === void 0 ? void 0 : _o.map((item) => {
var _b, _c, _d, _e, _f, _g, _h, _j, _k;
return ({
id: item.id.toString(),
malId: item.idMal,
title: {
romaji: item.title.romaji,
english: item.title.english,
native: item.title.native,
userPreferred: item.title.userPreferred,
} || item.title.romaji,
status: item.status == 'RELEASING'
? models_1.MediaStatus.ONGOING
: item.status == 'FINISHED'
? models_1.MediaStatus.COMPLETED
: item.status == 'NOT_YET_RELEASED'
? models_1.MediaStatus.NOT_YET_AIRED
: item.status == 'CANCELLED'
? models_1.MediaStatus.CANCELLED
: item.status == 'HIATUS'
? models_1.MediaStatus.HIATUS
: models_1.MediaStatus.UNKNOWN,
image: (_e = (_c = (_b = item.coverImage) === null || _b === void 0 ? void 0 : _b.extraLarge) !== null && _c !== void 0 ? _c : (_d = item.coverImage) === null || _d === void 0 ? void 0 : _d.large) !== null && _e !== void 0 ? _e : (_f = item.coverImage) === null || _f === void 0 ? void 0 : _f.medium,
cover: item.bannerImage,
popularity: item.popularity,
description: item.description,
rating: item.averageScore,
genres: item.genres,
color: (_g = item.coverImage) === null || _g === void 0 ? void 0 : _g.color,
totalEpisodes: (_h = item.episodes) !== null && _h !== void 0 ? _h : ((_j = item.nextAiringEpisode) === null || _j === void 0 ? void 0 : _j.episode) - 1,
currentEpisodeCount: (item === null || item === void 0 ? void 0 : item.nextAiringEpisode)
? ((_k = item === null || item === void 0 ? void 0 : item.nextAiringEpisode) === null || _k === void 0 ? void 0 : _k.episode) - 1
: item.episodes,
type: item.format,
releaseDate: item.seasonYear,
});
})) !== null && _p !== void 0 ? _p : data.data.map((item) => {
var _b, _c;
return ({
id: item.anilistId.toString(),
malId: item.mappings['mal'],
title: item.title,
status: item.status == 'RELEASING'
? models_1.MediaStatus.ONGOING
: item.status == 'FINISHED'
? models_1.MediaStatus.COMPLETED
: item.status == 'NOT_YET_RELEASED'
? models_1.MediaStatus.NOT_YET_AIRED
: item.status == 'CANCELLED'
? models_1.MediaStatus.CANCELLED
: item.status == 'HIATUS'
? models_1.MediaStatus.HIATUS
: models_1.MediaStatus.UNKNOWN,
image: (_b = item.coverImage) !== null && _b !== void 0 ? _b : item.bannerImage,
cover: item.bannerImage,
popularity: item.popularity,
description: item.description,
rating: item.averageScore,
genres: item.genre,
color: item.color,
totalEpisodes: item.currentEpisode,
currentEpisodeCount: (item === null || item === void 0 ? void 0 : item.nextAiringEpisode)
? ((_c = item === null || item === void 0 ? void 0 : item.nextAiringEpisode) === null || _c === void 0 ? void 0 : _c.episode) - 1
: item.currentEpisode,
type: item.format,
releaseDate: item.year,
});
}),
};
return res;
}
catch (err) {
throw new Error(err.message);
}
};
/**
*
* @param query Search query (optional)
* @param type Media type (optional) (default: `ANIME`) (options: `ANIME`, `MANGA`)
* @param page Page number (optional)
* @param perPage Number of results per page (optional) (default: `20`) (max: `50`)
* @param format Format (optional) (options: `TV`, `TV_SHORT`, `MOVIE`, `SPECIAL`, `OVA`, `ONA`, `MUSIC`)
* @param sort Sort (optional) (Default: `[POPULARITY_DESC, SCORE_DESC]`) (options: `POPULARITY_DESC`, `POPULARITY`, `TRENDING_DESC`, `TRENDING`, `UPDATED_AT_DESC`, `UPDATED_AT`, `START_DATE_DESC`, `START_DATE`, `END_DATE_DESC`, `END_DATE`, `FAVOURITES_DESC`, `FAVOURITES`, `SCORE_DESC`, `SCORE`, `TITLE_ROMAJI_DESC`, `TITLE_ROMAJI`, `TITLE_ENGLISH_DESC`, `TITLE_ENGLISH`, `TITLE_NATIVE_DESC`, `TITLE_NATIVE`, `EPISODES_DESC`, `EPISODES`, `ID`, `ID_DESC`)
* @param genres Genres (optional) (options: `Action`, `Adventure`, `Cars`, `Comedy`, `Drama`, `Fantasy`, `Horror`, `Mahou Shoujo`, `Mecha`, `Music`, `Mystery`, `Psychological`, `Romance`, `Sci-Fi`, `Slice of Life`, `Sports`, `Supernatural`, `Thriller`)
* @param id anilist Id (optional)
* @param year Year (optional) e.g. `2022`
* @param status Status (optional) (options: `RELEASING`, `FINISHED`, `NOT_YET_RELEASED`, `CANCELLED`, `HIATUS`)
* @param season Season (optional) (options: `WINTER`, `SPRING`, `SUMMER`, `FALL`)
*/
this.advancedSearch = async (query, type = 'ANIME', page = 1, perPage = 20, format, sort, genres, id, year, status, season) => {
var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
const options = {
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
query: (0, utils_1.anilistAdvancedQuery)(),
variables: {
search: query,
type: type,
page: page,
size: perPage,
format: format,
sort: sort,
genres: genres,
id: id,
year: year ? `${year}%` : undefined,
status: status,
season: season,
},
};
if (genres) {
genres.forEach(genre => {
if (!Object.values(models_1.Genres).includes(genre)) {
throw new Error(`genre ${genre} is not valid`);
}
});
}
try {
let { data, status } = await this.client.post(this.anilistGraphqlUrl, options, {
validateStatus: () => true,
});
if (status >= 500 && !query)
throw new Error('No results found');
if (status >= 500)
data = await new enime_1.default().rawSearch(query, page, perPage);
const res = {
currentPage: (_e = (_d = (_c = (_b = data.data) === null || _b === void 0 ? void 0 : _b.Page) === null || _c === void 0 ? void 0 : _c.pageInfo) === null || _d === void 0 ? void 0 : _d.currentPage) !== null && _e !== void 0 ? _e : (_f = data.meta) === null || _f === void 0 ? void 0 : _f.currentPage,
hasNextPage: (_k = (_j = (_h = (_g = data.data) === null || _g === void 0 ? void 0 : _g.Page) === null || _h === void 0 ? void 0 : _h.pageInfo) === null || _j === void 0 ? void 0 : _j.hasNextPage) !== null && _k !== void 0 ? _k : ((_l = data.meta) === null || _l === void 0 ? void 0 : _l.currentPage) != ((_m = data.meta) === null || _m === void 0 ? void 0 : _m.lastPage),
totalPages: (_q = (_p = (_o = data.data) === null || _o === void 0 ? void 0 : _o.Page) === null || _p === void 0 ? void 0 : _p.pageInfo) === null || _q === void 0 ? void 0 : _q.lastPage,
totalResults: (_t = (_s = (_r = data.data) === null || _r === void 0 ? void 0 : _r.Page) === null || _s === void 0 ? void 0 : _s.pageInfo) === null || _t === void 0 ? void 0 : _t.total,
results: [],
};
res.results.push(...((_x = (_w = (_v = (_u = data.data) === null || _u === void 0 ? void 0 : _u.Page) === null || _v === void 0 ? void 0 : _v.media) === null || _w === void 0 ? void 0 : _w.map((item) => {
var _b, _c, _d, _e, _f, _g, _h;
return ({
id: item.id.toString(),
malId: item.idMal,
title: {
romaji: item.title.romaji,
english: item.title.english,
native: item.title.native,
userPreferred: item.title.userPreferred,
} || item.title.romaji,
status: item.status == 'RELEASING'
? models_1.MediaStatus.ONGOING
: item.status == 'FINISHED'
? models_1.MediaStatus.COMPLETED
: item.status == 'NOT_YET_RELEASED'
? models_1.MediaStatus.NOT_YET_AIRED
: item.status == 'CANCELLED'
? models_1.MediaStatus.CANCELLED
: item.status == 'HIATUS'
? models_1.MediaStatus.HIATUS
: models_1.MediaStatus.UNKNOWN,
image: (_c = (_b = item.coverImage.extraLarge) !== null && _b !== void 0 ? _b : item.coverImage.large) !== null && _c !== void 0 ? _c : item.coverImage.medium,
cover: item.bannerImage,
popularity: item.popularity,
totalEpisodes: (_d = item.episodes) !== null && _d !== void 0 ? _d : ((_e = item.nextAiringEpisode) === null || _e === void 0 ? void 0 : _e.episode) - 1,
currentEpisode: (_g = ((_f = item.nextAiringEpisode) === null || _f === void 0 ? void 0 : _f.episode) - 1) !== null && _g !== void 0 ? _g : item.episodes,
countryOfOrigin: item.countryOfOrigin,
description: item.description,
genres: item.genres,
rating: item.averageScore,
color: (_h = item.coverImage) === null || _h === void 0 ? void 0 : _h.color,
type: item.format,
releaseDate: item.seasonYear,
});
})) !== null && _x !== void 0 ? _x : (_y = data.data) === null || _y === void 0 ? void 0 : _y.map((item) => {
var _b;
return ({
id: item.anilistId.toString(),
malId: item.mappings['mal'],
title: item.title,
status: item.status == 'RELEASING'
? models_1.MediaStatus.ONGOING
: item.status == 'FINISHED'
? models_1.MediaStatus.COMPLETED
: item.status == 'NOT_YET_RELEASED'
? models_1.MediaStatus.NOT_YET_AIRED
: item.status == 'CANCELLED'
? models_1.MediaStatus.CANCELLED
: item.status == 'HIATUS'
? models_1.MediaStatus.HIATUS
: models_1.MediaStatus.UNKNOWN,
image: (_b = item.coverImage) !== null && _b !== void 0 ? _b : item.bannerImage,
cover: item.bannerImage,
popularity: item.popularity,
description: item.description,
rating: item.averageScore,
genres: item.genre,
color: item.color,
totalEpisodes: item.currentEpisode,
type: item.format,
releaseDate: item.year,
});
})));
return res;
}
catch (err) {
throw new Error(err.message);
}
};
/**
*
* @param id Anime id
* @param dub to get dubbed episodes (optional) set to `true` to get dubbed episodes. **ONLY WORKS FOR GOGOANIME**
* @param fetchFiller to get filler boolean on the episode object (optional) set to `true` to get filler boolean on the episode object.
*/
this.fetchAnimeInfo = async (id, dub = false, fetchFiller = false) => {
var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64;
const animeInfo = {
id: id,
title: '',
};
const options = {
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
query: (0, utils_1.anilistMediaDetailQuery)(id),
};
let fillerEpisodes;
try {
let { data, status } = await this.client.post(this.anilistGraphqlUrl, options, {
validateStatus: () => true,
});
if (status == 404)
throw new Error('Media not found. Perhaps the id is invalid or the anime is not in anilist');
if (status == 429)
throw new Error('You have been ratelimited by anilist. Please try again later');
// if (status >= 500) throw new Error('Anilist seems to be down. Please try again later');
if (status != 200 && status < 429)
throw Error('Media not found. If the problem persists, please contact the developer');
if (status >= 500)
data = await new enime_1.default().fetchAnimeInfoByIdRaw(id);
animeInfo.malId = (_d = (_c = (_b = data.data) === null || _b === void 0 ? void 0 : _b.Media) === null || _c === void 0 ? void 0 : _c.idMal) !== null && _d !== void 0 ? _d : (_e = data === null || data === void 0 ? void 0 : data.mappings) === null || _e === void 0 ? void 0 : _e.mal;
animeInfo.title = data.data.Media
? {
romaji: data.data.Media.title.romaji,
english: data.data.Media.title.english,
native: data.data.Media.title.native,
userPreferred: data.data.Media.title.userPreferred,
}
: data.data.title;
animeInfo.synonyms = (_h = (_g = (_f = data.data) === null || _f === void 0 ? void 0 : _f.Media) === null || _g === void 0 ? void 0 : _g.synonyms) !== null && _h !== void 0 ? _h : data === null || data === void 0 ? void 0 : data.synonyms;
animeInfo.isLicensed = (_l = (_k = (_j = data.data) === null || _j === void 0 ? void 0 : _j.Media) === null || _k === void 0 ? void 0 : _k.isLicensed) !== null && _l !== void 0 ? _l : undefined;
animeInfo.isAdult = (_p = (_o = (_m = data.data) === null || _m === void 0 ? void 0 : _m.Media) === null || _o === void 0 ? void 0 : _o.isAdult) !== null && _p !== void 0 ? _p : undefined;
animeInfo.countryOfOrigin = (_s = (_r = (_q = data.data) === null || _q === void 0 ? void 0 : _q.Media) === null || _r === void 0 ? void 0 : _r.countryOfOrigin) !== null && _s !== void 0 ? _s : undefined;
if ((_v = (_u = (_t = data.data) === null || _t === void 0 ? void 0 : _t.Media) === null || _u === void 0 ? void 0 : _u.trailer) === null || _v === void 0 ? void 0 : _v.id) {
animeInfo.trailer = {
id: data.data.Media.trailer.id,
site: (_w = data.data.Media.trailer) === null || _w === void 0 ? void 0 : _w.site,
thumbnail: (_x = data.data.Media.trailer) === null || _x === void 0 ? void 0 : _x.thumbnail,
};
}
animeInfo.image =
(_10 = (_9 = (_5 = (_1 = (_0 = (_z = (_y = data.data) === null || _y === void 0 ? void 0 : _y.Media) === null || _z === void 0 ? void 0 : _z.coverImage) === null || _0 === void 0 ? void 0 : _0.extraLarge) !== null && _1 !== void 0 ? _1 : (_4 = (_3 = (_2 = data.data) === null || _2 === void 0 ? void 0 : _2.Media) === null || _3 === void 0 ? void 0 : _3.coverImage) === null || _4 === void 0 ? void 0 : _4.large) !== null && _5 !== void 0 ? _5 : (_8 = (_7 = (_6 = data.data) === null || _6 === void 0 ? void 0 : _6.Media) === null || _7 === void 0 ? void 0 : _7.coverImage) === null || _8 === void 0 ? void 0 : _8.medium) !== null && _9 !== void 0 ? _9 : data.coverImage) !== null && _10 !== void 0 ? _10 : data.bannerImage;
animeInfo.popularity = (_13 = (_12 = (_11 = data.data) === null || _11 === void 0 ? void 0 : _11.Media) === null || _12 === void 0 ? void 0 : _12.popularity) !== null && _13 !== void 0 ? _13 : data === null || data === void 0 ? void 0 : data.popularity;
animeInfo.color = (_17 = (_16 = (_15 = (_14 = data.data) === null || _14 === void 0 ? void 0 : _14.Media) === null || _15 === void 0 ? void 0 : _15.coverImage) === null || _16 === void 0 ? void 0 : _16.color) !== null && _17 !== void 0 ? _17 : data === null || data === void 0 ? void 0 : data.color;
animeInfo.cover = (_21 = (_20 = (_19 = (_18 = data.data) === null || _18 === void 0 ? void 0 : _18.Media) === null || _19 === void 0 ? void 0 : _19.bannerImage) !== null && _20 !== void 0 ? _20 : data === null || data === void 0 ? void 0 : data.bannerImage) !== null && _21 !== void 0 ? _21 : animeInfo.image;
animeInfo.description = (_24 = (_23 = (_22 = data.data) === null || _22 === void 0 ? void 0 : _22.Media) === null || _23 === void 0 ? void 0 : _23.description) !== null && _24 !== void 0 ? _24 : data === null || data === void 0 ? void 0 : data.description;
switch ((_27 = (_26 = (_25 = data.data) === null || _25 === void 0 ? void 0 : _25.Media) === null || _26 === void 0 ? void 0 : _26.status) !== null && _27 !== void 0 ? _27 : data === null || data === void 0 ? void 0 : data.status) {
case 'RELEASING':
animeInfo.status = models_1.MediaStatus.ONGOING;
break;
case 'FINISHED':
animeInfo.status = models_1.MediaStatus.COMPLETED;
break;
case 'NOT_YET_RELEASED':
animeInfo.status = models_1.MediaStatus.NOT_YET_AIRED;
break;
case 'CANCELLED':
animeInfo.status = models_1.MediaStatus.CANCELLED;
break;
case 'HIATUS':
animeInfo.status = models_1.MediaStatus.HIATUS;
default:
animeInfo.status = models_1.MediaStatus.UNKNOWN;
}
animeInfo.releaseDate = (_31 = (_30 = (_29 = (_28 = data.data) === null || _28 === void 0 ? void 0 : _28.Media) === null || _29 === void 0 ? void 0 : _29.startDate) === null || _30 === void 0 ? void 0 : _30.year) !== null && _31 !== void 0 ? _31 : data.year;
animeInfo.startDate = {
year: data.data.Media.startDate.year,
month: data.data.Media.startDate.month,
day: data.data.Media.startDate.day,
};
animeInfo.endDate = {
year: data.data.Media.endDate.year,
month: data.data.Media.endDate.month,
day: data.data.Media.endDate.day,
};
if ((_32 = data.data.Media.nextAiringEpisode) === null || _32 === void 0 ? void 0 : _32.airingAt)
animeInfo.nextAiringEpisode = {
airingTime: (_33 = data.data.Media.nextAiringEpisode) === null || _33 === void 0 ? void 0 : _33.airingAt,
timeUntilAiring: (_34 = data.data.Media.nextAiringEpisode) === null || _34 === void 0 ? void 0 : _34.timeUntilAiring,
episode: (_35 = data.data.Media.nextAiringEpisode) === null || _35 === void 0 ? void 0 : _35.episode,
};
animeInfo.totalEpisodes = (_37 = (_36 = data.data.Media) === null || _36 === void 0 ? void 0 : _36.episodes) !== null && _37 !== void 0 ? _37 : ((_38 = data.data.Media.nextAiringEpisode) === null || _38 === void 0 ? void 0 : _38.episode) - 1;
animeInfo.currentEpisode = ((_40 = (_39 = data.data.Media) === null || _39 === void 0 ? void 0 : _39.nextAiringEpisode) === null || _40 === void 0 ? void 0 : _40.episode)
? ((_41 = data.data.Media.nextAiringEpisode) === null || _41 === void 0 ? void 0 : _41.episode) - 1
: (_42 = data.data.Media) === null || _42 === void 0 ? void 0 : _42.episodes;
animeInfo.rating = data.data.Media.averageScore;
animeInfo.duration = data.data.Media.duration;
animeInfo.genres = data.data.Media.genres;
animeInfo.season = data.data.Media.season;
animeInfo.studios = data.data.Media.studios.edges.map((item) => item.node.name);
animeInfo.subOrDub = dub ? models_1.SubOrSub.DUB : models_1.SubOrSub.SUB;
animeInfo.type = data.data.Media.format;
animeInfo.recommendations = (_45 = (_44 = (_43 = data.data.Media) === null || _43 === void 0 ? void 0 : _43.recommendations) === null || _44 === void 0 ? void 0 : _44.edges) === null || _45 === void 0 ? void 0 : _45.map((item) => {
var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12;
return ({
id: (_b = item.node.mediaRecommendation) === null || _b === void 0 ? void 0 : _b.id,
malId: (_c = item.node.mediaRecommendation) === null || _c === void 0 ? void 0 : _c.idMal,
title: {
romaji: (_e = (_d = item.node.mediaRecommendation) === null || _d === void 0 ? void 0 : _d.title) === null || _e === void 0 ? void 0 : _e.romaji,
english: (_g = (_f = item.node.mediaRecommendation) === null || _f === void 0 ? void 0 : _f.title) === null || _g === void 0 ? void 0 : _g.english,
native: (_j = (_h = item.node.mediaRecommendation) === null || _h === void 0 ? void 0 : _h.title) === null || _j === void 0 ? void 0 : _j.native,
userPreferred: (_l = (_k = item.node.mediaRecommendation) === null || _k === void 0 ? void 0 : _k.title) === null || _l === void 0 ? void 0 : _l.userPreferred,
},
status: ((_m = item.node.mediaRecommendation) === null || _m === void 0 ? void 0 : _m.status) == 'RELEASING'
? models_1.MediaStatus.ONGOING
: ((_o = item.node.mediaRecommendation) === null || _o === void 0 ? void 0 : _o.status) == 'FINISHED'
? models_1.MediaStatus.COMPLETED
: ((_p = item.node.mediaRecommendation) === null || _p === void 0 ? void 0 : _p.status) == 'NOT_YET_RELEASED'
? models_1.MediaStatus.NOT_YET_AIRED
: ((_q = item.node.mediaRecommendation) === null || _q === void 0 ? void 0 : _q.status) == 'CANCELLED'
? models_1.MediaStatus.CANCELLED
: ((_r = item.node.mediaRecommendation) === null || _r === void 0 ? void 0 : _r.status) == 'HIATUS'
? models_1.MediaStatus.HIATUS
: models_1.MediaStatus.UNKNOWN,
episodes: (_s = item.node.mediaRecommendation) === null || _s === void 0 ? void 0 : _s.episodes,
image: (_y = (_v = (_u = (_t = item.node.mediaRecommendation) === null || _t === void 0 ? void 0 : _t.coverImage) === null || _u === void 0 ? void 0 : _u.extraLarge) !== null && _v !== void 0 ? _v : (_x = (_w = item.node.mediaRecommendation) === null || _w === void 0 ? void 0 : _w.coverImage) === null || _x === void 0 ? void 0 : _x.large) !== null && _y !== void 0 ? _y : (_0 = (_z = item.node.mediaRecommendation) === null || _z === void 0 ? void 0 : _z.coverImage) === null || _0 === void 0 ? void 0 : _0.medium,
cover: (_8 = (_5 = (_2 = (_1 = item.node.mediaRecommendation) === null || _1 === void 0 ? void 0 : _1.bannerImage) !== null && _2 !== void 0 ? _2 : (_4 = (_3 = item.node.mediaRecommendation) === null || _3 === void 0 ? void 0 : _3.coverImage) === null || _4 === void 0 ? void 0 : _4.extraLarge) !== null && _5 !== void 0 ? _5 : (_7 = (_6 = item.node.mediaRecommendation) === null || _6 === void 0 ? void 0 : _6.coverImage) === null || _7 === void 0 ? void 0 : _7.large) !== null && _8 !== void 0 ? _8 : (_10 = (_9 = item.node.mediaRecommendation) === null || _9 === void 0 ? void 0 : _9.coverImage) === null || _10 === void 0 ? void 0 : _10.medium,
rating: (_11 = item.node.mediaRecommendation) === null || _11 === void 0 ? void 0 : _11.meanScore,
type: (_12 = item.node.mediaRecommendation) === null || _12 === void 0 ? void 0 : _12.format,
});
});
animeInfo.characters = (_49 = (_48 = (_47 = (_46 = data.data) === null || _46 === void 0 ? void 0 : _46.Media) === null || _47 === void 0 ? void 0 : _47.characters) === null || _48 === void 0 ? void 0 : _48.edges) === null || _49 === void 0 ? void 0 : _49.map((item) => {
var _b, _c;
return ({
id: (_b = item.node) === null || _b === void 0 ? void 0 : _b.id,
role: item.role,
name: {
first: item.node.name.first,
last: item.node.name.last,
full: item.node.name.full,
native: item.node.name.native,
userPreferred: item.node.name.userPreferred,
},
image: (_c = item.node.image.large) !== null && _c !== void 0 ? _c : item.node.image.medium,
voiceActors: item.voiceActors.map((voiceActor) => {
var _b;
return ({
id: voiceActor.id,
language: voiceActor.languageV2,
name: {
first: voiceActor.name.first,
last: voiceActor.name.last,
full: voiceActor.name.full,
native: voiceActor.name.native,
userPreferred: voiceActor.name.userPreferred,
},
image: (_b = voiceActor.image.large) !== null && _b !== void 0 ? _b : voiceActor.image.medium,
});
}),
});
});
animeInfo.relations = (_53 = (_52 = (_51 = (_50 = data.data) === null || _50 === void 0 ? void 0 : _50.Media) === null || _51 === void 0 ? void 0 : _51.relations) === null || _52 === void 0 ? void 0 : _52.edges) === null || _53 === void 0 ? void 0 : _53.map((item) => {
var _b, _c, _d, _e, _f, _g;
return ({
id: item.node.id,
relationType: item.relationType,
malId: item.node.idMal,
title: {
romaji: item.node.title.romaji,
english: item.node.title.english,
native: item.node.title.native,
userPreferred: item.node.title.userPreferred,
},
status: item.node.status == 'RELEASING'
? models_1.MediaStatus.ONGOING
: item.node.status == 'FINISHED'
? models_1.MediaStatus.COMPLETED
: item.node.status == 'NOT_YET_RELEASED'
? models_1.MediaStatus.NOT_YET_AIRED
: item.node.status == 'CANCELLED'
? models_1.MediaStatus.CANCELLED
: item.node.status == 'HIATUS'
? models_1.MediaStatus.HIATUS
: models_1.MediaStatus.UNKNOWN,
episodes: item.node.episodes,
image: (_c = (_b = item.node.coverImage.extraLarge) !== null && _b !== void 0 ? _b : item.node.coverImage.large) !== null && _c !== void 0 ? _c : item.node.coverImage.medium,
color: (_d = item.node.coverImage) === null || _d === void 0 ? void 0 : _d.color,
type: item.node.format,
cover: (_g = (_f = (_e = item.node.bannerImage) !== null && _e !== void 0 ? _e : item.node.coverImage.extraLarge) !== null && _f !== void 0 ? _f : item.node.coverImage.large) !== null && _g !== void 0 ? _g : item.node.coverImage.medium,
rating: item.node.meanScore,
});
});
if ((this.provider instanceof zoro_1.default || this.provider instanceof gogoanime_1.default) &&
!dub &&
(animeInfo.status === models_1.MediaStatus.ONGOING ||
(0, utils_1.range)({ from: 1940, to: new Date().getFullYear() + 1 }).includes(parseInt(animeInfo.releaseDate)))) {
try {
const enimeInfo = await new enime_1.default().fetchAnimeInfoByAnilistId(id, this.provider.name.toLowerCase());
animeInfo.mappings = enimeInfo.mappings;
animeInfo.episodes = (_54 = enimeInfo.episodes) === null || _54 === void 0 ? void 0 : _54.map((item) => {
var _b;
return ({
id: item.slug,
title: item.title,
description: item.description,
number: item.number,
image: item.image,
airDate: (_b = item.airDate) !== null && _b !== void 0 ? _b : null,
});
});
if (!((_55 = animeInfo.episodes) === null || _55 === void 0 ? void 0 : _55.length)) {
animeInfo.episodes = await this.fetchDefaultEpisodeList({
idMal: animeInfo.malId,
season: data.data.Media.season,
startDate: { year: parseInt(animeInfo.releaseDate) },
title: { english: (_56 = animeInfo.title) === null || _56 === void 0 ? void 0 : _56.english, romaji: (_57 = animeInfo.title) === null || _57 === void 0 ? void 0 : _57.romaji },
}, dub, id);
animeInfo.episodes = (_58 = animeInfo.episodes) === null || _58 === void 0 ? void 0 : _58.map((episode) => {
if (!episode.image)
episode.image = animeInfo.image;
return episode;
});
}
}
catch (err) {
animeInfo.episodes = await this.fetchDefaultEpisodeList({
idMal: animeInfo.malId,
season: data.data.Media.season,
startDate: { year: parseInt(animeInfo.releaseDate) },
title: { english: (_59 = animeInfo.title) === null || _59 === void 0 ? void 0 : _59.english, romaji: (_60 = animeInfo.title) === null || _60 === void 0 ? void 0 : _60.romaji },
}, dub, id);
animeInfo.episodes = (_61 = animeInfo.episodes) === null || _61 === void 0 ? void 0 : _61.map((episode) => {
if (!episode.image)
episode.image = animeInfo.image;
return episode;
});
return animeInfo;
}
}
else
animeInfo.episodes = await this.fetchDefaultEpisodeList({
idMal: animeInfo.malId,
season: data.data.Media.season,
startDate: { year: parseInt(animeInfo.releaseDate) },
title: { english: (_62 = animeInfo.title) === null || _62 === void 0 ? void 0 : _62.english, romaji: (_63 = animeInfo.title) === null || _63 === void 0 ? void 0 : _63.romaji },
externalLinks: data.data.Media.externalLinks.filter((link) => link.type === 'STREAMING'),
}, dub, id);
if (fetchFiller) {
const { data: fillerData } = await this.client.get(`https://raw.githubusercontent.com/saikou-app/mal-id-filler-list/main/fillers/${animeInfo.malId}.json`, { validateStatus: () => true });
if (!fillerData.toString().startsWith('404')) {
fillerEpisodes = [];
fillerEpisodes === null || fillerEpisodes === void 0 ? void 0 : fillerEpisodes.push(...fillerData.episodes);
}
}
animeInfo.episodes = (_64 = animeInfo.episodes) === null || _64 === void 0 ? void 0 : _64.map((episode) => {
if (!episode.image)
episode.image = animeInfo.image;
if (fetchFiller &&
(fillerEpisodes === null || fillerEpisodes === void 0 ? void 0 : fillerEpisodes.length) > 0 &&
(fillerEpisodes === null || fillerEpisodes === void 0 ? void 0 : fillerEpisodes.length) >= animeInfo.episodes.length) {
if (fillerEpisodes[episode.number - 1])
episode.isFiller = new Boolean(fillerEpisodes[episode.number - 1]['filler-bool']).valueOf();
}
return episode;
});
return animeInfo;
}
catch (err) {
throw new Error(err.message);
}
};
/**
*
* @param episodeId Episode id
*/
this.fetchEpisodeSources = async (episodeId, ...args) => {
try {
if (episodeId.includes('enime'))
return new enime_1.default().fetchEpisodeSources(episodeId);
return this.provider.fetchEpisodeSources(episodeId, ...args);
}
catch (err) {
throw new Error(`Failed to fetch episode sources from ${this.provider.name}: ${err}`);
}
};
/**
*
* @param episodeId Episode id
*/
this.fetchEpisodeServers = async (episodeId) => {
try {
return this.provider.fetchEpisodeServers(episodeId);
}
catch (err) {
throw new Error(`Failed to fetch episode servers from ${this.provider.name}: ${err}`);
}
};
this.findAnime = async (title, season, startDate, malId, dub, anilistId, externalLinks) => {
var _b, _c, _d;
title.english = (_b = title.english) !== null && _b !== void 0 ? _b : title.romaji;
title.romaji = (_c = title.romaji) !== null && _c !== void 0 ? _c : title.english;
title.english = title.english.toLowerCase();
title.romaji = title.romaji.toLowerCase();
if (title.english === title.romaji) {
return ((_d = (await this.findAnimeSlug(title.english, season, startDate, malId, dub, anilistId, externalLinks))) !== null && _d !== void 0 ? _d : []);
}
const romajiPossibleEpisodes = await this.findAnimeSlug(title.romaji, season, startDate, malId, dub, anilistId, externalLinks);
if (romajiPossibleEpisodes) {
return romajiPossibleEpisodes;
}
const englishPossibleEpisodes = await this.findAnimeSlug(title.english, season, startDate, malId, dub, anilistId, externalLinks);
return englishPossibleEpisodes !== null && englishPossibleEpisodes !== void 0 ? englishPossibleEpisodes : [];
};
this.findAnimeSlug = async (title, season, startDate, malId, dub, anilistId, externalLinks) => {
var _b, _c, _d;
if (this.provider instanceof enime_1.default)
return (await this.provider.fetchAnimeInfoByAnilistId(anilistId)).episodes;
const slug = title.replace(/[^0-9a-zA-Z]+/g, ' ');
let possibleAnime;
if (malId && !(this.provider instanceof crunchyroll_1.default || this.provider instanceof bilibili_1.default)) {
const malAsyncReq = await this.client.get(`${this.malSyncUrl}/mal/anime/${malId}`, {
validateStatus: () => true,
});
if (malAsyncReq.status === 200) {
const sitesT = malAsyncReq.data.Sites;
let sites = Object.values(sitesT).map((v, i) => {
const obj = [...Object.values(Object.values(sitesT)[i])];
const pages = obj.map((v) => ({
page: v.page,
url: v.url,
title: v.title,
}));
return pages;
});
sites = sites.flat();
sites.sort((a, b) => {
const targetTitle = malAsyncReq.data.title.toLowerCase();
const firstRating = (0, utils_2.compareTwoStrings)(targetTitle, a.title.toLowerCase());
const secondRating = (0, utils_2.compareTwoStrings)(targetTitle, b.title.toLowerCase());
// Sort in descending order
return secondRating - firstRating;
});
const possibleSource = sites.find(s => {
if (s.page.toLowerCase() === this.provider.name.toLowerCase())
if (this.provider instanceof gogoanime_1.default)
return dub ? s.title.toLowerCase().includes('dub') : !s.title.toLowerCase().includes('dub');
else
return true;
return false;
});
if (possibleSource) {
try {
possibleAnime = await this.provider.fetchAnimeInfo(possibleSource.url.split('/').pop());
}
catch (err) {
console.error(err);
possibleAnime = await this.findAnimeRaw(slug);
}
}
else
possibleAnime = await this.findAnimeRaw(slug);
}
else
possibleAnime = await this.findAnimeRaw(slug);
}
else
possibleAnime = await this.findAnimeRaw(slug, externalLinks);
if (!possibleAnime)
return undefined;
// To avoid a new request, lets match and see if the anime show found is in sub/dub
const expectedType = dub ? models_1.SubOrSub.DUB : models_1.SubOrSub.SUB;
// Have this as a fallback in the meantime for compatibility
if (possibleAnime.subOrDub) {
if (possibleAnime.subOrDub != models_1.SubOrSub.BOTH && possibleAnime.subOrDub != expectedType) {
return undefined;
}
}
else if ((!possibleAnime.hasDub && dub) || (!possibleAnime.hasSub && !dub)) {
return undefined;
}
if (this.provider instanceof zoro_1.default) {
// Set the correct episode sub/dub request type
possibleAnime.episodes.forEach((_, index) => {
if (possibleAnime.subOrDub === models_1.SubOrSub.BOTH) {
possibleAnime.episodes[index].id = possibleAnime.episodes[index].id.replace(`$both`, dub ? '$dub' : '$sub');
}
});
}
if (this.provider instanceof crunchyroll_1.default) {
const nestedEpisodes = Object.keys(possibleAnime.episodes)
.filter((key) => key.toLowerCase().includes(dub ? 'dub' : 'sub'))
.sort((first, second) => {
var _b, _c, _d, _e;
return (((_c = (_b = possibleAnime.episodes[first]) === null || _b === void 0 ? void 0 : _b[0].season_number) !== null && _c !== void 0 ? _c : 0) -
((_e = (_d = possibleAnime.episodes[second]) === null || _d === void 0 ? void 0 : _d[0].season_number) !== null && _e !== void 0 ? _e : 0));
})
.map((key) => {
const audio = key
.replace(/[0-9]/g, '')
.replace(/(^\w{1})|(\s+\w{1})/g, (letter) => letter.toUpperCase());
possibleAnime.episodes[key].forEach((element) => (element.type = audio));
return possibleAnime.episodes[key];
});
return nestedEpisodes.flat();
}
if (this.provider instanceof _9anime_1.default) {
possibleAnime.episodes.forEach((_, index) => {
if (expectedType == models_1.SubOrSub.DUB) {
possibleAnime.episodes[index].id = possibleAnime.episodes[index].dubId;
}
if (possibleAnime.episodes[index].dubId) {
delete possibleAnime.episodes[index].dubId;
}
});
possibleAnime.episodes = possibleAnime.episodes.filter((el) => el.id != undefined);
}
const possibleProviderEpisodes = possibleAnime.episodes;
if (typeof ((_b = possibleProviderEpisodes[0]) === null || _b === void 0 ? void 0 : _b.image) !== 'undefined' &&
typeof ((_c = possibleProviderEpisodes[0]) === null || _c === void 0 ? void 0 : _c.title) !== 'undefined' &&
typeof ((_d = possibleProviderEpisodes[0]) === null || _d === void 0 ? void 0 : _d.description) !== 'undefined')
return possibleProviderEpisodes;
const options = {
headers: { 'Content-Type': 'application/json' },
query: (0, utils_1.kitsuSearchQuery)(slug),
};
const newEpisodeList = await this.findKitsuAnime(possibleProviderEpisodes, options, season, startDate);
return newEpisodeList;
};
this.findKitsuAnime = async (possibleProviderEpisodes, options, season, startDate) => {
const kitsuEpisodes = await this.client.post(this.kitsuGraphqlUrl, options);
const episodesList = new Map();
if (kitsuEpisodes === null || kitsuEpisodes === void 0 ? void 0 : kitsuEpisodes.data.data) {
const { nodes } = kitsuEpisodes.data.data.searchAnimeByTitle;
if (nodes) {
nodes.forEach((node) => {
var _b, _c;
if (node.season === season && node.startDate.trim().split('-')[0] === (startDate === null || startDate === void 0 ? void 0 : startDate.toString())) {
const episodes = node.episodes.nodes;