npm.io
9.2.0 • Published 1 week ago

node-hitomi

Licence
MIT
Version
9.2.0
Deps
0
Size
129 kB
Vulns
0
Weekly
0
Stars
37

banner

Hitomi.la API for Node.js

Would you call me a gentleman?

npm version npm type definition ci status license

Installation

Due to frequent changes on Hitomi.la, it is highly recommended to use the latest version.

Node.js 10.20 or newer is required.

npm install node-hitomi
yarn add node-hitomi
pnpm add node-hitomi
bun add node-hitomi
deno add npm:node-hitomi

Features

  • Gallery Search: Filter by tags and title, choose sort order, and paginate results.
  • Gallery Retrieval: Load full gallery metadata, including title, type, language, artists, and relations.
  • Tag Management: Create, parse, search, and list tags. Also list available languages for a tag.
  • Image Downloads: Resolve URLs and fetch images in AVIF/WebP/JXL (when available), with optional thumbnail sizes.
  • Video Downloads: Fetch gallery videos and poster images.

Usage

The package exports a default client, but you can also create your own client for custom configuration.

import { Hitomi, RequestContext } from 'node-hitomi';
import { Agent, RequestOptions } from 'https';

const agent: Agent = new Agent({
	keepAlive: true,
	// Bypass server name indication field blocking
	servername: '',
	rejectUnauthorized: false
});

const hitomi = new Hitomi({
	onRequest: function (context: RequestContext<RequestOptions>): void {
		// Inspect or modify the request context before each HTTP request
		console.log(context);

		context.options.agent = agent;

		context.options.headers['X-Forwarded-Host'] = context.host;
		context.host = 'proxy.example.com';
	},
	indexMaximumAge: 300000,
	imageContextMaximumAge: 1800000
});

If you use CommonJS:

const { hitomi, SortType /* and more... */ } = require('node-hitomi');

Galleries

GalleryManager lets you retrieve individual galleries and list matching gallery references.

GalleryManager.retrieve(id)

Retrieves a full Gallery by its id.

import hitomi from 'node-hitomi';

// Retrieve a gallery by id
const gallery = await hitomi.galleries.retrieve(123456);

console.log(`Title: ${gallery.title.display}`);
console.log(`Type: ${gallery.type}`);
console.log(`Language: ${gallery.language?.name}`);
GalleryManager.list(options?)

Lists galleries that match the given criteria and returns GalleryReference[]. You can pass tags, a title query, sort options, and paging options.

import hitomi, { SortType } from 'node-hitomi';

// Parse a search expression into tags
const tags = hitomi.tags.parse('male:sole_male -female:netorare series:blue_archive');

// List matching gallery references
const references = await hitomi.galleries.list({
	tags: tags,
	title: 'serina',
	orderBy: SortType.PopularityMonth
});

// Resolve the first reference to a full gallery
if(references.length > 0) {
	const firstGallery = await references[0].retrieve();
	console.log(firstGallery.title.display);
}

Not every options.page usage is valid. It must meet the restrictions below.

  • Only one non-language tag is allowed (optionally combined with a language tag).
  • Negative tags and title queries are not supported.
const simpleTags = hitomi.tags.parse('type:manga language:english');

// List matching gallery references with pagination
const pagedReferences = await hitomi.galleries.list({
	tags: simpleTags,
	orderBy: SortType.DatePublished,
	page: {
		index: 0,
		size: 25
	}
});

console.log(pagedReferences, `(${pagedReferences.length} galleries)`);

Tags

TagManager helps you create, parse, search, and list tags.

TagManager.create(type, name, isNegative?)

Creates a Tag from a type and name. You can pass true to make it negative.

import hitomi from 'node-hitomi';

// Create a series tag and list available languages for that tag
const tag = hitomi.tags.create('series', 'trickcal_revive', false);
const languages = await tag.listLanguages();

console.log(languages);
TagManager.parse(expression)

Parses a space-separated expression into unique Tag[]. The expected format is [-]type:name, where spaces are represented by underscores.

import hitomi from 'node-hitomi';

// Parse a string expression into tags
const parsedTags = hitomi.tags.parse('female:yandere male:sole_male -tag:group');

console.log(parsedTags);
TagManager.search(term)

Searches tags by partial term and returns tuples of [Tag, count], where count is the number of galleries associated with each tag.

import hitomi from 'node-hitomi';

// Search tags and print their gallery counts
const tagAndCounts = await hitomi.tags.search('character:agnes');

for(const [tag, count] of tagAndCounts) {
	console.log(`${String(tag)} (${count} galleries)`);
}
TagManager.list(type, startsWith?)

Lists tags of a specific type, optionally filtered by an initial character.

import hitomi, { NameInitial } from 'node-hitomi';

// List female tags that start with 'a'
const femaleATags = await hitomi.tags.list('female', NameInitial.A);

for(const tag of femaleATags) {
	console.log(String(tag));
}

Media
Image.resolveUrl(extension, thumbnailSize?)

Resolves an image URL in the requested format and optional thumbnail size.

Not every extension and thumbnailSize combination is valid. It must meet the restrictions below.

Thumbnail Size Extension Requirement (must be true)
(none) (all) has{Extension}
Small (all) has{Extension}
Medium Avif hasThumbnail && has{Extension}
Big (all) hasThumbnail && has{Extension}
import hitomi, { Extension, ThumbnailSize } from 'node-hitomi';

// Retrieve a gallery by id and get representative thumbnails
const gallery = await hitomi.galleries.retrieve(123456);
const thumbnails = gallery.getThumbnails();

// Resolve the full-size WebP URL
const imageUrl = await thumbnails[0].resolveUrl(Extension.Webp);
console.log(`Image URL: ${imageUrl}`);

// Resolve the medium AVIF thumbnail URL
const thumbnailUrl = await thumbnails[1].resolveUrl(Extension.Avif, ThumbnailSize.Medium);
console.log(`Thumbnail URL: ${thumbnailUrl}`);
Image.fetch(extension, thumbnailSize?)

Fetches an image as a Uint8Array. The same extension and thumbnailSize restrictions as Image.resolveUrl apply.

import hitomi, { Extension, ThumbnailSize } from 'node-hitomi';
import { writeFileSync } from 'fs';

// Retrieve a gallery by id and get representative thumbnails
const gallery = await hitomi.galleries.retrieve(123456);
const thumbnails = gallery.getThumbnails();

// Fetch and save the full-size WebP image
const imageBuffer = await thumbnails[0].fetch(Extension.Webp);
writeFileSync('image.webp', imageBuffer);

// Fetch and save the medium AVIF thumbnail
const thumbnailBuffer = await thumbnails[1].fetch(Extension.Avif, ThumbnailSize.Medium);
writeFileSync('thumbnail.avif', thumbnailBuffer);
Video.fetch()

Fetches a gallery video as an MP4 Uint8Array.

import hitomi from 'node-hitomi';
import { writeFileSync } from 'fs';

const gallery = await hitomi.galleries.retrieve(123456);

if(gallery.video) {
	// Fetch and store the MP4 video
	const videoBuffer = await gallery.video.fetch();
	writeFileSync('video.mp4', videoBuffer);
}
Video.fetchPoster()

Fetches the video poster as a WebP Uint8Array.

import hitomi from 'node-hitomi';
import { writeFileSync } from 'fs';

const gallery = await hitomi.galleries.retrieve(123456);

if(gallery.video) {
	// Fetch and store the WebP poster image
	const posterBuffer = await gallery.video.fetchPoster();
	writeFileSync('poster.webp', posterBuffer);
}

Contribution

Contributions are welcome. Feel free to open an issue for bugs or submit a pull request with improvements.

License

This project is licensed under the MIT License.