hianime
Version:
a scraper for hianime
241 lines (236 loc) • 7.68 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
Hianime: () => hianime_default,
Type: () => Type,
default: () => index_default
});
module.exports = __toCommonJS(index_exports);
// src/hianime.ts
var import_axios = __toESM(require("axios"));
var cheerio = __toESM(require("cheerio"));
var Hianime = class {
BASE_URL = "https://hianime.to";
MALSYNC_URL = "https://api.malsync.moe";
async getAnimeList(category, page = 1, query) {
const { data } = await import_axios.default.get(`${this.BASE_URL}/${category}`, {
params: {
page,
...query && { keyword: decodeURIComponent(query) }
}
});
const $ = cheerio.load(data);
const animeList = $(".tab-content div.film_list-wrap > div.flw-item").map((_, element) => {
const anime = {
id: $(element).find("a[data-id]").attr("href"),
image: $(element).find("div.film-poster > img").attr("data-src"),
title: $(element).find("div.film-detail > .film-name > a").attr("title"),
type: $(element).find("div.fd-infor > span.fdi-item").first().text().toUpperCase(),
language: {
sub: $(element).find(".tick.ltr > .tick-sub").text() || null,
dub: $(element).find(".tick.ltr > .tick-dub").text() || null
},
dataId: $(element).find("a[data-id]").attr("data-id")
};
return anime;
}).get();
const totalPage = parseInt(
$('a[title="Last"]').attr("href")?.match(/page=(\d+)/)?.[1] ?? page.toString()
);
return {
page,
totalPage,
hasNextPage: page < totalPage,
results: animeList
};
}
async getSubbedAnime(page = 1) {
return this.getAnimeList("subbed-anime", page);
}
async getDubbedAnime(page = 1) {
return this.getAnimeList("dubbed-anime", page);
}
async getMostPopular(page = 1) {
return this.getAnimeList("most-popular", page);
}
async getMovies(page = 1) {
return this.getAnimeList("movie", page);
}
async getTVShows(page = 1) {
return this.getAnimeList("tv", page);
}
async getSpecialList(page = 1) {
return this.getAnimeList("special", page);
}
async getONAList(page = 1) {
return this.getAnimeList("ona", page);
}
async getOVAList(page = 1) {
return this.getAnimeList("ova", page);
}
async getTopAiring(page = 1) {
return this.getAnimeList("top-airing", page);
}
async search(query, page = 1) {
return this.getAnimeList("search", page, query);
}
async getEpisodesByMALID(malId) {
const { data: malsyncData } = await import_axios.default.get(
`${this.MALSYNC_URL}/mal/anime/${malId}`
);
const ids = malsyncData.Sites.Zoro;
if (!ids) {
throw new Error(`No Zoro IDs found for MAL ID ${malId}`);
}
let id = Object.keys(ids)[0];
const episodes = await this.getEpisodes(id ?? "");
return episodes;
}
async getEpisodes(dataId) {
const { data } = await import_axios.default.get(
`${this.BASE_URL}/ajax/v2/episode/list/${dataId}`
);
const $ = cheerio.load(data.html);
const episodes = $("div.ss-list > a.ep-item").map((_, element) => {
const episode = {
id: $(element).attr("data-id"),
number: $(element).attr("data-number"),
title: $(element).attr("title"),
href: $(element).attr("href")
};
return episode;
}).get();
return episodes;
}
async getEpisodeServers(episodeId) {
const { data } = await import_axios.default.get(
`${this.BASE_URL}/ajax/v2/episode/servers`,
{
params: {
episodeId
}
}
);
const $ = cheerio.load(data.html);
const subServers = $("div.servers-sub .server-item").map((_, element) => {
const server = {
type: $(element).attr("data-type"),
id: $(element).attr("data-id"),
serverId: $(element).attr("data-server-id"),
name: $(element).find("a.btn").text()
};
return server;
}).get();
const dubServers = $("div.servers-dub .server-item").map((_, element) => {
const server = {
type: $(element).attr("data-type"),
id: $(element).attr("data-id"),
serverId: $(element).attr("data-server-id"),
name: $(element).find("a.btn").text()
};
return server;
}).get();
return {
sub: subServers,
dub: dubServers
};
}
async getEpisodeSources(serverId) {
const { data } = await import_axios.default.get(
`${this.BASE_URL}/ajax/v2/episode/sources?id=${serverId}`
);
const embedLink = data?.link;
if (!embedLink) {
throw new Error(
`No embed link returned for serverId ${serverId}. Response: ${JSON.stringify(
data
).slice(0, 200)}...`
);
}
const { data: embedData } = await import_axios.default.get(embedLink, {
headers: {
Referer: this.BASE_URL
}
});
const $ = cheerio.load(embedData);
const dataId = $("div[data-id]").attr("data-id");
let nonce = null;
const regex48 = /\b[a-zA-Z0-9]{48}\b/;
const match48 = embedData.match(regex48);
if (match48 && match48[0]) {
nonce = match48[0];
} else {
const regex16 = /"([a-zA-Z0-9]{16})"/g;
const parts = [];
let m;
while ((m = regex16.exec(embedData)) !== null) {
if (m[1]) parts.push(m[1]);
}
if (parts.length) nonce = parts.join("");
}
if (!nonce) {
throw new Error(
`Failed to extract nonce from embed page for serverId ${serverId}`
);
}
const { data: sources } = await import_axios.default.get(
`https://megacloud.blog/embed-2/v3/e-1/getSources`,
{
params: {
id: dataId,
_k: nonce
},
headers: {
Referer: embedLink
}
}
);
sources.headers = {
Referer: "https://megacloud.blog/"
};
return sources;
}
};
var hianime_default = Hianime;
// src/types/hianime-result.ts
var Type = /* @__PURE__ */ ((Type2) => {
Type2["Ona"] = "ONA";
Type2["Special"] = "SPECIAL";
Type2["Tv"] = "TV";
return Type2;
})(Type || {});
// src/index.ts
var index_default = hianime_default;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Hianime,
Type
});