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
-
Install uv. It manages the Python version and dependencies for you.
-
Install the required packages.
uv pip install h2hdb
-
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 isdownload.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 is768.h2h.cbz_grouping:flat,date-yyyy,date-yyyy-mm, ordate-yyyy-mm-dd. The default isflat.h2h.cbz_sort:no,upload_time,download_time,gid,title,pages, orpages+[num]. The default isno.h2h.file_hash_workers: maximum number of files read and hashed concurrently. The default is the smaller of4and the available CPU count; set it to1for serial hashing. Valid values are1–32.database.sql_type:mariadborsqlite. The default ismariadb. Existing config files that still usemysqlmust update this field.database.host,database.port,database.user, anddatabase.passwordare only used formariadb.database.database: formariadb, this is the database name. Forsqlite, this is the path to the database file.maintenance.optimize_enabled: enables automatic optimization in the resident main loop. ManualH2HDB.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 is1000.maintenance.min_data_free_bytesandmaintenance.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 ofNOTSET,DEBUG,INFO,WARNING,ERROR, orCRITICAL.
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-fencedDownloadTurn, orNonewhile h2hdb owns the turn.renew_download_turn(turn, lease_seconds=...)extends a live downloader lease and returns whether that token still owns the generation.ensure_download_request(gid, url="")atomically reuses an existing durable request without replacing its token, or creates one and reports that it was newly created.complete_download_request_in_turn(turn, request)exact-deletes a completed root request while its fenced turn remains inDOWNLOADINGfor more roots.complete_missing_download_request_in_turn(turn, request, gid)performs the equivalent live-turn-fenced exact deletion and missing-marker write.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 andcompleted_generation; a downloader may start its next batch or independent root only aftercompleted_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.
A download turn may cover one independent root or a bounded batch of
todownload_gids roots; every root's complete deep traversal remains an
indivisible unit. Between roots, a batch uses the live-turn-fenced
complete_download_request_in_turn() or
complete_missing_download_request_in_turn() operation to persist completed
work without handing off DOWNLOADING. At its root-count boundary, snapshot
exhaustion, cancellation, or failure, it calls request_gallery_ingest() once.
The single-root APIs retain finish_download_turn() and
finish_missing_download_turn(), where final request mutation and handoff share
one transaction.
All request completion remains exact-token conditional. If the same GID was
already re-enqueued with a newer token, success deletion is a no-op and a stale
missing result writes no marker. A later successful lookup calls
clear_removed_gallery_gid() to repair a prior marker; replaying the older
completion cannot restore it. Interrupting an in-turn completion commits both
its fenced request mutation and missing marker or neither. If a downloader
stops before handoff, the durable DOWNLOADING lease eventually expires so
h2hdb scans already published files; completed roots stay settled while the
unfinished root remains queued. If h2hdb itself stops in INGESTING, its lease
recovery repeats synchronization until convergence before acknowledging the
generation.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file h2hdb-0.19.0.0.tar.gz.
File metadata
- Download URL: h2hdb-0.19.0.0.tar.gz
- Upload date:
- Size: 129.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90177aca71a003b00013fd960937380e61e7f3cc3bbf4babfc45df40ba11c7a3
|
|
| MD5 |
3a21a257c57652df5fc59d02f9e537cb
|
|
| BLAKE2b-256 |
cde5c7bfe35a1920356bcc38b10c5aba8c75d27c587148bec94db2eb9ffbb7cb
|
Provenance
The following attestation bundles were made for h2hdb-0.19.0.0.tar.gz:
Publisher:
publish.yml on Kuan-Lun/h2hdb
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
h2hdb-0.19.0.0.tar.gz -
Subject digest:
90177aca71a003b00013fd960937380e61e7f3cc3bbf4babfc45df40ba11c7a3 - Sigstore transparency entry: 2305719910
- Sigstore integration time:
-
Permalink:
Kuan-Lun/h2hdb@53b7fa4bad4c3df0cba08b615ed64bfb776bd97a -
Branch / Tag:
refs/heads/master - Owner: https://github.com/Kuan-Lun
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@53b7fa4bad4c3df0cba08b615ed64bfb776bd97a -
Trigger Event:
push
-
Statement type:
File details
Details for the file h2hdb-0.19.0.0-py3-none-any.whl.
File metadata
- Download URL: h2hdb-0.19.0.0-py3-none-any.whl
- Upload date:
- Size: 95.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
644fc68584ad279b44ff1954a62e93098111f3a860a01c02da1b67f5dc80cf0b
|
|
| MD5 |
7060fa0d05284013d6bbc4ac070e2e85
|
|
| BLAKE2b-256 |
a6bc4dd444c585a60df6f285301c81f4cb1fa0b9f9dbfa08df1b9a783777b536
|
Provenance
The following attestation bundles were made for h2hdb-0.19.0.0-py3-none-any.whl:
Publisher:
publish.yml on Kuan-Lun/h2hdb
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
h2hdb-0.19.0.0-py3-none-any.whl -
Subject digest:
644fc68584ad279b44ff1954a62e93098111f3a860a01c02da1b67f5dc80cf0b - Sigstore transparency entry: 2305719995
- Sigstore integration time:
-
Permalink:
Kuan-Lun/h2hdb@53b7fa4bad4c3df0cba08b615ed64bfb776bd97a -
Branch / Tag:
refs/heads/master - Owner: https://github.com/Kuan-Lun
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@53b7fa4bad4c3df0cba08b615ed64bfb776bd97a -
Trigger Event:
push
-
Statement type: