99 lines
2.6 KiB
TypeScript
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,
|
|
};
|