feat: add product image download pipeline for PageSpeed 100%

Downloads Printify CDN images via ImageDownloadWorker, processes
through Media pipeline (WebP conversion, AVIF/WebP variant generation),
and links to ProductImage via new image_id FK.

- Add image_id to product_images table
- ImageDownloadWorker downloads and processes external images
- sync_product_images preserves image_id when URL unchanged
- PreviewData uses local images for responsive <picture> elements
- VariantCache enqueues pending downloads on startup
- mix simpleshop.download_images backfill task

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-02-01 00:26:19 +00:00
parent c818d0399c
commit 1b49b470f2
12 changed files with 381 additions and 33 deletions

View File

@@ -15,6 +15,8 @@ defmodule SimpleshopTheme.Images.VariantCache do
alias SimpleshopTheme.Repo
alias SimpleshopTheme.Media.Image, as: ImageSchema
alias SimpleshopTheme.Images.{Optimizer, OptimizeWorker}
alias SimpleshopTheme.Products
alias SimpleshopTheme.Sync.ImageDownloadWorker
import Ecto.Query
@mockup_dir "priv/static/mockups"
@@ -35,6 +37,7 @@ defmodule SimpleshopTheme.Images.VariantCache do
ensure_database_image_variants()
ensure_mockup_variants()
ensure_product_image_downloads()
end
defp ensure_database_image_variants do
@@ -100,4 +103,15 @@ defmodule SimpleshopTheme.Images.VariantCache do
dir = Path.dirname(source_path)
File.exists?(Path.join(dir, "#{basename}-800.webp"))
end
defp ensure_product_image_downloads do
pending = Products.list_pending_downloads(limit: 500)
if pending == [] do
Logger.info("[VariantCache] All product images downloaded")
else
Logger.info("[VariantCache] Enqueueing #{length(pending)} product images for download")
Enum.each(pending, fn image -> ImageDownloadWorker.enqueue(image.id) end)
end
end
end