284 lines
7.6 KiB
Go
284 lines
7.6 KiB
Go
package course_management
|
|
|
|
import (
|
|
"Yimaru-Backend/internal/domain"
|
|
"Yimaru-Backend/internal/pkgs/vimeo"
|
|
vimeoservice "Yimaru-Backend/internal/services/vimeo"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"path"
|
|
"time"
|
|
)
|
|
|
|
func (s *Service) CreateSubCourseVideo(
|
|
ctx context.Context,
|
|
subCourseID int64,
|
|
title string,
|
|
description *string,
|
|
videoURL string,
|
|
duration int32,
|
|
resolution *string,
|
|
instructorID *string,
|
|
thumbnail *string,
|
|
visibility *string,
|
|
displayOrder *int32,
|
|
status *string,
|
|
) (domain.SubCourseVideo, error) {
|
|
// Default to DIRECT provider when no Vimeo info provided
|
|
provider := string(domain.VideoHostProviderDirect)
|
|
return s.courseStore.CreateSubCourseVideo(
|
|
ctx, subCourseID, title, description, videoURL, duration,
|
|
resolution, instructorID, thumbnail, visibility, displayOrder, status,
|
|
nil, nil, nil, nil, &provider,
|
|
)
|
|
}
|
|
|
|
// CreateSubCourseVideoWithVimeo creates a video and uploads it to Vimeo
|
|
func (s *Service) CreateSubCourseVideoWithVimeo(
|
|
ctx context.Context,
|
|
subCourseID int64,
|
|
title string,
|
|
description *string,
|
|
sourceURL string,
|
|
fileSize int64,
|
|
duration int32,
|
|
resolution *string,
|
|
instructorID *string,
|
|
thumbnail *string,
|
|
visibility *string,
|
|
displayOrder *int32,
|
|
) (domain.SubCourseVideo, error) {
|
|
if s.vimeoSvc == nil {
|
|
return domain.SubCourseVideo{}, fmt.Errorf("vimeo service is not configured")
|
|
}
|
|
|
|
descStr := ""
|
|
if description != nil {
|
|
descStr = *description
|
|
}
|
|
|
|
var uploadResult *vimeoservice.UploadResult
|
|
var err error
|
|
|
|
if s.cloudConvertSvc != nil {
|
|
httpClient := &http.Client{Timeout: 30 * time.Minute}
|
|
req, reqErr := http.NewRequestWithContext(ctx, http.MethodGet, sourceURL, nil)
|
|
if reqErr != nil {
|
|
return domain.SubCourseVideo{}, fmt.Errorf("failed to create download request: %w", reqErr)
|
|
}
|
|
resp, dlErr := httpClient.Do(req)
|
|
if dlErr != nil {
|
|
return domain.SubCourseVideo{}, fmt.Errorf("failed to download source video: %w", dlErr)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return domain.SubCourseVideo{}, fmt.Errorf("failed to download source video: status %d", resp.StatusCode)
|
|
}
|
|
|
|
dlSize := resp.ContentLength
|
|
if dlSize <= 0 {
|
|
dlSize = fileSize
|
|
}
|
|
|
|
filename := path.Base(sourceURL)
|
|
if filename == "" || filename == "." || filename == "/" {
|
|
filename = "video.mp4"
|
|
}
|
|
|
|
result, compErr := s.cloudConvertSvc.CompressVideo(ctx, filename, resp.Body, dlSize)
|
|
if compErr != nil {
|
|
return domain.SubCourseVideo{}, fmt.Errorf("failed to compress video: %w", compErr)
|
|
}
|
|
defer result.Data.Close()
|
|
|
|
uploadResult, err = s.vimeoSvc.UploadVideoFile(ctx, title, descStr, result.Data, result.FileSize)
|
|
} else {
|
|
uploadResult, err = s.vimeoSvc.CreatePullUpload(ctx, title, descStr, sourceURL, fileSize)
|
|
}
|
|
|
|
if err != nil {
|
|
return domain.SubCourseVideo{}, fmt.Errorf("failed to upload to Vimeo: %w", err)
|
|
}
|
|
|
|
embedURL := vimeo.GenerateEmbedURL(uploadResult.VimeoID, &vimeo.EmbedOptions{
|
|
Title: true,
|
|
Byline: true,
|
|
Portrait: true,
|
|
})
|
|
|
|
embedHTML := vimeo.GenerateIframeEmbed(uploadResult.VimeoID, 640, 360, nil)
|
|
|
|
provider := string(domain.VideoHostProviderVimeo)
|
|
vimeoStatus := "uploading"
|
|
status := "DRAFT"
|
|
|
|
return s.courseStore.CreateSubCourseVideo(
|
|
ctx, subCourseID, title, description,
|
|
uploadResult.Link,
|
|
duration, resolution, instructorID, thumbnail, visibility, displayOrder, &status,
|
|
&uploadResult.VimeoID, &embedURL, &embedHTML, &vimeoStatus, &provider,
|
|
)
|
|
}
|
|
|
|
func (s *Service) CreateSubCourseVideoWithFileUpload(
|
|
ctx context.Context,
|
|
subCourseID int64,
|
|
title string,
|
|
description *string,
|
|
filename string,
|
|
fileData io.Reader,
|
|
fileSize int64,
|
|
duration int32,
|
|
resolution *string,
|
|
instructorID *string,
|
|
thumbnail *string,
|
|
visibility *string,
|
|
displayOrder *int32,
|
|
) (domain.SubCourseVideo, error) {
|
|
if s.vimeoSvc == nil {
|
|
return domain.SubCourseVideo{}, fmt.Errorf("vimeo service is not configured")
|
|
}
|
|
|
|
descStr := ""
|
|
if description != nil {
|
|
descStr = *description
|
|
}
|
|
|
|
videoReader := fileData
|
|
videoSize := fileSize
|
|
|
|
if s.cloudConvertSvc != nil {
|
|
result, err := s.cloudConvertSvc.CompressVideo(ctx, filename, fileData, fileSize)
|
|
if err != nil {
|
|
return domain.SubCourseVideo{}, fmt.Errorf("failed to compress video: %w", err)
|
|
}
|
|
defer result.Data.Close()
|
|
videoReader = result.Data
|
|
videoSize = result.FileSize
|
|
}
|
|
|
|
uploadResult, err := s.vimeoSvc.UploadVideoFile(ctx, title, descStr, videoReader, videoSize)
|
|
if err != nil {
|
|
return domain.SubCourseVideo{}, fmt.Errorf("failed to upload video file to Vimeo: %w", err)
|
|
}
|
|
|
|
embedURL := vimeo.GenerateEmbedURL(uploadResult.VimeoID, &vimeo.EmbedOptions{
|
|
Title: true,
|
|
Byline: true,
|
|
Portrait: true,
|
|
})
|
|
|
|
embedHTML := vimeo.GenerateIframeEmbed(uploadResult.VimeoID, 640, 360, nil)
|
|
|
|
provider := string(domain.VideoHostProviderVimeo)
|
|
vimeoStatus := "uploading"
|
|
status := "DRAFT"
|
|
|
|
return s.courseStore.CreateSubCourseVideo(
|
|
ctx, subCourseID, title, description,
|
|
uploadResult.Link,
|
|
duration, resolution, instructorID, thumbnail, visibility, displayOrder, &status,
|
|
&uploadResult.VimeoID, &embedURL, &embedHTML, &vimeoStatus, &provider,
|
|
)
|
|
}
|
|
|
|
// CreateSubCourseVideoFromVimeoID creates a video record from an existing Vimeo video
|
|
func (s *Service) CreateSubCourseVideoFromVimeoID(
|
|
ctx context.Context,
|
|
subCourseID int64,
|
|
vimeoVideoID string,
|
|
title string,
|
|
description *string,
|
|
displayOrder *int32,
|
|
instructorID *string,
|
|
) (domain.SubCourseVideo, error) {
|
|
if s.vimeoSvc == nil {
|
|
return domain.SubCourseVideo{}, fmt.Errorf("vimeo service is not configured")
|
|
}
|
|
|
|
// Fetch video info from Vimeo
|
|
info, err := s.vimeoSvc.GetVideoInfo(ctx, vimeoVideoID)
|
|
if err != nil {
|
|
return domain.SubCourseVideo{}, fmt.Errorf("failed to get Vimeo video info: %w", err)
|
|
}
|
|
|
|
// Use Vimeo data
|
|
embedHTML := vimeo.GenerateIframeEmbed(vimeoVideoID, 640, 360, nil)
|
|
provider := string(domain.VideoHostProviderVimeo)
|
|
vimeoStatus := info.TranscodeStatus
|
|
if vimeoStatus == "" {
|
|
vimeoStatus = "available"
|
|
}
|
|
status := "DRAFT"
|
|
duration := int32(info.Duration)
|
|
resolution := fmt.Sprintf("%dx%d", info.Width, info.Height)
|
|
thumbnail := info.ThumbnailURL
|
|
|
|
return s.courseStore.CreateSubCourseVideo(
|
|
ctx, subCourseID, title, description,
|
|
info.Link, duration, &resolution, instructorID, &thumbnail, nil, displayOrder, &status,
|
|
&vimeoVideoID, &info.EmbedURL, &embedHTML, &vimeoStatus, &provider,
|
|
)
|
|
}
|
|
|
|
func (s *Service) GetSubCourseVideoByID(
|
|
ctx context.Context,
|
|
id int64,
|
|
) (domain.SubCourseVideo, error) {
|
|
return s.courseStore.GetSubCourseVideoByID(ctx, id)
|
|
}
|
|
|
|
func (s *Service) GetVideosBySubCourse(
|
|
ctx context.Context,
|
|
subCourseID int64,
|
|
) ([]domain.SubCourseVideo, int64, error) {
|
|
return s.courseStore.GetVideosBySubCourse(ctx, subCourseID)
|
|
}
|
|
|
|
func (s *Service) GetPublishedVideosBySubCourse(
|
|
ctx context.Context,
|
|
subCourseID int64,
|
|
) ([]domain.SubCourseVideo, error) {
|
|
return s.courseStore.GetPublishedVideosBySubCourse(ctx, subCourseID)
|
|
}
|
|
|
|
func (s *Service) PublishSubCourseVideo(
|
|
ctx context.Context,
|
|
videoID int64,
|
|
) error {
|
|
return s.courseStore.PublishSubCourseVideo(ctx, videoID)
|
|
}
|
|
|
|
func (s *Service) UpdateSubCourseVideo(
|
|
ctx context.Context,
|
|
id int64,
|
|
title *string,
|
|
description *string,
|
|
videoURL *string,
|
|
duration *int32,
|
|
resolution *string,
|
|
visibility *string,
|
|
thumbnail *string,
|
|
displayOrder *int32,
|
|
status *string,
|
|
) error {
|
|
return s.courseStore.UpdateSubCourseVideo(ctx, id, title, description, videoURL, duration, resolution, visibility, thumbnail, displayOrder, status)
|
|
}
|
|
|
|
func (s *Service) ArchiveSubCourseVideo(
|
|
ctx context.Context,
|
|
id int64,
|
|
) error {
|
|
return s.courseStore.ArchiveSubCourseVideo(ctx, id)
|
|
}
|
|
|
|
func (s *Service) DeleteSubCourseVideo(
|
|
ctx context.Context,
|
|
id int64,
|
|
) error {
|
|
return s.courseStore.DeleteSubCourseVideo(ctx, id)
|
|
}
|