From 52fb8c9328fc295ffe3ffe803f8195c458973a0b Mon Sep 17 00:00:00 2001 From: hanxuanyu <2252193204@qq.com> Date: Fri, 30 Jan 2026 14:28:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=9B=BE=E7=89=87=E5=A4=84?= =?UTF-8?q?=E7=90=86=E9=80=BB=E8=BE=91=EF=BC=9A=E4=BC=98=E5=85=88=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E6=9C=80=E5=B0=8F=E5=8F=98=E4=BD=93=E4=BB=A5=E8=8A=82?= =?UTF-8?q?=E7=9C=81=E6=B5=81=E9=87=8F=EF=BC=8C=E5=B9=B6=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20`normalizeImageUrl`=20=E5=87=BD=E6=95=B0=E5=A4=84=E7=90=86?= =?UTF-8?q?=E7=9B=B8=E5=AF=B9=E8=B7=AF=E5=BE=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/http/handlers/image.go | 45 +++++++++++++++++++++++++++- internal/http/handlers/image_test.go | 15 ++++++++++ webapp/src/lib/api-config.ts | 20 +++++++++++++ webapp/src/views/Home.vue | 8 +++-- 4 files changed, 85 insertions(+), 3 deletions(-) diff --git a/internal/http/handlers/image.go b/internal/http/handlers/image.go index 9fe58cf..ef3f0a9 100644 --- a/internal/http/handlers/image.go +++ b/internal/http/handlers/image.go @@ -218,7 +218,7 @@ func ListImages(c *gin.Context) { result := []gin.H{} for _, img := range images { - result = append(result, formatMeta(&img)) + result = append(result, formatMetaSummary(&img)) } c.JSON(http.StatusOK, result) } @@ -300,6 +300,49 @@ func serveLocal(c *gin.Context, key string, etag string, maxAge int) { io.Copy(c.Writer, reader) } +func formatMetaSummary(img *model.Image) gin.H { + cfg := config.GetConfig() + + // 找到最小的变体(Size 最小) + var smallest *model.ImageVariant + for i := range img.Variants { + v := &img.Variants[i] + if smallest == nil || v.Size < smallest.Size { + smallest = v + } + } + + variants := []gin.H{} + if smallest != nil { + url := smallest.PublicURL + if url == "" && cfg.API.Mode == "redirect" && img.URLBase != "" { + url = fmt.Sprintf("https://www.bing.com%s_%s.jpg", img.URLBase, smallest.Variant) + } else if cfg.API.Mode == "local" || url == "" { + url = fmt.Sprintf("%s/api/v1/image/date/%s?variant=%s&format=%s&mkt=%s", cfg.Server.BaseURL, img.Date, smallest.Variant, smallest.Format, img.Mkt) + } + variants = append(variants, gin.H{ + "variant": smallest.Variant, + "format": smallest.Format, + "size": smallest.Size, + "url": url, + "storage_key": smallest.StorageKey, + }) + } + + return gin.H{ + "date": img.Date, + "mkt": img.Mkt, + "title": img.Title, + "copyright": img.Copyright, + "copyrightlink": img.CopyrightLink, + "quiz": img.Quiz, + "startdate": img.StartDate, + "fullstartdate": img.FullStartDate, + "hsh": img.HSH, + "variants": variants, + } +} + func formatMeta(img *model.Image) gin.H { cfg := config.GetConfig() variants := []gin.H{} diff --git a/internal/http/handlers/image_test.go b/internal/http/handlers/image_test.go index f10d98b..1617caa 100644 --- a/internal/http/handlers/image_test.go +++ b/internal/http/handlers/image_test.go @@ -66,6 +66,21 @@ func TestHandleImageResponseRedirect(t *testing.T) { assert.Contains(t, variants[0]["url"].(string), "myserver.com") assert.Contains(t, variants[0]["url"].(string), "/api/v1/image/date/") }) + + t.Run("FormatMetaSummary should only return the smallest variant", func(t *testing.T) { + imgWithMultipleVariants := &model.Image{ + Date: "2026-01-26", + Variants: []model.ImageVariant{ + {Variant: "UHD", Size: 1000, Format: "jpg"}, + {Variant: "640x480", Size: 200, Format: "jpg"}, + {Variant: "1920x1080", Size: 500, Format: "jpg"}, + }, + } + meta := formatMetaSummary(imgWithMultipleVariants) + variants := meta["variants"].([]gin.H) + assert.Equal(t, 1, len(variants)) + assert.Equal(t, "640x480", variants[0]["variant"]) + }) } func TestGetRegions(t *testing.T) { diff --git a/webapp/src/lib/api-config.ts b/webapp/src/lib/api-config.ts index 9a6e907..289b16b 100644 --- a/webapp/src/lib/api-config.ts +++ b/webapp/src/lib/api-config.ts @@ -35,6 +35,26 @@ export const buildApiUrl = (endpoint: string): string => { return `${API_BASE_URL}${normalizedEndpoint}` } +/** + * 标准化图片 URL + * 当后端返回相对路径且配置了绝对 API 基础地址时,自动拼接完整域名 + */ +export const normalizeImageUrl = (url: string | undefined): string => { + if (!url) return '' + if (url.startsWith('http')) return url + + // 处理相对路径问题:如果配置了绝对 API 基础地址,则拼接 Origin + if (API_BASE_URL.startsWith('http')) { + try { + const origin = new URL(API_BASE_URL).origin + return url.startsWith('/') ? origin + url : origin + '/' + url + } catch (e) { + // 解析失败则返回原样 + } + } + return url +} + /** * HTTP 状态码枚举 */ diff --git a/webapp/src/views/Home.vue b/webapp/src/views/Home.vue index 9e3b2fb..04ddb3e 100644 --- a/webapp/src/views/Home.vue +++ b/webapp/src/views/Home.vue @@ -156,7 +156,7 @@ -
+
{ return bingPaperApi.getImageUrlByDate(latestImage.value.date, 'UHD', 'jpg', latestImage.value.mkt) } -// 获取图片 URL(缩略图 - 使用较小分辨率节省流量) +// 获取图片 URL(缩略图 - 优先使用后端返回的最小变体以节省流量) const getImageUrl = (image: any) => { + if (image.variants && image.variants.length > 0) { + return normalizeImageUrl(image.variants[0].url) + } return bingPaperApi.getImageUrlByDate(image.date!, '640x480', 'jpg', image.mkt) }