♻️ Reuse struct in caption
This commit is contained in:
1 parent
6233f89c02
commit
faa0b233f1
7 files changed
+216
-331
No files matched your search
+10
-31
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user