publish-vod/pkg/uploader/youtube/youtube.go

115 lines
3.2 KiB
Go
Raw Permalink Normal View History

// Package youtube contains an uploader to push VoDs to a Youtube
// channel
package youtube
import (
"context"
"fmt"
"path"
"strings"
"time"
"github.com/sirupsen/logrus"
"google.golang.org/api/option"
"google.golang.org/api/youtube/v3"
"git.luzifer.io/luzifer/publish-vod/pkg/uploader"
vaultoauth2 "git.luzifer.io/luzifer/publish-vod/pkg/vault-oauth2"
oauth4youtube "git.luzifer.io/luzifer/publish-vod/pkg/vault-oauth2/youtube"
"github.com/Luzifer/go_helpers/v2/fieldcollection"
)
type (
impl struct{}
)
var ptrStringEmpty = func(v string) *string { return &v }("")
// New creates a new Youtube Uploader
func New() uploader.Uploader { return impl{} }
func (impl) Prepare(ctx context.Context, opts uploader.Opts) error {
_, ts, err := oauth4youtube.GetOAuth2Client(ctx, opts.Config.MustString("vaultKey", nil))
if err != nil {
return fmt.Errorf("getting oauth credentials: %w", err)
}
t, err := ts.Token()
if err != nil {
return fmt.Errorf("getting token to store: %w", err)
}
if err := vaultoauth2.SaveTokenToVault(opts.Config.MustString("vaultKey", nil), t); err != nil {
return fmt.Errorf("storing token to vault: %w", err)
}
return nil
}
func (impl) UploadFile(ctx context.Context, opts uploader.Opts) error {
client, ts, err := oauth4youtube.GetOAuth2Client(ctx, opts.Config.MustString("vaultKey", nil))
if err != nil {
return fmt.Errorf("getting oauth credentials: %w", err)
}
defer func() {
t, err := ts.Token()
if err != nil {
logrus.WithError(err).Error("getting token to store back")
}
if err := vaultoauth2.SaveTokenToVault(opts.Config.MustString("vaultKey", nil), t); err != nil {
logrus.WithError(err).Error("storing token back to vault")
}
}()
service, err := youtube.NewService(ctx, option.WithHTTPClient(client))
if err != nil {
return fmt.Errorf("creating Youtube client: %w", err)
}
upload := &youtube.Video{
Snippet: &youtube.VideoSnippet{
CategoryId: "20", // Gaming
ChannelId: opts.Config.MustString("channel", nil),
DefaultAudioLanguage: "de",
DefaultLanguage: "de",
Description: opts.Config.MustString("description", ptrStringEmpty),
LiveBroadcastContent: "none",
Title: strings.ReplaceAll(path.Base(opts.Filename), path.Ext(opts.Filename), ""),
},
Status: &youtube.VideoStatus{
Embeddable: true,
License: "youtube",
MadeForKids: false,
PrivacyStatus: "private",
PublicStatsViewable: true,
},
RecordingDetails: &youtube.VideoRecordingDetails{
RecordingDate: time.Now().Format(time.RFC3339),
},
}
progressReader := opts.ProgressBar.NewProxyReader(opts.Content)
resp, err := service.Videos.
Insert([]string{"snippet", "status", "recordingDetails"}, upload).
Media(progressReader).
Do()
if err != nil {
return fmt.Errorf("inserting video: %w", err)
}
opts.FinalMessage("Video uploaded: https://youtu.be/%s", resp.Id)
return nil
}
func (impl) ValidateConfig(config *fieldcollection.FieldCollection) error {
for _, key := range []string{"channel", "vaultKey"} {
if v, err := config.String(key); err != nil || v == "" {
return fmt.Errorf("key %q must be non-empty string", key)
}
}
return nil
}