aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dist/api.router.js3
-rw-r--r--dist/controllers/animeCategory.controller.d.ts3
-rw-r--r--dist/controllers/animeCategory.controller.js23
-rw-r--r--dist/controllers/index.d.ts2
-rw-r--r--dist/controllers/index.js8
-rw-r--r--dist/models/anime.d.ts33
-rw-r--r--dist/models/anime.js17
-rw-r--r--dist/models/index.d.ts3
-rw-r--r--dist/models/index.js5
-rw-r--r--dist/models/parser.d.ts15
-rw-r--r--dist/models/parser.js2
-rw-r--r--dist/parsers/animeCategory.d.ts4
-rw-r--r--dist/parsers/animeCategory.js112
-rw-r--r--dist/parsers/index.d.ts2
-rw-r--r--dist/parsers/index.js8
-rw-r--r--dist/routes/index.d.ts3
-rw-r--r--dist/routes/index.js7
-rw-r--r--dist/server.d.ts1
-rw-r--r--dist/server.js38
-rw-r--r--dist/types.js14
-rw-r--r--dist/utils.d.ts12
-rw-r--r--dist/utils.js95
-rw-r--r--dist/utils/index.d.ts12
-rw-r--r--dist/utils/index.js95
24 files changed, 507 insertions, 10 deletions
diff --git a/dist/api.router.js b/dist/api.router.js
new file mode 100644
index 0000000..541877b
--- /dev/null
+++ b/dist/api.router.js
@@ -0,0 +1,3 @@
+import { Router } from "express";
+const router = Router();
+export default router;
diff --git a/dist/controllers/animeCategory.controller.d.ts b/dist/controllers/animeCategory.controller.d.ts
new file mode 100644
index 0000000..635ec04
--- /dev/null
+++ b/dist/controllers/animeCategory.controller.d.ts
@@ -0,0 +1,3 @@
+import { Handler } from "express";
+declare const getAnimeCategory: Handler;
+export default getAnimeCategory;
diff --git a/dist/controllers/animeCategory.controller.js b/dist/controllers/animeCategory.controller.js
new file mode 100644
index 0000000..cb6f53f
--- /dev/null
+++ b/dist/controllers/animeCategory.controller.js
@@ -0,0 +1,23 @@
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const parsers_1 = require("../parsers");
+const http_errors_1 = __importDefault(require("http-errors"));
+const getAnimeCategory = async (req, res, next) => {
+ try {
+ const category = decodeURIComponent(req.params.category);
+ const page = req.query.page
+ ? Number(decodeURIComponent(req.query?.page))
+ : 1;
+ if (!category)
+ throw http_errors_1.default.BadRequest("category required");
+ const data = await (0, parsers_1.scrapeAnimeCategory)(category, page);
+ res.status(200).json(data);
+ }
+ catch (err) {
+ next(err);
+ }
+};
+exports.default = getAnimeCategory;
diff --git a/dist/controllers/index.d.ts b/dist/controllers/index.d.ts
new file mode 100644
index 0000000..c6e82eb
--- /dev/null
+++ b/dist/controllers/index.d.ts
@@ -0,0 +1,2 @@
+import getAnimeCategory from "./animeCategory.controller";
+export { getAnimeCategory };
diff --git a/dist/controllers/index.js b/dist/controllers/index.js
new file mode 100644
index 0000000..a8b27fa
--- /dev/null
+++ b/dist/controllers/index.js
@@ -0,0 +1,8 @@
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.getAnimeCategory = void 0;
+const animeCategory_controller_1 = __importDefault(require("./animeCategory.controller"));
+exports.getAnimeCategory = animeCategory_controller_1.default;
diff --git a/dist/models/anime.d.ts b/dist/models/anime.d.ts
new file mode 100644
index 0000000..b46e995
--- /dev/null
+++ b/dist/models/anime.d.ts
@@ -0,0 +1,33 @@
+export interface Anime {
+ id: string | null;
+ name: string | null;
+ poster: string | null;
+ duration: string | null;
+ type: string | null;
+ rating: string | null;
+ episodes: string | null;
+}
+type CommonAnimeProps = "id" | "name" | "poster";
+export interface Top10Anime extends Pick<Anime, CommonAnimeProps> {
+ rank: number | null;
+ eps: {
+ sub: number | null;
+ dub: number | null;
+ };
+}
+export type Top10AnimeTimePeriod = "day" | "week" | "month";
+export type AnimeCategories = "most-favorite" | "most-popular" | "subbed-anime" | "dubbed-anime" | "recently-updated" | "recently-added" | "top-upcoming" | "top-airing" | "movie" | "special" | "ova" | "ona" | "tv" | "completed";
+export declare enum Servers {
+ AsianLoad = "asianload",
+ GogoCDN = "gogocdn",
+ StreamSB = "streamsb",
+ MixDrop = "mixdrop",
+ UpCloud = "upcloud",
+ VidCloud = "vidcloud",
+ StreamTape = "streamtape",
+ VizCloud = "vizcloud",
+ MyCloud = "mycloud",
+ Filemoon = "filemoon",
+ VidStreaming = "vidstreaming"
+}
+export {};
diff --git a/dist/models/anime.js b/dist/models/anime.js
new file mode 100644
index 0000000..68b3bef
--- /dev/null
+++ b/dist/models/anime.js
@@ -0,0 +1,17 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.Servers = void 0;
+var Servers;
+(function (Servers) {
+ Servers["AsianLoad"] = "asianload";
+ Servers["GogoCDN"] = "gogocdn";
+ Servers["StreamSB"] = "streamsb";
+ Servers["MixDrop"] = "mixdrop";
+ Servers["UpCloud"] = "upcloud";
+ Servers["VidCloud"] = "vidcloud";
+ Servers["StreamTape"] = "streamtape";
+ Servers["VizCloud"] = "vizcloud";
+ Servers["MyCloud"] = "mycloud";
+ Servers["Filemoon"] = "filemoon";
+ Servers["VidStreaming"] = "vidstreaming";
+})(Servers || (exports.Servers = Servers = {}));
diff --git a/dist/models/index.d.ts b/dist/models/index.d.ts
new file mode 100644
index 0000000..7afe301
--- /dev/null
+++ b/dist/models/index.d.ts
@@ -0,0 +1,3 @@
+import { Anime, AnimeCategories, Top10Anime, Top10AnimeTimePeriod, Servers } from "./anime";
+import { ScrapedAnimeCategory } from "./parser";
+export { Anime, AnimeCategories, Top10Anime, Top10AnimeTimePeriod, Servers, ScrapedAnimeCategory, };
diff --git a/dist/models/index.js b/dist/models/index.js
new file mode 100644
index 0000000..78ec497
--- /dev/null
+++ b/dist/models/index.js
@@ -0,0 +1,5 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.Servers = void 0;
+const anime_1 = require("./anime");
+Object.defineProperty(exports, "Servers", { enumerable: true, get: function () { return anime_1.Servers; } });
diff --git a/dist/models/parser.d.ts b/dist/models/parser.d.ts
new file mode 100644
index 0000000..09484b7
--- /dev/null
+++ b/dist/models/parser.d.ts
@@ -0,0 +1,15 @@
+import { HttpError } from "http-errors";
+import { Anime, AnimeCategories, Top10Anime } from "./anime";
+export interface ScrapedAnimeCategory {
+ animes: Array<Anime> | HttpError;
+ genres: Array<string>;
+ top10Animes: {
+ today: Array<Top10Anime> | HttpError;
+ week: Array<Top10Anime> | HttpError;
+ month: Array<Top10Anime> | HttpError;
+ };
+ category: AnimeCategories;
+ currentPage: number;
+ hasNextPage: boolean;
+ totalPages: number;
+}
diff --git a/dist/models/parser.js b/dist/models/parser.js
new file mode 100644
index 0000000..c8ad2e5
--- /dev/null
+++ b/dist/models/parser.js
@@ -0,0 +1,2 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
diff --git a/dist/parsers/animeCategory.d.ts b/dist/parsers/animeCategory.d.ts
new file mode 100644
index 0000000..3c72412
--- /dev/null
+++ b/dist/parsers/animeCategory.d.ts
@@ -0,0 +1,4 @@
+import { HttpError } from "http-errors";
+import { ScrapedAnimeCategory, AnimeCategories } from "../models";
+declare function scrapeAnimeCategory(category: AnimeCategories, page?: number): Promise<ScrapedAnimeCategory | HttpError>;
+export default scrapeAnimeCategory;
diff --git a/dist/parsers/animeCategory.js b/dist/parsers/animeCategory.js
new file mode 100644
index 0000000..347d903
--- /dev/null
+++ b/dist/parsers/animeCategory.js
@@ -0,0 +1,112 @@
+"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const axios_1 = __importStar(require("axios"));
+const cheerio_1 = require("cheerio");
+const utils_1 = require("../utils");
+const http_errors_1 = __importDefault(require("http-errors"));
+async function scrapeAnimeCategory(category, page = 1) {
+ const res = {
+ animes: [],
+ genres: [],
+ top10Animes: {
+ today: [],
+ week: [],
+ month: [],
+ },
+ category,
+ currentPage: Number(page),
+ hasNextPage: false,
+ totalPages: 0,
+ };
+ try {
+ const scrapeUrl = new URL(category, utils_1.SRC_BASE_URL);
+ const mainPage = await axios_1.default.get(`${scrapeUrl}?page=${page}`, {
+ headers: {
+ "User-Agent": utils_1.USER_AGENT_HEADER,
+ "Accept-Encoding": utils_1.ACCEPT_ENCODING_HEADER,
+ Accept: utils_1.ACCEPT_HEADER,
+ },
+ });
+ const $ = (0, cheerio_1.load)(mainPage.data);
+ const selector = "#main-content .tab-content .film_list-wrap .flw-item";
+ res.hasNextPage =
+ $(".pagination > li").length > 0
+ ? $(".pagination li.active").length > 0
+ ? $(".pagination > li").last().hasClass("active")
+ ? false
+ : true
+ : false
+ : false;
+ res.totalPages =
+ parseInt($('.pagination > .page-item a[title="Last"]')
+ ?.attr("href")
+ ?.split("=")
+ .pop() ??
+ $('.pagination > .page-item a[title="Next"]')
+ ?.attr("href")
+ ?.split("=")
+ .pop() ??
+ $(".pagination > .page-item.active a")?.text()?.trim()) || 0;
+ if (res.totalPages === 0 && !res.hasNextPage) {
+ res.totalPages = 0;
+ }
+ res.animes = (0, utils_1.extractAnimes)($, selector);
+ if (res.animes.length === 0) {
+ res.totalPages = 0;
+ res.hasNextPage = false;
+ }
+ const genreSelector = "#main-sidebar .block_area.block_area_sidebar.block_area-genres .sb-genre-list li";
+ $(genreSelector).each((i, el) => {
+ res.genres.push(`${$(el).text().trim()}`);
+ });
+ const top10AnimeSelector = '#main-sidebar .block_area-realtime [id^="top-viewed-"]';
+ $(top10AnimeSelector).each((i, el) => {
+ const period = $(el).attr("id")?.split("-")?.pop()?.trim();
+ if (period === "day") {
+ res.top10Animes.today = (0, utils_1.extractTop10Animes)($, period);
+ return;
+ }
+ if (period === "week") {
+ res.top10Animes.week = (0, utils_1.extractTop10Animes)($, period);
+ return;
+ }
+ if (period === "month") {
+ res.top10Animes.month = (0, utils_1.extractTop10Animes)($, period);
+ }
+ });
+ return res;
+ }
+ catch (err) {
+ if (err instanceof axios_1.AxiosError) {
+ throw (0, http_errors_1.default)(err?.response?.status || 500, err?.response?.statusText || "Something went wrong");
+ }
+ throw http_errors_1.default.InternalServerError(err?.message);
+ }
+}
+exports.default = scrapeAnimeCategory;
diff --git a/dist/parsers/index.d.ts b/dist/parsers/index.d.ts
new file mode 100644
index 0000000..5ac4249
--- /dev/null
+++ b/dist/parsers/index.d.ts
@@ -0,0 +1,2 @@
+import scrapeAnimeCategory from "./animeCategory";
+export { scrapeAnimeCategory };
diff --git a/dist/parsers/index.js b/dist/parsers/index.js
new file mode 100644
index 0000000..f23c21d
--- /dev/null
+++ b/dist/parsers/index.js
@@ -0,0 +1,8 @@
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.scrapeAnimeCategory = void 0;
+const animeCategory_1 = __importDefault(require("./animeCategory"));
+exports.scrapeAnimeCategory = animeCategory_1.default;
diff --git a/dist/routes/index.d.ts b/dist/routes/index.d.ts
new file mode 100644
index 0000000..5ec6d27
--- /dev/null
+++ b/dist/routes/index.d.ts
@@ -0,0 +1,3 @@
+import { IRouter } from "express";
+declare const router: IRouter;
+export default router;
diff --git a/dist/routes/index.js b/dist/routes/index.js
new file mode 100644
index 0000000..5e5579b
--- /dev/null
+++ b/dist/routes/index.js
@@ -0,0 +1,7 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+const express_1 = require("express");
+const controllers_1 = require("../controllers");
+const router = (0, express_1.Router)();
+router.get("/:category", controllers_1.getAnimeCategory);
+exports.default = router;
diff --git a/dist/server.d.ts b/dist/server.d.ts
new file mode 100644
index 0000000..cb0ff5c
--- /dev/null
+++ b/dist/server.d.ts
@@ -0,0 +1 @@
+export {};
diff --git a/dist/server.js b/dist/server.js
index f7d8395..12d78e3 100644
--- a/dist/server.js
+++ b/dist/server.js
@@ -1,15 +1,33 @@
-import express from "express";
-import { config } from "dotenv";
-import morgan from "morgan";
-import createHttpError from "http-errors";
-config();
-const app = express();
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+const express_1 = __importDefault(require("express"));
+const dotenv_1 = require("dotenv");
+const morgan_1 = __importDefault(require("morgan"));
+const http_errors_1 = __importDefault(require("http-errors"));
+const routes_1 = __importDefault(require("./routes"));
+(0, dotenv_1.config)();
+const app = (0, express_1.default)();
const PORT = Number(process.env.PORT) || 4000;
-app.use(morgan("dev"));
+app.use((0, morgan_1.default)("dev"));
app.get("/", (req, res) => {
- res.json("hi there");
+ res.send(`
+ <body style="font-family: sans-serif; background: #000; color: #FFF;">
+ <h3>Welcome to Zoro.to api ⚔️</h3>
+ <a
+ style="color: #00AEDD;"
+ href="https://github.com/ghoshRitesh12/zoro.to-api#readme"
+ rel="noopener noreferer"
+ >
+ Visit docs for more into
+ </a>
+ </body>
+ `);
});
-app.use((req, res, next) => next(createHttpError.NotFound()));
+app.use("/anime", routes_1.default);
+app.use((req, res, next) => next(http_errors_1.default.NotFound()));
const errorHandler = (error, req, res, next) => {
const status = error?.status || 500;
res.status(status).json({
@@ -19,5 +37,5 @@ const errorHandler = (error, req, res, next) => {
};
app.use(errorHandler);
app.listen(PORT, () => {
- console.log(`⚔ api @ http://localhost:${PORT}`);
+ console.log(`⚔️ api @ http://localhost:${PORT}`);
});
diff --git a/dist/types.js b/dist/types.js
new file mode 100644
index 0000000..4928f61
--- /dev/null
+++ b/dist/types.js
@@ -0,0 +1,14 @@
+export var Servers;
+(function (Servers) {
+ Servers["AsianLoad"] = "asianload";
+ Servers["GogoCDN"] = "gogocdn";
+ Servers["StreamSB"] = "streamsb";
+ Servers["MixDrop"] = "mixdrop";
+ Servers["UpCloud"] = "upcloud";
+ Servers["VidCloud"] = "vidcloud";
+ Servers["StreamTape"] = "streamtape";
+ Servers["VizCloud"] = "vizcloud";
+ Servers["MyCloud"] = "mycloud";
+ Servers["Filemoon"] = "filemoon";
+ Servers["VidStreaming"] = "vidstreaming";
+})(Servers || (Servers = {}));
diff --git a/dist/utils.d.ts b/dist/utils.d.ts
new file mode 100644
index 0000000..719e176
--- /dev/null
+++ b/dist/utils.d.ts
@@ -0,0 +1,12 @@
+import { HttpError } from "http-errors";
+import { CheerioAPI, SelectorType } from "cheerio";
+import { Anime, Top10Anime, Top10AnimeTimePeriod } from "./models";
+export declare const USER_AGENT_HEADER: string | undefined;
+export declare const ACCEPT_HEADER: string | undefined;
+export declare const ACCEPT_ENCODING_HEADER: string | undefined;
+export declare const SRC_BASE_URL: string | undefined;
+export declare const SRC_AJAX_URL: string | undefined;
+export declare const SRC_HOME_URL: string | undefined;
+export declare const SRC_SEARCH_URL: string | undefined;
+export declare function extractAnimes($: CheerioAPI, selector: SelectorType): Array<Anime> | HttpError;
+export declare function extractTop10Animes($: CheerioAPI, period: Top10AnimeTimePeriod): Array<Top10Anime> | HttpError;
diff --git a/dist/utils.js b/dist/utils.js
new file mode 100644
index 0000000..2e6b45d
--- /dev/null
+++ b/dist/utils.js
@@ -0,0 +1,95 @@
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.extractTop10Animes = exports.extractAnimes = exports.SRC_SEARCH_URL = exports.SRC_HOME_URL = exports.SRC_AJAX_URL = exports.SRC_BASE_URL = exports.ACCEPT_ENCODING_HEADER = exports.ACCEPT_HEADER = exports.USER_AGENT_HEADER = void 0;
+const dotenv_1 = require("dotenv");
+const http_errors_1 = __importDefault(require("http-errors"));
+(0, dotenv_1.config)();
+exports.USER_AGENT_HEADER = process.env.APP_SRC_USER_AGENT;
+exports.ACCEPT_HEADER = process.env.APP_SRC_ACCEPT_HEADER;
+exports.ACCEPT_ENCODING_HEADER = process.env.APP_SRC_ACCEPT_HEADER;
+exports.SRC_BASE_URL = process.env.APP_SRC_BASE_URL;
+exports.SRC_AJAX_URL = process.env.APP_SRC_AJAX_URL;
+exports.SRC_HOME_URL = process.env.APP_SRC_HOME_URL;
+exports.SRC_SEARCH_URL = process.env.APP_SRC_SEARCH_URL;
+function extractAnimes($, selector) {
+ try {
+ const animes = [];
+ $(selector).each((i, el) => {
+ const animeId = $(el)
+ .find(".film-detail .film-name .dynamic-name")
+ ?.attr("href")
+ ?.slice(1)
+ .split("?ref=search")[0] || null;
+ animes.push({
+ id: animeId,
+ name: $(el)
+ .find(".film-detail .film-name .dynamic-name")
+ ?.text()
+ ?.trim(),
+ poster: $(el)
+ .find(".film-poster .film-poster-img")
+ ?.attr("data-src")
+ ?.trim() || null,
+ duration: $(el)
+ .find(".film-detail .fd-infor .fdi-item.fdi-duration")
+ ?.text()
+ ?.trim(),
+ type: $(el)
+ .find(".film-detail .fd-infor .fdi-item:nth-of-type(1)")
+ ?.text()
+ ?.trim(),
+ rating: $(el).find(".film-poster .tick-rate")?.text()?.trim() || null,
+ episodes: $(el)
+ .find(".film-poster .tick-eps")
+ ?.text()
+ ?.trim()
+ .split(" ")
+ .pop() || null,
+ });
+ });
+ return animes;
+ }
+ catch (err) {
+ throw http_errors_1.default.InternalServerError(err?.message || "Something went wrong");
+ }
+}
+exports.extractAnimes = extractAnimes;
+function extractTop10Animes($, period) {
+ try {
+ const animes = [];
+ const selector = `#top-viewed-${period} ul li`;
+ $(selector).each((i, el) => {
+ animes.push({
+ id: $(el)
+ .find(".film-detail .dynamic-name")
+ ?.attr("href")
+ ?.slice(1)
+ .trim() || null,
+ rank: Number($(el).find(".film-number span")?.text()?.trim()) || null,
+ name: $(el).find(".film-detail .dynamic-name")?.text()?.trim() || null,
+ poster: $(el)
+ .find(".film-poster .film-poster-img")
+ ?.attr("data-src")
+ ?.trim() || null,
+ eps: {
+ sub: Number($(el)
+ .find(".film-detail .fd-infor .tick-item.tick-sub")
+ ?.text()
+ ?.trim()) || null,
+ dub: Number($(el)
+ .find(".film-detail .fd-infor .tick-item.tick-dub")
+ ?.text()
+ ?.trim()) || null,
+ },
+ });
+ });
+ return animes;
+ }
+ catch (err) {
+ throw http_errors_1.default.InternalServerError(err?.message || "Something went wrong");
+ }
+}
+exports.extractTop10Animes = extractTop10Animes;
diff --git a/dist/utils/index.d.ts b/dist/utils/index.d.ts
new file mode 100644
index 0000000..4156d72
--- /dev/null
+++ b/dist/utils/index.d.ts
@@ -0,0 +1,12 @@
+import { HttpError } from "http-errors";
+import { CheerioAPI, SelectorType } from "cheerio";
+import { Anime, Top10Anime, Top10AnimeTimePeriod } from "../models";
+export declare const USER_AGENT_HEADER: string | undefined;
+export declare const ACCEPT_HEADER: string | undefined;
+export declare const ACCEPT_ENCODING_HEADER: string | undefined;
+export declare const SRC_BASE_URL: string | undefined;
+export declare const SRC_AJAX_URL: string | undefined;
+export declare const SRC_HOME_URL: string | undefined;
+export declare const SRC_SEARCH_URL: string | undefined;
+export declare function extractAnimes($: CheerioAPI, selector: SelectorType): Array<Anime> | HttpError;
+export declare function extractTop10Animes($: CheerioAPI, period: Top10AnimeTimePeriod): Array<Top10Anime> | HttpError;
diff --git a/dist/utils/index.js b/dist/utils/index.js
new file mode 100644
index 0000000..2e6b45d
--- /dev/null
+++ b/dist/utils/index.js
@@ -0,0 +1,95 @@
+"use strict";
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.extractTop10Animes = exports.extractAnimes = exports.SRC_SEARCH_URL = exports.SRC_HOME_URL = exports.SRC_AJAX_URL = exports.SRC_BASE_URL = exports.ACCEPT_ENCODING_HEADER = exports.ACCEPT_HEADER = exports.USER_AGENT_HEADER = void 0;
+const dotenv_1 = require("dotenv");
+const http_errors_1 = __importDefault(require("http-errors"));
+(0, dotenv_1.config)();
+exports.USER_AGENT_HEADER = process.env.APP_SRC_USER_AGENT;
+exports.ACCEPT_HEADER = process.env.APP_SRC_ACCEPT_HEADER;
+exports.ACCEPT_ENCODING_HEADER = process.env.APP_SRC_ACCEPT_HEADER;
+exports.SRC_BASE_URL = process.env.APP_SRC_BASE_URL;
+exports.SRC_AJAX_URL = process.env.APP_SRC_AJAX_URL;
+exports.SRC_HOME_URL = process.env.APP_SRC_HOME_URL;
+exports.SRC_SEARCH_URL = process.env.APP_SRC_SEARCH_URL;
+function extractAnimes($, selector) {
+ try {
+ const animes = [];
+ $(selector).each((i, el) => {
+ const animeId = $(el)
+ .find(".film-detail .film-name .dynamic-name")
+ ?.attr("href")
+ ?.slice(1)
+ .split("?ref=search")[0] || null;
+ animes.push({
+ id: animeId,
+ name: $(el)
+ .find(".film-detail .film-name .dynamic-name")
+ ?.text()
+ ?.trim(),
+ poster: $(el)
+ .find(".film-poster .film-poster-img")
+ ?.attr("data-src")
+ ?.trim() || null,
+ duration: $(el)
+ .find(".film-detail .fd-infor .fdi-item.fdi-duration")
+ ?.text()
+ ?.trim(),
+ type: $(el)
+ .find(".film-detail .fd-infor .fdi-item:nth-of-type(1)")
+ ?.text()
+ ?.trim(),
+ rating: $(el).find(".film-poster .tick-rate")?.text()?.trim() || null,
+ episodes: $(el)
+ .find(".film-poster .tick-eps")
+ ?.text()
+ ?.trim()
+ .split(" ")
+ .pop() || null,
+ });
+ });
+ return animes;
+ }
+ catch (err) {
+ throw http_errors_1.default.InternalServerError(err?.message || "Something went wrong");
+ }
+}
+exports.extractAnimes = extractAnimes;
+function extractTop10Animes($, period) {
+ try {
+ const animes = [];
+ const selector = `#top-viewed-${period} ul li`;
+ $(selector).each((i, el) => {
+ animes.push({
+ id: $(el)
+ .find(".film-detail .dynamic-name")
+ ?.attr("href")
+ ?.slice(1)
+ .trim() || null,
+ rank: Number($(el).find(".film-number span")?.text()?.trim()) || null,
+ name: $(el).find(".film-detail .dynamic-name")?.text()?.trim() || null,
+ poster: $(el)
+ .find(".film-poster .film-poster-img")
+ ?.attr("data-src")
+ ?.trim() || null,
+ eps: {
+ sub: Number($(el)
+ .find(".film-detail .fd-infor .tick-item.tick-sub")
+ ?.text()
+ ?.trim()) || null,
+ dub: Number($(el)
+ .find(".film-detail .fd-infor .tick-item.tick-dub")
+ ?.text()
+ ?.trim()) || null,
+ },
+ });
+ });
+ return animes;
+ }
+ catch (err) {
+ throw http_errors_1.default.InternalServerError(err?.message || "Something went wrong");
+ }
+}
+exports.extractTop10Animes = extractTop10Animes;