Merge branch 'develop'

pull/27/head v3.4.0
Jéluchu 5 years ago
commit 1746c96037

@ -1,4 +1,4 @@
# **Aruppi API** (v3.3.7)
# **Aruppi API** (v3.4.0)
> This API has everything about Japan, from anime, music, radio, images, videos ... to japanese culture
>

33
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "aruppi",
"version": "3.3.7",
"version": "3.4.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -437,6 +437,17 @@
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"fuzzball": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/fuzzball/-/fuzzball-1.3.1.tgz",
"integrity": "sha512-6SVlrHhVxFdzvsW/a0fgzc/xunWJ5JVkHFV6dqfWcplWEt+E/VQgo4FQQxqrF+zy6XDBvSH70kjMKZkDrpltWQ==",
"requires": {
"heap": ">=0.2.0",
"setimmediate": "^1.0.5",
"string.fromcodepoint": "^0.2.1",
"string.prototype.codepointat": "^0.2.0"
}
},
"get-stream": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
@ -463,6 +474,11 @@
"responselike": "^2.0.0"
}
},
"heap": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/heap/-/heap-0.2.6.tgz",
"integrity": "sha1-CH4fELBGky/IWU3Z5tN4r8nR5aw="
},
"helmet": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-4.3.1.tgz",
@ -814,6 +830,11 @@
"send": "0.17.1"
}
},
"setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
},
"setprototypeof": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
@ -824,6 +845,16 @@
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
"string.fromcodepoint": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/string.fromcodepoint/-/string.fromcodepoint-0.2.1.tgz",
"integrity": "sha1-jZeDM8C8klOPUPOD5IiPPlYZ1lM="
},
"string.prototype.codepointat": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz",
"integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg=="
},
"toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",

@ -1,6 +1,6 @@
{
"name": "aruppi",
"version": "3.3.7",
"version": "3.4.0",
"description": "Aruppi is a custom API to obtain data from the Japanese culture for the mobile app",
"main": "./src/api/api.js",
"scripts": {
@ -47,6 +47,7 @@
"compose-middleware": "^5.0.1",
"cors": "^2.8.5",
"express": "^4.17.1",
"fuzzball": "^1.3.1",
"got": "^11.8.1",
"helmet": "^4.3.1",
"rss-to-json": "^1.1.2",

@ -1,9 +1,8 @@
const rss = require('rss-to-json');
const fuzzball = require('fuzzball');
const {
homgot
} = require('../api/apiCall');
const {
jkanimeInfo,
animeflvInfo,
@ -16,18 +15,22 @@ const {
structureThemes,
videoServersJK,
getThemes,
getMALid
getRelatedAnimesFLV,
getRelatedAnimesMAL,
directoryAnimes,
radioStations,
animeGenres,
animeThemes
} = require('../utils/index');
const ThemeParser = require('../utils/animetheme');
const parserThemes = new ThemeParser()
const parserThemes = new ThemeParser();
const {
BASE_ANIMEFLV_JELU, BASE_JIKAN, BASE_IVOOX, BASE_QWANT, BASE_YOUTUBE, BASE_THEMEMOE, BASE_ANIMEFLV, BASE_ARUPPI
} = require('./urls');
const schedule = async (day) =>{
const data = await homgot(`${BASE_JIKAN}schedule/${day.current}`, { parse: true });
return data[day.current].map(doc =>({
@ -35,12 +38,10 @@ const schedule = async (day) =>{
malid: doc.mal_id,
image: doc.image_url
}));
};
const top = async (top) =>{
let data
let data;
if (top.subtype !== undefined) {
data = await homgot(`${BASE_JIKAN}top/${top.type}/${top.page}/${top.subtype}`, { parse: true });
@ -58,11 +59,9 @@ const top = async (top) =>{
page: top.page,
score: doc.score
}));
};
const getAllAnimes = async () =>{
let data = await homgot(`${BASE_ANIMEFLV}api/animes/list`, { parse: true })
return data.map(item => ({
@ -72,16 +71,15 @@ const getAllAnimes = async () =>{
id: item[2],
type: item[4]
}));
};
const getAllDirectory = async (genres) => {
let data;
let data
if (genres === "sfw") {
data = JSON.parse(JSON.stringify(require('../assets/directory.json'))).filter(function (item) {
if (genres === 'sfw') {
data = directoryAnimes.filter(function (item) {
return !item.genres.includes("Ecchi") && !item.genres.includes("ecchi");
})
});
} else {
data = JSON.parse(JSON.stringify(require('../assets/directory.json')));
}
@ -98,12 +96,11 @@ const getAllDirectory = async (genres) =>{
jkanime: false,
description: doc.description
}));
};
const getAnitakume = async () => {
const promises = []
const promises = [];
await rss.load(BASE_IVOOX).then(rss => {
@ -139,11 +136,9 @@ const getAnitakume = async () =>{
};
const getNews = async (pageRss) =>{
let promises = []
let promises = [];
for(let i = 0; i <= pageRss.length -1; i++) {
await rss.load(pageRss[i].url).then(rss => {
const body = JSON.parse(JSON.stringify(rss, null, 3)).items
@ -156,19 +151,14 @@ const getNews = async (pageRss) =>{
thumbnail: obtainPreviewNews(doc[pageRss[i].content]),
content: doc[pageRss[i].content]
});
});
});
}
return promises;
};
const season = async (season) =>{
const data = await homgot(`${BASE_JIKAN}season/${season.year}/${season.type}`, { parse: true });
return data.anime.map(doc =>({
@ -176,22 +166,18 @@ const season = async (season) =>{
image: doc.image_url,
genres: doc.genres.map(x => x.name)
}));
};
const allSeasons = async () =>{
const data = await homgot(`${BASE_JIKAN}season/archive`, { parse: true });
return data.archive.map(doc =>({
year: doc.year,
seasons: doc.seasons,
}));
};
const laterSeasons = async () =>{
const data = await homgot(`${BASE_JIKAN}season/later`, { parse: true });
return data.anime.map(doc =>({
@ -199,12 +185,11 @@ const laterSeasons = async () =>{
image: doc.image_url,
malink: doc.url
}));
};
const getLastEpisodes = async () =>{
const data = await homgot(`${BASE_ANIMEFLV_JELU}LatestEpisodesAdded`, { parse: true });
return await Promise.all(data.episodes.map(async (item) => ({
id: item.id,
title: item.title,
@ -212,17 +197,16 @@ const getLastEpisodes = async () =>{
episode: item.episode,
servers: await transformUrlServer(JSON.parse(JSON.stringify(item.servers)))
})));
};
const getSpecials = async (data) =>{
const res = await homgot(`${BASE_ANIMEFLV_JELU}${data.url}/${data.type}/${data.page}`, { parse: true });
return res[data.prop].map(doc =>({
id: doc.id,
title: doc.title,
type: doc.type,
type: data.url.toLowerCase(),
page: data.page,
banner: doc.banner,
image: doc.poster,
synopsis: doc.synopsis,
@ -235,12 +219,25 @@ const getSpecials = async (data) =>{
};
const getMoreInfo = async (title) =>{
try {
let data = directoryAnimes;
let result = data.filter(anime => fuzzball.ratio(anime.title, title) > 90)[0];
let data = JSON.parse(JSON.stringify(require('../assets/directory.json')));
let result = data.filter(anime => anime.title === title)[0];
if (!result.jkanime) {
return {
title: result.title || null,
poster: result.poster || null,
synopsis: result.description || null,
status: result.state || null,
type: result.type || null,
rating: result.score || null,
genres: result.genres || null,
moreInfo: await animeExtraInfo(result.mal_id).then(info => info || null),
promo: await getAnimeVideoPromo(result.mal_id).then(promo => promo || null),
characters: await getAnimeCharacters(result.mal_id).then(characters => characters || null),
related: await getRelatedAnimesFLV(result.id)
};
}else {
return {
title: result.title || null,
poster: result.poster || null,
@ -249,51 +246,47 @@ const getMoreInfo = async (title) =>{
type: result.type || null,
rating: result.score || null,
genres: result.genres || null,
moreInfo: await animeExtraInfo(result.mal_title).then(info => info || null),
promo: await getAnimeVideoPromo(result.mal_title).then(promo => promo || null),
characters: await getAnimeCharacters(result.mal_title).then(characters => characters || null)
moreInfo: await animeExtraInfo(result.mal_id).then(info => info || null),
promo: await getAnimeVideoPromo(result.mal_id).then(promo => promo || null),
characters: await getAnimeCharacters(result.mal_id).then(characters => characters || null),
related: await getRelatedAnimesMAL(result.mal_id)
};
}
} catch (e) {
console.log(e)
console.log(e);
}
};
const getEpisodes = async (title) =>{
try {
let data = directoryAnimes;
const result = data.filter(x => x.title === title)[0];
let data = JSON.parse(JSON.stringify(require('../assets/directory.json')));
const res = data.filter(x => x.title === title || x.mal_title === title)[0];
if (!res.jkanime) {
return await animeflvInfo(res.id).then(episodes => episodes || null)
if (!result.jkanime) {
return await animeflvInfo(result.id).then(episodes => episodes || null);
} else {
return await jkanimeInfo(res.id).then(episodes => episodes || null)
return await jkanimeInfo(result.id).then(episodes => episodes || null);
}
} catch (e) {
console.log(e)
console.log(e);
}
};
const getAnimeServers = async (id) => {
if (isNaN(id.split('/')[0])) {
return await videoServersJK(id)
return await videoServersJK(id);
} else {
const data = await homgot(`${BASE_ANIMEFLV_JELU}GetAnimeServers/${id}`, { parse: true });
return await transformUrlServer(data.servers);
}
};
const search = async (title) =>{ return await searchAnime(title); };
const getImages = async (query) => {
try {
const data = await homgot(`${BASE_QWANT}count=${query.count}&q=${query.title}&t=${query.type}&safesearch=${query.safesearch}&locale=${query.country}&uiv=4`, { parse: true });
return data.data.result.items.map(doc =>({
@ -304,11 +297,9 @@ const getImages = async (query) => {
} catch (e) {
console.log(e)
}
};
const getYoutubeVideos = async (channelId) => {
const data = await homgot(`${BASE_YOUTUBE}${channelId.id}&part=${channelId.part}&order=${channelId.order}&maxResults=${channelId.maxResults}`, { parse: true });
return data[channelId.prop].map(doc =>({
@ -318,7 +309,6 @@ const getYoutubeVideos = async (channelId) => {
thumbMedium: doc.snippet.thumbnails.medium.url,
thumbHigh: doc.snippet.thumbnails.high.url
}));
};
const getSectionYoutubeVideos = async (type) => {
@ -357,24 +347,22 @@ const getSectionYoutubeVideos = async (type) => {
};
const getRadioStations = async () => require('../assets/radiostations.json');
const getRadioStations = async () => radioStations;
const getOpAndEd = async (title) => await structureThemes(await parserThemes.serie(title), true);
const getThemesYear = async (year) => {
let data = [];
let data = []
if (year === undefined) {
return await parserThemes.allYears();
} else {
data = await parserThemes.year(year)
return await structureThemes(data, false)
data = await parserThemes.year(year);
return await structureThemes(data, false);
}
};
const getRandomTheme = async () => {
let data = await homgot(`${BASE_THEMEMOE}roulette`, { parse: true });
let themes = await getThemes(data.themes)
@ -383,26 +371,22 @@ const getRandomTheme = async () => {
title: doc.name,
link: doc.video
}));
};
const getArtist = async (id) => {
if (id === undefined) {
return await parserThemes.artists();
} else {
return await structureThemes(await parserThemes.artist(id), false)
}
};
const getAnimeGenres = async(genres) => {
let res
let promises = []
let res;
let promises = [];
if (genres.genre === undefined && genres.page === undefined && genres.order === undefined) {
return require('../assets/genres.json');
return animeGenres;
} else {
if (genres.page !== undefined) {
@ -429,28 +413,24 @@ const getAnimeGenres = async(genres) => {
}
return promises;
}
};
const getAllThemes = async () => require('../assets/themes.json');
const getAllThemes = async () => animeThemes;
const getDestAnimePlatforms = async () => {
let data = await homgot(`${BASE_ARUPPI}res/documents/animelegal/top.json`, { parse: true });
return data.map(doc =>({
id: doc.id,
name: doc.name,
logo: doc.logo
logo: doc.logo,
link: doc.link
}));
};
const getPlatforms = async (id) => {
let data
let data;
if (id === undefined) {
@ -463,6 +443,27 @@ const getPlatforms = async (id) => {
cover: doc.cover
}));
} if (id === "producers" || id === "apps" || id === "publishers" || "events") {
data = await homgot(`${BASE_ARUPPI}res/documents/animelegal/type/${id}.json`, { parse: true });
return data.map(doc =>({
id: doc.id,
name: doc.name,
logo: doc.logo,
cover: doc.cover,
description: doc.description,
type: doc.type,
moreInfo: doc.moreInfo,
facebook: doc.facebook,
twitter: doc.twitter,
instagram: doc.instagram,
webInfo: doc.webInfo,
webpage: doc.webpage,
latitude: doc.latitude || null,
longitude: doc.longitude || null
}));
} else {
data = await homgot(`${BASE_ARUPPI}res/documents/animelegal/type/${id}.json`, { parse: true });
@ -473,15 +474,14 @@ const getPlatforms = async (id) => {
type: doc.type,
logo: doc.logo,
cover: doc.cover,
link: doc.link
webpage: doc.webpage,
}));
}
};
const getProfilePlatform = async (id) => {
let data = await homgot(`${BASE_ARUPPI}res/documents/animelegal/platforms/${id}.json`, { parse: true })
let data = await homgot(`${BASE_ARUPPI}res/documents/animelegal/platforms/${id}.json`, { parse: true });
let channelId = { id: data[0].youtubeId, part: 'snippet,id', order: 'date', maxResults: '50', prop: 'items' };
let videos = await getYoutubeVideos(channelId)
@ -502,8 +502,44 @@ const getProfilePlatform = async (id) => {
faq: doc.faq,
videos: videos
}));
};
async function getRandomAnime() {
let data = directoryAnimes;
const randomNumber = Math.floor(Math.random() * data.length);
let result = data[randomNumber];
if (!result.jkanime) {
return {
title: result.title || null,
poster: result.poster || null,
synopsis: result.description || null,
status: result.state || null,
type: result.type || null,
rating: result.score || null,
genres: result.genres || null,
moreInfo: await animeExtraInfo(result.mal_id).then(info => info || null),
promo: await getAnimeVideoPromo(result.mal_id).then(promo => promo || null),
characters: await getAnimeCharacters(result.mal_id).then(characters => characters || null),
related: await getRelatedAnimesFLV(result.id)
};
}else {
return {
title: result.title || null,
poster: result.poster || null,
synopsis: result.description || null,
status: result.state || null,
type: result.type || null,
rating: result.score || null,
genres: result.genres || null,
moreInfo: await animeExtraInfo(result.mal_id).then(info => info || null),
promo: await getAnimeVideoPromo(result.mal_id).then(promo => promo || null),
characters: await getAnimeCharacters(result.mal_id).then(characters => characters || null),
related: await getRelatedAnimesMAL(result.mal_id)
};
}
}
module.exports = {
schedule,
@ -533,5 +569,6 @@ module.exports = {
getDestAnimePlatforms,
getPlatforms,
getSectionYoutubeVideos,
getProfilePlatform
getProfilePlatform,
getRandomAnime
};

@ -1,27 +1,30 @@
const got = require('got');
const got = require('got'); // This is to make a HTTP request without doing AJAX
const cheerio = require('cheerio');
const { CookieJar} = require('tough-cookie');
const cookieJar = new CookieJar();
let response
let data
let response;
let data;
const homgot = async (url, options) => {
if (options !== undefined) {
if (options.scrapy) {
response = await got(url, { cookieJar })
data = await cheerio.load(response.body)
response = await got(url, { cookieJar });
data = await cheerio.load(response.body);
}
if (options.parse) {
data = await got(url, { cookieJar }).json()
data = await got(url, { cookieJar }).json();
}
} else {
data = await got.get(url, { cookieJar });
}
return data
return data;
}
module.exports = {homgot}
module.exports = { homgot };

@ -16,6 +16,7 @@ router.get('/', (req, res) => {
'Schedule': '/api/v3/schedule/:day',
'Top': '/api/v3/top/:type/:subtype/:page',
'AllAnimes': '/api/v3/allAnimes',
'RandomAnime': '/api/v3/randomAnime',
'Anitakume': '/api/v3/anitakume',
'News': '/api/v3/news',
'Season': '/api/v3/season/:year/:type',
@ -25,8 +26,8 @@ router.get('/', (req, res) => {
'Futures Seasons': '/api/v3/laterSeasons',
'LastEpisodes': '/api/v3/lastEpisodes',
'Movies': '/api/v3/movies/:type/:page',
'Ovas': '/api/v3/ovas/:type/:page',
'Specials': '/api/v3/specials/:type/:page',
'Ovas': '/api/v3/ova/:type/:page',
'Specials': '/api/v3/special/:type/:page',
'Tv': '/api/v3/tv/:type/:page',
'MoreInfo': '/api/v3/moreInfo/:title',
'GetEpisodes': '/api/v3/getEpisodes/:title',
@ -42,8 +43,7 @@ router.get('/', (req, res) => {
'Random Theme': '/api/v3/randomTheme',
'Artists Theme': '/api/v3/artists/:id?',
'Famous Platforms': '/api/v3/destAnimePlatforms',
'Legal Platforms': '/api/v3/platforms/:id?',
'Platforms Details': '/api/v3/profilePlatform/:id'
'Legal Platforms': '/api/v3/platforms/:id?'
}
]
});

@ -193,10 +193,10 @@ router.get('/movies/:type/:page' , (req, res) =>{
let data = {url: 'Movies', prop: 'movies', type: req.params.type, page: req.params.page }
api.getSpecials(data)
.then(movies =>{
if (movies.length > 0) {
.then(animes =>{
if (animes.length > 0) {
res.status(200).json({
movies
animes
});
} else (
res.status(500).json({ message: 'Aruppi lost in the shell'})
@ -207,15 +207,15 @@ router.get('/movies/:type/:page' , (req, res) =>{
});
router.get('/ovas/:type/:page' , (req, res) =>{
router.get('/ova/:type/:page' , (req, res) =>{
let data = {url: 'Ova', prop: 'ova', type: req.params.type, page: req.params.page }
api.getSpecials(data)
.then(ovas =>{
if (ovas.length > 0) {
.then(animes =>{
if (animes.length > 0) {
res.status(200).json({
ovas
animes
});
} else (
res.status(500).json({ message: 'Aruppi lost in the shell'})
@ -226,15 +226,15 @@ router.get('/ovas/:type/:page' , (req, res) =>{
});
router.get('/specials/:type/:page' , (req, res) =>{
router.get('/special/:type/:page' , (req, res) =>{
let data = {url: 'Special', prop: 'special', type: req.params.type, page: req.params.page }
api.getSpecials(data)
.then(specials =>{
if (specials.length > 0) {
.then(animes =>{
if (animes.length > 0) {
res.status(200).json({
specials
animes
});
} else (
res.status(500).json({ message: 'Aruppi lost in the shell'})
@ -250,10 +250,10 @@ router.get('/tv/:type/:page' , (req, res) =>{
let data = {url: 'Tv', prop: 'tv', type: req.params.type, page: req.params.page }
api.getSpecials(data)
.then(tv =>{
if (tv.length > 0) {
.then(animes =>{
if (animes.length > 0) {
res.status(200).json({
tv
animes
});
} else (
res.status(500).json({ message: 'Aruppi lost in the shell'})
@ -272,9 +272,9 @@ router.get('/moreInfo/:title' , (req, res) =>{
.then(info => {
if (info !== undefined) {
res.status(200).json(info);
} else (
res.status(500).json({ message: 'Aruppi lost in the shell'})
)
} else {
res.status(500).json({ message: 'Aruppi lost in the shell'});
}
}).catch((err) =>{
console.error(err);
});
@ -287,12 +287,14 @@ router.get('/getEpisodes/:title' , (req, res) =>{
api.getEpisodes(title)
.then(episodes => {
if (episodes.length > 0) {
res.status(200).json({episodes});
} else (
res.status(500).json({ message: 'Aruppi lost in the shell'})
)
} else {
res.status(500).json({ message: 'Aruppi lost in the shell'});
}
}).catch((err) =>{
console.error(err);
});
@ -308,9 +310,9 @@ router.get('/getAnimeServers/:id([^/]+/[^/]+)' , (req, res) =>{
res.status(200).json({
servers
});
} else (
res.status(500).json({ message: 'Aruppi lost in the shell'})
)
} else {
res.status(500).json({ message: 'Aruppi lost in the shell'});
}
}).catch((err) =>{
console.error(err);
});
@ -318,7 +320,6 @@ router.get('/getAnimeServers/:id([^/]+/[^/]+)' , (req, res) =>{
});
router.get('/search/:title' , (req, res) =>{
let title = req.params.title;
api.search(title)
@ -337,7 +338,6 @@ router.get('/search/:title' , (req, res) =>{
});
router.get('/images/:query' , (req, res) =>{
let query = { title: req.params.query, count: '51', type: 'images', safesearch: '1', country: 'es_ES', uiv: '4' };
api.getImages(query)
@ -356,7 +356,6 @@ router.get('/images/:query' , (req, res) =>{
});
router.get('/videos/:channelId' , (req, res) =>{
let channelId = { id: req.params.channelId, part: 'snippet,id', order: 'date', maxResults: '50', prop: 'items' };
api.getYoutubeVideos(channelId)
@ -375,7 +374,6 @@ router.get('/videos/:channelId' , (req, res) =>{
});
router.get('/sectionedVideos/:type' , (req, res) =>{
let type = req.params.type;
api.getSectionYoutubeVideos(type)
@ -394,7 +392,6 @@ router.get('/sectionedVideos/:type' , (req, res) =>{
});
router.get('/radio' , (req, res) =>{
api.getRadioStations()
.then(stations =>{
if (stations.length > 0) {
@ -429,18 +426,17 @@ router.get('/allThemes', (req, res) =>{
router.get('/themes/:title' , (req, res) =>{
let title = req.params.title;
api.getOpAndEd(title)
.then(themes => {
if (themes.length > 0) {
if (themes) {
res.status(200).json({
themes
});
} else (
res.status(500).json({ message: 'Aruppi lost in the shell'})
)
} else {
res.status(500).json({ message: 'Aruppi lost in the shell'});
}
}).catch((err) =>{
console.error(err);
});
@ -448,19 +444,17 @@ router.get('/themes/:title' , (req, res) =>{
});
router.get('/themesYear/:year?', (req, res) =>{
let year = req.params.year;
let season = req.params.season
api.getThemesYear(year, season)
api.getThemesYear(year)
.then(themes =>{
if (themes.length > 0) {
res.status(200).json({
themes
});
} else (
res.status(500).json({ message: 'Aruppi lost in the shell'})
)
} else {
res.status(500).json({ message: 'Aruppi lost in the shell'});
}
}).catch((err) =>{
console.error(err);
});
@ -505,7 +499,6 @@ router.get('/artists/:id?', (req, res) =>{
});
router.get('/getByGenres/:genre?/:order?/:page?' , (req , res) =>{
let genres = { genre: req.params.genre, order: req.params.order, page: req.params.page };
api.getAnimeGenres(genres)
@ -514,14 +507,29 @@ router.get('/getByGenres/:genre?/:order?/:page?' , (req , res) =>{
res.status(200).json({
animes
});
} else (
res.status(500).json({ message: 'Aruppi lost in the shell'})
)
} else {
res.status(500).json({ message: 'Aruppi lost in the shell'});
}
}).catch((err) =>{
console.error(err);
});
});
router.get('/randomAnime', (req, res) => {
api.getRandomAnime()
.then(anime => {
if (anime) {
res.set('Cache-Control', 'no-store');
res.status(200).json(anime);
}else {
res.status(500).json({ message: 'Aruppi lost in the shell'});
}
})
.catch(error => {
console.log(error);
});
});
router.get('/destAnimePlatforms' , (req , res) =>{
api.getDestAnimePlatforms()
@ -545,25 +553,7 @@ router.get('/platforms/:id?' , (req , res) =>{
api.getPlatforms(id)
.then(platforms =>{
if (platforms.length > 0) {
res.status(200).json({
platforms
});
} else (
res.status(500).json({ message: 'Aruppi lost in the shell'})
)
}).catch((err) =>{
console.error(err);
});
});
router.get('/profilePlatform/:id' , (req , res) =>{
let id = req.params.id;
api.getProfilePlatform(id)
.then(info =>{
if (info.length > 0) {
res.status(200).json(info[0]);
res.status(200).json({platforms});
} else (
res.status(500).json({ message: 'Aruppi lost in the shell'})
)

File diff suppressed because it is too large Load Diff

@ -19,7 +19,7 @@ class ThemeParser {
return await this.parseLinks();
}
catch(err) {
throw err;
console.log(err);
}
}
@ -30,18 +30,18 @@ class ThemeParser {
return await this.parseYears();
}
catch(err) {
throw err;
console.log(err);
}
}
async serie(query) {
async serie(title) {
try {
this.animes = [];
this.$ = await redditocall('anime_index');
return await this.parseSerie(query);
return await this.parseSerie(title);
}
catch(err) {
throw err;
console.log(err);
}
}
@ -52,7 +52,7 @@ class ThemeParser {
return await this.parseArtists();
}
catch(err) {
throw err;
console.log(err);
}
}
@ -63,7 +63,7 @@ class ThemeParser {
return await this.parseArtist();
}
catch(err) {
throw err;
console.log(err);
}
}
@ -74,18 +74,19 @@ class ThemeParser {
return await this.parseRandom(query);
}
catch(err) {
throw err;
console.log(err);
}
}
async year(date) {
let animes = [];
this.$ = await redditocall(date)
this.$('h3').each((i, el) => {
let parsed = this.parseAnime(el);
this.$ = await redditocall(date);
this.$('h3').each((index, element) => {
let parsed = this.parseAnime(this.$(element));
parsed.year = date;
animes.push(parsed);
})
});
return animes;
}
@ -102,29 +103,29 @@ class ThemeParser {
let parsed = this.parseAnime(this.$('h3')[rand]);
resolve(parsed);
})
});
}
/* -ParseYears
Get the data from the year
get the name and the id to do the respective
scrapping.
*/
parseYears() {
return new Promise(async resolve => {
let years = [];
let promises = []
let data = this.$('h3 a');
for (let i = 0; i < data.length; i++) {
promises.push({
id: data[i].children[0].parent.attribs.href.split('/')[4],
name: data[i].children[0].data
})
if (i === data.length - 1) {
resolve(promises)
}
this.$('h3 a').each((index, element) => {
years.push(
{
id: this.$(element).attr('href').split('/')[4],
name: this.$(element).text()
}
);
});
})
resolve(years);
});
}
parseArtists() {
@ -157,34 +158,42 @@ class ThemeParser {
for (let i = 0; i < data.length; i++) {
let parsed = await this.parseAnime(data[i])
let parsed = await this.parseAnime(data[i]);
promises.push(parsed)
if (i === data.length - 1) {
resolve(promises)
resolve(promises);
}
}
})
}
parseSerie(query){
/* - ParseSerie
Parse the HTML from the redditocall
and search for the h3 tag to be the
same of the title and resolve a object.
*/
parseSerie(title) {
return new Promise(async resolve => {
let data = this.$('p a');
for (let i = 0; i < data.length; i++) {
let serieElement = data[i].children[0].data
let serieElement = data[i].children[0].data;
if (serieElement.split(" (")[0] === query) {
if (serieElement.split(" (")[0] === title) {
let year = this.$('p a')[i].attribs.href.split('/r/AnimeThemes/wiki/')[1].split('#wiki')[0];
this.$ = await redditocall(this.$('p a')[i].attribs.href.split('/r/AnimeThemes/wiki/')[1].split('#wiki')[0]);
for (let i = 0; i < this.$('h3').length; i++) {
if (this.$('h3')[i].children[0].children[0].data === query) {
if (this.$('h3')[i].children[0].children[0].data === title) {
let parsed = this.parseAnime(this.$('h3')[i]);
parsed.year = year;
resolve(parsed);
}
}
@ -192,17 +201,18 @@ class ThemeParser {
}
}
})
});
}
parseLinks() {
return new Promise(async resolve => {
let years = this.$('h3 a');
this.$('h3 a')[0].children[0].data
for (let i = 0; i < years.length; i++) {
let yearElement = years[i];
await this.year(this.$(yearElement).attr('href').split('/')[4])
.then(async animes => {
this.animes = this.animes.concat(animes);
@ -215,65 +225,77 @@ class ThemeParser {
})
}
parseAnime(dat) {
let el = this.$(dat).children('a');
let title = el.text();
let malId = el.attr('href').split('/')[4];
let next = this.$(dat).next();
/* - ParseAnime
Parse the h3 tag and get the table
for the next function to parse the table
and get the information about the ending and
openings.
*/
parseAnime(element) {
let el = this.$(element).find('a');
let title = this.$(el).text();
let mal_id = this.$(el).attr('href').split('/')[4];
let next = this.$(element).next();
let theme = {
id: malId,
id: mal_id,
title
}
};
if (next.prop("tagName") === "P") {
theme.themes = this.parseTable(next.next());
} else if (next.prop("tagName") === "TABLE") {
theme.themes = this.parseTable(next);
if (this.$(next).prop("tagName") === "TABLE") {
theme.themes = this.parseTable(this.$(next));
}else if (this.$(next).prop("tagName") === "P") {
theme.themes = this.parseTable(this.$(next).next());
}
return theme;
}
parseTable(table) {
if (table.prop('tagName') !== "TABLE") {
return this.parseTable(table.next());
/* - ParseTable
Parse the table tag from the HTML
and returns a object with all the
information.
*/
parseTable(element) {
if (this.$(element).prop('tagName') !== "TABLE") {
return this.parseTable(this.$(element).next());
}
let themes = [];
table.children('tbody').children('tr').each(function () {
const $ = cheerio.load(this);
const td = $('td'); // Theme row
let name = replaceAll(td.first().text(), "&quot;", "\"")
let linkEl = td.eq(1).children().first();
let link = linkEl.attr('href');
let linkDesc = linkEl.text();
let episodes = td.eq(2).text();
let notes = td.eq(3).text();
this.$(element).find('tbody').find('tr').each((i, elem) => {
let name = replaceAll(this.$(elem).find('td').eq(0).text(), '&quot;', '"');
let link = this.$(elem).find('td').eq(1).find('a').attr('href');
let linkDesc = this.$(elem).find('td').eq(1).find('a').text();
let episodes = this.$(elem).find('td').eq(2).text().length > 0 ? this.$(elem).find('td').eq(2).text() : "";
let notes = this.$(elem).find('td').eq(3).text().length > 0 ? this.$(elem).find('td').eq(3).text() : "";
themes.push({
name,
link,
desc: linkDesc,
type: (name.startsWith('OP') ? 'opening' : 'ending'),
type: name.startsWith('OP') ? 'Opening' : name.startsWith('ED') ? 'Ending' : 'OP/ED',
episodes,
notes
})
})
});
});
return themes;
}
}
async function redditocall(href) {
let resp = await homgot(REDDIT_ANIMETHEMES + href + ".json", { parse: true })
let resp = await homgot(REDDIT_ANIMETHEMES + href + ".json", { parse: true });
return cheerio.load(getHTML(resp.data.content_html));
}
function getHTML(str) {
let html = replaceAll(str, "&lt;", "<")
html = replaceAll(html, "&gt;", ">")
let html = replaceAll(str, "&lt;", "<");
html = replaceAll(html, "&gt;", ">");
return html;
}
@ -281,4 +303,5 @@ function replaceAll(str, find, replace) {
return str.replace(new RegExp(find, 'g'), replace);
}
module.exports = ThemeParser;

@ -1,10 +1,13 @@
const {
BASE_ANIMEFLV, BASE_JIKAN, BASE_ARUPPI, BASE_JKANIME
} = require('../api/urls');
const {
homgot
} = require('../api/apiCall');
const directoryAnimes = JSON.parse(JSON.stringify(require('../assets/directory.json')));
const radioStations = require('../assets/radiostations.json');
const animeGenres = require('../assets/genres.json');
const animeThemes = require('../assets/themes.json');
function btoa(str) {
let buffer;
@ -20,93 +23,107 @@ function btoa(str) {
global.btoa = btoa;
async function videoServersJK(id) {
const $ = await homgot(`${BASE_JKANIME}${id}`, { scrapy: true });
let servers = {};
let script;
const scripts = $('script');
const episodes = $('div#reproductor-box li');
const serverNames = [];
let servers = [];
const serverNames = $('div#reproductor-box li').map((index, element) => {
return $(element).find('a').text();
}).get();
episodes.each((index, element) => serverNames.push($(element).find('a').text()))
$('script').each((index, element) => {
if ($(element).html().includes('var video = [];')) {
script = $(element).html();
}
});
for (let i = 0; i < scripts.length; i++) {
try {
const contents = $(scripts[i]).html();
if ((contents || '').includes('var video = [];')) {
Array.from({ length: episodes.length }, (v, k) => {
let index = Number(k + 1);
let videoPageURL = contents.split(`video[${index}] = \'<iframe class="player_conte" src="`)[1].split('"')[0];
servers.push({ iframe: videoPageURL });
});
let videoUrls = script.match(/(?<=src=").*?(?=[\*"])/gi);
for (let i = 0; i < serverNames.length; i++) {
servers[serverNames[i]] = videoUrls[i];
}
} catch (err) {
console.log(err)
console.log(err);
return null;
}
}
let serverList = [];
for (let server in servers) {
if (serverNames[serverNames.indexOf(server)].toLowerCase() === 'desu') {
serverList.push({
id: serverNames[serverNames.indexOf(server)].toLowerCase(),
url: await desuServerUrl(servers[server]) !== null ? await desuServerUrl(servers[server]) : servers[server],
direct: true
});
}else {
serverList.push({
id: serverNames[server].toLowerCase(),
url: await getVideoURL(servers[server].iframe),
id: serverNames[serverNames.indexOf(server)].toLowerCase(),
url: servers[server],
direct: true
});
}
}
serverList = serverList.filter(x => x.id !== 'xtreme s' && x.id !== 'desuka');
return await Promise.all(serverList);
return serverList;
}
async function getVideoURL(url) {
async function desuServerUrl(url) {
const $ = await homgot(url, { scrapy: true});
let script;
const video = $('video');
if (video.length) {
const src = $(video).find('source').attr('src');
return src || null;
$('script').each((index, element) => {
if ($(element).html().includes('var parts = {')) {
if ($(element).html()) {
script = $(element).html();
}else {
return null;
}
else {
const scripts = $('script');
const l = global;
const ll = String;
const $script2 = $(scripts[1]).html();
eval($script2);
return l.ss || null;
}
});
let result = script.match(/swarmId: '(https:\/\/\S+)'/gi)
.toString()
.split('\'')[1];
return result;
}
const jkanimeInfo = async (id) => {
const jkanimeInfo = async (id) => {
let $ = await homgot(`${BASE_JKANIME}${id}`, { scrapy: true });
let nextEpisodeDate
let rawNextEpisode = $('div[id="container"] div.left-container div[id="proxep"] p')[0]
let nextEpisodeDate;
let rawNextEpisode = $('div[id="container"] div.left-container div[id="proxep"] p')[0];
if (rawNextEpisode === undefined) {
nextEpisodeDate = null
nextEpisodeDate = null;
} else {
if (rawNextEpisode.children[1].data === ' ') {
nextEpisodeDate = null
nextEpisodeDate = null;
} else {
nextEpisodeDate = rawNextEpisode.children[1].data.trim()
nextEpisodeDate = rawNextEpisode.children[1].data.trim();
}
}
const eps_temp_list = [];
let episodes_aired = '';
$('div#container div.left-container div.navigation a').each(async (index, element) => {
const $element = $(element);
const total_eps = $element.text();
eps_temp_list.push(total_eps);
})
});
try { episodes_aired = eps_temp_list[0].split('-')[1].trim(); } catch (err) { }
const animeListEps = [{ nextEpisodeDate: nextEpisodeDate }];
for (let i = 1; i <= episodes_aired; i++) {
let episode = i;
let animeId = $('div[id="container"] div.content-box div[id="episodes-content"]')[0].children[1].children[3].attribs.src.split('/')[7].split('.jpg')[0];
@ -122,52 +139,147 @@ const jkanimeInfo = async (id) => {
};
function getPosterAndType(id, mal_id) {
let data = directoryAnimes;
if (id) {
for (let anime of data) {
if (anime.id === id) {
return [
anime.poster,
anime.type
];
}
}
}
if (mal_id) {
for (let anime of data) {
if (anime.mal_id === parseInt(mal_id)) {
return [
anime.poster,
anime.type
];
}
}
}
return "";
}
async function getRelatedAnimesFLV(id) {
const $ = await homgot(`${BASE_ANIMEFLV}/anime/${id}`, { scrapy: true });
let listRelated = {};
let relatedAnimes = [];
if ($('ul.ListAnmRel').length) {
$('ul.ListAnmRel li a').each((index, element) => {
listRelated[$(element).text()] = $(element).attr('href');
});
for (related in listRelated) {
let posterUrl = getPosterAndType(listRelated[related].split('/')[2], false);
relatedAnimes.push(
{
title: related,
type: posterUrl[1],
poster: posterUrl[0]
}
);
}
return relatedAnimes;
}else {
return [];
}
}
async function getRelatedAnimesMAL(mal_id) {
const $ = await homgot(`https://myanimelist.net/anime/${mal_id}`, { scrapy: true });
let listRelated = {};
let relatedAnimes = [];
if ($('table.anime_detail_related_anime').length > 0) {
$('table.anime_detail_related_anime').find('tbody tr').each((index, element) => {
if ($(element).find('td').eq(0) !== 'Adaptation:') {
listRelated[$(element).find('td').eq(1).text()] = $(element).find('td').children('a').attr('href');
}
});
for (related in listRelated) {
let posterUrl = getPosterAndType(false, listRelated[related].split('/')[2]);
if (posterUrl !== "") {
relatedAnimes.push(
{
title: related,
type: posterUrl[1],
poster: posterUrl[0]
}
);
}
}
return relatedAnimes;
}else {
return [];
}
}
const animeflvGenres = async (id) => {
let $ = await homgot(`${BASE_ANIMEFLV}${id}`, { scrapy: true });
let $ = await homgot(`${BASE_ANIMEFLV}/${id}`, { scrapy: true });
$('main.Main section.WdgtCn nav.Nvgnrs a').each((index, element) => {
return $(element).attr('href').split('=')[1] || null;
});
}
const animeflvInfo = async (id) => {
let $ = await homgot(`${BASE_ANIMEFLV}anime/${id}`, { scrapy: true });
let $ = await homgot(`${BASE_ANIMEFLV}/anime/${id}`, { scrapy: true });
let scripts = $('script').toArray();
const anime_info_ids = [];
const anime_eps_data = [];
Array.from({ length: scripts.length }, (v, k) => {
const contents = $(scripts[k]).html();
for (let script of scripts) {
const contents = $(script).html();
if ((contents || '').includes('var anime_info = [')) {
let anime_info = contents.split('var anime_info = ')[1].split(';\n')[0];
let dat_anime_info = JSON.parse(anime_info);
anime_info_ids.push(dat_anime_info);
}
if ((contents || '').includes('var episodes = [')) {
let episodes = contents.split('var episodes = ')[1].split(';')[0];
let eps_data = JSON.parse(episodes)
let eps_data = JSON.parse(episodes);
anime_eps_data.push(eps_data);
}
});
}
const animeId = id;
let nextEpisodeDate
let nextEpisodeDate;
if (anime_info_ids.length > 0) {
if (anime_info_ids[0].length === 4) {
nextEpisodeDate = anime_info_ids[0][3]
nextEpisodeDate = anime_info_ids[0][3];
} else {
nextEpisodeDate = null
nextEpisodeDate = null;
}
}
const amimeTempList = [];
for (const [key] of Object.entries(anime_eps_data)) {
let episode = anime_eps_data[key].map(x => x[0]);
let episodeId = anime_eps_data[key].map(x => x[1]);
amimeTempList.push(episode, episodeId);
}
const animeListEps = [{ nextEpisodeDate: nextEpisodeDate }];
for (let i = 0; i < amimeTempList[1].length; i++) {
let data = amimeTempList.map(x => x[i]);
let episode = data[0];
@ -177,20 +289,23 @@ const animeflvInfo = async (id) => {
animeListEps.push({
episode: episode,
id: link,
})
});
}
return animeListEps
return animeListEps;
};
const getAnimeCharacters = async(title) =>{
const matchAnime = await getMALid(title)
const getAnimeCharacters = async(mal_id) =>{
let data;
try {
if(matchAnime !== null) {
const data = await homgot(`${BASE_JIKAN}anime/${matchAnime.mal_id}/characters_staff`, { parse: true });
data = await homgot(`${BASE_JIKAN}anime/${mal_id}/characters_staff`, { parse: true });
}catch(error) {
console.log(error);
}
if(data !== null) {
return data.characters.map(doc => ({
id: doc.mal_id,
name: doc.name,
@ -198,42 +313,34 @@ const getAnimeCharacters = async(title) =>{
role: doc.role
}));
}
} catch (err) {
console.log(err)
}
};
const getAnimeVideoPromo = async(title) =>{
const matchAnime = await getMALid(title)
const getAnimeVideoPromo = async(mal_id) =>{
let data;
try {
if(matchAnime !== null) {
const data = await homgot(`${BASE_JIKAN}anime/${matchAnime.mal_id}/videos`, {parse: true})
data = await homgot(`${BASE_JIKAN}anime/${mal_id}/videos`, {parse: true});
}catch(error) {
console.log(error);
}
if(data !== null) {
return data.promo.map(doc => ({
title: doc.title,
previewImage: doc.image_url,
videoURL: doc.video_url
}));
}
} catch (err) {
console.log(err)
}
};
const animeExtraInfo = async (title) => {
const matchAnime = await getMALid(title)
const animeExtraInfo = async (mal_id) => {
const data = await homgot(`${BASE_JIKAN}anime/${mal_id}`, { parse: true });
try {
if(matchAnime !== null) {
const data = await homgot(`${BASE_JIKAN}anime/${matchAnime.mal_id}`, {parse: true})
const promises = [];
let broadcast = ''
if(data !== null) {
let promises = [];
let broadcast = '';
Array(data).map(doc => {
@ -283,30 +390,7 @@ const animeExtraInfo = async (title) => {
}
} catch (err) {
console.log(err)
}
};
const getMALid = async(title) =>{
if (title === undefined || title === null) {
return 1
} else {
const res = await homgot(`${BASE_JIKAN}search/anime?q=${title}`,{ parse: true })
const matchAnime = res.results.find(x => x.title === title);
if(typeof matchAnime === 'undefined') {
return null;
} else {
return matchAnime;
}
console.log(err);
}
};
@ -317,9 +401,8 @@ const imageUrlToBase64 = async (url) => {
};
const searchAnime = async (query) => {
let data = JSON.parse(JSON.stringify(require('../assets/directory.json')));
let queryLowerCase = query.toLowerCase()
let data = directoryAnimes;
let queryLowerCase = query.toLowerCase();
const res = data.filter(x => x.title.toLowerCase().includes(queryLowerCase));
return res.map(doc => ({
@ -328,7 +411,6 @@ const searchAnime = async (query) => {
type: doc.type || null,
image: doc.poster || null
}));
};
const transformUrlServer = async (urlReal) => {
@ -336,8 +418,8 @@ const transformUrlServer = async (urlReal) => {
for (const data of urlReal) {
if (data.server === 'amus' || data.server === 'natsuki') {
let res = await homgot(data.code.replace("embed", "check"), { parse: true });
data.code = res.file || null
data.direct = true
data.code = res.file || null;
data.direct = true;
}
}
@ -384,55 +466,71 @@ const obtainPreviewNews = (encoded) => {
return image;
}
/* - StructureThemes
This function only parses the theme/themes
if indv is true, then only return a object, if it's false
then returns a array with the themes selected.
*/
const structureThemes = async (body, indv) => {
let themes = [];
const promises = []
if (indv === true) {
promises.push({
return {
title: body.title,
year: body.year,
themes: await getThemesData(body.themes),
});
themes: await getThemesData(body.themes)
};
} else {
for (let i = 0; i <= body.length - 1; i++) {
promises.push({
themes.push({
title: body[i].title,
year: body[i].year,
themes: await getThemesData(body[i].themes),
});
}
return themes;
}
return promises;
};
/* - GetThemesData
Get the themes from the object and
format to a new array of items where
these items are formatted better.
*/
const getThemesData = async (themes) => {
let promises = []
let items = [];
for (let i = 0; i <= themes.length - 1; i++) {
promises.push({
items.push({
title: themes[i].name.split('"')[1] || 'Remasterización',
type: themes[i].name.split('"')[0] || 'OP/ED',
episodes: themes[i].episodes || null,
type: themes[i].type,
episodes: themes[i].episodes !== "" ? themes[i].episodes : null,
notes: themes[i].notes !== "" ? themes[i].notes : null,
video: themes[i].link
});
}
return promises.filter(x => x.title !== 'Remasterización');
return items.filter(x => x.title !== 'Remasterización');
};
const getThemes = async (themes) => {
return themes.map(doc => ({
name: doc.themeName,
type: doc.themeType,
video: doc.mirror.mirrorURL
}));
};
module.exports = {
@ -441,13 +539,18 @@ module.exports = {
animeflvInfo,
getAnimeCharacters,
getAnimeVideoPromo,
getRelatedAnimesFLV,
getRelatedAnimesMAL,
animeExtraInfo,
getMALid,
imageUrlToBase64,
searchAnime,
transformUrlServer,
obtainPreviewNews,
structureThemes,
getThemes,
videoServersJK
videoServersJK,
directoryAnimes,
radioStations,
animeGenres,
animeThemes
}

Loading…
Cancel
Save