95 lines
2.8 KiB
Go
95 lines
2.8 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,
|
|
)
|
|
maxBytes := int(asset.Size) + 1
|
|
if maxBytes < 1<<20 {
|
|
maxBytes = 1 << 20
|
|
}
|
|
if err := s.store.PutLarge(ctx, key, asset.Data, asset.MIME, maxBytes); 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"
|
|
}
|
|
}
|