111 lines
3.0 KiB
Go
111 lines
3.0 KiB
Go
package cloudconvert
|
|
|
|
import (
|
|
cc "Yimaru-Backend/internal/pkgs/cloudconvert"
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"time"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type Service struct {
|
|
client *cc.Client
|
|
logger *zap.Logger
|
|
}
|
|
|
|
func NewService(apiKey string, logger *zap.Logger) *Service {
|
|
return &Service{
|
|
client: cc.NewClient(apiKey),
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
type CompressResult struct {
|
|
Data io.ReadCloser
|
|
FileSize int64
|
|
Filename string
|
|
}
|
|
|
|
func (s *Service) CompressVideo(ctx context.Context, filename string, fileData io.Reader, fileSize int64) (*CompressResult, error) {
|
|
s.logger.Info("Creating CloudConvert compression job", zap.String("filename", filename), zap.Int64("original_size", fileSize))
|
|
|
|
job, err := s.client.CreateVideoCompressionJob(ctx)
|
|
if err != nil {
|
|
s.logger.Error("Failed to create CloudConvert job", zap.Error(err))
|
|
return nil, fmt.Errorf("failed to create compression job: %w", err)
|
|
}
|
|
|
|
var uploadForm *cc.UploadForm
|
|
for _, task := range job.Tasks {
|
|
if task.Name == "import-video" && task.Result != nil && task.Result.Form != nil {
|
|
uploadForm = task.Result.Form
|
|
break
|
|
}
|
|
}
|
|
|
|
if uploadForm == nil {
|
|
return nil, fmt.Errorf("no upload form found in job response")
|
|
}
|
|
|
|
s.logger.Info("Uploading video to CloudConvert", zap.String("job_id", job.ID))
|
|
|
|
if err := s.client.UploadFile(ctx, uploadForm, filename, fileData); err != nil {
|
|
s.logger.Error("Failed to upload file to CloudConvert", zap.Error(err))
|
|
return nil, fmt.Errorf("failed to upload file: %w", err)
|
|
}
|
|
|
|
s.logger.Info("Waiting for CloudConvert job to complete", zap.String("job_id", job.ID))
|
|
|
|
completedJob, err := s.client.WaitForJob(ctx, job.ID, 5*time.Second, 30*time.Minute)
|
|
if err != nil {
|
|
s.logger.Error("CloudConvert job failed", zap.String("job_id", job.ID), zap.Error(err))
|
|
return nil, fmt.Errorf("compression job failed: %w", err)
|
|
}
|
|
|
|
var exportURL string
|
|
var exportFilename string
|
|
for _, task := range completedJob.Tasks {
|
|
if task.Name == "export-video" && task.Result != nil && len(task.Result.Files) > 0 {
|
|
exportURL = task.Result.Files[0].URL
|
|
exportFilename = task.Result.Files[0].Filename
|
|
break
|
|
}
|
|
}
|
|
|
|
if exportURL == "" {
|
|
return nil, fmt.Errorf("no export URL found in completed job")
|
|
}
|
|
|
|
s.logger.Info("Downloading compressed video from CloudConvert", zap.String("job_id", job.ID), zap.String("filename", exportFilename))
|
|
|
|
body, contentLength, err := s.client.DownloadFile(ctx, exportURL)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to download compressed file: %w", err)
|
|
}
|
|
|
|
if contentLength <= 0 {
|
|
data, err := io.ReadAll(body)
|
|
body.Close()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read compressed file: %w", err)
|
|
}
|
|
contentLength = int64(len(data))
|
|
body = io.NopCloser(bytes.NewReader(data))
|
|
}
|
|
|
|
s.logger.Info("Video compression complete",
|
|
zap.Int64("original_size", fileSize),
|
|
zap.Int64("compressed_size", contentLength),
|
|
zap.String("filename", exportFilename),
|
|
)
|
|
|
|
return &CompressResult{
|
|
Data: body,
|
|
FileSize: contentLength,
|
|
Filename: exportFilename,
|
|
}, nil
|
|
}
|