UNPKG

node-hitomi

Version:
96 lines (93 loc) 3.35 kB
import { GalleryManager } from './managers/gallery.js'; import { TagManager } from './managers/tag.js'; import { RESOURCE_DOMAIN } from './internal/constants.js'; import { Provider, IndexProvider } from './internal/providers.js'; import { HitomiError, ErrorCode } from './structures/error.js'; import { hashTerm, createContext, toString, request } from './platform/browser.js'; import { defineProperties } from './internal/base.js'; 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 HitomiError(ErrorCode.InvalidArgument, 'Options.' + key, 'a non-negative integer'); } return options[key]; } static async fetchImageContext() { const response = await this.hitomi.request(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 HitomiError.unparsableImageContext; } context[0].add(subdomainCode); currentIndex = nextIndex + 1; } if(!context[0].size) { throw HitomiError.unparsableImageContext; } currentIndex = response.indexOf('var o = ') + 8; const rawIsSuffix1 = +response.slice(currentIndex, response.indexOf(';', currentIndex)); if(!Number.isInteger(rawIsSuffix1)) { throw HitomiError.unparsableImageContext; } context[1] = !rawIsSuffix1; currentIndex = response.lastIndexOf('b: \'') + 4; if(currentIndex === 3) { throw HitomiError.unparsableImageContext; } context[2] = response.slice(currentIndex, response.indexOf('\'', currentIndex)); if(!context[2].length) { throw 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; defineProperties(this, { request: options.transport ? async function (host, path, type, range) { const context = 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 toString(buffer); } case 3: { return JSON.parse(toString(buffer)); } } } : request, onRequest: options.onRequest || function () { }, hashTerm: options.computeHash ? async function (text) { return (await options.computeHash(text)).subarray(0, 4); } : hashTerm, indexMaximumAge: Hitomi.getMaximumAge(options, 'indexMaximumAge', 600000) }); this.galleries = new GalleryManager(this); this.tags = new TagManager(this); defineProperties(this, { languageIndex: new IndexProvider(this, 'languages'), imageContext: new Provider(this, Hitomi.fetchImageContext, Hitomi.getMaximumAge(options, 'imageContextMaximumAge', 3600000)) }); } } export { Hitomi };