node-hitomi
Version:
Hitomi.la API for Node.js
98 lines (94 loc) • 3.4 kB
JavaScript
;
const gallery = require('./managers/gallery.cjs');
const tag = require('./managers/tag.cjs');
const constants = require('./internal/constants.cjs');
const providers = require('./internal/providers.cjs');
const error = require('./structures/error.cjs');
const node = require('./platform/node.cjs');
const base = require('./internal/base.cjs');
class Hitomi {
static getMaximumAge(options, key, defaultValue) {
if(options[key] === 0) {
return 0;
}
if(!options[key]) {
return defaultValue;
}
if(!Number.isInteger(options[key]) || options[key] < 0) {
throw new error.HitomiError(error.ErrorCode.InvalidArgument, 'Options.' + key, 'a non-negative integer');
}
return options[key];
}
static async fetchImageContext() {
const response = await this.hitomi.request(constants.RESOURCE_DOMAIN, '/gg.js', 2);
const context = [new Set(), false, ''];
let currentIndex = 0;
let nextIndex;
while((currentIndex = response.indexOf('case ', currentIndex) + 5) !== 4 &&
(nextIndex = response.indexOf(':', currentIndex)) !== -1) {
const subdomainCode = +response.slice(currentIndex, nextIndex);
if(!Number.isInteger(subdomainCode)) {
throw error.HitomiError.unparsableImageContext;
}
context[0].add(subdomainCode);
currentIndex = nextIndex + 1;
}
if(!context[0].size) {
throw error.HitomiError.unparsableImageContext;
}
currentIndex = response.indexOf('var o = ') + 8;
const rawIsSuffix1 = +response.slice(currentIndex, response.indexOf(';', currentIndex));
if(!Number.isInteger(rawIsSuffix1)) {
throw error.HitomiError.unparsableImageContext;
}
context[1] = !rawIsSuffix1;
currentIndex = response.lastIndexOf('b: \'') + 4;
if(currentIndex === 3) {
throw error.HitomiError.unparsableImageContext;
}
context[2] = response.slice(currentIndex, response.indexOf('\'', currentIndex));
if(!context[2].length) {
throw error.HitomiError.unparsableImageContext;
}
return context;
}
constructor(options = {}) {
options = Object.assign({}, options);
options.onRequest = options.agent ? function (context) {
context.options.agent = options.agent;
return context;
} : options.onRequest;
base.defineProperties(this, {
request: options.transport ? async function (host, path, type, range) {
const context = node.createContext(host, path, type, range);
const buffer = await options.transport(await this.onRequest(context) || context);
switch(type) {
case 0: {
return buffer;
}
case 1: {
return new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
}
case 2: {
return node.toString(buffer);
}
case 3: {
return JSON.parse(node.toString(buffer));
}
}
} : node.request,
onRequest: options.onRequest || function () { },
hashTerm: options.computeHash ? async function (text) {
return (await options.computeHash(text)).subarray(0, 4);
} : node.hashTerm,
indexMaximumAge: Hitomi.getMaximumAge(options, 'indexMaximumAge', 600000)
});
this.galleries = new gallery.GalleryManager(this);
this.tags = new tag.TagManager(this);
base.defineProperties(this, {
languageIndex: new providers.IndexProvider(this, 'languages'),
imageContext: new providers.Provider(this, Hitomi.fetchImageContext, Hitomi.getMaximumAge(options, 'imageContextMaximumAge', 3600000))
});
}
}
exports.Hitomi = Hitomi;