Files
djk/internal/app/provider_huangdou_detail.go

68 lines
1.8 KiB
Go

package app
import (
"context"
"errors"
"strings"
"time"
)
type huangdouDetailEntry struct {
row map[string]any
expiresAt time.Time
}
type huangdouDetailCall struct {
done chan struct{}
row map[string]any
err error
}
func (d *Downloader) huangdouDetail(ctx context.Context, id string) (map[string]any, error) {
if !rankingSourceID.MatchString(id) {
return nil, errors.New("无效的黄豆剧集 ID")
}
d.providerMu.Lock()
if cached, found := d.huangdouDetails[id]; found && time.Now().Before(cached.expiresAt) {
d.providerMu.Unlock()
return cached.row, nil
}
if pending := d.huangdouDetailPending[id]; pending != nil {
d.providerMu.Unlock()
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-pending.done:
if (errors.Is(pending.err, context.Canceled) || errors.Is(pending.err, context.DeadlineExceeded)) && ctx.Err() == nil {
return d.huangdouDetail(ctx, id)
}
return pending.row, pending.err
}
}
if d.huangdouDetailPending == nil {
d.huangdouDetailPending = make(map[string]*huangdouDetailCall)
}
call := &huangdouDetailCall{done: make(chan struct{})}
d.huangdouDetailPending[id] = call
d.providerMu.Unlock()
var decoded any
err := newHuangdouAPIClient(d).call(ctx, "/drama/detail", map[string]any{"id": id}, &decoded)
row := huangdouDataMap(decoded)
if err == nil && strings.TrimPrefix(mapString(row, "id", "drama_id"), "rp_") != id {
row = nil
err = errors.New("黄豆详情返回了其他剧集")
}
d.providerMu.Lock()
if err == nil {
if d.huangdouDetails == nil || len(d.huangdouDetails) >= 128 {
d.huangdouDetails = make(map[string]huangdouDetailEntry)
}
d.huangdouDetails[id] = huangdouDetailEntry{row: row, expiresAt: time.Now().Add(dramaRefreshRetryDelay)}
}
call.row, call.err = row, err
delete(d.huangdouDetailPending, id)
close(call.done)
d.providerMu.Unlock()
return row, err
}