* fix apidocs definitions * add nhentaiStrategy method * add MaybeError types * add simulateCookie to janda class * test case * env example * push release
このコミットが含まれているのは:
コミット
0b6ffbd9a6
30
.env.schema
30
.env.schema
|
@ -1,14 +1,22 @@
|
||||||
# cloudflare stuff for testing nhentai: https://github.com/Zekfad/nhentai-api/issues/25#issuecomment-1141360074
|
# railway, fly.dev, heroku, vercel or any free service, NHENTAI_IP_ORIGIN should be true
|
||||||
# you can skip this as it's no longer needed
|
RAILWAY = sinkaroid
|
||||||
CF_COOKIE=
|
|
||||||
CF=
|
|
||||||
|
|
||||||
# your username if it's on railway.app
|
# default port
|
||||||
RAILWAY=sinkaroid
|
PORT = 3000
|
||||||
|
|
||||||
# jandapress config
|
# backend storage, default is redis with this format
|
||||||
PORT=3000
|
REDIS_URL = redis://default:somenicepassword@redis-666.c10.us-east-6-6.ec666.cloud.redislabs.com:1337
|
||||||
REDIS_URL=redis://default:somenicepassword@redis-666.c10.us-east-6-6.ec666.cloud.redislabs.com:1337
|
|
||||||
|
|
||||||
# ttl for cache in a hour
|
# ttl expire cache (in X hour)
|
||||||
EXPIRE_CACHE=1
|
EXPIRE_CACHE = 1
|
||||||
|
|
||||||
|
# nhentai strategy
|
||||||
|
# default is true which is assign to request on origin IP instead of nhentai.net with cloudflare protection
|
||||||
|
# if you have paid instance like vps you need chromium or firefox installed and set NHENTAI_IP_ORIGIN to false
|
||||||
|
NHENTAI_IP_ORIGIN = true
|
||||||
|
|
||||||
|
# you must set COOKIE if NHENTAI_IP_ORIGIN is false, read the jandapress docs
|
||||||
|
COOKIE = "cf_clearance=l7RsUjiZ3LHAZZKcM7BcCylwD2agwPDU7l9zkg8MzPo-1676044652-0-250"
|
||||||
|
|
||||||
|
# you must set USER_AGENT if NHENTAI_IP_ORIGIN is false, read the jandapress docs
|
||||||
|
USER_AGENT = "jandapress/1.0.5 Node.js/16.9.1"
|
||||||
|
|
18
README.md
18
README.md
|
@ -28,11 +28,11 @@ The motivation of this project is to bring you an actionable data related doujin
|
||||||
- [Installation](#installation)
|
- [Installation](#installation)
|
||||||
- [Docker](#docker)
|
- [Docker](#docker)
|
||||||
- [Manual](#manual)
|
- [Manual](#manual)
|
||||||
|
- [Nhentai guide](#limitations)
|
||||||
- [Running tests](#running-tests)
|
- [Running tests](#running-tests)
|
||||||
- [Playground](https://sinkaroid.github.io/jandapress)
|
- [Playground](https://sinkaroid.github.io/jandapress)
|
||||||
- [Routing](#playground)
|
- [Routing](#playground)
|
||||||
- [Status response](#status-response)
|
- [Status response](#status-response)
|
||||||
- [Limitations](#limitations)
|
|
||||||
- [CLosing remarks](https://github.com/sinkaroid/jandapress/blob/master/CLOSING_REMARKS.md)
|
- [CLosing remarks](https://github.com/sinkaroid/jandapress/blob/master/CLOSING_REMARKS.md)
|
||||||
- [Alternative links](https://github.com/sinkaroid/jandapress/blob/master/CLOSING_REMARKS.md#alternative-links)
|
- [Alternative links](https://github.com/sinkaroid/jandapress/blob/master/CLOSING_REMARKS.md#alternative-links)
|
||||||
- [Pronunciation](#Pronunciation)
|
- [Pronunciation](#Pronunciation)
|
||||||
|
@ -83,6 +83,9 @@ REDIS_URL=redis://default:somenicepassword@someredishost:1337 ## the database ur
|
||||||
EXPIRE_CACHE=1 ## a hour
|
EXPIRE_CACHE=1 ## a hour
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Nhentai guide
|
||||||
|
Nhentai was cloudflare protection enabled, If IP and our thoughts against them? You should implement a proxy. Check [`cookie branch`](https://github.com/sinkaroid/jandapress/tree/cookie), take a look this workaround [Zekfad/nhentai-api/issues/25#issuecomment-1141360074](https://github.com/Zekfad/nhentai-api/issues/25#issuecomment-1141360074)
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
|
||||||
docker pull ghcr.io/sinkaroid/jandapress:latest
|
docker pull ghcr.io/sinkaroid/jandapress:latest
|
||||||
|
@ -101,12 +104,6 @@ EXPIRE_CACHE=1 ## a hour
|
||||||
|
|
||||||
|
|
||||||
## Running tests
|
## Running tests
|
||||||
Jandapress depends on
|
|
||||||
- [express](https://github.com/expressjs/express) web api framework
|
|
||||||
- [keyv](https://github.com/jaredwray/keyv) key-value storage with support for multiple backends
|
|
||||||
- [cheerio](https://cheerio.js.org/) for parsing html
|
|
||||||
- [cors](https://github.com/expressjs/cors) middleware for enabling CORS
|
|
||||||
- [rate-limit](https://github.com/nfriedly/express-rate-limit) rate-limiting middleware for express
|
|
||||||
|
|
||||||
### Start the production server
|
### Start the production server
|
||||||
`npm run start:prod`
|
`npm run start:prod`
|
||||||
|
@ -216,11 +213,8 @@ The missing piece of 3hentai.net - https://sinkaroid.github.io/jandapress/#api-3
|
||||||
## Status response
|
## Status response
|
||||||
|
|
||||||
HTTP/1.1 200 OK
|
HTTP/1.1 200 OK
|
||||||
HTTP/1.1 200 (cached)
|
HTTP/1.1 400 Bad Request
|
||||||
HTTP/1.1 500 (bad parameters)
|
HTTP/1.1 500 Fail to get data
|
||||||
|
|
||||||
## Limitations
|
|
||||||
Nhentai was cloudflare protection enabled, If IP and our thoughts against them? You should implement a proxy. Check [`cookie branch`](https://github.com/sinkaroid/jandapress/tree/cookie), take a look this workaround [Zekfad/nhentai-api/issues/25#issuecomment-1141360074](https://github.com/Zekfad/nhentai-api/issues/25#issuecomment-1141360074)
|
|
||||||
|
|
||||||
## Frequently asked questions
|
## Frequently asked questions
|
||||||
**Q: The website response is slow**
|
**Q: The website response is slow**
|
||||||
|
|
10
package.json
10
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "jandapress",
|
"name": "jandapress",
|
||||||
"version": "2.0.4-dev",
|
"version": "2.1.1-alpha",
|
||||||
"description": "RESTful and experimental API for the Doujinshi, Pressing the whole nhentai, pururin, hentaifox, and more.. where the official one is lack.",
|
"description": "RESTful and experimental API for the Doujinshi, Pressing the whole nhentai, pururin, hentaifox, and more.. where the official one is lack.",
|
||||||
"main": "build/src/index.js",
|
"main": "build/src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
},
|
},
|
||||||
"apidoc": {
|
"apidoc": {
|
||||||
"title": "Jandapress API Documentation",
|
"title": "Jandapress API Documentation",
|
||||||
"url" : "https://janda.mod.land",
|
"url": "https://janda.mod.land",
|
||||||
"sampleUrl": "https://janda.mod.land",
|
"sampleUrl": "https://janda.mod.land",
|
||||||
"name": "Jandapress"
|
"name": "Jandapress"
|
||||||
},
|
},
|
||||||
|
@ -44,10 +44,12 @@
|
||||||
"express": "^4.18.1",
|
"express": "^4.18.1",
|
||||||
"express-rate-limit": "^6.4.0",
|
"express-rate-limit": "^6.4.0",
|
||||||
"express-slow-down": "^1.4.0",
|
"express-slow-down": "^1.4.0",
|
||||||
|
"http-cookie-agent": "^5.0.2",
|
||||||
"keyv": "^4.5.2",
|
"keyv": "^4.5.2",
|
||||||
"phin": "^3.6.1",
|
"phin": "^3.6.1",
|
||||||
"pino": "^8.7.0",
|
"pino": "^8.7.0",
|
||||||
"pino-pretty": "^9.1.1"
|
"pino-pretty": "^9.1.1",
|
||||||
|
"tough-cookie": "^4.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/cors": "^2.8.12",
|
"@types/cors": "^2.8.12",
|
||||||
|
@ -69,4 +71,4 @@
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,80 @@
|
||||||
import p from "phin";
|
import p from "phin";
|
||||||
import Keyv from "keyv";
|
import Keyv from "keyv";
|
||||||
import dotenv from "dotenv";
|
import { CookieJar } from "tough-cookie";
|
||||||
dotenv.config();
|
import { HttpsCookieAgent } from "http-cookie-agent/http";
|
||||||
|
|
||||||
const keyv = new Keyv(process.env.REDIS_URL);
|
const keyv = new Keyv(process.env.REDIS_URL);
|
||||||
|
const strategy = process.env.NHENTAI_IP_ORIGIN || "true";
|
||||||
|
|
||||||
keyv.on("error", err => console.log("Connection Error", err));
|
keyv.on("error", err => console.log("Connection Error", err));
|
||||||
const ttl = 1000 * 60 * 60 * Number(process.env.EXPIRE_CACHE);
|
const ttl = 1000 * 60 * 60 * Number(process.env.EXPIRE_CACHE);
|
||||||
|
|
||||||
|
const jar = new CookieJar();
|
||||||
|
jar.setCookie(process.env.COOKIE || "", "https://nhentai.net/");
|
||||||
|
|
||||||
class JandaPress {
|
class JandaPress {
|
||||||
url: string;
|
url: string;
|
||||||
|
useragent: string;
|
||||||
constructor() {
|
constructor() {
|
||||||
this.url = "";
|
this.url = "";
|
||||||
|
this.useragent = "jandapress/1.0.5 Node.js/16.9.1";
|
||||||
|
}
|
||||||
|
|
||||||
|
async simulateCookie(target: string, parseJson = false): Promise<p.IResponse | unknown> {
|
||||||
|
if (!parseJson) {
|
||||||
|
const res = await p({
|
||||||
|
url: target,
|
||||||
|
followRedirects: true,
|
||||||
|
core: {
|
||||||
|
agent: new HttpsCookieAgent({ cookies: { jar, }, }),
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
"User-Agent": process.env.USER_AGENT || "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
const res = await p({
|
||||||
|
url: target,
|
||||||
|
parse: "json",
|
||||||
|
core: {
|
||||||
|
agent: new HttpsCookieAgent({ cookies: { jar, }, }),
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
"User-Agent": process.env.USER_AGENT || "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return res.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulating nhentai request if origin api is not available
|
||||||
|
* You'll need [tough-cookie](https://www.npmjs.com/package/tough-cookie) and [http-cookie-agent](https://www.npmjs.com/package/http-cookie-agent) to make this work
|
||||||
|
* @param target url to fetch
|
||||||
|
* @returns Promise<unknown>
|
||||||
|
* @throws Error
|
||||||
|
*/
|
||||||
|
async simulateNhentaiRequest(target: string): Promise<unknown> {
|
||||||
|
if (strategy === "true") {
|
||||||
|
const res = await p({
|
||||||
|
url: target,
|
||||||
|
parse: "json"
|
||||||
|
});
|
||||||
|
return res.body;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const res = await this.simulateCookie(target, true);
|
||||||
|
return res;
|
||||||
|
} catch (err) {
|
||||||
|
const e = err as Error;
|
||||||
|
throw new Error(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,7 +105,7 @@ class JandaPress {
|
||||||
* @param url url to fetch
|
* @param url url to fetch
|
||||||
* @returns Buffer
|
* @returns Buffer
|
||||||
*/
|
*/
|
||||||
async fetchJson(url: string) {
|
async fetchJson(url: string): Promise<unknown> {
|
||||||
const cached = await keyv.get(url);
|
const cached = await keyv.get(url);
|
||||||
|
|
||||||
if (cached) {
|
if (cached) {
|
||||||
|
@ -50,9 +113,9 @@ class JandaPress {
|
||||||
return cached;
|
return cached;
|
||||||
} else {
|
} else {
|
||||||
console.log("Fetching from source");
|
console.log("Fetching from source");
|
||||||
const res = await p({ url: url, parse: "json" });
|
const res = await this.simulateNhentaiRequest(url);
|
||||||
await keyv.set(url, res.body, ttl);
|
await keyv.set(url, res, ttl);
|
||||||
return res.body;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,9 +129,7 @@ class JandaPress {
|
||||||
rss: `${Math.round(rss * 100) / 100} MB`,
|
rss: `${Math.round(rss * 100) / 100} MB`,
|
||||||
heap: `${Math.round(heap * 100) / 100}/${Math.round(heaptotal * 100) / 100} MB`
|
heap: `${Math.round(heap * 100) / 100}/${Math.round(heaptotal * 100) / 100} MB`
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default JandaPress;
|
export default JandaPress;
|
||||||
|
|
|
@ -20,7 +20,7 @@ export async function get3hentai(req: Request, res: Response, next: NextFunction
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/3hentai/get?book=123
|
* curl -i https://janda.mod.land/3hentai/get?book=123
|
||||||
|
|
|
@ -13,7 +13,7 @@ export async function random3hentai(req: Request, res: Response, next: NextFunct
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/3hentai/random
|
* curl -i https://janda.mod.land/3hentai/random
|
||||||
|
|
|
@ -23,7 +23,7 @@ export async function search3hentai(req: Request, res: Response, next: NextFunct
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/3hentai/search?key=yuri
|
* curl -i https://janda.mod.land/3hentai/search?key=yuri
|
||||||
|
|
|
@ -20,7 +20,7 @@ export async function getAsmhentai(req: Request, res: Response, next: NextFuncti
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/asmhentai/get?book=123
|
* curl -i https://janda.mod.land/asmhentai/get?book=123
|
||||||
|
|
|
@ -13,7 +13,7 @@ export async function randomAsmhentai(req: Request, res: Response, next: NextFun
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/asmhentai/random
|
* curl -i https://janda.mod.land/asmhentai/random
|
||||||
|
|
|
@ -20,7 +20,7 @@ export async function searchAsmhentai(req: Request, res: Response, next: NextFun
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/asmhentai/search?key=yuri
|
* curl -i https://janda.mod.land/asmhentai/search?key=yuri
|
||||||
|
|
|
@ -19,7 +19,7 @@ export async function getHentai2read(req: Request, res: Response) {
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/hentai2read/get?book=butabako_shotaone_matome_fgo_hen/1
|
* curl -i https://janda.mod.land/hentai2read/get?book=butabako_shotaone_matome_fgo_hen/1
|
||||||
|
|
|
@ -17,7 +17,7 @@ export async function searchHentai2read(req: Request, res: Response, next: NextF
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/hentai2read/search?key=yuri
|
* curl -i https://janda.mod.land/hentai2read/search?key=yuri
|
||||||
|
|
|
@ -20,7 +20,7 @@ export async function getHentaifox(req: Request, res: Response, next: NextFuncti
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/hentaifox/get?book=123
|
* curl -i https://janda.mod.land/hentaifox/get?book=123
|
||||||
|
|
|
@ -13,7 +13,7 @@ export async function randomHentaifox(req: Request, res: Response, next: NextFun
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/hentaifox/random
|
* curl -i https://janda.mod.land/hentaifox/random
|
||||||
|
|
|
@ -17,7 +17,7 @@ export async function searchHentaifox(req: Request, res: Response, next: NextFun
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/hentaifox/search?key=yuri
|
* curl -i https://janda.mod.land/hentaifox/search?key=yuri
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { scrapeContent } from "../../scraper/nhentai/nhentaiGetController";
|
import { scrapeContent } from "../../scraper/nhentai/nhentaiGetController";
|
||||||
import c from "../../utils/options";
|
|
||||||
import { logger } from "../../utils/logger";
|
import { logger } from "../../utils/logger";
|
||||||
import { mock, isNumeric } from "../../utils/modifier";
|
import { nhentaiStrategy, isNumeric, maybeError } from "../../utils/modifier";
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
export async function getNhentai(req: Request, res: Response) {
|
export async function getNhentai(req: Request, res: Response) {
|
||||||
|
@ -10,10 +9,6 @@ export async function getNhentai(req: Request, res: Response) {
|
||||||
if (!book) throw Error("Parameter book is required");
|
if (!book) throw Error("Parameter book is required");
|
||||||
if (!isNumeric(book)) throw Error("Parameter book must be number");
|
if (!isNumeric(book)) throw Error("Parameter book must be number");
|
||||||
|
|
||||||
let actualAPI;
|
|
||||||
if (!await mock(c.NHENTAI)) actualAPI = c.NHENTAI_IP_3;
|
|
||||||
else actualAPI = c.NHENTAI;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {get} /nhentai/get?book=:book Get nhentai
|
* @api {get} /nhentai/get?book=:book Get nhentai
|
||||||
* @apiName Get nhentai
|
* @apiName Get nhentai
|
||||||
|
@ -24,7 +19,7 @@ export async function getNhentai(req: Request, res: Response) {
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/nhentai/get?book=123
|
* curl -i https://janda.mod.land/nhentai/get?book=123
|
||||||
|
@ -43,7 +38,7 @@ export async function getNhentai(req: Request, res: Response) {
|
||||||
* print(await resp.json())
|
* print(await resp.json())
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const url = `${actualAPI}/api/gallery/${book}`;
|
const url = `${nhentaiStrategy()}/api/gallery/${book}`;
|
||||||
const data = await scrapeContent(url);
|
const data = await scrapeContent(url);
|
||||||
logger.info({
|
logger.info({
|
||||||
path: req.path,
|
path: req.path,
|
||||||
|
@ -53,11 +48,8 @@ export async function getNhentai(req: Request, res: Response) {
|
||||||
useragent: req.get("User-Agent")
|
useragent: req.get("User-Agent")
|
||||||
});
|
});
|
||||||
return res.json(data);
|
return res.json(data);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
const e = {
|
const e = err as Error;
|
||||||
"success": false,
|
res.status(400).json(maybeError(false, e.message));
|
||||||
"message": err.message
|
|
||||||
};
|
|
||||||
res.json(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
import { scrapeContent } from "../../scraper/nhentai/nhentaiGetController";
|
import { scrapeContent } from "../../scraper/nhentai/nhentaiGetController";
|
||||||
import c from "../../utils/options";
|
|
||||||
import { logger } from "../../utils/logger";
|
import { logger } from "../../utils/logger";
|
||||||
import { mock } from "../../utils/modifier";
|
import { nhentaiStrategy, getIdRandomNhentai, maybeError } from "../../utils/modifier";
|
||||||
import { getIdRandomNhentai } from "../../utils/modifier";
|
import { Request, Response } from "express";
|
||||||
import { Request, Response, NextFunction } from "express";
|
|
||||||
|
|
||||||
export async function randomNhentai(req: Request, res: Response, next: NextFunction) {
|
export async function randomNhentai(req: Request, res: Response) {
|
||||||
try {
|
try {
|
||||||
let actualAPI;
|
|
||||||
if (!await mock(c.NHENTAI)) actualAPI = c.NHENTAI_IP_3;
|
|
||||||
else actualAPI = c.NHENTAI;
|
|
||||||
|
|
||||||
const id = await getIdRandomNhentai();
|
const id = await getIdRandomNhentai();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,7 +15,7 @@ export async function randomNhentai(req: Request, res: Response, next: NextFunct
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/nhentai/random
|
* curl -i https://janda.mod.land/nhentai/random
|
||||||
|
@ -41,7 +35,7 @@ export async function randomNhentai(req: Request, res: Response, next: NextFunct
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const url = `${actualAPI}/api/gallery/${id}`;
|
const url = `${nhentaiStrategy()}/api/gallery/${id}`;
|
||||||
const data = await scrapeContent(url, true);
|
const data = await scrapeContent(url, true);
|
||||||
logger.info({
|
logger.info({
|
||||||
path: req.path,
|
path: req.path,
|
||||||
|
@ -51,7 +45,8 @@ export async function randomNhentai(req: Request, res: Response, next: NextFunct
|
||||||
useragent: req.get("User-Agent")
|
useragent: req.get("User-Agent")
|
||||||
});
|
});
|
||||||
return res.json(data);
|
return res.json(data);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
next(Error(err.message));
|
const e = err as Error;
|
||||||
|
res.status(400).json(maybeError(false, `Error Try again: ${e.message}`));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { scrapeContent } from "../../scraper/nhentai/nhentaiRelatedController";
|
import { scrapeContent } from "../../scraper/nhentai/nhentaiRelatedController";
|
||||||
import c from "../../utils/options";
|
|
||||||
import { logger } from "../../utils/logger";
|
import { logger } from "../../utils/logger";
|
||||||
import { mock, isNumeric } from "../../utils/modifier";
|
import { nhentaiStrategy, isNumeric, maybeError } from "../../utils/modifier";
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
export async function relatedNhentai(req: Request, res: Response) {
|
export async function relatedNhentai(req: Request, res: Response) {
|
||||||
|
@ -10,10 +9,6 @@ export async function relatedNhentai(req: Request, res: Response) {
|
||||||
if (!book) throw Error("Parameter book is required");
|
if (!book) throw Error("Parameter book is required");
|
||||||
if (!isNumeric(book)) throw Error("Value must be number");
|
if (!isNumeric(book)) throw Error("Value must be number");
|
||||||
|
|
||||||
let actualAPI;
|
|
||||||
if (!await mock(c.NHENTAI)) actualAPI = c.NHENTAI_IP_3;
|
|
||||||
else actualAPI = c.NHENTAI;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {get} /nhentai/related?book=:book Get related nhentai
|
* @api {get} /nhentai/related?book=:book Get related nhentai
|
||||||
* @apiName Get related nhentai
|
* @apiName Get related nhentai
|
||||||
|
@ -24,7 +19,7 @@ export async function relatedNhentai(req: Request, res: Response) {
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/nhentai/related?book=123
|
* curl -i https://janda.mod.land/nhentai/related?book=123
|
||||||
|
@ -43,7 +38,7 @@ export async function relatedNhentai(req: Request, res: Response) {
|
||||||
* print(await resp.json())
|
* print(await resp.json())
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const url = `${actualAPI}/api/gallery/${book}/related`;
|
const url = `${nhentaiStrategy()}/api/gallery/${book}/related`;
|
||||||
const data = await scrapeContent(url);
|
const data = await scrapeContent(url);
|
||||||
logger.info({
|
logger.info({
|
||||||
path: req.path,
|
path: req.path,
|
||||||
|
@ -53,11 +48,8 @@ export async function relatedNhentai(req: Request, res: Response) {
|
||||||
useragent: req.get("User-Agent")
|
useragent: req.get("User-Agent")
|
||||||
});
|
});
|
||||||
return res.json(data);
|
return res.json(data);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
const e = {
|
const e = err as Error;
|
||||||
"success": false,
|
res.status(400).json(maybeError(false, e.message));
|
||||||
"message": err.message
|
|
||||||
};
|
|
||||||
res.json(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { scrapeContent } from "../../scraper/nhentai/nhentaiSearchController";
|
import { scrapeContent } from "../../scraper/nhentai/nhentaiSearchController";
|
||||||
import c from "../../utils/options";
|
|
||||||
import { logger } from "../../utils/logger";
|
import { logger } from "../../utils/logger";
|
||||||
import { mock } from "../../utils/modifier";
|
import { nhentaiStrategy, maybeError } from "../../utils/modifier";
|
||||||
const sorting = ["popular-today", "popular-week", "popular"];
|
const sorting = ["popular-today", "popular-week", "popular"];
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
|
@ -13,10 +12,6 @@ export async function searchNhentai(req: Request, res: Response) {
|
||||||
if (!key) throw Error("Parameter key is required");
|
if (!key) throw Error("Parameter key is required");
|
||||||
if (!sorting.includes(sort)) throw Error("Invalid sort: " + sorting.join(", "));
|
if (!sorting.includes(sort)) throw Error("Invalid sort: " + sorting.join(", "));
|
||||||
|
|
||||||
let actualAPI;
|
|
||||||
if (!await mock(c.NHENTAI)) actualAPI = c.NHENTAI_IP_3;
|
|
||||||
else actualAPI = c.NHENTAI;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {get} /nhentai/search Search nhentai
|
* @api {get} /nhentai/search Search nhentai
|
||||||
* @apiName Search nhentai
|
* @apiName Search nhentai
|
||||||
|
@ -28,7 +23,7 @@ export async function searchNhentai(req: Request, res: Response) {
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/nhentai/search?key=yuri
|
* curl -i https://janda.mod.land/nhentai/search?key=yuri
|
||||||
|
@ -48,7 +43,7 @@ export async function searchNhentai(req: Request, res: Response) {
|
||||||
* print(await resp.json())
|
* print(await resp.json())
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const url = `${actualAPI}/api/galleries/search?query=${key}&sort=${sort}&page=${page}`;
|
const url = `${nhentaiStrategy()}/api/galleries/search?query=${key}&sort=${sort}&page=${page}`;
|
||||||
const data = await scrapeContent(url);
|
const data = await scrapeContent(url);
|
||||||
logger.info({
|
logger.info({
|
||||||
path: req.path,
|
path: req.path,
|
||||||
|
@ -58,11 +53,8 @@ export async function searchNhentai(req: Request, res: Response) {
|
||||||
useragent: req.get("User-Agent")
|
useragent: req.get("User-Agent")
|
||||||
});
|
});
|
||||||
return res.json(data);
|
return res.json(data);
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
const e = {
|
const e = err as Error;
|
||||||
"success": false,
|
res.status(400).json(maybeError(false, e.message));
|
||||||
"message": err.message
|
|
||||||
};
|
|
||||||
res.json(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,7 +20,7 @@ export async function getPururin(req: Request, res: Response, next: NextFunction
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/pururin/get?book=123
|
* curl -i https://janda.mod.land/pururin/get?book=123
|
||||||
|
|
|
@ -16,7 +16,7 @@ export async function randomPururin(req: Request, res: Response, next: NextFunct
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/pururin/random
|
* curl -i https://janda.mod.land/pururin/random
|
||||||
|
|
|
@ -23,7 +23,7 @@ export async function searchPururin(req: Request, res: Response, next: NextFunct
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/pururin/search?key=yuri
|
* curl -i https://janda.mod.land/pururin/search?key=yuri
|
||||||
|
|
|
@ -22,7 +22,7 @@ export async function getSimplyhentai(req: Request, res: Response) {
|
||||||
*
|
*
|
||||||
* @apiSuccessExample {json} Success-Response:
|
* @apiSuccessExample {json} Success-Response:
|
||||||
* HTTP/1.1 200 OK
|
* HTTP/1.1 200 OK
|
||||||
* HTTP/1.1 200 (cached)
|
* HTTP/1.1 400 Bad Request
|
||||||
*
|
*
|
||||||
* @apiExample {curl} curl
|
* @apiExample {curl} curl
|
||||||
* curl -i https://janda.mod.land/simply-hentai/get?book=fate-grand-order/fgo-sanbunkatsuhou/all-pages
|
* curl -i https://janda.mod.land/simply-hentai/get?book=fate-grand-order/fgo-sanbunkatsuhou/all-pages
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import "dotenv/config";
|
||||||
import JandaPress from "./JandaPress";
|
import JandaPress from "./JandaPress";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
|
@ -6,11 +7,10 @@ import { slow, limiter } from "./utils/limit-options";
|
||||||
import { logger } from "./utils/logger";
|
import { logger } from "./utils/logger";
|
||||||
import { isNumeric } from "./utils/modifier";
|
import { isNumeric } from "./utils/modifier";
|
||||||
import * as pkg from "../package.json";
|
import * as pkg from "../package.json";
|
||||||
import dotenv from "dotenv";
|
|
||||||
|
|
||||||
const janda = new JandaPress();
|
const janda = new JandaPress();
|
||||||
const app = express();
|
const app = express();
|
||||||
dotenv.config();
|
|
||||||
|
|
||||||
app.get("/", slow, limiter, (req, res) => {
|
app.get("/", slow, limiter, (req, res) => {
|
||||||
res.send({
|
res.send({
|
||||||
|
|
|
@ -34,3 +34,7 @@ interface T {
|
||||||
count: number;
|
count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MaybeError {
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import p from "phin";
|
|
||||||
import JandaPress from "../../JandaPress";
|
import JandaPress from "../../JandaPress";
|
||||||
import c from "../../utils/options";
|
import c from "../../utils/options";
|
||||||
import { getDate, timeAgo } from "../../utils/modifier";
|
import { getDate, timeAgo } from "../../utils/modifier";
|
||||||
|
@ -32,10 +31,8 @@ const janda = new JandaPress();
|
||||||
export async function scrapeContent(url: string, random = false) {
|
export async function scrapeContent(url: string, random = false) {
|
||||||
try {
|
try {
|
||||||
let res, raw;
|
let res, raw;
|
||||||
if (random) res = await p({ url: url, parse: "json" }),
|
if (random) res = await janda.simulateNhentaiRequest(url), raw = res as Nhentai;
|
||||||
raw = res.body as Nhentai;
|
else res = await janda.fetchJson(url), raw = res as Nhentai;
|
||||||
else res = await janda.fetchJson(url),
|
|
||||||
raw = res as Nhentai;
|
|
||||||
|
|
||||||
const GALLERY = "https://i.nhentai.net/galleries";
|
const GALLERY = "https://i.nhentai.net/galleries";
|
||||||
const imagesRaw = raw.images.pages;
|
const imagesRaw = raw.images.pages;
|
||||||
|
@ -93,11 +90,13 @@ export async function scrapeContent(url: string, random = false) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
|
success: true,
|
||||||
data: objectData,
|
data: objectData,
|
||||||
source: `${c.NHENTAI}/g/${raw.id}`,
|
source: `${c.NHENTAI}/g/${raw.id}`,
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
throw Error(err.message);
|
const e = err as Error;
|
||||||
|
throw Error(e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -42,6 +42,7 @@ export async function scrapeContent(url: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
|
success: true,
|
||||||
data: content,
|
data: content,
|
||||||
source: url.replace(c.NHENTAI_IP, c.NHENTAI),
|
source: url.replace(c.NHENTAI_IP, c.NHENTAI),
|
||||||
};
|
};
|
||||||
|
|
|
@ -56,6 +56,7 @@ export async function scrapeContent(url: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
|
success: true,
|
||||||
data: content,
|
data: content,
|
||||||
page: Number(url.split("&page=")[1]),
|
page: Number(url.split("&page=")[1]),
|
||||||
sort: url.split("&sort=")[1].split("&")[0],
|
sort: url.split("&sort=")[1].split("&")[0],
|
||||||
|
@ -63,7 +64,8 @@ export async function scrapeContent(url: string) {
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
} catch (err: any) {
|
} catch (err) {
|
||||||
throw Error(err.message);
|
const e = err as Error;
|
||||||
|
throw Error(e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,33 +1,70 @@
|
||||||
|
import JandaPress from "../JandaPress";
|
||||||
import p from "phin";
|
import p from "phin";
|
||||||
import { load } from "cheerio";
|
import { load } from "cheerio";
|
||||||
import c from "./options";
|
import c from "./options";
|
||||||
|
|
||||||
|
const janda = new JandaPress();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Pururin info and replace
|
||||||
|
* @param value
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
function getPururinInfo(value: string) {
|
function getPururinInfo(value: string) {
|
||||||
return value.replace(/\n/g, " ").replace(/\s\s+/g, " ").trim();
|
return value.replace(/\n/g, " ").replace(/\s\s+/g, " ").trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Pururin page count
|
||||||
|
* @param value
|
||||||
|
* @returns number
|
||||||
|
*/
|
||||||
function getPururinPageCount(value: string) {
|
function getPururinPageCount(value: string) {
|
||||||
const data = value.replace(/\n/g, " ").replace(/\s\s+/g, " ").trim().split(", ").pop();
|
const data = value.replace(/\n/g, " ").replace(/\s\s+/g, " ").trim().split(", ").pop();
|
||||||
return Number(data?.split(" ")[0]);
|
return Number(data?.split(" ")[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Pururin language
|
||||||
|
* @param value
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
function getPururinLanguage(value: string) {
|
function getPururinLanguage(value: string) {
|
||||||
return value.split(",").reverse()[1].trim();
|
return value.split(",").reverse()[1].trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse url
|
||||||
|
* @param url
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
function getUrl(url: string) {
|
function getUrl(url: string) {
|
||||||
return url.replace(/^\/\//, "https://");
|
return url.replace(/^\/\//, "https://");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse id
|
||||||
|
* @param url
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
function getId(url: string) {
|
function getId(url: string) {
|
||||||
return url.replace(/^https?:\/\/[^\\/]+/, "").replace(/\/$/, "");
|
return url.replace(/^https?:\/\/[^\\/]+/, "").replace(/\/$/, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse alphabet only
|
||||||
|
* @param input
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
function removeNonNumeric(input: string) {
|
function removeNonNumeric(input: string) {
|
||||||
return input.replace(/[^0-9]/g, "");
|
return input.replace(/[^0-9]/g, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse date format on nhentai
|
||||||
|
* @param date
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
function getDate(date: Date) {
|
function getDate(date: Date) {
|
||||||
return date.toLocaleDateString("en-US", {
|
return date.toLocaleDateString("en-US", {
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
|
@ -36,6 +73,11 @@ function getDate(date: Date) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fancy time ago format
|
||||||
|
* @param input
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
function timeAgo(input: Date) {
|
function timeAgo(input: Date) {
|
||||||
const date = new Date(input);
|
const date = new Date(input);
|
||||||
const formatter: any = new Intl.RelativeTimeFormat("en");
|
const formatter: any = new Intl.RelativeTimeFormat("en");
|
||||||
|
@ -57,6 +99,11 @@ function timeAgo(input: Date) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check nhentai status
|
||||||
|
* @param url
|
||||||
|
* @returns boolean
|
||||||
|
*/
|
||||||
async function mock(url: string) {
|
async function mock(url: string) {
|
||||||
const site = await p({ url: url });
|
const site = await p({ url: url });
|
||||||
if (site.statusCode === 200) {
|
if (site.statusCode === 200) {
|
||||||
|
@ -68,11 +115,20 @@ async function mock(url: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isNumeric = (val: string) : boolean => {
|
/**
|
||||||
|
* Check if string is numeric
|
||||||
|
* @param val
|
||||||
|
* @returns boolean
|
||||||
|
*/
|
||||||
|
export const isNumeric = (val: string): boolean => {
|
||||||
return !isNaN(Number(val));
|
return !isNaN(Number(val));
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getIdRandomPururin (): Promise<number> {
|
/**
|
||||||
|
* Simulate random on pururin
|
||||||
|
* @returns Promise<number>
|
||||||
|
*/
|
||||||
|
export async function getIdRandomPururin(): Promise<number> {
|
||||||
const randomNumber = Math.floor(Math.random() * 500) + 1;
|
const randomNumber = Math.floor(Math.random() * 500) + 1;
|
||||||
const raw = await p(`${c.PURURIN}/browse/random?page=${randomNumber}`);
|
const raw = await p(`${c.PURURIN}/browse/random?page=${randomNumber}`);
|
||||||
const $ = load(raw.body);
|
const $ = load(raw.body);
|
||||||
|
@ -82,13 +138,14 @@ export async function getIdRandomPururin (): Promise<number> {
|
||||||
return parseInt(randomgallery);
|
return parseInt(randomgallery);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getIdRandomNhentai (): Promise<number> {
|
/**
|
||||||
if (await mock(c.NHENTAI)) {
|
* Simulate random on nhentai
|
||||||
const res: any = await p({
|
* @returns Promise<number>
|
||||||
url: `${c.NHENTAI}/random`,
|
*/
|
||||||
followRedirects: true,
|
export async function getIdRandomNhentai(): Promise<number> {
|
||||||
});
|
if (process.env.NHENTAI_IP_ORIGIN === "false") {
|
||||||
|
const res: any = await janda.simulateCookie(`${c.NHENTAI}/random`);
|
||||||
|
|
||||||
const getId = res.socket._httpMessage.path;
|
const getId = res.socket._httpMessage.path;
|
||||||
return parseInt(getId.replace(/^\/g\/([0-9]+)\/?$/, "$1"));
|
return parseInt(getId.replace(/^\/g\/([0-9]+)\/?$/, "$1"));
|
||||||
} else {
|
} else {
|
||||||
|
@ -98,6 +155,28 @@ export async function getIdRandomNhentai (): Promise<number> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error handler
|
||||||
|
* @param success
|
||||||
|
* @param message
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function maybeError(success: boolean, message: string) {
|
||||||
|
return { success, message };
|
||||||
|
}
|
||||||
|
|
||||||
export { getPururinInfo, getPururinPageCount, getUrl, getId, getDate, timeAgo,
|
/**
|
||||||
mock, getPururinLanguage, removeNonNumeric };
|
* Get nhentai strategy from origin api or simulating the request cookie
|
||||||
|
* @returns string
|
||||||
|
*/
|
||||||
|
export function nhentaiStrategy() {
|
||||||
|
let strategy: string;
|
||||||
|
if (process.env.NHENTAI_IP_ORIGIN === "true" || process.env.NHENTAI_IP_ORIGIN === undefined) strategy = c.NHENTAI_IP_3;
|
||||||
|
else strategy = c.NHENTAI;
|
||||||
|
return strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getPururinInfo, getPururinPageCount, getUrl, getId, getDate, timeAgo,
|
||||||
|
mock, getPururinLanguage, removeNonNumeric
|
||||||
|
};
|
|
@ -5,20 +5,20 @@ import * as dotenv from "dotenv";
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
const jar = new CookieJar();
|
const jar = new CookieJar();
|
||||||
jar.setCookie(process.env.CF_COOKIE || "", "https://nhentai.net/");
|
jar.setCookie(process.env.COOKIE || "", "https://nhentai.net/");
|
||||||
|
|
||||||
async function test() {
|
async function test() {
|
||||||
const res = await p({
|
const res = await p({
|
||||||
url: "https://nhentai.net/api/galleries/search?query=futa",
|
url: "https://nhentai.net/api/gallery/1",
|
||||||
core: {
|
core: {
|
||||||
agent: new HttpsCookieAgent({ cookies: { jar, }, }),
|
agent: new HttpsCookieAgent({ cookies: { jar, }, }),
|
||||||
},
|
},
|
||||||
"headers": {
|
"headers": {
|
||||||
"User-Agent": "jandapress/1.0.5 Node.js/16.9.1" // nhentai-api-client/3.4.3 Node.js/16.9.1
|
"User-Agent": process.env.USER_AGENT || "jandapress/1.0.5 Node.js/16.9.1",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
//check status
|
|
||||||
console.log(res.statusCode);
|
console.log(res.statusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
test();
|
test().catch(console.error);
|
読み込み中…
新しいイシューから参照