package configser import ( "bytes" "context" "encoding/json" "strings" "videoweb/app/api/proto" "videoweb/app/appg" "videoweb/pub/common/ipaddr" "github.com/gin-gonic/gin" ) // ClientIPFromCtx 从 gin 请求上下文解析客户端 IP。 func ClientIPFromCtx(ctx context.Context) string { c, ok := ctx.(*gin.Context) if !ok || c == nil { return "" } return ipaddr.ResolveClientIP(c) } // IsOverseasIP 与 m3u8 TS 域名判断一致:按 v4/v6 库识别是否海外。 func IsOverseasIP(ip string) bool { ip = strings.TrimSpace(ip) if ip == "" { return false } detector := appg.DetectorV6 if ipaddr.IsIPv4(ip) { detector = appg.DetectorV4 } if detector == nil { return false } ok, _ := detector.IsOverseasIP(ip) return ok } // GetAppImageCdn 海外 IP 且配置了 imgAppUsCdn 时用海外图床,否则用 imgAppCdn。 func GetAppImageCdn(ip string) string { cfg := GetConfigInfo() if IsOverseasIP(ip) { if us := strings.TrimSpace(cfg.ImgAppUsCdn); us != "" { return us } } return strings.TrimSpace(cfg.ImgCdn) } // ImageCdnFromCtx 按当前请求 IP 选择图片 CDN。 func ImageCdnFromCtx(ctx context.Context) string { return GetAppImageCdn(ClientIPFromCtx(ctx)) } // GetRequestConfig 返回当前请求应使用的配置副本,海外 IP 且海外图床非空时覆盖 ImgCdn。 func GetRequestConfig(ctx context.Context) proto.ConfigInfo { cfg := GetConfigInfo() if cdn := GetAppImageCdn(ClientIPFromCtx(ctx)); cdn != "" { cfg.ImgCdn = cdn } return cfg } // RewriteImageCdn 将已拼好的国内图床域名替换为当前请求应使用的图床,用于缓存数据。 func RewriteImageCdn(ctx context.Context, data any) { if data == nil { return } from := strings.TrimRight(strings.TrimSpace(GetConfigInfo().ImgCdn), "/") to := strings.TrimRight(GetAppImageCdn(ClientIPFromCtx(ctx)), "/") if from == "" || to == "" || from == to { return } raw, err := json.Marshal(data) if err != nil { return } replaced := bytes.ReplaceAll(raw, []byte(from), []byte(to)) if bytes.Equal(raw, replaced) { return } _ = json.Unmarshal(replaced, data) }