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)) } }