🍃 Setting everything up with TypeScript & Eslint

pull/33/head
capitanwesler 5 years ago
parent c7b313857c
commit c0bab5e174

@ -0,0 +1 @@
PORT=5000

@ -0,0 +1,47 @@
{
"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 @@
{
"singleQuote": true,
"trailingComma": "all",
"arrowParens": "avoid"
}

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

933
package-lock.json generated

@ -1,933 +0,0 @@
{
"name": "aruppi",
"version": "3.4.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@sindresorhus/is": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.0.tgz",
"integrity": "sha512-FyD2meJpDPjyNQejSjvnhpgI/azsQkA4lGbuu5BQZfjvJ9cbRZXzeWL2HceCekW4lixO9JPesIIQkSoLjeJHNQ=="
},
"@szmarczak/http-timer": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz",
"integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==",
"requires": {
"defer-to-connect": "^2.0.0"
}
},
"@types/cacheable-request": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz",
"integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==",
"requires": {
"@types/http-cache-semantics": "*",
"@types/keyv": "*",
"@types/node": "*",
"@types/responselike": "*"
}
},
"@types/debug": {
"version": "0.0.31",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-0.0.31.tgz",
"integrity": "sha512-LS1MCPaQKqspg7FvexuhmDbWUhE2yIJ+4AgVIyObfc06/UKZ8REgxGNjZc82wPLWmbeOm7S+gSsLgo75TanG4A=="
},
"@types/http-cache-semantics": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz",
"integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A=="
},
"@types/keyv": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz",
"integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==",
"requires": {
"@types/node": "*"
}
},
"@types/node": {
"version": "14.14.20",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.20.tgz",
"integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A=="
},
"@types/responselike": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
"integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==",
"requires": {
"@types/node": "*"
}
},
"accepts": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
"requires": {
"mime-types": "~2.1.24",
"negotiator": "0.6.2"
}
},
"array-flatten": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
"integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ=="
},
"axios": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
"requires": {
"follow-redirects": "^1.10.0"
}
},
"bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"requires": {
"file-uri-to-path": "1.0.0"
}
},
"body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
"requires": {
"bytes": "3.1.0",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "~1.1.2",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"on-finished": "~2.3.0",
"qs": "6.7.0",
"raw-body": "2.4.0",
"type-is": "~1.6.17"
}
},
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
},
"cacheable-lookup": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
"integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA=="
},
"cacheable-request": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz",
"integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==",
"requires": {
"clone-response": "^1.0.2",
"get-stream": "^5.1.0",
"http-cache-semantics": "^4.0.0",
"keyv": "^4.0.0",
"lowercase-keys": "^2.0.0",
"normalize-url": "^4.1.0",
"responselike": "^2.0.0"
}
},
"cheerio": {
"version": "1.0.0-rc.5",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.5.tgz",
"integrity": "sha512-yoqps/VCaZgN4pfXtenwHROTp8NG6/Hlt4Jpz2FEP0ZJQ+ZUkVDd0hAPDNKhj3nakpfPt/CNs57yEtxD1bXQiw==",
"requires": {
"cheerio-select-tmp": "^0.1.0",
"dom-serializer": "~1.2.0",
"domhandler": "^4.0.0",
"entities": "~2.1.0",
"htmlparser2": "^6.0.0",
"parse5": "^6.0.0",
"parse5-htmlparser2-tree-adapter": "^6.0.0"
}
},
"cheerio-select-tmp": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/cheerio-select-tmp/-/cheerio-select-tmp-0.1.1.tgz",
"integrity": "sha512-YYs5JvbpU19VYJyj+F7oYrIE2BOll1/hRU7rEy/5+v9BzkSo3bK81iAeeQEMI92vRIxz677m72UmJUiVwwgjfQ==",
"requires": {
"css-select": "^3.1.2",
"css-what": "^4.0.0",
"domelementtype": "^2.1.0",
"domhandler": "^4.0.0",
"domutils": "^2.4.4"
}
},
"clone-response": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
"integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=",
"requires": {
"mimic-response": "^1.0.0"
}
},
"compose-middleware": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/compose-middleware/-/compose-middleware-5.0.1.tgz",
"integrity": "sha512-Rcv19QgPOtYHu8wDJsu4ehSfkqSXjQLwKRXhIy9TFiIijSZz330ORyLCeirb4sPuBBbDNC5lUvQLuM72vWjKSQ==",
"requires": {
"@types/debug": "0.0.31",
"array-flatten": "^2.1.2",
"debug": "^4.1.0"
},
"dependencies": {
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"content-disposition": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
"integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
"requires": {
"safe-buffer": "5.1.2"
},
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}
}
},
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"cookie": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"requires": {
"object-assign": "^4",
"vary": "^1"
}
},
"css-select": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-3.1.2.tgz",
"integrity": "sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA==",
"requires": {
"boolbase": "^1.0.0",
"css-what": "^4.0.0",
"domhandler": "^4.0.0",
"domutils": "^2.4.3",
"nth-check": "^2.0.0"
}
},
"css-what": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-4.0.0.tgz",
"integrity": "sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A=="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"requires": {
"mimic-response": "^3.1.0"
},
"dependencies": {
"mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="
}
}
},
"defer-to-connect": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.0.tgz",
"integrity": "sha512-bYL2d05vOSf1JEZNx5vSAtPuBMkX8K9EUutg7zlKvTqKXHt7RhWJFbmd7qakVuf13i+IkGmp6FwSsONOf6VYIg=="
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"dom-serializer": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz",
"integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==",
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^4.0.0",
"entities": "^2.0.0"
}
},
"domelementtype": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz",
"integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w=="
},
"domhandler": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz",
"integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==",
"requires": {
"domelementtype": "^2.1.0"
}
},
"domutils": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.4.tgz",
"integrity": "sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA==",
"requires": {
"dom-serializer": "^1.0.1",
"domelementtype": "^2.0.1",
"domhandler": "^4.0.0"
}
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"requires": {
"once": "^1.4.0"
}
},
"entities": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
"integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w=="
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"express": {
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
"requires": {
"accepts": "~1.3.7",
"array-flatten": "1.1.1",
"body-parser": "1.19.0",
"content-disposition": "0.5.3",
"content-type": "~1.0.4",
"cookie": "0.4.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "~1.1.2",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "~1.1.2",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.5",
"qs": "6.7.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.1.2",
"send": "0.17.1",
"serve-static": "1.14.1",
"setprototypeof": "1.1.1",
"statuses": "~1.5.0",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"dependencies": {
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}
}
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
},
"finalhandler": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
"integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
"requires": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"statuses": "~1.5.0",
"unpipe": "~1.0.0"
}
},
"follow-redirects": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz",
"integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg=="
},
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"fuzzball": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/fuzzball/-/fuzzball-1.3.1.tgz",
"integrity": "sha512-6SVlrHhVxFdzvsW/a0fgzc/xunWJ5JVkHFV6dqfWcplWEt+E/VQgo4FQQxqrF+zy6XDBvSH70kjMKZkDrpltWQ==",
"requires": {
"heap": ">=0.2.0",
"setimmediate": "^1.0.5",
"string.fromcodepoint": "^0.2.1",
"string.prototype.codepointat": "^0.2.0"
}
},
"get-stream": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
"requires": {
"pump": "^3.0.0"
}
},
"got": {
"version": "11.8.1",
"resolved": "https://registry.npmjs.org/got/-/got-11.8.1.tgz",
"integrity": "sha512-9aYdZL+6nHmvJwHALLwKSUZ0hMwGaJGYv3hoPLPgnT8BoBXm1SjnZeky+91tfwJaDzun2s4RsBRy48IEYv2q2Q==",
"requires": {
"@sindresorhus/is": "^4.0.0",
"@szmarczak/http-timer": "^4.0.5",
"@types/cacheable-request": "^6.0.1",
"@types/responselike": "^1.0.0",
"cacheable-lookup": "^5.0.3",
"cacheable-request": "^7.0.1",
"decompress-response": "^6.0.0",
"http2-wrapper": "^1.0.0-beta.5.2",
"lowercase-keys": "^2.0.0",
"p-cancelable": "^2.0.0",
"responselike": "^2.0.0"
}
},
"heap": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/heap/-/heap-0.2.6.tgz",
"integrity": "sha1-CH4fELBGky/IWU3Z5tN4r8nR5aw="
},
"helmet": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-4.3.1.tgz",
"integrity": "sha512-WsafDyKsIexB0+pUNkq3rL1rB5GVAghR68TP8ssM9DPEMzfBiluEQlVzJ/FEj6Vq2Ag3CNuxf7aYMjXrN0X49Q=="
},
"hoek": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz",
"integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA=="
},
"htmlparser2": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.0.0.tgz",
"integrity": "sha512-numTQtDZMoh78zJpaNdJ9MXb2cv5G3jwUoe3dMQODubZvLoGvTE/Ofp6sHvH8OGKcN/8A47pGLi/k58xHP/Tfw==",
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^4.0.0",
"domutils": "^2.4.4",
"entities": "^2.0.0"
}
},
"http-cache-semantics": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ=="
},
"http-errors": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.3",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.0"
}
},
"http2-wrapper": {
"version": "1.0.0-beta.5.2",
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.0-beta.5.2.tgz",
"integrity": "sha512-xYz9goEyBnC8XwXDTuC/MZ6t+MrKVQZOk4s7+PaDkwIsQd8IwqvM+0M6bA/2lvG8GHXcPdf+MejTUeO2LCPCeQ==",
"requires": {
"quick-lru": "^5.1.1",
"resolve-alpn": "^1.0.0"
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
},
"isemail": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz",
"integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==",
"requires": {
"punycode": "2.x.x"
}
},
"joi": {
"version": "13.7.0",
"resolved": "https://registry.npmjs.org/joi/-/joi-13.7.0.tgz",
"integrity": "sha512-xuY5VkHfeOYK3Hdi91ulocfuFopwgbSORmIwzcwHKESQhC7w1kD5jaVSPnqDxS2I8t3RZ9omCKAxNwXN5zG1/Q==",
"requires": {
"hoek": "5.x.x",
"isemail": "3.x.x",
"topo": "3.x.x"
},
"dependencies": {
"hoek": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.4.tgz",
"integrity": "sha512-Alr4ZQgoMlnere5FZJsIyfIjORBqZll5POhDsF4q64dPuJR6rNxXdDxtHSQq8OXRurhmx+PWYEE8bXRROY8h0w=="
}
}
},
"json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
},
"keyv": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.3.tgz",
"integrity": "sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==",
"requires": {
"json-buffer": "3.0.1"
}
},
"lowercase-keys": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
"integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
},
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
},
"mime-db": {
"version": "1.44.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
},
"mime-types": {
"version": "2.1.27",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
"requires": {
"mime-db": "1.44.0"
}
},
"mimic-response": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
"integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"nan": {
"version": "2.14.2",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
"integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ=="
},
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
},
"node-expat": {
"version": "2.3.18",
"resolved": "https://registry.npmjs.org/node-expat/-/node-expat-2.3.18.tgz",
"integrity": "sha512-9dIrDxXePa9HSn+hhlAg1wXkvqOjxefEbMclGxk2cEnq/Y3U7Qo5HNNqeo3fQ4bVmLhcdt3YN1TZy7WMZy4MHw==",
"requires": {
"bindings": "^1.5.0",
"nan": "^2.13.2"
}
},
"normalize-url": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
"integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ=="
},
"nth-check": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz",
"integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==",
"requires": {
"boolbase": "^1.0.0"
}
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"requires": {
"ee-first": "1.1.1"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"p-cancelable": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz",
"integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg=="
},
"parse5": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
},
"parse5-htmlparser2-tree-adapter": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
"integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
"requires": {
"parse5": "^6.0.1"
}
},
"parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
},
"path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"proxy-addr": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
"integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
"requires": {
"forwarded": "~0.1.2",
"ipaddr.js": "1.9.1"
}
},
"psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
},
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"qs": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
},
"quick-lru": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="
},
"range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
},
"raw-body": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
"requires": {
"bytes": "3.1.0",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
}
},
"resolve-alpn": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.0.0.tgz",
"integrity": "sha512-rTuiIEqFmGxne4IovivKSDzld2lWW9QCjqv80SYjPgf+gS35eaCAjaP54CCwGAwBtnCsvNLYtqxe1Nw+i6JEmA=="
},
"responselike": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz",
"integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==",
"requires": {
"lowercase-keys": "^2.0.0"
}
},
"rss-to-json": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/rss-to-json/-/rss-to-json-1.1.2.tgz",
"integrity": "sha512-88J6yuApSgYL7eU7fNMDNVp3K7za/Bp2cj9Mjh0flDqChX6WG8f6OLJHqBeuxcvQjxTVALUPz82MGJMAATZplg==",
"requires": {
"axios": "^0.21.0",
"xml2json": "^0.12.0"
}
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"send": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
"integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
"requires": {
"debug": "2.6.9",
"depd": "~1.1.2",
"destroy": "~1.0.4",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "~1.7.2",
"mime": "1.6.0",
"ms": "2.1.1",
"on-finished": "~2.3.0",
"range-parser": "~1.2.1",
"statuses": "~1.5.0"
},
"dependencies": {
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}
}
},
"serve-static": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
"integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
"requires": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.17.1"
}
},
"setimmediate": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
},
"setprototypeof": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
},
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
"string.fromcodepoint": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/string.fromcodepoint/-/string.fromcodepoint-0.2.1.tgz",
"integrity": "sha1-jZeDM8C8klOPUPOD5IiPPlYZ1lM="
},
"string.prototype.codepointat": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz",
"integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg=="
},
"toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
},
"topo": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz",
"integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==",
"requires": {
"hoek": "6.x.x"
},
"dependencies": {
"hoek": {
"version": "6.1.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz",
"integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ=="
}
}
},
"tough-cookie": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz",
"integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==",
"requires": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
"universalify": "^0.1.2"
}
},
"type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"requires": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
}
},
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"xml2json": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/xml2json/-/xml2json-0.12.0.tgz",
"integrity": "sha512-EPJHRWJnJUYbJlzR4pBhZODwWdi2IaYGtDdteJi0JpZ4OD31IplWALuit8r73dJuM4iHZdDVKY1tLqY2UICejg==",
"requires": {
"hoek": "^4.2.1",
"joi": "^13.1.2",
"node-expat": "^2.3.18"
}
}
}
}

@ -1,10 +1,12 @@
{
"name": "aruppi",
"version": "3.4.1",
"version": "4.0.0",
"description": "Aruppi is a custom API to obtain data from the Japanese culture for the mobile app",
"main": "./src/api/api.js",
"main": "./src/api/api.ts",
"scripts": {
"start": "node src/index.js"
"start": "node ./dist/server.js",
"dev": "tsnd --transpile-only --ignore-watch node_modules --respawn src/server.ts",
"build": "tsc -p ."
},
"keywords": [
"aruppi",
@ -46,10 +48,31 @@
"cheerio": "^1.0.0-rc.5",
"compose-middleware": "^5.0.1",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"got": "^11.8.1",
"helmet": "^4.3.1",
"helmet": "^4.4.1",
"mongodb": "^3.6.4",
"rss-to-json": "^1.1.2",
"tough-cookie": "^4.0.0"
"tough-cookie": "^4.0.0",
"ts-node-dev": "^1.1.1"
},
"devDependencies": {
"@types/cors": "^2.8.10",
"@types/express": "^4.17.11",
"@types/got": "^9.6.11",
"@types/node": "^14.14.31",
"@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",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-prettier": "^3.3.1",
"prettier": "^2.2.1",
"ts-node": "^9.1.1",
"typescript": "^4.2.2"
}
}
}

@ -1,588 +0,0 @@
const rss = require('rss-to-json');
const {
homgot
} = require('../api/apiCall');
const {
jkanimeInfo,
animeflvInfo,
getAnimeCharacters,
getAnimeVideoPromo,
animeExtraInfo,
searchAnime,
transformUrlServer,
obtainPreviewNews,
structureThemes,
videoServersJK,
getThemes,
getRelatedAnimesFLV,
getRelatedAnimesMAL,
directoryAnimes,
radioStations,
animeGenres,
animeThemes
} = require('../utils/index');
const ThemeParser = require('../utils/animetheme');
const parserThemes = new ThemeParser();
const {
BASE_ANIMEFLV_JELU, BASE_JIKAN, BASE_IVOOX, BASE_QWANT, BASE_YOUTUBE, BASE_THEMEMOE, BASE_ANIMEFLV, BASE_ARUPPI
} = require('./urls');
const schedule = async (day) => {
const data = await homgot(`${BASE_JIKAN}schedule/${day.current}`, { parse: true });
return data[day.current].map(doc => ({
title: doc.title,
malid: doc.mal_id,
image: doc.image_url
}));
};
const top = async (top) => {
let data;
if (top.subtype !== undefined) {
data = await homgot(`${BASE_JIKAN}top/${top.type}/${top.page}/${top.subtype}`, { parse: true });
} else {
data = await homgot(`${BASE_JIKAN}top/${top.type}/${top.page}`, { parse: true });
}
return data.top.map(doc => ({
rank: doc.rank,
title: doc.title,
url: doc.url,
image_url: doc.image_url,
type: top.type,
subtype: top.subtype,
page: top.page,
score: doc.score
}));
};
const getAllAnimes = async () => {
let data = await homgot(`${BASE_ANIMEFLV}api/animes/list`, { parse: true })
return data.map(item => ({
index: item[0],
animeId: item[3],
title: item[1],
id: item[2],
type: item[4]
}));
};
const getAllDirectory = async (genres) => {
if (genres === 'sfw') {
return directoryAnimes.filter(function (doc) {
if (!doc.genres.includes('Ecchi') && !doc.genres.includes('ecchi')) {
return {
id: doc.id,
title: doc.title,
mal_id: doc.mal_id,
poster: doc.poster,
type: doc.type,
genres: doc.genres,
state: doc.state,
score: doc.score,
jkanime: false,
description: doc.description
};
}
});
}
return directoryAnimes.map(doc => ({
id: doc.id,
title: doc.title,
mal_id: doc.mal_id,
poster: doc.poster,
type: doc.type,
genres: doc.genres,
state: doc.state,
score: doc.score,
jkanime: false,
description: doc.description
}));
};
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[0].url
});
});
});
return promises;
};
const getNews = async (pageRss) => {
let promises = [];
for (let i = 0; i <= pageRss.length - 1; i++) {
await rss.load(pageRss[i].url).then(rss => {
const body = JSON.parse(JSON.stringify(rss, null, 3)).items
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 (season) => {
const data = await homgot(`${BASE_JIKAN}season/${season.year}/${season.type}`, { parse: true });
return data.anime.map(doc => ({
title: doc.title,
image: doc.image_url,
genres: doc.genres.map(x => x.name)
}));
};
const allSeasons = async () => {
const data = await homgot(`${BASE_JIKAN}season/archive`, { parse: true });
return data.archive.map(doc => ({
year: doc.year,
seasons: doc.seasons,
}));
};
const laterSeasons = async () => {
const data = await homgot(`${BASE_JIKAN}season/later`, { parse: true });
return data.anime.map(doc => ({
title: doc.title,
image: doc.image_url,
malink: doc.url
}));
};
const getLastEpisodes = async () => {
const data = await homgot(`${BASE_ANIMEFLV_JELU}LatestEpisodesAdded`, { parse: true });
return await Promise.all(data.episodes.map(async (item) => ({
id: item.id,
title: item.title,
image: item.poster,
episode: item.episode,
servers: await transformUrlServer(JSON.parse(JSON.stringify(item.servers)))
})));
};
const getSpecials = async (data) => {
const res = await homgot(`${BASE_ANIMEFLV_JELU}${data.url}/${data.type}/${data.page}`, { parse: true });
return res[data.prop].map(doc => ({
id: doc.id,
title: doc.title,
type: data.url.toLowerCase(),
page: data.page,
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)
}));
};
const getMoreInfo = async (title) => {
try {
const result = directoryAnimes.filter(x => {
if (x.title === title) {
return x;
} else {
return x.title === `${title} (TV)` ? x : undefined;
}
})[0];
if (!result.jkanime) {
return {
title: result.title || null,
poster: result.poster || null,
synopsis: result.description || null,
status: result.state || null,
type: result.type || null,
rating: result.score || null,
genres: result.genres || null,
moreInfo: await animeExtraInfo(result.mal_id).then(info => info || null),
promo: await getAnimeVideoPromo(result.mal_id).then(promo => promo || null),
characters: await getAnimeCharacters(result.mal_id).then(characters => characters || null),
related: await getRelatedAnimesFLV(result.id)
};
} else {
return {
title: result.title || null,
poster: result.poster || null,
synopsis: result.description || null,
status: result.state || null,
type: result.type || null,
rating: result.score || null,
genres: result.genres || null,
moreInfo: await animeExtraInfo(result.mal_id).then(info => info || null),
promo: await getAnimeVideoPromo(result.mal_id).then(promo => promo || null),
characters: await getAnimeCharacters(result.mal_id).then(characters => characters || null),
related: await getRelatedAnimesMAL(result.mal_id)
};
}
} catch (e) {
console.log(e);
}
};
const getEpisodes = async (title) => {
try {
const result = directoryAnimes.filter(x => {
if (x.title === title) {
return x;
} else {
return x.title === `${title} (TV)` ? x : undefined;
}
})[0];
if (!result.jkanime) {
return await animeflvInfo(result.id).then(episodes => episodes || null);
} else {
return await jkanimeInfo(result.id).then(episodes => episodes || null);
}
} catch (e) {
console.log(e);
}
};
const getAnimeServers = async (id) => {
if (isNaN(id.split('/')[0])) {
return await videoServersJK(id);
} else {
const data = await homgot(`${BASE_ANIMEFLV_JELU}GetAnimeServers/${id}`, { parse: true });
return await transformUrlServer(data.servers);
}
};
const search = async (title) => { return await searchAnime(title); };
const getImages = async (query) => {
try {
const data = await homgot(`${BASE_QWANT}count=${query.count}&q=${query.title}&t=${query.type}&safesearch=${query.safesearch}&locale=${query.country}&uiv=4`, { parse: true });
return data.data.result.items.map(doc => ({
type: doc.thumb_type,
thumbnail: `https:${doc.thumbnail}`,
fullsize: `https:${doc.media_fullsize}`
}));
} catch (e) {
console.log(e)
}
};
const getYoutubeVideos = async (channelId) => {
const data = await homgot(`${BASE_YOUTUBE}${channelId.id}&part=${channelId.part}&order=${channelId.order}&maxResults=${channelId.maxResults}`, { parse: true });
return data[channelId.prop].map(doc => ({
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
}));
};
const getSectionYoutubeVideos = async (type) => {
if (type === 'learn') {
let data = await homgot(`${BASE_YOUTUBE}UCCyQwSS6m2mVB0-H2FOFJtw&part=snippet,id&order=date&maxResults=50`, { parse: true });
return data.items.map(doc => ({
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
}));
} else if (type === 'amv') {
let yt1 = await homgot(`${BASE_YOUTUBE}UCkTFkshjAsLMKwhAe1uPC1A&part=snippet,id&order=date&maxResults=25`, { parse: true });
let yt2 = await homgot(`${BASE_YOUTUBE}UC2cpvlLeowpqnR6bQofwNew&part=snippet,id&order=date&maxResults=25`, { parse: true });
return yt1.items.concat(yt2.items).map(doc => ({
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
}));
} else if (type === 'produccer') {
let yt1 = await homgot(`${BASE_YOUTUBE}UC-5MT-BUxTzkPTWMediyV0w&part=snippet,id&order=date&maxResults=25`, { parse: true });
let yt2 = await homgot(`${BASE_YOUTUBE}UCwUeTOXP3DD9DIvHttowuSA&part=snippet,id&order=date&maxResults=25`, { parse: true });
let yt3 = await homgot(`${BASE_YOUTUBE}UCA8Vj7nN8bzT3rsukD2ypUg&part=snippet,id&order=date&maxResults=25`, { parse: true });
return yt1.items.concat(yt2.items.concat(yt3.items)).map(doc => ({
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
}));
}
};
const getRadioStations = async () => radioStations;
const getOpAndEd = async (title) => await structureThemes(await parserThemes.serie(title), 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 data = await homgot(`${BASE_THEMEMOE}roulette`, { parse: true });
let themes = await getThemes(data.themes);
return themes.map(doc => ({
name: data.name,
title: doc.name,
link: doc.video
}));
};
const getArtist = async (id) => {
if (id === undefined) {
return await parserThemes.artists();
} else {
return await structureThemes(await parserThemes.artist(id), false)
}
};
const getAnimeGenres = async (genres) => {
let res;
let promises = [];
if (genres.genre === undefined && genres.page === undefined && genres.order === undefined) {
return animeGenres;
} else {
if (genres.page !== undefined) {
res = await homgot(`${BASE_ANIMEFLV_JELU}Genres/${genres.genre}/${genres.order}/${genres.page}`, { parse: true })
} else {
res = await homgot(`${BASE_ANIMEFLV_JELU}Genres/${genres.genre}/${genres.order}/1`, { parse: true })
}
let data = res.animes
for (let i = 0; i <= data.length - 1; i++) {
promises.push({
id: data[i].id || null,
title: data[i].title.trim() || null,
mention: genres.genre,
page: genres.page,
poster: data[i].poster || null,
banner: data[i].banner || null,
synopsis: data[i].synopsis || null,
type: data[i].type || null,
rating: data[i].rating || null,
genre: data[i].genres
})
}
return promises;
}
};
const getAllThemes = async () => animeThemes;
const getDestAnimePlatforms = async () => {
let data = await homgot(`${BASE_ARUPPI}res/documents/animelegal/top.json`, { parse: true });
return data.map(doc => ({
id: doc.id,
name: doc.name,
logo: doc.logo,
link: doc.link
}));
};
const getPlatforms = async (id) => {
let data;
if (id === undefined) {
data = await homgot(`${BASE_ARUPPI}res/documents/animelegal/typeplatforms.json`, { parse: true });
return data.map(doc => ({
id: doc.id,
name: doc.name,
comming: doc.comming || false,
cover: doc.cover
}));
} if (id === "producers" || id === "apps" || id === "publishers" || "events") {
data = await homgot(`${BASE_ARUPPI}res/documents/animelegal/type/${id}.json`, { parse: true });
return data.map(doc => ({
id: doc.id,
name: doc.name,
logo: doc.logo,
cover: doc.cover,
description: doc.description,
type: doc.type,
moreInfo: doc.moreInfo,
facebook: doc.facebook,
twitter: doc.twitter,
instagram: doc.instagram,
webInfo: doc.webInfo,
webpage: doc.webpage
}));
} else {
data = await homgot(`${BASE_ARUPPI}res/documents/animelegal/type/${id}.json`, { parse: true });
return data.map(doc => ({
id: doc.id,
name: doc.name,
type: doc.type,
logo: doc.logo,
cover: doc.cover,
webpage: doc.webpage,
}));
}
};
const getProfilePlatform = async (id) => {
let data = await homgot(`${BASE_ARUPPI}res/documents/animelegal/platforms/${id}.json`, { parse: true });
let channelId = { id: data[0].youtubeId, part: 'snippet,id', order: 'date', maxResults: '50', prop: 'items' };
let videos = await getYoutubeVideos(channelId)
return data.map(doc => ({
id: doc.id,
name: doc.name,
logo: doc.logo,
cover: doc.cover,
category: doc.category,
description: doc.description,
facebook: doc.facebook,
twitter: doc.twitter,
instagram: doc.instagram,
webpage: doc.webpage,
simulcast: doc.simulcast,
paid: doc.paid,
shop: doc.shop,
faq: doc.faq,
videos: videos
}));
};
async function getRandomAnime() {
const randomNumber = Math.floor(Math.random() * directoryAnimes.length);
let result = directoryAnimes[randomNumber];
if (!result.jkanime) {
return {
title: result.title || null,
poster: result.poster || null,
synopsis: result.description || null,
status: result.state || null,
type: result.type || null,
rating: result.score || null,
genres: result.genres || null,
moreInfo: await animeExtraInfo(result.mal_id).then(info => info || null),
promo: await getAnimeVideoPromo(result.mal_id).then(promo => promo || null),
characters: await getAnimeCharacters(result.mal_id).then(characters => characters || null),
related: await getRelatedAnimesFLV(result.id)
};
} else {
return {
title: result.title || null,
poster: result.poster || null,
synopsis: result.description || null,
status: result.state || null,
type: result.type || null,
rating: result.score || null,
genres: result.genres || null,
moreInfo: await animeExtraInfo(result.mal_id).then(info => info || null),
promo: await getAnimeVideoPromo(result.mal_id).then(promo => promo || null),
characters: await getAnimeCharacters(result.mal_id).then(characters => characters || null),
related: await getRelatedAnimesMAL(result.mal_id)
};
}
}
module.exports = {
schedule,
top,
getAllAnimes,
getAllDirectory,
getAnitakume,
getNews,
season,
allSeasons,
laterSeasons,
getLastEpisodes,
getSpecials,
getMoreInfo,
getEpisodes,
getAnimeServers,
search,
getImages,
getYoutubeVideos,
getRadioStations,
getOpAndEd,
getThemesYear,
getRandomTheme,
getArtist,
getAnimeGenres,
getAllThemes,
getDestAnimePlatforms,
getPlatforms,
getSectionYoutubeVideos,
getProfilePlatform,
getRandomAnime
};

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

@ -1,54 +0,0 @@
const express = require('express');
const routes = require('./routes/index');
const version = require('./../../package.json').version;
const router = express.Router();
router.get('/', (req, res) => {
res.set('Cache-Control', 'no-store');
res.json({
message: 'Aruppi API - 🎏',
author: 'Jéluchu',
version: version,
credits: 'The bitch loves APIs that offers data to Aruppi App',
entries: [
{
'Schedule': '/api/v3/schedule/:day',
'Top': '/api/v3/top/:type/:subtype/:page',
'AllAnimes': '/api/v3/allAnimes',
'RandomAnime': '/api/v3/randomAnime',
'Anitakume': '/api/v3/anitakume',
'News': '/api/v3/news',
'Season': '/api/v3/season/:year/:type',
'All Seasons': '/api/v3/allSeasons',
'All Directory': '/api/v3/allDirectory/:type',
'Genres': '/api/v3/getByGenres/:genre?/:order?/:page?',
'Futures Seasons': '/api/v3/laterSeasons',
'LastEpisodes': '/api/v3/lastEpisodes',
'Movies': '/api/v3/movies/:type/:page',
'Ovas': '/api/v3/ova/:type/:page',
'Specials': '/api/v3/special/:type/:page',
'Tv': '/api/v3/tv/:type/:page',
'MoreInfo': '/api/v3/moreInfo/:title',
'GetEpisodes': '/api/v3/getEpisodes/:title',
'GetAnimeServers': '/api/v3/getAnimeServers/:id',
'Search': '/api/v3/search/:title',
'Images': '/api/v3/images/:query',
'Videos': '/api/v3/videos/:channelId',
'Type Videos': '/api/v3/sectionedVideos/:type',
'Radios': '/api/v3/radio',
'All Themes': '/api/v3/allThemes',
'Themes': '/api/v3/themes/:title',
'Year Themes': '/api/v3/themesYear/:year?',
'Random Theme': '/api/v3/randomTheme',
'Artists Theme': '/api/v3/artists/:id?',
'Famous Platforms': '/api/v3/destAnimePlatforms',
'Legal Platforms': '/api/v3/platforms/:id?'
}
]
});
});
router.use('/', routes);
module.exports = router;

@ -1,565 +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 top = {type: req.params.type, subtype: req.params.subtype, page: req.params.page}
api.top(top)
.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/:genres?' , (req, res) =>{
let genres = req.params.genres;
api.getAllDirectory(genres)
.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 season = {year: req.params.year, type: req.params.type}
api.season(season)
.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 data = {url: 'Movies', prop: 'movies', type: req.params.type, page: req.params.page }
api.getSpecials(data)
.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('/ova/:type/:page' , (req, res) =>{
let data = {url: 'Ova', prop: 'ova', type: req.params.type, page: req.params.page }
api.getSpecials(data)
.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('/special/:type/:page' , (req, res) =>{
let data = {url: 'Special', prop: 'special', type: req.params.type, page: req.params.page }
api.getSpecials(data)
.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('/tv/:type/:page' , (req, res) =>{
let data = {url: 'Tv', prop: 'tv', type: req.params.type, page: req.params.page }
api.getSpecials(data)
.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('/moreInfo/:title' , (req, res) =>{
let title = req.params.title;
api.getMoreInfo(title)
.then(info => {
if (info !== undefined) {
res.status(200).json(info);
} else {
res.status(500).json({ message: 'Aruppi lost in the shell'});
}
}).catch((err) =>{
console.error(err);
});
});
router.get('/getEpisodes/:title' , (req, res) =>{
let title = req.params.title;
api.getEpisodes(title)
.then(episodes => {
if (episodes.length > 0) {
res.status(200).json({episodes});
} else {
res.status(500).json({ message: 'Aruppi lost in the shell'});
}
}).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('/sectionedVideos/:type' , (req, res) =>{
let type = req.params.type;
api.getSectionYoutubeVideos(type)
.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) {
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;
api.getThemesYear(year)
.then(themes =>{
if (themes.length > 0) {
res.status(200).json({
themes
});
} else {
res.status(500).json({ message: 'Aruppi lost in the shell'});
}
}).catch((err) =>{
console.error(err);
});
});
router.get('/randomTheme', (req, res) =>{
api.getRandomTheme()
.then(random =>{
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'})
)
}).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 genres = { genre: req.params.genre, order: req.params.order, page: req.params.page };
api.getAnimeGenres(genres)
.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('/randomAnime', (req, res) => {
api.getRandomAnime()
.then(anime => {
if (anime) {
res.set('Cache-Control', 'no-store');
res.status(200).json(anime);
}else {
res.status(500).json({ message: 'Aruppi lost in the shell'});
}
})
.catch(error => {
console.log(error);
});
});
router.get('/destAnimePlatforms' , (req , res) =>{
api.getDestAnimePlatforms()
.then(destPlatforms =>{
if (destPlatforms.length > 0) {
res.status(200).json({
destPlatforms
});
} else (
res.status(500).json({ message: 'Aruppi lost in the shell'})
)
}).catch((err) =>{
console.error(err);
});
});
router.get('/platforms/:id?' , (req , res) =>{
let id = req.params.id;
api.getPlatforms(id)
.then(platforms =>{
if (platforms.length > 0) {
res.status(200).json({platforms});
} else (
res.status(500).json({ message: 'Aruppi lost in the shell'})
)
}).catch((err) =>{
console.error(err);
});
});
module.exports = router;

@ -1,49 +0,0 @@
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const bodyParser = require('body-parser');
const version = require('./../package.json').version;
const middlewares = require('./middlewares/index').middleware;
const api = require('./api');
const api_legacy = require('./v2/api');
const app = express();
app.use(helmet());
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.get('/', (req, res) => {
// we dont want to enforce the redirect storing, so just check
res.set('Cache-Control', 'no-cache,proxy-revalidate');
res.redirect('/api/')
});
app.get('/api/', (req, res) => {
// dont cache answer 'cause we can check upstream version
res.set('Cache-Control', 'no-store');
res.json({
title: 'Aruppi API',
version: version,
source: 'https://github.com/aruppi/aruppi-api',
description: 'This API has everything about Japan, from anime, music, radio, images, videos... to japanese culture (Spanish Only)',
powers: 'https://play.google.com/store/apps/details?id=com.jeluchu.aruppi'
});
});
app.get('/api/v1', (req, res) => {
res.set('Cache-Control', 'no-cache,proxy-revalidate');
res.json({
message: 'Sorry, version v1 is not avaiable, if you want to see content go to v2'
});
});
app.use('/api/v2', api_legacy);
app.use('/api/v3', api);
app.use(middlewares);
module.exports = app;

File diff suppressed because it is too large Load Diff

@ -1,42 +0,0 @@
[
{ "name": " Acción", "value": "accion" },
{ "name": " Artes Marciales", "value": "artes-marciales" },
{ "name": " Aventuras", "value": "aventura" },
{ "name": " Carreras", "value": "carreras" },
{ "name": " Ciencia Ficción", "value": "ciencia-ficcion" },
{ "name": " Comedia", "value": "comedia" },
{ "name": " Demencia", "value": "demencia" },
{ "name": " Demonios", "value": "demonios" },
{ "name": " Deportes", "value": "deportes" },
{ "name": " Drama", "value": "drama" },
{ "name": " Ecchi", "value": "ecchi" },
{ "name": " Escolares", "value": "escolares" },
{ "name": " Espacial", "value": "espacial" },
{ "name": " Fantasía", "value": "fantasia" },
{ "name": " Harem", "value": "harem" },
{ "name": " Historico", "value": "historico" },
{ "name": " Infantil", "value": "infantil" },
{ "name": " Josei", "value": "josei" },
{ "name": " Juegos", "value": "juegos" },
{ "name": " Magia", "value": "magia" },
{ "name": " Mecha", "value": "mecha" },
{ "name": " Militar", "value": "militar" },
{ "name": " Misterio", "value": "misterio" },
{ "name": " Música", "value": "musica" },
{ "name": " Parodia", "value": "parodia" },
{ "name": " Policía", "value": "policia" },
{ "name": " Psicológico", "value": "psicologico" },
{ "name": " Recuentos de la vida", "value": "recuentos-de-la-vida" },
{ "name": " Romance", "value": "romance" },
{ "name": " Samurai", "value": "samurai" },
{ "name": " Seinen", "value": "seinen" },
{ "name": " Shoujo", "value": "shoujo" },
{ "name": " Shounen", "value": "shounen" },
{ "name": " Sobrenatural", "value": "sobrenatural" },
{ "name": " Superpoderes", "value": "superpoderes" },
{ "name": " Suspenso", "value": "suspenso" },
{ "name": " Terror", "value": "terror" },
{ "name": " Vampiros", "value": "vampiros" },
{ "name": " Yaoi", "value": "yaoi" },
{ "name": " Yuri", "value": "yuri" }
]

@ -1,278 +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": "Radio Japan Next",
"url": "http://perseus.shoutca.st:8803/stream"
},
{
"name": "Listen Radio (J-Pop)",
"url": "https://listen.moe/stream"
},
{
"name": "Listen Radio (K-Pop)",
"url": "https://listen.moe/kpop/stream"
},
{
"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://54.37.73.148:8000/stream"
},
{
"name": "Radio Touhou",
"url": "http://www.touhouradio.com/touhouradio"
},
{
"name": "Radio MultiAnime",
"url": "http://67.20.61.70:8301"
},
{
"name": "Radio Fan World Anime",
"url": "http://184.154.45.106:8461/stream"
},
{
"name": "Radio Hot Mix",
"url": "http://hotmixradio-japan.ice.infomaniak.ch/hotmixradio-japan-128.mp3"
},
{
"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": "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 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"
}
]

File diff suppressed because it is too large Load Diff

@ -0,0 +1,114 @@
import { Request, Response } from 'express';
import { requestGot } from '../utils/requestCall';
import urls from '../utils/urls';
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;
}
export default class AnimeController {
async schedule(req: Request, res: Response) {
const { day } = req.params;
const data: any = await requestGot(`${urls.BASE_JIKAN}schedule/${day}`, {
parse: true,
scrapy: false,
});
const animeList: Schedule[] = data[day].map((doc: Schedule) => ({
title: doc.title,
mal_id: doc.mal_id,
image: doc.image_url,
}));
if (animeList.length > 0) {
res.status(200).json({
animeList,
});
} else {
res.status(500).json({ message: 'Aruppi lost in the shell' });
}
}
async top(req: Request, res: Response) {
const { type, subtype, page } = req.params;
let data: any;
try {
if (subtype !== undefined) {
data = await requestGot(
`${urls.BASE_JIKAN}top/${type}/${page}/${subtype}`,
{ parse: true, scrapy: false },
);
} else {
data = await requestGot(`${urls.BASE_JIKAN}top/${type}/${page}`, {
parse: true,
scrapy: false,
});
}
} catch (error) {
console.log(error);
return res.status(404);
}
const top: Top[] = data.top.map((item: Top) => ({
rank: item.rank,
title: item.title,
url: item.url,
image_url: item.image_url,
type: item.type,
subtype: item.subtype,
page: item.page,
score: item.score,
}));
if (top.length > 0) {
return res.status(200).json({ top });
} else {
return res.status(400).json({ message: 'Aruppi lost in the shell' });
}
}
async getAllAnimes(req: Request, res: Response) {
const data: any = await requestGot(`${urls.BASE_ANIMEFLV}api/animes/list`, {
parse: true,
scrapy: false,
});
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' });
}
}
}

@ -1,18 +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();
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,43 @@
import {
Request,
Response,
NextFunction,
ErrorRequestHandler,
RequestHandler,
} from 'express';
export const errorHandler: ErrorRequestHandler = (
err: any,
req: Request,
res: Response,
next: NextFunction,
) => {
const statusCode = res.statusCode !== 200 ? res.statusCode : 500;
res.status(statusCode);
res.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,62 @@
import { Router, Request, Response } from 'express';
import AnimeController from './controllers/AnimeController';
const routes = Router();
const animeController = new AnimeController();
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/');
});
routes.get('/api/', (req: Request, res: Response) => {
res.set('Cache-Control', 'no-store');
res.json({
message: 'Aruppi API - 🎏',
author: 'Jéluchu',
version: '4.0.0',
credits: 'The bitch loves APIs that offers data to Aruppi App',
entries: [
{
Schedule: '/api/schedule/:day',
Top: '/api/top/:type/:page/:subtype',
AllAnimes: '/api/ allAnimes',
RandomAnime: '/api/randomAnime',
Anitakume: '/api/anitakume',
News: '/api/news',
Season: '/api/season/:year/:type',
'All Seasons': '/api/allSeasons',
'All Directory': '/api/allDirectory/:type',
Genres: '/api/getByGenres/:genre?/:order?/:page?',
'Futures Seasons': '/api/laterSeasons',
LastEpisodes: '/api/lastEpisodes',
Movies: '/api/movies/:type/:page',
Ovas: '/api/ova/:type/:page',
Specials: '/api/special/:type/:page',
Tv: '/api/tv/:type/:page',
MoreInfo: '/api/moreInfo/:title',
GetEpisodes: '/api/getEpisodes/:title',
GetAnimeServers: '/api/getAnimeServers/:id',
Search: '/api/search/:title',
Images: '/api/images/:query',
Videos: '/api/videos/:channelId',
'Type Videos': '/api/sectionedVideos/:type',
Radios: '/api/radio',
'All Themes': '/api/allThemes',
Themes: '/api/themes/:title',
'Year Themes': '/api/themesYear/:year?',
'Random Theme': '/api/randomTheme',
'Artists Theme': '/api/artists/:id?',
'Famous Platforms': '/api/destAnimePlatforms',
'Legal Platforms': '/api/platforms/:id?',
},
],
});
});
routes.get('/api/schedule/:day', animeController.schedule);
routes.get('/api/top/:type/:page/:subtype?/', animeController.top);
routes.get('/api/allAnimes', animeController.getAllAnimes);
export default routes;

@ -0,0 +1,20 @@
import express, { Application } from 'express';
import cors from 'cors';
import helmet from 'helmet';
import dotenv from 'dotenv';
import { errorHandler, notFound } from './middlewares/middleware';
import routes from './routes';
const app: Application = express();
dotenv.config();
app.use(cors());
app.use(helmet());
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(routes);
app.use(errorHandler);
app.use(notFound);
// Starting to listen the server in port
app.listen(process.env.PORT || 3000);

@ -1,307 +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) {
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) {
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) {
try {
this.animes = [];
this.$ = await redditocall(`artist/${id}`);
return await this.parseArtist();
}
catch(err) {
console.log(err);
}
}
async random(query) {
try {
this.animes = [];
this.$ = await redditocall('anime_index');
return await this.parseRandom(query);
}
catch(err) {
console.log(err);
}
}
async year(date) {
let animes = [];
this.$ = await redditocall(date);
this.$('h3').each((index, 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 = '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 = [];
this.$('h3 a').each((index, 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 => 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) {
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) {
let el = this.$(element).find('a');
let title = this.$(el).text();
let mal_id = this.$(el).attr('href').split('/')[4];
let next = this.$(element).next();
let theme = {
id: 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) {
if (this.$(element).prop('tagName') !== "TABLE") {
return this.parseTable(this.$(element).next());
}
let themes = [];
this.$(element).find('tbody').find('tr').each((i, elem) => {
let name = replaceAll(this.$(elem).find('td').eq(0).text(), '&quot;', '"');
let link = this.$(elem).find('td').eq(1).find('a').attr('href');
let linkDesc = this.$(elem).find('td').eq(1).find('a').text();
let episodes = this.$(elem).find('td').eq(2).text().length > 0 ? this.$(elem).find('td').eq(2).text() : "";
let notes = this.$(elem).find('td').eq(3).text().length > 0 ? this.$(elem).find('td').eq(3).text() : "";
themes.push({
name,
link,
desc: linkDesc,
type: name.startsWith('OP') ? 'Opening' : name.startsWith('ED') ? 'Ending' : 'OP/ED',
episodes,
notes
});
});
return themes;
}
}
async function redditocall(href) {
let resp = await homgot(REDDIT_ANIMETHEMES + href + ".json", { parse: true });
return cheerio.load(getHTML(resp.data.content_html));
}
function getHTML(str) {
let html = replaceAll(str, "&lt;", "<");
html = replaceAll(html, "&gt;", ">");
return html;
}
function replaceAll(str, find, replace) {
return str.replace(new RegExp(find, 'g'), replace);
}
module.exports = ThemeParser;

@ -1,553 +0,0 @@
const {
BASE_ANIMEFLV, BASE_JIKAN, BASE_ARUPPI, BASE_JKANIME
} = require('../api/urls');
const {
homgot
} = require('../api/apiCall');
const directoryAnimes = JSON.parse(JSON.stringify(require('../assets/directory.json')));
const radioStations = require('../assets/radiostations.json');
const animeGenres = require('../assets/genres.json');
const animeThemes = require('../assets/themes.json');
function btoa(str) {
let buffer;
if (str instanceof Buffer) {
buffer = str;
}
else {
buffer = Buffer.from(str.toString(), 'binary');
}
return buffer.toString('base64');
}
global.btoa = btoa;
async function videoServersJK(id) {
const $ = await homgot(`${BASE_JKANIME}${id}`, { scrapy: true });
let servers = {};
let script;
const serverNames = $('div#reproductor-box li').map((index, element) => {
return $(element).find('a').text();
}).get();
$('script').each((index, element) => {
if ($(element).html().includes('var video = [];')) {
script = $(element).html();
}
});
try {
let videoUrls = script.match(/(?<=src=").*?(?=[\*"])/gi);
for (let i = 0; i < serverNames.length; i++) {
servers[serverNames[i]] = videoUrls[i];
}
} catch (err) {
console.log(err);
return null;
}
let serverList = [];
for (let server in servers) {
if (serverNames[serverNames.indexOf(server)].toLowerCase() === 'desu') {
serverList.push({
id: serverNames[serverNames.indexOf(server)].toLowerCase(),
url: await desuServerUrl(servers[server]) !== null ? await desuServerUrl(servers[server]) : servers[server],
direct: true
});
}else {
serverList.push({
id: serverNames[serverNames.indexOf(server)].toLowerCase(),
url: servers[server],
direct: true
});
}
}
serverList = serverList.filter(x => x.id !== 'xtreme s' && x.id !== 'desuka');
return serverList;
}
async function desuServerUrl(url) {
const $ = await homgot(url, { scrapy: true});
let script;
$('script').each((index, element) => {
if ($(element).html().includes('var parts = {')) {
if ($(element).html()) {
script = $(element).html();
}else {
return null;
}
}
});
let result = script.match(/swarmId: '(https:\/\/\S+)'/gi)
.toString()
.split('\'')[1];
return result;
}
const jkanimeInfo = async (id) => {
let $ = await homgot(`${BASE_JKANIME}${id}`, { scrapy: true });
let nextEpisodeDate;
let rawNextEpisode = $('div[id="container"] div.left-container div[id="proxep"] p')[0];
if (rawNextEpisode === undefined) {
nextEpisodeDate = null;
} else {
if (rawNextEpisode.children[1].data === ' ') {
nextEpisodeDate = null;
} else {
nextEpisodeDate = rawNextEpisode.children[1].data.trim();
}
}
const eps_temp_list = [];
let episodes_aired = '';
$('div#container div.left-container div.navigation a').each(async (index, element) => {
const $element = $(element);
const total_eps = $element.text();
eps_temp_list.push(total_eps);
});
try { episodes_aired = eps_temp_list[0].split('-')[1].trim(); } catch (err) { }
const animeListEps = [{ nextEpisodeDate: nextEpisodeDate }];
for (let i = 1; i <= episodes_aired; i++) {
let episode = i;
let animeId = $('div[id="container"] div.content-box div[id="episodes-content"]')[0].children[1].children[3].attribs.src.split('/')[7].split('.jpg')[0];
let link = `${animeId}/${episode}`
animeListEps.push({
episode: episode,
id: link
})
}
return animeListEps;
};
function getPosterAndType(id, mal_id) {
if (id) {
for (let anime of directoryAnimes) {
if (anime.id === id) {
return [
anime.poster,
anime.type
];
}
}
}
if (mal_id) {
for (let anime of directoryAnimes) {
if (anime.mal_id === parseInt(mal_id)) {
return [
anime.poster,
anime.type
];
}
}
}
return "";
}
async function getRelatedAnimesFLV(id) {
const $ = await homgot(`${BASE_ANIMEFLV}/anime/${id}`, { scrapy: true });
let listRelated = {};
let relatedAnimes = [];
if ($('ul.ListAnmRel').length) {
$('ul.ListAnmRel li a').each((index, element) => {
listRelated[$(element).text()] = $(element).attr('href');
});
for (related in listRelated) {
let posterUrl = getPosterAndType(listRelated[related].split('/')[2], false);
relatedAnimes.push(
{
title: related,
type: posterUrl[1],
poster: posterUrl[0]
}
);
}
return relatedAnimes;
}else {
return [];
}
}
async function getRelatedAnimesMAL(mal_id) {
const $ = await homgot(`https://myanimelist.net/anime/${mal_id}`, { scrapy: true });
let listRelated = {};
let relatedAnimes = [];
if ($('table.anime_detail_related_anime').length > 0) {
$('table.anime_detail_related_anime').find('tbody tr').each((index, element) => {
if ($(element).find('td').eq(0) !== 'Adaptation:') {
listRelated[$(element).find('td').eq(1).text()] = $(element).find('td').children('a').attr('href');
}
});
for (related in listRelated) {
let posterUrl = getPosterAndType(false, listRelated[related].split('/')[2]);
if (posterUrl !== "") {
relatedAnimes.push(
{
title: related,
type: posterUrl[1],
poster: posterUrl[0]
}
);
}
}
return relatedAnimes;
}else {
return [];
}
}
const animeflvGenres = async (id) => {
let $ = await homgot(`${BASE_ANIMEFLV}/${id}`, { scrapy: true });
$('main.Main section.WdgtCn nav.Nvgnrs a').each((index, element) => {
return $(element).attr('href').split('=')[1] || null;
});
}
const animeflvInfo = async (id) => {
let $ = await homgot(`${BASE_ANIMEFLV}/anime/${id}`, { scrapy: true });
let scripts = $('script').toArray();
const anime_info_ids = [];
const anime_eps_data = [];
for (let script of scripts) {
const contents = $(script).html();
if ((contents || '').includes('var anime_info = [')) {
let anime_info = contents.split('var anime_info = ')[1].split(';\n')[0];
let dat_anime_info = JSON.parse(anime_info);
anime_info_ids.push(dat_anime_info);
}
if ((contents || '').includes('var episodes = [')) {
let episodes = contents.split('var episodes = ')[1].split(';')[0];
let eps_data = JSON.parse(episodes);
anime_eps_data.push(eps_data);
}
}
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] of Object.entries(anime_eps_data)) {
let episode = anime_eps_data[key].map(x => x[0]);
let episodeId = anime_eps_data[key].map(x => x[1]);
amimeTempList.push(episode, episodeId);
}
const animeListEps = [{ nextEpisodeDate: nextEpisodeDate }];
for (let i = 0; i < amimeTempList[1].length; i++) {
let data = amimeTempList.map(x => x[i]);
let episode = data[0];
let id = data[1];
let link = `${id}/${animeId}-${episode}`
animeListEps.push({
episode: episode,
id: link,
});
}
return animeListEps;
};
const getAnimeCharacters = async(mal_id) =>{
let data;
try {
data = await homgot(`${BASE_JIKAN}anime/${mal_id}/characters_staff`, { parse: true });
}catch(error) {
console.log(error);
}
if(data !== null) {
return data.characters.map(doc => ({
id: doc.mal_id,
name: doc.name,
image: doc.image_url,
role: doc.role
}));
}
};
const getAnimeVideoPromo = async(mal_id) =>{
let data;
try {
data = await homgot(`${BASE_JIKAN}anime/${mal_id}/videos`, {parse: true});
}catch(error) {
console.log(error);
}
if(data !== null) {
return data.promo.map(doc => ({
title: doc.title,
previewImage: doc.image_url,
videoURL: doc.video_url
}));
}
};
const animeExtraInfo = async (mal_id) => {
const data = await homgot(`${BASE_JIKAN}anime/${mal_id}`, { parse: true });
try {
if(data !== null) {
let promises = [];
let broadcast = '';
Array(data).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'
};
if (doc.broadcast === null) {
broadcast = null
} else {
broadcast = airDay[doc.broadcast.split('at')[0].replace(" ", "").toLowerCase()]
}
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: broadcast,
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);
}
} catch (err) {
console.log(err);
}
};
const imageUrlToBase64 = async (url) => {
let img = await homgot(url)
return img.rawBody.toString('base64');
};
const searchAnime = async (query) => {
let queryLowerCase = query.toLowerCase();
const res = directoryAnimes.filter(x => x.title.toLowerCase().includes(queryLowerCase));
return res.map(doc => ({
id: doc.id || null,
title: doc.title || null,
type: doc.type || null,
image: doc.poster || null
}));
};
const transformUrlServer = async (urlReal) => {
for (const data of urlReal) {
if (data.server === 'amus' || data.server === 'natsuki') {
let res = await homgot(data.code.replace("embed", "check"), { parse: true });
data.code = res.file || null;
data.direct = true;
}
}
return urlReal.map(doc => ({
id: doc.title.toLowerCase(),
url: doc.code,
direct: doc.direct || false
}));
}
const obtainPreviewNews = (encoded) => {
let image;
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 = `${BASE_ARUPPI}news/${number}.png`
}
return image;
}
/* - StructureThemes
This function only parses the theme/themes
if indv is true, then only return a object, if it's false
then returns a array with the themes selected.
*/
const structureThemes = async (body, indv) => {
let themes = [];
if (indv === true) {
return {
title: body.title,
year: body.year,
themes: await getThemesData(body.themes)
};
} else {
for (let i = 0; i <= body.length - 1; i++) {
themes.push({
title: body[i].title,
year: body[i].year,
themes: await getThemesData(body[i].themes),
});
}
return themes;
}
};
/* - GetThemesData
Get the themes from the object and
format to a new array of items where
these items are formatted better.
*/
const getThemesData = async (themes) => {
let items = [];
for (let i = 0; i <= themes.length - 1; i++) {
items.push({
title: themes[i].name.split('"')[1] || 'Remasterización',
type: themes[i].type,
episodes: themes[i].episodes !== "" ? themes[i].episodes : null,
notes: themes[i].notes !== "" ? themes[i].notes : null,
video: themes[i].link
});
}
return items.filter(x => x.title !== 'Remasterización');
};
const getThemes = async (themes) => {
return themes.map(doc => ({
name: doc.themeName,
type: doc.themeType,
video: doc.mirror.mirrorURL
}));
};
module.exports = {
jkanimeInfo,
animeflvGenres,
animeflvInfo,
getAnimeCharacters,
getAnimeVideoPromo,
getRelatedAnimesFLV,
getRelatedAnimesMAL,
animeExtraInfo,
imageUrlToBase64,
searchAnime,
transformUrlServer,
obtainPreviewNews,
structureThemes,
getThemes,
videoServersJK,
directoryAnimes,
radioStations,
animeGenres,
animeThemes
}

@ -0,0 +1,28 @@
import got from 'got';
import cheerio from 'cheerio';
import { CookieJar } from 'tough-cookie';
const cookieJar = new CookieJar();
interface Options {
scrapy: boolean;
parse: boolean;
}
export const requestGot = async (
url: string,
options: Options,
): Promise<any> => {
if (options !== undefined) {
if (options.scrapy) {
const response = await got(url, { cookieJar });
return await cheerio.load(response.body);
}
if (options.parse) {
return await got(url, { cookieJar }).json();
}
} else {
return await got.get(url, { cookieJar });
}
};

@ -1,11 +1,12 @@
module.exports = {
export default {
BASE_ARUPPI: 'https://aruppi.jeluchu.xyz/',
BASE_ANIMEFLV: 'https://animeflv.net/',
BASE_JKANIME: 'https://jkanime.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_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/',
@ -16,5 +17,5 @@ module.exports = {
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/',
BASE_THEMEMOE: 'https://themes.moe/api/'
BASE_THEMEMOE: 'https://themes.moe/api/',
};

@ -1,469 +0,0 @@
const rss = require('rss-to-json');
const {
homgot
} = require('./apiCall');
const {
jkanimeInfo,
animeflvGenres,
animeflvInfo,
imageUrlToBase64,
getAnimeCharacters,
getAnimeVideoPromo,
animeExtraInfo,
searchAnime,
transformUrlServer,
obtainPreviewNews,
structureThemes,
videoServersJK,
getAnimes,
getDirectory,
getThemes,
directoryAnimes,
radioStations,
animeGenres,
animeThemes
} = require('../utils');
const ThemeParser = require('../utils/animetheme');
const parserThemes = new ThemeParser();
const {
BASE_ANIMEFLV_JELU, BASE_JIKAN, BASE_IVOOX, BASE_QWANT, BASE_YOUTUBE, GENRES_URL, BASE_THEMEMOE
} = 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 (genres) =>{ return await getDirectory(genres); };
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 () =>{
const data = await homgot(`${BASE_ANIMEFLV_JELU}LatestEpisodesAdded`, { parse: true });
return await Promise.all(data.episodes.map(async (item) => ({
id: item.id,
title: item.title,
image: item.poster,
episode: item.episode,
servers: await transformUrlServer(JSON.parse(JSON.stringify(item.servers)))
})));
};
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) =>{
try {
const promises = [];
const res = directoryAnimes.filter(x => {
if (x.title === title) {
return x;
} else {
return x.title === `${title} (TV)` ? x : undefined;
}
})[0];
if (!res.jkanime) {
promises.push({
title: res.title || null,
poster: res.poster || null,
synopsis: res.description || null,
status: res.state || null,
type: res.type || null,
rating: res.score || null,
genres: res.genres || null,
episodes: await animeflvInfo(res.id).then(episodes => episodes || null),
moreInfo: await animeExtraInfo(res.mal_id).then(info => info || null),
promo: await getAnimeVideoPromo(res.mal_id).then(promo => promo || null),
characters: await getAnimeCharacters(res.mal_id).then(characters => characters || null)
});
} else {
promises.push({
title: res.title || null,
poster: res.poster || null,
synopsis: res.description || null,
status: res.state || null,
type: res.type || null,
rating: res.score || null,
genres: res.genres || null,
episodes: await jkanimeInfo(res.id).then(episodes => episodes || null),
moreInfo: await animeExtraInfo(res.mal_id).then(info => info || null),
promo: await getAnimeVideoPromo(res.mal_id).then(promo => promo || null),
characters: await getAnimeCharacters(res.mal_id).then(characters => characters || null)
});
}
return promises;
} catch (e) {
console.log(e)
}
};
const getAnimeServers = async (id) => {
if (isNaN(id.split('/')[0])) {
return await videoServersJK(id)
} else {
const data = await homgot(`${BASE_ANIMEFLV_JELU}GetAnimeServers/${id}`, { parse: true });
return await transformUrlServer(data.servers);
}
};
const search = async (title) =>{ return await searchAnime(title); };
const getImages = async (query) => {
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 radioStations;
}
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 options = { parse: true }
const data = await homgot(`${BASE_THEMEMOE}roulette`, options);
let themes = await getThemes(data.themes)
promise.push({
name: data.name,
title: themes[0].name,
link: themes[0].video
});
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(animeflvGenres(id).then(async genres => ({
id: id || null,
title: title || null,
poster: await imageUrlToBase64(poster) || null,
banner: banner || null,
synopsis: synopsis || null,
type: type || null,
rating: rating || null,
genres: genres || null
})))
})
return Promise.all(promises);
};
const getAllThemes = async () => animeThemes;
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,27 +0,0 @@
const got = require('got');
const cheerio = require('cheerio');
const { CookieJar} = require('tough-cookie');
const cookieJar = new CookieJar();
let response
let data
const homgot = async (url, options) => {
if (options !== undefined) {
if (options.scrapy) {
response = await got(url, { cookieJar })
data = await cheerio.load(response.body)
}
if (options.parse) {
data = await got(url, { cookieJar }).json()
}
} else {
data = await got.get(url, { cookieJar });
}
return data
}
module.exports = {homgot}

@ -1,49 +0,0 @@
const express = require('express');
const routes = require('./routes/index');
const router = express.Router();
router.get('/', (req, res) => {
res.set('Cache-Control', 'no-store');
res.json({
message: 'Aruppi API - 🎏',
author: 'Jéluchu',
version: '2.6.9',
credits: 'The bitch loves APIs that offers data to Aruppi App',
deprecated: 'This version will be available until users migrate to Aruppi App v1.5.0',
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,503 +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/:genres?' , (req, res) =>{
let genres = req.params.genres;
api.getAllDirectory(genres)
.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.set('Cache-Control', 'no-store');
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,20 +0,0 @@
module.exports = {
BASE_ARUPPI: 'https://aruppi.jeluchu.xyz/',
BASE_ANIMEFLV: 'https://animeflv.net/',
BASE_JKANIME: 'https://jkanime.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',
ANIMEFLV_SEARCH: 'https://animeflv.net/browse?',
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/',
BASE_THEMEMOE: 'https://themes.moe/api/'
};

@ -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"
}
]

@ -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(), "&quot;", "\"")
let linkEl = td.eq(1).children().first();
let link = linkEl.attr('href');
let linkDesc = linkEl.text();
let episodes = td.eq(2).text();
let notes = td.eq(3).text();
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, "&lt;", "<")
html = replaceAll(html, "&gt;", ">")
return html;
}
function replaceAll(str, find, replace) {
return str.replace(new RegExp(find, 'g'), replace);
}
module.exports = ThemeParser;

@ -1,528 +0,0 @@
const {
BASE_ANIMEFLV, BASE_JIKAN, BASE_EPISODE_IMG_URL, BASE_ARUPPI, ANIMEFLV_SEARCH, BASE_JKANIME
} = require('../api/urls.js');
const {
homgot
} = require('../api/apiCall.js');
const directoryAnimes = JSON.parse(JSON.stringify(require('../../assets/directory.json')));
const radioStations = require('../../assets/radiostations.json');
const animeGenres = require('../../assets/genres.json');
const animeThemes = require('../../assets/themes.json');
function btoa(str) {
let buffer;
if (str instanceof Buffer) {
buffer = str;
}
else {
buffer = Buffer.from(str.toString(), 'binary');
}
return buffer.toString('base64');
}
global.btoa = btoa;
async function videoServersJK(id) {
const $ = await homgot(`${BASE_JKANIME}${id}`, { scrapy: true });
const scripts = $('script');
const episodes = $('div#reproductor-box li');
const serverNames = [];
let servers = [];
episodes.each((index, element) => serverNames.push($(element).find('a').text()))
for (let i = 0; i < scripts.length; i++) {
try {
const contents = $(scripts[i]).html();
if ((contents || '').includes('var video = [];')) {
Array.from({ length: episodes.length }, (v, k) => {
let index = Number(k + 1);
let videoPageURL = contents.split(`video[${index}] = \'<iframe class="player_conte" src="`)[1].split('"')[0];
servers.push({ iframe: videoPageURL });
});
}
} catch (err) {
console.log(err)
return null;
}
}
let serverList = [];
for (let server in servers) {
serverList.push({
id: serverNames[server].toLowerCase(),
url: servers[server].iframe,
direct: false
});
}
serverList = serverList.filter(x => x.id !== 'xtreme s' && x.id !== 'desuka');
return await Promise.all(serverList);
}
async function getVideoURL(url) {
const $ = await homgot(url, { scrapy: true });
const video = $('video');
if (video.length) {
const src = $(video).find('source').attr('src');
return src || null;
}
else {
const scripts = $('script');
const l = global;
const ll = String;
const $script2 = $(scripts[1]).html();
eval($script2);
return l.ss || null;
}
}
const jkanimeInfo = async (id) => {
let $ = await homgot(`${BASE_JKANIME}${id}`, { scrapy: true });
let nextEpisodeDate
let rawNextEpisode = $('div[id="container"] div.left-container div[id="proxep"] p')[0]
if (rawNextEpisode === undefined) {
nextEpisodeDate = null
} else {
if (rawNextEpisode.children[1].data === ' ') {
nextEpisodeDate = null
} else {
nextEpisodeDate = rawNextEpisode.children[1].data.trim()
}
}
const eps_temp_list = [];
let episodes_aired = '';
$('div#container div.left-container div.navigation a').each(async (index, element) => {
const $element = $(element);
const total_eps = $element.text();
eps_temp_list.push(total_eps);
})
try { episodes_aired = eps_temp_list[0].split('-')[1].trim(); } catch (err) { }
const animeListEps = [{ nextEpisodeDate: nextEpisodeDate }];
for (let i = 1; i <= episodes_aired; i++) {
let episode = i;
let animeId = $('div[id="container"] div.content-box div[id="episodes-content"]')[0].children[1].children[3].attribs.src.split('/')[7].split('.jpg')[0];
let link = `${animeId}/${episode}`
animeListEps.push({
episode: episode,
id: link
})
}
return animeListEps;
};
const animeflvGenres = async (id) => {
const promises = [];
let options = { scrapy: true }
let $ = await homgot(`${BASE_ANIMEFLV}${id}`, options);
$('main.Main section.WdgtCn nav.Nvgnrs a').each((index, element) => {
const $element = $(element);
const genre = $element.attr('href').split('=')[1] || null;
promises.push(genre);
});
return promises;
}
const animeflvInfo = async (id) => {
let $ = await homgot(`${BASE_ANIMEFLV}anime/${id}`, { scrapy: true });
let scripts = $('script').toArray();
const anime_info_ids = [];
const anime_eps_data = [];
Array.from({ length: scripts.length }, (v, k) => {
const contents = $(scripts[k]).html();
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 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] 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 link = `${id}/${animeId}-${episode}`
animeListEps.push({
episode: episode,
id: link,
})
})
return animeListEps
};
const getAnimeCharacters = async(mal_id) =>{
let data;
try {
data = await homgot(`${BASE_JIKAN}anime/${mal_id}/characters_staff`, { parse: true });
}catch(error) {
console.log(error);
}
if(data !== null) {
return data.characters.map(doc => ({
id: doc.mal_id,
name: doc.name,
image: doc.image_url,
role: doc.role
}));
}
};
const getAnimeVideoPromo = async(mal_id) =>{
let data;
try {
data = await homgot(`${BASE_JIKAN}anime/${mal_id}/videos`, {parse: true});
}catch(error) {
console.log(error);
}
if(data !== null) {
return data.promo.map(doc => ({
title: doc.title,
previewImage: doc.image_url,
videoURL: doc.video_url
}));
}
};
const animeExtraInfo = async (mal_id) => {
const data = await homgot(`${BASE_JIKAN}anime/${mal_id}`, {parse: true});
try {
if(data !== null) {
const promises = [];
let broadcast = ''
Array(data).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'
};
if (doc.broadcast === null) {
broadcast = null
} else {
broadcast = airDay[doc.broadcast.split('at')[0].replace(" ", "").toLowerCase()]
}
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: broadcast,
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);
}
} catch (err) {
console.log(err)
}
};
const imageUrlToBase64 = async (url) => {
let img = await homgot(url)
return img.rawBody.toString('base64');
};
const searchAnime = async (query) => {
let $ = await homgot(`${ANIMEFLV_SEARCH}q=${query}`, { scrapy: true });
return Promise.all(await obtainAnimeSeries($));
};
const obtainAnimeSeries = async ($) => {
let promises = [];
await asyncForEach($('div.Container ul.ListAnimes li article'), async (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({
id: id || null,
title: title || null,
type: type || null,
image: await imageUrlToBase64(poster) || null
});
})
return promises;
}
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
const transformUrlServer = async (urlReal) => {
let res
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
}
}
urlReal.map(doc => {
promises.push({
id: doc.title.toLowerCase(),
url: doc.code,
direct: doc.direct || false
});
});
return promises;
}
const obtainPreviewNews = (encoded) => {
let image;
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 = `${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',
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 () => await homgot(`${BASE_ANIMEFLV}api/animes/list`, { parse: true });
const getDirectory = async (genres) => {
if (genres === 'sfw') {
return directoryAnimes.filter(function (doc) {
if (!doc.genres.includes('Ecchi') && !doc.genres.includes('ecchi')) {
return {
id: doc.id,
title: doc.title,
mal_id: doc.mal_id,
poster: doc.poster,
type: doc.type,
genres: doc.genres,
state: doc.state,
score: doc.score,
jkanime: false,
description: doc.description
};
}
});
}
return directoryAnimes.map(doc => ({
id: doc.id,
title: doc.title,
mal_id: doc.mal_id,
poster: doc.poster,
type: doc.type,
genres: doc.genres,
state: doc.state,
score: doc.score,
jkanime: false,
description: doc.description
}));
};
module.exports = {
jkanimeInfo,
animeflvGenres,
animeflvInfo,
getAnimeCharacters,
getAnimeVideoPromo,
animeExtraInfo,
imageUrlToBase64,
searchAnime,
transformUrlServer,
obtainPreviewNews,
structureThemes,
getThemes,
getAnimes,
getDirectory,
videoServersJK,
directoryAnimes,
radioStations,
animeGenres,
animeThemes
}

@ -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. */
}
}

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