From 7ac068d3e541e4e3f657542467240947d8cefdf4 Mon Sep 17 00:00:00 2001 From: Zukaritasu <77790801+Zukaritasu@users.noreply.github.com> Date: Mon, 24 Jun 2024 09:19:26 -0400 Subject: [PATCH 1/3] Update README.md There was a problem with the logo in the README that has been fixed --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a6726b25..f9c9b1a6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # JIMOV - Media Content API -![image description](<.gitbook/assets/JIMOV\_logo (1).png>) +![image description](<./src/images/JIMOV_logo.png>) [![discordBadge](https://img.shields.io/badge/Chat-Click%20here-7289d9?style=for-the-badge\&logo=discord)](https://discord.com/invite/tyZ39GCX7R)[![documentationBadge](https://img.shields.io/badge/License-MIT-green.svg?style=for-the-badge)](https://choosealicense.com/licenses/mit/)[![documentationBadge](https://img.shields.io/badge/Documentation-Click%20here-blue?style=for-the-badge)](https://jimov-api-docs.vercel.app/) From 6ffe7016d836b139b36324012332b7aa0ac341c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=83=80=E3=82=A4=E3=83=AC=E3=82=AF=E3=83=88=E3=82=B3?= =?UTF-8?q?=E3=83=8D=E3=82=AF=E3=83=88?= <52444606+TokyoTF@users.noreply.github.com> Date: Fri, 19 Jul 2024 22:30:45 -0400 Subject: [PATCH 2/3] Add: HentaiLa Provider --- src/index.ts | 3 +- .../v1/anime/hentaila/HentaiLaRoutes.ts | 30 ++++ src/scraper/sites/anime/hentaila/HentaiLa.ts | 139 ++++++++++++++++++ src/scraper/sites/manga/comick/Comick.ts | 3 - src/test/Hentaila.spec.ts | 24 +++ 5 files changed, 195 insertions(+), 4 deletions(-) create mode 100644 src/routes/v1/anime/hentaila/HentaiLaRoutes.ts create mode 100644 src/scraper/sites/anime/hentaila/HentaiLa.ts create mode 100644 src/test/Hentaila.spec.ts diff --git a/src/index.ts b/src/index.ts index 7b443354..d47794c9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,6 +15,7 @@ import tioanime from "../src/routes/v1/anime/tioanime/TioAnimeRoute"; import WcoStream from "../src/routes/v1/anime/wcostream/wcostreamRoutes"; import AnimeBlix from "../src/routes/v1/anime/animeblix/AnimeBlixRoutes"; import Animevostfr from "../src/routes/v1/anime/animevostfr/AnimevostfrRoutes"; +import hentaila from "../src/routes/v1/anime/hentaila/HentailaRoutes"; /* Manga */ import comick from "../src/routes/v1/manga/comick/ComickRoutes"; @@ -47,7 +48,7 @@ app.use(tioanime); app.use(WcoStream); app.use(AnimeBlix); app.use(Animevostfr); - +app.use(hentaila); /* anime */ /*Manga*/ diff --git a/src/routes/v1/anime/hentaila/HentaiLaRoutes.ts b/src/routes/v1/anime/hentaila/HentaiLaRoutes.ts new file mode 100644 index 00000000..4cf36bf8 --- /dev/null +++ b/src/routes/v1/anime/hentaila/HentaiLaRoutes.ts @@ -0,0 +1,30 @@ +import { Router } from "express"; +import { HentaiLa } from "../../../../scraper/sites/anime/hentaila/HentaiLa"; +const Anime = new HentaiLa(); +const router = Router(); + +// Filter +router.get("/anime/hentaila/filter", async (req, res) => { + const { search } = req.query; + + const data = await Anime.GetItemByFilter( + search as string + ); + res.send(data); +}); + +// Anime Info +(Episodes list) +router.get("/anime/hentaila/name/:name", async (req, res) => { + const { name } = req.params; + const data = await Anime.GetItemInfo(name); + res.send(data); +}); + +// Episode Info +(Video Servers) +router.get("/anime/hentaila/episode/:episode", async (req, res) => { + const { episode } = req.params; + const data = await Anime.GetEpisodeServers(episode); + res.send(data); +}); + +export default router; diff --git a/src/scraper/sites/anime/hentaila/HentaiLa.ts b/src/scraper/sites/anime/hentaila/HentaiLa.ts new file mode 100644 index 00000000..505c1b22 --- /dev/null +++ b/src/scraper/sites/anime/hentaila/HentaiLa.ts @@ -0,0 +1,139 @@ +import * as cheerio from "cheerio"; +import axios from "axios"; +import { AnimeMedia } from "../../../../types/anime"; +import { Episode, EpisodeServer } from "../../../../types/episode"; + +import { ResultSearch, AnimeResult } from "../../../../types/search"; +import { AnimeScraperModel } from "../../../../models/AnimeScraperModel"; + +export class HentaiLa extends AnimeScraperModel { + readonly url = "https://www4.hentaila.com"; + + async GetItemInfo(anime: string): Promise { + try { + const formatUrl = !anime.includes("hentai-") ? "hentai-" + anime : anime; + const { data } = await axios.get(`${this.url}/${formatUrl}`); + const $ = cheerio.load(data); + const genres = []; + $(".genres a").each((_i, e) => genres.push($(e).text())); + + const AnimeInfo: AnimeMedia = { + name: $(".hentai-single .h-header h1.h-title").text().trim(), + url: `/anime/hentaila/name/${anime}`, + synopsis: $(".hentai-single .h-content p").text(), + image: { + url: `${this.url}${$(".hentai-single .h-thumb figure img").attr( + "src" + )}`, + }, + genres: [...genres], + nsfw: true, + type: "Anime", + status: $(".h-meta .status-on").text().includes("En Emision") + ? "En emisiĆ³n" + : "Finalizado", + episodes: [], + }; + + $(".episodes-list article").each((_i, e) => { + const number = Number( + $(e) + .find("h2.h-title") + .text() + .replace( + $(".hentai-single .h-header h1.h-title").text() + " Episodio", + "" + ) + ); + const AnimeEpisode: Episode = { + name: $(e).find("h2.h-title").text(), + num: number, + thumbnail: { + url: `${this.url}${$(e).find(".h-thumb figure img").attr("src")}`, + }, + url: `/anime/hentaila/episode/${formatUrl}-${number}`, + }; + + AnimeInfo.episodes.push(AnimeEpisode); + }); + + return AnimeInfo; + } catch (error) { + console.log(error); + } + } + async GetEpisodeServers(episode: string): Promise { + try { + const number = episode.substring(episode.lastIndexOf("-") + 1); + const anime = episode.substring(0, episode.lastIndexOf("-")); + const formaturl = anime.includes("hentai-") + ? anime.replace("hentai-", "") + : anime; + const { data } = await axios.get( + `${this.url}/ver/${formaturl}-${number}` + ); + const $ = cheerio.load(data); + + const AnimeEpisodeInfo: Episode = { + name: $(".section-header h1.section-title").text(), + url: `/anime/hentaila/episode/${episode}`, + num: Number(number), + servers: [], + }; + + const video_script = $("script").get().at(-3).children[0].data; + const video_format = eval( + video_script + .slice( + video_script.indexOf("var videos ="), + video_script.lastIndexOf("$(document)") + ) + .replace("var videos =", "") + ); + for (let index = 0; index < video_format.length; index++) { + const Server: EpisodeServer = { + name: video_format[index][0].includes("Yupi") ? "YourUpload" : video_format[index][0], + url: video_format[index][1], + }; + AnimeEpisodeInfo.servers.push(Server); + } + + AnimeEpisodeInfo.servers.sort((a, b) => a.name.localeCompare(b.name)); + return AnimeEpisodeInfo; + } catch (error) { + console.log(error); + } + } + + async GetItemByFilter( + search?: string + ): Promise> { + try { + const content = new FormData(); + content.append("value", search); + const { data } = await axios.post(`${this.url}/api/search`, content); + + const animeSearch: ResultSearch = { + nav: { + count: data.length, + current: 1, + next: 0, + hasNext: false, + }, + results: [], + }; + data.map((e) => { + const animeSearchData: AnimeResult = { + name: e.title, + image: `${this.url}/uploads/portadas/${e.id}.jpg`, + url: `/anime/hentaila/name/${e.slug}`, + type: "Anime", + }; + animeSearch.results.push(animeSearchData); + }); + return animeSearch; + } catch (error) { + console.log(error); + } + } +} diff --git a/src/scraper/sites/manga/comick/Comick.ts b/src/scraper/sites/manga/comick/Comick.ts index 37936924..5448d97f 100644 --- a/src/scraper/sites/manga/comick/Comick.ts +++ b/src/scraper/sites/manga/comick/Comick.ts @@ -78,7 +78,6 @@ export class Comick { return ResultList; } catch (error) { - console.log(error); } } @@ -154,7 +153,6 @@ export class Comick { } return MangaInfo; } catch (error) { - console.log(error); } } @@ -245,7 +243,6 @@ export class Comick { return MangaChapterInfoChapter; } } catch (error) { - console.log(error); } } } diff --git a/src/test/Hentaila.spec.ts b/src/test/Hentaila.spec.ts new file mode 100644 index 00000000..adf27162 --- /dev/null +++ b/src/test/Hentaila.spec.ts @@ -0,0 +1,24 @@ +import { HentaiLa } from "../scraper/sites/anime/hentaila/HentaiLa"; + +describe("AnimeLatinohd", () => { + let hentaila: HentaiLa; + + beforeEach(() => { + hentaila = new HentaiLa(); + }); + + it("should get anime info successfully", async () => { + const animeInfo = await hentaila.GetItemInfo("hentai-korashime-2"); + expect(animeInfo.name).toBe("Korashime 2"); + expect(animeInfo.image.url).toContain(".jpg"); + expect(animeInfo.status).toBe("Finalizado"); + expect(animeInfo.synopsis?.length).toBeGreaterThan(0); + expect(animeInfo.genres?.length).toBeGreaterThan(0); + expect(animeInfo.episodes?.length).toBeGreaterThan(0); + }); + + it("should filter anime successfully", async () => { + const result = await hentaila.GetItemByFilter("na"); + expect(result.results.length).toBeGreaterThan(0); + }, 10000); +}); From 158314d339d58ebd2a523820892ffacefd479b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=83=80=E3=82=A4=E3=83=AC=E3=82=AF=E3=83=88=E3=82=B3?= =?UTF-8?q?=E3=83=8D=E3=82=AF=E3=83=88?= <52444606+TokyoTF@users.noreply.github.com> Date: Fri, 19 Jul 2024 22:38:52 -0400 Subject: [PATCH 3/3] Fix: path Route HentaiLa --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index d47794c9..34ea41fd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,7 +15,7 @@ import tioanime from "../src/routes/v1/anime/tioanime/TioAnimeRoute"; import WcoStream from "../src/routes/v1/anime/wcostream/wcostreamRoutes"; import AnimeBlix from "../src/routes/v1/anime/animeblix/AnimeBlixRoutes"; import Animevostfr from "../src/routes/v1/anime/animevostfr/AnimevostfrRoutes"; -import hentaila from "../src/routes/v1/anime/hentaila/HentailaRoutes"; +import hentaila from "../src/routes/v1/anime/hentaila/HentaiLaRoutes"; /* Manga */ import comick from "../src/routes/v1/manga/comick/ComickRoutes";