diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..2e1fa2d --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +*.md \ No newline at end of file diff --git a/README.md b/README.md index cfa52b2..7c0ffb9 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,237 @@ -# Monoschinos API REST +# Monoschinos API REST V2 +## Endpoints + +> PATH: /lastest + +|Querys|Params| +|-|-| +|none|none| + +```js +[ + { + "id": "kimetsu-no-yaiba-yuukaku-hen-episodio-1", + "title": "Kimetsu no Yaiba: Yuukaku-hen", + "image": "https://monoschinos2.com/assets/img/serie/episodio/kimetsu-no-yaiba-yuukaku-hen-1-1638722630.jpg", + "type": "Anime", + "no": 1 + }, + { + "id": "mushoku-tensei-isekai-ittara-honki-dasu-2nd-season-episodio-10", + "title": "Mushoku Tensei: Isekai Ittara Honki Dasu 2nd Season", + "image": "https://monoschinos2.com/assets/img/serie/episodio/mushoku-tensei-isekai-ittara-honki-dasu-2nd-season-10-1638721531.jpg", + "type": "Anime", + "no": 10 + }, + ... +] +``` + + +> PATH: /emision + +|Querys|Params| +|-|-| +|`page`|none| + +```js +[ + { + "id": "jojos-bizarre-adventure-stone-ocean-sub-espanol", + "title": "JoJo's Bizarre Adventure: Stone Ocean", + "image": "https://monoschinos2.com/thumbs/imagen/jojos-bizarre-adventure-stone-ocean-1638350799.jpg?v=1" + }, + { + "id": "kimetsu-no-yaiba-yuukaku-hen-sub-espanol", + "title": "Kimetsu no Yaiba: Yuukaku-hen", + "image": "https://monoschinos2.com/thumbs/imagen/kimetsu-distrito-rojo.jpg?v=1" + }, + ... +] +``` + + +> PATH: /week + +|Querys|Params| +|-|-| +|none|none| + +```js +[ + { + "day": "lunes", + "animes": [ + { + "id": "shinka-no-mi-shiranai-uchi-ni-kachigumi-jinsei-sub-espanol", + "title": "Shinka no Mi: Shiranai Uchi ni Kachigumi Jinsei", + "image": "https://monoschinos2.com/thumbs/imagen/shinka-no-mi-shiranai-uchi-ni-kachigumi-jinsei-1637559521.jpg?v=1" + }, + ... + ] + }, + ... +] +``` + + +> PATH: /all + +|Querys|Params| +|-|-| +|`page`|none| + +```js +[ + { + "id": "mai-otome-zwei-sub-espanol", + "title": "Mai-Otome Zwei", + "image": "https://monoschinos2.com/thumbs/imagen/mai-otome-zwei-1638649807.jpg?v=1" + }, + { + "id": "mai-hime-sub-espanol", + "title": "Mai-HiME", + "image": "https://monoschinos2.com/thumbs/imagen/mai-hime-1638591018.jpg?v=1" + }, + ... +] +``` + + +> PATH: /search/:id + +|Querys|Params| +|-|-| +|none|`id`| + +```js +[ + { + "id": "mai-otome-zwei-sub-espanol", + "title": "Mai-Otome Zwei", + "image": "https://monoschinos2.com/thumbs/imagen/mai-otome-zwei-1638649807.jpg?v=1" + }, + { + "id": "mai-hime-sub-espanol", + "title": "Mai-HiME", + "image": "https://monoschinos2.com/thumbs/imagen/mai-hime-1638591018.jpg?v=1" + }, + ... +] ``` - ## Monoschinos API REST - ## Rewrite in typescript + + + + +> PATH: /filterBy + +|Querys|Params| +|-|-| +|`pagina` , `categoria`, `fecha` ,`genero`, `letra`|none| + +```js +[ + { + "id": "mai-otome-zwei-sub-espanol", + "title": "Mai-Otome Zwei", + "image": "https://monoschinos2.com/thumbs/imagen/mai-otome-zwei-1638649807.jpg?v=1" + }, + { + "id": "mai-hime-sub-espanol", + "title": "Mai-HiME", + "image": "https://monoschinos2.com/thumbs/imagen/mai-hime-1638591018.jpg?v=1" + }, + ... +] ``` -* ### Dependencies - * Axios - * Morgan - * Cheerio - * Cors - * Dotenv -Documentation (soon) +> PATH: /ver/:id + +|Querys|Params| +|-|-| +|none|`id`| + +```js +{ + "title": "Kaifuku Jutsushi no Yarinaoshi. 2 ", + "nextEpisodes": [ + { + "image": "https://monoschinos2.com/assets/img/serie/episodio/kaifuku-jutsushi-no-yarinaoshi-3.png", + "date": "27 Ene 2021", + "title": "Kaifuku Jutsushi no Yarinaoshi", + "no": "Capitulo 3" + } + ], + "ctrs": { + "next": true, + "prev": true + }, + "sugestions": [ + { + "image": "https://monoschinos2.com/thumbs/portada/gundamhathawayvisual-e1621256405818.jpg?v=1.1", + "date": "08 Jul 2021", + "title": "Mobile Suit Gundam: Hathaway's Flash", + "no": "Capitulo 1" + }, + ... + ], + "videos": [ + { + "title": "cloud", + "url": "https://monoschinos2.com/reproductor?url=https://repro.monoschinos2.com/aqua/cl?url=redo02.mp4" + }, + ... + ], + "downloads": [ + { + "title": "1fichier ", + "url": "https://1fichier.com/?yssqgolputegizq4xkhb" + }, + ... + ] +} +``` + + + +> PATH: /anime/:id + +|Querys|Params| +|-|-| +|none|`id`| + +```js +{ + "banner": "https://monoschinos2.com/assets/img/serie/portada/portada_kimetsu-37.jpg", + "image": "https://monoschinos2.com/thumbs/imagen/crunchyroll-Demon-Slayer-Kimetsu-no-Yaiba-Mugen-Train-Arc.jpg?v=1", + "title": "Kimetsu no Yaiba: Mugen Ressha-hen (TV)", + "sinopsis": "Versión para televisión de la película Mugen Train que conecta el arco de Tanjiro Kamado, Resolve inquebrantable con el arco del distrito de entretenimiento , que presenta un episodio original de televisión nunca antes visto de Kyojuro Rengoku asumiendo una nueva misión en el camino hacia el tren Mugen.\nAdemás del episodio completamente nuevo, la serie también incluirá 70 escenas nuevas, nuevas pistas musicales, avances de episodios y nuevos temas musicales.\n", + "status": "Finalizado", + "date": 2021, + "rating": "4.8", + "genders": [ + "Acción", + "Aventura", + "Gore", + "Shonen", + "Histórico" + ], + "episodes": [ + { + "image": "https://monoschinos2.com/thumbs/portada/portada_kimetsu-37.jpg?v=1.1", + "no": 1, + "id": "kimetsu-no-yaiba-mugen-ressha-hen-tv-episodio-1" + }, + ... + ] +} +``` + + + +### Author: Carlos Burelo + -#### Based on original work by [atleugim](https://github.com/atleugim/monoschinos-api) \ No newline at end of file diff --git a/package.json b/package.json index e880d5e..b595b22 100644 --- a/package.json +++ b/package.json @@ -12,14 +12,14 @@ "author": "", "license": "ISC", "devDependencies": { - "nodemon": "^2.0.14" + "nodemon": "^2.0.14", + "morgan": "^1.10.0" }, "dependencies": { "axios": "^0.24.0", "cors": "^2.8.5", "dotenv": "^8.2.0", "express": "^4.17.1", - "morgan": "^1.10.0", "node-html-parser": "^5.1.0" } } diff --git a/src/app.js b/src/app.js index 034dee6..a251c26 100644 --- a/src/app.js +++ b/src/app.js @@ -1,7 +1,7 @@ import express from 'express'; import cors from 'cors'; import morgan from 'morgan'; -import routes from './routes/api.routes.js'; +import routes from './router.js'; const app = express(); app.use(cors(), morgan('dev')); app.use('/', routes); diff --git a/src/config.js b/src/config.js index 16ce151..11002b2 100644 --- a/src/config.js +++ b/src/config.js @@ -1,19 +1,17 @@ -const page = 'https://monoschinos2.com'; +const url = 'https://monoschinos2.com'; -export const urls = { - main: page, - emision: page + '/emision?page=', - search: page + '/search?q=', - anime: page + '/anime', - episode: page + '/ver', - gender: page + '/genero', - letter: page + '/letra', - ova: page + '/categoria/ova', +export const api = { + home: `${url}`, + all: (id) => `${url}/animes?p=${id}`, + emision: (id) => `${url}/emision?p=${id}`, + calendar: `${url}/calendario`, + search: (id, page) => `${url}/buscar?q=${id.replace(/\s/g, '+')}&p=${page}`, + anime: (id) => `${url}/anime/${id}`, + episode: (id) => `${url}/ver/${id}`, + gender: (id) => `${url}/genero/${id}`, + filter: ({ categoria, fecha, genero, letra, pagina }) => + `${url}/animes?categoria=${categoria}&genero=${genero}&fecha=${fecha}&letra=${letra}&p=${pagina}`, }; - -/** - * @returns {string} - */ -export function getAttr(html, selector, attr) { - return html.querySelector(selector).attributes[attr]; +export function attr(html, selector, attribute = 'src') { + return html.querySelector(selector)?.attributes[attribute]; } diff --git a/src/controllers/getAnimes.js b/src/controllers/all.js similarity index 67% rename from src/controllers/getAnimes.js rename to src/controllers/all.js index 0b3ab31..259eff6 100644 --- a/src/controllers/getAnimes.js +++ b/src/controllers/all.js @@ -1,18 +1,19 @@ import { parse } from 'node-html-parser'; import axios from 'axios'; -import { getAttr, urls } from '../config.js'; +import { attr, api } from '../config.js'; + export async function getAnimes(req, res) { try { let { page = '1' } = req.params; - const { data } = await axios.get(`${urls.main}/animes?page=${page}`); + const { data } = await axios.get(`${api.all(page)}`); const html = parse(data); res.status(200).json( html.querySelectorAll('.heromain .row .col-md-4.col-lg-2.col-6').map((i) => { return { - id: getAttr(i, 'a', 'href').split('/').pop() || null, + id: attr(i, 'a', 'href').split('/').pop() || null, title: i.querySelector('.seristitles').text.trim() || null, - image: getAttr(i, '.animemainimg', 'src') || null, + image: attr(i, '.animemainimg', 'src') || null, }; }) ); @@ -22,3 +23,4 @@ export async function getAnimes(req, res) { }); } } + diff --git a/src/controllers/getAnime.js b/src/controllers/anime.js similarity index 84% rename from src/controllers/getAnime.js rename to src/controllers/anime.js index 7db445e..ce0e49c 100644 --- a/src/controllers/getAnime.js +++ b/src/controllers/anime.js @@ -1,5 +1,5 @@ import axios from 'axios'; -import { getAttr, urls } from '../config.js'; +import { attr, api } from '../config.js'; import { parse } from 'node-html-parser'; export async function getAnime(req, res) { @@ -8,15 +8,15 @@ export async function getAnime(req, res) { const noImage = 'https://monoschinos2.com/assets/img/no_image.png'; const defaulImage = 'https://image.freepik.com/free-vector/404-error-page-found_41910-364.jpg'; const { id } = req.params; - const { data } = await axios.get(`${urls.anime}/${id}`); + const { data } = await axios.get(api.anime(id)); const html = parse(data); const urlMatch = /url\((.+)\)/gim; - const image = getAttr(html, '.heroarea', 'style') + const image = attr(html, '.heroarea', 'style') .match(urlMatch)[0] .replace(/url\(|\)/g, ''); res.status(200).json({ banner: image == noImage ? defaulImage : image || null, - image: getAttr(html, '.chapterpic img', 'src') || null, + image: attr(html, '.chapterpic img', 'src') || null, title: html .querySelector('.chapterdetails h1') @@ -31,7 +31,7 @@ export async function getAnime(req, res) { html.querySelectorAll('.row.jpage.row-cols-md-6 .col-item a').map((cap) => { const epId = cap.attributes['href'].replace(`${url}ver/`, ''); return { - image: getAttr(cap, '.animeimghv', 'src'), + image: attr(cap, '.animeimghv', 'src'), no: parseInt(epId.split('-').pop()), id: epId, }; diff --git a/src/controllers/calendar.js b/src/controllers/calendar.js new file mode 100644 index 0000000..4da9f54 --- /dev/null +++ b/src/controllers/calendar.js @@ -0,0 +1,30 @@ + +import { parse } from 'node-html-parser'; +import { attr, api } from '../config.js'; +import axios from 'axios'; + +export async function getCalendar(req, res) { + try { + const { data } = await axios.get(api.calendar); + const html = parse(data); + res.status(200).json( + html.querySelectorAll('.heromain [data-dia]').map((i) => { + const day = i.getAttribute('data-dia'); + return { + day, + animes: i + .querySelectorAll('.col-md-6.col-lg-4.col-sm-12.for768') + .map((i) => { + return { + id: attr(i, 'a', 'href').split('/').pop() || null, + title: i.querySelector('.serisdtls a h3').text.trim() || null, + image: attr(i, '.seriesimg a img') || null, + }; + }), + }; + }) + ) + } catch (error) { + res.status(500).json({ message: error.message }); + } +} diff --git a/src/controllers/getEmision.js b/src/controllers/emision.js similarity index 56% rename from src/controllers/getEmision.js rename to src/controllers/emision.js index 04f4c80..d8d2735 100644 --- a/src/controllers/getEmision.js +++ b/src/controllers/emision.js @@ -1,24 +1,22 @@ import axios from 'axios'; +import { attr, api } from '../config.js'; import { parse } from 'node-html-parser'; -import { getAttr, urls } from '../config.js'; export async function getEmision(req, res) { try { let { page = '1' } = req.query; - const { data } = await axios.get(`${urls.emision}${page}`); + const { data } = await axios.get(api.emision(page)); const html = parse(data); res.status(200).json( html.querySelectorAll('.heromain .row .col-md-4.col-lg-2.col-6').map((i) => { return { - id: getAttr(i, 'a', 'href').split('/').pop() || null, + id: attr(i, 'a', 'href').split('/').pop() || null, title: i.querySelector('.seristitles').text.trim() || null, - image: getAttr(i, '.animemainimg', 'src') || null, + image: attr(i, '.animemainimg') || null, }; }) - ); - } catch (err) { - res.status(500).json({ - message: err.message, - }); + ) + } catch (error) { + res.status(500).json({ message: error.message }); } } diff --git a/src/controllers/getEpisode.js b/src/controllers/episode.js similarity index 88% rename from src/controllers/getEpisode.js rename to src/controllers/episode.js index 8f7f7b3..25223e9 100644 --- a/src/controllers/getEpisode.js +++ b/src/controllers/episode.js @@ -1,11 +1,11 @@ import axios from 'axios'; -import { getAttr, urls } from '../config.js'; +import { attr, api } from '../config.js'; import { parse } from 'node-html-parser'; export async function getEpisode(req, res) { try { const { id } = req.params; - const { data } = await axios.get(`${urls.episode}/${id}`); + const { data } = await axios.get(api.episode(id)); const html = parse(data); const ctrls = html.querySelectorAll('.controldiv2 a'); let nav = {}; @@ -21,7 +21,7 @@ export async function getEpisode(req, res) { } const nextEpisodes = html.querySelectorAll('.nextplay:nth-child(1) .nextplays a').map((i) => { return { - image: getAttr(i, '.nxtmainimg', 'src'), + image: attr(i, '.nxtmainimg', 'src'), date: i.querySelector('.nxtplaybtn p').text, title: i.querySelector('.nxtplaybtn h5').text, no: i.querySelector('.nxtplaybtn span').text, @@ -34,7 +34,7 @@ export async function getEpisode(req, res) { nextEpisodes: nextEpisodes.length == 0 ? null : nextEpisodes, ctrs: nav, sugestions: html.querySelectorAll('.nextplay:nth-child(2) .nextplays a').map((i) => { - const image = getAttr(i, '.nxtmainimg', 'src'); + const image = attr(i, '.nxtmainimg', 'src'); return { image: image.length == 0 || !image ? imgNotFound : image, date: i.querySelector('.nxtplaybtn p').text, @@ -43,7 +43,7 @@ export async function getEpisode(req, res) { }; }), videos: html.querySelectorAll('.dropdown-menu.dropcap #play-video').map((i) => { - const base64 = getAttr(i, 'a', 'data-player'); + const base64 = attr(i, 'a', 'data-player'); return { title: i.querySelector('a').text, url: Buffer.from(base64, 'base64').toString('ascii'), diff --git a/src/controllers/filterBy.js b/src/controllers/filterBy.js new file mode 100644 index 0000000..417272a --- /dev/null +++ b/src/controllers/filterBy.js @@ -0,0 +1,30 @@ +import axios from 'axios'; +import { parse } from 'node-html-parser'; +import { api, attr } from '../config.js'; + +export async function filterBy(req, res) { + try { + let { + categoria = 'false', + fecha = 'false', + genero = 'false', + letra = 'false', + pagina = '1', + } = req.query; + const { data } = await axios.get(`${api.filter({ categoria, fecha, genero, letra, pagina })}`); + const html = parse(data); + res.status(200).json( + html.querySelectorAll('.heromain .row .col-md-4.col-lg-2.col-6').map((i) => { + return { + id: attr(i, 'a', 'href').split('/').pop() || null, + title: i.querySelector('.seristitles').text.trim() || null, + image: attr(i, '.animemainimg', 'src') || null, + }; + }) + ); + } catch (err) { + res.status(500).json({ + message: err.message, + }); + } +} diff --git a/src/controllers/getBy.js b/src/controllers/getBy.js deleted file mode 100644 index 02b6ef5..0000000 --- a/src/controllers/getBy.js +++ /dev/null @@ -1,35 +0,0 @@ -import axios from 'axios'; -import { parse } from 'node-html-parser'; -import { urls, getAttr } from '../config.js'; - -export async function getBy(req, res) { - try { - const { gender, category, letter, year, page = '1', sort, order } = req.query; - let response; - if (gender) response = await axios.get(`${urls.main}/genero/${gender}?page=${page}`); - if (category) response = await axios.get(`${urls.main}/categoria/${category}?page=${page}`); - if (letter) response = await axios.get(`${urls.main}/letra/${letter}?page=${page}`); - if (year) response = await axios.get(`${urls.main}/year/${year}?page=${page}`); - const { data } = response; - const html = parse(data); - const animes = html.querySelectorAll('.animes .container .row article').map((i) => { - const id = getAttr(i, 'a', 'href'); - return { - id: id.split('/').pop() || null, - title: i.querySelector('.Title').text.trim() || null, - image: getAttr(i, '.Image img', 'src') || null, - type: i.querySelector('.category.text-uppercase').text.trim() || null, - year: parseInt(i.querySelector('.fecha').text) || null, - }; - }); - const isAsc = order == 'asc'; - const ordered = animes.sort((a, b) => { - return (a[sort] < b[sort] ? -1 : 1) * (isAsc ? 1 : -1); - }); - res.status(200).json(sort ? ordered : animes); - } catch (err) { - res.status(500).json({ - message: err.message, - }); - } -} diff --git a/src/controllers/getCategories.js b/src/controllers/getCategories.js deleted file mode 100644 index b5186f6..0000000 --- a/src/controllers/getCategories.js +++ /dev/null @@ -1,25 +0,0 @@ -import axios from 'axios'; -import { parse } from 'node-html-parser'; -import { urls } from '../config.js'; - -export async function getCategories(req, res) { - try { - const { data } = await axios.get(`${urls.main}/animes`); - const html = parse(data); - res.status(200).json( - html - .querySelectorAll('div[aria-labelledby="categoryMenuButton"] a') - .map((i) => { - return { - name: i.text.trim(), - id: i?.attributes['href'].replace('/categoria/', ''), - }; - }) - .filter((i) => i.id !== '') - ); - } catch (err) { - res.status(500).json({ - message: err.message, - }); - } -} diff --git a/src/controllers/getGenders.js b/src/controllers/getGenders.js deleted file mode 100644 index 1a7c5a6..0000000 --- a/src/controllers/getGenders.js +++ /dev/null @@ -1,26 +0,0 @@ -import axios from 'axios'; -import { parse } from 'node-html-parser'; -import { urls } from '../config.js'; - -export async function getGenders(req, res) { - try { - const { data } = await axios.get(`${urls.main}/animes`); - const html = parse(data); - res.status(200).json( - html - .querySelectorAll('div[aria-labelledby="genreMenuButton"] a') - .map((i) => { - return { - name: i.text.trim(), - id: i?.attributes['href'].replace('/genero/', ''), - }; - }) - .filter((i) => i.id !== '') - ); - } catch (err) { - res.status(500).json({ - message: err, - success: false, - }); - } -} diff --git a/src/controllers/getLastest.js b/src/controllers/getLastest.js deleted file mode 100644 index 1c23ba8..0000000 --- a/src/controllers/getLastest.js +++ /dev/null @@ -1,24 +0,0 @@ -import axios from 'axios'; -import { getAttr, urls } from '../config.js'; -import { parse } from 'node-html-parser'; - -export async function getLastest(req, res) { - try { - const { data } = await axios.get(urls.main); - const html = parse(data); - res.json( - html.querySelectorAll('.row.row-cols-5 .col.col-md-6.col-lg-2.col-6').map((i) => { - const id = getAttr(i, 'a', 'href').split('/').pop(); - return { - id: id || null, - title: i.querySelector('.animetitles').text || null, - image: getAttr(i, '.animeimghv', 'src') || null, - type: i.querySelector('.positioning button').text.trim() || null, - episode: parseInt(i.querySelector('.positioning h5').text.trim()) || null, - }; - }) - ); - } catch (error) { - return res.json({ error: error.message }).status(500); - } -} diff --git a/src/controllers/getYears.js b/src/controllers/getYears.js deleted file mode 100644 index 383ac4b..0000000 --- a/src/controllers/getYears.js +++ /dev/null @@ -1,26 +0,0 @@ -import axios from 'axios'; -import { parse } from 'node-html-parser'; -import { urls } from '../config.js'; - -export async function getYears(req, res) { - try { - const { data } = await axios.get(`${urls.main}/animes`); - const html = parse(data); - res.status(200).json( - html - .querySelectorAll('div[aria-labelledby="yearMenuButton"] a') - .map((i) => { - return { - name: i.text.trim(), - id: i?.attributes['href'].replace('/year/', ''), - }; - }) - .filter((i) => i.id !== '') - ); - } catch (err) { - res.status(500).json({ - message: err, - success: false, - }); - } -} diff --git a/src/controllers/index.js b/src/controllers/index.js index 99f0ed0..d6f74a3 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -1,10 +1,8 @@ -export * from './getLastest.js'; -export * from './getEmision.js'; -export * from './getAnime.js'; -export * from './searchAnimes.js'; -export * from './getAnimes.js'; -export * from './getEpisode.js'; -export * from './getCategories.js'; -export * from './getGenders.js'; -export * from './getYears.js'; -export * from './getBy.js'; +export * from './all.js'; +export * from './calendar.js'; +export * from './emision.js'; +export * from './episode.js'; +export * from './filterBy.js'; +export * from './lastest.js'; +export * from './search.js'; +export * from './anime.js'; diff --git a/src/controllers/lastest.js b/src/controllers/lastest.js new file mode 100644 index 0000000..a0e908b --- /dev/null +++ b/src/controllers/lastest.js @@ -0,0 +1,26 @@ +import axios from 'axios'; +import { attr, api } from '../config.js'; +import { parse } from 'node-html-parser'; + +export async function getLastest(req, res) { + try { + const { data } = await axios.get(api.home); + const html = parse(data); + res.json( + html + .querySelectorAll('.row.row-cols-5 .col.col-md-6.col-lg-2.col-6') + .map((i) => { + const id = attr(i, 'a', 'href').split('/').pop(); + return { + id: id || null, + title: i.querySelector('.animetitles')?.text || null, + image: attr(i, '.animeimghv') || null, + type: i.querySelector('.positioning button').text.trim() || null, + no: parseInt(i.querySelector('.positioning h5').text.trim() || '0') || null, + }; + }) + ); + } catch (error) { + res.status(500).json({ message: error.message }); + } +} diff --git a/src/controllers/search.js b/src/controllers/search.js new file mode 100644 index 0000000..3c31342 --- /dev/null +++ b/src/controllers/search.js @@ -0,0 +1,25 @@ +import axios from 'axios'; +import { parse } from 'node-html-parser'; +import { api, attr } from '../config.js'; + +export async function searchAnime(req, res) { + try { + let { id } = req.params; + let { page = '1' } = req.query; + const { data } = await axios.get(api.search(id, page)); + const html = parse(data); + res.json( + html.querySelectorAll('.heromain .row .col-md-4.col-lg-2.col-6').map((i) => { + return { + id: attr(i, 'a', 'href').split('/').pop() || null, + title: i.querySelector('.seristitles ').text || null, + image: attr(i, '.seriesimg .animemainimg', 'src') || null, + }; + }) + ); + } catch (error) { + res.status(500).json({ + message: error.message, + }); + } +} diff --git a/src/controllers/searchAnimes.js b/src/controllers/searchAnimes.js deleted file mode 100644 index 1fad91c..0000000 --- a/src/controllers/searchAnimes.js +++ /dev/null @@ -1,27 +0,0 @@ -import { parse } from 'node-html-parser'; -import axios from 'axios'; -import { getAttr, urls } from '../config.js'; - -export async function searchAnime(req, res) { - try { - let { id } = req.params; - const { data } = await axios.get(`${urls.search}${id}`); - const html = parse(data); - res.json( - html.querySelectorAll('.animes .row article').map((i) => { - return { - id: getAttr(i, 'a', 'href').split('/').pop() || null, - title: i.querySelector('h3.Title').text || null, - image: getAttr(i, '.cover .img-fluid', 'src') || null, - type: i.querySelector('.category.text-uppercase').text.trim() || null, - year: parseInt(i.querySelector('.fecha').text) || null, - }; - }) - ); - } catch (error) { - res.status(500).json({ - id: 'intertal-server-error', - message: error.message, - }); - } -} diff --git a/src/router.js b/src/router.js new file mode 100644 index 0000000..ac18fed --- /dev/null +++ b/src/router.js @@ -0,0 +1,61 @@ +import { Router } from 'express'; +const routes = Router(); + +import { + getEmision, + getLastest, + getCalendar, + getAnimes, + filterBy, + searchAnime, + getEpisode, + getAnime, +} from './controllers/index.js'; + +routes.get('/', (_, res) => { + res.json({ + message: 'API Works', + author: 'Carlos Burelo', + repository: 'https://github.com/carlos-burelo/monoschinos-api-v2', + endpoints: { + lastest: '/lastest', + emision: '/emision', + calendar: '/week', + getAnimeByID: '/anime/:id', + getAnimesByPage: '/all', + getEpisodeByID: '/ver/:id', + searchAnimeByID: '/search/:id', + filterBy: { + path: '/filterBy', + querys: ['categoria', 'fecha', 'genero', 'letra', 'pagina'], + }, + }, + }); +}); + +routes.get('/lastest', (req, res) => { + getLastest(req, res); +}); +routes.get('/emision', (req, res) => { + getEmision(req, res); +}); +routes.get('/week', (req, res) => { + getCalendar(req, res); +}); +routes.get('/all', (req, res) => { + getAnimes(req, res); +}); +routes.get('/filterBy', (req, res) => { + filterBy(req, res); +}); +routes.get('/search/:id', (req, res) => { + searchAnime(req, res); +}); +routes.get('/ver/:id', (req, res) => { + getEpisode(req, res); +}); +routes.get('/anime/:id', (req, res) => { + getAnime(req, res); +}); + +export default routes; diff --git a/src/routes/api.routes.js b/src/routes/api.routes.js deleted file mode 100644 index d90fee2..0000000 --- a/src/routes/api.routes.js +++ /dev/null @@ -1,80 +0,0 @@ -import { Router } from 'express'; -const routes = Router(); - -import { - getEmision, - getGenders, - getLastest, - getAnime, - searchAnime, - getAnimes, - getEpisode, - getCategories, - getYears, - getBy, -} from '../controllers/index.js'; - -routes.get('/', (_, res) => { - res.json({ - message: 'API Works', - author: 'Carlos Burelo', - repository: 'https://github.com/carlos-burelo/monoschinos-api-ts', - endpoints: { - lastest: '/lastest', - emision: '/emision', - getAnimeByID: '/anime/:id', - getAnimesByPage: '/animes/:page', - getEpisodeByID: '/ver/:id', - searchAnimeByID: '/search/:id', - getYears: '/years', - getGenders: '/genders', - getLetters: '/letter', - getCategories: '/categories', - getByParams: { - example: '/by?gender=drama&sort=title&order=asc', - filters: ['gender', 'year', 'category', 'letter'], - querys: { - sort: '&sort={prop}', - order: '&order=asc', - page: '&page={number}', - limit: '&limit=3...(soon)', - }, - }, - }, - }); -}); - -routes.get('/lastest', (req, res) => { - getLastest(req, res); -}); -routes.get('/emision', (req, res) => { - getEmision(req, res); -}); -routes.get('/anime/:id', (req, res) => { - getAnime(req, res); -}); -routes.get('/animes/:page', (req, res) => { - getAnimes(req, res); -}); -routes.get('/ver/:id', (req, res) => { - getEpisode(req, res); -}); -routes.get('/search/:id', (req, res) => { - searchAnime(req, res); -}); -routes.get('/genders', (req, res) => { - getGenders(req, res); -}); -routes.get('/categories', (req, res) => { - getCategories(req, res); -}); -routes.get('/years', (req, res) => { - getYears(req, res); -}); -routes.get('/letters', (req, res) => { - getLetters(req, res); -}); -routes.get('/by', (req, res) => { - getBy(req, res); -}); -export default routes; diff --git a/yarn.lock b/yarn.lock index ea70a2c..5ad1a7e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -164,30 +164,6 @@ chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -cheerio-select@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-1.5.0.tgz#faf3daeb31b17c5e1a9dabcee288aaf8aafa5823" - integrity sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg== - dependencies: - css-select "^4.1.3" - css-what "^5.0.1" - domelementtype "^2.2.0" - domhandler "^4.2.0" - domutils "^2.7.0" - -cheerio@^1.0.0-rc.5: - version "1.0.0-rc.10" - resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.10.tgz#2ba3dcdfcc26e7956fc1f440e61d51c643379f3e" - integrity sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw== - dependencies: - cheerio-select "^1.5.0" - dom-serializer "^1.3.2" - domhandler "^4.2.0" - htmlparser2 "^6.1.0" - parse5 "^6.0.1" - parse5-htmlparser2-tree-adapter "^6.0.1" - tslib "^2.2.0" - chokidar@^3.2.2: version "3.5.2" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" @@ -295,7 +271,7 @@ css-select@^4.1.3: domutils "^2.6.0" nth-check "^2.0.0" -css-what@^5.0.0, css-what@^5.0.1: +css-what@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad" integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg== @@ -346,7 +322,7 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= -dom-serializer@^1.0.1, dom-serializer@^1.3.2: +dom-serializer@^1.0.1: version "1.3.2" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== @@ -360,14 +336,14 @@ domelementtype@^2.0.1, domelementtype@^2.2.0: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== -domhandler@^4.0.0, domhandler@^4.2.0: +domhandler@^4.2.0: version "4.2.2" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.2.tgz#e825d721d19a86b8c201a35264e226c678ee755f" integrity sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w== dependencies: domelementtype "^2.2.0" -domutils@^2.5.2, domutils@^2.6.0, domutils@^2.7.0: +domutils@^2.6.0: version "2.8.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== @@ -581,16 +557,6 @@ he@1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -htmlparser2@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" - integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.0.0" - domutils "^2.5.2" - entities "^2.0.0" - http-cache-semantics@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" @@ -944,18 +910,6 @@ package-json@^6.3.0: registry-url "^5.0.0" semver "^6.2.0" -parse5-htmlparser2-tree-adapter@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" - integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== - dependencies: - parse5 "^6.0.1" - -parse5@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -1199,11 +1153,6 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -tslib@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - type-fest@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"