spark-server/internal/module/squarebot/logic/attach.go
DESKTOP-L8OUL9F\gfl0034 5fda6be8ec feat(squarebot): 接入媒体引导与 Bot 附件/锁
完善 bootstrap 媒体装配、配置开关,并补充 squarebot 附件与锁逻辑。
2026-09-24 23:37:44 +08:00

91 lines
2.7 KiB
Go

package logic
import (
"context"
"strings"
"time"
"go.uber.org/zap"
infmedia "spark-server/internal/infrastructure/media"
squareentity "spark-server/internal/module/square/entity"
uploadentity "spark-server/internal/module/upload/entity"
"spark-server/internal/pkg/reqctx"
)
// ObjectStore writes compressed bot assets before square publish.
type ObjectStore interface {
Put(ctx context.Context, key string, body []byte, contentType string) error
PutLarge(ctx context.Context, key string, body []byte, contentType string, maxBytes int) error
}
// BindMedia attaches optional compressor + object store for RSS enclosure images/videos.
func (s *Service) BindMedia(comp *MediaCompressor, store ObjectStore, botCompress bool) {
if s == nil {
return
}
s.comp = comp
s.store = store
s.botCompress = botCompress
}
// attachMedia downloads/compresses optional enclosure and returns square Image refs (best-effort).
func (s *Service) attachMedia(ctx context.Context, item FeedItem) []*squareentity.Image {
if s == nil || !s.botCompress || s.comp == nil || s.store == nil {
return nil
}
imgURL := strings.TrimSpace(item.ImageURL)
if imgURL == "" {
return nil
}
asset, err := s.comp.FetchImage(ctx, imgURL)
if err != nil {
s.log.Warn("squarebot compress image", zap.String("url", imgURL), zap.Error(err))
return nil
}
ext := extForMIME(asset.MIME)
key := uploadentity.BuildObjectKey(
uploadentity.PurposeSquareImage, 0, reqctx.NewObjectName(),
time.Now().UTC().Format("20060102"), ext,
)
if err := s.store.Put(ctx, key, asset.Data, asset.MIME); err != nil {
s.log.Warn("squarebot put image", zap.String("key", key), zap.Error(err))
return nil
}
return []*squareentity.Image{{
Key: key, Mime: asset.MIME, Width: asset.Width, Height: asset.Height, Size: asset.Size,
}}
}
// PrepareVideoAsset compresses a remote video and uploads it (bot video paths; requires ffmpeg).
func (s *Service) PrepareVideoAsset(ctx context.Context, videoURL string) (*infmedia.BotAsset, string, error) {
if s == nil || !s.botCompress || s.comp == nil || s.store == nil {
return nil, "", nil
}
asset, err := s.comp.FetchVideo(ctx, videoURL)
if err != nil {
return nil, "", err
}
key := uploadentity.BuildObjectKey(
uploadentity.PurposeSquareVideo, 0, reqctx.NewObjectName(),
time.Now().UTC().Format("20060102"), "mp4",
)
if err := s.store.PutLarge(ctx, key, asset.Data, asset.MIME, int(asset.Size)+1); err != nil {
return nil, "", err
}
return asset, key, nil
}
func extForMIME(mime string) string {
switch strings.ToLower(strings.TrimSpace(mime)) {
case "image/png":
return "png"
case "image/gif":
return "gif"
case "image/webp":
return "webp"
default:
return "jpg"
}
}