RenaiApp/src/main/services/nhentai-crawler.ts

99 lines
2.6 KiB
TypeScript

import { JSDOM } from 'jsdom';
import { RequestInit, Response } from 'node-fetch';
import RenaiError, { Errors } from '../../types/error';
import fetch from './web-crawler';
const url = 'https://nhentai.net/';
const paths = {
books: 'g/',
login: 'login/',
favorites: 'favorites/',
};
const usernameInput = 'username_or_email';
const passwordInput = 'password';
interface ILoginMeta {
[key: string]: string;
}
interface ILoginAuth {
[usernameInput]: string;
[passwordInput]: string;
}
interface ILoginParams extends ILoginMeta, ILoginAuth {}
function login(name: string, password: string): Promise<void> {
return getLoginMeta()
.then((meta: ILoginMeta) => {
const loginParams: ILoginParams = {
...meta,
...{
// tslint:disable-next-line: object-literal-sort-keys
username_or_email: name,
password,
},
};
return postNHentai(paths.login, {
body: encodeURI(
Object.keys(loginParams)
.map((key: keyof ILoginParams) => `${key}=${loginParams[key]}`)
.join('&')
),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
})
.then(() => {})
.catch(() => Promise.reject(new RenaiError(Errors.ELOGINFAIL)));
}
function getNHentai(path: string): Promise<Document> {
return fetch(`${url}${path}`)
.then((res: Response) => {
return res.text();
})
.then((text: string) => {
const { document } = new JSDOM(text).window;
return document;
});
}
function postNHentai(path: string, init: RequestInit = {}): Promise<Response> {
return fetch(`${url}${path}`, { ...init, ...{ method: 'post' } });
}
function getLoginMeta(): Promise<ILoginMeta> {
return getNHentai(paths.login).then((document: Document) => {
// tslint:disable-next-line: prefer-for-of
for (let i = 0; i < document.forms.length; i++) {
const form: HTMLFormElement = document.forms[i];
const valueStore: ILoginMeta = {};
let isLoginForm = false;
// tslint:disable-next-line: prefer-for-of
for (let j = 0; j < form.elements.length; j++) {
const input = form.elements[j];
const name = input.getAttribute('name');
if (name === usernameInput || name === passwordInput) {
isLoginForm = true;
} else if (name) {
valueStore[name] = input.getAttribute('value');
}
}
if (isLoginForm) {
return valueStore;
}
}
return Promise.reject(new RenaiError(Errors.ENOLOGIN));
});
}
export default {
login,
};