Compare commits

...

88 Commits
v4.0.0 ... v4

Author SHA1 Message Date
Darkangeel_hd 6c44d5a712 Fixed getImages urls
No more "https:https://"
Will this work tomorrow, i don't know
2 years ago
Darkangeel_hd cef7574083 Minor updates
Changed PromoVideos redis keyname, using mal_id now
Changed schedule key TTL from 2 to 6 hours
2 years ago
Darkangeel_hd 7c6307cb1e Expire getRelatedMAL_* faster
TTL set to 1h
Also, forgot to mention on last commit that we changed the key name to a more friendly one, using the mal_id now.
As the relation between mal_id and its content is 1:1 collisions are not possible
That way is easier to identify on the db
2 years ago
Darkangeel_hd 58ac761098 Reimplemented getRelatedAnimesMAL
Reimplemented getRelatedAnimesMAL using jikan v4 and aruppi DB
what a pain in the ass was this one...
2 years ago
Darkangeel_hd 3a633b2ff2 Migrating to jikan v4
moved v3 endpoints to jikan v4
Quick fixes, will review later (as in between a day and 2 years later UwU)
2 years ago
dependabot[bot] e39bb486b0 Bump http-cache-semantics from 4.1.0 to 4.1.1
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2 years ago
dependabot[bot] 189a5bfb79 Bump mongoose from 5.13.13 to 5.13.15
Bumps [mongoose](https://github.com/Automattic/mongoose) from 5.13.13 to 5.13.15.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/5.13.13...5.13.15)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2 years ago
dependabot[bot] df30fd785e Bump json5 from 1.0.1 to 1.0.2
Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2)

---
updated-dependencies:
- dependency-name: json5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2 years ago
dependabot[bot] 656d4ce1ba Bump express from 4.17.1 to 4.17.3
Bumps [express](https://github.com/expressjs/express) from 4.17.1 to 4.17.3.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.17.1...4.17.3)

---
updated-dependencies:
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2 years ago
dependabot[bot] a90e522c21 Bump minimatch from 3.0.4 to 3.1.2
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.0.4 to 3.1.2.
- [Release notes](https://github.com/isaacs/minimatch/releases)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.1.2)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2 years ago
Darkangeel_hd faf0afee8c Updated utils/requestCall
Added new options to spoof user agent
New Aruppi APi user agent
Adapt relevant code to new funcionality

fixed line break on urls.ts
3 years ago
Darkangeel_hd 736ff79707 Update qwant api url 3 years ago
dependabot[bot] 2b4e3d0d7d
Bump minimist from 1.2.5 to 1.2.6 (#58)
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
3 years ago
Jesús María fdb744582f
Merge pull request #57 from aruppi/dependabot/npm_and_yarn/got-11.8.5
Bump got from 11.8.3 to 11.8.5
3 years ago
dependabot[bot] c3fa6cd854
Bump got from 11.8.3 to 11.8.5
Bumps [got](https://github.com/sindresorhus/got) from 11.8.3 to 11.8.5.
- [Release notes](https://github.com/sindresorhus/got/releases)
- [Commits](https://github.com/sindresorhus/got/compare/v11.8.3...v11.8.5)

---
updated-dependencies:
- dependency-name: got
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
3 years ago
Angel 868a958e36
Update README.md
Fixed Akiyama logo
Updated copyright year
3 years ago
Jesús María 99d636fa3f Fixed the episode number in recent episodes 4 years ago
Jesús María 361d0553e9 Fixed getEpisodes 4 years ago
Jesús María 08fb60749b Fixed lastEpisodes 4 years ago
Jesús María 5f3720446b Fixed MonosChinos failed queries 4 years ago
Jesús María 6912a2eddd Fixed video request 4 years ago
Jesús María 033b35aee9 Merge branch 'develop' into v4 4 years ago
Jesús María 9ba3e1035e Include updates for security dependant bots 4 years ago
Jesús María 11ed6d5731 Merge branch 'develop' into v4 4 years ago
Jesús María dafe02215a Update dependencies 4 years ago
Jesús María 90cb8bab66
Merge pull request #54 from aruppi/dependabot/npm_and_yarn/path-parse-1.0.7
Bump path-parse from 1.0.6 to 1.0.7
4 years ago
dependabot[bot] 31075ce33d
Bump path-parse from 1.0.6 to 1.0.7
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
4 years ago
Jesús María 5c06108a3e
Merge pull request #50 from aruppi/dependabot/npm_and_yarn/css-what-5.0.1
Bump css-what from 5.0.0 to 5.0.1
4 years ago
dependabot[bot] 78315e4017
Bump css-what from 5.0.0 to 5.0.1
Bumps [css-what](https://github.com/fb55/css-what) from 5.0.0 to 5.0.1.
- [Release notes](https://github.com/fb55/css-what/releases)
- [Commits](https://github.com/fb55/css-what/compare/v5.0.0...v5.0.1)

---
updated-dependencies:
- dependency-name: css-what
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
4 years ago
Jesús María 7be55d1f87
Merge pull request #49 from aruppi/dependabot/npm_and_yarn/normalize-url-4.5.1
Bump normalize-url from 4.5.0 to 4.5.1
4 years ago
dependabot[bot] 3bcdc34012
Bump normalize-url from 4.5.0 to 4.5.1
Bumps [normalize-url](https://github.com/sindresorhus/normalize-url) from 4.5.0 to 4.5.1.
- [Release notes](https://github.com/sindresorhus/normalize-url/releases)
- [Commits](https://github.com/sindresorhus/normalize-url/commits)

---
updated-dependencies:
- dependency-name: normalize-url
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
4 years ago
capitanwesler 24fa86de87 Merge remote-tracking branch 'origin/develop' into v4 4 years ago
capitanwesler a9bca94952 Merge branch 'v4' into origin/develop 4 years ago
capitanwesler 22141c16f8 Encoding URI 4 years ago
capitanwesler 5719ef1b17 Removing encodeURI 4 years ago
capitanwesler f32ca2bdcf 😎 Encoding URI parameters in qwant call 4 years ago
capitanwesler 57dedd3ab5 Setting cache-control in qwant 4 years ago
capitanwesler 0a60814065 😎 Refactoring the getAnimeServers
Adding the possibility to target another source, if one of them doesn't work, if any source doesn't work at all, just return undefined to the data options.
4 years ago
capitanwesler 2afd59cf7a 😎 Changing the version control 4 years ago
capitanwesler 10cdb63ac4 😎 Refactoring the getLastEpisodes call
Refactoring the lastEpisodes in the API, removed a unused function and remove unused switches.
4 years ago
capitanwesler 327c635467 💀Fixed unused type from node:http 4 years ago
capitanwesler 116e89e6c5 👾 Updating @types/node 4 years ago
capitanwesler c46b5eeb9d 🤖 Fixing error in the parameters of lastEpisodes 4 years ago
Jesús María c0d4fbe317
Merge pull request #48 from aruppi/develop
🤖 Changin version control.
4 years ago
capitanwesler bcc22b436d 🦾 Changing version control
Changing version control.
4 years ago
Jesús María 21e8fc2637
Merge pull request #47 from aruppi/develop
🤖 Fixing error in callback
4 years ago
capitanwesler e53fefd653 🤖 Fixing error in callback
Fixing error in callback to get the respective information fo myanimelist.
4 years ago
Guillermo Rivas b529f6f13a
Merge pull request #46 from aruppi/develop 4 years ago
capitanwesler d5550bbaeb 👾 Fixing build error compile 4 years ago
capitanwesler f2e13f5201 🤖 Fixing some issues with extraInfo in the call to getEpisodes 4 years ago
capitanwesler 5708086201 🤖 Fixing some issues with packages and other plugins from eslint 4 years ago
Guillermo Rivas c1c33cb4a9
Merge pull request #45 from aruppi/develop
🦾 Error with index in episodesList
4 years ago
capitanwesler 177ddcb924 🦾 Error with index in episodesList 4 years ago
Jesús María fdef7d04e2
Merge pull request #44 from aruppi/develop
🐧 Fixing genres to get them from the directory
4 years ago
capitanwesler 6480c272ab 👾 Changing control version 4 years ago
capitanwesler 3fc5ddab5d 🤖 Implementing TioAnime as source of anime 4 years ago
capitanwesler 04b30632f8 👓 Adding the changes to the other fonts 4 years ago
capitanwesler f8ab77b289 👓 Changing the version control 4 years ago
capitanwesler 77513c4820 👓 Adding the lastEpisodes with animeflv function 4 years ago
capitanwesler adad49eaae 🦊 Sorting genres by the order 4 years ago
capitanwesler b0e5b4c7bc 🐧 Fixing genres to get them from the directory 4 years ago
Jéluchu ea1ee08c78 Merge branch 'develop' into v4 4 years ago
Jéluchu c0e1e5172b 🥺 Fix versionCode 4 years ago
Jesús María 893a9e7386
Merge pull request #42 from aruppi/develop
Adding the anime state and the nextEpisodeDate
4 years ago
capitanwesler 87cecdafec 🔧 Fixing format date 4 years ago
capitanwesler 0be12412ce 🔧 Fixing wrong date and work without redis 4 years ago
capitanwesler a4d9332510 🛠 Deleting unused console.log 4 years ago
capitanwesler 482891e39b 🧢 Changing the from how it takes the nextEpisode 4 years ago
capitanwesler 76994fdbe9 🧢 Changing date format on the nextEpisodeDate 4 years ago
Guillermo Rivas 44afd0c085
Merge pull request #43 from aruppi/feature/NormalizeId
👓 Updating package and README version control
4 years ago
capitanwesler 4f2bbbd417 👓 Updating package and README version control 4 years ago
Guillermo Rivas d34241a0ac
Merge pull request #41 from aruppi/feature/NormalizeId
🦾 Adding the nextEpisodeDate and the anime state
4 years ago
capitanwesler 533ae5da2d 🦾 Adding the nextEpisodeDate and the anime state 4 years ago
Jéluchu 8bd8be8370 Delete packge-lock.json 4 years ago
Jesús María 526a24c3d7
Merge pull request #40 from aruppi/develop
💀 lower case from anime servers
4 years ago
capitanwesler 27955db82e 👹 Changing version control 4 years ago
capitanwesler 9bdbc458fc 💀 lower case from anime servers 4 years ago
Jesús María d64e2df268
Merge pull request #39 from aruppi/develop
Feature/upgrading monoschinos
4 years ago
Guillermo Rivas e7d45c19d2
Merge pull request #38 from aruppi/feature/upgradingMonoschinos
Feature/upgrading monoschinos
4 years ago
capitanwesler cda086a583 💀 Adding monoschinos lastest episodes 4 years ago
capitanwesler d8cc3626f2 🤖 Deleting palomitron from urls from the news 4 years ago
Jesús María 133e800b75
Update README.md 4 years ago
Jéluchu a2f1a08d0d Update cover image 4 years ago
Jéluchu fcd1ddc87b Merge remote-tracking branch 'origin/v4' into v4 4 years ago
Jéluchu db943834e8 Merge branch 'develop' into v4 4 years ago
Jesús María a634921de8
Merge pull request #33 from aruppi/develop
Update README.md
4 years ago
Jesús María 841c5ad166
Update README.md 4 years ago
Jéluchu 4a7b775159 Updated README.md 4 years ago

@ -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: {},
},
},
},
};

@ -1,47 +0,0 @@
{
"env": {
"browser": true,
"commonjs": true,
"es2021": true,
"node": true
},
"extends": [
"airbnb-base",
"plugin:@typescript-eslint/recommended",
"prettier/@typescript-eslint",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"plugins": ["@typescript-eslint", "prettier"],
"rules": {
"no-underscore-dangle": "off",
"prettier/prettier": "error",
"class-methods-use-this": "off",
"camelcase": "off",
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_"
}
],
"import/extensions": [
"error",
"ignorePackages",
{
"ts": "never"
}
]
},
"settings": {
"import/resolver": {
"node": {
"extensions": [".ts"],
"typescript": {}
}
}
}
}

@ -0,0 +1,5 @@
module.exports = {
singleQuote: true,
trailingComma: 'all',
arrowParens: 'avoid',
};

@ -1,5 +0,0 @@
{
"singleQuote": true,
"trailingComma": "all",
"arrowParens": "avoid"
}

@ -1,4 +1,4 @@
# **Aruppi API** (v4.0.0)
# **Aruppi API** (v4.2.2)
> This API has everything about Japan, from anime, music, radio, images, videos ... to japanese culture
>
@ -12,22 +12,21 @@
![now](https://badgen.net/badge/icon/now?icon=now&label)
![gitrepo](https://img.shields.io/github/stars/aruppi/aruppi-api?style=social)
---
<img src="./assets/img/logo.png" width="100%" alt="">
## 📖 API Documentation
#
Soon we will add the documentation information in a link
<img src="./assets/img/cover.png" width="100%" alt="">
## :rocket: Custom Aruppi API Link
&nbsp;
&nbsp;
&nbsp;
Link to access the [Aruppi API](https://aruppi-api.jeluchu.now.sh/api/v2)
&nbsp;
&nbsp;
&nbsp;
## 📚 **Development Diary**
Aruppi API has been developed to bring together all the information about Japanese culture, from anime and manga to the most secret places in Japan, its gastronomy and even its festivities.
Describe the purpose of the project and give clues about what the code does.
For more information go to the following link [Diary Reference](./development_diary/README.md).
We are in continuous development to implement more features and improvements in the functioning of it, to later implement it in the mobile application.
## **:wrench: Developer usage**
@ -46,14 +45,15 @@ you need to have installed these versions:
Then:
- Choose a folder project in your system and switch in `cd [folder path]`
- Clone the repo in your folder path `git clone https://github.com/aruppi/aruppi-api`
- Clone the repo in your folder path `git clone https://github.com/aruppi/aruppi-api`.
Here are the steps to get started with the project on both platforms, use the corresponding commands if **npm** or **yarn**.
---
### **Installation**
In order to install the project and all dependencies, enter in the project folder and run `npm install`
or you can do the same with yarn with `yarn` in the project
In order to install the project and all dependencies, enter in the project folder and run `npm install` or you can do the same with yarn with `yarn` in the project
---
@ -63,8 +63,6 @@ or you can do the same with yarn with `yarn` in the project
npm start
```
or
```bash
yarn start
```
@ -75,8 +73,6 @@ yarn start
npm build
```
or
```bash
yarn build
```
@ -91,47 +87,18 @@ npm test
yarn test
```
---
## Deprecated v1 for API
Aruppi has grown since it was launched and we need to continue improving the application along with the services to be able to give new features.
But if you need to see the code or the operation of the old version you can do it
- [Aruppi API GitHub (v1) [Deprecated]](https://github.com/aruppi/aruppi-api-v1)
- [Aruppi API Custom Link(v1) [Deprecated]](https://aruppi.herokuapp.com/api/Aruppi/)
## Countdown to deprecation of v2 API
Aruppi has grown since it was launched and we need to continue improving the application along with the services to be able to give new features.
At this time version 2.6.9 will remain functional until Aruppi App users fully migrate to version 1.5.0 of the app
## **:handshake: Contributing**
- Fork it!
- Create your feature branch: `git checkout -b my-new-feature`
- Commit your changes: `git commit -am 'Add some feature'`
- Push to the branch: `git push origin my-new-feature`
- Submit a pull request
---
### **:busts_in_silhouette: Credits**
## 📖 API Documentation
- [Darkangeel](https://github.com/Darkangeel-hd) (System administration authority (SYSADM))
- [Jéluchu](https://github.com/Jeluchu) (Android Developer, designer, and others)
- [Capitanwesler](https://github.com/capitanwesler) (Backend developer, web developer and others)
**Documentation coming soon** at the following link: [**Aruppi Wiki**](https://github.com/aruppi/aruppi-api/wiki)
Where we will show more information about the calls and queries together with the response obtained or the different types of variables in some of the queries.
---
## Countdown to deprecation of v3 API
### **:heart: Show your support**
Aruppi API version 3.x.x has been deprecated, that's why all of you who are using it should migrate as soon as possible to version 4.x.x which we have already released.
Please :star: this repository if you like it or this project helped you!\
Feel free to open issues or submit pull-requests to help me improving my work.
Otherwise, if you want to use older versions you can host them yourself on your servers, and download the code in the corresponding branches of [**v2.x.x**](https://github.com/aruppi/aruppi-api/tree/v2) and [**v3.x.x**](https://github.com/aruppi/aruppi-api/tree/v3). In case you want to use an even lower version of the API we recommend you to have a look at this other version [**v1.x.x**](https://github.com/aruppi/aruppi-api-v1)
---
Currently the Aruppi app on Android is already using the v4.x.x API services from version v2.0.8, which you can download from our website: [**Download Aruppi App**](https://aruppi.jeluchu.com/download)
### **📚 Projects that use the API**
@ -148,8 +115,8 @@ Feel free to open issues or submit pull-requests to help me improving my work.
</a>
</td>
<td align="center">
<a href="https://fmaldonado6.github.io/Akiyama/">
<img src="https://raw.githubusercontent.com/Fmaldonado6/Akiyama/master/images/logo/web-logo.png" width="75px;" alt="Jeluchu"/><br />
<a href="https://github.com/Fmaldonado6/Akiyama">
<img src="https://raw.githubusercontent.com/Fmaldonado6/Akiyama/master/images/logo/logo.png" width="75px;" alt="Jeluchu"/><br />
<sub>
<b>Akiyama</b>
</sub>
@ -160,13 +127,33 @@ Feel free to open issues or submit pull-requests to help me improving my work.
</tr>
</table>
### **:robot: Author**
## Contributors ✨
_*Jéluchu*_
Here are the **main contributors to the API**, along with Aruppi's creator
> You can follow me on
> [github](https://github.com/Jeluchu)&nbsp;&middot;&nbsp;[twitter](https://twitter.com/Jeluchu)
<table>
<tr>
<td align="center"><a href="https://github.com/Jeluchu"><img src="https://avatars.githubusercontent.com/u/32357592?v=4" width="100px;" alt=""/><br /><sub><b>Jéluchu</b></sub></a><br /><a href="https://www.instagram.com/jeluchu/" title="Instagram">📸</a> <a href="https://about.jeluchu.com/" title="About Jelu">🌍</a> <a href="https://twitter.com/Jeluchu" title="Twitter">📢</a><a href="https://www.linkedin.com/in/jesusmariacalderon/" title="LinkedIn">🔍</a></td>
<td align="center"><a href="https://github.com/capitanwesler"><img src="https://avatars.githubusercontent.com/u/61250854?v=4" width="100px;" alt=""/><br /><sub><b>Guillermo</b></sub></a><br/><a href="https://www.facebook.com/profile.php?id=100009163736196" title="Facebook">👀</a> <a href="mailto:guillermo.campanudo@hotmail.com" title="E-mail">📧</a> <a href="https://www.linkedin.com/in/guillermo-campanudo/" title="LinkedIn">🔍</a></td>
<td align="center"><a href="https://github.com/Darkangeel-hd"><img src="https://i.pinimg.com/564x/24/73/c0/2473c02e2ac93f617a28b2b5058bb41d.jpg" width="100px;" alt=""/><br /><sub><b>Darkangeel-hd</b></sub></a><br /><a href="https://i.pinimg.com/originals/19/41/22/1941222eaee4de7d08dc21cc3993e791.jpg" title="Let's All Love lain!">👀</a></td>
</tr>
</table>
---
There are also **people who have made contributions** and therefore it is also important to highlight them.
<table>
<tr>
<td align="center"><a href="https://github.com/Fmaldonado6"><img src="https://avatars.githubusercontent.com/u/28517542?v=4" width="100px;" alt=""/><br /><sub><b>Fmaldonado6</b></sub></a><br/></td>
<td align="center"><a href="https://github.com/HernanSsj"><img src="https://avatars.githubusercontent.com/u/41026227?v=4" width="100px;" alt=""/><br /><sub><b>HernanSsj</b></sub></a><br/></td>
</tr>
</table>
#
### **:busts_in_silhouette: Credits**
- [Darkangeel](https://github.com/Darkangeel-hd) (System administration authority (SYSADM))
- [Jéluchu](https://github.com/Jeluchu) (Multiplatform Developer, designer, and others)
- [Capitanwesler](https://github.com/capitanwesler) (Backend developer, web developer and others)
Copyright © 2020 [Jéluchu](https://about.jeluchu.com/).
Copyright © 2022 [Jéluchu](https://about.jeluchu.com/).

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 KiB

8109
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
{
"name": "aruppi",
"version": "4.0.0",
"version": "4.2.2",
"description": "Aruppi is a custom API to obtain data from the Japanese culture for the mobile app",
"main": "./src/api/api.ts",
"scripts": {
@ -50,37 +50,35 @@
"license": "MIT",
"dependencies": {
"body-parser": "^1.19.0",
"cheerio": "^1.0.0-rc.5",
"cheerio": "^1.0.0-rc.6",
"compose-middleware": "^5.0.1",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"got": "^11.8.1",
"helmet": "^4.4.1",
"mongodb": "^3.6.4",
"mongoose": "^5.11.18",
"redis": "^3.0.2",
"express": "^4.17.3",
"got": "^11.8.5",
"helmet": "^4.5.0",
"mongodb": "^3.6.6",
"mongoose": "^5.13.15",
"redis": "^3.1.2",
"rss-parser": "^3.12.0",
"tough-cookie": "^4.0.0",
"ts-node-dev": "^1.1.1"
},
"devDependencies": {
"@types/cheerio": "^0.22.24",
"@types/cheerio": "^0.22.28",
"@types/cors": "^2.8.10",
"@types/express": "^4.17.11",
"@types/node": "^14.14.31",
"@types/node": "^15.0.2",
"@types/redis": "^2.8.28",
"@types/tough-cookie": "^4.0.0",
"@typescript-eslint/eslint-plugin": "^4.15.2",
"@typescript-eslint/parser": "^4.15.2",
"eslint": "^5.16.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-config-prettier": "^8.0.0",
"eslint-import-resolver-typescript": "^2.4.0",
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0",
"eslint": "^7.24.0",
"eslint-config-prettier": "^8.2.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-prettier": "^3.4.0",
"prettier": "^2.2.1",
"ts-node": "^9.1.1",
"typescript": "^4.2.3"
"typescript": "^4.2.4"
}
}

@ -1,11 +1,13 @@
import { NextFunction, Request, Response } from 'express';
import { requestGot } from '../utils/requestCall';
import {
animeFlvInfo,
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';
@ -15,7 +17,6 @@ import {
animeExtraInfo,
getAnimeVideoPromo,
getAnimeCharacters,
getRelatedAnimesFLV,
getRelatedAnimesMAL,
} from '../utils/util';
import urls from '../utils/urls';
@ -80,47 +81,51 @@ interface Movie {
export default class AnimeController {
async schedule(req: Request, res: Response, next: NextFunction) {
const { day } = req.params;
let data: any;
let info: any;
try {
const resultQueryRedis: any = await redisClient.get(
`schedule_${hashStringMd5(day)}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`schedule_${hashStringMd5(day)}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
data = await requestGot(`${urls.BASE_JIKAN}schedule/${day}`, {
parse: true,
scrapy: false,
});
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[] = data[day].map((item: Schedule) => ({
title: item.title,
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.image_url,
image: item.images.jpg.image_url,
}));
if (animeList.length > 0) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`schedule_${hashStringMd5(day)}`,
JSON.stringify({ day: animeList }),
);
redisClient.set(
`schedule_${hashStringMd5(day)}`,
JSON.stringify({ day: animeList }),
);
/* After 24hrs expire the key. */
/* After 6hrs expire the key. */
redisClient.expireat(
`schedule_${hashStringMd5(day)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
redisClient.expire(
`schedule_${hashStringMd5(day)}`,
+ 21600,
);
}
res.status(200).json({
day: animeList,
@ -132,47 +137,50 @@ export default class AnimeController {
async top(req: Request, res: Response, next: NextFunction) {
const { type, subtype, page } = req.params;
let data: any;
let info: any;
try {
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);
if (redisClient.connected) {
let resultQueryRedis: any;
return res.status(200).json(resultRedis);
} else {
if (subtype !== undefined) {
data = await requestGot(
`${urls.BASE_JIKAN}top/${type}/${page}/${subtype}`,
{ parse: true, scrapy: false },
if (subtype) {
resultQueryRedis = await redisClient.get(
`top_${hashStringMd5(`${type}:${subtype}:${page}`)}`,
);
} else {
data = await requestGot(`${urls.BASE_JIKAN}top/${type}/${page}`, {
parse: true,
scrapy: false,
});
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[] = data.top.map((item: Top) => ({
rank: item.rank,
title: item.title,
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.image_url,
image_url: item.images.jpg.image_url,
type: type,
subtype: subtype,
page: page,
@ -180,31 +188,33 @@ export default class AnimeController {
}));
if (top.length > 0) {
/* 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 }),
);
}
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. */
/* 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,
);
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 });
@ -220,6 +230,7 @@ export default class AnimeController {
data = await requestGot(`${urls.BASE_ANIMEFLV}api/animes/list`, {
parse: true,
scrapy: false,
spoof: true,
});
} catch (err) {
return next(err);
@ -241,57 +252,68 @@ export default class AnimeController {
}
async getLastEpisodes(req: Request, res: Response, next: NextFunction) {
let data: any;
let lastEpisodes;
let episodes: Episode[] = [];
let animeList: any[] = [];
try {
const resultQueryRedis: any = await redisClient.get(
`lastEpisodes_${hashStringMd5('lastEpisodes')}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`lastEpisodes_${hashStringMd5('lastEpisodes')}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
data = await requestGot(
`${urls.BASE_ANIMEFLV_JELU}LatestEpisodesAdded`,
{
parse: true,
scrapy: false,
},
);
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 episode of data.episodes) {
const formattedEpisode: Episode = {
id: '12345/' + episode.id,
title: episode.title,
image: episode.poster,
episode: episode.episode,
servers: await transformUrlServer(episode.servers),
};
for (const anime of lastEpisodes) {
animeList.push({
id: `ver/${anime.id}`,
title: anime.title,
image: anime.image,
episode: anime.no,
});
}
episodes.push(formattedEpisode);
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) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`lastEpisodes_${hashStringMd5('lastEpisodes')}`,
JSON.stringify({ episodes }),
);
redisClient.set(
`lastEpisodes_${hashStringMd5('lastEpisodes')}`,
JSON.stringify({ episodes }),
);
/* After 24hrs expire the key. */
/* After 24hrs expire the key. */
redisClient.expireat(
`lastEpisodes_${hashStringMd5('lastEpisodes')}`,
parseInt(`${+new Date() / 1000}`, 10) + 1800,
);
redisClient.expireat(
`lastEpisodes_${hashStringMd5('lastEpisodes')}`,
parseInt(`${+new Date() / 1000}`, 10) + 1800,
);
}
res.status(200).json({
episodes,
@ -307,25 +329,27 @@ export default class AnimeController {
let data: any;
try {
const resultQueryRedis: any = await redisClient.get(
`contentTv_${hashStringMd5(`${type}:${page}`)}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`contentTv_${hashStringMd5(`${type}:${page}`)}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
data = await requestGot(
`${urls.BASE_ANIMEFLV_JELU}${
url.charAt(0).toUpperCase() + url.slice(1)
}/${type}/${page}`,
{
parse: true,
scrapy: false,
},
);
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);
}
@ -347,19 +371,21 @@ export default class AnimeController {
});
if (animes.length > 0) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`contentTv_${hashStringMd5(`${type}:${page}`)}`,
JSON.stringify({ animes }),
);
redisClient.set(
`contentTv_${hashStringMd5(`${type}:${page}`)}`,
JSON.stringify({ animes }),
);
/* After 24hrs expire the key. */
/* After 24hrs expire the key. */
redisClient.expireat(
`contentTv_${hashStringMd5(`${type}:${page}`)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
redisClient.expireat(
`contentTv_${hashStringMd5(`${type}:${page}`)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
}
res.status(200).json({
animes,
@ -375,25 +401,27 @@ export default class AnimeController {
let data: any;
try {
const resultQueryRedis: any = await redisClient.get(
`contentSpecial_${hashStringMd5(`${type}:${page}`)}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`contentSpecial_${hashStringMd5(`${type}:${page}`)}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
data = await requestGot(
`${urls.BASE_ANIMEFLV_JELU}${
url.charAt(0).toUpperCase() + url.slice(1)
}/${type}/${page}`,
{
parse: true,
scrapy: false,
},
);
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);
}
@ -415,19 +443,21 @@ export default class AnimeController {
});
if (animes.length > 0) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`contentSpecial_${hashStringMd5(`${type}:${page}`)}`,
JSON.stringify({ animes }),
);
redisClient.set(
`contentSpecial_${hashStringMd5(`${type}:${page}`)}`,
JSON.stringify({ animes }),
);
/* After 24hrs expire the key. */
/* After 24hrs expire the key. */
redisClient.expireat(
`contentSpecial_${hashStringMd5(`${type}:${page}`)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
redisClient.expireat(
`contentSpecial_${hashStringMd5(`${type}:${page}`)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
}
res.status(200).json({
animes,
@ -443,25 +473,27 @@ export default class AnimeController {
let data: any;
try {
const resultQueryRedis: any = await redisClient.get(
`contentOva_${hashStringMd5(`${type}:${page}`)}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`contentOva_${hashStringMd5(`${type}:${page}`)}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
data = await requestGot(
`${urls.BASE_ANIMEFLV_JELU}${
url.charAt(0).toUpperCase() + url.slice(1)
}/${type}/${page}`,
{
parse: true,
scrapy: false,
},
);
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);
}
@ -483,19 +515,21 @@ export default class AnimeController {
});
if (animes.length > 0) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`contentOva_${hashStringMd5(`${type}:${page}`)}`,
JSON.stringify({ animes }),
);
redisClient.set(
`contentOva_${hashStringMd5(`${type}:${page}`)}`,
JSON.stringify({ animes }),
);
/* After 24hrs expire the key. */
/* After 24hrs expire the key. */
redisClient.expireat(
`contentOva_${hashStringMd5(`${type}:${page}`)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
redisClient.expireat(
`contentOva_${hashStringMd5(`${type}:${page}`)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
}
res.status(200).json({
animes,
@ -511,25 +545,27 @@ export default class AnimeController {
let data: any;
try {
const resultQueryRedis: any = await redisClient.get(
`contentMovie_${hashStringMd5(`${type}:${page}`)}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`contentMovie_${hashStringMd5(`${type}:${page}`)}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
data = await requestGot(
`${urls.BASE_ANIMEFLV_JELU}${
url.charAt(0).toUpperCase() + url.slice(1)
}/${type}/${page}`,
{
parse: true,
scrapy: false,
},
);
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);
}
@ -551,19 +587,21 @@ export default class AnimeController {
});
if (animes.length > 0) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`contentMovie_${hashStringMd5(`${type}:${page}`)}`,
JSON.stringify({ animes }),
);
redisClient.set(
`contentMovie_${hashStringMd5(`${type}:${page}`)}`,
JSON.stringify({ animes }),
);
/* After 24hrs expire the key. */
/* After 24hrs expire the key. */
redisClient.expireat(
`contentMovie_${hashStringMd5(`${type}:${page}`)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
redisClient.expireat(
`contentMovie_${hashStringMd5(`${type}:${page}`)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
}
res.status(200).json({
animes,
@ -579,32 +617,34 @@ export default class AnimeController {
let episodes: any;
try {
const resultQueryRedis: any = await redisClient.get(
`episodes_${hashStringMd5(title)}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`episodes_${hashStringMd5(title)}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
searchAnime = await AnimeModel.findOne({
$or: [{ title: { $eq: title } }, { title: { $eq: `${title} (TV)` } }],
});
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 'animeflv':
episodes = await animeFlvInfo(searchAnime?.id);
break;
case 'jkanime':
episodes = await jkanimeInfo(searchAnime?.id);
episodes = await jkanimeInfo(searchAnime?.id, searchAnime?.mal_id);
break;
case 'monoschinos':
episodes = await monoschinosInfo(searchAnime?.id);
episodes = await monoschinosInfo(searchAnime?.id, searchAnime?.mal_id);
break;
case 'tioanime':
episodes = await tioanimeInfo(searchAnime?.id, searchAnime?.mal_id);
break;
default:
episodes = undefined;
@ -612,19 +652,21 @@ export default class AnimeController {
}
if (episodes) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`episodes_${hashStringMd5(title)}`,
JSON.stringify({ episodes }),
);
redisClient.set(
`episodes_${hashStringMd5(title)}`,
JSON.stringify({ episodes }),
);
/* After 24hrs expire the key. */
/* After 24hrs expire the key. */
redisClient.expireat(
`episodes_${hashStringMd5(title)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
redisClient.expireat(
`episodes_${hashStringMd5(title)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
}
res.status(200).json({ episodes });
} else {
@ -637,31 +679,52 @@ export default class AnimeController {
let data: any;
try {
const resultQueryRedis: any = await redisClient.get(
`servers_${hashStringMd5(id)}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`servers_${hashStringMd5(id)}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
if (isNaN(parseInt(id.split('/')[0]))) {
if (id.split('/')[0] === 'ver') {
data = await videoServersMonosChinos(id);
} else {
data = await videoServersJK(id);
}
} else {
data = await requestGot(
`${urls.BASE_ANIMEFLV_JELU}GetAnimeServers/${id}`,
{ parse: true, scrapy: false },
);
return res.status(200).json(resultRedis);
}
}
data = await transformUrlServer(data.servers);
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;
if (data) {
/*
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(
@ -675,11 +738,11 @@ export default class AnimeController {
`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' });
}
res.status(200).json({ servers: data });
} else {
res.status(500).json({ message: 'Aruppi lost in the shell' });
}
} catch (err) {
return next(err);
@ -696,41 +759,18 @@ export default class AnimeController {
return next(err);
}
switch (animeQuery[0].source) {
case 'animeflv':
animeResult = {
title: animeQuery[0].title || null,
poster: animeQuery[0].poster || null,
synopsis: animeQuery[0].description || null,
status: animeQuery[0].state || 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 getRelatedAnimesFLV(animeQuery[0].id),
};
break;
case 'jkanime':
animeResult = {
title: animeQuery[0].title || null,
poster: animeQuery[0].poster || null,
synopsis: animeQuery[0].description || null,
status: animeQuery[0].state || 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),
};
break;
default:
animeResult = undefined;
break;
}
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');

@ -1,14 +1,12 @@
import { NextFunction, Request, Response } from 'express';
import { requestGot } from '../utils/requestCall';
import AnimeModel, { Anime } from '../database/models/anime.model';
import GenreModel, { Genre } from '../database/models/genre.model';
import util from 'util';
import { hashStringMd5 } from '../utils/util';
import {
animeExtraInfo,
getAnimeVideoPromo,
getAnimeCharacters,
getRelatedAnimesFLV,
getRelatedAnimesMAL,
} from '../utils/util';
import urls from '../utils/urls';
@ -61,7 +59,6 @@ export default class DirectoryController {
poster: item.poster,
type: item.type,
genres: item.genres,
state: item.state,
score: item.score,
source: item.source,
description: item.description,
@ -87,7 +84,6 @@ export default class DirectoryController {
poster: item.poster,
type: item.type,
genres: item.genres,
state: item.state,
score: item.score,
source: item.source,
description: item.description,
@ -108,49 +104,53 @@ export default class DirectoryController {
async getSeason(req: Request, res: Response, next: NextFunction) {
const { year, type } = req.params;
let data: any;
let info: any;
try {
const resultQueryRedis: any = await redisClient.get(
`season_${hashStringMd5(`${year}:${type}`)}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`season_${hashStringMd5(`${year}:${type}`)}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
data = await requestGot(`${urls.BASE_JIKAN}season/${year}/${type}`, {
scrapy: false,
parse: true,
});
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[] = data.anime.map((item: any) => {
const season: TypeAnime[] = info.data.map((item: any) => {
return {
title: item.title,
image: item.image_url,
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) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`season_${hashStringMd5(`${year}:${type}`)}`,
JSON.stringify({ season }),
);
redisClient.set(
`season_${hashStringMd5(`${year}:${type}`)}`,
JSON.stringify({ season }),
);
/* After 24hrs expire the key. */
/* After 24hrs expire the key. */
redisClient.expireat(
`season_${hashStringMd5(`${year}:${type}`)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
redisClient.expireat(
`season_${hashStringMd5(`${year}:${type}`)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
}
res.status(200).json({
season,
@ -161,28 +161,30 @@ export default class DirectoryController {
}
async allSeasons(req: Request, res: Response, next: NextFunction) {
let data: any;
let info: any;
try {
const resultQueryRedis: any = await redisClient.get(
`allSeasons_${hashStringMd5('allSeasons')}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`allSeasons_${hashStringMd5('allSeasons')}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
data = await requestGot(`${urls.BASE_JIKAN}season/archive`, {
parse: true,
scrapy: false,
});
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[] = data.archive.map((item: any) => {
const archive: Archive[] = info.data.map((item: any) => {
return {
year: item.year,
seasons: item.seasons,
@ -190,19 +192,21 @@ export default class DirectoryController {
});
if (archive.length > 0) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`allSeasons_${hashStringMd5('allSeasons')}`,
JSON.stringify({ archive }),
);
redisClient.set(
`allSeasons_${hashStringMd5('allSeasons')}`,
JSON.stringify({ archive }),
);
/* After 24hrs expire the key. */
/* After 24hrs expire the key. */
redisClient.expireat(
`allSeasons_${hashStringMd5('allSeasons')}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
redisClient.expireat(
`allSeasons_${hashStringMd5('allSeasons')}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
}
res.status(200).json({ archive });
} else {
@ -211,49 +215,53 @@ export default class DirectoryController {
}
async laterSeasons(req: Request, res: Response, next: NextFunction) {
let data: any;
let info: any;
try {
const resultQueryRedis: any = await redisClient.get(
`laterSeasons_${hashStringMd5('laterSeasons')}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`laterSeasons_${hashStringMd5('laterSeasons')}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
data = await requestGot(`${urls.BASE_JIKAN}season/later`, {
parse: true,
scrapy: false,
});
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[] = data.anime.map((item: any) => {
const future: Season[] = info.data.map((item: any) => {
return {
title: item.title,
image: item.image_url,
title: item.titles.find((x: { type: string; }) => x.type === "Default").title,
image: item.images.jpg.image_url,
malink: item.url,
};
});
if (future.length > 0) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`laterSeasons_${hashStringMd5('laterSeasons')}`,
JSON.stringify({ future }),
);
redisClient.set(
`laterSeasons_${hashStringMd5('laterSeasons')}`,
JSON.stringify({ future }),
);
/* After 24hrs expire the key. */
/* After 24hrs expire the key. */
redisClient.expireat(
`laterSeasons_${hashStringMd5('laterSeasons')}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
redisClient.expireat(
`laterSeasons_${hashStringMd5('laterSeasons')}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
}
res.status(200).json({ future });
} else {
@ -267,88 +275,58 @@ export default class DirectoryController {
let resultAnime: any;
try {
const resultQueryRedis: any = await redisClient.get(
`moreInfo_${hashStringMd5(title)}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`moreInfo_${hashStringMd5(title)}`,
);
return res.status(200).json(resultRedis);
} else {
resultQuery = await AnimeModel.findOne({
$or: [{ title: { $eq: title } }, { title: { $eq: `${title} (TV)` } }],
});
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
switch (resultQuery?.source) {
case 'animeflv':
resultAnime = {
title: resultQuery?.title,
poster: resultQuery?.poster,
synopsis: resultQuery?.description,
status: resultQuery?.state,
type: resultQuery?.type,
rating: resultQuery?.score,
genres: resultQuery?.genres,
moreInfo: [await animeExtraInfo(resultQuery!.mal_id)],
promo: await getAnimeVideoPromo(resultQuery!.mal_id),
characters: await getAnimeCharacters(resultQuery!.mal_id),
related: await getRelatedAnimesFLV(resultQuery!.id),
};
break;
case 'jkanime':
resultAnime = {
title: resultQuery?.title,
poster: resultQuery?.poster,
synopsis: resultQuery?.description,
status: resultQuery?.state,
type: resultQuery?.type,
rating: resultQuery?.score,
genres: resultQuery?.genres,
moreInfo: [await animeExtraInfo(resultQuery!.mal_id)],
promo: await getAnimeVideoPromo(resultQuery!.mal_id),
characters: await getAnimeCharacters(resultQuery!.mal_id),
related: await getRelatedAnimesMAL(resultQuery!.mal_id),
};
break;
case 'monoschinos':
resultAnime = {
title: resultQuery?.title,
poster: resultQuery?.poster,
synopsis: resultQuery?.description,
status: resultQuery?.state,
type: resultQuery?.type,
rating: resultQuery?.score,
genres: resultQuery?.genres,
moreInfo: [await animeExtraInfo(resultQuery!.mal_id)],
promo: await getAnimeVideoPromo(resultQuery!.mal_id),
characters: await getAnimeCharacters(resultQuery!.mal_id),
related: await getRelatedAnimesMAL(resultQuery!.mal_id),
};
break;
default:
resultAnime = undefined;
break;
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) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`moreInfo_${hashStringMd5(title)}`,
JSON.stringify(resultAnime),
);
redisClient.set(
`moreInfo_${hashStringMd5(title)}`,
JSON.stringify(resultAnime),
);
/* After 24hrs expire the key. */
/* After 24hrs expire the key. */
redisClient.expireat(
`moreInfo_${hashStringMd5(title)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
redisClient.expireat(
`moreInfo_${hashStringMd5(title)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
}
res.status(200).json(resultAnime);
} else {
@ -386,30 +364,97 @@ export default class DirectoryController {
async getAnimeGenres(req: Request, res: Response, next: NextFunction) {
const { genre, order, page } = req.params;
let data: Genre[];
let resultReq: any;
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) {
data = await GenreModel.find();
result = await AnimeModel.aggregate([{ $sample: { size: 25 } }]);
} else {
if (page !== undefined) {
resultReq = await requestGot(
`${urls.BASE_ANIMEFLV_JELU}Genres/${genre}/${order}/${page}`,
{ parse: true, scrapy: false },
);
// 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 {
resultReq = await requestGot(
`${urls.BASE_ANIMEFLV_JELU}Genres/${genre}/${order}/1`,
{ parse: true, scrapy: false },
);
return res.status(500).json({ message: 'Aruppi lost in the shell' });
}
}
} catch (err) {
return next(err);
}
const animes: any[] = resultReq.animes.map((item: any) => {
const animes: any[] = result.map((item: any) => {
return {
id: item.id,
title: item.title.trim(),

@ -69,17 +69,19 @@ export default class UtilsController {
let feed: CustomFeed & Parser.Output<CustomItem>;
try {
const resultQueryRedis: any = await redisClient.get(
`anitakume_${hashStringMd5('anitakume')}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`anitakume_${hashStringMd5('anitakume')}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
feed = await parser.parseURL(urls.BASE_IVOOX);
return res.status(200).json(resultRedis);
}
}
feed = await parser.parseURL(urls.BASE_IVOOX);
} catch (err) {
return next(err);
}
@ -116,19 +118,21 @@ export default class UtilsController {
});
if (podcast.length > 0) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`anitakume_${hashStringMd5('anitakume')}`,
JSON.stringify({ podcast }),
);
redisClient.set(
`anitakume_${hashStringMd5('anitakume')}`,
JSON.stringify({ podcast }),
);
/* After 24hrs expire the key. */
/* After 24hrs expire the key. */
redisClient.expireat(
`anitakume_${hashStringMd5('anitakume')}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
redisClient.expireat(
`anitakume_${hashStringMd5('anitakume')}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
}
res.status(200).json({ podcast });
} else {
@ -140,11 +144,6 @@ export default class UtilsController {
const news: News[] = [];
const pagesRss: rssPage[] = [
{ url: urls.BASE_KUDASAI, author: 'Kudasai', content: 'content_encoded' },
{
url: urls.BASE_PALOMITRON,
author: 'Palomitron',
content: 'description',
},
{
url: urls.BASE_RAMENPARADOS,
author: 'Ramen para dos',
@ -158,51 +157,55 @@ export default class UtilsController {
];
try {
const resultQueryRedis: any = await redisClient.get(
`news_${hashStringMd5('news')}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`news_${hashStringMd5('news')}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
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);
});
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) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`news_${hashStringMd5('news')}`,
JSON.stringify({ news }),
);
redisClient.set(
`news_${hashStringMd5('news')}`,
JSON.stringify({ news }),
);
/* After 24hrs expire the key. */
/* After 24hrs expire the key. */
redisClient.expireat(
`news_${hashStringMd5('news')}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
redisClient.expireat(
`news_${hashStringMd5('news')}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
}
res.status(200).json({ news });
} else {
@ -215,20 +218,24 @@ export default class UtilsController {
let data: any;
try {
const resultQueryRedis: any = await redisClient.get(
`images_${hashStringMd5(title)}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`images_${hashStringMd5(title)}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
data = await requestGot(
`${urls.BASE_QWANT}count=51&q=${title}&t=images&safesearch=1&locale=es_ES&uiv=4`,
{ scrapy: false, parse: true },
);
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);
}
@ -236,26 +243,29 @@ export default class UtilsController {
const results: any[] = data.data.result.items.map((item: any) => {
return {
type: item.thumb_type,
thumbnail: `https:${item.thumbnail}`,
fullsize: `https:${item.media_fullsize}`,
thumbnail: `${item.thumbnail}`,
fullsize: `${item.media_fullsize}`,
};
});
if (results.length > 0) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`images_${hashStringMd5(title)}`,
JSON.stringify({ images: results }),
);
redisClient.set(
`images_${hashStringMd5(title)}`,
JSON.stringify({ images: results }),
);
/* After 24hrs expire the key. */
/* After 24hrs expire the key. */
redisClient.expireat(
`images_${hashStringMd5(title)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
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' });
@ -267,20 +277,81 @@ export default class UtilsController {
let data: any;
try {
const resultQueryRedis: any = await redisClient.get(
`videos_${hashStringMd5(channelId)}`,
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);
}
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
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,
};
});
return res.status(200).json(resultRedis);
} else {
data = await requestGot(
`${urls.BASE_YOUTUBE}${channelId}&part=snippet,id&order=date&maxResults=50`,
{ scrapy: false, parse: true },
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);
}
@ -296,19 +367,21 @@ export default class UtilsController {
});
if (results.length > 0) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/!* Set the key in the redis cache. *!/
redisClient.set(
`videos_${hashStringMd5(channelId)}`,
JSON.stringify({ videos: results }),
);
redisClient.set(
`videos_${hashStringMd5(playlistId)}`,
JSON.stringify({ videos: results }),
);
/* After 24hrs expire the key. */
/!* After 24hrs expire the key. *!/
redisClient.expireat(
`videos_${hashStringMd5(channelId)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
redisClient.expireat(
`videos_${hashStringMd5(playlistId)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
}
res.status(200).json({ videos: results });
} else {
@ -447,35 +520,39 @@ export default class UtilsController {
let themes: any;
try {
const resultQueryRedis: any = await redisClient.get(
`oped_${hashStringMd5(title)}`,
);
if (redisClient.connected) {
const resultQueryRedis: any = await redisClient.get(
`oped_${hashStringMd5(title)}`,
);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
themes = await structureThemes(await themeParser.serie(title), true);
return res.status(200).json(resultRedis);
}
}
themes = await structureThemes(await themeParser.serie(title), true);
} catch (err) {
return next(err);
}
if (themes) {
/* Set the key in the redis cache. */
if (redisClient.connected) {
/* Set the key in the redis cache. */
redisClient.set(
`oped_${hashStringMd5(title)}`,
JSON.stringify({ themes }),
);
redisClient.set(
`oped_${hashStringMd5(title)}`,
JSON.stringify({ themes }),
);
/* After 24hrs expire the key. */
/* After 24hrs expire the key. */
redisClient.expireat(
`oped_${hashStringMd5(title)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
redisClient.expireat(
`oped_${hashStringMd5(title)}`,
parseInt(`${+new Date() / 1000}`, 10) + 7200,
);
}
res.status(200).json({ themes });
} else {
@ -489,58 +566,62 @@ export default class UtilsController {
let resultQueryRedis: any;
try {
if (year) {
resultQueryRedis = await redisClient.get(
`themesyear_${hashStringMd5(year)}`,
);
} else {
resultQueryRedis = await redisClient.get(
`themesyear_${hashStringMd5('allYear')}`,
);
}
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);
if (resultQueryRedis) {
const resultRedis: any = JSON.parse(resultQueryRedis);
return res.status(200).json(resultRedis);
} else {
if (year === undefined) {
themes = await themeParser.allYears();
} else {
themes = await structureThemes(await themeParser.year(year), false);
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) {
/* 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 }),
);
}
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. */
/* 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,
);
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 });
@ -556,6 +637,7 @@ export default class UtilsController {
data = await requestGot(`${urls.BASE_THEMEMOE}roulette`, {
parse: true,
scrapy: false,
spoof: true,
});
} catch (err) {
return next(err);

@ -40,8 +40,30 @@ 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);
});

@ -12,7 +12,6 @@ export interface Anime extends Document {
poster: string;
type: string;
genres: Types.Array<string>;
state: string;
score: string;
source: string;
description: string;
@ -26,7 +25,6 @@ const AnimeSchema: Schema = new Schema({
poster: { type: String },
type: { type: String },
genres: [{ type: String }],
state: { type: String },
score: { type: String },
source: { type: String },
description: { type: String },

@ -26,7 +26,7 @@ routes.get('/api/v4/', (req: Request, res: Response) => {
res.json({
message: 'Aruppi /api - 🎏',
author: 'Jéluchu',
version: '4.0.0',
version: '4.2.2',
credits: 'The bitch loves /apis that offers data to Aruppi App',
entries: [
{
@ -52,6 +52,7 @@ routes.get('/api/v4/', (req: Request, res: Response) => {
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',
@ -104,6 +105,7 @@ 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);

@ -7,7 +7,6 @@ import {
createConnectionMongo,
} from './database/connection';
import routes from './routes';
import { Server } from 'node:http';
const app: Application = express();
@ -30,7 +29,7 @@ app.use(errorHandler);
is going to listen in the server.
ex: PORT=3000.
*/
const server: Server = app.listen(process.env.PORT_LISTEN || 3000);
const server = app.listen(process.env.PORT_LISTEN || 3000);
function shutdown(): void {
server.close();

@ -285,6 +285,7 @@ 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));

@ -1,28 +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;
scrapy?: boolean,
parse?: boolean,
spoof?: boolean
}
export const requestGot = async (
url: string,
options: Options,
url: string,
options?: Options,
): Promise<any> => {
if (options !== undefined) {
if (options.scrapy) {
const response = await got(url, { cookieJar });
return await cheerio.load(response.body);
}
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) {
return await got(url, { cookieJar }).json();
if (options.parse) {
got_options.responseType = 'json';
const response = await got(url, got_options);
return response.body;
}
}
} else {
return await got.get(url, { cookieJar });
}
const response = await got.get(url, got_options);
return response;
};

@ -1,22 +1,23 @@
export default {
BASE_ARUPPI: 'https://aruppi.jeluchu.xyz/',
BASE_ANIMEFLV: 'https://animeflv.net/',
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_JIKAN: 'https://aruppi.jeluchu.xyz/apis/jikan/v3/',
BASE_IVOOX:
'https://www.ivoox.com/podcast-anitakume_fg_f1660716_filtro_1.xml',
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_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',
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/search/images?',
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

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save