v1.0.1
Overview
GPT Image Linux v1.0.1 is a Gallery export and R2 backup reliability release focused on large libraries and multi-worker deployments. It moves Gallery export/sync coordination further into SQLite so GRANIAN_WORKERS>1 deployments can safely share tracked export jobs, direct ZIP downloads, R2 sync jobs, progress updates, and cleanup behavior across worker processes.
The release also refreshes the published GHCR image and latest tag.
Container Image
Multi-platform GHCR image:
ghcr.io/z1rconium/gpt-image-linux:v1.0.1
ghcr.io/z1rconium/gpt-image-linux:latest
Manifest digest:
sha256:3c63d9dbf21461e89fec7afe6721541746b4ded98a77df19680eeea1c5a29a00
Verified platforms:
linux/amd64
linux/arm64
What's Changed
Gallery export jobs are now SQLite-backed across workers
Tracked Gallery ZIP export jobs now persist their lifecycle in SQLite, including queued/running/success/error state, progress fields, lease ownership, output path, archive filename, counters, and download URL. Workers claim queued or expired running jobs through SQLite leases, so export job creation, status polling, SSE progress, and download behavior work across multiple Granian worker processes.
This keeps the public API stable while making tracked export jobs usable in multi-worker deployments:
POST /api/gallery/export-jobsGET /api/gallery/export-jobs/{job_id}GET /api/gallery/export-jobs/{job_id}/eventsGET /api/gallery/export-jobs/{job_id}/download
Direct ZIP downloads share global export capacity
Direct Gallery ZIP downloads, including /api/download-all and selected batch ZIP downloads, now reserve short-lived SQLite export_direct slot rows. These slots count against the same global export capacity as tracked export jobs, preventing multiple worker processes from each allowing their own local maximum and overselling export concurrency.
The default export concurrency semantics remain MAX_ACTIVE_EXPORT_JOBS = 5, but the limit is now enforced across workers for both direct and tracked exports.
Progress writes are throttled and lighter
Gallery export and R2 sync progress updates now use a shared throttling path. High-frequency progress updates write to SQLite at most every 0.5 seconds or every 50 processed entries, while stage changes and terminal states still force a final update.
Progress-only updates also avoid the previous update-then-select pattern. SSE clients still poll the same gallery_jobs.updated_at edge and receive the same event names and payload shape, but large exports and syncs now create much less SQLite write pressure.
ZIP export metadata avoids expensive hash backfills
ZIP export metadata now uses stored sha256 and bytes values when available. If a row is missing sha256, export no longer reads the whole image file just to compute a hash during ZIP creation. Missing byte sizes are filled from a cheap stat() where possible.
This keeps ZIP export low-memory and reduces repeated disk reads on large galleries.
R2 sync handles large prefixes better
R2 Gallery backup sync now limits how much remote listing data it keeps in memory. The sync still lists the configured R2_KEY_PREFIX, but it retains only remote keys that match local Gallery filenames. For very large remote prefixes, it stops accumulating the listing and falls back to per-file HeadObject checks for local candidates.
The backup semantics remain unchanged:
- local Gallery remains the source of truth
- missing local files are skipped
- existing remote objects are skipped
- bucket-only objects are not deleted
- Gallery images are never served from R2
Export cleanup is more robust
Stale export ZIP cleanup now tracks active export job file paths through SQLite job rows, reducing the chance of deleting files that still belong to active or downloadable jobs. Expired direct export slot rows are also garbage collected so interrupted direct downloads do not leave permanent capacity records behind.
SQLite indexes and cleanup queries improved
The gallery_jobs table now has more targeted indexes for active job counting, claiming, and terminal job cleanup. Terminal export/sync cleanup also filters stale rows on the SQL side instead of loading all terminal rows and filtering them in Python.
Release Assets
Attached assets:
docker-compose.yml- image-based Compose file pinned toghcr.io/z1rconium/gpt-image-linux:v1.0.1env.example- environment template; download it as.env.exampleif desiredgpt-image-panel-v1.0.1-prebuilt.tar.gz- offline prebuilt package with backend source, frontend build output, docs, deployment files, and runtime directory placeholdersSHA256SUMS- checksums for the release assets
Download the env template as .env.example:
curl -Lo .env.example https://github.com/Z1rconium/gpt-image-linux/releases/download/v1.0.1/env.exampleDocker Run
Minimal local run:
docker run --rm \
-p 127.0.0.1:9090:9090 \
-v "$PWD/images:/app/images" \
-v "$PWD/data:/app/data" \
--env-file .env.example \
ghcr.io/z1rconium/gpt-image-linux:v1.0.1Then open:
http://127.0.0.1:9090
Docker Compose
Download the release Compose file and env template:
curl -LO https://github.com/Z1rconium/gpt-image-linux/releases/download/v1.0.1/docker-compose.yml
curl -Lo .env.example https://github.com/Z1rconium/gpt-image-linux/releases/download/v1.0.1/env.example
mkdir -p images data
docker compose up -dChecksums
904d50b5012ebba41f877cacfaed373539204e2ee3e7b2271371988ecab92afa docker-compose.yml
ec0224cceee093dc8f80cf1ff498a5cef81420b6993e3cf81e40cca55dcab7c3 env.example
c465025bcdd2244f2ce7689fc94883ec6a8128462753543736f41a076b157496 gpt-image-panel-v1.0.1-prebuilt.tar.gz
Changelog
Full comparison: v1.0.0...v1.0.1
Commits included:
a9f777bfeat(gallery): implement gallery job management and persistencea825a78feat(gallery): enhance cleanup of stale export files with job trackingaf6e8d6feat(gallery): enhance gallery export management with direct download slots and progress throttling349e27achore: release v1.0.1