diff --git a/TODO.md b/TODO.md
index c90e676..9b2e453 100644
--- a/TODO.md
+++ b/TODO.md
@@ -460,6 +460,21 @@
- There is one known local commit that has not been pushed because the remote repo reported an unpacker error.
## Recent Change Log
+- Date: `2026-03-16`
+- What changed:
+ - When Gemini batch evaluation is only partially successful, the API now explicitly backfills the final list with preview-capable ranked candidates instead of leaving the visible result set too thin.
+ - Result modal behavior was switched so Envato and Artgrid open their actual item webpages inside the modal iframe again, while Google Video still uses the YouTube embed path.
+ - Frontend asset version was bumped again to force clients off stale preview-handling code.
+- Why it changed:
+ - The new debug log showed `recommendedCount: 2` plus one failed Gemini batch, but the final visible list still collapsed to `6` items even though the raw pool was `25`.
+ - The user wants in-modal login/download for Envato and Artgrid rather than preview-only media mode.
+- How it was verified:
+ - log review from `ai-media-hub-2026-03-16T06-00-31-359Z.log`
+ - code inspection of post-Gemini backfill and modal rendering path
+- What is still risky or incomplete:
+ - Artgrid candidate volume is still often low because SearXNG is returning many `0`-result queries for current Artgrid query templates.
+ - If a browser still holds older frontend assets, a hard refresh may be required before the latest modal/preview behavior appears.
+
- Date: `2026-03-16`
- What changed:
- Significantly increased backend debug logging volume and routed it into the existing WebSocket `debug` stream so the in-app `Logs` panel captures much deeper request, search, preview, Gemini, and ranking traces.
diff --git a/backend/handlers/api.go b/backend/handlers/api.go
index 80dd192..1b47b23 100644
--- a/backend/handlers/api.go
+++ b/backend/handlers/api.go
@@ -458,6 +458,14 @@ func (a *App) searchMedia(c *gin.Context) {
}
merged := services.MergeRecommendations(recommended, scored, 20)
+ if geminiErr != nil {
+ merged = services.BackfillRecommendations(
+ merged,
+ scored,
+ 12,
+ "Gemini 배치 일부가 실패해 미리보기 가능한 상위 후보를 보강했습니다.",
+ )
+ }
merged = services.RandomizeTopRecommendations(merged, 8)
warning := ""
if geminiErr != nil {
diff --git a/backend/services/ranker.go b/backend/services/ranker.go
index 8b65bdf..8871181 100644
--- a/backend/services/ranker.go
+++ b/backend/services/ranker.go
@@ -355,6 +355,38 @@ func MergeRecommendations(recommended []AIRecommendation, ranked []SearchResult,
return merged
}
+func BackfillRecommendations(existing []AIRecommendation, ranked []SearchResult, limit int, reason string) []AIRecommendation {
+ merged := make([]AIRecommendation, 0, min(limit, len(ranked)))
+ seen := map[string]bool{}
+ for _, item := range existing {
+ if item.Link == "" || seen[item.Link] {
+ continue
+ }
+ seen[item.Link] = true
+ merged = append(merged, item)
+ }
+ for _, item := range ranked {
+ if len(merged) >= limit || item.Link == "" || seen[item.Link] {
+ continue
+ }
+ if strings.TrimSpace(item.ThumbnailURL) == "" && strings.TrimSpace(item.PreviewVideoURL) == "" {
+ continue
+ }
+ seen[item.Link] = true
+ merged = append(merged, AIRecommendation{
+ Title: item.Title,
+ Link: item.Link,
+ Snippet: item.Snippet,
+ ThumbnailURL: item.ThumbnailURL,
+ PreviewVideoURL: item.PreviewVideoURL,
+ Source: item.Source,
+ Reason: reason,
+ Recommended: false,
+ })
+ }
+ return merged
+}
+
func max(a, b int) int {
if a > b {
return a
diff --git a/frontend/app.js b/frontend/app.js
index 233b959..923a1e7 100644
--- a/frontend/app.js
+++ b/frontend/app.js
@@ -513,10 +513,8 @@ function openResultModal(item) {
resetResultModalMedia();
if (item.source === "Google Video") {
showResultModalFrame(buildResultModalEmbedURL(item));
- } else if (item.previewVideoUrl) {
- showResultModalVideo(item.previewVideoUrl);
} else {
- showResultModalThumbnail(item.thumbnailUrl, item.title || "");
+ showResultModalFrame(item.link || "about:blank");
}
showModal(resultModal);
logEvent("result:modal:open", { title: item.title, source: item.source, link: item.link });
diff --git a/frontend/index.html b/frontend/index.html
index 2b0c77b..954d6b4 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -202,6 +202,6 @@
-
+