UNPKG

node-hitomi

Version:
174 lines (171 loc) 4.29 kB
import { HitomiError, ErrorCode } from '../structures/error.js'; import { TAG_INDEX_DOMAIN, FRONT_DOMAIN } from '../internal/constants.js'; import { Base } from '../internal/base.js'; import { Tag, Language } from '../structures/tag.js'; import { Gallery } from '../structures/gallery.js'; const NameInitial = { A: 'a', B: 'b', C: 'c', D: 'd', E: 'e', F: 'f', G: 'g', H: 'h', I: 'i', J: 'j', K: 'k', L: 'l', M: 'm', N: 'n', O: 'o', P: 'p', Q: 'q', R: 'r', S: 's', T: 't', U: 'u', V: 'v', W: 'w', X: 'x', Y: 'y', Z: 'z', _123: '123' }; class TagManager extends Base { constructor(hitomi) { super(hitomi); } create(type, name, isNegative = false) { if(!name.length) { throw new HitomiError(ErrorCode.InvalidArgument, 'Name', 'empty', false); } return new Tag(this.hitomi, type, name.replace(/_/g, ' '), isNegative); } parse(expression) { expression = expression.trim() + ' '; const tags = []; const rawTags = new Set(); let currentIndex = 0; let nextIndex; while((nextIndex = expression.indexOf(' ', currentIndex)) !== -1) { const colonIndex = expression.indexOf(':', currentIndex); if(colonIndex !== -1 && colonIndex < nextIndex) { const rawTag = expression.slice(currentIndex, nextIndex); const isNegative = expression[currentIndex] === '-'; if(!rawTags.has(rawTag)) { tags.push(new Tag(this.hitomi, expression.slice(currentIndex + isNegative, colonIndex), expression.slice(colonIndex + 1, nextIndex).replace(/_/g, ' '), isNegative)); rawTags.add(rawTag); } } currentIndex = nextIndex + 1; } return tags; } async search(term) { const isNegative = term[0] === '-'; let i = term.indexOf(':') + 1; let path; if(i) { const type = term.slice(isNegative, i - 1); if(!Tag.TYPES.has(type)) { throw HitomiError.invalidMember('Type', Tag.TYPES); } path = '/' + type; } else { if(isNegative) { i++; } path = '/global'; } for(; i < term.length && term[i] !== ':'; i++) { path += '/'; switch(term[i]) { case '.': { path += 'dot'; break; } case '/': { path += 'slash'; break; } default: { path += term[i]; } } } const response = await this.hitomi.request(TAG_INDEX_DOMAIN, path + '.json', 3); const tagAndCounts = []; for(i = 0; i < response.length; i++) { tagAndCounts.push([ new Tag(this.hitomi, response[i][2], response[i][0]), response[i][1] ]); } return tagAndCounts; } async list(type, startsWith) { const tags = []; let names; switch(type) { case 'type': { names = Gallery.TYPES; } case 'language': { if(!names) { names = Language.NAMES; } for(const name of names) { tags.push(new Tag(this.hitomi, type, name)); } break; } default: { if(!startsWith) { throw new HitomiError(ErrorCode.InvalidCombination, 'StartsWith', 'provided except forlanguage and type'); } if(!TagManager.NAME_INITIALS.has(startsWith)) { throw HitomiError.invalidMember('StartsWith', TagManager.NAME_INITIALS); } let target = 'href="/' + type + '/'; let area; switch(type) { case 'male': case 'female': { target = 'href="/tag/' + type + '%3A'; } case 'tag': { area = 'tags'; break; } case 'series': { area = type; break; } case 'artist': case 'character': case 'group': { area = type + 's'; break; } default: { throw HitomiError.invalidMember('Type', Tag.TYPES); } } const response = await this.hitomi.request(FRONT_DOMAIN, '/all' + area + '-' + startsWith + '.html', 2); const endIndex = target.length - 1; let currentIndex; let nextIndex = 0; while((currentIndex = response.indexOf(target, nextIndex) + target.length) !== endIndex) { nextIndex = response.indexOf('.', currentIndex); if(type !== 'tag' || !response.startsWith('male', currentIndex) && !response.startsWith('female', currentIndex)) { tags.push(new Tag(this.hitomi, type, decodeURIComponent(response.slice(currentIndex, nextIndex - 4)))); } } } } return tags; } } TagManager.NAME_INITIALS = new Set(Object.values(NameInitial)); export { NameInitial, TagManager };