mirror of https://github.com/aruppi/aruppi-api.git
Compare commits
233 Commits
Author | SHA1 | Date |
---|---|---|
|
6c44d5a712 | 2 years ago |
|
cef7574083 | 2 years ago |
|
7c6307cb1e | 2 years ago |
|
58ac761098 | 2 years ago |
|
3a633b2ff2 | 2 years ago |
|
e39bb486b0 | 2 years ago |
|
189a5bfb79 | 2 years ago |
|
df30fd785e | 2 years ago |
|
656d4ce1ba | 2 years ago |
|
a90e522c21 | 2 years ago |
|
faf0afee8c | 3 years ago |
|
736ff79707 | 3 years ago |
|
2b4e3d0d7d | 3 years ago |
|
fdb744582f | 3 years ago |
|
c3fa6cd854 | 3 years ago |
|
868a958e36 | 3 years ago |
|
99d636fa3f | 4 years ago |
|
361d0553e9 | 4 years ago |
|
08fb60749b | 4 years ago |
|
5f3720446b | 4 years ago |
|
6912a2eddd | 4 years ago |
|
033b35aee9 | 4 years ago |
|
9ba3e1035e | 4 years ago |
|
11ed6d5731 | 4 years ago |
|
dafe02215a | 4 years ago |
|
90cb8bab66 | 4 years ago |
|
31075ce33d | 4 years ago |
|
5c06108a3e | 4 years ago |
|
78315e4017 | 4 years ago |
|
7be55d1f87 | 4 years ago |
|
3bcdc34012 | 4 years ago |
|
24fa86de87 | 4 years ago |
|
a9bca94952 | 4 years ago |
|
22141c16f8 | 4 years ago |
|
5719ef1b17 | 4 years ago |
|
f32ca2bdcf | 4 years ago |
|
57dedd3ab5 | 4 years ago |
|
0a60814065 | 4 years ago |
|
2afd59cf7a | 4 years ago |
|
10cdb63ac4 | 4 years ago |
|
327c635467 | 4 years ago |
|
116e89e6c5 | 4 years ago |
|
c46b5eeb9d | 4 years ago |
|
c0d4fbe317 | 4 years ago |
|
bcc22b436d | 4 years ago |
|
21e8fc2637 | 4 years ago |
|
e53fefd653 | 4 years ago |
|
b529f6f13a | 4 years ago |
|
d5550bbaeb | 4 years ago |
|
f2e13f5201 | 4 years ago |
|
5708086201 | 4 years ago |
|
c1c33cb4a9 | 4 years ago |
|
177ddcb924 | 4 years ago |
|
fdef7d04e2 | 4 years ago |
|
6480c272ab | 4 years ago |
|
3fc5ddab5d | 4 years ago |
|
04b30632f8 | 4 years ago |
|
f8ab77b289 | 4 years ago |
|
77513c4820 | 4 years ago |
|
adad49eaae | 4 years ago |
|
b0e5b4c7bc | 4 years ago |
|
ea1ee08c78 | 4 years ago |
|
c0e1e5172b | 4 years ago |
|
893a9e7386 | 4 years ago |
|
87cecdafec | 4 years ago |
|
0be12412ce | 4 years ago |
|
a4d9332510 | 4 years ago |
|
482891e39b | 4 years ago |
|
76994fdbe9 | 4 years ago |
|
44afd0c085 | 4 years ago |
|
4f2bbbd417 | 4 years ago |
|
d34241a0ac | 4 years ago |
|
533ae5da2d | 4 years ago |
|
8bd8be8370 | 4 years ago |
|
526a24c3d7 | 4 years ago |
|
27955db82e | 4 years ago |
|
9bdbc458fc | 4 years ago |
|
d64e2df268 | 4 years ago |
|
e7d45c19d2 | 4 years ago |
|
cda086a583 | 4 years ago |
|
d8cc3626f2 | 4 years ago |
|
133e800b75 | 4 years ago |
|
a2f1a08d0d | 4 years ago |
|
fcd1ddc87b | 4 years ago |
|
db943834e8 | 4 years ago |
|
a634921de8 | 4 years ago |
|
841c5ad166 | 4 years ago |
|
4a7b775159 | 4 years ago |
|
3f7d86be67 | 4 years ago |
|
021af8f19d | 4 years ago |
|
dabc7f6c23 | 4 years ago |
|
421efd2961 | 4 years ago |
|
f855479650 | 4 years ago |
|
c4d83df972 | 4 years ago |
|
189bf729c0 | 4 years ago |
|
596524f03b | 4 years ago |
|
819109d371 | 4 years ago |
|
31573b631d | 4 years ago |
|
a13981d49d | 4 years ago |
|
e0b22d4edb | 4 years ago |
|
aa016be0c8 | 4 years ago |
|
f490c81cf1 | 4 years ago |
|
1dead82ddc | 4 years ago |
|
faa3743569 | 4 years ago |
|
8b53015280 | 4 years ago |
|
375ba8bb81 | 4 years ago |
|
79114fa000 | 4 years ago |
|
2effa8e95c | 4 years ago |
|
cf7e3a39a9 | 4 years ago |
|
75e6eaf364 | 4 years ago |
|
c04b349995 | 4 years ago |
|
aefe45a723 | 4 years ago |
|
967f35ef77 | 4 years ago |
|
3bc8ec2f38 | 4 years ago |
|
7f13918f85 | 4 years ago |
|
a48eef2383 | 4 years ago |
|
19f470c077 | 4 years ago |
|
61830c85cb | 4 years ago |
|
37d9516b0d | 4 years ago |
|
5507023b39 | 4 years ago |
|
065b1dff0b | 4 years ago |
|
3c117fd98d | 4 years ago |
|
fd3f8dc778 | 4 years ago |
|
aefe93de52 | 4 years ago |
|
7b8dca11fc | 4 years ago |
|
7345d7fc45 | 4 years ago |
|
b4cde8964e | 4 years ago |
|
6325d31cc1 | 4 years ago |
|
e327b4be11 | 4 years ago |
|
d35db8944e | 4 years ago |
|
fc2dc9ae79 | 4 years ago |
|
40d8fe8a3a | 4 years ago |
|
da96f84228 | 4 years ago |
|
8ebd8dbceb | 4 years ago |
|
121bc98a89 | 4 years ago |
|
afa20d36df | 4 years ago |
|
0fea12c350 | 5 years ago |
|
16c17ac0ca | 5 years ago |
|
563d0a7c4c | 5 years ago |
|
c0bab5e174 | 5 years ago |
|
c7b313857c | 5 years ago |
|
55b09858a3 | 5 years ago |
|
ebdbd6987b | 5 years ago |
|
ba24488e72 | 5 years ago |
|
62a059c1fd | 5 years ago |
|
01d23d5076 | 5 years ago |
|
56d063bf9b | 5 years ago |
|
4a0846b02b | 5 years ago |
|
992d35799b | 5 years ago |
|
1783b49c22 | 5 years ago |
|
18724d7226 | 5 years ago |
|
8fcc690dce | 5 years ago |
|
f80aaf6d12 | 5 years ago |
|
8de23d0bd9 | 5 years ago |
|
dbf8b494cd | 5 years ago |
|
2f18461bf4 | 5 years ago |
|
9a7d302854 | 5 years ago |
|
441223a0a0 | 5 years ago |
|
4165ef546e | 5 years ago |
|
0ed7927283 | 5 years ago |
|
412897ca90 | 5 years ago |
|
43296328c7 | 5 years ago |
|
cf5b050917 | 5 years ago |
|
e4fded0057 | 5 years ago |
|
9a511f9814 | 5 years ago |
|
31feb54230 | 5 years ago |
|
e7136dba71 | 5 years ago |
|
b26a0dbd35 | 5 years ago |
|
355f38b1dc | 5 years ago |
|
7930667295 | 5 years ago |
|
720cddb4d5 | 5 years ago |
|
17510dbb5b | 5 years ago |
|
26c0d766cd | 5 years ago |
|
d671c6fc58 | 5 years ago |
|
1e44d6f286 | 5 years ago |
|
02293276bf | 5 years ago |
|
2746613f9f | 5 years ago |
|
1532e15bbf | 5 years ago |
|
b8374812e7 | 5 years ago |
|
3c505cf54e | 5 years ago |
|
04cdccc8f6 | 5 years ago |
|
6c6334759d | 5 years ago |
|
7cd965261d | 5 years ago |
|
1bd6f42937 | 5 years ago |
|
0c14e0f4bf | 5 years ago |
|
c65a5bd3e4 | 5 years ago |
|
9107698f04 | 5 years ago |
|
d65fc54821 | 5 years ago |
|
26f2341631 | 5 years ago |
|
872bc25204 | 5 years ago |
|
214a0aa15c | 5 years ago |
|
22c99e0641 | 5 years ago |
|
a67057ed9d | 5 years ago |
|
fc028ea441 | 5 years ago |
|
87421d8978 | 5 years ago |
|
324f5a4a1e | 5 years ago |
|
dacdcdd88f | 5 years ago |
|
dfa6283a38 | 5 years ago |
|
fabfcb969b | 5 years ago |
|
a89decfc35 | 5 years ago |
|
64601c4914 | 5 years ago |
|
d80ab08a1a | 5 years ago |
|
4a89b12a2c | 5 years ago |
|
27528a0fb1 | 5 years ago |
|
1a8c1e1258 | 5 years ago |
|
9ea6a60d1f | 5 years ago |
|
21cfacba70 | 5 years ago |
|
933ec74822 | 5 years ago |
|
d3558c7f33 | 5 years ago |
|
5c151093a9 | 5 years ago |
|
078a75073b | 5 years ago |
|
9f4e8fc865 | 5 years ago |
|
0d1c2ee1fe | 5 years ago |
|
c6e6194701 | 5 years ago |
|
5124765eac | 5 years ago |
|
1e357ad206 | 5 years ago |
|
cfa6b05917 | 5 years ago |
|
2b88dfb7a1 | 5 years ago |
|
78ada322f0 | 5 years ago |
|
d7e2609b56 | 5 years ago |
|
f01535e187 | 5 years ago |
|
0c71bfda9a | 5 years ago |
|
fd0583de4f | 5 years ago |
|
0c57e47bb4 | 5 years ago |
|
36e1665ea6 | 5 years ago |
|
b70747ee99 | 5 years ago |
|
61c14e9ccd | 5 years ago |
|
bd7b22ddc8 | 5 years ago |
|
fa6bd4bcb9 | 5 years ago |
|
d33e9c1a8a | 5 years ago |
|
25b57ce716 | 5 years ago |
|
bc9e712614 | 5 years ago |
|
b07d16d33d | 5 years ago |
@ -0,0 +1,6 @@
|
||||
PORT_LISTEN=5000
|
||||
DATABASE_HOST=localhost
|
||||
DATABASE_PORT=27017
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=aruppiTime
|
@ -0,0 +1,32 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
commonjs: true,
|
||||
node: true,
|
||||
},
|
||||
extends: ['prettier', 'eslint:recommended'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
sourceType: 'module',
|
||||
ecmaFeatures: {
|
||||
jsx: false,
|
||||
},
|
||||
},
|
||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
||||
rules: {
|
||||
'no-underscore-dangle': 'off',
|
||||
'class-methods-use-this': 'off',
|
||||
camelcase: 'off',
|
||||
'no-unused-vars': 'warn',
|
||||
'no-undef': 'warn',
|
||||
},
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
node: {
|
||||
extensions: ['.ts'],
|
||||
typescript: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
singleQuote: true,
|
||||
trailingComma: 'all',
|
||||
arrowParens: 'avoid',
|
||||
};
|
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
Before Width: | Height: | Size: 425 KiB |
File diff suppressed because it is too large
Load Diff
@ -1,512 +0,0 @@
|
||||
const rss = require('rss-to-json');
|
||||
|
||||
const {
|
||||
homgot
|
||||
} = require('../api/apiCall');
|
||||
|
||||
const {
|
||||
animeflvInfo,
|
||||
imageUrlToBase64,
|
||||
getAnimeCharacters,
|
||||
getAnimeVideoPromo,
|
||||
animeExtraInfo,
|
||||
searchAnime,
|
||||
transformUrlServer,
|
||||
obtainPreviewNews,
|
||||
structureThemes,
|
||||
getAnimes,
|
||||
getDirectory,
|
||||
helper
|
||||
} = require('../utils/index');
|
||||
|
||||
const ThemeParser = require('../utils/animetheme');
|
||||
const parserThemes = new ThemeParser()
|
||||
|
||||
const {
|
||||
BASE_ANIMEFLV_JELU, BASE_JIKAN, BASE_IVOOX, BASE_QWANT, BASE_YOUTUBE, GENRES_URL
|
||||
} = require('./urls');
|
||||
|
||||
const schedule = async (day) =>{
|
||||
|
||||
let options = { parse: true }
|
||||
const data = await homgot(`${BASE_JIKAN}schedule/${day.current}`, options);
|
||||
const body = data[day.current];
|
||||
const promises = []
|
||||
|
||||
body.map(doc =>{
|
||||
|
||||
promises.push({
|
||||
title: doc.title,
|
||||
malid: doc.mal_id,
|
||||
image: doc.image_url
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
return promises;
|
||||
|
||||
};
|
||||
|
||||
const top = async (type, subtype, page) =>{
|
||||
let options = { parse: true }
|
||||
const data = await homgot(`${BASE_JIKAN}top/${type}/${page}/${subtype}`, options);
|
||||
return data.top;
|
||||
};
|
||||
|
||||
const getAllAnimes = async () =>{
|
||||
|
||||
let data = await getAnimes()
|
||||
|
||||
return data.map(item => ({
|
||||
index: item[0],
|
||||
animeId: item[3],
|
||||
title: item[1],
|
||||
id: item[2],
|
||||
type: item[4]
|
||||
}));
|
||||
|
||||
};
|
||||
|
||||
const getAllDirectory = async () =>{ return await getDirectory(); };
|
||||
|
||||
const getAnitakume = async () =>{
|
||||
|
||||
const promises = []
|
||||
|
||||
await rss.load(BASE_IVOOX).then(rss => {
|
||||
|
||||
const body = JSON.parse(JSON.stringify(rss, null, 3)).items
|
||||
body.map(doc =>{
|
||||
|
||||
let time = new Date(doc.created)
|
||||
const monthNames = ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"];
|
||||
|
||||
let day = time.getDate()
|
||||
let month = monthNames[time.getMonth()]
|
||||
let year = time.getFullYear()
|
||||
let date
|
||||
|
||||
if(month < 10){
|
||||
date = `${day} de 0${month} de ${year}`
|
||||
}else{
|
||||
date = `${day} de ${month} de ${year}`
|
||||
}
|
||||
|
||||
promises.push({
|
||||
title: doc.title,
|
||||
duration: doc.itunes_duration,
|
||||
created: date,
|
||||
mp3: doc.enclosures.map(x => x.url)
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
return promises;
|
||||
|
||||
};
|
||||
|
||||
const getNews = async (pageRss) =>{
|
||||
|
||||
const 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
|
||||
body.map(doc => {
|
||||
|
||||
promises.push({
|
||||
title: doc.title,
|
||||
url: doc.link,
|
||||
author: pageRss[i].author,
|
||||
thumbnail: obtainPreviewNews(doc[pageRss[i].content]),
|
||||
content: doc[pageRss[i].content]
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return promises;
|
||||
|
||||
};
|
||||
|
||||
const season = async (year, type) =>{
|
||||
|
||||
let options = { parse: true }
|
||||
const data = await homgot(`${BASE_JIKAN}season/${year}/${type}`, options);
|
||||
let body = data.anime;
|
||||
const promises = []
|
||||
|
||||
body.map(doc =>{
|
||||
|
||||
promises.push({
|
||||
title: doc.title,
|
||||
malid: doc.mal_id,
|
||||
image: doc.image_url,
|
||||
genres: doc.genres.map(x => x.name)
|
||||
});
|
||||
});
|
||||
|
||||
return promises;
|
||||
|
||||
};
|
||||
|
||||
const allSeasons = async () =>{
|
||||
|
||||
let options = { parse: true }
|
||||
const data = await homgot(`${BASE_JIKAN}season/archive`, options);
|
||||
let body = data.archive;
|
||||
const promises = []
|
||||
|
||||
body.map(doc =>{
|
||||
|
||||
promises.push({
|
||||
year: doc.year,
|
||||
seasons: doc.seasons,
|
||||
});
|
||||
});
|
||||
|
||||
return promises;
|
||||
|
||||
};
|
||||
|
||||
const laterSeasons = async () =>{
|
||||
|
||||
let options = { parse: true }
|
||||
const data = await homgot(`${BASE_JIKAN}season/later`, options);
|
||||
let body = data.anime;
|
||||
const promises = []
|
||||
|
||||
body.map(doc =>{
|
||||
|
||||
promises.push({
|
||||
malid: doc.mal_id,
|
||||
title: doc.title,
|
||||
image: doc.image_url
|
||||
});
|
||||
});
|
||||
|
||||
return promises;
|
||||
|
||||
};
|
||||
|
||||
const getLastEpisodes = async () =>{
|
||||
|
||||
let options = { parse: true }
|
||||
const data = await homgot(`${BASE_ANIMEFLV_JELU}LatestEpisodesAdded`, options);
|
||||
let body = data.episodes;
|
||||
const promises = []
|
||||
|
||||
body.map(doc => {
|
||||
|
||||
promises.push(helper().then(async () => ({
|
||||
id: doc.id,
|
||||
title: doc.title,
|
||||
image: doc.poster,
|
||||
episode: doc.episode,
|
||||
servers: await transformUrlServer(JSON.parse(JSON.stringify(doc.servers)))
|
||||
})));
|
||||
|
||||
});
|
||||
|
||||
return Promise.all(promises);
|
||||
|
||||
};
|
||||
|
||||
const getSpecials = async (type, subType, page) =>{
|
||||
|
||||
let options = { parse: true }
|
||||
const data = await homgot(`${BASE_ANIMEFLV_JELU}${type.url}/${subType}/${page}`, options);
|
||||
let body = data[type.prop];
|
||||
const promises = []
|
||||
|
||||
body.map(doc =>{
|
||||
|
||||
promises.push({
|
||||
id: doc.id,
|
||||
title: doc.title,
|
||||
type: doc.type,
|
||||
banner: doc.banner,
|
||||
image: doc.poster,
|
||||
synopsis: doc.synopsis,
|
||||
status: doc.debut,
|
||||
rate: doc.rating,
|
||||
genres: doc.genres.map(x => x),
|
||||
episodes: doc.episodes.map(x => x)
|
||||
});
|
||||
});
|
||||
|
||||
return promises;
|
||||
|
||||
};
|
||||
|
||||
const getMoreInfo = async (title) =>{
|
||||
|
||||
const promises = []
|
||||
let animeTitle = ''
|
||||
let animeId = ''
|
||||
let animeType = ''
|
||||
let animeIndex = ''
|
||||
|
||||
let seriesTitle
|
||||
let position
|
||||
|
||||
const titles = [
|
||||
{ animeflv: 'Kaguya-sama wa Kokurasetai: Tensai-tachi no Renai Zunousen 2nd Season', myanimelist: 'Kaguya-sama wa Kokurasetai?: Tensai-tachi no Renai Zunousen', alternative: 'Kaguya-sama wa Kokurasetai'},
|
||||
{ animeflv: 'Naruto Shippuden', myanimelist: 'Naruto: Shippuuden' },
|
||||
{ animeflv: 'Rock Lee no Seishun Full-Power Ninden', myanimelist: 'Naruto SD: Rock Lee no Seishun Full-Power Ninden' }
|
||||
];
|
||||
|
||||
for (let name in titles) {
|
||||
if (title === titles[name].animeflv || title === titles[name].myanimelist || title === titles[name].alternative) {
|
||||
seriesTitle = titles[name].animeflv
|
||||
position = name
|
||||
}
|
||||
}
|
||||
|
||||
if (seriesTitle === undefined) {
|
||||
seriesTitle = title
|
||||
}
|
||||
|
||||
await getAllAnimes().then(animes => {
|
||||
|
||||
for (const i in animes) {
|
||||
if (animes[i].title.split('\t')[0] === seriesTitle.split('\t')[0] || animes[i].title === `${seriesTitle} (TV)`) {
|
||||
if (animes[i].title.includes('(TV)', 0)) { animeTitle = animes[i].title.split('\t')[0].replace(' (TV)', '') }
|
||||
else { animeTitle = animes[i].title.split('\t')[0] }
|
||||
animeId = animes[i].id
|
||||
animeIndex = animes[i].index
|
||||
animeType = animes[i].type.toLowerCase()
|
||||
|
||||
if (position !== undefined) {
|
||||
seriesTitle = titles[position].myanimelist
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
try{
|
||||
|
||||
if (animeType === 'tv') {
|
||||
promises.push(await animeflvInfo(animeId, animeIndex).then(async extra => ({
|
||||
title: animeTitle || null,
|
||||
poster: await imageUrlToBase64(extra.animeExtraInfo[0].poster) || null,
|
||||
synopsis: extra.animeExtraInfo[0].synopsis || null,
|
||||
status: extra.animeExtraInfo[0].debut || null,
|
||||
type: extra.animeExtraInfo[0].type || null,
|
||||
rating: extra.animeExtraInfo[0].rating || null,
|
||||
genres: extra.genres || null,
|
||||
episodes: extra.listByEps || null,
|
||||
moreInfo: await animeExtraInfo(seriesTitle).then(info =>{
|
||||
return info || null
|
||||
}),
|
||||
promo: await getAnimeVideoPromo(seriesTitle).then(promo =>{
|
||||
return promo || null
|
||||
}),
|
||||
characters: await getAnimeCharacters(seriesTitle).then(characters =>{
|
||||
return characters || null
|
||||
})
|
||||
})));
|
||||
} else {
|
||||
promises.push(await animeflvInfo(animeId).then(async extra => ({
|
||||
title: animeTitle || null,
|
||||
poster: await imageUrlToBase64(extra.animeExtraInfo[0].poster) || null,
|
||||
synopsis: extra.animeExtraInfo[0].synopsis || null,
|
||||
status: extra.animeExtraInfo[0].debut || null,
|
||||
type: extra.animeExtraInfo[0].type || null,
|
||||
rating: extra.animeExtraInfo[0].rating || null,
|
||||
genres: extra.genres || null,
|
||||
episodes: extra.listByEps || null,
|
||||
})));
|
||||
}
|
||||
|
||||
}catch(err){
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
return promises;
|
||||
|
||||
};
|
||||
|
||||
const getAnimeServers = async (id) => {
|
||||
|
||||
let options = { parse: true }
|
||||
const data = await homgot(`${BASE_ANIMEFLV_JELU}GetAnimeServers/${id}`, options);
|
||||
let body = data.servers;
|
||||
|
||||
return await transformUrlServer(body);
|
||||
|
||||
};
|
||||
|
||||
const search = async (title) =>{ return await searchAnime(title); };
|
||||
|
||||
const getImages = async (query) => {
|
||||
|
||||
let options = { parse: true }
|
||||
const data = await homgot(`${BASE_QWANT}count=${query.count}&q=${query.title}&t=${query.type}&safesearch=${query.safesearch}&locale=${query.country}&uiv=4`, options);
|
||||
const body = data.data.result.items;
|
||||
const promises = []
|
||||
|
||||
body.map(doc =>{
|
||||
|
||||
promises.push({
|
||||
type: doc.thumb_type,
|
||||
thumbnail: `https:${doc.thumbnail}`,
|
||||
fullsize: `https:${doc.media_fullsize}`
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
return promises;
|
||||
|
||||
};
|
||||
|
||||
const getYoutubeVideos = async (channelId) => {
|
||||
|
||||
let options = { parse: true }
|
||||
const data = await homgot(`${BASE_YOUTUBE}${channelId.id}&part=${channelId.part}&order=${channelId.order}&maxResults=${channelId.maxResults}`, options);
|
||||
const body = data[channelId.prop];
|
||||
const promises = []
|
||||
|
||||
body.map(doc =>{
|
||||
|
||||
promises.push({
|
||||
title: doc.snippet.title,
|
||||
videoId: doc.id.videoId,
|
||||
thumbDefault: doc.snippet.thumbnails.default.url,
|
||||
thumbMedium: doc.snippet.thumbnails.medium.url,
|
||||
thumbHigh: doc.snippet.thumbnails.high.url
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
return promises;
|
||||
|
||||
};
|
||||
|
||||
const getRadioStations = async () => {
|
||||
return require('../assets/radiostations.json');
|
||||
}
|
||||
|
||||
const getOpAndEd = async (title) => {
|
||||
let data = await parserThemes.serie(title)
|
||||
return await structureThemes(data, true)
|
||||
};
|
||||
|
||||
const getThemesYear = async (year) => {
|
||||
let data = []
|
||||
|
||||
if (year === undefined) {
|
||||
return await parserThemes.allYears();
|
||||
} else {
|
||||
data = await parserThemes.year(year)
|
||||
return await structureThemes(data, false)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const getRandomTheme = async () => {
|
||||
|
||||
let promise = []
|
||||
let data = await parserThemes.random()
|
||||
let random = Math.round(Math.random()*(data.themes.length - 1));
|
||||
|
||||
promise.push({
|
||||
name: data.title,
|
||||
title: data.themes[random].name.split('"')[1] || null,
|
||||
link: data.themes[random].link
|
||||
})
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
const getArtist = async (id) => {
|
||||
|
||||
let data
|
||||
|
||||
if (id === undefined) {
|
||||
return await parserThemes.artists();
|
||||
} else {
|
||||
data = await parserThemes.artist(id)
|
||||
return await structureThemes(data, false)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const getAnimeGenres = async(genre, order, page) => {
|
||||
|
||||
let $
|
||||
let promises = []
|
||||
let options = { scrapy: true }
|
||||
|
||||
if (page !== undefined) {
|
||||
$ = await homgot(`${GENRES_URL}genre%5B%5D=${genre}&order=${order}&page=${page}`,options)
|
||||
} else {
|
||||
$ = await homgot(`${GENRES_URL}genre%5B%5D=${genre}&order=${order}`,options)
|
||||
}
|
||||
|
||||
|
||||
$('div.Container ul.ListAnimes li article').each((index , element) =>{
|
||||
const $element = $(element);
|
||||
const id = $element.find('div.Description a.Button').attr('href').slice(1);
|
||||
const title = $element.find('a h3').text();
|
||||
const poster = $element.find('a div.Image figure img').attr('src');
|
||||
const banner = poster.replace('covers' , 'banners').trim();
|
||||
const type = $element.find('div.Description p span.Type').text();
|
||||
const synopsis = $element.find('div.Description p').eq(1).text().trim();
|
||||
const rating = $element.find('div.Description p span.Vts').text();
|
||||
|
||||
promises.push(helper().then(async () => ({
|
||||
id: id || null,
|
||||
title: title || null,
|
||||
poster: await imageUrlToBase64(poster) || null,
|
||||
banner: banner || null,
|
||||
synopsis: synopsis || null,
|
||||
type: type || null,
|
||||
rating: rating || null
|
||||
})))
|
||||
|
||||
})
|
||||
|
||||
return Promise.all(promises);
|
||||
|
||||
};
|
||||
|
||||
const getAllThemes = async () => {
|
||||
let data = await parserThemes.all()
|
||||
return await structureThemes(data, false)
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
schedule,
|
||||
top,
|
||||
getAllAnimes,
|
||||
getAllDirectory,
|
||||
getAnitakume,
|
||||
getNews,
|
||||
season,
|
||||
allSeasons,
|
||||
laterSeasons,
|
||||
getLastEpisodes,
|
||||
getSpecials,
|
||||
getMoreInfo,
|
||||
getAnimeServers,
|
||||
search,
|
||||
getImages,
|
||||
getYoutubeVideos,
|
||||
getRadioStations,
|
||||
getOpAndEd,
|
||||
getThemesYear,
|
||||
getRandomTheme,
|
||||
getArtist,
|
||||
getAnimeGenres,
|
||||
getAllThemes
|
||||
};
|
@ -1,30 +0,0 @@
|
||||
const hooman = require('hooman');
|
||||
const { CookieJar } = require('tough-cookie');
|
||||
const cookieJar = new CookieJar();
|
||||
const cheerio = require('cheerio');
|
||||
|
||||
let response
|
||||
let data
|
||||
|
||||
const homgot = async (url, options) => {
|
||||
|
||||
response = await hooman.get(url, cookieJar);
|
||||
|
||||
if (options !== undefined) {
|
||||
if (options.scrapy) {
|
||||
data = await cheerio.load(response.body)
|
||||
}
|
||||
if (options.parse) {
|
||||
data = JSON.parse(response.body)
|
||||
}
|
||||
} else {
|
||||
data = response
|
||||
}
|
||||
|
||||
return data
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
homgot
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
const express = require('express');
|
||||
const routes = require('./routes/index');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
res.json({
|
||||
message: 'Aruppi API - 🎏',
|
||||
author: 'Jéluchu',
|
||||
version: '2.5.0',
|
||||
credits: 'The bitch loves APIs that offers data to Aruppi App',
|
||||
entries: [
|
||||
{
|
||||
'Schedule': '/api/v2/schedule/:day',
|
||||
'Top': '/api/v2/top/:type/:subtype/:page',
|
||||
'AllAnimes': '/api/v2/allAnimes',
|
||||
'Anitakume': '/api/v2/anitakume',
|
||||
'News': '/api/v2/news',
|
||||
'Season': '/api/v2/season/:year/:type',
|
||||
'All Seasons': '/api/v2/allSeasons',
|
||||
'All Directory': '/api/v2/allDirectory',
|
||||
'Genres': '/api/v2/getByGenres/:genre/:order/:page?',
|
||||
'Futures Seasons': '/api/v2/laterSeasons',
|
||||
'LastEpisodes': '/api/v2/lastEpisodes',
|
||||
'Movies': '/api/v2/movies/:type/:page',
|
||||
'Ovas': '/api/v2/ovas/:type/:page',
|
||||
'Specials': '/api/v2/specials/:type/:page',
|
||||
'Tv': '/api/v2/tv/:type/:page',
|
||||
'MoreInfo': '/api/v2/moreInfo/:title',
|
||||
'GetAnimeServers': '/api/v2/getAnimeServers/:id',
|
||||
'Search': '/api/v2/search/:title',
|
||||
'Images': '/api/v2/images/:query',
|
||||
'Videos': '/api/v2/videos/:channelId',
|
||||
'Radios': '/api/v2/radio',
|
||||
'All Themes': '/api/v2/allThemes',
|
||||
'Themes': '/api/v2/themes/:title',
|
||||
'Year Themes': '/api/v2/themesYear/:year?',
|
||||
'Random Theme': '/api/v2/randomTheme',
|
||||
'Artists Theme': '/api/v2/artists/:id?'
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
router.use('/', routes);
|
||||
|
||||
module.exports = router;
|
@ -1,500 +0,0 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const api = require('../api');
|
||||
|
||||
const { BASE_KUDASAI, BASE_PALOMITRON, BASE_RAMENPARADOS, BASE_CRUNCHYROLL } = require('../urls');
|
||||
|
||||
router.get('/schedule/:day' , (req, res) =>{
|
||||
|
||||
let day = {current: req.params.day}
|
||||
|
||||
api.schedule(day)
|
||||
.then(day =>{
|
||||
if (day.length > 0) {
|
||||
res.status(200).json({
|
||||
day
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/top/:type/:subtype/:page' , (req, res) =>{
|
||||
|
||||
let type = req.params.type;
|
||||
let subtype = req.params.subtype;
|
||||
let page = req.params.page;
|
||||
|
||||
api.top(type, subtype, page)
|
||||
.then(top =>{
|
||||
if (top.length > 0) {
|
||||
res.status(200).json({
|
||||
top
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/allAnimes' , (req, res) =>{
|
||||
|
||||
api.getAllAnimes()
|
||||
.then(animes =>{
|
||||
if (animes.length > 0) {
|
||||
res.status(200).json({
|
||||
animes
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/allDirectory' , (req, res) =>{
|
||||
|
||||
api.getAllDirectory()
|
||||
.then(directory =>{
|
||||
if (directory.length > 0) {
|
||||
res.status(200).json({
|
||||
directory
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/anitakume' , (req, res) =>{
|
||||
|
||||
api.getAnitakume()
|
||||
.then(podcast =>{
|
||||
if (podcast.length > 0) {
|
||||
res.status(200).json({
|
||||
podcast
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/news' , (req, res) =>{
|
||||
|
||||
let pagesRss = [
|
||||
{ url: BASE_KUDASAI, author: 'Kudasai', content: 'content_encoded' },
|
||||
{ url: BASE_PALOMITRON, author: 'Palomitron', content: 'description' },
|
||||
{ url: BASE_RAMENPARADOS, author: 'Ramen para dos', content: 'content' },
|
||||
{ url: BASE_CRUNCHYROLL, author: 'Crunchyroll', content: 'content_encoded' }
|
||||
];
|
||||
|
||||
api.getNews(pagesRss)
|
||||
.then(news =>{
|
||||
if (news.length > 0) {
|
||||
res.status(200).json({
|
||||
news
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/season/:year/:type' , (req, res) =>{
|
||||
|
||||
let year = req.params.year;
|
||||
let type = req.params.type;
|
||||
|
||||
api.season(year, type)
|
||||
.then(season =>{
|
||||
if (season.length > 0) {
|
||||
res.status(200).json({
|
||||
season
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/allSeasons' , (req, res) =>{
|
||||
|
||||
api.allSeasons()
|
||||
.then(archive =>{
|
||||
if (archive.length > 0) {
|
||||
res.status(200).json({
|
||||
archive
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/laterSeasons' , (req, res) =>{
|
||||
|
||||
api.laterSeasons()
|
||||
.then(future =>{
|
||||
if (future.length > 0) {
|
||||
res.status(200).json({
|
||||
future
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/lastEpisodes' , (req, res) =>{
|
||||
|
||||
api.getLastEpisodes()
|
||||
.then(episodes =>{
|
||||
if (episodes.length > 0) {
|
||||
res.status(200).json({
|
||||
episodes
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/movies/:type/:page' , (req, res) =>{
|
||||
|
||||
let type = {url: 'Movies', prop: 'movies'}
|
||||
let subType = req.params.type;
|
||||
let page = req.params.page;
|
||||
|
||||
api.getSpecials(type, subType, page)
|
||||
.then(movies =>{
|
||||
if (movies.length > 0) {
|
||||
res.status(200).json({
|
||||
movies
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/ovas/:type/:page' , (req, res) =>{
|
||||
|
||||
let type = {url: 'Ova', prop: 'ova'}
|
||||
let subType = req.params.type;
|
||||
let page = req.params.page;
|
||||
|
||||
api.getSpecials(type, subType, page)
|
||||
.then(ovas =>{
|
||||
if (ovas.length > 0) {
|
||||
res.status(200).json({
|
||||
ovas
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/specials/:type/:page' , (req, res) =>{
|
||||
|
||||
let type = {url: 'Special', prop: 'special'}
|
||||
let subType = req.params.type;
|
||||
let page = req.params.page;
|
||||
|
||||
api.getSpecials(type, subType, page)
|
||||
.then(specials =>{
|
||||
if (specials.length > 0) {
|
||||
res.status(200).json({
|
||||
specials
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/tv/:type/:page' , (req, res) =>{
|
||||
|
||||
let type = {url: 'Tv', prop: 'tv'}
|
||||
let subType = req.params.type;
|
||||
let page = req.params.page;
|
||||
|
||||
api.getSpecials(type, subType, page)
|
||||
.then(tv =>{
|
||||
if (tv.length > 0) {
|
||||
res.status(200).json({
|
||||
tv
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/moreInfo/:title' , (req, res) =>{
|
||||
|
||||
let title = req.params.title;
|
||||
|
||||
api.getMoreInfo(title)
|
||||
.then(info =>{
|
||||
if (info.length > 0) {
|
||||
res.status(200).json({
|
||||
info
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/getAnimeServers/:id([^/]+/[^/]+)' , (req, res) =>{
|
||||
|
||||
let id = req.params.id;
|
||||
|
||||
api.getAnimeServers(id)
|
||||
.then(servers =>{
|
||||
if (servers.length > 0) {
|
||||
res.status(200).json({
|
||||
servers
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/search/:title' , (req, res) =>{
|
||||
|
||||
let title = req.params.title;
|
||||
|
||||
api.search(title)
|
||||
.then(search =>{
|
||||
if (search.length > 0) {
|
||||
res.status(200).json({
|
||||
search
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
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)
|
||||
.then(images =>{
|
||||
if (images.length > 0) {
|
||||
res.status(200).json({
|
||||
images
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/videos/:channelId' , (req, res) =>{
|
||||
|
||||
let channelId = { id: req.params.channelId, part: 'snippet,id', order: 'date', maxResults: '50', prop: 'items' };
|
||||
|
||||
api.getYoutubeVideos(channelId)
|
||||
.then(videos =>{
|
||||
if (videos.length > 0) {
|
||||
res.status(200).json({
|
||||
videos
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/radio' , (req, res) =>{
|
||||
|
||||
api.getRadioStations()
|
||||
.then(stations =>{
|
||||
if (stations.length > 0) {
|
||||
res.status(200).json({
|
||||
stations
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/allThemes', (req, res) =>{
|
||||
|
||||
api.getAllThemes()
|
||||
.then(themes =>{
|
||||
if (themes.length > 0) {
|
||||
res.status(200).json({
|
||||
themes
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
router.get('/themes/:title' , (req, res) =>{
|
||||
|
||||
let title = req.params.title;
|
||||
|
||||
api.getOpAndEd(title)
|
||||
.then(themes =>{
|
||||
if (themes.length > 0) {
|
||||
res.status(200).json({
|
||||
themes
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/themesYear/:year?', (req, res) =>{
|
||||
|
||||
let year = req.params.year;
|
||||
let season = req.params.season
|
||||
|
||||
api.getThemesYear(year, season)
|
||||
.then(themes =>{
|
||||
if (themes.length > 0) {
|
||||
res.status(200).json({
|
||||
themes
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/randomTheme', (req, res) =>{
|
||||
|
||||
api.getRandomTheme()
|
||||
.then(random =>{
|
||||
if (random.length > 0) {
|
||||
res.status(200).json({
|
||||
random
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/artists/:id?', (req, res) =>{
|
||||
|
||||
let id = req.params.id;
|
||||
|
||||
api.getArtist(id)
|
||||
.then(artists =>{
|
||||
if (artists.length > 0) {
|
||||
res.status(200).json({
|
||||
artists
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
router.get('/getByGenres/:genre/:order/:page?' , (req , res) =>{
|
||||
let genre = req.params.genre;
|
||||
let order = req.params.order;
|
||||
let page = req.params.page;
|
||||
api.getAnimeGenres(genre, order , page)
|
||||
.then(animes =>{
|
||||
if (animes.length > 0) {
|
||||
res.status(200).json({
|
||||
animes
|
||||
});
|
||||
} else (
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell'})
|
||||
)
|
||||
}).catch((err) =>{
|
||||
console.error(err);
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
@ -1,18 +0,0 @@
|
||||
module.exports = {
|
||||
BASE_ARUPPI: 'https://aruppi.jeluchu.xyz/',
|
||||
BASE_ANIMEFLV: 'https://animeflv.net/',
|
||||
BASE_ANIMEFLV_JELU: 'https://aruppi.jeluchu.xyz/apis/animeflv/v1/',
|
||||
BASE_YOUTUBE: 'https://aruppi.jeluchu.xyz/apis/youtube/v3/search?channelId=',
|
||||
BASE_JIKAN: 'https://aruppi.jeluchu.xyz/apis/jikan/v3/',
|
||||
BASE_IVOOX: 'https://www.ivoox.com/podcast-anitakume_fg_f1660716_filtro_1.xml',
|
||||
BASE_KUDASAI: 'https://somoskudasai.com/feed/',
|
||||
BASE_PALOMITRON: 'https://elpalomitron.com/category/animemanga/feed/',
|
||||
BASE_RAMENPARADOS: 'https://ramenparados.com/category/noticias/anime/feed/',
|
||||
BASE_CRUNCHYROLL: 'https://www.crunchyroll.com/newsrss?lang=esES',
|
||||
SEARCH_URL: 'https://animeflv.net/browse?q=',
|
||||
GENRES_URL: 'https://animeflv.net/browse?',
|
||||
SEARCH_DIRECTORY: 'https://animeflv.net/browse?order=title&page=',
|
||||
BASE_EPISODE_IMG_URL: 'https://cdn.animeflv.net/screenshots/',
|
||||
BASE_QWANT: 'https://api.qwant.com/search/images?',
|
||||
REDDIT_ANIMETHEMES: 'https://reddit.com/r/AnimeThemes/wiki/'
|
||||
};
|
@ -1,37 +0,0 @@
|
||||
const express = require('express');
|
||||
const helmet = require('helmet');
|
||||
const cors = require('cors');
|
||||
const bodyParser = require('body-parser');
|
||||
|
||||
const middlewares = require('./middlewares/index').middleware;
|
||||
const api = require('./api');
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(helmet());
|
||||
app.use(cors());
|
||||
app.use(bodyParser.json());
|
||||
app.use(bodyParser.urlencoded({ extended: false }));
|
||||
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
res.redirect('/api/')
|
||||
});
|
||||
|
||||
app.get('/api/', (req, res) => {
|
||||
res.json({
|
||||
message: 'Tu~tu~ruuu! You have traveled to the API Black Hole'
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/api/v1', (req, res) => {
|
||||
res.json({
|
||||
message: 'Sorry, version v1 is deprecated, if you want to see content go to v2'
|
||||
});
|
||||
});
|
||||
|
||||
app.use('/api/v2', api);
|
||||
|
||||
app.use(middlewares);
|
||||
|
||||
module.exports = app;
|
@ -1,306 +0,0 @@
|
||||
[
|
||||
{
|
||||
"name": "Ghost Anime Radio",
|
||||
"url": "http://animeradio.su:8000/"
|
||||
},
|
||||
{
|
||||
"name": "Vocaloid Radio",
|
||||
"url": "http://curiosity.shoutca.st:8019/stream"
|
||||
},
|
||||
{
|
||||
"name": "NyanServer (J-Trance)",
|
||||
"url": "http://radio.nyan.pw/station/stream"
|
||||
},
|
||||
{
|
||||
"name": "Listen Radio (J-Pop)",
|
||||
"url": "https://listen.moe/stream"
|
||||
},
|
||||
{
|
||||
"name": "Listen Radio (K-Pop)",
|
||||
"url": "https://listen.moe/kpop/stream"
|
||||
},
|
||||
{
|
||||
"name": "Anison FM",
|
||||
"url": "http://pool.anison.fm:9000/AniSonFM(128)"
|
||||
},
|
||||
{
|
||||
"name": "Radio Nami",
|
||||
"url": "https://radionami.com/play_radio.m3u"
|
||||
},
|
||||
{
|
||||
"name": "R/a/dio",
|
||||
"url": "http://relay0.r-a-d.io/main.mp3"
|
||||
},
|
||||
{
|
||||
"name": "Chiru.no",
|
||||
"url": "http://chiru.no:8000/stream.mp3"
|
||||
},
|
||||
{
|
||||
"name": "Vocaloid Radio VRX",
|
||||
"url": "http://vrx.piro.moe:8000/stream-192"
|
||||
},
|
||||
{
|
||||
"name": "Asian Wave Japan",
|
||||
"url": "https://listen1.myradio24.com/7934"
|
||||
},
|
||||
{
|
||||
"name": "Radio Vocaloid",
|
||||
"url": "http://142.4.217.133:9848/stream"
|
||||
},
|
||||
{
|
||||
"name": "Final Fantasy Radio",
|
||||
"url": "http://finalfantasystation.com:8000/stream"
|
||||
},
|
||||
{
|
||||
"name": "Shinsen Radio",
|
||||
"url": "http://shinsen-radio.org:8000/shinsen-radio.128.mp3"
|
||||
},
|
||||
{
|
||||
"name": "Anime Nexus",
|
||||
"url": "http://radio.animenexus.mx:8000/animenexus"
|
||||
},
|
||||
{
|
||||
"name": "Yggdrasil Radio",
|
||||
"url": "http://shirayuki.org:9100/"
|
||||
},
|
||||
{
|
||||
"name": "Eden Radio",
|
||||
"url": "http://edenofthewest.com:8080/eden.mp3"
|
||||
},
|
||||
{
|
||||
"name": "Gensokyo Radio",
|
||||
"url": "http://stream.gensokyoradio.net:8000/"
|
||||
},
|
||||
{
|
||||
"name": "Radio J-Hero",
|
||||
"url": "http://stm1.radiojhero.com:8008/;"
|
||||
},
|
||||
{
|
||||
"name": "Phate Radio",
|
||||
"url": "http://stream.phate.io/phatecc"
|
||||
},
|
||||
{
|
||||
"name": "91.8 The fan",
|
||||
"url": "http://198.27.80.154:8800/live"
|
||||
},
|
||||
{
|
||||
"name": "Radio AOI",
|
||||
"url": "http://radioaoi.pl/stream.m3u"
|
||||
},
|
||||
{
|
||||
"name": "Radio Touhou",
|
||||
"url": "http://www.touhouradio.com/touhouradio.m3u"
|
||||
},
|
||||
{
|
||||
"name": "Radio MultiAnime",
|
||||
"url": "http://67.20.61.70:8301"
|
||||
},
|
||||
{
|
||||
"name": "Radio Fan World Anime",
|
||||
"url": "http://stream.miradio.in:2199/tunein/fanworld.pls"
|
||||
},
|
||||
{
|
||||
"name": "Radio Japan-A",
|
||||
"url": "http://www.japanaradio.com/free/48kaacp.pls"
|
||||
},
|
||||
{
|
||||
"name": "Radio JPopsuki",
|
||||
"url": "http://jpopsuki.fm:2199/tunein/jpopsuki-stream.pls"
|
||||
},
|
||||
{
|
||||
"name": "Radio Hot Mix",
|
||||
"url": "http://hotmixradio-japan.ice.infomaniak.ch/hotmixradio-japan-128.mp3"
|
||||
},
|
||||
{
|
||||
"name": "Dada more Radio",
|
||||
"url": "http://dadamore2.ddo.jp:8000/listen.pls"
|
||||
},
|
||||
{
|
||||
"name": "Initial D World",
|
||||
"url": "http://69.163.186.124:9001/listen.aac"
|
||||
},
|
||||
{
|
||||
"name": "Radio Blast",
|
||||
"url": "http://192.99.150.31:8315/"
|
||||
},
|
||||
{
|
||||
"name": "Kibo FM",
|
||||
"url": "http://listen.kibo.fm:8000/kibofm"
|
||||
},
|
||||
{
|
||||
"name": "Power 945",
|
||||
"url": "http://38.96.148.28:8754/stream"
|
||||
},
|
||||
{
|
||||
"name": "Japan Fans",
|
||||
"url": "http://159.253.37.137:9984/listen.pls"
|
||||
},
|
||||
{
|
||||
"name": "Radio Aniterasu",
|
||||
"url": "http://aniterasu.com:8000/;?1442956789440.mp3"
|
||||
},
|
||||
{
|
||||
"name": "Big B Radio's J-Pop",
|
||||
"url": "http://64.71.79.181:6059/stream"
|
||||
},
|
||||
{
|
||||
"name": "Radio Blue Heron",
|
||||
"url": "http://cp3.digistream.info:8170"
|
||||
},
|
||||
{
|
||||
"name": "Friends Forever",
|
||||
"url": "http://23.29.71.154:8066/"
|
||||
},
|
||||
{
|
||||
"name": "Radio Greek Otaku",
|
||||
"url": "http://192.99.4.210:3684/stream"
|
||||
},
|
||||
{
|
||||
"name": "Radio UR",
|
||||
"url": "http://listen.ur-radio.de/anime.mp3"
|
||||
},
|
||||
{
|
||||
"name": "Radio Anime",
|
||||
"url": "http://stream.animeradio.de/animeradio.mp3"
|
||||
},
|
||||
{
|
||||
"name": "PowerPlay J-Pop",
|
||||
"url": "http://agnes.torontocast.com:8102"
|
||||
},
|
||||
{
|
||||
"name": "Radio Asia Dream",
|
||||
"url": "http://bluford.torontocast.com:8526"
|
||||
},
|
||||
{
|
||||
"name": "J-Pop Kawaii",
|
||||
"url": "http://bb31.sonixcast.com:20002/stream/1/"
|
||||
},
|
||||
{
|
||||
"name": "J-Club HipHop",
|
||||
"url": "http://agnes.torontocast.com:8051"
|
||||
},
|
||||
{
|
||||
"name": "J-Rock",
|
||||
"url": "http://cristina.torontocast.com:8057"
|
||||
},
|
||||
{
|
||||
"name": "J-Pop Sakura",
|
||||
"url": "http://bb31.sonixcast.com:20278/stream/1/"
|
||||
},
|
||||
{
|
||||
"name": "J-Pop Haru Sakura",
|
||||
"url": "http://184.75.223.178:8087/"
|
||||
},
|
||||
{
|
||||
"name": "Radio Ronin",
|
||||
"url": "https://s3.radio.co/sff133d65b/listen"
|
||||
},
|
||||
{
|
||||
"name": "Radio Shinka",
|
||||
"url": "http://5.9.65.9:8171/live"
|
||||
},
|
||||
{
|
||||
"name": "Radio Naihatsu",
|
||||
"url": "http://108.163.223.242:8305/"
|
||||
},
|
||||
{
|
||||
"name": "J-Pop Project",
|
||||
"url": "http://agnes.torontocast.com:8083/"
|
||||
},
|
||||
{
|
||||
"name": "J-idols Project",
|
||||
"url": "http://agnes.torontocast.com:8011/"
|
||||
},
|
||||
{
|
||||
"name": "Radio J1",
|
||||
"url": "https://jenny.torontocast.com:2000/stream/J1HITS"
|
||||
},
|
||||
{
|
||||
"name": "J1 XTRA",
|
||||
"url": "https://jenny.torontocast.com:2000/stream/J1XTRA"
|
||||
},
|
||||
{
|
||||
"name": "J1 GOLD",
|
||||
"url": "https://jenny.torontocast.com:2000/stream/J1GOLD"
|
||||
},
|
||||
{
|
||||
"name": "Animu FM",
|
||||
"url": "http://cast.animu.com.br:9021/stream"
|
||||
},
|
||||
{
|
||||
"name": "Radio Wave Anime",
|
||||
"url": "http://s04.radio-tochka.com:5470/mount"
|
||||
},
|
||||
{
|
||||
"name": "Radio Anime Stream",
|
||||
"url": "https://radioanime.radioca.st/stream"
|
||||
},
|
||||
{
|
||||
"name": "Radio Baka",
|
||||
"url": "http://144.217.203.184:8398/;"
|
||||
},
|
||||
{
|
||||
"name": "Radio Animecol",
|
||||
"url": "http://node-15.zeno.fm/6bfysacxc6quv"
|
||||
},
|
||||
{
|
||||
"name": "JMusic Anime",
|
||||
"url": "http://ample-zeno-24.radiojar.com/ddetxwuhkpeuv"
|
||||
},
|
||||
{
|
||||
"name": "Radio Japanese Music",
|
||||
"url": "http://live.japanesemusicid.com:8000/japanesemusic"
|
||||
},
|
||||
{
|
||||
"name": "Radio Japannext",
|
||||
"url": "https://perseus.shoutca.st/tunein/japannex.pls"
|
||||
},
|
||||
{
|
||||
"name": "Radio Akari",
|
||||
"url": "http://ample-zeno-22.radiojar.com/0t952vqukfeuv"
|
||||
},
|
||||
{
|
||||
"name": "Anime Universe",
|
||||
"url": "http://176.31.241.17:8147/;"
|
||||
},
|
||||
{
|
||||
"name": "Geek Radio Music",
|
||||
"url": "http://stream.zenolive.com/8d0xskxsxxquv"
|
||||
},
|
||||
{
|
||||
"name": "Radio Aniterasu",
|
||||
"url": "http://aniterasuradio.com:8000/;"
|
||||
},
|
||||
{
|
||||
"name": "Radio Akiba",
|
||||
"url": "http://stm24.srvstm.com:9526/;"
|
||||
},
|
||||
{
|
||||
"name": "Radio Caprice",
|
||||
"url": "http://79.111.119.111:8002/anime"
|
||||
},
|
||||
{
|
||||
"name": "Radio Caprice J-Rock",
|
||||
"url": "http://79.111.119.111:8002/jpop"
|
||||
},
|
||||
{
|
||||
"name": "Nihonara!",
|
||||
"url": "http://79.111.119.111:8002/jrock"
|
||||
},
|
||||
{
|
||||
"name": "Radio Opening",
|
||||
"url": "http://5.39.86.120:8000/nihonara_128.mp3"
|
||||
},
|
||||
{
|
||||
"name": "Radio Aewen K-J-Pop",
|
||||
"url": "http://stream.zeno.fm/tza2ayy47qruv"
|
||||
},
|
||||
{
|
||||
"name": "Radio Wkend",
|
||||
"url": "http://209.58.145.135:8031/stream"
|
||||
},
|
||||
{
|
||||
"name": "Nihongo FM",
|
||||
"url": "http://199.180.72.2:9004/stream"
|
||||
}
|
||||
]
|
@ -0,0 +1,782 @@
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
import { requestGot } from '../utils/requestCall';
|
||||
import {
|
||||
imageUrlToBase64,
|
||||
jkanimeInfo,
|
||||
monoschinosInfo,
|
||||
tioanimeInfo,
|
||||
videoServersJK,
|
||||
videoServersMonosChinos,
|
||||
videoServersTioAnime,
|
||||
} from '../utils/util';
|
||||
import { transformUrlServer } from '../utils/transformerUrl';
|
||||
import AnimeModel, { Anime as ModelA } from '../database/models/anime.model';
|
||||
import util from 'util';
|
||||
import { hashStringMd5 } from '../utils/util';
|
||||
import {
|
||||
animeExtraInfo,
|
||||
getAnimeVideoPromo,
|
||||
getAnimeCharacters,
|
||||
getRelatedAnimesMAL,
|
||||
} from '../utils/util';
|
||||
import urls from '../utils/urls';
|
||||
import { redisClient } from '../database/connection';
|
||||
|
||||
// @ts-ignore
|
||||
redisClient.get = util.promisify(redisClient.get);
|
||||
|
||||
/*
|
||||
AnimeController - a class to manage the schedule,
|
||||
top, all the animes, return the last episodes
|
||||
with async to return promises.
|
||||
*/
|
||||
|
||||
interface Schedule {
|
||||
title: string;
|
||||
mal_id: number;
|
||||
image_url: any;
|
||||
}
|
||||
|
||||
interface Anime {
|
||||
index: string;
|
||||
animeId: string;
|
||||
title: string;
|
||||
id: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface Top {
|
||||
rank: string;
|
||||
title: string;
|
||||
url: string;
|
||||
image_url: string;
|
||||
type: string;
|
||||
subtype: string;
|
||||
page: number;
|
||||
score: string;
|
||||
}
|
||||
|
||||
interface Episode {
|
||||
id: string;
|
||||
title: string;
|
||||
image: string;
|
||||
episode: number;
|
||||
servers: { id: string; url: string; direct: boolean };
|
||||
}
|
||||
|
||||
interface Movie {
|
||||
id: string;
|
||||
title: string;
|
||||
type: string;
|
||||
page: string;
|
||||
banner: string;
|
||||
image: string;
|
||||
synopsis: string;
|
||||
status: string;
|
||||
rate: string;
|
||||
genres: string[];
|
||||
episodes: object[];
|
||||
}
|
||||
|
||||
export default class AnimeController {
|
||||
async schedule(req: Request, res: Response, next: NextFunction) {
|
||||
const { day } = req.params;
|
||||
let info: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`schedule_${hashStringMd5(day)}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
info = await requestGot(`${urls.BASE_JIKAN}schedules?filter=${day}`, {
|
||||
parse: true,
|
||||
scrapy: false,
|
||||
});
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const animeList: Schedule[] = info.data.map((item: any) => ({
|
||||
title: item.titles.find((x: { type: string; }) => x.type === "Default").title,
|
||||
malid: item.mal_id,
|
||||
image: item.images.jpg.image_url,
|
||||
}));
|
||||
|
||||
if (animeList.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`schedule_${hashStringMd5(day)}`,
|
||||
JSON.stringify({ day: animeList }),
|
||||
);
|
||||
|
||||
/* After 6hrs expire the key. */
|
||||
|
||||
redisClient.expire(
|
||||
`schedule_${hashStringMd5(day)}`,
|
||||
+ 21600,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
day: animeList,
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async top(req: Request, res: Response, next: NextFunction) {
|
||||
const { type, subtype, page } = req.params;
|
||||
let info: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
let resultQueryRedis: any;
|
||||
|
||||
if (subtype) {
|
||||
resultQueryRedis = await redisClient.get(
|
||||
`top_${hashStringMd5(`${type}:${subtype}:${page}`)}`,
|
||||
);
|
||||
} else {
|
||||
resultQueryRedis = await redisClient.get(
|
||||
`top_${hashStringMd5(`${type}:${page}`)}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
if (subtype !== undefined) {
|
||||
info = await requestGot(
|
||||
`${urls.BASE_JIKAN}top/${type}?filter=${subtype}&page=${page}`,
|
||||
{ parse: true, scrapy: false },
|
||||
);
|
||||
} else {
|
||||
info = await requestGot(`${urls.BASE_JIKAN}top/${type}?page=${page}`, {
|
||||
parse: true,
|
||||
scrapy: false,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const top: Top[] = info.data.map((item: any, index: number) => ({
|
||||
// A little hacky way to fix null ranks
|
||||
rank: item.rank || index + 1 + (info.pagination.current_page-1)*info.pagination.items.per_page,
|
||||
title: item.titles.find((x: { type: string; }) => x.type === "Default").title,
|
||||
url: item.url,
|
||||
image_url: item.images.jpg.image_url,
|
||||
type: type,
|
||||
subtype: subtype,
|
||||
page: page,
|
||||
score: item.score,
|
||||
}));
|
||||
|
||||
if (top.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
if (subtype) {
|
||||
redisClient.set(
|
||||
`top_${hashStringMd5(`${type}:${subtype}:${page}`)}`,
|
||||
JSON.stringify({ top }),
|
||||
);
|
||||
} else {
|
||||
redisClient.set(
|
||||
`top_${hashStringMd5(`${type}:${page}`)}`,
|
||||
JSON.stringify({ top }),
|
||||
);
|
||||
}
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
if (subtype) {
|
||||
redisClient.expireat(
|
||||
`top_${hashStringMd5(`${type}:${subtype}:${page}`)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
} else {
|
||||
redisClient.expireat(
|
||||
`top_${hashStringMd5(`${type}:${page}`)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(200).json({ top });
|
||||
} else {
|
||||
return res.status(400).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getAllAnimes(req: Request, res: Response, next: NextFunction) {
|
||||
let data: any;
|
||||
|
||||
try {
|
||||
data = await requestGot(`${urls.BASE_ANIMEFLV}api/animes/list`, {
|
||||
parse: true,
|
||||
scrapy: false,
|
||||
spoof: true,
|
||||
});
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const animes: Anime[] = data.map((item: any) => ({
|
||||
index: item[0],
|
||||
animeId: item[3],
|
||||
title: item[1],
|
||||
id: item[2],
|
||||
type: item[4],
|
||||
}));
|
||||
|
||||
if (animes.length > 0) {
|
||||
res.status(200).send({ animes });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getLastEpisodes(req: Request, res: Response, next: NextFunction) {
|
||||
|
||||
let lastEpisodes;
|
||||
let episodes: Episode[] = [];
|
||||
let animeList: any[] = [];
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`lastEpisodes_${hashStringMd5('lastEpisodes')}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
lastEpisodes = await requestGot(`${urls.BASE_ARUPPI_MONOSCHINOS}lastest`, {
|
||||
scrapy: false,
|
||||
parse: true,
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
for (const anime of lastEpisodes) {
|
||||
animeList.push({
|
||||
id: `ver/${anime.id}`,
|
||||
title: anime.title,
|
||||
image: anime.image,
|
||||
episode: anime.no,
|
||||
});
|
||||
}
|
||||
|
||||
for (const anime of animeList) {
|
||||
episodes.push({
|
||||
id: anime.id,
|
||||
title: anime.title,
|
||||
image: await imageUrlToBase64(anime.image),
|
||||
episode: anime.episode,
|
||||
servers: await videoServersMonosChinos(anime.id),
|
||||
});
|
||||
}
|
||||
|
||||
if (episodes.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`lastEpisodes_${hashStringMd5('lastEpisodes')}`,
|
||||
JSON.stringify({ episodes }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`lastEpisodes_${hashStringMd5('lastEpisodes')}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 1800,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
episodes,
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getContentTv(req: Request, res: Response, next: NextFunction) {
|
||||
const { type, page } = req.params;
|
||||
const url = 'tv';
|
||||
let data: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`contentTv_${hashStringMd5(`${type}:${page}`)}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
data = await requestGot(
|
||||
`${urls.BASE_ANIMEFLV_JELU}${
|
||||
url.charAt(0).toUpperCase() + url.slice(1)
|
||||
}/${type}/${page}`,
|
||||
{
|
||||
parse: true,
|
||||
scrapy: false,
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const animes: Movie[] = data[url].map((item: any) => {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
type: url,
|
||||
page: page,
|
||||
banner: item.banner,
|
||||
image: item.poster,
|
||||
synopsis: item.synopsis,
|
||||
status: item.debut,
|
||||
rate: item.rating,
|
||||
genres: item.genres.map((genre: any) => genre),
|
||||
episodes: item.episodes.map((episode: any) => episode),
|
||||
};
|
||||
});
|
||||
|
||||
if (animes.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`contentTv_${hashStringMd5(`${type}:${page}`)}`,
|
||||
JSON.stringify({ animes }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`contentTv_${hashStringMd5(`${type}:${page}`)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
animes,
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getContentSpecial(req: Request, res: Response, next: NextFunction) {
|
||||
const { type, page } = req.params;
|
||||
const url = 'special';
|
||||
let data: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`contentSpecial_${hashStringMd5(`${type}:${page}`)}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
data = await requestGot(
|
||||
`${urls.BASE_ANIMEFLV_JELU}${
|
||||
url.charAt(0).toUpperCase() + url.slice(1)
|
||||
}/${type}/${page}`,
|
||||
{
|
||||
parse: true,
|
||||
scrapy: false,
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const animes: Movie[] = data[url].map((item: any) => {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
type: url,
|
||||
page: page,
|
||||
banner: item.banner,
|
||||
image: item.poster,
|
||||
synopsis: item.synopsis,
|
||||
status: item.debut,
|
||||
rate: item.rating,
|
||||
genres: item.genres.map((genre: any) => genre),
|
||||
episodes: item.episodes.map((episode: any) => episode),
|
||||
};
|
||||
});
|
||||
|
||||
if (animes.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`contentSpecial_${hashStringMd5(`${type}:${page}`)}`,
|
||||
JSON.stringify({ animes }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`contentSpecial_${hashStringMd5(`${type}:${page}`)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
animes,
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getContentOva(req: Request, res: Response, next: NextFunction) {
|
||||
const { type, page } = req.params;
|
||||
const url = 'ova';
|
||||
let data: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`contentOva_${hashStringMd5(`${type}:${page}`)}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
data = await requestGot(
|
||||
`${urls.BASE_ANIMEFLV_JELU}${
|
||||
url.charAt(0).toUpperCase() + url.slice(1)
|
||||
}/${type}/${page}`,
|
||||
{
|
||||
parse: true,
|
||||
scrapy: false,
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const animes: Movie[] = data[url].map((item: any) => {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
type: url,
|
||||
page: page,
|
||||
banner: item.banner,
|
||||
image: item.poster,
|
||||
synopsis: item.synopsis,
|
||||
status: item.debut,
|
||||
rate: item.rating,
|
||||
genres: item.genres.map((genre: any) => genre),
|
||||
episodes: item.episodes.map((episode: any) => episode),
|
||||
};
|
||||
});
|
||||
|
||||
if (animes.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`contentOva_${hashStringMd5(`${type}:${page}`)}`,
|
||||
JSON.stringify({ animes }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`contentOva_${hashStringMd5(`${type}:${page}`)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
animes,
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getContentMovie(req: Request, res: Response, next: NextFunction) {
|
||||
const { type, page } = req.params;
|
||||
const url = 'movies';
|
||||
let data: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`contentMovie_${hashStringMd5(`${type}:${page}`)}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
data = await requestGot(
|
||||
`${urls.BASE_ANIMEFLV_JELU}${
|
||||
url.charAt(0).toUpperCase() + url.slice(1)
|
||||
}/${type}/${page}`,
|
||||
{
|
||||
parse: true,
|
||||
scrapy: false,
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const animes: Movie[] = data[url].map((item: any) => {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
type: url,
|
||||
page: page,
|
||||
banner: item.banner,
|
||||
image: item.poster,
|
||||
synopsis: item.synopsis,
|
||||
status: item.debut,
|
||||
rate: item.rating,
|
||||
genres: item.genres.map((genre: any) => genre),
|
||||
episodes: item.episodes.map((episode: any) => episode),
|
||||
};
|
||||
});
|
||||
|
||||
if (animes.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`contentMovie_${hashStringMd5(`${type}:${page}`)}`,
|
||||
JSON.stringify({ animes }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`contentMovie_${hashStringMd5(`${type}:${page}`)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
animes,
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getEpisodes(req: Request, res: Response, next: NextFunction) {
|
||||
const { title } = req.params;
|
||||
let searchAnime: ModelA | null;
|
||||
let episodes: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`episodes_${hashStringMd5(title)}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
searchAnime = await AnimeModel.findOne({
|
||||
$or: [{ title: { $eq: title } }, { title: { $eq: `${title} (TV)` } }],
|
||||
});
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
switch (searchAnime?.source) {
|
||||
case 'jkanime':
|
||||
episodes = await jkanimeInfo(searchAnime?.id, searchAnime?.mal_id);
|
||||
break;
|
||||
case 'monoschinos':
|
||||
episodes = await monoschinosInfo(searchAnime?.id, searchAnime?.mal_id);
|
||||
break;
|
||||
case 'tioanime':
|
||||
episodes = await tioanimeInfo(searchAnime?.id, searchAnime?.mal_id);
|
||||
break;
|
||||
default:
|
||||
episodes = undefined;
|
||||
break;
|
||||
}
|
||||
|
||||
if (episodes) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`episodes_${hashStringMd5(title)}`,
|
||||
JSON.stringify({ episodes }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`episodes_${hashStringMd5(title)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({ episodes });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getServers(req: Request, res: Response, next: NextFunction) {
|
||||
const { id } = req.params;
|
||||
let data: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`servers_${hashStringMd5(id)}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
let indicator = false;
|
||||
|
||||
if (id.split('/')[0] === 'ver' && !indicator) {
|
||||
data = await videoServersTioAnime(id);
|
||||
|
||||
if (!data.name) {
|
||||
indicator = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (id.split('/')[0] === 'ver' && !indicator) {
|
||||
data = await videoServersMonosChinos(id);
|
||||
|
||||
if (!data.name) {
|
||||
console.log(data.name);
|
||||
indicator = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!indicator) {
|
||||
data = undefined;
|
||||
|
||||
indicator = true;
|
||||
|
||||
/*
|
||||
This part is just for handling the error
|
||||
if the two above doesn't complete the operation
|
||||
does not make sense to have the getServers from
|
||||
JKAnime.
|
||||
*/
|
||||
}
|
||||
|
||||
if (data) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`servers_${hashStringMd5(id)}`,
|
||||
JSON.stringify({ servers: data }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`servers_${hashStringMd5(id)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({ servers: data });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
}
|
||||
|
||||
async getRandomAnime(req: Request, res: Response, next: NextFunction) {
|
||||
let animeQuery: ModelA[] | null;
|
||||
let animeResult: any;
|
||||
|
||||
try {
|
||||
animeQuery = await AnimeModel.aggregate([{ $sample: { size: 1 } }]);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
animeResult = {
|
||||
title: animeQuery[0].title || null,
|
||||
poster: animeQuery[0].poster || null,
|
||||
synopsis: animeQuery[0].description || null,
|
||||
type: animeQuery[0].type || null,
|
||||
rating: animeQuery[0].score || null,
|
||||
genres: animeQuery[0].genres || null,
|
||||
moreInfo: [await animeExtraInfo(animeQuery[0].mal_id)],
|
||||
promo: await getAnimeVideoPromo(animeQuery[0].mal_id),
|
||||
characters: await getAnimeCharacters(animeQuery[0].mal_id),
|
||||
related: await getRelatedAnimesMAL(animeQuery[0].mal_id),
|
||||
};
|
||||
|
||||
if (animeResult) {
|
||||
res.set('Cache-Control', 'no-store');
|
||||
res.status(200).json(animeResult);
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,478 @@
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
import { requestGot } from '../utils/requestCall';
|
||||
import AnimeModel, { Anime } from '../database/models/anime.model';
|
||||
import util from 'util';
|
||||
import { hashStringMd5 } from '../utils/util';
|
||||
import {
|
||||
animeExtraInfo,
|
||||
getAnimeVideoPromo,
|
||||
getAnimeCharacters,
|
||||
getRelatedAnimesMAL,
|
||||
} from '../utils/util';
|
||||
import urls from '../utils/urls';
|
||||
import { redisClient } from '../database/connection';
|
||||
|
||||
// @ts-ignore
|
||||
redisClient.get = util.promisify(redisClient.get);
|
||||
|
||||
/*
|
||||
DirectoryController - async functions controlling the directory
|
||||
in the database of MongoDB, functions like getAllDirectory from the DB
|
||||
other functions with realation to the directory, like the season and stuff.
|
||||
*/
|
||||
|
||||
interface TypeAnime {
|
||||
title: string;
|
||||
image: string;
|
||||
genres: string[];
|
||||
}
|
||||
|
||||
interface Season {
|
||||
title: string;
|
||||
image: string;
|
||||
malink: string;
|
||||
}
|
||||
|
||||
interface Archive {
|
||||
year: string;
|
||||
seasons: string[];
|
||||
}
|
||||
|
||||
export default class DirectoryController {
|
||||
async getAllDirectory(req: Request, res: Response, next: NextFunction) {
|
||||
const { genres } = req.params;
|
||||
|
||||
try {
|
||||
if (genres === 'sfw') {
|
||||
await AnimeModel.find(
|
||||
{
|
||||
genres: { $nin: ['ecchi', 'Ecchi'] },
|
||||
},
|
||||
(err: any, docs: Anime[]) => {
|
||||
let directory: any[] = [];
|
||||
|
||||
for (const item of docs) {
|
||||
directory.push({
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
mal_id: item.mal_id,
|
||||
poster: item.poster,
|
||||
type: item.type,
|
||||
genres: item.genres,
|
||||
score: item.score,
|
||||
source: item.source,
|
||||
description: item.description,
|
||||
});
|
||||
}
|
||||
|
||||
if (directory.length > 0) {
|
||||
res.status(200).json({ directory });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
await AnimeModel.find((err: any, docs: Anime[]) => {
|
||||
let directory: any[] = [];
|
||||
|
||||
for (const item of docs) {
|
||||
directory.push({
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
mal_id: item.mal_id,
|
||||
poster: item.poster,
|
||||
type: item.type,
|
||||
genres: item.genres,
|
||||
score: item.score,
|
||||
source: item.source,
|
||||
description: item.description,
|
||||
});
|
||||
}
|
||||
|
||||
if (directory.length > 0) {
|
||||
res.status(200).json({ directory });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
}
|
||||
|
||||
async getSeason(req: Request, res: Response, next: NextFunction) {
|
||||
const { year, type } = req.params;
|
||||
let info: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`season_${hashStringMd5(`${year}:${type}`)}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
info = await requestGot(`${urls.BASE_JIKAN}seasons/${year}/${type}`, {
|
||||
scrapy: false,
|
||||
parse: true,
|
||||
});
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const season: TypeAnime[] = info.data.map((item: any) => {
|
||||
return {
|
||||
title: item.titles.find((x: { type: string; }) => x.type === "Default").title,
|
||||
image: item.images.jpg.image_url,
|
||||
genres: item.genres.map((genre: any) => genre.name),
|
||||
};
|
||||
});
|
||||
|
||||
if (season.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`season_${hashStringMd5(`${year}:${type}`)}`,
|
||||
JSON.stringify({ season }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`season_${hashStringMd5(`${year}:${type}`)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
season,
|
||||
});
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async allSeasons(req: Request, res: Response, next: NextFunction) {
|
||||
let info: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`allSeasons_${hashStringMd5('allSeasons')}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
info = await requestGot(`${urls.BASE_JIKAN}seasons`, {
|
||||
parse: true,
|
||||
scrapy: false,
|
||||
});
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const archive: Archive[] = info.data.map((item: any) => {
|
||||
return {
|
||||
year: item.year,
|
||||
seasons: item.seasons,
|
||||
};
|
||||
});
|
||||
|
||||
if (archive.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`allSeasons_${hashStringMd5('allSeasons')}`,
|
||||
JSON.stringify({ archive }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`allSeasons_${hashStringMd5('allSeasons')}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({ archive });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async laterSeasons(req: Request, res: Response, next: NextFunction) {
|
||||
let info: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`laterSeasons_${hashStringMd5('laterSeasons')}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
info = await requestGot(`${urls.BASE_JIKAN}seasons/upcoming`, {
|
||||
parse: true,
|
||||
scrapy: false,
|
||||
});
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const future: Season[] = info.data.map((item: any) => {
|
||||
return {
|
||||
title: item.titles.find((x: { type: string; }) => x.type === "Default").title,
|
||||
image: item.images.jpg.image_url,
|
||||
malink: item.url,
|
||||
};
|
||||
});
|
||||
|
||||
if (future.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`laterSeasons_${hashStringMd5('laterSeasons')}`,
|
||||
JSON.stringify({ future }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`laterSeasons_${hashStringMd5('laterSeasons')}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({ future });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getMoreInfo(req: Request, res: Response, next: NextFunction) {
|
||||
const { title } = req.params;
|
||||
let resultQuery: Anime | null;
|
||||
let resultAnime: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`moreInfo_${hashStringMd5(title)}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
resultQuery = await AnimeModel.findOne({
|
||||
$or: [{ title: { $eq: title } }, { title: { $eq: `${title} (TV)` } }],
|
||||
});
|
||||
|
||||
const extraInfo: any = await animeExtraInfo(resultQuery!.mal_id);
|
||||
|
||||
resultAnime = {
|
||||
//aruppi_key: hashStringMd5(title),
|
||||
title: resultQuery?.title,
|
||||
poster: resultQuery?.poster,
|
||||
synopsis: resultQuery?.description,
|
||||
status: !extraInfo.aired.to ? 'En emisión' : 'Finalizado',
|
||||
type: resultQuery?.type,
|
||||
rating: resultQuery?.score,
|
||||
genres: resultQuery?.genres,
|
||||
moreInfo: [extraInfo],
|
||||
promo: await getAnimeVideoPromo(resultQuery!.mal_id),
|
||||
characters: await getAnimeCharacters(resultQuery!.mal_id),
|
||||
related: await getRelatedAnimesMAL(resultQuery!.mal_id),
|
||||
};
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (resultAnime) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`moreInfo_${hashStringMd5(title)}`,
|
||||
JSON.stringify(resultAnime),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`moreInfo_${hashStringMd5(title)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json(resultAnime);
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async search(req: Request, res: Response, next: NextFunction) {
|
||||
const { title } = req.params;
|
||||
let results: Anime[] | null;
|
||||
|
||||
try {
|
||||
results = await AnimeModel.find({
|
||||
title: { $regex: new RegExp(title, 'i') },
|
||||
});
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const resultAnimes: any[] = results.map((item: any) => {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
type: item.type,
|
||||
image: item.poster,
|
||||
};
|
||||
});
|
||||
|
||||
if (resultAnimes.length > 0) {
|
||||
res.status(200).json({ search: resultAnimes });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getAnimeGenres(req: Request, res: Response, next: NextFunction) {
|
||||
const { genre, order, page } = req.params;
|
||||
let result: any;
|
||||
|
||||
const genres: any = {
|
||||
accion: 'Acción',
|
||||
'artes-marciales': 'Artes Marciales',
|
||||
aventura: 'Aventuras',
|
||||
carreras: 'Carreras',
|
||||
'ciencia-ficcion': 'Ciencia Ficción',
|
||||
comedia: 'Comedia',
|
||||
demencia: 'Demencia',
|
||||
demonios: 'Demonios',
|
||||
deportes: 'Deportes',
|
||||
drama: 'Drama',
|
||||
ecchi: 'Ecchi',
|
||||
escolares: 'Escolares',
|
||||
espacial: 'Espacial',
|
||||
fantasia: 'Fantasía',
|
||||
harem: 'Harem',
|
||||
historico: 'Historico',
|
||||
infantil: 'Infantil',
|
||||
josei: 'Josei',
|
||||
juegos: 'Juegos',
|
||||
magia: 'Magia',
|
||||
mecha: 'Mecha',
|
||||
militar: 'Militar',
|
||||
misterio: 'Misterio',
|
||||
musica: 'Música',
|
||||
parodia: 'Parodia',
|
||||
policia: 'Policía',
|
||||
psicologico: 'Psicológico',
|
||||
'recuentos-de-la-vida': 'Recuentos de la vida',
|
||||
romance: 'Romance',
|
||||
samurai: 'Samurai',
|
||||
seinen: 'Seinen',
|
||||
shoujo: 'Shoujo',
|
||||
shounen: 'Shounen',
|
||||
sobrenatural: 'Sobrenatural',
|
||||
superpoderes: 'Superpoderes',
|
||||
suspenso: 'Suspenso',
|
||||
terror: 'Terror',
|
||||
vampiros: 'Vampiros',
|
||||
yaoi: 'Yaoi',
|
||||
yuri: 'Yuri',
|
||||
};
|
||||
|
||||
try {
|
||||
if (genre === undefined && order === undefined && page === undefined) {
|
||||
result = await AnimeModel.aggregate([{ $sample: { size: 25 } }]);
|
||||
} else {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (genres.hasOwnProperty(genre)) {
|
||||
if (page !== undefined && parseInt(page) > 1) {
|
||||
if (order === 'asc') {
|
||||
result = await AnimeModel.find({ genres: genres[genre] })
|
||||
.limit(25)
|
||||
.skip(25 * parseInt(page))
|
||||
.sort({ title: 'ascending' });
|
||||
} else if (order === 'desc') {
|
||||
result = await AnimeModel.find({ genres: genres[genre] })
|
||||
.limit(25)
|
||||
.skip(25 * parseInt(page))
|
||||
.sort({ title: 'descending' });
|
||||
} else {
|
||||
result = await AnimeModel.find({ genres: genres[genre] })
|
||||
.limit(25)
|
||||
.skip(25 * parseInt(page));
|
||||
}
|
||||
} else {
|
||||
if (order === 'asc') {
|
||||
result = await AnimeModel.find({ genres: genres[genre] })
|
||||
.limit(25)
|
||||
.sort({ title: 'ascending' });
|
||||
} else if (order === 'desc') {
|
||||
result = await AnimeModel.find({ genres: genres[genre] })
|
||||
.limit(25)
|
||||
.sort({ title: 'descending' });
|
||||
} else {
|
||||
result = await AnimeModel.find({ genres: genres[genre] }).limit(
|
||||
25,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const animes: any[] = result.map((item: any) => {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.title.trim(),
|
||||
mention: genre,
|
||||
page: page,
|
||||
poster: item.poster,
|
||||
banner: item.banner,
|
||||
synopsis: item.synopsis,
|
||||
type: item.type,
|
||||
rating: item.rating,
|
||||
genre: item.genre,
|
||||
};
|
||||
});
|
||||
|
||||
if (animes.length > 0) {
|
||||
res.status(200).json({ animes });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,818 @@
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
import Parser from 'rss-parser';
|
||||
import urls from '../utils/urls';
|
||||
import { obtainPreviewNews } from '../utils/obtainPreviews';
|
||||
import { requestGot } from '../utils/requestCall';
|
||||
import RadioStationModel, {
|
||||
RadioStation,
|
||||
} from '../database/models/radiostation.model';
|
||||
import ThemeModel, { Theme } from '../database/models/theme.model';
|
||||
import ThemeParser from '../utils/animeTheme';
|
||||
import { structureThemes } from '../utils/util';
|
||||
import { getThemes } from '../utils/util';
|
||||
import WaifuModel, { Waifu } from '../database/models/waifu.model';
|
||||
import util from 'util';
|
||||
import { hashStringMd5 } from '../utils/util';
|
||||
import { redisClient } from '../database/connection';
|
||||
|
||||
// @ts-ignore
|
||||
redisClient.get = util.promisify(redisClient.get);
|
||||
|
||||
/*
|
||||
UtilsController - controller to parse the
|
||||
feed and get news, all with scraping and
|
||||
parsing RSS.
|
||||
*/
|
||||
|
||||
const themeParser = new ThemeParser();
|
||||
|
||||
type CustomFeed = {
|
||||
foo: string;
|
||||
};
|
||||
type CustomItem = {
|
||||
bar: number;
|
||||
itunes: { duration: string; image: string };
|
||||
'content:encoded': string;
|
||||
'content:encodedSnippet': string;
|
||||
};
|
||||
|
||||
const parser: Parser<CustomFeed, CustomItem> = new Parser({
|
||||
customFields: {
|
||||
feed: ['foo'],
|
||||
item: ['bar'],
|
||||
},
|
||||
});
|
||||
|
||||
interface News {
|
||||
title?: string;
|
||||
url?: string;
|
||||
author?: string;
|
||||
thumbnail?: string;
|
||||
content?: string;
|
||||
}
|
||||
|
||||
interface Podcast {
|
||||
title?: string;
|
||||
duration?: string;
|
||||
created?: Date | string;
|
||||
mp3?: string;
|
||||
}
|
||||
|
||||
interface rssPage {
|
||||
url: string;
|
||||
author: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export default class UtilsController {
|
||||
async getAnitakume(req: Request, res: Response, next: NextFunction) {
|
||||
let feed: CustomFeed & Parser.Output<CustomItem>;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`anitakume_${hashStringMd5('anitakume')}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
feed = await parser.parseURL(urls.BASE_IVOOX);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const podcast: Podcast[] = [];
|
||||
const monthNames = [
|
||||
'Enero',
|
||||
'Febrero',
|
||||
'Marzo',
|
||||
'Abril',
|
||||
'Mayo',
|
||||
'Junio',
|
||||
'Julio',
|
||||
'Agosto',
|
||||
'Septiembre',
|
||||
'Octubre',
|
||||
'Noviembre',
|
||||
'Diciembre',
|
||||
];
|
||||
|
||||
feed.items.forEach((item: any) => {
|
||||
const date: Date = new Date(item.pubDate!);
|
||||
|
||||
const formattedObject: Podcast = {
|
||||
title: item.title,
|
||||
duration: item.itunes.duration,
|
||||
created: `${date.getDate()} de ${
|
||||
monthNames[date.getMonth()]
|
||||
} de ${date.getFullYear()}`,
|
||||
mp3: item.enclosure?.url,
|
||||
};
|
||||
|
||||
podcast.push(formattedObject);
|
||||
});
|
||||
|
||||
if (podcast.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`anitakume_${hashStringMd5('anitakume')}`,
|
||||
JSON.stringify({ podcast }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`anitakume_${hashStringMd5('anitakume')}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({ podcast });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getNews(req: Request, res: Response, next: NextFunction) {
|
||||
const news: News[] = [];
|
||||
const pagesRss: rssPage[] = [
|
||||
{ url: urls.BASE_KUDASAI, author: 'Kudasai', content: 'content_encoded' },
|
||||
{
|
||||
url: urls.BASE_RAMENPARADOS,
|
||||
author: 'Ramen para dos',
|
||||
content: 'content',
|
||||
},
|
||||
{
|
||||
url: urls.BASE_CRUNCHYROLL,
|
||||
author: 'Crunchyroll',
|
||||
content: 'content_encoded',
|
||||
},
|
||||
];
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`news_${hashStringMd5('news')}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
for (const rssPage of pagesRss) {
|
||||
const feed = await parser.parseURL(rssPage.url);
|
||||
|
||||
feed.items.forEach((item: any) => {
|
||||
const formattedObject: News = {
|
||||
title: item.title,
|
||||
url: item.link,
|
||||
author: feed.title?.includes('Crunchyroll')
|
||||
? 'Crunchyroll'
|
||||
: feed.title,
|
||||
thumbnail: obtainPreviewNews(item['content:encoded']),
|
||||
content: item['content:encoded'],
|
||||
};
|
||||
|
||||
news.push(formattedObject);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (news.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`news_${hashStringMd5('news')}`,
|
||||
JSON.stringify({ news }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`news_${hashStringMd5('news')}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({ news });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getImages(req: Request, res: Response, next: NextFunction) {
|
||||
const { title } = req.params;
|
||||
let data: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`images_${hashStringMd5(title)}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
data = await requestGot(
|
||||
`${urls.BASE_QWANT}t=images&q=${encodeURIComponent(
|
||||
title,
|
||||
)}&count=51&locale=es_ES&safesearch=1`,
|
||||
{ scrapy: false, parse: true, spoof: true, },
|
||||
);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const results: any[] = data.data.result.items.map((item: any) => {
|
||||
return {
|
||||
type: item.thumb_type,
|
||||
thumbnail: `${item.thumbnail}`,
|
||||
fullsize: `${item.media_fullsize}`,
|
||||
};
|
||||
});
|
||||
|
||||
if (results.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`images_${hashStringMd5(title)}`,
|
||||
JSON.stringify({ images: results }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`images_${hashStringMd5(title)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.set('Cache-Control', 'max-age=604800');
|
||||
res.status(200).json({ images: results });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getVideos(req: Request, res: Response, next: NextFunction) {
|
||||
const { channelId } = req.params;
|
||||
let data: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`videos_${hashStringMd5(channelId)}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
data = await requestGot(
|
||||
`${urls.BASE_YOUTUBE}${channelId}&part=snippet,id&order=date&maxResults=50`,
|
||||
{ scrapy: false, parse: true },
|
||||
);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const results: any[] = data.items.map((item: any) => {
|
||||
return {
|
||||
title: item.snippet.title,
|
||||
videoId: item.id.videoId,
|
||||
thumbDefault: item.snippet.thumbnails.default.url,
|
||||
thumbMedium: item.snippet.thumbnails.medium.url,
|
||||
thumbHigh: item.snippet.thumbnails.high.url,
|
||||
};
|
||||
});
|
||||
|
||||
if (results.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`videos_${hashStringMd5(channelId)}`,
|
||||
JSON.stringify({ videos: results }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`videos_${hashStringMd5(channelId)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({ videos: results });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getPlaylists(req: Request, res: Response, next: NextFunction) {
|
||||
|
||||
const { playlistId } = req.params;
|
||||
let data: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
|
||||
const resultQueryRedis: any = redisClient.get(
|
||||
`videos_${hashStringMd5(playlistId)}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
data = await requestGot(
|
||||
`${urls.BASE_YOUTUBE_PLAYLIST}${playlistId}`,
|
||||
{ scrapy: false, parse: true },
|
||||
);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const results: any[] = data.items.map((item: any) => {
|
||||
return {
|
||||
title: item.snippet.title,
|
||||
videoId: item.id.videoId,
|
||||
thumbDefault: item.snippet.thumbnails.default.url,
|
||||
thumbMedium: item.snippet.thumbnails.medium.url,
|
||||
thumbHigh: item.snippet.thumbnails.high.url,
|
||||
};
|
||||
});
|
||||
|
||||
if (results.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/!* Set the key in the redis cache. *!/
|
||||
|
||||
redisClient.set(
|
||||
`videos_${hashStringMd5(playlistId)}`,
|
||||
JSON.stringify({ videos: results }),
|
||||
);
|
||||
|
||||
/!* After 24hrs expire the key. *!/
|
||||
|
||||
redisClient.expireat(
|
||||
`videos_${hashStringMd5(playlistId)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({ videos: results });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getSectionVideos(req: Request, res: Response, next: NextFunction) {
|
||||
const { type } = req.params;
|
||||
let y1: any, y2: any, y3: any;
|
||||
let data: any;
|
||||
|
||||
try {
|
||||
if (type === 'learn') {
|
||||
data = await requestGot(
|
||||
`${urls.BASE_YOUTUBE}UCCyQwSS6m2mVB0-H2FOFJtw&part=snippet,id&order=date&maxResults=50`,
|
||||
{ parse: true, scrapy: false },
|
||||
);
|
||||
} else if (type === 'amv') {
|
||||
y1 = await requestGot(
|
||||
`${urls.BASE_YOUTUBE}UCkTFkshjAsLMKwhAe1uPC1A&part=snippet,id&order=date&maxResults=25`,
|
||||
{ parse: true, scrapy: false },
|
||||
);
|
||||
|
||||
y2 = await requestGot(
|
||||
`${urls.BASE_YOUTUBE}UC2cpvlLeowpqnR6bQofwNew&part=snippet,id&order=date&maxResults=25`,
|
||||
{ parse: true, scrapy: false },
|
||||
);
|
||||
} else if (type === 'produccer') {
|
||||
y1 = await requestGot(
|
||||
`${urls.BASE_YOUTUBE}UC-5MT-BUxTzkPTWMediyV0w&part=snippet,id&order=date&maxResults=25`,
|
||||
{ parse: true, scrapy: false },
|
||||
);
|
||||
|
||||
y2 = await requestGot(
|
||||
`${urls.BASE_YOUTUBE}UCwUeTOXP3DD9DIvHttowuSA&part=snippet,id&order=date&maxResults=25`,
|
||||
{ parse: true, scrapy: false },
|
||||
);
|
||||
|
||||
y3 = await requestGot(
|
||||
`${urls.BASE_YOUTUBE}UCA8Vj7nN8bzT3rsukD2ypUg&part=snippet,id&order=date&maxResults=25`,
|
||||
{ parse: true, scrapy: false },
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (data && !y1 && !y2 && !y3) {
|
||||
const results: any[] = data.items.map((item: any) => ({
|
||||
title: item.snippet.title,
|
||||
videoId: item.id.videoId,
|
||||
thumbDefault: item.snippet.thumbnails.default.url,
|
||||
thumbMedium: item.snippet.thumbnails.medium.url,
|
||||
thumbHigh: item.snippet.thumbnails.high.url,
|
||||
}));
|
||||
|
||||
res.status(200).json({ videos: results });
|
||||
} else if (!data && y1 && y2 && !y3) {
|
||||
const results: any[] = y1.items.concat(y2.items).map((item: any) => ({
|
||||
title: item.snippet.title,
|
||||
videoId: item.id.videoId,
|
||||
thumbDefault: item.snippet.thumbnails.default.url,
|
||||
thumbMedium: item.snippet.thumbnails.medium.url,
|
||||
thumbHigh: item.snippet.thumbnails.high.url,
|
||||
}));
|
||||
|
||||
res.status(200).json({ videos: results });
|
||||
} else if (!data && y1 && y2 && y3) {
|
||||
const results: any[] = y1.items
|
||||
.concat(y2.items.concat(y3.items))
|
||||
.map((item: any) => ({
|
||||
title: item.snippet.title,
|
||||
videoId: item.id.videoId,
|
||||
thumbDefault: item.snippet.thumbnails.default.url,
|
||||
thumbMedium: item.snippet.thumbnails.medium.url,
|
||||
thumbHigh: item.snippet.thumbnails.high.url,
|
||||
}));
|
||||
|
||||
res.status(200).json({ videos: results });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getRadioStations(req: Request, res: Response, next: NextFunction) {
|
||||
let data: RadioStation[];
|
||||
|
||||
try {
|
||||
data = await RadioStationModel.find();
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const results: any[] = data.map((item: RadioStation) => {
|
||||
return {
|
||||
name: item.name,
|
||||
url: item.url,
|
||||
};
|
||||
});
|
||||
|
||||
if (results.length > 0) {
|
||||
res.status(200).json({ stations: results });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getAllThemes(req: Request, res: Response, next: NextFunction) {
|
||||
let data: Theme[];
|
||||
|
||||
try {
|
||||
data = await ThemeModel.find();
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const results: any[] = data.map((item: Theme) => {
|
||||
return {
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
year: item.year,
|
||||
themes: item.themes,
|
||||
};
|
||||
});
|
||||
|
||||
if (results.length > 0) {
|
||||
res.status(200).json({ themes: results });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getOpAndEd(req: Request, res: Response, next: NextFunction) {
|
||||
const { title } = req.params;
|
||||
let themes: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
const resultQueryRedis: any = await redisClient.get(
|
||||
`oped_${hashStringMd5(title)}`,
|
||||
);
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
themes = await structureThemes(await themeParser.serie(title), true);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (themes) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
redisClient.set(
|
||||
`oped_${hashStringMd5(title)}`,
|
||||
JSON.stringify({ themes }),
|
||||
);
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
redisClient.expireat(
|
||||
`oped_${hashStringMd5(title)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
|
||||
res.status(200).json({ themes });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getThemesYear(req: Request, res: Response, next: NextFunction) {
|
||||
const { year } = req.params;
|
||||
let themes: any;
|
||||
let resultQueryRedis: any;
|
||||
|
||||
try {
|
||||
if (redisClient.connected) {
|
||||
if (year) {
|
||||
resultQueryRedis = await redisClient.get(
|
||||
`themesyear_${hashStringMd5(year)}`,
|
||||
);
|
||||
} else {
|
||||
resultQueryRedis = await redisClient.get(
|
||||
`themesyear_${hashStringMd5('allYear')}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (resultQueryRedis) {
|
||||
const resultRedis: any = JSON.parse(resultQueryRedis);
|
||||
|
||||
return res.status(200).json(resultRedis);
|
||||
}
|
||||
}
|
||||
|
||||
if (year === undefined) {
|
||||
themes = await themeParser.allYears();
|
||||
} else {
|
||||
themes = await structureThemes(await themeParser.year(year), false);
|
||||
}
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (themes.length > 0) {
|
||||
if (redisClient.connected) {
|
||||
/* Set the key in the redis cache. */
|
||||
|
||||
if (year) {
|
||||
redisClient.set(
|
||||
`themesyear_${hashStringMd5(year)}`,
|
||||
JSON.stringify({ themes }),
|
||||
);
|
||||
} else {
|
||||
redisClient.set(
|
||||
`themesyear_${hashStringMd5('allYear')}`,
|
||||
JSON.stringify({ themes }),
|
||||
);
|
||||
}
|
||||
|
||||
/* After 24hrs expire the key. */
|
||||
|
||||
if (year) {
|
||||
redisClient.expireat(
|
||||
`themesyear_${hashStringMd5(year)}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
} else {
|
||||
redisClient.expireat(
|
||||
`themesyear_${hashStringMd5('allYear')}`,
|
||||
parseInt(`${+new Date() / 1000}`, 10) + 7200,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
res.status(200).json({ themes });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async randomTheme(req: Request, res: Response, next: NextFunction) {
|
||||
let data: any;
|
||||
|
||||
try {
|
||||
data = await requestGot(`${urls.BASE_THEMEMOE}roulette`, {
|
||||
parse: true,
|
||||
scrapy: false,
|
||||
spoof: true,
|
||||
});
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const random: any[] = getThemes(data.themes);
|
||||
|
||||
if (random.length > 0) {
|
||||
res.set('Cache-Control', 'no-store');
|
||||
res.status(200).json({ random });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getArtist(req: Request, res: Response, next: NextFunction) {
|
||||
const { id } = req.params;
|
||||
let artists: any;
|
||||
|
||||
try {
|
||||
if (id === undefined) {
|
||||
artists = await themeParser.artists();
|
||||
} else {
|
||||
artists = await structureThemes(await themeParser.artist(id), false);
|
||||
}
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (artists.length > 0) {
|
||||
res.status(200).json({ artists });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getDestAnimePlatforms(req: Request, res: Response, next: NextFunction) {
|
||||
let data: any;
|
||||
|
||||
try {
|
||||
data = await requestGot(
|
||||
`${urls.BASE_ARUPPI}res/documents/animelegal/top.json`,
|
||||
{ parse: true, scrapy: false },
|
||||
);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const destPlatforms: any[] = data.map((item: any) => {
|
||||
return {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
logo: item.logo,
|
||||
link: item.link,
|
||||
};
|
||||
});
|
||||
|
||||
if (destPlatforms.length > 0) {
|
||||
res.status(200).json({ destPlatforms });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getPlatforms(req: Request, res: Response, next: NextFunction) {
|
||||
const { id } = req.params;
|
||||
let data: any;
|
||||
|
||||
try {
|
||||
if (id === undefined) {
|
||||
data = await requestGot(
|
||||
`${urls.BASE_ARUPPI}res/documents/animelegal/typeplatforms.json`,
|
||||
{ parse: true, scrapy: false },
|
||||
);
|
||||
} else if (
|
||||
id === 'producers' ||
|
||||
id === 'apps' ||
|
||||
id === 'publishers' ||
|
||||
'events'
|
||||
) {
|
||||
data = await requestGot(
|
||||
`${urls.BASE_ARUPPI}res/documents/animelegal/type/${id}.json`,
|
||||
{ parse: true, scrapy: false },
|
||||
);
|
||||
} else {
|
||||
data = await requestGot(
|
||||
`${urls.BASE_ARUPPI}res/documents/animelegal/type/${id}.json`,
|
||||
{ parse: true, scrapy: false },
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const platforms: any[] = data.map((item: any) => {
|
||||
if (id === undefined) {
|
||||
return {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
comming: item.comming || false,
|
||||
cover: item.cover,
|
||||
};
|
||||
} else if (
|
||||
id === 'producers' ||
|
||||
id === 'apps' ||
|
||||
id === 'publishers' ||
|
||||
'events'
|
||||
) {
|
||||
return {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
logo: item.logo,
|
||||
cover: item.cover,
|
||||
description: item.description,
|
||||
type: item.type,
|
||||
moreInfo: item.moreInfo,
|
||||
facebook: item.facebook,
|
||||
twitter: item.twitter,
|
||||
instagram: item.instagram,
|
||||
webInfo: item.webInfo,
|
||||
webpage: item.webpage,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
logo: item.logo,
|
||||
cover: item.cover,
|
||||
webpage: item.webpage,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
if (platforms.length > 0) {
|
||||
res.status(200).json({ platforms });
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
|
||||
async getWaifuRandom(req: Request, res: Response, next: NextFunction) {
|
||||
let waifuQuery: Waifu[] | null;
|
||||
let waifuResult: any;
|
||||
|
||||
try {
|
||||
waifuQuery = await WaifuModel.aggregate([{ $sample: { size: 1 } }]);
|
||||
} catch (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (waifuQuery.length > 0) {
|
||||
waifuResult = {
|
||||
id: waifuQuery[0].id,
|
||||
name: waifuQuery[0].name,
|
||||
weight: waifuQuery[0].weight,
|
||||
series: waifuQuery[0].series,
|
||||
height: waifuQuery[0].height,
|
||||
birthday: waifuQuery[0].birthday,
|
||||
likes: waifuQuery[0].likes,
|
||||
trash: waifuQuery[0].trash,
|
||||
blood_type: waifuQuery[0].blood_type,
|
||||
hip: waifuQuery[0].hip,
|
||||
bust: waifuQuery[0].bust,
|
||||
description: waifuQuery[0].description,
|
||||
display_picture: waifuQuery[0].display_picture,
|
||||
waist: waifuQuery[0].waist,
|
||||
};
|
||||
}
|
||||
|
||||
if (waifuResult) {
|
||||
res.set('Cache-Control', 'no-store');
|
||||
res.status(200).json(waifuResult);
|
||||
} else {
|
||||
res.status(500).json({ message: 'Aruppi lost in the shell' });
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
import mongoose from 'mongoose';
|
||||
import redis, { RedisClient } from 'redis';
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
// Configuring dotenv to read the variable from .env file
|
||||
dotenv.config();
|
||||
|
||||
/*
|
||||
Create the connection to the database
|
||||
of mongodb.
|
||||
*/
|
||||
|
||||
export const createConnectionMongo = (databaseObj: {
|
||||
port: string | undefined;
|
||||
host: string | undefined;
|
||||
}) => {
|
||||
mongoose.connect(
|
||||
`mongodb://${databaseObj.host}:${databaseObj.port}/anime-directory`,
|
||||
{
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true,
|
||||
},
|
||||
);
|
||||
|
||||
mongoose.connection.on('error', err => {
|
||||
console.log('err', err);
|
||||
});
|
||||
mongoose.connection.on('connected', (err, res) => {
|
||||
console.log('Database connected: mongoose.');
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Create the connection to the cache of
|
||||
redis, and exporting the redis client
|
||||
with the call of this file.
|
||||
*/
|
||||
|
||||
export const redisClient: RedisClient = redis.createClient({
|
||||
host: process.env.REDIS_HOST,
|
||||
port: parseInt(process.env.REDIS_PORT!),
|
||||
password: process.env.REDIS_PASSWORD,
|
||||
retry_strategy: function (options) {
|
||||
if (options.error && options.error.code === 'ECONNREFUSED') {
|
||||
// End reconnecting on a specific error and flush all commands with
|
||||
// a individual error
|
||||
return new Error('The server refused the connection');
|
||||
}
|
||||
if (options.total_retry_time > 1000 * 60 * 60) {
|
||||
// End reconnecting after a specific timeout and flush all commands
|
||||
// with a individual error
|
||||
return new Error('Retry time exhausted');
|
||||
}
|
||||
if (options.attempt > 10) {
|
||||
// End reconnecting with built in error
|
||||
return undefined;
|
||||
}
|
||||
// reconnect after
|
||||
return Math.min(options.attempt * 100, 3000);
|
||||
},
|
||||
});
|
||||
|
||||
redisClient.on('connect', () => {
|
||||
console.log('Redis connected: redis.');
|
||||
});
|
||||
|
||||
redisClient.on('error', function (err) {
|
||||
console.log('Redis error: ' + err);
|
||||
});
|
@ -0,0 +1,33 @@
|
||||
import { Document, model, Types, Schema } from 'mongoose';
|
||||
|
||||
/*
|
||||
This is the model for each anime
|
||||
of the directory, the anime model.
|
||||
*/
|
||||
|
||||
export interface Anime extends Document {
|
||||
id: string;
|
||||
title: string;
|
||||
mal_id: number;
|
||||
poster: string;
|
||||
type: string;
|
||||
genres: Types.Array<string>;
|
||||
score: string;
|
||||
source: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
// Schema for the anime
|
||||
const AnimeSchema: Schema = new Schema({
|
||||
id: { type: String },
|
||||
title: { type: String },
|
||||
mal_id: { type: Number },
|
||||
poster: { type: String },
|
||||
type: { type: String },
|
||||
genres: [{ type: String }],
|
||||
score: { type: String },
|
||||
source: { type: String },
|
||||
description: { type: String },
|
||||
});
|
||||
|
||||
export default model<Anime>('Anime', AnimeSchema);
|
@ -0,0 +1,19 @@
|
||||
import { Document, model, Types, Schema } from 'mongoose';
|
||||
|
||||
/*
|
||||
This is the model for each genre
|
||||
of the directory, the genre model.
|
||||
*/
|
||||
|
||||
export interface Genre extends Document {
|
||||
name: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
// Schema for the theme
|
||||
const GenreSchema: Schema = new Schema({
|
||||
name: { type: String },
|
||||
value: { type: String },
|
||||
});
|
||||
|
||||
export default model<Genre>('Genre', GenreSchema);
|
@ -0,0 +1,19 @@
|
||||
import { Document, model, Schema } from 'mongoose';
|
||||
|
||||
/*
|
||||
This is the model for each radiostation
|
||||
of the directory, the radiostation model.
|
||||
*/
|
||||
|
||||
export interface RadioStation extends Document {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
// Schema for the theme
|
||||
const RadioStationSchema: Schema = new Schema({
|
||||
name: { type: String },
|
||||
url: { type: String },
|
||||
});
|
||||
|
||||
export default model<RadioStation>('RadioStation', RadioStationSchema);
|
@ -0,0 +1,29 @@
|
||||
import { Document, model, Types, Schema } from 'mongoose';
|
||||
|
||||
/*
|
||||
This is the model for each theme
|
||||
of the directory, the theme model.
|
||||
*/
|
||||
|
||||
interface TInterface {
|
||||
title: string;
|
||||
video: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface Theme extends Document {
|
||||
id: string;
|
||||
title: string;
|
||||
year: string;
|
||||
themes: Types.Array<TInterface>;
|
||||
}
|
||||
|
||||
// Schema for the theme
|
||||
const ThemeSchema: Schema = new Schema({
|
||||
id: { type: String },
|
||||
title: { type: String },
|
||||
year: { type: String },
|
||||
themes: [{ type: Object }],
|
||||
});
|
||||
|
||||
export default model<Theme>('Theme', ThemeSchema);
|
@ -0,0 +1,43 @@
|
||||
import { Document, model, Schema } from 'mongoose';
|
||||
|
||||
/*
|
||||
This is the model for each anime
|
||||
of the directory, the anime model.
|
||||
*/
|
||||
|
||||
export interface Waifu extends Document {
|
||||
id: string;
|
||||
name: string;
|
||||
weight: string;
|
||||
series: object;
|
||||
height: string;
|
||||
birthday: string;
|
||||
likes: number;
|
||||
trash: number;
|
||||
blood_type: string;
|
||||
hip: string;
|
||||
bust: string;
|
||||
description: string;
|
||||
display_picture: string;
|
||||
waist: string;
|
||||
}
|
||||
|
||||
// Schema for the Waifu
|
||||
const WaifuSchema: Schema = new Schema({
|
||||
id: { type: String },
|
||||
name: { type: String },
|
||||
weight: { type: String },
|
||||
series: { type: Object },
|
||||
height: { type: String },
|
||||
birthday: { type: String },
|
||||
likes: { type: Number },
|
||||
trash: { type: Number },
|
||||
blood_type: { type: String },
|
||||
hip: { type: String },
|
||||
bust: { type: String },
|
||||
description: { type: String },
|
||||
display_picture: { type: String },
|
||||
waist: { type: String },
|
||||
});
|
||||
|
||||
export default model<Waifu>('Waifu', WaifuSchema);
|
@ -1,20 +0,0 @@
|
||||
const app = require('./app');
|
||||
const port = process.env.PORT || 5000;
|
||||
const addr = isNaN(port) ?
|
||||
'' :
|
||||
(process.env.ADDR || '0.0.0.0');
|
||||
|
||||
server = app.listen(port, addr, () => {
|
||||
/* eslint-disable no-console */
|
||||
console.log(`\n🚀 ... Listening: ${addr}${addr ? '\:' : 'unix://'}${port}`);
|
||||
/* eslint-enable no-console */
|
||||
});
|
||||
|
||||
function shutdown() {
|
||||
server.close(); // socket file is automatically removed here
|
||||
process.exit();
|
||||
}
|
||||
|
||||
process.on('SIGINT', shutdown);
|
||||
process.on('SIGQUIT', shutdown);
|
||||
process.on('SIGTERM', shutdown);
|
@ -1,12 +0,0 @@
|
||||
const compose = require('compose-middleware').compose;
|
||||
const {errorHandler , notFound , requestLoggerMiddleware} = require('./middlewares');
|
||||
|
||||
const middleware = compose([
|
||||
notFound,
|
||||
errorHandler,
|
||||
requestLoggerMiddleware
|
||||
]);
|
||||
|
||||
module.exports = {
|
||||
middleware
|
||||
};
|
@ -0,0 +1,48 @@
|
||||
import {
|
||||
Request,
|
||||
Response,
|
||||
NextFunction,
|
||||
ErrorRequestHandler,
|
||||
RequestHandler,
|
||||
} from 'express';
|
||||
|
||||
/*
|
||||
Error handler and notFound handler
|
||||
for all the API like a middleware with
|
||||
the function next of express.
|
||||
*/
|
||||
|
||||
export const errorHandler: ErrorRequestHandler = (
|
||||
err: any,
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction,
|
||||
) => {
|
||||
const statusCode = res.statusCode !== 200 ? res.statusCode : 500;
|
||||
res.status(statusCode).json({
|
||||
message: err.message,
|
||||
stack: process.env.NODE_ENV === 'production' ? '🥞' : err.stack,
|
||||
});
|
||||
};
|
||||
|
||||
export const notFound: any = (
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction,
|
||||
) => {
|
||||
res.status(404);
|
||||
const error = new Error(`🔍 - Not Found - ${req.originalUrl}`);
|
||||
next(error);
|
||||
};
|
||||
|
||||
// export const requestLoggerMiddleWare: RequestHandler = (req, res, next) => {
|
||||
// console.log(`${req.method} ${req.originalUrl}`);
|
||||
// const start: number = new Date().getTime();
|
||||
// res.on('finish', () => {
|
||||
// const elapsed: number = new Date().getTime() - start;
|
||||
// console.info(
|
||||
// `${req.method} ${req.originalUrl} ${req.statusCode} ${elapsed}ms`,
|
||||
// );
|
||||
// });
|
||||
// next();
|
||||
// };
|
@ -1,32 +0,0 @@
|
||||
const notFound = (req, res, next) => {
|
||||
res.status(404);
|
||||
const error = new Error(`🔍 - Not Found - ${req.originalUrl}`);
|
||||
next(error);
|
||||
};
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
const errorHandler = (err, req, res, next) => {
|
||||
/* eslint-enable no-unused-vars */
|
||||
const statusCode = res.statusCode !== 200 ? res.statusCode : 500;
|
||||
res.status(statusCode);
|
||||
res.json({
|
||||
message: err.message,
|
||||
stack: process.env.NODE_ENV === 'production' ? '🥞' : err.stack
|
||||
});
|
||||
};
|
||||
|
||||
const requestLoggerMiddleware = (req, res, next) => {
|
||||
console.log(`${req.method} ${req.originalUrl}`);
|
||||
const start = new Date().getTime();
|
||||
res.on('finish', () => {
|
||||
const elapsed = new Date().getTime() - start;
|
||||
console.info(`${req.method} ${req.originalUrl} ${req.statusCode} ${elapsed}ms`);
|
||||
});
|
||||
next();
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
notFound,
|
||||
errorHandler,
|
||||
requestLoggerMiddleware
|
||||
};
|
@ -0,0 +1,144 @@
|
||||
import { Router, Request, Response, NextFunction } from 'express';
|
||||
import AnimeController from './controllers/AnimeController';
|
||||
import DirectoryController from './controllers/DirectoryController';
|
||||
import UtilsController from './controllers/UtilsController';
|
||||
|
||||
const routes = Router();
|
||||
const animeController = new AnimeController();
|
||||
const directoryController = new DirectoryController();
|
||||
const utilsController = new UtilsController();
|
||||
|
||||
routes.get('/', (req: Request, res: Response) => {
|
||||
// We dont want to enforce the redirect storing, so just check
|
||||
res.set('Cache-Control', 'no-cache,proxy-revalidate');
|
||||
res.redirect('/api/v4/');
|
||||
});
|
||||
|
||||
/*
|
||||
Routes - JSON
|
||||
Message with the JSON of all the routes in the
|
||||
/api, parameters and some examples, how to call the
|
||||
endpoints of the /api.
|
||||
*/
|
||||
|
||||
routes.get('/api/v4/', (req: Request, res: Response) => {
|
||||
res.set('Cache-Control', 'no-store');
|
||||
res.json({
|
||||
message: 'Aruppi /api - 🎏',
|
||||
author: 'Jéluchu',
|
||||
version: '4.2.2',
|
||||
credits: 'The bitch loves /apis that offers data to Aruppi App',
|
||||
entries: [
|
||||
{
|
||||
Schedule: '/api/v4/schedule/:day',
|
||||
Top: '/api/v4/top/:type/:page/:subtype',
|
||||
AllAnimes: '/api/v4/allAnimes',
|
||||
RandomAnime: '/api/v4/randomAnime',
|
||||
Anitakume: '/api/v4/anitakume',
|
||||
News: '/api/v4/news',
|
||||
Season: '/api/v4/season/:year/:type',
|
||||
'All Seasons': '/api/v4/allSeasons',
|
||||
'All Directory': '/api/v4/allDirectory/:type',
|
||||
Genres: '/api/v4/getByGenres/:genre?/:order?/:page?',
|
||||
'Futures Seasons': '/api/v4/laterSeasons',
|
||||
LastEpisodes: '/api/v4/lastEpisodes',
|
||||
Movies: '/api/v4/movies/:type/:page',
|
||||
Ovas: '/api/v4/ova/:type/:page',
|
||||
Specials: '/api/v4/special/:type/:page',
|
||||
Tv: '/api/v4/tv/:type/:page',
|
||||
MoreInfo: '/api/v4/moreInfo/:title',
|
||||
GetEpisodes: '/api/v4/getEpisodes/:title',
|
||||
GetAnimeServers: '/api/v4/getAnimeServers/:id',
|
||||
Search: '/api/v4/search/:title',
|
||||
Images: '/api/v4/images/:query',
|
||||
Videos: '/api/v4/videos/:channelId',
|
||||
Playlist: '/api/v4/playlistVideos/:playlistId',
|
||||
'Type Videos': '/api/v4/sectionedVideos/:type',
|
||||
Radios: '/api/v4/radio',
|
||||
'All Themes': '/api/v4/allThemes',
|
||||
Themes: '/api/v4/themes/:title',
|
||||
'Year Themes': '/api/v4/themesYear/:year?',
|
||||
'Random Theme': '/api/v4/randomTheme',
|
||||
'Artists Theme': '/api/v4/artists/:id?',
|
||||
'Famous Platforms': '/api/v4/destAnimePlatforms',
|
||||
'Legal Platforms': '/api/v4/platforms/:id?',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
/* Routes of the app below */
|
||||
|
||||
/* Anime Controller */
|
||||
routes.get('/api/v4/schedule/:day', animeController.schedule);
|
||||
routes.get('/api/v4/top/:type/:subtype?/:page', animeController.top);
|
||||
routes.get('/api/v4/allAnimes', animeController.getAllAnimes);
|
||||
routes.get('/api/v4/lastEpisodes', animeController.getLastEpisodes);
|
||||
routes.get('/api/v4/movies/:type/:page', animeController.getContentMovie);
|
||||
routes.get('/api/v4/ova/:type/:page', animeController.getContentOva);
|
||||
routes.get('/api/v4/special/:type/:page', animeController.getContentSpecial);
|
||||
routes.get('/api/v4/tv/:type/:page', animeController.getContentTv);
|
||||
routes.get('/api/v4/getEpisodes/:title', animeController.getEpisodes);
|
||||
routes.get(
|
||||
'/api/v4/getAnimeServers/:id([^/]+/[^/]+)',
|
||||
animeController.getServers,
|
||||
);
|
||||
routes.get('/api/v4/randomAnime', animeController.getRandomAnime);
|
||||
|
||||
/* Directory Controller */
|
||||
routes.get(
|
||||
'/api/v4/allDirectory/:genres?',
|
||||
directoryController.getAllDirectory,
|
||||
);
|
||||
routes.get('/api/v4/season/:year/:type', directoryController.getSeason);
|
||||
routes.get('/api/v4/allSeasons', directoryController.allSeasons);
|
||||
routes.get('/api/v4/laterSeasons', directoryController.laterSeasons);
|
||||
routes.get('/api/v4/moreInfo/:title', directoryController.getMoreInfo);
|
||||
routes.get('/api/v4/search/:title', directoryController.search);
|
||||
routes.get(
|
||||
'/api/v4/getByGenres/:genre?/:order?/:page?',
|
||||
directoryController.getAnimeGenres,
|
||||
);
|
||||
|
||||
/* Utils Controller */
|
||||
routes.get('/api/v4/anitakume', utilsController.getAnitakume);
|
||||
routes.get('/api/v4/news', utilsController.getNews);
|
||||
routes.get('/api/v4/images/:title', utilsController.getImages);
|
||||
routes.get('/api/v4/videos/:channelId', utilsController.getVideos);
|
||||
routes.get('/api/v4/playlistVideos/:playlistId', utilsController.getPlaylists);
|
||||
routes.get('/api/v4/sectionedVideos/:type', utilsController.getSectionVideos);
|
||||
routes.get('/api/v4/radio', utilsController.getRadioStations);
|
||||
routes.get('/api/v4/allThemes', utilsController.getAllThemes);
|
||||
routes.get('/api/v4/themes/:title', utilsController.getOpAndEd);
|
||||
routes.get('/api/v4/themesYear/:year?', utilsController.getThemesYear);
|
||||
routes.get('/api/v4/randomTheme', utilsController.randomTheme);
|
||||
routes.get('/api/v4/artists/:id?', utilsController.getArtist);
|
||||
routes.get('/api/v4/destAnimePlatforms', utilsController.getDestAnimePlatforms);
|
||||
routes.get('/api/v4/platforms/:id?', utilsController.getPlatforms);
|
||||
routes.get('/api/v4/generateWaifu/', utilsController.getWaifuRandom);
|
||||
|
||||
/* Routes to handling the v3 deprecated */
|
||||
routes.get('/api/v3/*', (req: Request, res: Response, next: NextFunction) => {
|
||||
res.status(302).redirect('/api/v3');
|
||||
});
|
||||
|
||||
routes.get('/api/v3', (req: Request, res: Response, next: NextFunction) => {
|
||||
res.status(200).json({
|
||||
message:
|
||||
'Sorry, version v3 is not avaiable, if you want to see content go to v4',
|
||||
});
|
||||
});
|
||||
|
||||
/* Routes to handling the v2 deprecated */
|
||||
routes.get('/api/v2/*', (req: Request, res: Response, next: NextFunction) => {
|
||||
res.status(302).redirect('/api/v2');
|
||||
});
|
||||
|
||||
routes.get('/api/v2', (req: Request, res: Response, next: NextFunction) => {
|
||||
res.status(200).json({
|
||||
message:
|
||||
'Sorry, version v2 is not avaiable, if you want to see content go to v4',
|
||||
});
|
||||
});
|
||||
|
||||
export default routes;
|
@ -0,0 +1,41 @@
|
||||
import express, { Application } from 'express';
|
||||
import cors from 'cors';
|
||||
import helmet from 'helmet';
|
||||
import dotenv from 'dotenv';
|
||||
import { errorHandler, notFound } from './middlewares/middleware';
|
||||
import {
|
||||
createConnectionMongo,
|
||||
} from './database/connection';
|
||||
import routes from './routes';
|
||||
|
||||
const app: Application = express();
|
||||
|
||||
dotenv.config();
|
||||
createConnectionMongo({
|
||||
host: process.env.DATABASE_HOST,
|
||||
port: process.env.DATABASE_PORT,
|
||||
});
|
||||
app.use(cors());
|
||||
app.use(helmet());
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
app.use(routes);
|
||||
app.use(notFound);
|
||||
app.use(errorHandler);
|
||||
|
||||
/*
|
||||
Starting the server on the .env process
|
||||
you can define the PORT where the server
|
||||
is going to listen in the server.
|
||||
ex: PORT=3000.
|
||||
*/
|
||||
const server = app.listen(process.env.PORT_LISTEN || 3000);
|
||||
|
||||
function shutdown(): void {
|
||||
server.close();
|
||||
process.exit();
|
||||
}
|
||||
|
||||
process.on('SIGINT', shutdown);
|
||||
process.on('SIGQUIT', shutdown);
|
||||
process.on('SIGTERM', shutdown);
|
@ -0,0 +1,302 @@
|
||||
import cheerio from 'cheerio';
|
||||
import { requestGot } from './requestCall';
|
||||
import urls from './urls';
|
||||
|
||||
export default class ThemeParser {
|
||||
animes: any[] = [];
|
||||
$: any = '';
|
||||
|
||||
async all() {
|
||||
try {
|
||||
this.animes = [];
|
||||
this.$ = await redditocall('year_index');
|
||||
return await this.parseLinks();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
async allYears() {
|
||||
try {
|
||||
this.animes = [];
|
||||
this.$ = await redditocall('year_index');
|
||||
return await this.parseYears();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
async serie(title: string) {
|
||||
try {
|
||||
this.animes = [];
|
||||
this.$ = await redditocall('anime_index');
|
||||
return await this.parseSerie(title);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
async artists() {
|
||||
try {
|
||||
this.animes = [];
|
||||
this.$ = await redditocall('artist');
|
||||
return await this.parseArtists();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
async artist(id: string) {
|
||||
try {
|
||||
this.animes = [];
|
||||
this.$ = await redditocall(`artist/${id}`);
|
||||
return await this.parseArtist();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
async random() {
|
||||
try {
|
||||
this.animes = [];
|
||||
this.$ = await redditocall('anime_index');
|
||||
return await this.parseRandom();
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
async year(date: string) {
|
||||
let animes: any = [];
|
||||
|
||||
this.$ = await redditocall(date);
|
||||
this.$('h3').each((index: number, element: cheerio.Element) => {
|
||||
let parsed = this.parseAnime(this.$(element));
|
||||
parsed.year = date;
|
||||
animes.push(parsed);
|
||||
});
|
||||
return animes;
|
||||
}
|
||||
|
||||
parseRandom() {
|
||||
return new Promise(async resolve => {
|
||||
let data = this.$('p a');
|
||||
const origin: any = '1';
|
||||
let randomize = Math.round(
|
||||
Math.random() * (data.length - 1 - origin) + parseInt(origin),
|
||||
);
|
||||
|
||||
this.$ = await redditocall(
|
||||
this.$('p a')
|
||||
[randomize].attribs.href.split('/r/AnimeThemes/wiki/')[1]
|
||||
.split('#wiki')[0],
|
||||
);
|
||||
|
||||
let rand = Math.round(Math.random() * this.$('h3').length - 1);
|
||||
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: any[] = [];
|
||||
|
||||
this.$('h3 a').each((index: number, element: cheerio.Element) => {
|
||||
years.push({
|
||||
id: this.$(element).attr('href').split('/')[4],
|
||||
name: this.$(element).text(),
|
||||
});
|
||||
});
|
||||
|
||||
resolve(years);
|
||||
});
|
||||
}
|
||||
|
||||
parseArtists() {
|
||||
return new Promise(async resolve => {
|
||||
let promises = [];
|
||||
let data = this.$('p a').filter((x: any) => x > 0);
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
promises.push({
|
||||
id: data[i].children[0].parent.attribs.href.split('/')[5],
|
||||
name: data[i].children[0].data,
|
||||
});
|
||||
|
||||
if (i === data.length - 1) {
|
||||
resolve(promises);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
parseArtist() {
|
||||
return new Promise(async resolve => {
|
||||
let promises = [];
|
||||
let data = this.$('h3');
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let parsed = await this.parseAnime(data[i]);
|
||||
promises.push(parsed);
|
||||
|
||||
if (i === data.length - 1) {
|
||||
resolve(promises);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* - 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: string) {
|
||||
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;
|
||||
|
||||
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 === title) {
|
||||
let parsed = this.parseAnime(this.$('h3')[i]);
|
||||
parsed.year = year;
|
||||
resolve(parsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
parseLinks() {
|
||||
return new Promise(async resolve => {
|
||||
let years = this.$('h3 a');
|
||||
|
||||
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);
|
||||
if (i === years.length - 1) {
|
||||
resolve(this.animes);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* - 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: cheerio.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: any = {
|
||||
id: mal_id,
|
||||
title,
|
||||
};
|
||||
|
||||
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
|
||||
Parse the table tag from the HTML
|
||||
and returns a object with all the
|
||||
information.
|
||||
*/
|
||||
parseTable(element: cheerio.Element): any {
|
||||
if (this.$(element).prop('tagName') !== 'TABLE') {
|
||||
return this.parseTable(this.$(element).next());
|
||||
}
|
||||
|
||||
let themes: any = [];
|
||||
|
||||
this.$(element)
|
||||
.find('tbody')
|
||||
.find('tr')
|
||||
.each((index: number, element: cheerio.Element) => {
|
||||
let name = replaceAll(
|
||||
this.$(element).find('td').eq(0).text(),
|
||||
'"',
|
||||
'"',
|
||||
);
|
||||
let link = this.$(element).find('td').eq(1).find('a').attr('href');
|
||||
let linkDesc = this.$(element).find('td').eq(1).find('a').text();
|
||||
let episodes =
|
||||
this.$(element).find('td').eq(2).text().length > 0
|
||||
? this.$(element).find('td').eq(2).text()
|
||||
: '';
|
||||
let notes =
|
||||
this.$(element).find('td').eq(3).text().length > 0
|
||||
? this.$(element).find('td').eq(3).text()
|
||||
: '';
|
||||
|
||||
themes.push({
|
||||
name,
|
||||
link,
|
||||
desc: linkDesc,
|
||||
type: name.startsWith('OP')
|
||||
? `OP${name[2]}`
|
||||
: name.startsWith('ED')
|
||||
? `ED${name[2]}`
|
||||
: 'OP/ED',
|
||||
episodes,
|
||||
notes,
|
||||
});
|
||||
});
|
||||
|
||||
return themes;
|
||||
}
|
||||
}
|
||||
|
||||
async function redditocall(href: string) {
|
||||
const resp = await requestGot(urls.REDDIT_ANIMETHEMES + href + '.json', {
|
||||
parse: true,
|
||||
scrapy: false,
|
||||
spoof: true,
|
||||
});
|
||||
|
||||
return cheerio.load(getHTML(resp.data.content_html));
|
||||
}
|
||||
|
||||
function getHTML(str: string) {
|
||||
let html = replaceAll(str, '<', '<');
|
||||
html = replaceAll(html, '>', '>');
|
||||
return html;
|
||||
}
|
||||
|
||||
function replaceAll(str: string, find: string, replace: string) {
|
||||
return str.replace(new RegExp(find, 'g'), replace);
|
||||
}
|
@ -1,288 +0,0 @@
|
||||
const cheerio = require('cheerio');
|
||||
|
||||
const {
|
||||
homgot
|
||||
} = require('../api/apiCall');
|
||||
|
||||
const {
|
||||
REDDIT_ANIMETHEMES
|
||||
} = require('../api/urls');
|
||||
|
||||
class ThemeParser {
|
||||
|
||||
constructor() {}
|
||||
|
||||
async all() {
|
||||
try {
|
||||
this.animes = [];
|
||||
this.$ = await redditocall('year_index');
|
||||
return await this.parseLinks();
|
||||
}
|
||||
catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async allYears() {
|
||||
try {
|
||||
this.animes = [];
|
||||
this.$ = await redditocall('year_index');
|
||||
return await this.parseYears();
|
||||
}
|
||||
catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async serie(query) {
|
||||
try {
|
||||
this.animes = [];
|
||||
this.$ = await redditocall('anime_index');
|
||||
return await this.parseSerie(query);
|
||||
}
|
||||
catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async artists() {
|
||||
try {
|
||||
this.animes = [];
|
||||
this.$ = await redditocall('artist');
|
||||
return await this.parseArtists();
|
||||
}
|
||||
catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async artist(id) {
|
||||
try {
|
||||
this.animes = [];
|
||||
this.$ = await redditocall(`artist/${id}`);
|
||||
return await this.parseArtist();
|
||||
}
|
||||
catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async random(query) {
|
||||
try {
|
||||
this.animes = [];
|
||||
this.$ = await redditocall('anime_index');
|
||||
return await this.parseRandom(query);
|
||||
}
|
||||
catch(err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async year(date) {
|
||||
let animes = [];
|
||||
this.$ = await redditocall(date)
|
||||
this.$('h3').each((i, el) => {
|
||||
let parsed = this.parseAnime(el);
|
||||
parsed.year = date;
|
||||
animes.push(parsed);
|
||||
})
|
||||
return animes;
|
||||
}
|
||||
|
||||
parseRandom() {
|
||||
return new Promise(async resolve => {
|
||||
|
||||
let data = this.$('p a');
|
||||
const origin = '1'
|
||||
let randomize = Math.round(Math.random()*((data.length-1)-origin)+parseInt(origin));
|
||||
|
||||
this.$ = await redditocall(this.$('p a')[randomize].attribs.href.split('/r/AnimeThemes/wiki/')[1].split('#wiki')[0]);
|
||||
|
||||
let rand = Math.round(Math.random()*this.$('h3').length - 1);
|
||||
let parsed = this.parseAnime(this.$('h3')[rand]);
|
||||
resolve(parsed);
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
parseYears(){
|
||||
return new Promise(async resolve => {
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
parseArtists(){
|
||||
return new Promise(async resolve => {
|
||||
|
||||
let promises = []
|
||||
let data = this.$('p a').filter(x => x > 0);
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
|
||||
promises.push({
|
||||
id: data[i].children[0].parent.attribs.href.split('/')[5],
|
||||
name: data[i].children[0].data
|
||||
})
|
||||
|
||||
if (i === data.length - 1) {
|
||||
resolve(promises)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
parseArtist(){
|
||||
return new Promise(async resolve => {
|
||||
|
||||
let promises = []
|
||||
let data = this.$('h3');
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
|
||||
let parsed = await this.parseAnime(data[i])
|
||||
promises.push(parsed)
|
||||
|
||||
if (i === data.length - 1) {
|
||||
resolve(promises)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
parseSerie(query){
|
||||
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
|
||||
|
||||
if (serieElement.split(" (")[0] === query) {
|
||||
|
||||
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) {
|
||||
let parsed = this.parseAnime(this.$('h3')[i]);
|
||||
resolve(parsed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
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);
|
||||
if(i === years.length - 1) {
|
||||
resolve(this.animes);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
parseAnime(dat) {
|
||||
let el = this.$(dat).children('a');
|
||||
let title = el.text();
|
||||
let malId = el.attr('href').split('/')[4];
|
||||
let next = this.$(dat).next();
|
||||
|
||||
let theme = {
|
||||
id: malId,
|
||||
title
|
||||
}
|
||||
|
||||
if (next.prop("tagName") === "P") {
|
||||
theme.themes = this.parseTable(next.next());
|
||||
} else if (next.prop("tagName") === "TABLE") {
|
||||
theme.themes = this.parseTable(next);
|
||||
}
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
||||
parseTable(table) {
|
||||
if (table.prop('tagName') !== "TABLE") {
|
||||
return this.parseTable(table.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(), """, "\"")
|
||||
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();
|
||||
|
||||
themes.push({
|
||||
name,
|
||||
link,
|
||||
desc: linkDesc,
|
||||
type: (name.startsWith('OP') ? 'opening' : 'ending'),
|
||||
episodes,
|
||||
notes
|
||||
})
|
||||
})
|
||||
|
||||
return themes;
|
||||
}
|
||||
}
|
||||
|
||||
async function redditocall(href) {
|
||||
let options = { parse: true }
|
||||
let resp = await homgot(REDDIT_ANIMETHEMES + href + ".json", options)
|
||||
|
||||
return cheerio.load(getHTML(resp.data.content_html));
|
||||
}
|
||||
|
||||
function getHTML(str) {
|
||||
let html = replaceAll(str, "<", "<")
|
||||
html = replaceAll(html, ">", ">")
|
||||
return html;
|
||||
}
|
||||
|
||||
function replaceAll(str, find, replace) {
|
||||
return str.replace(new RegExp(find, 'g'), replace);
|
||||
}
|
||||
|
||||
module.exports = ThemeParser;
|
@ -1,449 +0,0 @@
|
||||
const {
|
||||
BASE_ANIMEFLV, BASE_JIKAN, BASE_EPISODE_IMG_URL, SEARCH_URL, SEARCH_DIRECTORY, BASE_ARUPPI
|
||||
} = require('../api/urls');
|
||||
|
||||
const {
|
||||
homgot
|
||||
} = require('../api/apiCall');
|
||||
|
||||
const animeflvInfo = async (id, index) => {
|
||||
|
||||
let poster = ""
|
||||
let banner = ""
|
||||
let synopsis = ""
|
||||
let rating = ""
|
||||
let debut = ""
|
||||
let type = ""
|
||||
let $
|
||||
|
||||
try {
|
||||
|
||||
let options = { scrapy: true }
|
||||
$ = await homgot(`${BASE_ANIMEFLV}anime/${id}`, options);
|
||||
|
||||
const scripts = $('script');
|
||||
const anime_info_ids = [];
|
||||
const anime_eps_data = [];
|
||||
const animeExtraInfo = [];
|
||||
const genres = [];
|
||||
let listByEps;
|
||||
|
||||
poster = `${BASE_ANIMEFLV}` + $('body div div div div div aside div.AnimeCover div.Image figure img').attr('src')
|
||||
banner = poster.replace('covers', 'banners').trim();
|
||||
synopsis = $('body div div div div div main section div.Description p').text().trim();
|
||||
rating = $('body div div div.Ficha.fchlt div.Container div.vtshr div.Votes span#votes_prmd').text();
|
||||
debut = $('body div.Wrapper div.Body div div.Container div.BX.Row.BFluid.Sp20 aside.SidebarA.BFixed p.AnmStts').text();
|
||||
type = $('body div.Wrapper div.Body div div.Ficha.fchlt div.Container span.Type').text()
|
||||
|
||||
animeExtraInfo.push({
|
||||
poster: poster,
|
||||
banner: banner,
|
||||
synopsis: synopsis,
|
||||
rating: rating,
|
||||
debut: debut,
|
||||
type: type,
|
||||
})
|
||||
|
||||
$('main.Main section.WdgtCn nav.Nvgnrs a').each((index, element) => {
|
||||
const $element = $(element);
|
||||
const genre = $element.attr('href').split('=')[1] || null;
|
||||
genres.push(genre);
|
||||
});
|
||||
|
||||
|
||||
Array.from({length: scripts.length}, (v, k) => {
|
||||
const $script = $(scripts[k]);
|
||||
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)
|
||||
anime_eps_data.push(eps_data);
|
||||
}
|
||||
});
|
||||
const AnimeThumbnailsId = index;
|
||||
const animeId = id;
|
||||
let nextEpisodeDate
|
||||
|
||||
if (anime_info_ids.length > 0) {
|
||||
if (anime_info_ids[0].length === 4) {
|
||||
nextEpisodeDate = anime_info_ids[0][3]
|
||||
} else {
|
||||
nextEpisodeDate = null
|
||||
}
|
||||
}
|
||||
|
||||
const amimeTempList = [];
|
||||
for (const [key, value] 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}];
|
||||
Array.from({length: amimeTempList[1].length}, (v, k) => {
|
||||
let data = amimeTempList.map(x => x[k]);
|
||||
let episode = data[0];
|
||||
let id = data[1];
|
||||
let imagePreview = `${BASE_EPISODE_IMG_URL}${AnimeThumbnailsId}/${episode}/th_3.jpg`
|
||||
let link = `${id}/${animeId}-${episode}`
|
||||
|
||||
animeListEps.push({
|
||||
episode: episode,
|
||||
id: link,
|
||||
imagePreview: imagePreview
|
||||
})
|
||||
})
|
||||
|
||||
listByEps = animeListEps;
|
||||
|
||||
return {listByEps, genres, animeExtraInfo};
|
||||
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const getAnimeCharacters = async (title) => {
|
||||
|
||||
let options = { parse: true }
|
||||
|
||||
const res = await homgot(`${BASE_JIKAN}search/anime?q=${title}`, options);
|
||||
const matchAnime = res.results.filter(x => x.title === title);
|
||||
const malId = matchAnime[0].mal_id;
|
||||
|
||||
if (typeof matchAnime[0].mal_id === 'undefined') return null;
|
||||
|
||||
const data = await homgot(`${BASE_JIKAN}anime/${malId}/characters_staff`, options);
|
||||
let body = data.characters;
|
||||
|
||||
if (typeof body === 'undefined') return null;
|
||||
|
||||
const charactersId = body.map(doc => {
|
||||
return doc.mal_id
|
||||
})
|
||||
const charactersNames = body.map(doc => {
|
||||
return doc.name;
|
||||
});
|
||||
const charactersImages = body.map(doc => {
|
||||
return doc.image_url
|
||||
});
|
||||
|
||||
let characters = [];
|
||||
Array.from({length: charactersNames.length}, (v, k) => {
|
||||
const id = charactersId[k];
|
||||
let name = charactersNames[k];
|
||||
let characterImg = charactersImages[k];
|
||||
characters.push({
|
||||
id: id,
|
||||
name: name,
|
||||
image: characterImg
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(characters);
|
||||
};
|
||||
|
||||
const getAnimeVideoPromo = async (title) => {
|
||||
|
||||
let options = { parse: true }
|
||||
const res = await homgot(`${BASE_JIKAN}search/anime?q=${title}`, options);
|
||||
const matchAnime = res.results.filter(x => x.title === title);
|
||||
const malId = matchAnime[0].mal_id;
|
||||
|
||||
if (typeof matchAnime[0].mal_id === 'undefined') return null;
|
||||
|
||||
const data = await homgot(`${BASE_JIKAN}anime/${malId}/videos`, options);
|
||||
const body = data.promo;
|
||||
const promises = [];
|
||||
|
||||
body.map(doc => {
|
||||
promises.push({
|
||||
title: doc.title,
|
||||
previewImage: doc.image_url,
|
||||
videoURL: doc.video_url
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(promises);
|
||||
};
|
||||
|
||||
const animeExtraInfo = async (title) => {
|
||||
|
||||
let options = { parse: true }
|
||||
const res = await homgot(`${BASE_JIKAN}search/anime?q=${title}`, options);
|
||||
const matchAnime = res.results.filter(x => x.title === title);
|
||||
const malId = matchAnime[0].mal_id;
|
||||
|
||||
if (typeof matchAnime[0].mal_id === 'undefined') return null;
|
||||
|
||||
const data = await homgot(`${BASE_JIKAN}anime/${malId}`, options);
|
||||
const body = Array(data);
|
||||
const promises = [];
|
||||
|
||||
body.map(doc => {
|
||||
|
||||
let airDay = {
|
||||
'mondays': 'Lunes',
|
||||
'monday': 'Lunes',
|
||||
'tuesdays': 'Martes',
|
||||
'tuesday': 'Martes',
|
||||
'wednesdays': 'Miércoles',
|
||||
'wednesday': 'Miércoles',
|
||||
'thursdays': 'Jueves',
|
||||
'thursday': 'Jueves',
|
||||
'fridays': 'Viernes',
|
||||
'friday': 'Viernes',
|
||||
'saturdays': 'Sábados',
|
||||
'saturday': 'Sábados',
|
||||
'sundays': 'Domingos',
|
||||
'sunday': 'Domingos',
|
||||
'default': 'Sin emisión'
|
||||
};
|
||||
|
||||
promises.push({
|
||||
titleJapanese: doc.title_japanese,
|
||||
source: doc.source,
|
||||
totalEpisodes: doc.episodes,
|
||||
aired: {
|
||||
from: doc.aired.from,
|
||||
to: doc.aired.to
|
||||
},
|
||||
duration: doc.duration.split('per')[0],
|
||||
rank: doc.rank,
|
||||
broadcast: airDay[doc.broadcast.split('at')[0].replace(" ", "").toLowerCase()],
|
||||
producers: doc.producers.map(x => x.name) || null,
|
||||
licensors: doc.licensors.map(x => x.name) || null,
|
||||
studios: doc.studios.map(x => x.name) || null,
|
||||
openingThemes: doc.opening_themes || null,
|
||||
endingThemes: doc.ending_themes || null
|
||||
});
|
||||
});
|
||||
return Promise.all(promises);
|
||||
};
|
||||
|
||||
const imageUrlToBase64 = async (url) => {
|
||||
let img = await homgot(url)
|
||||
return img.rawBody.toString('base64');
|
||||
};
|
||||
|
||||
const helper = async () => {}
|
||||
|
||||
const searchAnime = async (query) => {
|
||||
|
||||
let $
|
||||
let promises = []
|
||||
|
||||
let options = { scrapy: true }
|
||||
$ = await homgot(`${SEARCH_URL}${query}`, options);
|
||||
$('div.Container ul.ListAnimes li article').each((index, element) => {
|
||||
const $element = $(element);
|
||||
const id = $element.find('div.Description a.Button').attr('href').slice(1);
|
||||
const title = $element.find('a h3').text();
|
||||
let poster = $element.find('a div.Image figure img').attr('src') || $element.find('a div.Image figure img').attr('data-cfsrc');
|
||||
const type = $element.find('div.Description p span.Type').text();
|
||||
|
||||
promises.push(helper().then(async () => ({
|
||||
id: id || null,
|
||||
title: title || null,
|
||||
type: type || null,
|
||||
image: await imageUrlToBase64(poster) || null
|
||||
})));
|
||||
|
||||
})
|
||||
|
||||
return Promise.all(promises);
|
||||
|
||||
};
|
||||
|
||||
const transformUrlServer = async (urlReal) => {
|
||||
|
||||
let res
|
||||
let data
|
||||
const promises = []
|
||||
|
||||
for (const index in urlReal) {
|
||||
if (urlReal[index].server === 'amus' || urlReal[index].server === 'natsuki') {
|
||||
|
||||
let options = { parse: true }
|
||||
res = await homgot(urlReal[index].code.replace("embed", "check"), options);
|
||||
|
||||
urlReal[index].code = res.file || null
|
||||
urlReal[index].direct = true
|
||||
} else {
|
||||
urlReal[index].direct = false
|
||||
}
|
||||
}
|
||||
|
||||
urlReal.map(doc => {
|
||||
promises.push({
|
||||
id: doc.title.toLowerCase(),
|
||||
url: doc.code,
|
||||
direct: doc.direct
|
||||
});
|
||||
});
|
||||
|
||||
return promises;
|
||||
}
|
||||
|
||||
const obtainPreviewNews = (encoded) => {
|
||||
|
||||
let image;
|
||||
|
||||
if (encoded.includes('<img title=')) {
|
||||
image = encoded.substring(encoded.indexOf("<img title=\""), encoded.indexOf("\" alt")).split('src=\"')[1]
|
||||
} else if (encoded.includes('<img src=')) {
|
||||
image = encoded
|
||||
.substring(encoded.indexOf("<img src=\""), encoded.indexOf("\" alt"))
|
||||
.substring(10).replace("http", "https")
|
||||
.replace("httpss", "https")
|
||||
} else if (encoded.includes('<img')) {
|
||||
image = encoded.split("src=")[1].split(" class=")[0].replace("\"", '').replace('\"', '')
|
||||
} else if (encoded.includes('https://www.youtube.com/embed/')) {
|
||||
let getSecondThumb = encoded.split('https://www.youtube.com/embed/')[1].split('?feature')[0]
|
||||
image = `https://img.youtube.com/vi/${getSecondThumb}/0.jpg`
|
||||
} else if (encoded.includes('https://www.dailymotion.com/')) {
|
||||
let getDailymotionThumb = encoded
|
||||
.substring(encoded.indexOf("\" src=\""), encoded.indexOf("\" a"))
|
||||
.substring(47)
|
||||
image = `https://www.dailymotion.com/thumbnail/video/${getDailymotionThumb}`
|
||||
} else {
|
||||
let number = Math.floor(Math.random() * 30);
|
||||
image = `${BASE_ARUPPI}news/${number}.png`
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
const structureThemes = async (body, indv) => {
|
||||
|
||||
const promises = []
|
||||
let themes
|
||||
|
||||
if (indv === true) {
|
||||
themes = await getThemesData(body.themes)
|
||||
|
||||
promises.push({
|
||||
title: body.title,
|
||||
year: body.year,
|
||||
themes: themes,
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
for (let i = 0; i <= body.length - 1; i++) {
|
||||
|
||||
themes = await getThemesData(body[i].themes)
|
||||
|
||||
promises.push({
|
||||
title: body[i].title,
|
||||
year: body[i].year,
|
||||
themes: themes,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return promises;
|
||||
|
||||
};
|
||||
|
||||
|
||||
const getThemesData = async (themes) => {
|
||||
|
||||
let promises = []
|
||||
|
||||
for (let i = 0; i <= themes.length - 1; i++) {
|
||||
|
||||
promises.push({
|
||||
title: themes[i].name.split('"')[1] || 'Remasterización',
|
||||
type: themes[i].name.split('"')[0] || 'OP/ED',
|
||||
episodes: themes[i].episodes || null,
|
||||
video: themes[i].link
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return promises;
|
||||
|
||||
};
|
||||
|
||||
const getThemes = async (themes) => {
|
||||
|
||||
let promises = []
|
||||
|
||||
themes.map(doc => {
|
||||
|
||||
promises.push({
|
||||
name: doc.themeName,
|
||||
type: doc.themeType,
|
||||
video: doc.mirror.mirrorURL
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
return promises;
|
||||
|
||||
};
|
||||
|
||||
const getAnimes = async () => {
|
||||
let options = { parse: true }
|
||||
return await homgot(`${BASE_ANIMEFLV}api/animes/list`, options);
|
||||
};
|
||||
|
||||
|
||||
const getDirectory = async () => {
|
||||
|
||||
let $
|
||||
let promises = []
|
||||
|
||||
let options = { scrapy: true }
|
||||
$ = await homgot(`${SEARCH_URL}`, options);
|
||||
const lastPage = $('body div.Wrapper div.Container main div.NvCnAnm ul li a')[11].children[0].data
|
||||
|
||||
for (let i = 1; i <= lastPage; i++) {
|
||||
|
||||
let options = { scrapy: true }
|
||||
$ = await homgot(`${SEARCH_DIRECTORY}${i}`, options);
|
||||
|
||||
$('div.Container ul.ListAnimes li article').each((index, element) => {
|
||||
const $element = $(element);
|
||||
const id = $element.find('div.Description a.Button').attr('href').slice(1);
|
||||
const title = $element.find('a h3').text();
|
||||
let poster = $element.find('a div.Image figure img').attr('src') || $element.find('a div.Image figure img').attr('data-cfsrc');
|
||||
const type = $element.find('div.Description p span.Type').text();
|
||||
|
||||
promises.push(helper().then(async () => ({
|
||||
id: id || null,
|
||||
title: title || null,
|
||||
type: type || null,
|
||||
image: await imageUrlToBase64(poster) || null
|
||||
})));
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
animeflvInfo,
|
||||
getAnimeCharacters,
|
||||
getAnimeVideoPromo,
|
||||
animeExtraInfo,
|
||||
imageUrlToBase64,
|
||||
searchAnime,
|
||||
transformUrlServer,
|
||||
obtainPreviewNews,
|
||||
structureThemes,
|
||||
getThemes,
|
||||
getAnimes,
|
||||
getDirectory,
|
||||
helper
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
import urls from './urls';
|
||||
|
||||
export const obtainPreviewNews = (encoded: string) => {
|
||||
let image: string;
|
||||
|
||||
try {
|
||||
if (encoded.includes('src="https://img1.ak.crunchyroll.com/')) {
|
||||
if (
|
||||
encoded.split('https://img1.ak.crunchyroll.com/')[1].includes('.jpg')
|
||||
) {
|
||||
image = `https://img1.ak.crunchyroll.com/${
|
||||
encoded.split('https://img1.ak.crunchyroll.com/')[1].split('.jpg')[0]
|
||||
}.jpg`;
|
||||
} else {
|
||||
image = `https://img1.ak.crunchyroll.com/${
|
||||
encoded.split('https://img1.ak.crunchyroll.com/')[1].split('.png')[0]
|
||||
}.png`;
|
||||
}
|
||||
} else if (encoded.includes('<img title=')) {
|
||||
image = encoded
|
||||
.substring(encoded.indexOf('<img title="'), encoded.indexOf('" alt'))
|
||||
.split('src="')[1];
|
||||
} else if (encoded.includes('<img src=')) {
|
||||
image = encoded
|
||||
.substring(encoded.indexOf('<img src="'), encoded.indexOf('" alt'))
|
||||
.substring(10)
|
||||
.replace('http', 'https')
|
||||
.replace('httpss', 'https');
|
||||
} else if (encoded.includes('<img')) {
|
||||
image = encoded
|
||||
.split('src=')[1]
|
||||
.split(' class=')[0]
|
||||
.replace('"', '')
|
||||
.replace('"', '');
|
||||
} else if (encoded.includes('https://www.youtube.com/embed/')) {
|
||||
let getSecondThumb = encoded
|
||||
.split('https://www.youtube.com/embed/')[1]
|
||||
.split('?feature')[0];
|
||||
image = `https://img.youtube.com/vi/${getSecondThumb}/0.jpg`;
|
||||
} else if (encoded.includes('https://www.dailymotion.com/')) {
|
||||
let getDailymotionThumb = encoded
|
||||
.substring(encoded.indexOf('" src="'), encoded.indexOf('" a'))
|
||||
.substring(47);
|
||||
image = `https://www.dailymotion.com/thumbnail/video/${getDailymotionThumb}`;
|
||||
} else {
|
||||
let number = Math.floor(Math.random() * 30);
|
||||
image = `${urls.BASE_ARUPPI}news/${number}.png`;
|
||||
}
|
||||
|
||||
return image;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
@ -0,0 +1,52 @@
|
||||
import got from 'got';
|
||||
import cheerio from 'cheerio';
|
||||
import { CookieJar } from 'tough-cookie';
|
||||
// @ts-ignore
|
||||
import * as got_pjson from 'got/package.json'
|
||||
const pjson = require('../../package.json');
|
||||
|
||||
const cookieJar = new CookieJar();
|
||||
const aruppi_options: any = {
|
||||
cookieJar,
|
||||
'headers': {
|
||||
'user-agent': `Aruppi-API/${pjson.version} ${got_pjson.name}/${got_pjson.version}`,
|
||||
'x-client': 'aruppi-api'
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
interface Options {
|
||||
scrapy?: boolean,
|
||||
parse?: boolean,
|
||||
spoof?: boolean
|
||||
}
|
||||
|
||||
export const requestGot = async (
|
||||
url: string,
|
||||
options?: Options,
|
||||
): Promise<any> => {
|
||||
const got_options: any = {...got.defaults.options, ...aruppi_options}
|
||||
if (options) {
|
||||
if (options.spoof != null) {
|
||||
got_options.headers["user-agent"] = "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:71.0) Gecko/20100101 Firefox/69.0";
|
||||
delete got_options.headers['x-client'];
|
||||
if (!options.spoof)
|
||||
got_options.headers['user-agent'] = got.defaults.options.headers['user-agent'];
|
||||
} else if (process.env.ALPI_KEY && (new URL(url)).hostname.match(/\.jeluchu\.xyz$/)) {
|
||||
got_options.headers['x-aruppi-key'] = process.env.ALPI_KEY;
|
||||
}
|
||||
|
||||
if (options.scrapy) {
|
||||
const response = await got(url, got_options);
|
||||
return cheerio.load(response.body);
|
||||
}
|
||||
|
||||
if (options.parse) {
|
||||
got_options.responseType = 'json';
|
||||
const response = await got(url, got_options);
|
||||
return response.body;
|
||||
}
|
||||
}
|
||||
const response = await got.get(url, got_options);
|
||||
return response;
|
||||
};
|
@ -0,0 +1,22 @@
|
||||
import { requestGot } from './requestCall';
|
||||
|
||||
export const transformUrlServer = async (urlReal: any) => {
|
||||
for (const data of urlReal) {
|
||||
if (data.server === 'amus' || data.server === 'natsuki') {
|
||||
let res = await requestGot(data.code.replace('embed', 'check'), {
|
||||
parse: true,
|
||||
scrapy: false,
|
||||
});
|
||||
data.code = res.file || null;
|
||||
data.direct = true;
|
||||
}
|
||||
}
|
||||
|
||||
return urlReal.map((item: any) => {
|
||||
return {
|
||||
id: item.title.toLowerCase(),
|
||||
url: item.code,
|
||||
direct: item.direct || false,
|
||||
};
|
||||
});
|
||||
};
|
@ -0,0 +1,23 @@
|
||||
export default {
|
||||
BASE_ARUPPI: 'https://aruppi.jeluchu.xyz/',
|
||||
BASE_ANIMEFLV: 'https://www3.animeflv.net/',
|
||||
BASE_MONOSCHINOS: 'https://monoschinos2.com/',
|
||||
BASE_TIOANIME: 'https://tioanime.com/',
|
||||
BASE_JKANIME: 'https://jkanime.net/',
|
||||
BASE_ANIMEFLV_JELU: 'https://aruppi.jeluchu.xyz/apis/animeflv/v1/',
|
||||
BASE_YOUTUBE: 'https://aruppi.jeluchu.xyz/api/Youtube/?channelId=',
|
||||
BASE_YOUTUBE_PLAYLIST: 'https://aruppi.jeluchu.xyz/api/Youtube/playlist/?playlistId=',
|
||||
BASE_JIKAN: 'https://aruppi.jeluchu.xyz/apis/jikan/v4/',
|
||||
BASE_IVOOX: 'https://www.ivoox.com/podcast-anitakume_fg_f1660716_filtro_1.xml',
|
||||
BASE_KUDASAI: 'https://somoskudasai.com/feed/',
|
||||
BASE_RAMENPARADOS: 'https://ramenparados.com/category/noticias/anime/feed/',
|
||||
BASE_CRUNCHYROLL: 'https://www.crunchyroll.com/newsrss?lang=esES',
|
||||
JKANIME_SEARCH: 'https://jkanime.net/buscar/',
|
||||
ANIMEFLV_SEARCH: 'https://animeflv.net/browse?',
|
||||
SEARCH_DIRECTORY: 'https://animeflv.net/browse?order=title&page=',
|
||||
BASE_EPISODE_IMG_URL: 'https://cdn.animeflv.net/screenshots/',
|
||||
BASE_QWANT: 'https://api.qwant.com/v3/search/images?',
|
||||
REDDIT_ANIMETHEMES: 'https://reddit.com/r/AnimeThemes/wiki/',
|
||||
BASE_THEMEMOE: 'https://themes.moe/api/',
|
||||
BASE_ARUPPI_MONOSCHINOS: 'https://aruppi.jeluchu.xyz/apis/monoschinos/',
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,70 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "ES2017" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
|
||||
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./" /* Concatenate and emit output to single file. */,
|
||||
"outDir": "./dist" /* Redirect output structure to the directory. */,
|
||||
"rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
/* Additional Checks */
|
||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
||||
|
||||
/* Module Resolution Options */
|
||||
"moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
/* Source Map Options */
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true /* Skip type checking of declaration files. */,
|
||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue