Yimaru-BackEnd/internal/services/vimeo/service.go
2026-03-06 06:03:05 -08:00

214 lines
6.0 KiB
Go

package vimeo
import (
"Yimaru-Backend/internal/pkgs/vimeo"
"context"
"fmt"
"io"
"go.uber.org/zap"
)
type Service struct {
client *vimeo.Client
logger *zap.Logger
}
func NewService(accessToken string, logger *zap.Logger) *Service {
return &Service{
client: vimeo.NewClient(accessToken),
logger: logger,
}
}
type VideoInfo struct {
VimeoID string
URI string
Name string
Description string
Duration int
Width int
Height int
Link string
EmbedURL string
EmbedHTML string
ThumbnailURL string
Status string
TranscodeStatus string
}
type UploadResult struct {
VimeoID string
URI string
Link string
UploadLink string
Status string
}
func (s *Service) GetVideoInfo(ctx context.Context, videoID string) (*VideoInfo, error) {
video, err := s.client.GetVideo(ctx, videoID)
if err != nil {
s.logger.Error("Failed to get video from Vimeo", zap.String("video_id", videoID), zap.Error(err))
return nil, fmt.Errorf("failed to get video: %w", err)
}
info := &VideoInfo{
VimeoID: videoID,
URI: video.URI,
Name: video.Name,
Description: video.Description,
Duration: video.Duration,
Width: video.Width,
Height: video.Height,
Link: video.Link,
Status: video.Status,
}
if video.PlayerEmbedURL != "" {
info.EmbedURL = video.PlayerEmbedURL
} else {
info.EmbedURL = vimeo.GenerateEmbedURL(videoID, nil)
}
if video.Embed != nil {
info.EmbedHTML = video.Embed.HTML
}
if video.Pictures != nil && len(video.Pictures.Sizes) > 0 {
info.ThumbnailURL = video.Pictures.Sizes[len(video.Pictures.Sizes)-1].Link
}
if video.Transcode != nil {
info.TranscodeStatus = video.Transcode.Status
}
return info, nil
}
func (s *Service) CreatePullUpload(ctx context.Context, name, description, sourceURL string, fileSize int64) (*UploadResult, error) {
resp, err := s.client.CreatePullUpload(ctx, name, description, sourceURL, fileSize)
if err != nil {
s.logger.Error("Failed to create pull upload", zap.String("source_url", sourceURL), zap.Error(err))
return nil, fmt.Errorf("failed to create pull upload: %w", err)
}
videoID := vimeo.ExtractVideoID(resp.URI)
return &UploadResult{
VimeoID: videoID,
URI: resp.URI,
Link: resp.Link,
UploadLink: resp.Upload.UploadLink,
Status: resp.Upload.Status,
}, nil
}
func (s *Service) CreateTusUpload(ctx context.Context, name, description string, fileSize int64) (*UploadResult, error) {
resp, err := s.client.CreateTusUpload(ctx, name, description, fileSize)
if err != nil {
s.logger.Error("Failed to create TUS upload", zap.Error(err))
return nil, fmt.Errorf("failed to create TUS upload: %w", err)
}
videoID := vimeo.ExtractVideoID(resp.URI)
return &UploadResult{
VimeoID: videoID,
URI: resp.URI,
Link: resp.Link,
UploadLink: resp.Upload.UploadLink,
Status: resp.Upload.Status,
}, nil
}
func (s *Service) UploadVideoFile(ctx context.Context, name, description string, fileData io.Reader, fileSize int64) (*UploadResult, error) {
resp, err := s.client.CreateTusUpload(ctx, name, description, fileSize)
if err != nil {
s.logger.Error("Failed to create TUS upload slot", zap.Error(err))
return nil, fmt.Errorf("failed to create TUS upload slot: %w", err)
}
if err := s.client.UploadTusVideoFile(ctx, resp.Upload.UploadLink, fileData, fileSize); err != nil {
s.logger.Error("Failed to upload video file to Vimeo", zap.Error(err))
return nil, fmt.Errorf("failed to upload video file: %w", err)
}
videoID := vimeo.ExtractVideoID(resp.URI)
return &UploadResult{
VimeoID: videoID,
URI: resp.URI,
Link: resp.Link,
UploadLink: resp.Upload.UploadLink,
Status: "uploading",
}, nil
}
func (s *Service) UpdateVideoMetadata(ctx context.Context, videoID string, name, description *string) (*VideoInfo, error) {
req := &vimeo.UpdateVideoRequest{
Name: name,
Description: description,
}
video, err := s.client.UpdateVideo(ctx, videoID, req)
if err != nil {
s.logger.Error("Failed to update video metadata", zap.String("video_id", videoID), zap.Error(err))
return nil, fmt.Errorf("failed to update video: %w", err)
}
info := &VideoInfo{
VimeoID: videoID,
URI: video.URI,
Name: video.Name,
Description: video.Description,
Duration: video.Duration,
Link: video.Link,
}
return info, nil
}
func (s *Service) DeleteVideo(ctx context.Context, videoID string) error {
if err := s.client.DeleteVideo(ctx, videoID); err != nil {
s.logger.Error("Failed to delete video from Vimeo", zap.String("video_id", videoID), zap.Error(err))
return fmt.Errorf("failed to delete video: %w", err)
}
return nil
}
func (s *Service) GetTranscodeStatus(ctx context.Context, videoID string) (string, error) {
status, err := s.client.GetTranscodeStatus(ctx, videoID)
if err != nil {
return "", fmt.Errorf("failed to get transcode status: %w", err)
}
return status, nil
}
func (s *Service) GetEmbedCode(ctx context.Context, videoID string, width, height int, opts *vimeo.EmbedOptions) (string, error) {
return vimeo.GenerateIframeEmbed(videoID, width, height, opts), nil
}
func (s *Service) GetOEmbed(ctx context.Context, vimeoURL string, width, height int) (*vimeo.OEmbedResponse, error) {
return vimeo.GetOEmbed(ctx, vimeoURL, width, height)
}
func (s *Service) GeneratePlayerURL(videoID string, opts *vimeo.EmbedOptions) string {
return vimeo.GenerateEmbedURL(videoID, opts)
}
// GetSampleVideo fetches a public Vimeo video by ID and returns its info along with an embeddable iframe.
func (s *Service) GetSampleVideo(ctx context.Context, videoID string, width, height int) (*VideoInfo, string, error) {
info, err := s.GetVideoInfo(ctx, videoID)
if err != nil {
return nil, "", fmt.Errorf("failed to get sample video: %w", err)
}
iframe := vimeo.GenerateIframeEmbed(videoID, width, height, &vimeo.EmbedOptions{
Title: true,
Byline: true,
Portrait: true,
})
return info, iframe, nil
}