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 }