npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

node-hitomi

v9.2.0

Published

Hitomi.la API for Node.js

Readme

banner

Hitomi.la API for Node.js

Would you call me a gentleman?

npm version npm type definition ci status license

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-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);
}

[!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 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.

[!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 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.