feat: implement export engine
Add async ZIP and HTML offline viewer export workers, download endpoints,
and a guest-facing /export page.
Backend — export workers (tokio::spawn, run after gallery release):
- ZIP worker: streams all non-deleted originals into Gallery.zip via
async_zip (Stored compression), organised into Photos/ and Videos/
with {date}_{uploader}_{id}.{ext} filenames; updates progress_pct in DB
- HTML worker: renders Memories.html via minijinja template (self-contained:
inlined CSS + JS, relative media paths); packs it with README.txt and
all media into Memories.zip (Deflate for text, Stored for media)
- Both workers mark export_job status (running → done/failed), update
export_zip_ready / export_html_ready on the event, and broadcast SSE
export-progress + export-available when both complete
Backend — new endpoints (AuthUser):
- GET /export/zip → streams Gallery.zip if export_zip_ready
- GET /export/html → streams Memories.zip if export_html_ready
- GET /export/status → released flag + per-type status/progress (moved from admin)
Memories.html features: warm keepsake aesthetic, responsive grid, fullscreen
lightbox with captions/comments/likes, client-side hashtag filter chips,
XSS-safe JS, fully offline (no external deps)
Frontend — /export page:
- Locked state: padlock illustration + message
- Released state: ZIP and HTML cards with progress bars (SSE-driven),
download buttons enabled only when ready
- HTML guide modal (unzip instructions + Wi-Fi tip) before download begins
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -244,7 +244,7 @@ pub async fn release_gallery(
|
||||
.execute(&state.pool)
|
||||
.await?;
|
||||
|
||||
// Enqueue export jobs (processed by the export worker in a later step)
|
||||
// Enqueue export jobs
|
||||
for export_type in ["zip", "html"] {
|
||||
sqlx::query(
|
||||
"INSERT INTO export_job (event_id, type) VALUES ($1, $2::export_type)
|
||||
@@ -256,5 +256,14 @@ pub async fn release_gallery(
|
||||
.await?;
|
||||
}
|
||||
|
||||
// Spawn export workers
|
||||
crate::services::export::spawn_export_jobs(
|
||||
event.id,
|
||||
event.name,
|
||||
state.pool.clone(),
|
||||
state.config.media_path.clone(),
|
||||
state.sse_tx.clone(),
|
||||
);
|
||||
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user