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 three 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
uv run --no-sync python -m h2hdb ready --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
Container readiness probe Run python -m h2hdb ready

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 lightweight ready command checks only that ledger and deliberately does not wait on the database maintenance gate. It is suitable for a frequently repeated orchestrator probe; check remains the full schema-structure audit. 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, check, and ready 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.2.tar.gz (106.8 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.2-py3-none-any.whl (90.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: h2hdb-0.20.0.2.tar.gz
  • Upload date:
  • Size: 106.8 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.2.tar.gz
Algorithm Hash digest
SHA256 ca99644916b404e4da0eab24bcae24af7a36902c1ed7ecd6807f8dfef4db1fcd
MD5 3282f0d5f85c20c3120cb2ea32dce2f9
BLAKE2b-256 e3b1388646c08f6dba04f179c529f3b342a9ce26e7b5afc597667e8b6c112033

See more details on using hashes here.

Provenance

The following attestation bundles were made for h2hdb-0.20.0.2.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.2-py3-none-any.whl.

File metadata

  • Download URL: h2hdb-0.20.0.2-py3-none-any.whl
  • Upload date:
  • Size: 90.2 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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 9dc75a8e01a4c0e66e0d03c9d4585177a4850c7febab66c584178523684727bf
MD5 2a7caf8ddcadda65bf965dd61590df9a
BLAKE2b-256 a59190cc1de0f0c0a4a5a2435112a366e84619f53958f91bb15e7a98fd4d7af6

See more details on using hashes here.

Provenance

The following attestation bundles were made for h2hdb-0.20.0.2-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

This release

0.20.0.2 This release

2 files

0.20.0.1

2 files

0.20.0.0

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