Files
affiliate_dash/backend/cmd/cache_images/main.go
T
yml2213andCursor df1a170d44 refactor(catalog): 废弃 LEWAN_ 镜像,统一英文 SKU 与积分价,商品图按 SKU 缓存
对外目录只保留英文主 sku;迁移硬删镜像并校准 1元=100积分;发货页/凭证优先使用 local {sku}.webp。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-14 20:00:26 +08:00

99 lines
2.6 KiB
Go

package main
// 已废弃:请改用按英文 SKU 同步到 frontend/public/images/products/{sku}.webp
//
// cd backend && go run ./cmd/sync_product_images
//
// 本命令仍会把乐玩缩略图缓存到 data/uploads/products/{uuid}.webp,仅作历史兼容。
import (
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"time"
"affiliate_dash/internal/config"
"affiliate_dash/internal/pkg/lewan"
)
func main() {
cfg := config.Load()
client := lewan.NewClient(lewan.Config{
BaseURL: cfg.LewanBaseURL,
AccessKey: cfg.LewanAccessKey,
SecretKey: cfg.LewanSecretKey,
ApplicationID: cfg.LewanApplicationID,
}, nil)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
list, err := client.ListProducts(ctx, 1, 100, "")
if err != nil {
fmt.Printf("ListProducts error: %v\n", err)
return
}
fmt.Printf("Found %d products (total: %d)\n", len(list.Items), list.Total)
uploadDir := cfg.UploadDir
if uploadDir == "" {
uploadDir = "data/uploads"
}
cacheDir := filepath.Join(uploadDir, "products")
_ = os.MkdirAll(cacheDir, 0755)
httpClient := &http.Client{Timeout: 15 * time.Second}
for i, item := range list.Items {
fmt.Printf("[%d/%d] ID: %s, Name: %s, Thumb: %s\n", i+1, len(list.Items), item.ID, item.Name, item.ThumbnailUrl)
if item.ThumbnailUrl == "" {
continue
}
// 存储为 item.ID + 原扩展名
ext := filepath.Ext(item.ThumbnailUrl)
if ext == "" || len(ext) > 5 {
ext = ".webp"
}
destPath := filepath.Join(cacheDir, item.ID+ext)
// 同时也用 url hash 存一个软链或备份,以便 proxy 按 url 精准命中
urlHash := sha256.Sum256([]byte(item.ThumbnailUrl))
hashPath := filepath.Join(cacheDir, hex.EncodeToString(urlHash[:])+ext)
if _, err := os.Stat(destPath); err == nil {
fmt.Printf(" -> 已存在缓存: %s\n", destPath)
continue
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, item.ThumbnailUrl, nil)
if err != nil {
fmt.Printf(" -> 构建请求失败: %v\n", err)
continue
}
resp, err := httpClient.Do(req)
if err != nil {
fmt.Printf(" -> 下载失败: %v\n", err)
continue
}
if resp.StatusCode != http.StatusOK {
fmt.Printf(" -> 状态码错误: %d\n", resp.StatusCode)
resp.Body.Close()
continue
}
data, err := io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
fmt.Printf(" -> 读取失败: %v\n", err)
continue
}
_ = os.WriteFile(destPath, data, 0644)
_ = os.WriteFile(hashPath, data, 0644)
fmt.Printf(" -> 成功缓存: %s (大小: %d 字节)\n", destPath, len(data))
}
}