Extend the media post-processing subsystem (APP-101) to video, sharing
the media_process_task table via the media_type discriminator but running
on its own dedicated queue so a long transcode never blocks image work.
- Upload hook (enqueueMediaProcessIfEligible) now branches by mime: image/*
and video/* each gate on their own master switch + per-user opt-in +
min_size, then Enqueue with the matching MediaType.
- Cron runs two independent lanes (enqueueMediaProcessLane): images ->
MediaProcessQueue, videos -> MediaVideoQueue.
- New dedicated MediaVideoQueue (dependency.go), MediaCompressVideoTaskType,
started in application.go, live-reloaded via mediaVideoQueuePostProcessor,
metric in GetQueueMetrics.
- MediaCompressTask.compress branches by media_type; new compressVideo builds
the ffmpeg command (codec/CRF/preset, videoScaleFilter cap without upscale,
audio, -threads, optional nice on non-Windows); normalizeVideoContainer
defaults to "keep" so the file is not renamed.
- Settings block media_compress_video_* + MediaProcessVideo(ctx) getter;
engine is always ffmpeg for video. cpu_num virtual key in GetSetting feeds
the frontend threads selector. AutoCompressVideos user opt-in + Codec added
to the JSON props (no schema/migration/BackendVersion bump).
- Tests: TestMediaProcessEnqueueVideo (discriminator isolation),
TestNormalizeVideoContainer + TestVideoScaleFilter (ffmpeg arg building).
Bumps the assets submodule pointer to the APP-103 frontend.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Seed pending media_process_task rows for a user's already-stored images
so the APP-101 pipeline compresses them. Adds a resumable MediaBackfillTask
(mirrors full_text_rebuild) that paginates candidate files and enqueues
each image idempotently, a self-service /workflow/mediaBackfill endpoint,
and cursor-based candidate listers. A file-level guard (HasHandledForFile)
skips already-processed files so re-runs do not re-compress. Bumps the
assets submodule for the frontend UI.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a media post-processing pipeline that compresses images off the upload
path, in batches, to save storage:
- New media_process_task ent table (media_type discriminator; image now,
video later) + inventory client with idempotent Enqueue/ListPending.
- CompleteUpload enqueues the primary entity when the global switch and the
owner's auto_compress_images opt-in are on and mime/size gates pass.
- A configurable cron enqueues a bounded batch onto a dedicated
MediaProcessQueue (default 1 worker) that compresses each blob via vips
(default) or ffmpeg using EntitySource, then writes the result back as a
new version through manager.Update (quota handled by StorageDiff). A
context guard prevents the write-back from re-enqueueing itself.
- BackendVersion 4.14.1 -> 4.14.2 to fire the migration; new default
settings are idempotently backfilled.
BusyWorkers/metrics expose the queue in /admin/task; result mode 'version'
is the MVP (replace/auto are follow-ups).
* feat: implement batch delete service
* refactor: implement `GetByHashIDs` to make sure only query database once
* refactor: use decode instead of `Get` before `Delete`
- fix incorrect `DeleteBatch` method (for admin) calling
- implement DeleteBatchByUserID
* feat(share): add Open Graph preview for social media crawlers
Add middleware to intercept social media bot requests and return
OG meta tags for share links, enabling rich previews on platforms
like Facebook, Twitter, Discord, etc.
* feat(og): reuse existing share service and show thumbnail if possible
* resolve comments
---------
Co-authored-by: Aaron Liu <abslant.liu@gmail.com>
* feat(email): add init email template for multiple languages
* Update setting.go
* Update setting.go
* feat(email): support magic variables in email title