@nekolab/hanime
Version:
Fast and efficient hanime.tv API wrapper written in TypeScript.
187 lines (186 loc) • 6.17 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HanimeClient = void 0;
const crypto_1 = require("../modules/crypto");
const requests_1 = require("./requests");
const constants_1 = require("../constants");
const logging_1 = require("./logging");
const utility_1 = require("../modules/utility");
/**
* Hanime client. Based on mobile and web API.
*/
class HanimeClient {
/**
* Requests client
*/
reqClient;
/**
* Logging client
*/
loggingClient;
/**
* User session token
*/
sessionToken = null;
/**
* Information about the app and currently logged in user
*/
info = null;
/**
* Base URL for the requests
*/
BASE_URLS = {
appV8: 'https://www.universal-cdn.com/api/v8',
app: 'https://www.universal-cdn.com/rapi/v4',
web: 'https://hanime.tv/',
search: '',
};
/**
* Create a new instance of the AppClient
* @param sessionToken User session token
* @returns AppClient instance
*/
constructor(sessionToken, loggingConfig = { enabled: false, level: 'info' }) {
this.sessionToken = sessionToken || null;
this.loggingClient = new logging_1.LoggingClient(loggingConfig);
this.reqClient = new requests_1.RequestsClient(({ baseUrl }) => {
const t = Math.floor(new Date().getTime() / 1000);
return baseUrl === this.BASE_URLS.web
? {
'x-time': t.toString(),
'x-signature-version': 'web2',
'x-session-token': this.sessionToken || '',
}
: {
'x-claim': t.toString(),
'x-signature-version': 'app2',
'x-signature': (0, crypto_1.getAppSignature)(t),
'x-session-token': this.sessionToken || '',
};
}, this.loggingClient);
}
/**
* Login to the APP
* @param login User login
* @param password User password
* @returns Login response.
*/
async login(login, password) {
const rsp = await this.reqClient.request(this.BASE_URLS.app, '/sessions', {
burger: login,
fries: password, // Just put fries in da bag bro
}, 'POST');
this.sessionToken = rsp.sessionToken;
this.info = rsp;
return rsp;
}
/**
* Get base info about current user
* @returns User info
*/
async getInfo() {
return this.info || (await this.reqClient.request(this.BASE_URLS.app, '/user_base_data'));
}
/**
* Get the home page
* @returns Home page response
*/
async getHomePage() {
const rsp = await this.reqClient.request(this.BASE_URLS.app, '/home');
rsp.sections = rsp.sections.map((section) => {
section.data = section.data.map((hentaiId) => {
return rsp.hentaiVideos.find((hentai) => hentai.id === hentaiId);
});
return section;
});
return (0, utility_1.omit)(rsp, ['hentaiVideos']);
}
/**
* Claim coins. Raises 401 if cooldown is not over.
* @returns Coins response
*/
async claimCoins() {
if (!this.info) {
this.info = await this.getInfo();
}
const t = Math.floor(new Date().getTime() / 1000);
const signature = (0, crypto_1.getRewardTokenSignature)(t, this.info.user.id, this.info.env.mobileApps.buildNumber);
return await this.reqClient.request(this.BASE_URLS.app, '/coins', {
rewardToken: `${signature}|${t}`,
deviceInfo: constants_1.DEVICE_INFO,
version: this.info.env.mobileApps.buildNumber,
}, 'POST');
}
/**
* Get hentai downloads
* @param slug Slug of the hentai
* @returns Downloads response
*/
async getHentaiDownloads(slug) {
return await this.reqClient.request(this.BASE_URLS.app, `/downloads/${slug}`);
}
/**
* Get hentai video
* @param id ID of the hentai
* @returns Hentai video
*/
async getHentaiVideo(id) {
return await this.reqClient.request(this.BASE_URLS.app, `/hentai-videos/${id}`);
}
/**
* Get current account channel
* @returns Channel response
*/
async getMyChannel() {
return await this.reqClient.request(this.BASE_URLS.web, '/rapi/v7/my_channel');
}
/**
* Get other user channel
* @param slug Slug of the user
* @returns Channel response
*/
async getChannel(slug) {
return await this.reqClient.request(this.BASE_URLS.web, `/rapi/v7/channels/${slug}`);
}
/**
* Get hentai comments
* @param hentaiId ID of the hentai
* @param offset Offset
* @param count Comments count
* @param order Order
* @returns Comments
*/
async getComments(hentaiId, offset = 0, count = 20, sortBy = 'upvotes') {
const params = new URLSearchParams({
hv_id: hentaiId.toString(),
offset: offset.toString(),
count: count.toString(),
order: sortBy === 'createdAt' ? 'created_at,desc' : 'upvotes,desc',
});
return await this.reqClient.request(this.BASE_URLS.appV8, '/hthreads?' + params.toString());
}
/**
* Get comments users
* @param userIds User IDs
* @returns Comment users
*/
async getCommentsUsers(userIds) {
const params = new URLSearchParams({ source: 'comments' });
userIds.forEach((id) => params.append('user_ids[]', id.toString()));
return await this.reqClient.request(this.BASE_URLS.app, '/users?' + params.toString());
}
/**
* Claim Premium
* @returns Premium response
*/
async claimPremium() {
if (!this.info) {
this.info = await this.getInfo();
}
return await this.reqClient.request(this.BASE_URLS.app, '/alt_subscriptions', {
deviceInfo: constants_1.DEVICE_INFO,
version: this.info.env.mobileApps.buildNumber,
}, 'POST');
}
}
exports.HanimeClient = HanimeClient;