262 lines
6.4 KiB
Go
262 lines
6.4 KiB
Go
// Copyright 2025 eat-pray-ai & OpenWaygate
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package playlistImage
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
|
|
"github.com/eat-pray-ai/yutu/pkg"
|
|
"github.com/eat-pray-ai/yutu/pkg/common"
|
|
"github.com/jedib0t/go-pretty/v6/table"
|
|
"google.golang.org/api/youtube/v3"
|
|
)
|
|
|
|
var (
|
|
errGetPlaylistImage = errors.New("failed to get playlist image")
|
|
errInsertPlaylistImage = errors.New("failed to insert playlist image")
|
|
errUpdatePlaylistImage = errors.New("failed to update playlist image")
|
|
errDeletePlaylistImage = errors.New("failed to delete playlist image")
|
|
)
|
|
|
|
type PlaylistImage struct {
|
|
common.Fields
|
|
Height int64 `yaml:"height" json:"height,omitzero"`
|
|
PlaylistId string `yaml:"playlist_id" json:"playlist_id,omitempty"`
|
|
Type string `yaml:"type" json:"type,omitempty"`
|
|
Width int64 `yaml:"width" json:"width,omitzero"`
|
|
File string `yaml:"file" json:"file,omitempty"`
|
|
Parent string `yaml:"parent" json:"parent,omitempty"`
|
|
|
|
OnBehalfOfContentOwnerChannel string `yaml:"on_behalf_of_content_owner_channel" json:"on_behalf_of_content_owner_channel,omitempty"`
|
|
}
|
|
|
|
type IPlaylistImage[T any] interface {
|
|
Get() ([]*T, error)
|
|
List(io.Writer) error
|
|
Insert(io.Writer) error
|
|
Update(io.Writer) error
|
|
Delete(io.Writer) error
|
|
}
|
|
|
|
type Option func(*PlaylistImage)
|
|
|
|
func NewPlaylistImage(opts ...Option) IPlaylistImage[youtube.PlaylistImage] {
|
|
pi := &PlaylistImage{Fields: common.Fields{}}
|
|
for _, opt := range opts {
|
|
opt(pi)
|
|
}
|
|
return pi
|
|
}
|
|
|
|
func (pi *PlaylistImage) Get() ([]*youtube.PlaylistImage, error) {
|
|
if err := pi.EnsureService(); err != nil {
|
|
return nil, err
|
|
}
|
|
call := pi.Service.PlaylistImages.List()
|
|
call = call.Part(pi.Parts...)
|
|
if pi.Parent != "" {
|
|
call = call.Parent(pi.Parent)
|
|
}
|
|
if pi.OnBehalfOfContentOwner != "" {
|
|
call = call.OnBehalfOfContentOwner(pi.OnBehalfOfContentOwner)
|
|
}
|
|
if pi.OnBehalfOfContentOwnerChannel != "" {
|
|
call = call.OnBehalfOfContentOwnerChannel(pi.OnBehalfOfContentOwnerChannel)
|
|
}
|
|
|
|
return common.Paginate(
|
|
&pi.Fields, call,
|
|
func(r *youtube.PlaylistImageListResponse) ([]*youtube.PlaylistImage, string) {
|
|
return r.Items, r.NextPageToken
|
|
}, errGetPlaylistImage,
|
|
)
|
|
}
|
|
|
|
func (pi *PlaylistImage) List(writer io.Writer) error {
|
|
playlistImages, err := pi.Get()
|
|
if err != nil && playlistImages == nil {
|
|
return err
|
|
}
|
|
|
|
common.PrintList(
|
|
pi.Output, playlistImages, writer,
|
|
table.Row{"ID", "Kind", "Playlist ID", "Type"},
|
|
func(img *youtube.PlaylistImage) table.Row {
|
|
return table.Row{img.Id, img.Kind, img.Snippet.PlaylistId, img.Snippet.Type}
|
|
},
|
|
)
|
|
return err
|
|
}
|
|
|
|
func (pi *PlaylistImage) Insert(writer io.Writer) error {
|
|
if err := pi.EnsureService(); err != nil {
|
|
return err
|
|
}
|
|
file, err := pkg.Root.Open(pi.File)
|
|
if err != nil {
|
|
return errors.Join(errInsertPlaylistImage, err)
|
|
}
|
|
defer func(file *os.File) {
|
|
_ = file.Close()
|
|
}(file)
|
|
|
|
playlistImage := &youtube.PlaylistImage{
|
|
Kind: "youtube#playlistImages",
|
|
Snippet: &youtube.PlaylistImageSnippet{
|
|
PlaylistId: pi.PlaylistId,
|
|
Type: pi.Type,
|
|
Height: pi.Height,
|
|
Width: pi.Width,
|
|
},
|
|
}
|
|
|
|
call := pi.Service.PlaylistImages.Insert(playlistImage)
|
|
if pi.OnBehalfOfContentOwner != "" {
|
|
call = call.OnBehalfOfContentOwner(pi.OnBehalfOfContentOwner)
|
|
}
|
|
if pi.OnBehalfOfContentOwnerChannel != "" {
|
|
call = call.OnBehalfOfContentOwnerChannel(pi.OnBehalfOfContentOwnerChannel)
|
|
}
|
|
call = call.Media(file)
|
|
call = call.Part("kind", "snippet")
|
|
res, err := call.Do()
|
|
if err != nil {
|
|
return errors.Join(errInsertPlaylistImage, err)
|
|
}
|
|
|
|
common.PrintResult(
|
|
pi.Output, res, writer, "PlaylistImage inserted: %s\n", res.Id,
|
|
)
|
|
return nil
|
|
}
|
|
|
|
func (pi *PlaylistImage) Update(writer io.Writer) error {
|
|
if err := pi.EnsureService(); err != nil {
|
|
return err
|
|
}
|
|
pi.Parts = []string{"id", "kind", "snippet"}
|
|
playlistImages, err := pi.Get()
|
|
if err != nil {
|
|
return errors.Join(errUpdatePlaylistImage, err)
|
|
}
|
|
if len(playlistImages) == 0 {
|
|
return errGetPlaylistImage
|
|
}
|
|
|
|
playlistImage := playlistImages[0]
|
|
if pi.PlaylistId != "" {
|
|
playlistImage.Snippet.PlaylistId = pi.PlaylistId
|
|
}
|
|
if pi.Type != "" {
|
|
playlistImage.Snippet.Type = pi.Type
|
|
}
|
|
if pi.Height != 0 {
|
|
playlistImage.Snippet.Height = pi.Height
|
|
}
|
|
if pi.Width != 0 {
|
|
playlistImage.Snippet.Width = pi.Width
|
|
}
|
|
|
|
call := pi.Service.PlaylistImages.Update(playlistImage)
|
|
if pi.OnBehalfOfContentOwner != "" {
|
|
call = call.OnBehalfOfContentOwner(pi.OnBehalfOfContentOwner)
|
|
}
|
|
if pi.File != "" {
|
|
file, err := pkg.Root.Open(pi.File)
|
|
if err != nil {
|
|
return errors.Join(errUpdatePlaylistImage, err)
|
|
}
|
|
defer func(file *os.File) {
|
|
_ = file.Close()
|
|
}(file)
|
|
call = call.Media(file)
|
|
}
|
|
call = call.Part("id", "kind", "snippet")
|
|
|
|
res, err := call.Do()
|
|
if err != nil {
|
|
return errors.Join(errUpdatePlaylistImage, err)
|
|
}
|
|
|
|
common.PrintResult(
|
|
pi.Output, res, writer, "PlaylistImage updated: %s\n", res.Id,
|
|
)
|
|
return nil
|
|
}
|
|
|
|
func (pi *PlaylistImage) Delete(writer io.Writer) error {
|
|
if err := pi.EnsureService(); err != nil {
|
|
return err
|
|
}
|
|
for _, id := range pi.Ids {
|
|
call := pi.Service.PlaylistImages.Delete()
|
|
call = call.Id(id)
|
|
if pi.OnBehalfOfContentOwner != "" {
|
|
call = call.OnBehalfOfContentOwner(pi.OnBehalfOfContentOwner)
|
|
}
|
|
|
|
err := call.Do()
|
|
if err != nil {
|
|
return errors.Join(errDeletePlaylistImage, err)
|
|
}
|
|
_, _ = fmt.Fprintf(writer, "PlaylistImage %s deleted\n", id)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func WithHeight(height int64) Option {
|
|
return func(pi *PlaylistImage) {
|
|
pi.Height = height
|
|
}
|
|
}
|
|
|
|
func WithPlaylistId(playlistId string) Option {
|
|
return func(pi *PlaylistImage) {
|
|
pi.PlaylistId = playlistId
|
|
}
|
|
}
|
|
|
|
func WithType(t string) Option {
|
|
return func(pi *PlaylistImage) {
|
|
pi.Type = t
|
|
}
|
|
}
|
|
|
|
func WithWidth(width int64) Option {
|
|
return func(pi *PlaylistImage) {
|
|
pi.Width = width
|
|
}
|
|
}
|
|
|
|
func WithFile(file string) Option {
|
|
return func(pi *PlaylistImage) {
|
|
pi.File = file
|
|
}
|
|
}
|
|
|
|
func WithParent(parent string) Option {
|
|
return func(pi *PlaylistImage) {
|
|
pi.Parent = parent
|
|
}
|
|
}
|
|
|
|
func WithOnBehalfOfContentOwnerChannel(onBehalfOfContentOwnerChannel string) Option {
|
|
return func(pi *PlaylistImage) {
|
|
pi.OnBehalfOfContentOwnerChannel = onBehalfOfContentOwnerChannel
|
|
}
|
|
}
|
|
|
|
var (
|
|
WithParts = common.WithParts[*PlaylistImage]
|
|
WithOutput = common.WithOutput[*PlaylistImage]
|
|
WithService = common.WithService[*PlaylistImage]
|
|
WithIds = common.WithIds[*PlaylistImage]
|
|
WithMaxResults = common.WithMaxResults[*PlaylistImage]
|
|
|
|
WithOnBehalfOfContentOwner = common.WithOnBehalfOfContentOwner[*PlaylistImage]
|
|
)
|