ci: generate docs from apidoc definitions (#10)

* add some complier files to gitignore

* feat: add apidoc definitions in each controller

* ci: generate docs from apidoc definitions

* docs: update readme

* ci: update playground workflows

* bump marine template
このコミットが含まれているのは:
Indrawan I 2022-12-23 10:04:22 +07:00 committed by GitHub
コミット 87e9402305
この署名に対応する既知のキーがデータベースに存在しません
GPGキーID: 4AEE18F83AFDEB23
25個のファイルの変更652行の追加39行の削除

26
.github/workflows/playground.yml vendored ノーマルファイル
ファイルの表示

@ -0,0 +1,26 @@
name: Playground
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build-and-deploy:
concurrency: ci-${{ github.ref }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Installing dependencies
run: npm install
- name: Generating docs
run: npm run build:apidoc
- name: Deploy
uses: JamesIves/github-pages-deploy-action@v4.4.1
with:
branch: gh-pages
folder: docs

5
.gitignore vendored
ファイルの表示

@ -2,7 +2,10 @@
yarn.lock
/build
/playground
/template
/docs
p.ts
.env
.idea
CHANGELOG.md
CHANGELOG.md
theme.zip

ファイルの表示

@ -1,17 +1,17 @@
<div align="center">
<a href="https://janda.mod.land"><img width="500" src="https://cdn.discordapp.com/attachments/952117487166705747/986185787894812672/tomoe-janda.png" alt="jandapress"></a>
<a href="https://janda.mod.land"><img width="500" src="https://cdn.discordapp.com/attachments/1046495201176334467/1055678255866318898/tomoe-janda.png" alt="jandapress"></a>
<h4 align="center">RESTful and experimental API for the doujinboards</h4>
<p align="center">
<a href="https://github.com/sinkaroid/jandapress/actions/workflows/status.yml"><img src="https://github.com/sinkaroid/jandapress/actions/workflows/status.yml/badge.svg"></a>
<a href="https://github.com/sinkaroid/jandapress/actions/workflows/playground.yml"><img src="https://github.com/sinkaroid/jandapress/workflows/Playground/badge.svg"></a>
<a href="https://codeclimate.com/github/sinkaroid/jandapress/maintainability"><img src="https://api.codeclimate.com/v1/badges/829b8fe63ab78a425f0b/maintainability" /></a>
</p>
Jandapress was named **JCE** (Janda Cheerio Express) and definitely depends on them.
The motivation of this project is to bring you an actionable data related doujin with gather in mind.
<a href="https://sinkaroid.github.io/jandapress">Playground</a>
<a href="https://github.com/sinkaroid/jandapress/blob/master/CONTRIBUTING.md">Contributing</a>
<a href="https://github.com/sinkaroid/jandapress/wiki/Routing">Documentation</a>
<a href="https://github.com/sinkaroid/jandapress/issues/new/choose">Report Issues</a>
</div>
@ -26,19 +26,18 @@ The motivation of this project is to bring you an actionable data related doujin
- [Jandapress vs. the doujinboards](#jandapress-vs-the-whole-doujin-sites)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Docker](#docker)
- [Manual](#manual)
- [Running tests](#running-tests)
- [Routing](#routing)
- [nhentai-api](#routing)
- [pururin-api](#routing)
- [hentaifox-api](#routing)
- [asmhentai-api](#routing)
- [hentai2read-api](#routing)
- [simply-hentai-api](#routing)
- [3hentai-api](#routing)
- [Playground](https://sinkaroid.github.io/jandapress)
- [Routing](#playground)
- [Status response](#status-response)
- [Limitations](#limitations)
- [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)
- [Pronunciation](#Pronunciation)
- [Legal](#legal)
- [Client libraries / Wrappers](#client-libraries--wrappers)
- [Legal](#legal)
## The problem
@ -51,10 +50,10 @@ You enjoy consume doujin sites to build web applications. There are a lot sites
- Gather the most doujin sites
- Objects taken that are consistent structure, almost
- Objects taken is re-appended to make it more actionable
- Objects taken is re-appended to make extendable
- All in one: get, search, and random methods
- In the future we may implement JWT authentication
- Pure scraping
- Pure scraping, except nh sigh..
## Jandapress vs. the whole doujin sites
**Features availability** that Jandapress has
@ -68,15 +67,29 @@ You enjoy consume doujin sites to build web applications. There are a lot sites
| `asmhentai` | [![Asmhentai](https://github.com/sinkaroid/jandapress/workflows/Asmhentai%20test/badge.svg)](https://github.com/sinkaroid/jandapress/actions/workflows/asmhentai.yml) | ✅ | ✅ | ✅ |
| `3hentai` | [![Asmhentai](https://github.com/sinkaroid/jandapress/workflows/3hentai%20test/badge.svg)](https://github.com/sinkaroid/jandapress/actions/workflows/3hentai.yml) | ✅ | ✅ | ✅ |
## Prerequisites
<table>
<td><b>NOTE:</b> NodeJS 14.x or higher</td>
</table>
To handle several requests from each web, You will also need [Redis](https://redis.io/) for persistent caching, free tier is available on [Redis Labs](https://redislabs.com/), You can also choose another provider as we using [keyv](https://github.com/jaredwray/keyv) Key-value storage with support for multiple backends. All data must be stored in `<Buffer>` here.
## Installation
Rename `.env.schema` to `.env` and fill the value with your own.
```bash
PORT=3000 ## default port
REDIS_URL=redis://default:somenicepassword@someredishost:1337 ## the database url
EXPIRE_CACHE=1 ## should expired in a day
```
### Docker
docker pull ghcr.io/sinkaroid/jandapress:latest
docker run -p 3000:3000 -d ghcr.io/sinkaroid/jandapress:latest
### Manual
`git clone https://github.com/sinkaroid/jandapress.git`
- Install dependencies
- `npm install / yarn install`
@ -86,16 +99,11 @@ Rename `.env.schema` to `.env` and fill the value with your own.
- Jandapress testings
- `npm run start:dev`
## Prerequisites
<table>
<td><b>NOTE:</b> NodeJS 14.x or higher</td>
</table>
You will also need [Redis](https://redis.io/) for persistent caching, free tier is available on [Redis Labs](https://redislabs.com/)
## 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
@ -112,15 +120,20 @@ Jandapress depends on
### Check nhentai It's under cloudflare protection or not
`npm run test:cf`
### Generating playground like swagger from apidoc definition
`npm run build:apidoc`
> To running other tests, you can see object scripts in file `package.json`
## Routing
the `parameter?`: means is optional
## Playground
https://sinkaroid.github.io/jandapress
- These `parameter?`: means is optional
- `/` : index page
### Nhentai
The missing piece of nhentai.net
The missing piece of nhentai.net - https://sinkaroid.github.io/jandapress/#api-nhentai
- `/nhentai` : nhentai api
- **get**, takes parameters : `book`
- **search**, takes parameters : `key`, `?page`, `?sort`
@ -133,7 +146,7 @@ The missing piece of nhentai.net
- https://janda.mod.land/nhentai/search?key=futanari&page=2&sort=popular-today
### Pururin
The missing piece of pururin.to
The missing piece of pururin.to - https://sinkaroid.github.io/jandapress/#api-pururin
- `/pururin` : pururin api
- **get**, takes parameters : `book`
- **search**, takes parameters : `key`, `?page`, `?sort`
@ -145,7 +158,7 @@ The missing piece of pururin.to
- https://janda.mod.land/pururin/search?key=futanari&page=2&sort=most-viewed
### Hentaifox
The missing piece of hentaifox.com
The missing piece of hentaifox.com - https://sinkaroid.github.io/jandapress/#api-hentaifox
- `/hentaifox`: hentaifox api
- **get**, takes parameters : `book`
- **search**, takes parameters : `key`, `?page`, `?sort`
@ -157,7 +170,7 @@ The missing piece of hentaifox.com
- https://janda.mod.land/hentaifox/search?key=milf&page=2&sort=latest
### Asmhentai
The missing piece of asmhentai.com
The missing piece of asmhentai.com - https://sinkaroid.github.io/jandapress/#api-asmhentai
- `/asmhentai`: asmhentai api
- **get**, takes parameters : `book`
- **search**, takes parameters : `key`, `?page`
@ -169,7 +182,7 @@ The missing piece of asmhentai.com
- https://janda.mod.land/asmhentai/search?key=futanari&page=2
### Hentai2read
The missing piece of hentai2read.com
The missing piece of hentai2read.com - https://sinkaroid.github.io/jandapress/#api-hentai2read
- `/hentai2read`: hentai2read api
- **get**, takes parameters : `book`
- **search**, takes parameters : `key`
@ -180,7 +193,7 @@ The missing piece of hentai2read.com
- https://janda.mod.land/hentai2read/search?key=futanari
### Simply-hentai
The missing piece of simply-hentai.com
The missing piece of simply-hentai.com - https://sinkaroid.github.io/jandapress/#api-simply-hentai
- `/simply-hentai`: simply-hentai api
- **get**, takes parameters : `book`
- <u>sort parameters on search</u>
@ -189,7 +202,7 @@ The missing piece of simply-hentai.com
- https://janda.mod.land/simply-hentai/get?book=fate-grand-order/fgo-sanbunkatsuhou/all-pages
### 3hentai
The missing piece of 3hentai.net
The missing piece of 3hentai.net - https://sinkaroid.github.io/jandapress/#api-3hentai
- `/3hentai`: 3hentai api
- **get**, takes parameters : `book`
- **search**, takes parameters : `key`, `?page`, `?sort`
@ -200,6 +213,12 @@ The missing piece of 3hentai.net
- https://janda.mod.land/3hentai/get?book=608979
- https://janda.mod.land/3hentai/search?key=futanari&page=2&sort=popular-7d
## Status response
HTTP/1.1 200 OK
HTTP/1.1 200 (cached)
HTTP/1.1 500 (bad parameters)
## 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)
@ -211,10 +230,12 @@ Nhentai was cloudflare protection enabled, If IP and our thoughts against them?
> That's unfortunate, Hit the "Sponsor this project" button, any kind of donations will helps me to funding the development.
## Pronunciation
[`id_ID`](https://www.localeplanet.com/java/id-ID/index.html) • **/jan·da/** — dewasa dan mengikat; _(?)_
[`id_ID`](https://www.localeplanet.com/java/id-ID/index.html) • **/jan·da/** — Dewasa dan mengikat; _(?)_
## Client libraries / Wrappers
Seamlessly integrate with the languages you love, simplified the usage, and intelisense definitions on your IDEs
- [janda](https://github.com/sinkaroid/janda) Python wrapper by [sinkaroid](https://github.com/sinkaroid)
- Or [create your own](https://github.com/sinkaroid/jandapress/edit/master/README.md)

ファイルの表示

@ -1,7 +1,7 @@
{
"name": "jandapress",
"version": "2.0.2-dev",
"description": "Experimental doujin API with gather in mind",
"version": "2.0.3-dev",
"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",
"scripts": {
"build": "rimraf build && tsc",
@ -12,6 +12,9 @@
"start:dev": "ts-node-dev src/index.ts",
"lint": "npx eslint . --ext .ts",
"lint:fix": "npx eslint . --fix",
"build:freshdoc": "rimraf docs && rimraf template && rimraf theme.zip",
"build:template": " npm run build:freshdoc && curl https://codeload.github.com/ScathachGrip/apidocjs-theme/zip/refs/tags/v9 -o theme.zip && unzip theme.zip && mv apidocjs-theme-9 template",
"build:apidoc": "npm run build:template && npx apidoc -i src -o ./docs -t ./template/template-marine",
"test:nhentai": "npx start-server-and-test 3000 \"curl -v http://localhost:3000/nhentai/get?book=177013 | jq '.'\"",
"test:pururin": "npx start-server-and-test 3000 \"curl -v http://localhost:3000/pururin/get?book=47226 | jq '.'\"",
"test:hentaifox": "npx start-server-and-test 3000 \"curl -v http://localhost:3000/hentaifox/get?book=59026 | jq '.'\"",
@ -20,6 +23,12 @@
"test:simply-hentai": "npx start-server-and-test 3000 \"curl -v http://localhost:3000/simply-hentai/get?book=fate-grand-order/fgo-sanbunkatsuhou/all-pages | jq '.'\"",
"test:3hentai": "npx start-server-and-test 3000 \"curl -v http://localhost:3000/3hentai/get?book=608979 | jq '.'\""
},
"apidoc": {
"title": "Jandapress API Documentation",
"url" : "https://janda.mod.land",
"sampleUrl": "https://janda.mod.land",
"name": "Jandapress"
},
"keywords": [],
"author": "sinkaroid",
"repository": {
@ -31,12 +40,14 @@
"@keyv/redis": "^2.5.4",
"cheerio": "^1.0.0-rc.11",
"cors": "^2.8.5",
"dotenv": "^16.0.1",
"express": "^4.18.1",
"express-rate-limit": "^6.4.0",
"express-slow-down": "^1.4.0",
"keyv": "^4.5.2",
"phin": "^3.6.1",
"pino": "^8.7.0"
"pino": "^8.7.0",
"pino-pretty": "^9.1.1"
},
"devDependencies": {
"@types/cors": "^2.8.12",
@ -46,10 +57,9 @@
"@types/tough-cookie": "^4.0.2",
"@typescript-eslint/eslint-plugin": "^5.18.0",
"@typescript-eslint/parser": "^5.18.0",
"dotenv": "^16.0.1",
"apidoc": "^0.29.0",
"eslint": "^8.29.0",
"npx": "^10.2.2",
"pino-pretty": "^9.1.1",
"rimraf": "^3.0.2",
"start-server-and-test": "^1.14.0",
"ts-node": "^10.8.1",
@ -59,4 +69,4 @@
"engines": {
"node": ">=14"
}
}
}

ファイルの表示

@ -10,6 +10,35 @@ export async function get3hentai(req: Request, res: Response, next: NextFunction
if (!book) throw Error("Parameter book is required");
if (!isNumeric(book)) throw Error("Value must be number");
/**
* @api {get} /3hentai/get?book=:book Get 3hentai
* @apiName Get 3hentai
* @apiGroup 3hentai
* @apiDescription Get a doujinshi on 3hentai based on id
*
* @apiParam {Number} book Book ID
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/3hentai/get?book=123
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/3hentai/get?book=123")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/3hentai/get?book=123") as resp:
* print(await resp.json())
*/
const url = `${c.THREEHENTAI}/d/${book}`;
const data = await scrapeContent(url);
logger.info({

ファイルの表示

@ -5,6 +5,34 @@ import { Request, Response, NextFunction } from "express";
export async function random3hentai(req: Request, res: Response, next: NextFunction) {
try {
/**
* @api {get} /3hentai/random Random 3hentai
* @apiName Random 3hentai
* @apiGroup 3hentai
* @apiDescription Gets random doujinshi on 3hentai
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/3hentai/random
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/3hentai/random")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/3hentai/random") as resp:
* print(await resp.json())
*
*/
const url = `${c.THREEHENTAI}/random`;
const data = await scrapeContent(url);
logger.info({

ファイルの表示

@ -12,6 +12,37 @@ export async function search3hentai(req: Request, res: Response, next: NextFunct
if (!key) throw Error("Parameter key is required");
if (!sorting.includes(sort)) throw Error("Invalid sort: " + sorting.join(", "));
/**
* @api {get} /3hentai/search Search 3hentai
* @apiName Search 3hentai
* @apiGroup 3hentai
* @apiDescription Search doujinshi on 3hentai
* @apiParam {String} key Keyword to search
* @apiParam {Number} [page=1] Page number
* @apiParam {String} [sort=recent]
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/3hentai/search?key=yuri
* curl -i https://janda.mod.land/3hentai/search?key=yuri&page=2&sort=recent
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/3hentai/search?key=yuri")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/3hentai/search?key=yuri") as resp:
* print(await resp.json())
*/
const url = `${c.THREEHENTAI}/search?q=${key}&page=${page}&sort=${sort}`;
const data = await scrapeContent(url);
logger.info({

ファイルの表示

@ -10,6 +10,35 @@ export async function getAsmhentai(req: Request, res: Response, next: NextFuncti
if (!book) throw Error("Parameter book is required");
if (!isNumeric(book)) throw Error("Value must be number");
/**
* @api {get} /asmhentai/get?book=:book Get asmhentai
* @apiName Get asmhentai
* @apiGroup asmhentai
* @apiDescription Get a doujinshi on asmhentai based on id
*
* @apiParam {Number} book Book ID
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/asmhentai/get?book=123
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/asmhentai/get?book=123")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/asmhentai/get?book=123") as resp:
* print(await resp.json())
*/
const url = `${c.ASMHENTAI}/g/${book}/`;
const data = await scrapeContent(url);
logger.info({

ファイルの表示

@ -5,6 +5,34 @@ import { Request, Response, NextFunction } from "express";
export async function randomAsmhentai(req: Request, res: Response, next: NextFunction) {
try {
/**
* @api {get} /asmhentai/random Random asmhentai
* @apiName Random asmhentai
* @apiGroup asmhentai
* @apiDescription Gets random doujinshi on asmhentai
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/asmhentai/random
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/asmhentai/random")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/asmhentai/random") as resp:
* print(await resp.json())
*
*/
const url = `${c.ASMHENTAI}/random/`;
const data = await scrapeContent(url);
logger.info({

ファイルの表示

@ -10,6 +10,35 @@ export async function searchAsmhentai(req: Request, res: Response, next: NextFun
if (!key) throw Error("Parameter key is required");
/**
* @api {get} /asmhentai/search Search asmhentai
* @apiName Search asmhentai
* @apiGroup asmhentai
* @apiDescription Search doujinshi on asmhentai
* @apiParam {String} key Keyword to search
* @apiParam {Number} [page=1] Page number
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/asmhentai/search?key=yuri
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/asmhentai/search?key=yuri")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/asmhentai/search?key=yuri") as resp:
* print(await resp.json())
*/
const url = `${c.ASMHENTAI}/search/?q=${key}&page=${page}`;
const data = await scrapeContent(url);
logger.info({

ファイルの表示

@ -9,6 +9,35 @@ export async function getHentai2read(req: Request, res: Response) {
if (!book) throw Error("Parameter book is required");
if (book.split("/").length !== 2) throw Error("Book must be in format 'book_example/chapter'. Example: 'fate_lewd_summoning/1'");
/**
* @api {get} /hentai2read/get?book=:book Get hentai2read
* @apiName Get hentai2read
* @apiGroup hentai2read
* @apiDescription Get a doujinshi on hentai2read
*
* @apiParam {String} book Book path
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/hentai2read/get?book=butabako_shotaone_matome_fgo_hen/1
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/hentai2read/get?book=butabako_shotaone_matome_fgo_hen/1")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/hentai2read/get?book=butabako_shotaone_matome_fgo_hen/1") as resp:
* print(await resp.json())
*/
const url = `${c.HENTAI2READ}/${book}/`;
const data = await scrapeContent(url);
logger.info({

ファイルの表示

@ -7,6 +7,34 @@ export async function searchHentai2read(req: Request, res: Response, next: NextF
try {
const key = req.query.key || "";
if (!key) throw Error("Parameter book is required");
/**
* @api {get} /hentai2read/search Search hentai2read
* @apiName Search hentai2read
* @apiGroup hentai2read
* @apiDescription Search doujinshi on hentai2read
* @apiParam {String} key Keyword to search
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/hentai2read/search?key=yuri
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/hentai2read/search?key=yuri")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/hentai2read/search?key=yuri") as resp:
* print(await resp.json())
*/
const url = `${c.HENTAI2READ}/hentai-list/search/${key}`;
const data = await scrapeContent(url);

ファイルの表示

@ -10,6 +10,35 @@ export async function getHentaifox(req: Request, res: Response, next: NextFuncti
if (!book) throw Error("Parameter book is required");
if (!isNumeric(book)) throw Error("Parameter book must be number");
/**
* @api {get} /hentaifox/get?book=:book Get hentaifox
* @apiName Get hentaifox
* @apiGroup hentaifox
* @apiDescription Get a doujinshi on hentaifox based on id
*
* @apiParam {Number} book Book ID
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/hentaifox/get?book=123
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/hentaifox/get?book=123")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/hentaifox/get?book=123") as resp:
* print(await resp.json())
*/
const url = `${c.HENTAIFOX}/gallery/${book}/`;
const data = await scrapeContent(url);
logger.info({

ファイルの表示

@ -5,6 +5,33 @@ import { logger } from "../../utils/logger";
export async function randomHentaifox(req: Request, res: Response, next: NextFunction) {
try {
/**
* @api {get} /hentaifox/random Random hentaifox
* @apiName Random hentaifox
* @apiGroup hentaifox
* @apiDescription Gets random doujinshi on hentaifox
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/hentaifox/random
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/hentaifox/random")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/hentaifox/random") as resp:
* print(await resp.json())
*
*/
const url = `${c.HENTAIFOX}/random`;
const data = await scrapeContent(url);
logger.info({

ファイルの表示

@ -6,6 +6,37 @@ import { Request, Response, NextFunction } from "express";
export async function searchHentaifox(req: Request, res: Response, next: NextFunction) {
try {
/**
* @api {get} /hentaifox/search Search hentaifox
* @apiName Search hentaifox
* @apiGroup hentaifox
* @apiDescription Search doujinshi on hentaifox
* @apiParam {String} key Keyword to search
* @apiParam {Number} [page=1] Page number
* @apiParam {String} [sort=latest]
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/hentaifox/search?key=yuri
* curl -i https://janda.mod.land/hentaifox/search?key=yuri&page=2&sort=latest
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/hentaifox/search?key=yuri")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/hentaifox/search?key=yuri") as resp:
* print(await resp.json())
*/
const key = req.query.key as string;
const page = req.query.page || 1;
const sort = req.query.sort as string || sorting[0] as string;

ファイルの表示

@ -13,6 +13,35 @@ export async function getNhentai(req: Request, res: Response) {
let actualAPI;
if (!await mock(c.NHENTAI)) actualAPI = c.NHENTAI_IP_3;
else actualAPI = c.NHENTAI;
/**
* @api {get} /nhentai/get?book=:book Get nhentai
* @apiName Get nhentai
* @apiGroup nhentai
* @apiDescription Get a doujinshi on nhentai based on id
*
* @apiParam {Number} book Book ID
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/nhentai/get?book=123
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/nhentai/get?book=123")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/nhentai/get?book=123") as resp:
* print(await resp.json())
*/
const url = `${actualAPI}/api/gallery/${book}`;
const data = await scrapeContent(url);

ファイルの表示

@ -13,6 +13,34 @@ export async function randomNhentai(req: Request, res: Response, next: NextFunct
const id = await getIdRandomNhentai();
/**
* @api {get} /nhentai/random Random nhentai
* @apiName Random nhentai
* @apiGroup nhentai
* @apiDescription Gets random doujinshi on nhentai
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/nhentai/random
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/nhentai/random")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/nhentai/random") as resp:
* print(await resp.json())
*
*/
const url = `${actualAPI}/api/gallery/${id}`;
const data = await scrapeContent(url, true);
logger.info({

ファイルの表示

@ -13,6 +13,35 @@ export async function relatedNhentai(req: Request, res: Response) {
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
* @apiName Get related nhentai
* @apiGroup nhentai
* @apiDescription Get related or similar doujinshi on nhentai based on id
*
* @apiParam {Number} book Book ID
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/nhentai/related?book=123
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/nhentai/related?book=123")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/nhentai/related?book=123") as resp:
* print(await resp.json())
*/
const url = `${actualAPI}/api/gallery/${book}/related`;
const data = await scrapeContent(url);

ファイルの表示

@ -17,6 +17,37 @@ export async function searchNhentai(req: Request, res: Response) {
if (!await mock(c.NHENTAI)) actualAPI = c.NHENTAI_IP_3;
else actualAPI = c.NHENTAI;
/**
* @api {get} /nhentai/search Search nhentai
* @apiName Search nhentai
* @apiGroup nhentai
* @apiDescription Search doujinshi on nhentai
* @apiParam {String} key Keyword to search
* @apiParam {Number} [page=1] Page number
* @apiParam {String} [sort=popular-today]
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/nhentai/search?key=yuri
* curl -i https://janda.mod.land/nhentai/search?key=yuri&page=2&sort=popular-today
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/nhentai/search?key=yuri")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/nhentai/search?key=yuri") as resp:
* print(await resp.json())
*/
const url = `${actualAPI}/api/galleries/search?query=${key}&sort=${sort}&page=${page}`;
const data = await scrapeContent(url);
logger.info({

ファイルの表示

@ -10,6 +10,35 @@ export async function getPururin(req: Request, res: Response, next: NextFunction
if (!book) throw Error("Parameter book is required");
if (!isNumeric(book)) throw Error("Parameter book must be number");
/**
* @api {get} /pururin/get?book=:book Get pururin
* @apiName Get pururin
* @apiGroup pururin
* @apiDescription Get a doujinshi on pururin based on id
*
* @apiParam {Number} book Book ID
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/pururin/get?book=123
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/pururin/get?book=123")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/pururin/get?book=123") as resp:
* print(await resp.json())
*/
const url = `${c.PURURIN}/gallery/${book}/janda`;
const data = await scrapeContent(url);
logger.info({

ファイルの表示

@ -7,6 +7,35 @@ import { Request, Response, NextFunction } from "express";
export async function randomPururin(req: Request, res: Response, next: NextFunction) {
try {
const id = await getIdRandomPururin();
/**
* @api {get} /pururin/random Random pururin
* @apiName Random pururin
* @apiGroup pururin
* @apiDescription Gets random doujinshi on pururin
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/pururin/random
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/pururin/random")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/pururin/random") as resp:
* print(await resp.json())
*
*/
const url = `${c.PURURIN}/gallery/${id}/janda`;
const data = await scrapeContent(url, true);
logger.info({

ファイルの表示

@ -11,6 +11,37 @@ export async function searchPururin(req: Request, res: Response, next: NextFunct
const sort = req.query.sort as string || sorting[0] as string;
if (!key) throw Error("Parameter key is required");
if (!sorting.includes(sort)) throw Error("Invalid sort: " + sorting.join(", "));
/**
* @api {get} /pururin/search Search pururin
* @apiName Search pururin
* @apiGroup pururin
* @apiDescription Search doujinshi on pururin
* @apiParam {String} key Keyword to search
* @apiParam {Number} [page=1] Page number
* @apiParam {String} [sort=newest]
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/pururin/search?key=yuri
* curl -i https://janda.mod.land/pururin/search?key=yuri&page=2&sort=newest
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/pururin/search?key=yuri")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/pururin/search?key=yuri") as resp:
* print(await resp.json())
*/
const url = `${c.PURURIN}/search/${sort}?q=${key}&page=${page}`;
const data = await scrapeContent(url);

ファイルの表示

@ -11,6 +11,35 @@ export async function getSimplyhentai(req: Request, res: Response) {
let actualAPI;
if (!await mock(c.SIMPLY_HENTAI)) actualAPI = c.SIMPLY_HENTAI_PROXIFIED;
/**
* @api {get} /simply-hentai/get?book=:book Get simply-hentai
* @apiName Get simply-hentai
* @apiGroup simply-hentai
* @apiDescription Get a doujinshi on simply-hentai
*
* @apiParam {String} book Book path
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* HTTP/1.1 200 (cached)
*
* @apiExample {curl} curl
* curl -i https://janda.mod.land/simply-hentai/get?book=fate-grand-order/fgo-sanbunkatsuhou/all-pages
*
* @apiExample {js} JS/TS
* import axios from "axios"
*
* axios.get("https://janda.mod.land/simply-hentai/get?book=fate-grand-order/fgo-sanbunkatsuhou/all-pages")
* .then(res => console.log(res.data))
* .catch(err => console.error(err))
*
* @apiExample {python} Python
* import aiohttp
* async with aiohttp.ClientSession() as session:
* async with session.get("https://janda.mod.land/simply-hentai/get?book=fate-grand-order/fgo-sanbunkatsuhou/all-pages") as resp:
* print(await resp.json())
*/
const url = `${actualAPI}/${book}`;
const data = await scrapeContent(url);

ファイルの表示

@ -12,7 +12,6 @@ const janda = new JandaPress();
const app = express();
dotenv.config();
app.get("/", slow, limiter, (req, res) => {
res.send({
success: true,

ファイルの表示

@ -1,5 +1,7 @@
import { Router } from "express";
import cors from "cors";
import { slow, limiter } from "../utils/limit-options";
import { searchHentaifox } from "../controller/hentaifox/hentaifoxSearch";
import { getHentaifox } from "../controller/hentaifox/hentaifoxGet";
import { getPururin } from "../controller/pururin/pururinGet";
@ -20,7 +22,6 @@ import { get3hentai } from "../controller/3hentai/3hentaiGet";
import { search3hentai } from "../controller/3hentai/3hentaiSearch";
import { random3hentai } from "../controller/3hentai/3hentaiRandom";
import { slow, limiter } from "../utils/limit-options";
function scrapeRoutes() {
const router = Router();