Files
backend_v2/internal/pkg/imgurl/imgurl.go
toom1996 dbee704c95 update
2026-09-13 00:52:35 +08:00

96 lines
4.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package imgurl 把数据库里存储的图片存储值拼装为对外可访问的完整 URL。
//
// 存储约定(见迁移 007):库里只存「对象 key」(如 runway/abc.jpg)或「本地相对路径」
// (如 /uploads/runway/x.jpg),绝不存完整 URL。这样做两个好处:
// 1. 换 CDN 域名只改配置,无需迁移全表;
// 2. 做「普通 / 高清」分级时无需从 URL 反向解析 key。
//
// 质量模型(2026-09-11 调整):VIP 与免费用户现在看到同一质量,高清样式名为 `high`,
// 由缤纷云 CoreIX 公开样式提供(base_url/key!style:high),匿名可访问、免 token。
// 旧「免费低清 / VIP 原图预签名」付费墙已取消,故 Composer 不再区分 tier。
// - 列表缩略图:另走 `thumb` 公开样式(ComposeThumb),仅用于列表/卡片等小尺寸场景,省流量。
// - 本地兜底 /uploads/*:原样返回(前端 toAbs 拼 host)。
// - 外链 http(s):原样返回(历史遗留 / vogue 等,无法套样式)。
package imgurl
import (
"fmt"
"strings"
)
// Composer 图片 URL 拼装器。
type Composer struct {
// BaseURL 对外访问域名,如 https://toomstudio.s3.bitiful.net(末尾无斜杠)。
BaseURL string
// StyleDisplay 全量展示图 CoreIX 样式名(如 "high",对应控制台建的公开样式);
// 若值含 "=" 则视为查询串(如 "w=1080&q=80&fmt=webp"),拼成 base_url/key?查询串。
StyleDisplay string
// StyleThumb 列表缩略图 CoreIX 样式名(如 "thumb");仅用于列表/卡片等小尺寸场景。
// 留空时回落 StyleDisplay(无独立缩略图样式时行为与旧版一致)。
StyleThumb string
}
// New 构造 Composer。
// - styleDisplay 缺省回落 "high"(高清公开样式,VIP 与免费用户同质量);
// - styleThumb 缺省回落 styleDisplay(未单独配置缩略图样式时,列表与详情同图)。
func New(baseURL, styleDisplay, styleThumb string) *Composer {
if styleDisplay == "" {
styleDisplay = "high"
}
if styleThumb == "" {
styleThumb = styleDisplay
}
return &Composer{
BaseURL: strings.TrimRight(baseURL, "/"),
StyleDisplay: styleDisplay,
StyleThumb: styleThumb,
}
}
// Compose 把存储值拼成可访问 URL(详情/大图场景,统一走 StyleDisplay)。
//
// - stored 为空:返回 ""
// - 本地兜底 /uploads/*:原样返回(前端 toAbs 拼 host)
// - 已是完整 http(s) URL(历史遗留 / 外链图):原样返回(无法套样式)
// - key:base_url/key!style:high(或查询串模式)
func (c *Composer) Compose(stored string) string {
return c.compose(stored, c.StyleDisplay)
}
// ComposeThumb 把存储值拼成「列表缩略图」URL(卡片 / 列表封面 / 图条等小尺寸场景)。
// 与 Compose 共用同一套兜底逻辑,仅样式名换成 StyleThumb(未配置时回落 StyleDisplay)。
// 注意:仅适用于同一 base_url 下的对象 key;外链与 /uploads 路径不做处理(无法套样式)。
func (c *Composer) ComposeThumb(stored string) string {
return c.compose(stored, c.StyleThumb)
}
// compose 应用指定样式拼装 URL。
func (c *Composer) compose(stored, style string) string {
stored = strings.TrimSpace(stored)
if stored == "" {
return ""
}
// 本地兜底路径:由前端拼绝对地址,原样返回。
if strings.HasPrefix(stored, "/uploads/") {
return stored
}
// 已是完整 URL(历史遗留 / 外链图):原样返回(无法套样式)。
if strings.HasPrefix(stored, "http://") || strings.HasPrefix(stored, "https://") {
return stored
}
// 对象 key:按指定样式拼装(命名样式 key!style:xxx 或查询串 key?w=..&q=..)。
return c.styledURL(stored, style)
}
// styledURL 按样式名生成地址:命名样式(key!style:high)或查询串(key?w=..&q=..)两种模式。
func (c *Composer) styledURL(key, style string) string {
if strings.Contains(style, "=") {
sep := "?"
if strings.Contains(style, "?") {
sep = "&"
}
return fmt.Sprintf("%s/%s%s%s", c.BaseURL, key, sep, style)
}
return fmt.Sprintf("%s/%s!style:%s", c.BaseURL, key, style)
}