From 1ead57dd22e44662f58a49b536e486a2daed4c90 Mon Sep 17 00:00:00 2001 From: toom1996 <23cm.cn@gmail.com> Date: Sun, 25 Oct 2026 21:02:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8D=95=E5=9C=BA=E7=A7=80=E5=86=85?= =?UTF-8?q?=E7=9A=84=E5=9B=BE=E7=89=87=E8=BF=9B=E5=BA=A6=E4=B9=9F=E4=B8=8A?= =?UTF-8?q?=E6=8A=A5=EF=BC=88x/y=20=E5=BC=A0=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 一场秀几十到几百张图,按批处理要十几分钟,只报场次会让进度十几分钟不动。 media.UploadAllProgress 每批回调一次,spider 据此把「正在抓 X(32/50 张)」报给后台。 --- internal/media/upload.go | 12 ++++++++++++ internal/spider/vogue.go | 11 ++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/internal/media/upload.go b/internal/media/upload.go index 470f4c1..85fc2e0 100644 --- a/internal/media/upload.go +++ b/internal/media/upload.go @@ -77,6 +77,15 @@ func New(client *ingest.Client, prefix string, concurrency int) *Uploader { // UploadAll 并发完成「下载 → 生成 key → 预签名 → PUT」,返回与 urls 下标一一对应的结果。 // 单张失败不影响其他张:该下标 Err 非空,调用方据此对这张回退成 URL 上报。 func (u *Uploader) UploadAll(ctx context.Context, urls []string) []Result { + return u.UploadAllProgress(ctx, urls, nil) +} + +// UploadAllProgress 与 UploadAll 相同,但每完成一批回调一次 onBatch(done, total)。 +// +// 用途:一场秀几十到几百张图,按批处理要跑十几分钟。 +// 上层靠这个回调把「传到第几张」显示到后台,否则进度只能一场一跳, +// 中间十几分钟界面上什么都看不出。 +func (u *Uploader) UploadAllProgress(ctx context.Context, urls []string, onBatch func(done, total int)) []Result { results := make([]Result, len(urls)) if len(urls) == 0 { return results @@ -93,6 +102,9 @@ func (u *Uploader) UploadAll(ctx context.Context, urls []string) []Result { end = len(urls) } u.uploadBatch(ctx, urls, results, start, end) + if onBatch != nil { + onBatch(end, len(urls)) + } } return results } diff --git a/internal/spider/vogue.go b/internal/spider/vogue.go index abeab72..d480a42 100644 --- a/internal/spider/vogue.go +++ b/internal/spider/vogue.go @@ -2,6 +2,7 @@ package spider import ( "context" + "fmt" "log" "regexp" "strconv" @@ -101,7 +102,7 @@ const maxShowConcurrency = 2 // // 返回 true 表示全部成功;false 表示有失败项 —— 失败的图仍保留原始 URL, // 后端见到「没有 key」就用 URL 自己下载,所以整场不会因为几张图失败而报废。 -func (s *VogueSpider) uploadLookMedia(ctx context.Context, looks []ingest.RunwayLook) bool { +func (s *VogueSpider) uploadLookMedia(ctx context.Context, title string, looks []ingest.RunwayLook) bool { type ref struct{ look, detail int } // detail = -1 表示主图 urls := make([]string, 0, len(looks)*2) @@ -123,7 +124,11 @@ func (s *VogueSpider) uploadLookMedia(ctx context.Context, looks []ingest.Runway return true } - res := s.Media.UploadAll(ctx, urls) + // 每传完一批把「这场传到第几张」报给后台:一场秀按批要跑十几分钟, + // 只报场次的话界面会十几分钟不动,看着像卡死。 + res := s.Media.UploadAllProgress(ctx, urls, func(done, total int) { + s.reportProgress(fmt.Sprintf("%s(%d/%d 张)", title, done, total), false) + }) okAll := true for k, r := range res { if r.Err != nil || r.Key == "" { @@ -456,7 +461,7 @@ func (s *VogueSpider) getDetail(brandUID string, info gjson.Result) { // 任一张失败不影响整场:失败的图仍带原始 URL,由后端兜底下载。 if s.Media != nil && len(looks) > 0 { log.Printf("[media] 开始直传 %d 个 look / %d 张图", len(looks), totalImages) - okAll := s.uploadLookMedia(context.Background(), looks) + okAll := s.uploadLookMedia(context.Background(), hed, looks) if okAll { log.Printf("[media] 已直传 %d 个 look / %d 张图,后端将跳过下载", len(looks), totalImages) } else {