Skip to content

Commit

Permalink
Merge pull request #168 from koikiss-dev/zuka
Browse files Browse the repository at this point in the history
Zuka
  • Loading branch information
koikiss-dev authored Jul 2, 2024
2 parents b0d6fb5 + dfdf43d commit 9b7efb5
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 112 deletions.
22 changes: 20 additions & 2 deletions src/routes/v1/anime/monoschinos/MonosChinosRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,33 @@ r.get("/anime/monoschinos/filter", async (req, res) => {
const cat = req.query.category as string;
const gen = req.query.gen as string;
const year = req.query.year as string;
const letter = req.query.letter as string;

const monos = new Monoschinos();
const animeInfo = await monos.filter(title, cat, gen, year, letter);
const animeInfo = await monos.filter(title, cat, gen, year);
res.send(animeInfo);
} catch (error) {
console.log(error);
res.status(500).send(error);
}
});

//last episodes
r.get("/anime/monoschinos/last/:option", async (req, res) => {
try {
const { option } = req.params;

const monos = new Monoschinos();
if ("episodes" === option) {
res.send(await monos.getLastEpisodes());
} else if ("animes" === option) {
res.send(await monos.getLastAnimes());
} else {
throw "Invalid option in the URL";
}
} catch (error) {
console.log(error);
res.status(500).send(error);
}
});

export default r;
182 changes: 106 additions & 76 deletions src/scraper/sites/anime/monoschinos/Monoschinos.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import axios from "axios";
import axios, { AxiosResponse } from "axios";
import * as cheerio from "cheerio";
import { api, utils } from "../../../../types/utils";
import * as types from "../../../../types/.";
import { ResultSearch, IResultSearch, IAnimeSearch } from "../../../../types/search";
import { ResultSearch, IResultSearch, AnimeResult } from "../../../../types/search";

const PageInfo = {
name: 'monoschinos',
Expand All @@ -21,11 +21,19 @@ const PageInfo = {
async function getEpisodeServers(url: string): Promise<types.EpisodeServer[]> {
let servers: types.EpisodeServer[] = [];
const $ = cheerio.load((await axios.get(url)).data);
$('div.playother').children().each((_i, element) => {
servers.push(new types.EpisodeServer($(element).text().trim(),
Buffer.from($(element).attr('data-player'), 'base64').toString('binary'))
);
const referenceElement = $('p.fs-5.text-light.my-4');
const divElement = referenceElement.next('div.d-flex');

if (divElement.length === 0) {
throw new Error('The div following the reference element was not found');
}

divElement.find('a').each((_i, element) => {
servers.push(new types.EpisodeServer($(element).text().trim(),
$(element).attr('href')
));
});

return servers;
}

Expand All @@ -35,12 +43,12 @@ async function getEpisodeServers(url: string): Promise<types.EpisodeServer[]> {
* @param element
* @returns
*/
async function getEpisodeByElement($, element): Promise<types.Episode> {
const episode = new types.Episode();
episode.number = parseInt($(element).find('div.positioning p').text().trim());
episode.image = $(element).find('div.animeimgdiv img.animeimghv').attr('data-src');
episode.name = $(element).find('h2.animetitles').text().trim();
episode.url = api.getEpisodeURL(PageInfo, $(element).find('a').attr('href'));
function getEpisodeByElement($: cheerio.Root, element: cheerio.Element): types.Episode {
const episode = new types.Episode();
episode.num = parseInt($(element).find('span.episode').text().trim());
episode.thumbnail = new types.Image($(element).find('img').attr('data-src'));
episode.name = $(element).find('h2').text();
episode.url = api.getEpisodeURL(PageInfo, $(element).find('a').attr('href'));
return episode;
}

Expand All @@ -52,12 +60,9 @@ async function getEpisodeByElement($, element): Promise<types.Episode> {
async function getLastEpisodes(): Promise<types.Episode[]> {
let episodes: types.Episode[] = [];
const $ = cheerio.load((await axios.get(PageInfo.url)).data);
const elements = $('div.heroarea div.heroarea1 div.row').children();
for (let i = 0; i < elements.length; i++) {
if ($(elements[i]).children().length != 0) {
episodes.push(await getEpisodeByElement($, elements[i]));
}
}
$('ul.row.row-cols-xl-4.row-cols-lg-4.row-cols-md-3.row-cols-2').find('li').each((_i, element) => {
episodes.push(getEpisodeByElement($, element));
});
return episodes;
}

Expand All @@ -66,29 +71,44 @@ async function getLastEpisodes(): Promise<types.Episode[]> {
* @param $
* @returns
*/
function getGenres($): string[] {
function getGenres($: cheerio.Root): string[] {
let genres: string[] = [];
$('div.chapterdetls2 table tbody a').each((_i, element) => {
genres.push($(element).text().trim())
$('div.tab-content div.tab-pane div.lh-lg a').each((_i, element) => {
genres.push($(element).find('span').text().trim())
});
return genres;
}

/**
*
* @param $
* @param pageData
* @param animeName
* @returns
*/
function getAnimeEpisodes($): types.Episode[] {
async function getAnimeEpisodes($: cheerio.Root, animeName: string, pageData: AxiosResponse<any, any>, animePath: string): Promise<types.Episode[]> {
const response = await fetch($('.caplist').attr('data-ajax'), {
"headers": {
"accept": "application/json, text/javascript, */*; q=0.01",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"cookie": pageData.headers['set-cookie'].join(";"),
},
"body": `_token=${$('meta[name="csrf-token"]').attr('content')}`,
"method": "POST"
})

let episodes: types.Episode[] = [];
$('div.heromain2 div.allanimes div.row').children().each((_i, element) => {
const episode = new types.Episode();
episode.number = parseInt($(element).attr('data-episode').trim());
episode.image = $(element).find('img.animeimghv').attr('data-src');
episode.name = $(element).find('img.animeimghv').attr('alt');
episode.url = api.getEpisodeURL(PageInfo, $(element).find('a').attr('href'));

const length = (await response.json()).eps.length
const image = $('div img.lazy.w-100').attr('data-src')
for (let i = 1; i <= length; i++) {
const episode = new types.Episode();
episode.num = i;
episode.thumbnail = new types.Image(image);
episode.name = `${animeName} Episodio ${i}`;
episode.url = api.getEpisodeURL(PageInfo, `https://monoschinos2.com/ver/${animePath}-episodio-${i}`);
episodes.push(episode);
});
}
return episodes;
}

Expand All @@ -111,8 +131,8 @@ interface ClimaticCalendar {
* @param element
* @returns the calendar of anime
*/
function getAnimeCalendar(element): ClimaticCalendar {
const date = element.find('ol.breadcrumb li.breadcrumb-item').text().trim().split(' ');
function getAnimeCalendar(strDate: string): ClimaticCalendar {
const date = strDate.split(' ');
if (date.length != 5)
return { year: 0, station: null };
else {
Expand All @@ -129,70 +149,75 @@ function getAnimeCalendar(element): ClimaticCalendar {
* @param url
* @returns
*/
async function getAnime(url: string): Promise<types.Anime> {
async function getAnime(url: string): Promise<types.AnimeMedia> {
// The anime page in monoschinos does not define the chronology and type
const $ = cheerio.load((await axios.get(url)).data);
const calendar = getAnimeCalendar($($('div.chapterdetails nav').children()[1]));
const anime = new types.Anime();
anime.name = $('div.chapterdetails').find('h1').text();
anime.alt_name = $('div.chapterdetails').find('span.alterno').text();
anime.url = api.getAnimeURL(PageInfo, url);
anime.synopsis = $('div.chapterdetls2 p').text().trim();
anime.genres = getGenres($);
anime.image = new types.Image($('div.chapterpic img').attr('src'), $('div.herobg img').attr('src'));
anime.status = 'estreno' === $('div.butns button.btn1').text().toLowerCase().trim();
anime.episodes = getAnimeEpisodes($);
anime.date = new types.Calendar(calendar.year);
anime.station = calendar.station;
const pageData = await axios.get(url);
const $ = cheerio.load(pageData.data);

const info = $('div.tab-content div.bg-transparent dl').children();

const calendar = getAnimeCalendar($(info[3]).text().trim());
const anime = new types.AnimeMedia();
anime.name = $(info[5]).text()
anime.alt_names = $(info[7]).text()
anime.url = api.getAnimeURL(PageInfo, url);
anime.synopsis = $('section.d-sm-none div.mt-3 p').text()
anime.image = new types.Image($('div img.bg-secondary').attr('data-src'))
anime.status = $($('div.tab-content div.col-12.col-md-9 div.ms-2').children()[1]).text();
anime.genres = getGenres($);
anime.date = new types.Calendar(calendar.year);
anime.station = calendar.station;
anime.episodes = await getAnimeEpisodes($, anime.name, pageData, url.split('/').pop());
return anime;
}

/**
* If url is null then the function will return a list of the last anime
* that were published, otherwise it refers to a url that contains a
* search filtering that among them can be search by name or search by
* category, genre and date
*
* @throws {Error}
* @param url
* @returns
* @param url web address with results filtering
* @returns anime list
*/
async function getLastAnimes(url?: string): Promise<types.Anime[]> {
let animes: types.Anime[] = [];
const $ = cheerio.load((await axios.get(url ?? `${PageInfo.url}/emision`)).data);
const elements = $('div.heroarea div.heromain div.row').children();
for (let i = 0; i < elements.length; i++) {
const href = $(elements[i]).find('a').attr('href');
if (utils.isUsableValue(href) && href !== 'https://monoschinos2.com/emision?p=2') {
//animes.push(await getAnime(href));

let anime = new types.Anime();
anime.url = $(elements[i]).find('a').attr('href');
anime.image = new types.Image($(elements[i]).find('a img').attr('src'));
anime.name = $(elements[i]).find('h3.seristitles').text();

animes.push(anime);
}
async function getLastAnimes(url?: string): Promise<types.AnimeMedia[]> {
let animes: types.AnimeMedia[] = [];
const $ = cheerio.load((await axios.get(url ?? PageInfo.url)).data);

const addElement = (element: cheerio.Element) => {
let anime = new types.AnimeMedia();
anime.url = api.getAnimeURL(PageInfo, $(element).find('a').attr('href'))
anime.image = new types.Image($(element).find('img').attr('data-src'));
anime.name = $(element).find('h3').text().trim();
animes.push(anime);
}

if (url === null) {
$('ul.row.row-cols-2.row-cols-sm-3').find('li')
.each((_i, element) => addElement(element));
} else {
$('ul.row').find('li')
.each((_i, element) => addElement(element));
}
return animes;
}

//console.log(await getLastAnimes('https://monoschinos2.com/animes?categoria=anime&genero=accion&fecha=2023&letra=A'));

//console.log(await getLastAnimes())

/**
*
*
* @author Zukaritasu
*/
export class Monoschinos
{
getLastEpisodes = getLastEpisodes;
getLastAnimes = getLastEpisodes;
getLastEpisodes = getLastEpisodes;
getLastAnimes = (() => getLastAnimes(null));
getEpisodeServers = getEpisodeServers;
getAnime = getAnime;
getAnime = getAnime;

async filter(name: (string | null), category?: string, genre?: string, year?: string, letter?: string): Promise<IResultSearch<IAnimeSearch>> {
const animes = new ResultSearch<IAnimeSearch>();
async filter(name: (string | null), category?: string, genre?: string, year?: string): Promise<IResultSearch<AnimeResult>> {
const animes = new ResultSearch<AnimeResult>();
const link = utils.isUsableValue(name) ? `${PageInfo.url}/buscar?q=${name}` :
`${PageInfo.url}/animes?categoria=${category ?? false}&genero=${genre ?? false}&fecha=${year ?? false}&letra=${letter ?? false}`;
`${PageInfo.url}/animes?categoria=${category ?? false}&genero=${genre ?? false}&fecha=${year ?? false}`;
(await getLastAnimes(link))
.forEach(element => {
if (utils.isUsableValue(element)) {
Expand All @@ -205,5 +230,10 @@ export class Monoschinos
}
};


//console.log(await getAnime("https://monoschinos2.com/anime/world-dai-star-sub-espanol"));
/****************************** Test API ******************************/
/*new Monoschinos().filter(null, null, null, '2022').then(data => {
console.log(data)
}).catch(error => console.log(error))*/
/*getAnime("https://monoschinos2.com/anime/one-room-hiatari-futsuu-tenshi-tsuki-sub-espanol").then(data => {
console.log(data)
}).catch(error => console.log(error))*/
24 changes: 11 additions & 13 deletions src/scraper/sites/anime/tioanime/TioAnime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as types from "../../../../types/.";
import {
ResultSearch,
type IResultSearch,
type IAnimeSearch,
type AnimeResult,
} from "../../../../types/search";

const PageInfo = {
Expand Down Expand Up @@ -72,9 +72,9 @@ async function getAnimeEpisodes(data) {
data.episodes.forEach((episode_number) => {
let episode = new types.Episode();
episode.name = `${data.info[2]} Capitulo ${episode_number}`;
episode.image = PageInfo.url + `/uploads/thumbs/${data.info[0]}.jpg`;
episode.thumbnail = new types.Image(PageInfo.url + `/uploads/thumbs/${data.info[0]}.jpg`);
episode.url = `/anime/tioanime/episode/${data.info[1]}-${episode_number}`;
episode.number = episode_number;
episode.num = episode_number;
__episodes.push(episode);
});
return __episodes;
Expand All @@ -83,8 +83,7 @@ async function getAnimeEpisodes(data) {
function getEpisode($, element) {
const title = $(element).find("h3.title").text().trim();
const episode = new types.Episode();
episode.image =
PageInfo.url + $(element).find("figure.fa-play-circle img").attr("src");
episode.thumbnail = new types.Image(PageInfo.url + $(element).find("figure.fa-play-circle img").attr("src"))
episode.url = $(element)
.find("article.episode a")
.attr("href")
Expand All @@ -93,7 +92,7 @@ function getEpisode($, element) {
for (let i = title.length - 1; i >= 0; i--) {
if (title[i] == " ") {
episode.name = title.substring(0, i).trim();
episode.number = parseInt(title.substring(i + 1, title.length));
episode.num = parseInt(title.substring(i + 1, title.length));
break;
}
}
Expand Down Expand Up @@ -144,7 +143,7 @@ async function getAnime(url) {
// It is possible that the object returned by the getScriptAnimeInfo function is null.
if (data == null)
throw new Error("The getScriptAnimeInfo() function returns a null value.");
const anime = new types.Anime();
const anime = new types.AnimeMedia();
anime.name = $("div.container h1.title").text();
//anime.url = url;
anime.url = url.replace(
Expand Down Expand Up @@ -189,10 +188,9 @@ async function getAnime(url) {
return anime;
}

async function getLastAnimes(url: string) {
console.log(url);
async function getLastAnimes(url: string | null) {
try {
let animes: types.IAnime[] = [];
let animes: types.AnimeMedia[] = [];
const $ = cheerio.load((await axios.get(url ?? PageInfo.url)).data);
const elements = $(
utils.isUsableValue(url)
Expand All @@ -213,7 +211,7 @@ async function getLastAnimes(url: string) {
}

async function getSectionContents(section: number) {
let animes: types.IAnime[] = [];
let animes: types.AnimeMedia[] = [];
try {
const $ = cheerio.load(
(await axios.get(`${PageInfo.url}/directorio?type%5B%5D=${section}`)).data
Expand Down Expand Up @@ -284,8 +282,8 @@ export class TioAnime {
year_range?: IYearRange,
status?: number,
sort?: string
): Promise<IResultSearch<IAnimeSearch>> {
const animes = new ResultSearch<IAnimeSearch>();
): Promise<IResultSearch<AnimeResult>> {
const animes = new ResultSearch<AnimeResult>();
let usable;
if (!(usable = utils.isUsableValue(name) && name.trim().length != 0))
year_range ??
Expand Down
Loading

0 comments on commit 9b7efb5

Please sign in to comment.