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-hitomi- 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.
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');GalleryManager lets you retrieve individual galleries and list matching gallery references.
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}`);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.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 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)`);TagManager helps you create, parse, search, and list tags.
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);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);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)`);
}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));
}Resolves an image URL in the requested format and optional thumbnail size.
Warning
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 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}`);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);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);
}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);
}Contributions are welcome. Feel free to open an issue for bugs or submit a pull request with improvements.
This project is licensed under the MIT License.
