Skip to main content

H2HDB

Description

The H2HDB is a comprehensive database for organising and managing H@H comic collections. It offers a streamlined way to catalogue your comics, providing key information such as GID (Gallery ID), title, tags and more, ensuring your collection is always organised and accessible.


Features

  • Add new galleries to the database
  • Comporess H@H's galleries to a folder
  • Record the removed GIDs in a separate list
  • Coordinate bounded downloader and database-ingest turns
  • Write document (need?)

Installation and Usage

  1. Install uv. It manages the Python version and dependencies for you.

  2. Install the required packages.

    uv pip install h2hdb
    
  3. Run the script.

    uv run python -m h2hdb --config [json-path]
    

Config

{
    "h2h": {
        "download_path": "download",
        "cbz_max_size": 768,
        "cbz_grouping": "flat",
        "cbz_sort": "no"
    },
    "database": {
        "sql_type": "mariadb",
        "host": "localhost",
        "port": 3306,
        "user": "root",
        "password": "password",
        "database": "h2h"
    },
    "maintenance": {
        "optimize_enabled": true,
        "min_interval_seconds": 604800,
        "min_work_units": 1000,
        "min_data_free_bytes": 268435456,
        "min_data_free_ratio": 0.2,
        "lock_wait_seconds": 300
    },
    "logger": {
        "level": "INFO"
    }
}
  • h2h.download_path: H@H download path. The default is download.
  • h2h.cbz_path: directory for CBZ output. Unset (the default) disables CBZ output entirely; if given, it must be a non-empty path ("" is rejected).
  • h2h.cbz_max_size: maximum image size. The default is 768.
  • h2h.cbz_grouping: flat, date-yyyy, date-yyyy-mm, or date-yyyy-mm-dd. The default is flat.
  • h2h.cbz_sort: no, upload_time, download_time, gid, title, pages, or pages+[num]. The default is no.
  • h2h.file_hash_workers: maximum number of files read and hashed concurrently. The default is the smaller of 4 and the available CPU count; set it to 1 for serial hashing. Valid values are 132.
  • database.sql_type: mariadb or sqlite. The default is mariadb. Existing config files that still use mysql must update this field.
  • database.host, database.port, database.user, and database.password are only used for mariadb.
  • database.database: for mariadb, this is the database name. For sqlite, this is the path to the database file.
  • maintenance.optimize_enabled: enables automatic optimization in the resident main loop. Manual H2HDB.optimize_database() calls remain unconditional.
  • maintenance.min_interval_seconds: minimum time between automatic optimization evaluations. The default is seven days (604800).
  • maintenance.min_work_units: changed or removed galleries accumulated before an evaluation. New galleries do not count. The default is 1000.
  • maintenance.min_data_free_bytes and maintenance.min_data_free_ratio: minimum reclaimable space a table (or the SQLite database) must satisfy. Both thresholds must pass; the defaults are 256 MiB and 20%.
  • maintenance.lock_wait_seconds: one wait interval for the MariaDB cross-process database gate. The default is 300 seconds. A timeout is logged and retried rather than terminating the caller.
  • logger.level: one of NOTSET, DEBUG, INFO, WARNING, ERROR, or CRITICAL.

The main entry point remains resident and keeps its 30-minute periodic scan deadline, but it now polls the durable gallery_ingest_state every five seconds while waiting. A live downloader lease defers that scan; otherwise an ingest request wakes h2hdb without waiting for the old uninterruptible 30-minute sleep.

The singleton coordination row moves through INGEST_REQUESTED → INGESTING → READY → DOWNLOADING. A newly added row starts at INGEST_REQUESTED, so an upgraded or new installation completes one baseline scan before a downloader can claim READY. Downloader integrations use these public methods:

  • claim_download_turn(lease_seconds=...) returns a generation-fenced DownloadTurn, or None while h2hdb owns the turn.
  • renew_download_turn(turn, lease_seconds=...) extends a live downloader lease and returns whether that token still owns the generation.
  • request_gallery_ingest(turn) idempotently hands the generation to h2hdb.
  • finish_download_turn(turn, request) atomically hands off a successful root traversal and conditionally deletes only that request token.
  • finish_missing_download_turn(turn, request, gid) atomically fences and hands off a coordinated lookup; only while that exact request token is still current does it record the GID as removed and delete the request.
  • complete_missing_download_request(request, gid) records a confirmed missing gallery and deletes a direct request in one transaction, only while that exact token is still current.
  • clear_removed_gallery_gid(gid) clears a prior missing result after a later lookup finds the gallery again.
  • get_gallery_ingest_state() exposes the durable phase and completed_generation; a downloader may start its next root request only after completed_generation >= turn.generation.

A fresh DOWNLOADING lease prevents h2hdb from starting a scan until the downloader requests handoff; a periodic deadline does not override it. If the downloader terminates, h2hdb takes over after the lease expires and ingests any complete gallery folders already published. An ingest acknowledgement is written only after repeated synchronize_once() calls converge to a pass with no new or changed galleries and scheduled maintenance succeeds. A background heartbeat renews the ingest lease throughout synchronization and MariaDB maintenance. SQLite lock contention is retried only within the current lease; before SQLite maintenance h2hdb renews once and stops the heartbeat so VACUUM's exclusive lock can fence competing coordination writers. A successful SQLite optimization can acknowledge after the timestamp expires only if its generation and owner token are still current. Another resident treats SQLite lock contention while claiming as temporarily unavailable and keeps polling. Owner tokens fence stale downloader and h2hdb processes from renewing or completing a newer turn. Persisted handoff provenance distinguishes an explicit live-token handoff from an expired downloader lease recovered by h2hdb, so a recovered stale token cannot later report success.

One download turn covers one root todownload_gids request and its complete deep traversal. A failed, cancelled, or interrupted traversal leaves that durable request in the queue and may use request_gallery_ingest() to hand off any complete files. A successful traversal uses finish_download_turn() so handoff and exact-token deletion share one transaction. If the same GID was already re-enqueued with a newer request token, deletion is a no-op: the completed live turn still hands off immediately and the newer request remains queued. A confirmed missing result uses finish_missing_download_turn() for a coordinated root or complete_missing_download_request() for a direct request, so the removed marker and exact-token deletion cannot be partially committed and a stale token cannot write either. A later successful lookup calls clear_removed_gallery_gid() to repair that marker; replaying the older completion cannot restore it. If the turn was already handed off by the generic failure path, a later finish call acknowledges that handoff without performing any success or missing mutations.

Completed removal and changed-gallery batches add work to the singleton database_maintenance_state row. Automatic optimization is evaluated only after both the work and time thresholds pass, and MariaDB runs OPTIMIZE TABLE only for base tables that also pass both reclaimable-space thresholds. h2hdb clients can wrap short database work in H2HDB.database_gate() so it waits while maintenance owns the same MariaDB named lock.

H2HDB records a source-filename manifest for each gallery. Adding, deleting, or renaming a source file marks that gallery's CBZ for rebuilding. This pending state remains in the database if CBZ output is disabled or a run is interrupted. During ingestion, the provisional pass creates only missing CBZ files for new galleries and preserves existing CBZ files. After all galleries have been processed, one final pass uses the stable exclusion set to perform any required rebuilds. Created CBZ files carry a small input-layout marker in their ZIP comment, allowing the final pass to detect normalized renames and filename swaps even after the database has been deleted and rebuilt. H2HDB does not hash or scrub CBZ file contents.


Q & A

  • Why are some images missing from the CBZ-files?

H2HDB does not compress images that are considered spam according to certain rules. If you encounter any images that you believe should have been included, please report the issue.

  • Why are some images in some CBZ files and not in other CBZ-files?

H2HDB learns the spam rule from the previous CBZ files. If you kill the CBZ files containing these images, the new CBZ files will not contain these images.


Credits

The project was created by Kuan-Lun Wang.


License

This project is distributed under the terms of the GNU General Public Licence (GPL). For detailed licence terms, see the LICENSE file included in this distribution.

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.18.0.0.tar.gz (128.1 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.18.0.0-py3-none-any.whl (94.9 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for h2hdb-0.18.0.0.tar.gz
Algorithm Hash digest
SHA256 4cf65b13be713d6252181de054956f2ebfbcb6833230546aafd0ace0fc71141a
MD5 dcb7bceb12e28269e0f911da9e316c76
BLAKE2b-256 cccc7ef7c3ec698943f32d7d216e93ade9d0cddaac4a89bd920e978578cfa940

See more details on using hashes here.

Provenance

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

File metadata

  • Download URL: h2hdb-0.18.0.0-py3-none-any.whl
  • Upload date:
  • Size: 94.9 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.18.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 cec57baecd9a77edaa2f28ee144ff675a6392898f6c78a60b17a4cdf26d94516
MD5 87e2d728bfcd37c11dba4f858b770b2f
BLAKE2b-256 210476dfeb83388910093a198db136a83a816776bb6b441a98a2b04ee30d1ecc

See more details on using hashes here.

Provenance

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

0.20.0.0

2 files

0.19.0.0

2 files

This release

0.18.0.0 This release

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