Skip to main content

h2hdb

h2hdb is the database and coordination core for the H2HDB multi-repository system. It owns the durable schema and exposes backend-neutral public ports to ingest, download, Komga, and OPDS consumers.

It deliberately does not scan files, parse galleryinfo.txt, manipulate images or CBZ files, serve HTTP, serialize OPDS documents, or depend on hbrowser. Those responsibilities live in sibling packages.

Core responsibilities

  • MariaDB and SQLite connectors, transactions, and read-only access.
  • Forward-only, versioned schema migrations.
  • Durable download queue and token-fenced download/ingest leases.
  • Database maintenance gate and scheduling state. Core public operations own participation; consumers do not wrap calls themselves.
  • Neutral catalog domain models and revision-based projection.
  • Public ports: CatalogReader, CatalogPublisher, DownloadCoordinator, and DatabaseAdmin.

The catalog projection consists of catalog_publications, catalog_contributors, catalog_subjects, catalog_artifacts, and the singleton catalog_revision pointer. Immutable descriptors for every published revision live in catalog_revision_history. A complete snapshot and its history entry are inserted before the pointer advances in one transaction. The publish is fenced by a live ingest lease, unchanged projections reuse the current revision, and readers only see fully published revisions. Every newly published publication records its exact canonical source_gallery_name and, when content exists, content_sha256, so ingest can preserve deduplication incumbents.

Installation

This repository uses a src layout: the import package is h2hdb, while its source lives under src/h2hdb.

uv venv --python 3.14
uv pip install -e ".[dev]"

uv.lock is intentionally ignored. Rebuild the local environment with:

./scripts/rebuild-env.sh

Configuration and schema administration

{
  "database": {
    "sql_type": "sqlite",
    "database": "/var/lib/h2hdb/catalog.sqlite3",
    "access_mode": "read-write"
  },
  "maintenance": {
    "optimize_enabled": true
  },
  "logger": {
    "level": "INFO",
    "file": null
  }
}

JSON string values that consist exactly of ${ENV_NAME} are resolved from the process environment before validation, including values nested inside objects and arrays. Variable names must match [A-Za-z_][A-Za-z0-9_]*; a missing or invalid name stops startup without including the environment value in the error. Inline interpolation is deliberately unsupported, so strings such as db-${INSTANCE} remain literal. For example, keep a MariaDB password out of the file with "password": "${H2HDB_RW_DB_PASSWORD}". Unknown JSON fields are still rejected after placeholder resolution.

For MariaDB, set host, port, user, password, and database. Consumers such as OPDS should use "access_mode": "read-only"; their database account needs SELECT plus SHOW VIEW so compatibility checks can validate critical view definitions without write privileges.

Only the core administration command migrates current, versioned schema. Its two runtime operations are:

uv run --no-sync python -m h2hdb migrate --config config.json
uv run --no-sync python -m h2hdb check --config config.json

Choose the operation from database state, not from container lifecycle:

Database state Operation
Empty Run python -m h2hdb migrate once
Non-empty and has the supported h2hdb_schema_migrations ledger Run the same forward-only migrate command
Consumer startup Run python -m h2hdb check; never migrate

migrate deliberately refuses a non-empty database without h2hdb_schema_migrations. There is no old-schema recognition, adoption, backfill, config fallback, or upgrade command. Replace an old database with an empty one and rebuild it through the current ingest workflow. A database that already has the current ledger may use later forward-only migrations as they are added.

The schema version is stored in the append-only h2hdb_schema_migrations ledger and is independent of the Python package version. Consumer startup must call check_compatibility(); it must not migrate. The later ingest bootstrap-catalog.py command is a separate data operation: it does not create schema or write the schema ledger.

Public API

Create the facade from CoreConfig or load_config():

from h2hdb import H2HDB, load_config

database = H2HDB(load_config("config.json"))
database.check_compatibility()
page = database.list_publications(limit=50)
historical = database.get_catalog_revision(1)
historical_page = database.list_publications(revision=historical, limit=50)
acquirable_page = database.list_publications(
    revision=historical,
    limit=50,
    require_artifact=True,
)

get_catalog_revision() resolves the current pointer; get_catalog_revision(revision_number) loads a durable historical descriptor or raises CatalogRevisionNotFoundError.

get_publications_by_artifact_names(..., revision=descriptor) participates in the same revision pinning contract. require_artifact=True applies the artifact predicate to both page rows and total, which lets acquisition-feed consumers paginate without post-filtering.

Every supported revision persists exact source_gallery_name; consumers never infer it from mutable canonical tables. content_sha256 is nullable only for a current-domain reason: a gallery can have no non-galleryinfo content after exclusions.

Consumers should type against the exported protocols and domain models. Do not import connector, repository, or table implementation modules from another repository.

Multi-repository development

The repositories remain independent projects; this is not a uv workspace. To create an isolated editable-install integration environment for all local packages, run:

./scripts/rebuild-multirepo-integration.sh

The script uses uv venv and uv pip install -e for each repository and does not create or consume a lock file. See docs/multi-repo-deployment.md for the container split, fresh database initialization, shared database, and CBZ mount rules.

Verification

uv run --no-sync black --check src tests scripts
uv run --no-sync ruff check src tests scripts
uv run --no-sync mypy src tests scripts
uv run --no-sync pytest
uv run --no-sync python -m build
uv run --no-sync python scripts/build-and-verify-distributions.py \
  --output-directory /path/to/empty/output-directory

The final command always builds in a fresh temporary directory. It verifies the wheel boundary and confirms that an installation taken from that wheel exposes only the migrate and check CLI operations. It copies artifacts to the requested empty output directory only after every check passes.

SQLite runs locally. Set H2HDB_TEST_MARIADB=1 with a running Docker daemon to include the MariaDB testcontainer cases.

License

GNU Affero General Public License v3 or later. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

h2hdb-0.20.0.0.tar.gz (104.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

h2hdb-0.20.0.0-py3-none-any.whl (89.7 kB view details)

Uploaded Python 3

File details

Details for the file h2hdb-0.20.0.0.tar.gz.

File metadata

  • Download URL: h2hdb-0.20.0.0.tar.gz
  • Upload date:
  • Size: 104.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for h2hdb-0.20.0.0.tar.gz
Algorithm Hash digest
SHA256 444f853b1561ec2228e00da6aa1b566cd910f4fa6dce45b017c32fe1452da7a3
MD5 cda43a044713a72f593a4e7546e0ffd3
BLAKE2b-256 c8a6cf034df0e0bf1454d2f284f20c8e628da40e0d4cf65372be7102c2a12dce

See more details on using hashes here.

Provenance

The following attestation bundles were made for h2hdb-0.20.0.0.tar.gz:

Publisher: publish.yml on Kuan-Lun/h2hdb

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file h2hdb-0.20.0.0-py3-none-any.whl.

File metadata

  • Download URL: h2hdb-0.20.0.0-py3-none-any.whl
  • Upload date:
  • Size: 89.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for h2hdb-0.20.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 55b1b90ef57316b0d71046f48b133455d903e077de50a5ca1bb22c17e6f2222f
MD5 e64dc9f92d33f474e491cc14dce3efe0
BLAKE2b-256 19d67a65d1982df6efbe2578c3030fba32ec07c7658bb55b3153b434efabce5c

See more details on using hashes here.

Provenance

The following attestation bundles were made for h2hdb-0.20.0.0-py3-none-any.whl:

Publisher: publish.yml on Kuan-Lun/h2hdb

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.31.0

2 files

0.29.0

2 files

0.28.3

2 files

0.28.2

2 files

0.28.1

2 files

0.27.0

2 files

0.26.0

2 files

0.25.0

2 files

0.24.0

2 files

0.23.1

2 files

0.23.0.11

2 files

0.23.0.10

2 files

0.23.0.9

2 files

0.23.0.8

2 files

0.23.0.7

2 files

0.23.0.6

2 files

0.23.0.5

2 files

0.23.0.4

2 files

0.23.0.3

2 files

0.23.0.2

2 files

0.23.0.1

2 files

0.22.0.2

2 files

0.22.0.1

2 files

0.21.0.1

2 files

0.21.0.0

2 files

0.20.0.2

2 files

0.20.0.1

2 files

This release

0.20.0.0 This release

2 files

0.19.0.0

2 files

0.18.0.0

2 files

0.17.0.0

2 files

0.16.0.0

2 files

0.15.0.0

2 files

0.14.0.2

2 files

0.14.0.1

2 files

0.14.0.0

2 files

0.13.0.2

2 files

0.13.0.1

2 files

0.13.0.0

2 files

0.12.0.6

2 files

0.12.0.5

2 files

0.12.0.4

2 files

0.12.0.3

2 files

0.12.0.2

2 files

0.12.0.1

2 files

0.12.0.0

2 files

0.11.0.5

2 files

0.11.0.4

2 files

0.11.0.3

2 files

0.11.0.2

2 files

0.11.0.1

2 files

0.11.0.0

2 files

0.10.8.4

2 files

0.10.8.3

2 files

0.10.8.2

2 files

0.10.8.1

2 files

0.10.8.0

2 files

0.10.7.5

2 files

0.10.7.4

2 files

0.10.7.3

2 files

0.10.7.2

2 files

0.10.7.1

2 files

0.10.7.0

2 files

0.10.6.0

2 files

0.10.5.8

2 files

0.10.5.7

2 files

0.10.5.6

2 files

0.10.5.5

2 files

0.10.5.4

2 files

0.10.5.3

2 files

0.10.5.2

2 files

0.10.5.1

2 files

0.10.5.0

2 files

0.10.4.2

2 files

0.10.4.1

2 files

0.10.4.0

2 files

0.10.3.0

2 files

0.10.2.0

2 files

0.10.1.1

2 files

0.10.0.0

2 files

0.9.1.9

2 files

0.9.1.8

2 files

0.9.1.7

2 files

0.9.1.6

2 files

0.9.1.5

2 files

0.9.1.4

2 files

0.9.1.3

2 files

0.9.1.2

2 files

0.9.1.1

2 files

0.9.1.0

2 files

0.9.0.5

2 files

0.9.0.4

2 files

0.9.0.3

2 files

0.9.0.2

2 files

0.9.0.1

2 files

0.9.0.0

2 files

0.8.0.2

2 files

0.8.0.1

2 files

0.8.0.0

2 files

0.7.0.9

2 files

0.7.0.8

2 files

0.7.0.5

2 files

0.7.0.4

2 files

0.7.0.3

2 files

0.7.0.2

2 files

0.7.0.1

2 files

0.7.0.0

2 files

0.6.68.63

2 files

0.6.68.62

2 files

0.6.68.61

2 files

0.6.68.60

2 files

0.6.68.59

2 files

0.6.68.58

2 files

0.6.68.57

2 files

0.6.68.56

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page