♻️ Reuse struct in caption

This commit is contained in:
OpenWaygate committed 2026-01-24 23:16:27 +08:00
1 parent 6233f89c02
commit faa0b233f1
7 files changed
+216 -331

No files matched your search

+10 -31
View File
@@ -6,7 +6,6 @@ package caption
import (
"bytes"
"context"
"io"
"log/slog"
"time"
@@ -24,12 +23,6 @@ const (
deleteIdsUsage = "IDs of the captions to delete"
)
type deleteIn struct {
Ids []string `json:"ids"`
OnBehalfOf string `json:"onBehalfOf"`
OnBehalfOfContentOwner string `json:"onBehalfOfContentOwner"`
}
var deleteInSchema = &jsonschema.Schema{
Type: "object",
Required: []string{"ids"},
@@ -38,8 +31,8 @@ var deleteInSchema = &jsonschema.Schema{
Type: "array", Description: deleteIdsUsage,
Items: &jsonschema.Schema{Type: "string"},
},
"onBehalfOf": {Type: "string"},
"onBehalfOfContentOwner": {Type: "string"},
"on_behalf_of": {Type: "string"},
"on_behalf_of_content_owner": {Type: "string"},
},
}
@@ -71,12 +64,12 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Run: func(cmd *cobra.Command, args []string) {
input := &deleteIn{
Ids: ids,
OnBehalfOf: onBehalfOf,
OnBehalfOfContentOwner: onBehalfOfContentOwner,
}
if err := input.call(cmd.OutOrStdout()); err != nil {
input := caption.NewCation(
caption.WithIDs(ids),
caption.WithOnBehalfOf(onBehalfOf),
caption.WithOnBehalfOfContentOwner(onBehalfOfContentOwner),
)
if err := input.Delete(cmd.OutOrStdout()); err != nil {
_ = cmd.Help()
cmd.PrintErrf("Error: %v\n", err)
}
@@ -84,7 +77,7 @@ var deleteCmd = &cobra.Command{
}
func deleteHandler(
ctx context.Context, req *mcp.CallToolRequest, input deleteIn,
ctx context.Context, req *mcp.CallToolRequest, input caption.Caption,
) (*mcp.CallToolResult, any, error) {
logger := slog.New(
mcp.NewLoggingHandler(
@@ -96,23 +89,9 @@ func deleteHandler(
)
var writer bytes.Buffer
if err := input.call(&writer); err != nil {
if err := input.Delete(&writer); err != nil {
logger.ErrorContext(ctx, err.Error(), "input", input)
return nil, nil, err
}
return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: writer.String()}}}, nil, nil
}
func (d *deleteIn) call(writer io.Writer, opts ...caption.Option) error {
defaultOpts := []caption.Option{
caption.WithIDs(d.Ids),
caption.WithOnBehalfOf(d.OnBehalfOf),
caption.WithOnBehalfOfContentOwner(d.OnBehalfOfContentOwner),
caption.WithService(nil),
}
defaultOpts = append(defaultOpts, opts...)
c := caption.NewCation(defaultOpts...)
return c.Delete(writer)
}
+14 -41
View File
@@ -6,7 +6,6 @@ package caption
import (
"bytes"
"context"
"io"
"log/slog"
"time"
@@ -24,15 +23,6 @@ const (
downloadIdUsage = "ID of the caption to download"
)
type downloadIn struct {
Ids []string `json:"ids"`
File string `json:"file"`
Tfmt string `json:"tfmt"`
Tlang string `json:"tlang"`
OnBehalfOf string `json:"onBehalfOf"`
OnBehalfOfContentOwner string `json:"onBehalfOfContentOwner"`
}
var downloadInSchema = &jsonschema.Schema{
Type: "object",
Required: []string{"ids", "file"},
@@ -46,9 +36,9 @@ var downloadInSchema = &jsonschema.Schema{
Type: "string", Description: tfmtUsage,
Enum: []any{"sbv", "srt", "vtt", ""},
},
"tlang": {Type: "string", Description: tlangUsage},
"onBehalfOf": {Type: "string"},
"onBehalfOfContentOwner": {Type: "string"},
"tlang": {Type: "string", Description: tlangUsage},
"on_behalf_of": {Type: "string"},
"on_behalf_of_content_owner": {Type: "string"},
},
}
@@ -86,15 +76,15 @@ var downloadCmd = &cobra.Command{
Short: downloadShort,
Long: downloadLong,
Run: func(cmd *cobra.Command, args []string) {
input := &downloadIn{
Ids: ids,
File: file,
Tfmt: tfmt,
Tlang: tlang,
OnBehalfOf: onBehalfOf,
OnBehalfOfContentOwner: onBehalfOfContentOwner,
}
if err := input.call(cmd.OutOrStdout()); err != nil {
input := caption.NewCation(
caption.WithIDs(ids),
caption.WithFile(file),
caption.WithTfmt(tfmt),
caption.WithTlang(tlang),
caption.WithOnBehalfOf(onBehalfOf),
caption.WithOnBehalfOfContentOwner(onBehalfOfContentOwner),
)
if err := input.Download(cmd.OutOrStdout()); err != nil {
_ = cmd.Help()
cmd.PrintErrf("Error: %v\n", err)
}
@@ -102,7 +92,7 @@ var downloadCmd = &cobra.Command{
}
func downloadHandler(
ctx context.Context, req *mcp.CallToolRequest, input downloadIn,
ctx context.Context, req *mcp.CallToolRequest, input caption.Caption,
) (*mcp.CallToolResult, any, error) {
logger := slog.New(
mcp.NewLoggingHandler(
@@ -114,26 +104,9 @@ func downloadHandler(
)
var writer bytes.Buffer
if err := input.call(&writer); err != nil {
if err := input.Download(&writer); err != nil {
logger.ErrorContext(ctx, err.Error(), "input", input)
return nil, nil, err
}
return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: writer.String()}}}, nil, nil
}
func (d *downloadIn) call(writer io.Writer, opts ...caption.Option) error {
defaultOpts := []caption.Option{
caption.WithIDs(d.Ids),
caption.WithFile(d.File),
caption.WithTfmt(d.Tfmt),
caption.WithTlang(d.Tlang),
caption.WithOnBehalfOf(d.OnBehalfOf),
caption.WithOnBehalfOfContentOwner(d.OnBehalfOfContentOwner),
caption.WithService(nil),
}
defaultOpts = append(defaultOpts, opts...)
c := caption.NewCation(defaultOpts...)
return c.Download(writer)
}
+47 -73
View File
@@ -7,7 +7,6 @@ import (
"bytes"
"context"
"encoding/json"
"io"
"log/slog"
"time"
@@ -25,67 +24,49 @@ const (
insertLong = "Insert caption to a video"
)
type insertIn struct {
File string `json:"file"`
AudioTrackType string `json:"audioTrackType"`
IsAutoSynced *bool `json:"isAutoSynced,omitempty"`
IsCC *bool `json:"isCC,omitempty"`
IsDraft *bool `json:"isDraft,omitempty"`
IsEasyReader *bool `json:"isEasyReader,omitempty"`
IsLarge *bool `json:"isLarge,omitempty"`
Language string `json:"language"`
Name string `json:"name"`
TrackKind string `json:"trackKind"`
VideoId string `json:"videoId"`
OnBehalfOf string `json:"onBehalfOf"`
OnBehalfOfContentOwner string `json:"onBehalfOfContentOwner"`
Output string `json:"output"`
Jsonpath string `json:"jsonpath"`
}
var insertInSchema = &jsonschema.Schema{
Type: "object",
Required: []string{"file", "videoId"},
Properties: map[string]*jsonschema.Schema{
"file": {Type: "string", Description: fileUsage},
"audioTrackType": {
"audio_track_type": {
Type: "string", Description: attUsage,
Enum: []any{"unknown", "primary", "commentary", "descriptive"},
Default: json.RawMessage(`"unknown"`),
},
"isAutoSynced": {
"is_auto_synced": {
Type: "boolean", Description: iasUsage,
Enum: []any{true, false},
},
"isCC": {
"is_cc": {
Type: "boolean", Description: iscUsage,
Enum: []any{true, false},
},
"isDraft": {
"is_draft": {
Type: "boolean", Description: isdUsage,
Enum: []any{true, false},
},
"isEasyReader": {
"is_easy_reader": {
Type: "boolean", Description: iserUsage,
Enum: []any{true, false},
},
"isLarge": {
"is_large": {
Type: "boolean", Description: islUsage,
Enum: []any{true, false},
},
"language": {Type: "string", Description: languageUsage},
"name": {Type: "string", Description: nameUsage},
"trackKind": {
"track_kind": {
Type: "string", Description: tkUsage,
Enum: []any{"standard", "ASR", "forced"},
Default: json.RawMessage(`"standard"`),
},
"videoId": {
"video_id": {
Type: "string", Description: vidUsage,
Default: json.RawMessage(`""`),
},
"onBehalfOf": {Type: "string"},
"onBehalfOfContentOwner": {Type: "string"},
"on_behalf_of": {Type: "string"},
"on_behalf_of_content_owner": {Type: "string"},
"output": {
Type: "string", Description: pkg.SilentUsage,
Enum: []any{"json", "yaml", "silent", ""},
@@ -144,24 +125,41 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Run: func(cmd *cobra.Command, args []string) {
input := &insertIn{
File: file,
AudioTrackType: audioTrackType,
IsAutoSynced: isAutoSynced,
IsCC: isCC,
IsDraft: isDraft,
IsEasyReader: isEasyReader,
IsLarge: isLarge,
Language: language,
Name: name,
TrackKind: trackKind,
VideoId: videoId,
OnBehalfOf: onBehalfOf,
OnBehalfOfContentOwner: onBehalfOfContentOwner,
Output: output,
Jsonpath: jsonpath,
}
if err := input.call(cmd.OutOrStdout()); err != nil {
// input := &insertIn{
// File: file,
// AudioTrackType: audioTrackType,
// IsAutoSynced: isAutoSynced,
// IsCC: isCC,
// IsDraft: isDraft,
// IsEasyReader: isEasyReader,
// IsLarge: isLarge,
// Language: language,
// Name: name,
// TrackKind: trackKind,
// VideoId: videoId,
// OnBehalfOf: onBehalfOf,
// OnBehalfOfContentOwner: onBehalfOfContentOwner,
// Output: output,
// Jsonpath: jsonpath,
// }
input := caption.NewCation(
caption.WithFile(file),
caption.WithAudioTrackType(audioTrackType),
caption.WithIsAutoSynced(isAutoSynced),
caption.WithIsCC(isCC),
caption.WithIsDraft(isDraft),
caption.WithIsEasyReader(isEasyReader),
caption.WithIsLarge(isLarge),
caption.WithLanguage(language),
caption.WithName(name),
caption.WithTrackKind(trackKind),
caption.WithVideoId(videoId),
caption.WithOnBehalfOf(onBehalfOf),
caption.WithOnBehalfOfContentOwner(onBehalfOfContentOwner),
caption.WithOutput(output),
caption.WithJsonpath(jsonpath),
)
if err := input.Insert(cmd.OutOrStdout()); err != nil {
_ = cmd.Help()
cmd.PrintErrf("Error: %v\n", err)
}
@@ -169,7 +167,7 @@ var insertCmd = &cobra.Command{
}
func insertHandler(
ctx context.Context, req *mcp.CallToolRequest, input insertIn,
ctx context.Context, req *mcp.CallToolRequest, input caption.Caption,
) (*mcp.CallToolResult, any, error) {
logger := slog.New(
mcp.NewLoggingHandler(
@@ -181,33 +179,9 @@ func insertHandler(
)
var writer bytes.Buffer
if err := input.call(&writer); err != nil {
if err := input.Insert(&writer); err != nil {
logger.ErrorContext(ctx, err.Error(), "input", input)
return nil, nil, err
}
return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: writer.String()}}}, nil, nil
}
func (i *insertIn) call(writer io.Writer, opts ...caption.Option) error {
defaultOpts := []caption.Option{
caption.WithFile(i.File),
caption.WithAudioTrackType(i.AudioTrackType),
caption.WithIsAutoSynced(i.IsAutoSynced),
caption.WithIsCC(i.IsCC),
caption.WithIsDraft(i.IsDraft),
caption.WithIsEasyReader(i.IsEasyReader),
caption.WithIsLarge(i.IsLarge),
caption.WithLanguage(i.Language),
caption.WithName(i.Name),
caption.WithTrackKind(i.TrackKind),
caption.WithOnBehalfOf(i.OnBehalfOf),
caption.WithOnBehalfOfContentOwner(i.OnBehalfOfContentOwner),
caption.WithVideoId(i.VideoId),
caption.WithService(nil),
}
defaultOpts = append(defaultOpts, opts...)
c := caption.NewCation(defaultOpts...)
return c.Insert(i.Output, i.Jsonpath, writer)
}
+15 -41
View File
@@ -7,7 +7,6 @@ import (
"bytes"
"context"
"encoding/json"
"io"
"log/slog"
"time"
@@ -26,16 +25,6 @@ const (
listIdsUsage = "IDs of the captions to list"
)
type listIn struct {
Ids []string `json:"ids"`
VideoId string `json:"videoId"`
OnBehalfOf string `json:"onBehalfOf"`
OnBehalfOfContentOwner string `json:"onBehalfOfContentOwner"`
Parts []string `json:"parts"`
Output string `json:"output"`
Jsonpath string `json:"jsonpath"`
}
var listInSchema = &jsonschema.Schema{
Type: "object",
Required: []string{},
@@ -44,9 +33,9 @@ var listInSchema = &jsonschema.Schema{
Type: "array", Description: listIdsUsage,
Items: &jsonschema.Schema{Type: "string"},
},
"videoId": {Type: "string", Description: vidUsage},
"onBehalfOf": {Type: "string"},
"onBehalfOfContentOwner": {Type: "string"},
"video_id": {Type: "string", Description: vidUsage},
"on_behalf_of": {Type: "string"},
"on_behalf_of_content_owner": {Type: "string"},
"parts": {
Type: "array", Description: pkg.PartsUsage,
Items: &jsonschema.Schema{Type: "string"},
@@ -93,16 +82,16 @@ var listCmd = &cobra.Command{
Short: listShort,
Long: listLong,
Run: func(cmd *cobra.Command, args []string) {
input := &listIn{
Ids: ids,
VideoId: videoId,
OnBehalfOf: onBehalfOf,
OnBehalfOfContentOwner: onBehalfOfContentOwner,
Parts: parts,
Output: output,
Jsonpath: jsonpath,
}
if err := input.call(cmd.OutOrStdout()); err != nil {
input := caption.NewCation(
caption.WithIDs(ids),
caption.WithVideoId(videoId),
caption.WithOnBehalfOf(onBehalfOf),
caption.WithOnBehalfOfContentOwner(onBehalfOfContentOwner),
caption.WithParts(parts),
caption.WithOutput(output),
caption.WithJsonpath(jsonpath),
)
if err := input.List(cmd.OutOrStdout()); err != nil {
_ = cmd.Help()
cmd.PrintErrf("Error: %v\n", err)
}
@@ -110,7 +99,7 @@ var listCmd = &cobra.Command{
}
func listHandler(
ctx context.Context, req *mcp.CallToolRequest, input listIn,
ctx context.Context, req *mcp.CallToolRequest, input caption.Caption,
) (*mcp.CallToolResult, any, error) {
logger := slog.New(
mcp.NewLoggingHandler(
@@ -120,24 +109,9 @@ func listHandler(
)
var writer bytes.Buffer
if err := input.call(&writer); err != nil {
if err := input.List(&writer); err != nil {
logger.ErrorContext(ctx, err.Error(), "input", input)
return nil, nil, err
}
return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: writer.String()}}}, nil, nil
}
func (l *listIn) call(writer io.Writer, opts ...caption.Option) error {
defaultOpts := []caption.Option{
caption.WithIDs(l.Ids),
caption.WithVideoId(l.VideoId),
caption.WithOnBehalfOf(l.OnBehalfOf),
caption.WithOnBehalfOfContentOwner(l.OnBehalfOfContentOwner),
caption.WithService(nil),
}
defaultOpts = append(defaultOpts, opts...)
c := caption.NewCation(defaultOpts...)
return c.List(l.Parts, l.Output, l.Jsonpath, writer)
}
+30 -73
View File
@@ -7,7 +7,6 @@ import (
"bytes"
"context"
"encoding/json"
"io"
"log/slog"
"time"
@@ -25,63 +24,45 @@ const (
updateLong = "Update caption of a video"
)
type updateIn struct {
File string `json:"file"`
AudioTrackType string `json:"audioTrackType"`
IsAutoSynced *bool `json:"isAutoSynced,omitempty"`
IsCC *bool `json:"isCC,omitempty"`
IsDraft *bool `json:"isDraft,omitempty"`
IsEasyReader *bool `json:"isEasyReader,omitempty"`
IsLarge *bool `json:"isLarge,omitempty"`
Language string `json:"language"`
Name string `json:"name"`
TrackKind string `json:"trackKind"`
VideoId string `json:"videoId"`
OnBehalfOf string `json:"onBehalfOf"`
OnBehalfOfContentOwner string `json:"onBehalfOfContentOwner"`
Output string `json:"output"`
Jsonpath string `json:"jsonpath"`
}
var updateInSchema = &jsonschema.Schema{
Type: "object",
Required: []string{"videoId"},
Properties: map[string]*jsonschema.Schema{
"file": {Type: "string", Description: fileUsage},
"audioTrackType": {
"audio_track_type": {
Type: "string", Description: attUsage,
Default: json.RawMessage(`"unknown"`),
},
"isAutoSynced": {
"is_auto_synced": {
Type: "boolean", Description: iasUsage,
Enum: []any{true, false},
},
"isCC": {
"is_cc": {
Type: "boolean", Description: iscUsage,
Enum: []any{true, false},
},
"isDraft": {
"is_draft": {
Type: "boolean", Description: isdUsage,
Enum: []any{true, false},
},
"isEasyReader": {
"is_easy_reader": {
Type: "boolean", Description: iserUsage,
Enum: []any{true, false},
},
"isLarge": {
"is_large": {
Type: "boolean", Description: islUsage,
Enum: []any{true, false},
},
"language": {Type: "string", Description: languageUsage},
"name": {Type: "string", Description: nameUsage},
"trackKind": {
"track_kind": {
Type: "string", Description: tkUsage,
Enum: []any{"standard", "ASR", "forced"},
Default: json.RawMessage(`"standard"`),
},
"videoId": {Type: "string", Description: vidUsage},
"onBehalfOf": {Type: "string"},
"onBehalfOfContentOwner": {Type: "string"},
"video_id": {Type: "string", Description: vidUsage},
"on_behalf_of": {Type: "string"},
"on_behalf_of_content_owner": {Type: "string"},
"output": {
Type: "string", Description: pkg.SilentUsage,
Enum: []any{"json", "yaml", "silent", ""},
@@ -139,24 +120,24 @@ var updateCmd = &cobra.Command{
Short: updateShort,
Long: updateLong,
Run: func(cmd *cobra.Command, args []string) {
input := &updateIn{
File: file,
AudioTrackType: audioTrackType,
IsAutoSynced: isAutoSynced,
IsCC: isCC,
IsDraft: isDraft,
IsEasyReader: isEasyReader,
IsLarge: isLarge,
Language: language,
Name: name,
TrackKind: trackKind,
VideoId: videoId,
OnBehalfOf: onBehalfOf,
OnBehalfOfContentOwner: onBehalfOfContentOwner,
Output: output,
Jsonpath: jsonpath,
}
if err := input.call(cmd.OutOrStdout()); err != nil {
input := caption.NewCation(
caption.WithFile(file),
caption.WithAudioTrackType(audioTrackType),
caption.WithIsAutoSynced(isAutoSynced),
caption.WithIsCC(isCC),
caption.WithIsDraft(isDraft),
caption.WithIsEasyReader(isEasyReader),
caption.WithIsLarge(isLarge),
caption.WithLanguage(language),
caption.WithName(name),
caption.WithTrackKind(trackKind),
caption.WithVideoId(videoId),
caption.WithOnBehalfOf(onBehalfOf),
caption.WithOnBehalfOfContentOwner(onBehalfOfContentOwner),
caption.WithOutput(output),
caption.WithJsonpath(jsonpath),
)
if err := input.Update(cmd.OutOrStdout()); err != nil {
_ = cmd.Help()
cmd.PrintErrf("Error: %v\n", err)
}
@@ -164,7 +145,7 @@ var updateCmd = &cobra.Command{
}
func updateHandler(
ctx context.Context, req *mcp.CallToolRequest, input updateIn,
ctx context.Context, req *mcp.CallToolRequest, input caption.Caption,
) (*mcp.CallToolResult, any, error) {
logger := slog.New(
mcp.NewLoggingHandler(
@@ -176,33 +157,9 @@ func updateHandler(
)
var writer bytes.Buffer
if err := input.call(&writer); err != nil {
if err := input.Update(&writer); err != nil {
logger.ErrorContext(ctx, err.Error(), "input", input)
return nil, nil, err
}
return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: writer.String()}}}, nil, nil
}
func (u *updateIn) call(writer io.Writer, opts ...caption.Option) error {
defaultOpts := []caption.Option{
caption.WithFile(u.File),
caption.WithAudioTrackType(u.AudioTrackType),
caption.WithIsAutoSynced(u.IsAutoSynced),
caption.WithIsCC(u.IsCC),
caption.WithIsDraft(u.IsDraft),
caption.WithIsEasyReader(u.IsEasyReader),
caption.WithIsLarge(u.IsLarge),
caption.WithLanguage(u.Language),
caption.WithName(u.Name),
caption.WithTrackKind(u.TrackKind),
caption.WithOnBehalfOf(u.OnBehalfOf),
caption.WithOnBehalfOfContentOwner(u.OnBehalfOfContentOwner),
caption.WithVideoId(u.VideoId),
caption.WithService(nil),
}
defaultOpts = append(defaultOpts, opts...)
c := caption.NewCation(defaultOpts...)
return c.Update(u.Output, u.Jsonpath, writer)
}
+89 -63
View File
@@ -17,7 +17,6 @@ import (
)
var (
service *youtube.Service
errGetCaption = errors.New("failed to get caption")
errUpdateCaption = errors.New("failed to update caption")
errDeleteCaption = errors.New("failed to delete caption")
@@ -25,7 +24,8 @@ var (
errDownloadCaption = errors.New("failed to download caption")
)
type caption struct {
type Caption struct {
service *youtube.Service
IDs []string `yaml:"ids" json:"ids"`
File string `yaml:"file" json:"file"`
AudioTrackType string `yaml:"audio_track_type" json:"audio_track_type"`
@@ -42,29 +42,35 @@ type caption struct {
VideoId string `yaml:"video_id" json:"video_id"`
Tfmt string `yaml:"tfmt" json:"tfmt"`
Tlang string `yaml:"tlang" json:"tlang"`
Parts []string `yaml:"parts" json:"parts"`
Output string `yaml:"output" json:"output"`
Jsonpath string `yaml:"jsonpath" json:"jsonpath"`
}
type Caption[T youtube.Caption] interface {
Get([]string) ([]*T, error)
List([]string, string, string, io.Writer) error
Insert(string, string, io.Writer) error
Update(string, string, io.Writer) error
type ICaption[T youtube.Caption] interface {
Get() ([]*T, error)
List(io.Writer) error
Insert(io.Writer) error
Update(io.Writer) error
Delete(io.Writer) error
Download(io.Writer) error
preRun()
}
type Option func(*caption)
type Option func(*Caption)
func NewCation(opts ...Option) Caption[youtube.Caption] {
c := &caption{}
func NewCation(opts ...Option) ICaption[youtube.Caption] {
c := &Caption{}
for _, opt := range opts {
opt(c)
}
return c
}
func (c *caption) Get(parts []string) ([]*youtube.Caption, error) {
call := service.Captions.List(parts, c.VideoId)
func (c *Caption) Get() ([]*youtube.Caption, error) {
c.preRun()
call := c.service.Captions.List(c.Parts, c.VideoId)
if len(c.IDs) > 0 {
call = call.Id(c.IDs...)
}
@@ -83,19 +89,17 @@ func (c *caption) Get(parts []string) ([]*youtube.Caption, error) {
return res.Items, nil
}
func (c *caption) List(
parts []string, output string, jsonpath string, writer io.Writer,
) error {
captions, err := c.Get(parts)
func (c *Caption) List(writer io.Writer) error {
captions, err := c.Get()
if err != nil {
return err
}
switch output {
switch c.Output {
case "json":
utils.PrintJSON(captions, jsonpath, writer)
utils.PrintJSON(captions, c.Jsonpath, writer)
case "yaml":
utils.PrintYAML(captions, jsonpath, writer)
utils.PrintYAML(captions, c.Jsonpath, writer)
case "table":
tb := table.NewWriter()
tb.SetOutputMirror(writer)
@@ -114,9 +118,8 @@ func (c *caption) List(
return nil
}
func (c *caption) Insert(
output string, jsonpath string, writer io.Writer,
) error {
func (c *Caption) Insert(writer io.Writer) error {
c.preRun()
file, err := pkg.Root.Open(c.File)
if err != nil {
return errors.Join(errInsertCaption, err)
@@ -140,7 +143,7 @@ func (c *caption) Insert(
},
}
call := service.Captions.Insert([]string{"snippet"}, caption).Media(file)
call := c.service.Captions.Insert([]string{"snippet"}, caption).Media(file)
if c.OnBehalfOf != "" {
call = call.OnBehalfOf(c.OnBehalfOf)
}
@@ -153,11 +156,11 @@ func (c *caption) Insert(
return errors.Join(errInsertCaption, err)
}
switch output {
switch c.Output {
case "json":
utils.PrintJSON(res, jsonpath, writer)
utils.PrintJSON(res, c.Jsonpath, writer)
case "yaml":
utils.PrintYAML(res, jsonpath, writer)
utils.PrintYAML(res, c.Jsonpath, writer)
case "silent":
default:
_, _ = fmt.Fprintf(writer, "Caption inserted: %s\n", res.Id)
@@ -165,10 +168,10 @@ func (c *caption) Insert(
return nil
}
func (c *caption) Update(
output string, jsonpath string, writer io.Writer,
) error {
captions, err := c.Get([]string{"snippet"})
func (c *Caption) Update(writer io.Writer) error {
c.preRun()
c.Parts = []string{"snippet"}
captions, err := c.Get()
if err != nil {
return errors.Join(errUpdateCaption, err)
}
@@ -208,7 +211,7 @@ func (c *caption) Update(
caption.Snippet.VideoId = c.VideoId
}
call := service.Captions.Update([]string{"snippet"}, caption)
call := c.service.Captions.Update([]string{"snippet"}, caption)
if c.File != "" {
file, err := pkg.Root.Open(c.File)
if err != nil {
@@ -231,11 +234,11 @@ func (c *caption) Update(
return errors.Join(errUpdateCaption, err)
}
switch output {
switch c.Output {
case "json":
utils.PrintJSON(res, jsonpath, writer)
utils.PrintJSON(res, c.Jsonpath, writer)
case "yaml":
utils.PrintYAML(res, jsonpath, writer)
utils.PrintYAML(res, c.Jsonpath, writer)
case "silent":
default:
_, _ = fmt.Fprintf(writer, "Caption updated: %s\n", res.Id)
@@ -243,9 +246,10 @@ func (c *caption) Update(
return nil
}
func (c *caption) Delete(writer io.Writer) error {
func (c *Caption) Delete(writer io.Writer) error {
c.preRun()
for _, id := range c.IDs {
call := service.Captions.Delete(id)
call := c.service.Captions.Delete(id)
if c.OnBehalfOf != "" {
call = call.OnBehalfOf(c.OnBehalfOf)
}
@@ -263,8 +267,9 @@ func (c *caption) Delete(writer io.Writer) error {
return nil
}
func (c *caption) Download(writer io.Writer) error {
call := service.Captions.Download(c.IDs[0])
func (c *Caption) Download(writer io.Writer) error {
c.preRun()
call := c.service.Captions.Download(c.IDs[0])
if c.Tfmt != "" {
call = call.Tfmt(c.Tfmt)
}
@@ -308,26 +313,35 @@ func (c *caption) Download(writer io.Writer) error {
return nil
}
func (c *Caption) preRun() {
if c.service == nil {
c.service = auth.NewY2BService(
auth.WithCredential("", pkg.Root.FS()),
auth.WithCacheToken("", pkg.Root.FS()),
).GetService()
}
}
func WithIDs(ids []string) Option {
return func(c *caption) {
return func(c *Caption) {
c.IDs = ids
}
}
func WithFile(file string) Option {
return func(c *caption) {
return func(c *Caption) {
c.File = file
}
}
func WithAudioTrackType(audioTrackType string) Option {
return func(c *caption) {
return func(c *Caption) {
c.AudioTrackType = audioTrackType
}
}
func WithIsAutoSynced(isAutoSynced *bool) Option {
return func(c *caption) {
return func(c *Caption) {
if isAutoSynced != nil {
c.IsAutoSynced = isAutoSynced
}
@@ -335,7 +349,7 @@ func WithIsAutoSynced(isAutoSynced *bool) Option {
}
func WithIsCC(isCC *bool) Option {
return func(c *caption) {
return func(c *Caption) {
if isCC != nil {
c.IsCC = isCC
}
@@ -343,7 +357,7 @@ func WithIsCC(isCC *bool) Option {
}
func WithIsDraft(isDraft *bool) Option {
return func(c *caption) {
return func(c *Caption) {
if isDraft != nil {
c.IsDraft = isDraft
}
@@ -351,7 +365,7 @@ func WithIsDraft(isDraft *bool) Option {
}
func WithIsEasyReader(isEasyReader *bool) Option {
return func(c *caption) {
return func(c *Caption) {
if isEasyReader != nil {
c.IsEasyReader = isEasyReader
}
@@ -359,7 +373,7 @@ func WithIsEasyReader(isEasyReader *bool) Option {
}
func WithIsLarge(isLarge *bool) Option {
return func(c *caption) {
return func(c *Caption) {
if isLarge != nil {
c.IsLarge = isLarge
}
@@ -367,61 +381,73 @@ func WithIsLarge(isLarge *bool) Option {
}
func WithLanguage(language string) Option {
return func(c *caption) {
return func(c *Caption) {
c.Language = language
}
}
func WithName(name string) Option {
return func(c *caption) {
return func(c *Caption) {
c.Name = name
}
}
func WithTrackKind(trackKind string) Option {
return func(c *caption) {
return func(c *Caption) {
c.TrackKind = trackKind
}
}
func WithOnBehalfOf(onBehalfOf string) Option {
return func(c *caption) {
return func(c *Caption) {
c.OnBehalfOf = onBehalfOf
}
}
func WithOnBehalfOfContentOwner(onBehalfOfContentOwner string) Option {
return func(c *caption) {
return func(c *Caption) {
c.OnBehalfOfContentOwner = onBehalfOfContentOwner
}
}
func WithVideoId(videoId string) Option {
return func(c *caption) {
return func(c *Caption) {
c.VideoId = videoId
}
}
func WithTfmt(tfmt string) Option {
return func(c *caption) {
return func(c *Caption) {
c.Tfmt = tfmt
}
}
func WithTlang(tlang string) Option {
return func(c *caption) {
return func(c *Caption) {
c.Tlang = tlang
}
}
func WithService(svc *youtube.Service) Option {
return func(_ *caption) {
if svc == nil {
svc = auth.NewY2BService(
auth.WithCredential("", pkg.Root.FS()),
auth.WithCacheToken("", pkg.Root.FS()),
).GetService()
}
service = svc
func WithParts(parts []string) Option {
return func(c *Caption) {
c.Parts = parts
}
}
func WithOutput(output string) Option {
return func(c *Caption) {
c.Output = output
}
}
func WithJsonpath(jsonpath string) Option {
return func(c *Caption) {
c.Jsonpath = jsonpath
}
}
func WithService(svc *youtube.Service) Option {
return func(c *Caption) {
c.service = svc
}
}
+11 -9
View File
@@ -15,6 +15,7 @@ func TestNewCation(t *testing.T) {
opts []Option
}
svc := &youtube.Service{}
isAutoSyncedTrue := true
isAutoSyncedFalse := false
isCCTrue := true
@@ -29,7 +30,7 @@ func TestNewCation(t *testing.T) {
tests := []struct {
name string
args args
want Caption[youtube.Caption]
want ICaption[youtube.Caption]
}{
{
name: "with all options",
@@ -51,10 +52,11 @@ func TestNewCation(t *testing.T) {
WithVideoId("video123"),
WithTfmt("srt"),
WithTlang("es"),
WithService(&youtube.Service{}),
WithService(svc),
},
},
want: &caption{
want: &Caption{
service: svc,
IDs: []string{"caption1", "caption2"},
File: "/path/to/file.srt",
AudioTrackType: "primary",
@@ -78,7 +80,7 @@ func TestNewCation(t *testing.T) {
args: args{
opts: []Option{},
},
want: &caption{},
want: &Caption{},
},
{
name: "with nil boolean options",
@@ -91,7 +93,7 @@ func TestNewCation(t *testing.T) {
WithIsLarge(nil),
},
},
want: &caption{},
want: &Caption{},
},
{
name: "with false boolean options",
@@ -104,7 +106,7 @@ func TestNewCation(t *testing.T) {
WithIsLarge(&isLargeFalse),
},
},
want: &caption{
want: &Caption{
IsAutoSynced: &isAutoSyncedFalse,
IsCC: &isCCFalse,
IsDraft: &isDraftFalse,
@@ -128,7 +130,7 @@ func TestNewCation(t *testing.T) {
WithTlang(""),
},
},
want: &caption{
want: &Caption{
File: "",
AudioTrackType: "",
Language: "",
@@ -151,7 +153,7 @@ func TestNewCation(t *testing.T) {
WithIsCC(&isCCTrue),
},
},
want: &caption{
want: &Caption{
IDs: []string{"caption1"},
Language: "fr",
VideoId: "video456",
@@ -164,7 +166,7 @@ func TestNewCation(t *testing.T) {
t.Run(
tt.name, func(t *testing.T) {
if got := NewCation(tt.args.opts...); !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewCation() = %v, want %v", got, tt.want)
t.Errorf("%s\nNewCation() = %v\nwant %v", tt.name, got, tt.want)
}
},
)