Files
zim-utils/README.md
ztimson a2bde0b5cd
All checks were successful
Publish Library / Build NPM Project (push) Successful in 14s
Publish Library / Tag Version (push) Successful in 11s
Fixed server getter
2026-08-24 21:18:24 -04:00

188 lines
7.2 KiB
Markdown

<div id="top" align="center">
<br />
<!-- Logo -->
<img src="https://git.zakscode.com/repo-avatars/c44395fb50d10629bb79ae9294b43884679720fb589b69ea5fc854d790a6d8ec" alt="Logo" width="175" height="200">
<!-- Title -->
### Zim Utils
<!-- Description -->
Node.js wrapper around [kiwix-tools](https://github.com/kiwix/kiwix-tools) for managing a local ZIM library, serving content, and searching both locally and against the Kiwix catalog
<!-- Repo badges -->
[![Version](https://img.shields.io/badge/dynamic/json.svg?label=Version&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/zim-utils/tags&query=$[0].name)](https://git.zakscode.com/ztimson/zim-utils/tags)
[![Pull Requests](https://img.shields.io/badge/dynamic/json.svg?label=Pull%20Requests&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/zim-utils&query=open_pr_counter)](https://git.zakscode.com/ztimson/zim-utils/pulls)
[![Issues](https://img.shields.io/badge/dynamic/json.svg?label=Issues&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/zim-utils&query=open_issues_count)](https://git.zakscode.com/ztimson/zim-utils/issues)
<!-- Links -->
---
<div>
<a href="https://git.zakscode.com/ztimson/zim-utils/wiki" target="_blank">Documentation</a>
• <a href="https://git.zakscode.com/ztimson/zim-utils/releases" target="_blank">Release Notes</a>
• <a href="https://git.zakscode.com/ztimson/zim-utils/issues/new?template=.github%2fissue_template%2fbug.md" target="_blank">Report a Bug</a>
• <a href="https://git.zakscode.com/ztimson/zim-utils/issues/new?template=.github%2fissue_template%2fenhancement.md" target="_blank">Request a Feature</a>
</div>
---
</div>
## Table of Contents
- [Zim Utils](#top)
- [About](#about)
- [Built With](#built-with)
- [Setup](#setup)
- [Production](#production)
- [Usage](#usage)
- [KiwixServer](#kiwixserver)
- [Catalog](#catalog)
- [License](#license)
## About
`@ztimson/zim-utils` manages a local [ZIM](https://wiki.openzim.org/wiki/ZIM_file_format) library by driving the official [kiwix-tools](https://github.com/kiwix/kiwix-tools) binaries (`kiwix-serve`, `kiwix-manage`) as child processes, rather than re-implementing ZIM reading from scratch. This means content serving, indexing, and fulltext search all come straight from Kiwix's own battle-tested implementation.
It comes with:
- **`KiwixServer`** — Owns a directory of `.zim` files: builds/rebuilds `library.xml`, starts/stops `kiwix-serve`, lists the local library, runs fulltext search, and resolves content URLs/bytes for any archive+page
- **Catalog** (`zimCatalog`/`zimCatalogInfo`) — Helper functions to search the remote Kiwix OPDS catalog, for discovering and downloading new ZIMs
### Built With
[![Node](https://img.shields.io/badge/Node.js-000000?style=for-the-badge&logo=nodedotjs)](https://nodejs.org/)
[![JavaScript](https://img.shields.io/badge/JavaScript-000000?style=for-the-badge&logo=javascript)](https://javascript.com/)
[![Kiwix](https://img.shields.io/badge/kiwix--tools-000000?style=for-the-badge&logo=kiwix)](https://github.com/kiwix/kiwix-tools)
## Setup
<details>
<summary>
<h3 id="production" style="display: inline">
Production
</h3>
</summary>
#### Prerequisites
- [Node.js](https://nodejs.org/en/download)
#### Instructions
1. Install the package: `npm install @ztimson/zim-utils`
2. On first install, `kiwix-serve`/`kiwix-manage` binaries are fetched into `./bin` (or wherever `binDir` points) - no separate Kiwix install needed.
</details>
## Usage
### KiwixServer
`KiwixServer` owns a directory of `.zim` files and manages the whole `kiwix-serve` lifecycle for you.
```js
import {KiwixServer} from '@ztimson/zim-utils';
const server = new KiwixServer('./zims'); // optional 2nd arg: {port, host, binDir}
await server.start(); // rebuilds library.xml, spawns kiwix-serve, waits until ready
await server.reload(); // pick up newly added/removed .zim files, no downtime
await server.stop(); // Kill server
```
#### List Local ZIMs
```js
const local = await server.list();
[
{
id: '37a99758-43a0-6ba3-cd54-1af556369eee',
title: 'FOSS cooking',
updated: 2026-05-06T00:00:00.000Z,
summary: 'Making cooking fast, easy, foss',
language: 'eng',
name: 'foss.cooking_en_all',
category: 'other',
tags: ['_category:other', '_ftindex:yes', 'preppers,food', '_pictures:yes', '_videos:yes', '_details:yes'],
mediaCount: 154,
author: '-',
publisher: 'openZIM',
articleCount: 719,
sizeMb: 23.1,
href: 'foss.cooking_en_all_2026-05',
icon: undefined,
viewer: 'http://127.0.0.1:51992/content/foss.cooking_en_all_2026-05',
},
// ...
]
```
#### Search Local ZIMs
```js
// Fulltext search across every local archive: xapian prefilter, then fuzzy re-ranked
const hits = await server.search('chocolate', 5);
[
{
id: '37a99758-43a0-6ba3-cd54-1af556369eee',
title: 'Chocolate Chip Cookies',
page: 'foss.cooking/recipe/mfed3/chocolate-chip-cookies',
name: 'foss.cooking_en_all',
publisher: 'openZIM',
href: 'foss.cooking_en_all_2026-05/foss.cooking/recipe/mfed3/chocolate-chip-cookies',
icon: undefined,
viewer: 'http://127.0.0.1:51992/content/foss.cooking_en_all_2026-05/foss.cooking/recipe/mfed3/chocolate-chip-cookies',
summary: '...cream scooper or spoon to make uniform balls of cookie dough...',
score: 0.67,
},
// ...
]
```
#### View ZIM Content
```js
// Build a content URL from any href (list()/search() output, or a full viewer URL) without hitting the network
const url = server.fetch(hits[0].href);
'http://127.0.0.1:51992/content/foss.cooking_en_all_2026-05/foss.cooking/recipe/mfed3/chocolate-chip-cookies'
// Or fetch the bytes directly, proxied straight from kiwix-serve
const {mimetype, data} = await server.raw(hits[0].href);
{mimetype: 'text/html; charset=utf-8', data: <Buffer ...>}
```
### Catalog
```js
import {zimCatalog, zimCatalogInfo, CATALOG_URL} from '@ztimson/zim-utils';
// Search the remote Kiwix catalog to discover new ZIMs
const search = await zimCatalog('knots', {lang: 'eng', count: 20, url: CATALOG_URL});
// OR Exact lookup by catalog `name`, useful for checking if a local copy is outdated
const entry = await zimCatalogInfo('wikipedia_en_knots');
[
{
id: 'urn:uuid:3a4fe0d0-0bd0-7583-ada8-c52d173ae44d',
title: 'Knots by Wikipedia',
updated: 2026-07-20T00:00:00.000Z,
summary: 'A subset of Wikipedia encyclopedia dedicated to knots',
language: 'eng',
name: 'wikipedia_en_knots',
category: 'wikipedia',
tags: ['wikipedia', '_category:wikipedia', '_pictures:yes', '_videos:no', '_details:yes', '_ftindex:yes'],
mediaCount: 3501,
author: 'Wikipedia',
publisher: 'openZIM',
articleCount: 1730,
sizeMb: 17.6,
href: 'https://lb.download.kiwix.org/zim/wikipedia/wikipedia_en_knots_maxi_2026-07.zim.meta4',
icon: 'https://library.kiwix.org/catalog/v2/illustration/3a4fe0d0-0bd0-7583-ada8-c52d173ae44d/?size=48',
viewer: 'https://library.kiwix.org/viewer#wikipedia_en_knots',
},
// ...
]
// Download catalog ZIM if out of date (unless forced) and reload automatically
await mgr.download(search[0].href, force);
```
## License
Copyright © 2026 Zakary Timson | Available under MIT Licensing