feat: 单场秀内的图片进度也上报(x/y 张)

一场秀几十到几百张图,按批处理要十几分钟,只报场次会让进度十几分钟不动。
media.UploadAllProgress 每批回调一次,spider 据此把「正在抓 X(32/50 张)」报给后台。
This commit is contained in:
toom1996
2026-10-25 21:02:52 +08:00
parent fb9b6c4f6e
commit 1ead57dd22
2 changed files with 20 additions and 3 deletions

View File

@ -77,6 +77,15 @@ func New(client *ingest.Client, prefix string, concurrency int) *Uploader {
// UploadAll 并发完成「下载 → 生成 key → 预签名 → PUT」,返回与 urls 下标一一对应的结果。 // UploadAll 并发完成「下载 → 生成 key → 预签名 → PUT」,返回与 urls 下标一一对应的结果。
// 单张失败不影响其他张:该下标 Err 非空,调用方据此对这张回退成 URL 上报。 // 单张失败不影响其他张:该下标 Err 非空,调用方据此对这张回退成 URL 上报。
func (u *Uploader) UploadAll(ctx context.Context, urls []string) []Result { 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)) results := make([]Result, len(urls))
if len(urls) == 0 { if len(urls) == 0 {
return results return results
@ -93,6 +102,9 @@ func (u *Uploader) UploadAll(ctx context.Context, urls []string) []Result {
end = len(urls) end = len(urls)
} }
u.uploadBatch(ctx, urls, results, start, end) u.uploadBatch(ctx, urls, results, start, end)
if onBatch != nil {
onBatch(end, len(urls))
}
} }
return results return results
} }

View File

@ -2,6 +2,7 @@ package spider
import ( import (
"context" "context"
"fmt"
"log" "log"
"regexp" "regexp"
"strconv" "strconv"
@ -101,7 +102,7 @@ const maxShowConcurrency = 2
// //
// 返回 true 表示全部成功;false 表示有失败项 —— 失败的图仍保留原始 URL, // 返回 true 表示全部成功;false 表示有失败项 —— 失败的图仍保留原始 URL,
// 后端见到「没有 key」就用 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 表示主图 type ref struct{ look, detail int } // detail = -1 表示主图
urls := make([]string, 0, len(looks)*2) urls := make([]string, 0, len(looks)*2)
@ -123,7 +124,11 @@ func (s *VogueSpider) uploadLookMedia(ctx context.Context, looks []ingest.Runway
return true 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 okAll := true
for k, r := range res { for k, r := range res {
if r.Err != nil || r.Key == "" { if r.Err != nil || r.Key == "" {
@ -456,7 +461,7 @@ func (s *VogueSpider) getDetail(brandUID string, info gjson.Result) {
// 任一张失败不影响整场:失败的图仍带原始 URL,由后端兜底下载。 // 任一张失败不影响整场:失败的图仍带原始 URL,由后端兜底下载。
if s.Media != nil && len(looks) > 0 { if s.Media != nil && len(looks) > 0 {
log.Printf("[media] 开始直传 %d 个 look / %d 张图", len(looks), totalImages) log.Printf("[media] 开始直传 %d 个 look / %d 张图", len(looks), totalImages)
okAll := s.uploadLookMedia(context.Background(), looks) okAll := s.uploadLookMedia(context.Background(), hed, looks)
if okAll { if okAll {
log.Printf("[media] 已直传 %d 个 look / %d 张图,后端将跳过下载", len(looks), totalImages) log.Printf("[media] 已直传 %d 个 look / %d 张图,后端将跳过下载", len(looks), totalImages)
} else { } else {