diff --git a/TODO.md b/TODO.md index 03aaa1a..fce32e2 100644 --- a/TODO.md +++ b/TODO.md @@ -511,3 +511,17 @@ - `bash scripts/selftest.sh` - What is still risky or incomplete: - Partial-result responses are now preferred over hard 504s, so some searches may return fewer reviewed items when the time budget is exhausted. + +- Date: `2026-03-16` +- What changed: + - Loosened Envato and Artgrid query templates by adding unquoted variants so source discovery is less brittle when SearXNG has weak exact-phrase coverage. + - Replaced the Google Video modal embed with a dedicated in-app panel using thumbnail + metadata + action buttons, instead of relying on unstable YouTube embed playback. + - Bumped frontend asset version to `20260316g`. +- Why it changed: + - The latest log showed Envato and Artgrid repeatedly returning `rawCount: 0`, which is consistent with over-constrained exact-phrase queries. + - Google Video still hit YouTube player error `153`, so the modal needed a non-embed fallback that remains usable. +- How it was verified: + - log review from `ai-media-hub-2026-03-16T06-23-45-335Z.log` + - `go test ./...` +- What is still risky or incomplete: + - Even with looser queries, SearXNG quality still controls whether Envato and Artgrid candidates are discoverable for a given term. diff --git a/backend/services/cse.go b/backend/services/cse.go index 25bcfb9..87737d9 100644 --- a/backend/services/cse.go +++ b/backend/services/cse.go @@ -485,21 +485,23 @@ func buildGoogleVideoQueries(base string) []string { func buildEnvatoQueries(base string) []string { return []string{ - fmt.Sprintf(`"%s" ("stock footage" OR "stock video" OR "b-roll" OR cinematic) site:elements.envato.com`, base), - fmt.Sprintf(`"%s" ("stock footage" OR "stock video" OR "b-roll" OR cinematic) site:elements.envato.com/stock-video`, base), - fmt.Sprintf(`"%s" ("motion graphics" OR "backgrounds" OR "establishing shot" OR "loop") site:elements.envato.com`, base), - fmt.Sprintf(`"%s" ("urban" OR "night city" OR "cyberpunk" OR "sci-fi") site:elements.envato.com`, base), + fmt.Sprintf(`%s ("stock footage" OR "stock video" OR "b-roll" OR cinematic) site:elements.envato.com`, base), + fmt.Sprintf(`%s ("stock footage" OR "stock video" OR "b-roll" OR cinematic) site:elements.envato.com/stock-video`, base), + fmt.Sprintf(`%s ("motion graphics" OR "backgrounds" OR "establishing shot" OR "loop") site:elements.envato.com`, base), + fmt.Sprintf(`%s ("urban" OR "night city" OR "cyberpunk" OR "sci-fi") site:elements.envato.com`, base), + fmt.Sprintf(`"%s" site:elements.envato.com`, base), } } func buildArtgridQueries(base string) []string { return []string{ - fmt.Sprintf(`"%s" ("stock footage" OR "b-roll" OR cinematic OR editorial) site:artgrid.io/clip/`, base), - fmt.Sprintf(`"%s" ("footage" OR "cinematic" OR "establishing shot") site:artgrid.io/clip/`, base), - fmt.Sprintf(`"%s" ("stock footage" OR "b-roll" OR cinematic OR editorial) site:artlist.io/stock-footage/clip/`, base), - fmt.Sprintf(`"%s" ("footage" OR "cinematic" OR "establishing shot") site:artlist.io/stock-footage/clip/`, base), - fmt.Sprintf(`"%s" ("night drive" OR "urban night" OR "wet road" OR "cyberpunk") site:artgrid.io/clip/`, base), - fmt.Sprintf(`"%s" ("drone" OR "city skyline" OR "street scene" OR "mood shot") site:artlist.io/stock-footage/clip/`, base), + fmt.Sprintf(`%s ("stock footage" OR "b-roll" OR cinematic OR editorial) site:artgrid.io/clip/`, base), + fmt.Sprintf(`%s ("footage" OR "cinematic" OR "establishing shot") site:artgrid.io/clip/`, base), + fmt.Sprintf(`%s ("stock footage" OR "b-roll" OR cinematic OR editorial) site:artlist.io/stock-footage/clip/`, base), + fmt.Sprintf(`%s ("footage" OR "cinematic" OR "establishing shot") site:artlist.io/stock-footage/clip/`, base), + fmt.Sprintf(`%s ("night drive" OR "urban night" OR "wet road" OR "cyberpunk") site:artgrid.io/clip/`, base), + fmt.Sprintf(`%s ("drone" OR "city skyline" OR "street scene" OR "mood shot") site:artlist.io/stock-footage/clip/`, base), + fmt.Sprintf(`"%s" site:artgrid.io/clip/`, base), } } diff --git a/frontend/app.js b/frontend/app.js index 923a1e7..e4579ca 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -46,6 +46,9 @@ const resultModalFrame = document.getElementById("resultModalFrame"); const resultModalMediaFrame = document.getElementById("resultModalMediaFrame"); const resultModalVideo = document.getElementById("resultModalVideo"); const resultModalThumbnail = document.getElementById("resultModalThumbnail"); +const resultModalGooglePanel = document.getElementById("resultModalGooglePanel"); +const resultModalGoogleImage = document.getElementById("resultModalGoogleImage"); +const resultModalGoogleText = document.getElementById("resultModalGoogleText"); const resultModalOpenExternal = document.getElementById("resultModalOpenExternal"); const resultModalDownload = document.getElementById("resultModalDownload"); const closeResultModal = document.getElementById("closeResultModal"); @@ -59,6 +62,9 @@ const resultModalReady = Boolean( resultModalMediaFrame && resultModalVideo && resultModalThumbnail && + resultModalGooglePanel && + resultModalGoogleImage && + resultModalGoogleText && resultModalOpenExternal && resultModalDownload && closeResultModal, @@ -407,10 +413,13 @@ function resetResultModalMedia() { resultModalVideo.pause(); detachVideoSource(resultModalVideo); resultModalThumbnail.removeAttribute("src"); + resultModalGoogleImage.removeAttribute("src"); + resultModalGoogleText.textContent = ""; resultModalMediaFrame.style.aspectRatio = ""; setHidden(resultModalFrame, true, ""); setHidden(resultModalVideo, true, ""); setHidden(resultModalThumbnail, true, ""); + setHidden(resultModalGooglePanel, true, "flex"); } function showResultModalFrame(src) { @@ -435,6 +444,13 @@ function showResultModalThumbnail(src, alt) { setHidden(resultModalThumbnail, false, ""); } +function showResultModalGooglePanel(item) { + resultModalGoogleImage.src = item.thumbnailUrl || PREVIEW_PLACEHOLDER; + resultModalGoogleImage.alt = item.title || ""; + resultModalGoogleText.textContent = item.snippet || item.reason || "YouTube 페이지 열기 또는 Direct Download를 사용할 수 있습니다."; + setHidden(resultModalGooglePanel, false, "flex"); +} + function renderResults(results) { searchResults.innerHTML = ""; if (!results.length) { @@ -512,7 +528,7 @@ function openResultModal(item) { resultModalDownload.classList.toggle("hidden", !canDirectDownload); resetResultModalMedia(); if (item.source === "Google Video") { - showResultModalFrame(buildResultModalEmbedURL(item)); + showResultModalGooglePanel(item); } else { showResultModalFrame(item.link || "about:blank"); } diff --git a/frontend/index.html b/frontend/index.html index 954d6b4..509c9e0 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -166,6 +166,17 @@ +
@@ -202,6 +213,6 @@ - +