Files
huobao-drama/infrastructure/storage/oss_storage.go
empty fe595db96e 添加视频帧提取功能和阿里云OSS存储支持
- 新增从视频素材提取首帧/尾帧的功能,支持画面连续性编辑
- 添加阿里云OSS存储支持,可配置本地或OSS存储方式
- 导入视频素材时自动探测并更新视频时长信息
- 前端添加从素材提取尾帧的UI界面
- 添加FramePrompt模型的数据库迁移

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-18 21:44:05 +08:00

123 lines
3.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package storage
import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/drama-generator/backend/pkg/config"
)
// OssStorage 阿里云 OSS 存储实现
type OssStorage struct {
client *oss.Client
bucket *oss.Bucket
bucketName string
customDomain string
endpoint string
}
// NewOssStorage 创建 OSS 存储实例
func NewOssStorage(cfg *config.OssConfig) (*OssStorage, error) {
if cfg.Endpoint == "" || cfg.AccessKeyID == "" || cfg.AccessKeySecret == "" || cfg.BucketName == "" {
return nil, fmt.Errorf("OSS configuration is incomplete")
}
client, err := oss.New(cfg.Endpoint, cfg.AccessKeyID, cfg.AccessKeySecret)
if err != nil {
return nil, fmt.Errorf("failed to create OSS client: %w", err)
}
bucket, err := client.Bucket(cfg.BucketName)
if err != nil {
return nil, fmt.Errorf("failed to get OSS bucket: %w", err)
}
return &OssStorage{
client: client,
bucket: bucket,
bucketName: cfg.BucketName,
customDomain: cfg.CustomDomain,
endpoint: cfg.Endpoint,
}, nil
}
// Upload 上传文件到 OSS
func (s *OssStorage) Upload(localPath, category string) (string, error) {
// 读取本地文件
file, err := os.Open(localPath)
if err != nil {
return "", fmt.Errorf("failed to open file: %w", err)
}
defer file.Close()
// 生成 OSS 对象键
ext := filepath.Ext(localPath)
timestamp := time.Now().Format("20060102_150405_000")
objectKey := fmt.Sprintf("%s/%s%s", category, timestamp, ext)
// 上传到 OSS
err = s.bucket.PutObject(objectKey, file)
if err != nil {
return "", fmt.Errorf("failed to upload to OSS: %w", err)
}
// 构建访问 URL
url := s.GetURL(objectKey)
return url, nil
}
// UploadWithFilename 使用指定文件名上传文件到 OSS
func (s *OssStorage) UploadWithFilename(localPath, category, filename string) (string, error) {
file, err := os.Open(localPath)
if err != nil {
return "", fmt.Errorf("failed to open file: %w", err)
}
defer file.Close()
objectKey := fmt.Sprintf("%s/%s", category, filename)
err = s.bucket.PutObject(objectKey, file)
if err != nil {
return "", fmt.Errorf("failed to upload to OSS: %w", err)
}
return s.GetURL(objectKey), nil
}
// GetURL 获取 OSS 对象的访问 URL
func (s *OssStorage) GetURL(objectKey string) string {
if s.customDomain != "" {
// 使用自定义域名CDN
domain := strings.TrimSuffix(s.customDomain, "/")
if !strings.HasPrefix(domain, "http") {
domain = "https://" + domain
}
return fmt.Sprintf("%s/%s", domain, objectKey)
}
// 使用默认 OSS 域名
return fmt.Sprintf("https://%s.%s/%s", s.bucketName, s.endpoint, objectKey)
}
// Delete 删除 OSS 对象
func (s *OssStorage) Delete(objectKey string) error {
err := s.bucket.DeleteObject(objectKey)
if err != nil {
return fmt.Errorf("failed to delete OSS object: %w", err)
}
return nil
}
// IsConfigured 检查 OSS 是否已配置
func IsOssConfigured(cfg *config.OssConfig) bool {
return cfg != nil &&
cfg.Endpoint != "" &&
cfg.AccessKeyID != "" &&
cfg.AccessKeySecret != "" &&
cfg.BucketName != ""
}