feat: add image search with Bing, DuckDuckGo, and Qwant engines
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 6s
Mirror to GitHub / mirror (push) Failing after 3s
Tests / test (push) Successful in 25s

Three new image search engines:
- bing_images: Bing Images via RSS endpoint
- ddg_images: DuckDuckGo Images via VQD API
- qwant_images: Qwant Images via v3 search API

Frontend:
- Image grid layout with responsive columns
- image_item template with thumbnail, title, and source metadata
- Hover animations and lazy loading
- Grid activates automatically when category=images

Backend:
- category=images routes to image engines via planner
- Image engines registered in factory and engine allowlist
- extractImgSrc helper for parsing thumbnail URLs from HTML
- IsImageSearch flag on PageData for template layout switching
This commit is contained in:
Franz Kafka 2026-03-22 16:49:24 +00:00
parent a316763aca
commit 2b072e4de3
11 changed files with 687 additions and 4 deletions

View file

@ -23,7 +23,13 @@ import (
"github.com/metamorphosis-dev/kafka/internal/contracts"
)
var defaultPortedEngines = []string{"wikipedia", "arxiv", "crossref", "braveapi", "brave", "qwant", "duckduckgo", "github", "reddit", "bing", "google", "youtube"}
var defaultPortedEngines = []string{
"wikipedia", "arxiv", "crossref", "braveapi",
"brave", "qwant", "duckduckgo", "github", "reddit",
"bing", "google", "youtube",
// Image engines
"bing_images", "ddg_images", "qwant_images",
}
type Planner struct {
PortedSet map[string]bool
@ -114,6 +120,10 @@ func inferFromCategories(categories []string) []string {
set["reddit"] = true
case "videos":
set["youtube"] = true
case "images":
set["bing_images"] = true
set["ddg_images"] = true
set["qwant_images"] = true
}
}
@ -122,7 +132,11 @@ func inferFromCategories(categories []string) []string {
out = append(out, e)
}
// stable order
order := map[string]int{"wikipedia": 0, "braveapi": 1, "brave": 2, "qwant": 3, "duckduckgo": 4, "bing": 5, "google": 6, "arxiv": 7, "crossref": 8, "github": 9, "reddit": 10, "youtube": 11}
order := map[string]int{
"wikipedia": 0, "braveapi": 1, "brave": 2, "qwant": 3, "duckduckgo": 4, "bing": 5, "google": 6,
"arxiv": 7, "crossref": 8, "github": 9, "reddit": 10, "youtube": 11,
"bing_images": 12, "ddg_images": 13, "qwant_images": 14,
}
sortByOrder(out, order)
return out
}