node-hitomi
v9.1.1
Published
Hitomi.la API for Node.js
Maintainers
Readme
Hitomi.la API for Node.js
Would you call me a gentleman?
Installation
[!IMPORTANT]
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-hitomiFeatures
- 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 instance, but you can also create your own client for custom configuration.
import { Hitomi } from 'node-hitomi';
import { Agent } from 'https';
const agent = new Agent({
keepAlive: true,
// Bypass server name indication field blocking
servername: '',
rejectUnauthorized: false
});
const hitomi = new Hitomi({
agent: agent,
indexMaximumAge: 300000,
imageContextMaximumAge: 1800000
});If you use CommonJS module:
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 id and returns a Gallery instance.
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. You can pass tags, a title query, sort options, and paging options. The method returns GalleryReference[].
import hitomi, { SortType } from 'node-hitomi';
// Parse a search expression into structured tag objects
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);
}[!WARNING]
Not every
options.pageusage 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 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 instance with a type, name, and optional negation flag.
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 human-readable expression into unique Tag instances. The expected format is [-]type:name, where spaces are represented by underscores.
import hitomi from 'node-hitomi';
// Parse a string expression into Tag instances
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.
[!WARNING]
Not every
extensionandthumbnailSizecombination 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 thumbnail available images
const gallery = await hitomi.galleries.retrieve(123456);
const thumbnails = gallery.getThumbnails();
// Full-size WebP URL
const imageUrl = await thumbnails[0].resolveUrl(Extension.Webp);
console.log(`Image URL: ${imageUrl}`);
// AVIF medium 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 Buffer. The same extension and thumbnail constraints as Image.resolveUrl apply.
import hitomi, { Extension, ThumbnailSize } from 'node-hitomi';
import { writeFileSync } from 'fs';
// Retrieve a gallery by id and get thumbnail available images
const gallery = await hitomi.galleries.retrieve(123456);
const thumbnails = gallery.getThumbnails();
// Fetch and save a full-size image
const imageBuffer = await thumbnails[0].fetch(Extension.Webp);
writeFileSync('image.webp', imageBuffer);
// Fetch and save a medium thumbnail
const thumbnailBuffer = await thumbnails[1].fetch(Extension.Avif, ThumbnailSize.Medium);
writeFileSync('thumbnail.avif', thumbnailBuffer);Video.fetch()
Fetches a gallery video as an MP4 Buffer.
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 Buffer.
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.

