🔒 Add confirmation gate to MCP destructive tools

* ♻️ Refactor IsInteractive to accept any

* ♻️ Simplify Confirm to return bool

* ♻️ Use simplified Confirm in mutation commands

* 🔧 Update MODULE.bazel for go tool

* ✨ Add ConfirmPreRun utility

* ♻️ Migrate mutation commands to ConfirmPreRun

* 🎨 Fix alignment and trailing newlines
This commit is contained in:
OpenWaygate committed 2026-08-20 21:55:27 +08:00
1 parent 15c01c9534
commit 8bf6457508
71 files changed
+783 -763

No files matched your search

+1
View File
@@ -24,6 +24,7 @@ use_repo(
"com_github_savioxavier_termlink",
"com_github_spf13_cobra",
"com_github_spf13_pflag",
"com_github_tc_hib_go_winres",
"in_gopkg_yaml_v3",
"org_golang_google_adk",
"org_golang_google_api",
+4 -2
View File
@@ -27,7 +27,6 @@ go_library(
"@com_github_eat_pray_ai_cobra_mcp//:cobra-mcp",
"@com_github_savioxavier_termlink//:termlink",
"@com_github_spf13_cobra//:cobra",
"@org_golang_x_term//:term",
],
)
@@ -35,5 +34,8 @@ go_test(
name = "cmd_test",
srcs = ["flags_test.go"],
embed = [":cmd"],
deps = ["@com_github_spf13_cobra//:cobra"],
deps = [
"//pkg/utils",
"@com_github_spf13_cobra//:cobra",
],
)
+11 -10
View File
@@ -5,6 +5,7 @@ package abuseReport
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -48,6 +49,7 @@ var insertInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -63,6 +65,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
insertTool, func(input abuseReport.AbuseReport, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -89,11 +94,10 @@ func init() {
&parts, "parts", "p", []string{"snippet"}, "Parts to include",
)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("abuseTypes")
_ = insertCmd.MarkFlagRequired("subjectId")
_ = insertCmd.MarkFlagRequired("subjectTypeId")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -101,15 +105,12 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would report abuse for %s %s", subjectTypeId, subjectId)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(
c, "Would report abuse for %s %s", subjectTypeId, subjectId,
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := abuseReport.NewAbuseReport(
abuseReport.WithAbuseTypes(abuseTypes),
abuseReport.WithDescription(description),
+6 -6
View File
@@ -9,13 +9,13 @@ import (
)
const (
short = "Manage activities on YouTube"
long = "Manage activities on YouTube. Use this tool to list channel activities."
ciUsage = "ID of the channel"
short = "Manage activities on YouTube"
long = "Manage activities on YouTube. Use this tool to list channel activities."
ciUsage = "ID of the channel"
forUsage = "home|mine"
paUsage = "Filter on activities published after this date"
pbUsage = "Filter on activities published before this date"
rcUsage = "Display the content as seen by viewers in this country"
paUsage = "Filter on activities published after this date"
pbUsage = "Filter on activities published before this date"
rcUsage = "Display the content as seen by viewers in this country"
)
var (
-2
View File
@@ -162,7 +162,6 @@ var agentDefs = map[string]agentDef{
},
}
func init() {
for _, def := range agentDefs {
if v, ok := os.LookupEnv(def.envKey); ok && v != "" {
@@ -171,7 +170,6 @@ func init() {
}
}
func buildOrchestrator(
advancedModel, liteModel model.LLM, mcpToolSet tool.Toolset,
) (
+11 -8
View File
@@ -4,6 +4,7 @@
package caption
import (
"fmt"
"io"
"strings"
@@ -38,6 +39,7 @@ var deleteInSchema = &jsonschema.Schema{
},
"on_behalf_of": {Type: "string", Description: pkg.OBOUsage},
"on_behalf_of_content_owner": {Type: "string", Description: pkg.OBOCOUsage},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -53,6 +55,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
deleteTool, func(input caption.Caption, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Delete(writer)
},
),
@@ -64,9 +69,8 @@ func init() {
deleteCmd.Flags().StringVarP(
&onBehalfOfContentOwner, "onBehalfOfContentOwner", "B", "", pkg.OBOCOUsage,
)
deleteCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = deleteCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(deleteCmd)
}
var deleteCmd = &cobra.Command{
@@ -74,12 +78,11 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Example: deleteExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(c, "Would delete caption(s): %s", strings.Join(ids, ", "))
if err != nil {
utils.HandleCmdError(err, c)
return
}
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would delete caption(s): %s", strings.Join(ids, ", "))
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := caption.NewCaption(
caption.WithIds(ids),
caption.WithOnBehalfOf(onBehalfOf),
-1
View File
@@ -78,7 +78,6 @@ func init() {
downloadCmd.Flags().StringVarP(
&onBehalfOfContentOwner, "onBehalfOfContentOwner", "B", "", pkg.OBOCOUsage,
)
_ = downloadCmd.MarkFlagRequired("id")
_ = downloadCmd.MarkFlagRequired("file")
}
+11 -8
View File
@@ -5,6 +5,7 @@ package caption
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -59,6 +60,7 @@ var insertInSchema = &jsonschema.Schema{
Enum: []any{"json", "yaml", "silent"},
Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -74,6 +76,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
insertTool, func(input caption.Caption, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -104,10 +109,9 @@ func init() {
&onBehalfOfContentOwner, "onBehalfOfContentOwner", "B", "", pkg.OBOCOUsage,
)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("file")
_ = insertCmd.MarkFlagRequired("videoId")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -115,13 +119,12 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would insert caption: %s", file)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would insert caption")
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := caption.NewCaption(
caption.WithFile(file),
caption.WithAudioTrackType(audioTrackType),
+11 -8
View File
@@ -5,6 +5,7 @@ package caption
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -58,6 +59,7 @@ var updateInSchema = &jsonschema.Schema{
Enum: []any{"json", "yaml", "silent"},
Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -73,6 +75,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
updateTool, func(input caption.Caption, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Update(writer)
},
),
@@ -103,9 +108,8 @@ func init() {
&onBehalfOfContentOwner, "onBehalfOfContentOwner", "B", "", pkg.OBOCOUsage,
)
updateCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
updateCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = updateCmd.MarkFlagRequired("videoId")
cmd.AddMutationFlags(updateCmd)
}
var updateCmd = &cobra.Command{
@@ -113,13 +117,12 @@ var updateCmd = &cobra.Command{
Short: updateShort,
Long: updateLong,
Example: updateExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would update caption for video: %s", videoId)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would update caption for video: %s", videoId)
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := caption.NewCaption(
caption.WithFile(file),
caption.WithAudioTrackType(audioTrackType),
-1
View File
@@ -53,4 +53,3 @@ var channelCmd = &cobra.Command{
func init() {
cmd.RootCmd.AddCommand(channelCmd)
}
+11 -8
View File
@@ -5,6 +5,7 @@ package channel
import (
"encoding/json"
"fmt"
"io"
"strings"
@@ -48,6 +49,7 @@ var updateInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -63,6 +65,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
updateTool, func(input channel.Channel, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Update(writer)
},
),
@@ -80,9 +85,8 @@ func init() {
)
updateCmd.Flags().StringVarP(&title, "title", "t", "", titleUsage)
updateCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
updateCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = updateCmd.MarkFlagRequired("id")
cmd.AddMutationFlags(updateCmd)
}
var updateCmd = &cobra.Command{
@@ -90,13 +94,12 @@ var updateCmd = &cobra.Command{
Short: updateShort,
Long: updateLong,
Example: updateExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would update channel: %s", strings.Join(ids, ", "))
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would update channel: %s", strings.Join(ids, ", "))
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := channel.NewChannel(
channel.WithIds(ids),
channel.WithCountry(country),
+11 -8
View File
@@ -5,6 +5,7 @@ package channelBanner
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -46,6 +47,7 @@ var insertInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -62,6 +64,9 @@ func init() {
}, cobramcp.GenToolHandler(
insertTool,
func(input channelBanner.ChannelBanner, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -78,10 +83,9 @@ func init() {
pkg.OBOCOCUsage,
)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("channelId")
_ = insertCmd.MarkFlagRequired("file")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -89,13 +93,12 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would insert channel banner: %s", file)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would insert channel banner")
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := channelBanner.NewChannelBanner(
channelBanner.WithChannelId(channelId),
channelBanner.WithFile(file),
+12 -9
View File
@@ -4,6 +4,7 @@
package channelSection
import (
"fmt"
"io"
"strings"
@@ -37,6 +38,7 @@ var deleteInSchema = &jsonschema.Schema{
Items: &jsonschema.Schema{Type: "string"},
},
"on_behalf_of_content_owner": {Type: "string", Description: pkg.OBOCOUsage},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -53,6 +55,9 @@ func init() {
}, cobramcp.GenToolHandler(
deleteTool,
func(input channelSection.ChannelSection, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Delete(writer)
},
),
@@ -63,9 +68,8 @@ func init() {
deleteCmd.Flags().StringVarP(
&onBehalfOfContentOwner, "onBehalfOfContentOwner", "b", "", pkg.OBOCOUsage,
)
deleteCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = deleteCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(deleteCmd)
}
var deleteCmd = &cobra.Command{
@@ -73,14 +77,13 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Example: deleteExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(
c, "Would delete channel section(s): %s", strings.Join(ids, ", "),
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would delete channel section(s): %s", strings.Join(ids, ", "),
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := channelSection.NewChannelSection(
channelSection.WithIds(ids),
channelSection.WithOnBehalfOfContentOwner(onBehalfOfContentOwner),
+12 -7
View File
@@ -4,11 +4,13 @@
package comment
import (
"fmt"
"io"
"strings"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
"github.com/eat-pray-ai/yutu/cmd"
"github.com/eat-pray-ai/yutu/pkg"
"github.com/eat-pray-ai/yutu/pkg/comment"
"github.com/eat-pray-ai/yutu/pkg/utils"
"github.com/google/jsonschema-go/jsonschema"
@@ -34,6 +36,7 @@ var deleteInSchema = &jsonschema.Schema{
Type: "array", Description: idsUsage,
Items: &jsonschema.Schema{Type: "string"},
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -49,6 +52,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
deleteTool, func(input comment.Comment, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Delete(writer)
},
),
@@ -56,8 +62,8 @@ func init() {
commentCmd.AddCommand(deleteCmd)
deleteCmd.Flags().StringSliceVarP(&ids, "ids", "i", []string{}, idsUsage)
deleteCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = deleteCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(deleteCmd)
}
var deleteCmd = &cobra.Command{
@@ -65,12 +71,11 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Example: deleteExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(c, "Would delete comment(s): %s", strings.Join(ids, ", "))
if err != nil {
utils.HandleCmdError(err, c)
return
}
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would delete comment(s): %s", strings.Join(ids, ", "))
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := comment.NewComment(comment.WithIds(ids))
utils.HandleCmdError(input.Delete(c.OutOrStdout()), c)
},
+11 -8
View File
@@ -5,6 +5,7 @@ package comment
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -44,6 +45,7 @@ var insertInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -59,6 +61,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
insertTool, func(input comment.Comment, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -80,10 +85,9 @@ func init() {
)
insertCmd.Flags().StringVarP(&videoId, "videoId", "v", "", vidUsage)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("parentId")
_ = insertCmd.MarkFlagRequired("textOriginal")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -91,13 +95,12 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would insert comment on parent: %s", parentId)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would insert comment")
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := comment.NewComment(
comment.WithAuthorChannelId(authorChannelId),
comment.WithChannelId(channelId),
+13 -8
View File
@@ -5,6 +5,7 @@ package comment
import (
"encoding/json"
"fmt"
"io"
"strings"
@@ -40,6 +41,7 @@ var markAsSpamInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -55,6 +57,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
masTool, func(input comment.Comment, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.MarkAsSpam(writer)
},
),
@@ -63,9 +68,8 @@ func init() {
markAsSpamCmd.Flags().StringSliceVarP(&ids, "ids", "i", []string{}, idsUsage)
markAsSpamCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
markAsSpamCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = markAsSpamCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(markAsSpamCmd)
}
var markAsSpamCmd = &cobra.Command{
@@ -73,13 +77,14 @@ var markAsSpamCmd = &cobra.Command{
Short: masShort,
Long: masLong,
Example: masExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would mark comment(s) as spam: %s", strings.Join(ids, ", "),
)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would mark comment(s) as spam: %s", strings.Join(ids, ", "))
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := comment.NewComment(
comment.WithIds(ids),
comment.WithOutput(output),
+14 -8
View File
@@ -5,6 +5,7 @@ package comment
import (
"encoding/json"
"fmt"
"io"
"strings"
@@ -47,6 +48,7 @@ var setModerationStatusInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -63,6 +65,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
smsTool, func(input comment.Comment, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.SetModerationStatus(writer)
},
),
@@ -79,10 +84,9 @@ func init() {
banAuthor, "banAuthor", "A", false, baUsage,
)
setModerationStatusCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
setModerationStatusCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = setModerationStatusCmd.MarkFlagRequired("ids")
_ = setModerationStatusCmd.MarkFlagRequired("moderationStatus")
cmd.AddMutationFlags(setModerationStatusCmd)
}
var setModerationStatusCmd = &cobra.Command{
@@ -90,13 +94,15 @@ var setModerationStatusCmd = &cobra.Command{
Short: smsShort,
Long: smsLong,
Example: smsExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would set moderation status of comment(s): %s to %s",
strings.Join(ids, ", "), moderationStatus,
)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would set moderation status of comment(s): %s to %s", strings.Join(ids, ", "), moderationStatus)
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := comment.NewComment(
comment.WithIds(ids),
comment.WithModerationStatus(moderationStatus),
+11 -8
View File
@@ -5,6 +5,7 @@ package comment
import (
"encoding/json"
"fmt"
"io"
"strings"
@@ -49,6 +50,7 @@ var updateInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -64,6 +66,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
updateTool, func(input comment.Comment, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Update(writer)
},
),
@@ -79,9 +84,8 @@ func init() {
&viewerRating, "viewerRating", "r", "", vrUsage,
)
updateCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
updateCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = updateCmd.MarkFlagRequired("id")
cmd.AddMutationFlags(updateCmd)
}
var updateCmd = &cobra.Command{
@@ -89,13 +93,12 @@ var updateCmd = &cobra.Command{
Short: updateShort,
Long: updateLong,
Example: updateExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would update comment: %s", strings.Join(ids, ", "))
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would update comment: %s", strings.Join(ids, ", "))
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := comment.NewComment(
comment.WithIds(ids),
comment.WithCanRate(canRate),
+11 -8
View File
@@ -5,6 +5,7 @@ package commentThread
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -42,6 +43,7 @@ var insertInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -58,6 +60,9 @@ func init() {
}, cobramcp.GenToolHandler(
insertTool,
func(input commentThread.CommentThread, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -70,11 +75,10 @@ func init() {
insertCmd.Flags().StringVarP(&textOriginal, "textOriginal", "t", "", toUsage)
insertCmd.Flags().StringVarP(&videoId, "videoId", "v", "", insertVidUsage)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("channelId")
_ = insertCmd.MarkFlagRequired("textOriginal")
_ = insertCmd.MarkFlagRequired("videoId")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -82,13 +86,12 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would insert comment thread on video: %s", videoId)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would insert comment thread")
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := commentThread.NewCommentThread(
commentThread.WithAuthorChannelId(authorChannelId),
commentThread.WithChannelId(channelId),
-88
View File
@@ -1,88 +0,0 @@
// Copyright 2026 eat-pray-ai & OpenWaygate
// SPDX-License-Identifier: Apache-2.0
package cmd
import (
"bufio"
"errors"
"fmt"
"os"
"strings"
"github.com/eat-pray-ai/yutu/pkg/utils"
"github.com/spf13/cobra"
"golang.org/x/term"
)
// ErrDryRun is returned by Confirm when --dry-run is set.
var ErrDryRun = utils.ErrDryRun
// errAborted is returned by Confirm when the user declines the prompt.
var errAborted = errors.New("aborted")
// AddMutationFlags registers --dry-run and --yes on the given command.
func AddMutationFlags(cmd *cobra.Command) {
cmd.Flags().Bool(
"dry-run", false,
"Print what would happen without calling the API",
)
cmd.Flags().Bool(
"yes", false,
"Skip the confirmation prompt",
)
}
// DryRun returns whether --dry-run was passed.
func DryRun(cmd *cobra.Command) bool {
v, _ := cmd.Flags().GetBool("dry-run")
return v
}
// Confirm checks dry-run and yes flags, then prompts the user for
// confirmation if running in an interactive terminal.
//
// Returns ErrDryRun if --dry-run is set, nil if --yes is set or the user
// confirms, and errAborted if the user declines.
func Confirm(cmd *cobra.Command, format string, args ...any) error {
isTTY := term.IsTerminal(int(os.Stdin.Fd()))
return confirmWithTTYOverride(cmd, isTTY, format, args...)
}
// confirmWithTTYOverride is an internal helper that accepts a pre-computed
// isTTY value so tests can exercise the TTY and non-TTY paths without
// needing a real terminal.
func confirmWithTTYOverride(cmd *cobra.Command, isTTY bool, format string, args ...any) error {
msg := fmt.Sprintf(format, args...)
// 1. --dry-run takes precedence over everything.
if DryRun(cmd) {
_, _ = fmt.Fprintln(cmd.OutOrStdout(), msg)
return ErrDryRun
}
// 2. --yes skips the prompt entirely.
yes, _ := cmd.Flags().GetBool("yes")
if yes {
return nil
}
// 3. Non-interactive stdin requires --yes.
if !isTTY {
return errors.New("terminal required for confirmation; use --yes to skip")
}
// 4. Interactive prompt.
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "%s [y/N] ", msg)
scanner := bufio.NewScanner(cmd.InOrStdin())
if !scanner.Scan() {
return errAborted
}
answer := strings.TrimSpace(scanner.Text())
if answer == "y" || answer == "Y" {
return nil
}
return errAborted
}
-171
View File
@@ -1,171 +0,0 @@
// Copyright 2026 eat-pray-ai & OpenWaygate
// SPDX-License-Identifier: Apache-2.0
package cmd
import (
"bytes"
"errors"
"strings"
"testing"
"github.com/spf13/cobra"
)
// newTestCmd creates a minimal cobra.Command with mutation flags registered.
func newTestCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "test",
Run: func(cmd *cobra.Command, args []string) {},
}
AddMutationFlags(cmd)
return cmd
}
func TestAddMutationFlags(t *testing.T) {
cmd := newTestCmd()
dr := cmd.Flags().Lookup("dry-run")
if dr == nil {
t.Fatal("expected --dry-run flag to be registered")
} else if dr.DefValue != "false" {
t.Fatalf("expected --dry-run default to be false, got %s", dr.DefValue)
}
yes := cmd.Flags().Lookup("yes")
if yes == nil {
t.Fatal("expected --yes flag to be registered")
} else if yes.DefValue != "false" {
t.Fatalf("expected --yes default to be false, got %s", yes.DefValue)
}
}
func TestDryRun_DefaultFalse(t *testing.T) {
cmd := newTestCmd()
if DryRun(cmd) {
t.Fatal("expected DryRun to be false by default")
}
}
func TestDryRun_SetTrue(t *testing.T) {
cmd := newTestCmd()
if err := cmd.Flags().Set("dry-run", "true"); err != nil {
t.Fatal(err)
}
if !DryRun(cmd) {
t.Fatal("expected DryRun to be true after setting flag")
}
}
func TestConfirm_DryRun(t *testing.T) {
cmd := newTestCmd()
if err := cmd.Flags().Set("dry-run", "true"); err != nil {
t.Fatal(err)
}
var stdout bytes.Buffer
cmd.SetOut(&stdout)
err := Confirm(cmd, "would delete %s", "video123")
if !errors.Is(err, ErrDryRun) {
t.Fatalf("expected ErrDryRun, got %v", err)
}
got := stdout.String()
if !strings.Contains(got, "would delete video123") {
t.Fatalf("expected message in stdout, got %q", got)
}
}
func TestConfirm_Yes(t *testing.T) {
cmd := newTestCmd()
if err := cmd.Flags().Set("yes", "true"); err != nil {
t.Fatal(err)
}
err := Confirm(cmd, "delete video?")
if err != nil {
t.Fatalf("expected nil, got %v", err)
}
}
func TestConfirm_NonTTY(t *testing.T) {
cmd := newTestCmd()
cmd.SetIn(strings.NewReader(""))
// Use the internal helper with isTTY=false to simulate non-TTY stdin.
err := confirmWithTTYOverride(cmd, false, "delete video?")
if err == nil {
t.Fatal("expected error for non-TTY stdin")
}
if !strings.Contains(
err.Error(), "terminal required for confirmation; use --yes to skip",
) {
t.Fatalf("unexpected error message: %v", err)
}
}
func TestConfirm_TTY_Yes(t *testing.T) {
cmd := newTestCmd()
cmd.SetIn(strings.NewReader("y\n"))
var stderr bytes.Buffer
cmd.SetErr(&stderr)
err := confirmWithTTYOverride(cmd, true, "delete %s?", "video123")
if err != nil {
t.Fatalf("expected nil, got %v", err)
}
prompt := stderr.String()
if !strings.Contains(prompt, "delete video123?") {
t.Fatalf("expected prompt on stderr, got %q", prompt)
}
if !strings.Contains(prompt, "[y/N]") {
t.Fatalf("expected [y/N] in prompt, got %q", prompt)
}
}
func TestConfirm_TTY_No(t *testing.T) {
cmd := newTestCmd()
cmd.SetIn(strings.NewReader("n\n"))
var stderr bytes.Buffer
cmd.SetErr(&stderr)
err := confirmWithTTYOverride(cmd, true, "delete video?")
if !errors.Is(err, errAborted) {
t.Fatalf("expected errAborted, got %v", err)
}
}
func TestConfirm_TTY_Default(t *testing.T) {
cmd := newTestCmd()
cmd.SetIn(strings.NewReader("\n"))
var stderr bytes.Buffer
cmd.SetErr(&stderr)
err := confirmWithTTYOverride(cmd, true, "delete video?")
if !errors.Is(err, errAborted) {
t.Fatalf("expected errAborted for empty input (default N), got %v", err)
}
}
func TestConfirm_DryRunTakesPrecedence(t *testing.T) {
cmd := newTestCmd()
if err := cmd.Flags().Set("dry-run", "true"); err != nil {
t.Fatal(err)
}
if err := cmd.Flags().Set("yes", "true"); err != nil {
t.Fatal(err)
}
var stdout bytes.Buffer
cmd.SetOut(&stdout)
err := Confirm(cmd, "would delete video")
if !errors.Is(err, ErrDryRun) {
t.Fatalf("expected ErrDryRun even with --yes, got %v", err)
}
}
+13 -10
View File
@@ -5,6 +5,7 @@ package liveBroadcast
import (
"encoding/json"
"fmt"
"io"
"strings"
@@ -50,6 +51,7 @@ var bindInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -65,6 +67,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
bindTool, func(input liveBroadcast.LiveBroadcast, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Bind(writer)
},
),
@@ -87,9 +92,8 @@ func init() {
pkg.PartsUsage,
)
bindCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
bindCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = bindCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(bindCmd)
}
var bindCmd = &cobra.Command{
@@ -97,16 +101,15 @@ var bindCmd = &cobra.Command{
Short: bindShort,
Long: bindLong,
Example: bindExample,
Run: func(c *cobra.Command, args []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(
c, "Would bind live broadcast(s) %s to stream %s",
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would bind live broadcast(s) %s to stream %s",
strings.Join(ids, ", "), streamId,
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
input := liveBroadcast.NewLiveBroadcast(
liveBroadcast.WithIds(ids),
liveBroadcast.WithStreamId(streamId),
+12 -8
View File
@@ -4,6 +4,7 @@
package liveBroadcast
import (
"fmt"
"io"
"strings"
@@ -40,6 +41,7 @@ var deleteInSchema = &jsonschema.Schema{
"on_behalf_of_content_owner_channel": {
Type: "string", Description: obococUsage,
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -56,6 +58,9 @@ func init() {
}, cobramcp.GenToolHandler(
deleteTool,
func(input liveBroadcast.LiveBroadcast, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Delete(writer)
},
),
@@ -70,8 +75,8 @@ func init() {
&onBehalfOfContentOwnerChannel, "onBehalfOfContentOwnerChannel", "B", "",
obococUsage,
)
deleteCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = deleteCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(deleteCmd)
}
var deleteCmd = &cobra.Command{
@@ -79,14 +84,13 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Example: deleteExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(
c, "Would delete live broadcast(s): %s", strings.Join(ids, ", "),
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would delete live broadcast(s): %s", strings.Join(ids, ", "),
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := liveBroadcast.NewLiveBroadcast(
liveBroadcast.WithIds(ids),
liveBroadcast.WithOnBehalfOfContentOwner(onBehalfOfContentOwner),
+11 -8
View File
@@ -5,6 +5,7 @@ package liveBroadcast
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -52,6 +53,7 @@ var insertInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -68,6 +70,9 @@ func init() {
}, cobramcp.GenToolHandler(
insertTool,
func(input liveBroadcast.LiveBroadcast, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -95,10 +100,9 @@ func init() {
pkg.PartsUsage,
)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("title")
_ = insertCmd.MarkFlagRequired("scheduledStartTime")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -106,13 +110,12 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would create live broadcast: %s", title)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would create live broadcast: %s", title)
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := liveBroadcast.NewLiveBroadcast(
liveBroadcast.WithTitle(title),
liveBroadcast.WithDescription(description),
+13 -10
View File
@@ -5,6 +5,7 @@ package liveBroadcast
import (
"encoding/json"
"fmt"
"io"
"strings"
@@ -51,6 +52,7 @@ var insertCuepointInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -67,6 +69,9 @@ func init() {
}, cobramcp.GenToolHandler(
insertCuepointTool,
func(input liveBroadcast.LiveBroadcast, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.InsertCuepoint(writer)
},
),
@@ -96,9 +101,8 @@ func init() {
obococUsage,
)
insertCuepointCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCuepointCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCuepointCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(insertCuepointCmd)
}
var insertCuepointCmd = &cobra.Command{
@@ -106,16 +110,15 @@ var insertCuepointCmd = &cobra.Command{
Short: insertCuepointShort,
Long: insertCuepointLong,
Example: insertCuepointExample,
Run: func(c *cobra.Command, args []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(
c, "Would insert cuepoint into live broadcast(s): %s",
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would insert cuepoint into live broadcast(s): %s",
strings.Join(ids, ", "),
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
input := liveBroadcast.NewLiveBroadcast(
liveBroadcast.WithIds(ids),
liveBroadcast.WithCueType(cueType),
+13 -10
View File
@@ -5,6 +5,7 @@ package liveBroadcast
import (
"encoding/json"
"fmt"
"io"
"strings"
@@ -54,6 +55,7 @@ var transitionInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -70,6 +72,9 @@ func init() {
}, cobramcp.GenToolHandler(
transitionTool,
func(input liveBroadcast.LiveBroadcast, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Transition(writer)
},
),
@@ -93,10 +98,9 @@ func init() {
&parts, "parts", "p", []string{"id", "snippet", "status"}, pkg.PartsUsage,
)
transitionCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
transitionCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = transitionCmd.MarkFlagRequired("ids")
_ = transitionCmd.MarkFlagRequired("broadcastStatus")
cmd.AddMutationFlags(transitionCmd)
}
var transitionCmd = &cobra.Command{
@@ -104,16 +108,15 @@ var transitionCmd = &cobra.Command{
Short: transitionShort,
Long: transitionLong,
Example: transitionExample,
Run: func(c *cobra.Command, args []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(
c, "Would transition live broadcast(s) %s to %s",
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would transition live broadcast(s) %s to %s",
strings.Join(ids, ", "), broadcastStatus,
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
input := liveBroadcast.NewLiveBroadcast(
liveBroadcast.WithIds(ids),
liveBroadcast.WithBroadcastStatus(broadcastStatus),
+13 -10
View File
@@ -5,6 +5,7 @@ package liveBroadcast
import (
"encoding/json"
"fmt"
"io"
"strings"
@@ -53,6 +54,7 @@ var updateInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -69,6 +71,9 @@ func init() {
}, cobramcp.GenToolHandler(
updateTool,
func(input liveBroadcast.LiveBroadcast, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
input.MaxResults = 1
return input.Update(writer)
},
@@ -94,9 +99,8 @@ func init() {
obococUsage,
)
updateCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
updateCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = updateCmd.MarkFlagRequired("id")
cmd.AddMutationFlags(updateCmd)
}
var updateCmd = &cobra.Command{
@@ -104,15 +108,14 @@ var updateCmd = &cobra.Command{
Short: updateShort,
Long: updateLong,
Example: updateExample,
Run: func(c *cobra.Command, args []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(
c, "Would update live broadcast: %s", strings.Join(ids, ", "),
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would update live broadcast: %s", strings.Join(ids, ", "),
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
input := liveBroadcast.NewLiveBroadcast(
liveBroadcast.WithIds(ids),
liveBroadcast.WithTitle(title),
+13 -8
View File
@@ -4,11 +4,13 @@
package liveChatBan
import (
"fmt"
"io"
"strings"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
"github.com/eat-pray-ai/yutu/cmd"
"github.com/eat-pray-ai/yutu/pkg"
"github.com/eat-pray-ai/yutu/pkg/liveChatBan"
"github.com/eat-pray-ai/yutu/pkg/utils"
"github.com/google/jsonschema-go/jsonschema"
@@ -35,6 +37,7 @@ var deleteInSchema = &jsonschema.Schema{
Type: "array", Description: deleteIdsUsage,
Items: &jsonschema.Schema{Type: "string"},
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -50,6 +53,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
deleteTool, func(input liveChatBan.LiveChatBan, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Delete(writer)
},
),
@@ -57,8 +63,8 @@ func init() {
liveChatBanCmd.AddCommand(deleteCmd)
deleteCmd.Flags().StringSliceVarP(&ids, "ids", "i", []string{}, deleteIdsUsage)
deleteCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = deleteCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(deleteCmd)
}
var deleteCmd = &cobra.Command{
@@ -66,14 +72,13 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Example: deleteExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(
c, "Would delete live chat ban(s): %s", strings.Join(ids, ", "),
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would delete live chat ban(s): %s", strings.Join(ids, ", "),
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := liveChatBan.NewLiveChatBan(
liveChatBan.WithIds(ids),
)
+13 -10
View File
@@ -5,6 +5,7 @@ package liveChatBan
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -43,6 +44,7 @@ var insertInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -58,6 +60,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
insertTool, func(input liveChatBan.LiveChatBan, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -76,11 +81,10 @@ func init() {
&parts, "parts", "p", []string{"snippet"}, "Parts to include",
)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("liveChatId")
_ = insertCmd.MarkFlagRequired("bannedUserChannelId")
_ = insertCmd.MarkFlagRequired("banType")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -88,15 +92,14 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(
c, "Would ban user %s in live chat %s", bannedUserChannelId, liveChatId,
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would ban user %s in live chat %s", bannedUserChannelId, liveChatId,
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
input := liveChatBan.NewLiveChatBan(
liveChatBan.WithLiveChatId(liveChatId),
liveChatBan.WithBannedUserChannelId(bannedUserChannelId),
+13 -8
View File
@@ -4,11 +4,13 @@
package liveChatMessage
import (
"fmt"
"io"
"strings"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
"github.com/eat-pray-ai/yutu/cmd"
"github.com/eat-pray-ai/yutu/pkg"
"github.com/eat-pray-ai/yutu/pkg/liveChatMessage"
"github.com/eat-pray-ai/yutu/pkg/utils"
"github.com/google/jsonschema-go/jsonschema"
@@ -35,6 +37,7 @@ var deleteInSchema = &jsonschema.Schema{
Type: "array", Description: deleteIdsUsage,
Items: &jsonschema.Schema{Type: "string"},
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -51,6 +54,9 @@ func init() {
}, cobramcp.GenToolHandler(
deleteTool,
func(input liveChatMessage.LiveChatMessage, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Delete(writer)
},
),
@@ -58,8 +64,8 @@ func init() {
liveChatMessageCmd.AddCommand(deleteCmd)
deleteCmd.Flags().StringSliceVarP(&ids, "ids", "i", []string{}, deleteIdsUsage)
deleteCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = deleteCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(deleteCmd)
}
var deleteCmd = &cobra.Command{
@@ -67,14 +73,13 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Example: deleteExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(
c, "Would delete live chat message(s): %s", strings.Join(ids, ", "),
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would delete live chat message(s): %s", strings.Join(ids, ", "),
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := liveChatMessage.NewLiveChatMessage(
liveChatMessage.WithIds(ids),
)
+11 -10
View File
@@ -5,6 +5,7 @@ package liveChatMessage
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -39,6 +40,7 @@ var insertInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -55,6 +57,9 @@ func init() {
}, cobramcp.GenToolHandler(
insertTool,
func(input liveChatMessage.LiveChatMessage, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -67,10 +72,9 @@ func init() {
&parts, "parts", "p", []string{"snippet"}, "Parts to include",
)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("liveChatId")
_ = insertCmd.MarkFlagRequired("messageText")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -78,15 +82,12 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would send message to live chat %s", liveChatId)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(
c, "Would send message to live chat %s", liveChatId,
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := liveChatMessage.NewLiveChatMessage(
liveChatMessage.WithLiveChatId(liveChatId),
liveChatMessage.WithMessageText(messageText),
-1
View File
@@ -78,7 +78,6 @@ func init() {
&parts, "parts", "p", []string{"snippet", "authorDetails"}, pkg.PartsUsage,
)
listCmd.Flags().StringP("output", "o", "table", pkg.TableUsage)
_ = listCmd.MarkFlagRequired("liveChatId")
}
+13 -10
View File
@@ -5,6 +5,7 @@ package liveChatMessage
import (
"encoding/json"
"fmt"
"io"
"strings"
@@ -42,6 +43,7 @@ var transitionInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -58,6 +60,9 @@ func init() {
}, cobramcp.GenToolHandler(
transitionTool,
func(input liveChatMessage.LiveChatMessage, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Transition(writer)
},
),
@@ -69,10 +74,9 @@ func init() {
)
transitionCmd.Flags().StringVarP(&status, "status", "s", "", statusUsage)
transitionCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
transitionCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = transitionCmd.MarkFlagRequired("ids")
_ = transitionCmd.MarkFlagRequired("status")
cmd.AddMutationFlags(transitionCmd)
}
var transitionCmd = &cobra.Command{
@@ -80,16 +84,15 @@ var transitionCmd = &cobra.Command{
Short: transitionShort,
Long: transitionLong,
Example: transitionExample,
Run: func(c *cobra.Command, args []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(
c, "Would transition live chat message(s) %s to status %s",
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would transition live chat message(s) %s to status %s",
strings.Join(ids, ", "), status,
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
input := liveChatMessage.NewLiveChatMessage(
liveChatMessage.WithIds(ids),
liveChatMessage.WithStatus(status),
+13 -8
View File
@@ -4,11 +4,13 @@
package liveChatModerator
import (
"fmt"
"io"
"strings"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
"github.com/eat-pray-ai/yutu/cmd"
"github.com/eat-pray-ai/yutu/pkg"
"github.com/eat-pray-ai/yutu/pkg/liveChatModerator"
"github.com/eat-pray-ai/yutu/pkg/utils"
"github.com/google/jsonschema-go/jsonschema"
@@ -35,6 +37,7 @@ var deleteInSchema = &jsonschema.Schema{
Type: "array", Description: deleteIdsUsage,
Items: &jsonschema.Schema{Type: "string"},
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -51,6 +54,9 @@ func init() {
}, cobramcp.GenToolHandler(
deleteTool,
func(input liveChatModerator.LiveChatModerator, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Delete(writer)
},
),
@@ -58,8 +64,8 @@ func init() {
liveChatModeratorCmd.AddCommand(deleteCmd)
deleteCmd.Flags().StringSliceVarP(&ids, "ids", "i", []string{}, deleteIdsUsage)
deleteCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = deleteCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(deleteCmd)
}
var deleteCmd = &cobra.Command{
@@ -67,14 +73,13 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Example: deleteExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(
c, "Would delete live chat moderator(s): %s", strings.Join(ids, ", "),
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would delete live chat moderator(s): %s", strings.Join(ids, ", "),
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := liveChatModerator.NewLiveChatModerator(
liveChatModerator.WithIds(ids),
)
+13 -11
View File
@@ -5,6 +5,7 @@ package liveChatModerator
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -39,6 +40,7 @@ var insertInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -55,6 +57,9 @@ func init() {
}, cobramcp.GenToolHandler(
insertTool,
func(input liveChatModerator.LiveChatModerator, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -69,10 +74,9 @@ func init() {
&parts, "parts", "p", []string{"snippet"}, "Parts to include",
)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("liveChatId")
_ = insertCmd.MarkFlagRequired("moderatorChannelId")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -80,16 +84,14 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(
c, "Would add moderator %s to live chat %s", moderatorChannelId,
liveChatId,
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would add moderator %s to live chat %s", moderatorChannelId, liveChatId,
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
input := liveChatModerator.NewLiveChatModerator(
liveChatModerator.WithLiveChatId(liveChatId),
liveChatModerator.WithModeratorChannelId(moderatorChannelId),
-1
View File
@@ -74,7 +74,6 @@ func init() {
&parts, "parts", "p", []string{"snippet"}, pkg.PartsUsage,
)
listCmd.Flags().StringP("output", "o", "table", pkg.TableUsage)
_ = listCmd.MarkFlagRequired("liveChatId")
}
+12 -8
View File
@@ -4,6 +4,7 @@
package liveStream
import (
"fmt"
"io"
"strings"
@@ -40,6 +41,7 @@ var deleteInSchema = &jsonschema.Schema{
"on_behalf_of_content_owner_channel": {
Type: "string", Description: obococUsage,
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -55,6 +57,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
deleteTool, func(input liveStream.LiveStream, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Delete(writer)
},
),
@@ -69,8 +74,8 @@ func init() {
&onBehalfOfContentOwnerChannel, "onBehalfOfContentOwnerChannel", "B", "",
obococUsage,
)
deleteCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = deleteCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(deleteCmd)
}
var deleteCmd = &cobra.Command{
@@ -78,14 +83,13 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Example: deleteExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(
c, "Would delete live stream(s): %s", strings.Join(ids, ", "),
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would delete live stream(s): %s", strings.Join(ids, ", "),
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := liveStream.NewLiveStream(
liveStream.WithIds(ids),
liveStream.WithOnBehalfOfContentOwner(onBehalfOfContentOwner),
+11 -8
View File
@@ -5,6 +5,7 @@ package liveStream
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -58,6 +59,7 @@ var insertInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -73,6 +75,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
insertTool, func(input liveStream.LiveStream, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -95,11 +100,10 @@ func init() {
&parts, "parts", "p", []string{"snippet", "cdn", "status"}, pkg.PartsUsage,
)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("title")
_ = insertCmd.MarkFlagRequired("ingestionType")
_ = insertCmd.MarkFlagRequired("resolution")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -107,13 +111,12 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would create live stream: %s", title)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would create live stream: %s", title)
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := liveStream.NewLiveStream(
liveStream.WithTitle(title),
liveStream.WithDescription(description),
+11 -10
View File
@@ -5,6 +5,7 @@ package liveStream
import (
"encoding/json"
"fmt"
"io"
"strings"
@@ -59,6 +60,7 @@ var updateInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -74,6 +76,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
updateTool, func(input liveStream.LiveStream, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
input.MaxResults = 1
return input.Update(writer)
},
@@ -95,9 +100,8 @@ func init() {
obococUsage,
)
updateCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
updateCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = updateCmd.MarkFlagRequired("id")
cmd.AddMutationFlags(updateCmd)
}
var updateCmd = &cobra.Command{
@@ -105,15 +109,12 @@ var updateCmd = &cobra.Command{
Short: updateShort,
Long: updateLong,
Example: updateExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would update live stream: %s", strings.Join(ids, ", "))
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(
c, "Would update live stream: %s", strings.Join(ids, ", "),
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := liveStream.NewLiveStream(
liveStream.WithIds(ids),
liveStream.WithTitle(title),
+1 -1
View File
@@ -14,7 +14,7 @@ const (
)
var (
parts []string
parts []string
)
var membershipsLevelCmd = &cobra.Command{
+11 -8
View File
@@ -4,6 +4,7 @@
package playlist
import (
"fmt"
"io"
"strings"
@@ -37,6 +38,7 @@ var deleteInSchema = &jsonschema.Schema{
Items: &jsonschema.Schema{Type: "string"},
},
"on_behalf_of_content_owner": {Type: "string", Description: pkg.OBOCOUsage},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -52,6 +54,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
deleteTool, func(input playlist.Playlist, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Delete(writer)
},
),
@@ -62,9 +67,8 @@ func init() {
deleteCmd.Flags().StringVarP(
&onBehalfOfContentOwner, "onBehalfOfContentOwner", "b", "", pkg.OBOCOUsage,
)
deleteCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = deleteCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(deleteCmd)
}
var deleteCmd = &cobra.Command{
@@ -72,12 +76,11 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Example: deleteExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(c, "Would delete playlist(s): %s", strings.Join(ids, ", "))
if err != nil {
utils.HandleCmdError(err, c)
return
}
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would delete playlist(s): %s", strings.Join(ids, ", "))
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := playlist.NewPlaylist(
playlist.WithIds(ids),
playlist.WithOnBehalfOfContentOwner(onBehalfOfContentOwner),
+11 -8
View File
@@ -5,6 +5,7 @@ package playlist
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -50,6 +51,7 @@ var insertInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -65,6 +67,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
insertTool, func(input playlist.Playlist, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -78,11 +83,10 @@ func init() {
insertCmd.Flags().StringVarP(&channelId, "channelId", "c", "", insertCidUsage)
insertCmd.Flags().StringVarP(&privacy, "privacy", "p", "", privacyUsage)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("title")
_ = insertCmd.MarkFlagRequired("channelId")
_ = insertCmd.MarkFlagRequired("privacy")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -90,13 +94,12 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would insert playlist: %s", title)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would insert playlist")
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := playlist.NewPlaylist(
playlist.WithTitle(title),
playlist.WithDescription(description),
+12 -10
View File
@@ -5,6 +5,7 @@ package playlist
import (
"encoding/json"
"fmt"
"io"
"strings"
@@ -56,6 +57,7 @@ var updateInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -71,6 +73,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
updateTool, func(input playlist.Playlist, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Update(writer)
},
),
@@ -84,9 +89,8 @@ func init() {
updateCmd.Flags().StringVarP(&language, "language", "l", "", languageUsage)
updateCmd.Flags().StringVarP(&privacy, "privacy", "p", "", privacyUsage)
updateCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
updateCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = updateCmd.MarkFlagRequired("id")
cmd.AddMutationFlags(updateCmd)
}
var updateCmd = &cobra.Command{
@@ -94,13 +98,12 @@ var updateCmd = &cobra.Command{
Short: updateShort,
Long: updateLong,
Example: updateExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would update playlist: %s", strings.Join(ids, ", "))
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
confirmErr := cmd.Confirm(c, "Would update playlist: %s", strings.Join(ids, ", "))
if confirmErr != nil {
utils.HandleCmdError(confirmErr, c)
return
}
p := playlist.NewPlaylist(
playlist.WithIds(ids),
playlist.WithTitle(title),
@@ -110,7 +113,6 @@ var updateCmd = &cobra.Command{
playlist.WithPrivacy(privacy),
playlist.WithOutput(output),
)
err := p.Update(c.OutOrStdout())
utils.HandleCmdError(err, c)
utils.HandleCmdError(p.Update(c.OutOrStdout()), c)
},
}
+12 -9
View File
@@ -4,6 +4,7 @@
package playlistImage
import (
"fmt"
"io"
"strings"
@@ -36,6 +37,7 @@ var deleteInSchema = &jsonschema.Schema{
Items: &jsonschema.Schema{Type: "string"},
},
"on_behalf_of_content_owner": {Type: "string", Description: pkg.OBOCOUsage},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -52,6 +54,9 @@ func init() {
}, cobramcp.GenToolHandler(
deleteTool,
func(input playlistImage.PlaylistImage, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Delete(writer)
},
),
@@ -62,9 +67,8 @@ func init() {
deleteCmd.Flags().StringVarP(
&onBehalfOfContentOwner, "onBehalfOfContentOwner", "b", "", pkg.OBOCOUsage,
)
deleteCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = deleteCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(deleteCmd)
}
var deleteCmd = &cobra.Command{
@@ -72,14 +76,13 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Example: deleteExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(
c, "Would delete playlist image(s): %s", strings.Join(ids, ", "),
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would delete playlist image(s): %s", strings.Join(ids, ", "),
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := playlistImage.NewPlaylistImage(
playlistImage.WithIds(ids),
playlistImage.WithOnBehalfOfContentOwner(onBehalfOfContentOwner),
+11 -8
View File
@@ -5,6 +5,7 @@ package playlistImage
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -56,6 +57,7 @@ var insertInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -72,6 +74,9 @@ func init() {
}, cobramcp.GenToolHandler(
insertTool,
func(input playlistImage.PlaylistImage, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -91,10 +96,9 @@ func init() {
&onBehalfOfContentOwnerChannel, "onBehalfOfContentOwnerChannel", "B", "",
pkg.OBOCOCUsage,
)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("file")
_ = insertCmd.MarkFlagRequired("playlistId")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -102,13 +106,12 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would insert playlist image: %s", file)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
confirmErr := cmd.Confirm(c, "Would insert playlist image")
if confirmErr != nil {
utils.HandleCmdError(confirmErr, c)
return
}
pi := playlistImage.NewPlaylistImage(
playlistImage.WithFile(file),
playlistImage.WithPlaylistId(playlistId),
+13 -10
View File
@@ -5,6 +5,7 @@ package playlistImage
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -51,6 +52,7 @@ var updateInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -67,6 +69,9 @@ func init() {
}, cobramcp.GenToolHandler(
updateTool,
func(input playlistImage.PlaylistImage, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Update(writer)
},
),
@@ -85,9 +90,8 @@ func init() {
&onBehalfOfContentOwnerChannel, "onBehalfOfContentOwnerChannel", "B", "",
pkg.OBOCOCUsage,
)
updateCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = updateCmd.MarkFlagRequired("playlistId")
cmd.AddMutationFlags(updateCmd)
}
var updateCmd = &cobra.Command{
@@ -95,15 +99,14 @@ var updateCmd = &cobra.Command{
Short: updateShort,
Long: updateLong,
Example: updateExample,
Run: func(c *cobra.Command, args []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(
c, "Would update playlist image for playlist: %s", playlistId,
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would update playlist image for playlist: %s", playlistId,
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
input := playlistImage.NewPlaylistImage(
playlistImage.WithPlaylistId(playlistId),
playlistImage.WithType(type_),
+12 -9
View File
@@ -4,6 +4,7 @@
package playlistItem
import (
"fmt"
"io"
"strings"
@@ -37,6 +38,7 @@ var deleteInSchema = &jsonschema.Schema{
Items: &jsonschema.Schema{Type: "string"},
},
"on_behalf_of_content_owner": {Type: "string", Description: pkg.OBOCOUsage},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -52,6 +54,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
deleteTool, func(input playlistItem.PlaylistItem, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Delete(writer)
},
),
@@ -62,9 +67,8 @@ func init() {
deleteCmd.Flags().StringVarP(
&onBehalfOfContentOwner, "onBehalfOfContentOwner", "b", "", pkg.OBOCOUsage,
)
deleteCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = deleteCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(deleteCmd)
}
var deleteCmd = &cobra.Command{
@@ -72,14 +76,13 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Example: deleteExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(
c, "Would delete playlist item(s): %s", strings.Join(ids, ", "),
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would delete playlist item(s): %s", strings.Join(ids, ", "),
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := playlistItem.NewPlaylistItem(
playlistItem.WithIds(ids),
playlistItem.WithOnBehalfOfContentOwner(onBehalfOfContentOwner),
+11 -8
View File
@@ -5,6 +5,7 @@ package playlistItem
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -52,6 +53,7 @@ var insertInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -67,6 +69,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
insertTool, func(input playlistItem.PlaylistItem, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -88,11 +93,10 @@ func init() {
&onBehalfOfContentOwner, "onBehalfOfContentOwner", "b", "", pkg.OBOCOUsage,
)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("kind")
_ = insertCmd.MarkFlagRequired("playlistId")
_ = insertCmd.MarkFlagRequired("channelId")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -100,13 +104,12 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would insert playlist item to playlist: %s", playlistId)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would insert playlist item")
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := playlistItem.NewPlaylistItem(
playlistItem.WithTitle(title),
playlistItem.WithDescription(description),
+11 -10
View File
@@ -5,6 +5,7 @@ package playlistItem
import (
"encoding/json"
"fmt"
"io"
"strings"
@@ -50,6 +51,7 @@ var updateInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -65,6 +67,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
updateTool, func(input playlistItem.PlaylistItem, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Update(writer)
},
),
@@ -79,9 +84,8 @@ func init() {
&onBehalfOfContentOwner, "onBehalfOfContentOwner", "b", "", pkg.OBOCOUsage,
)
updateCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
updateCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = updateCmd.MarkFlagRequired("id")
cmd.AddMutationFlags(updateCmd)
}
var updateCmd = &cobra.Command{
@@ -89,15 +93,12 @@ var updateCmd = &cobra.Command{
Short: updateShort,
Long: updateLong,
Example: updateExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would update playlist item: %s", strings.Join(ids, ", "))
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(
c, "Would update playlist item: %s", strings.Join(ids, ", "),
)
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := playlistItem.NewPlaylistItem(
playlistItem.WithIds(ids),
playlistItem.WithTitle(title),
+14 -7
View File
@@ -4,11 +4,13 @@
package subscription
import (
"fmt"
"io"
"strings"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
"github.com/eat-pray-ai/yutu/cmd"
"github.com/eat-pray-ai/yutu/pkg"
"github.com/eat-pray-ai/yutu/pkg/subscription"
"github.com/eat-pray-ai/yutu/pkg/utils"
"github.com/google/jsonschema-go/jsonschema"
@@ -35,6 +37,7 @@ var deleteInSchema = &jsonschema.Schema{
Type: "array", Description: deleteIdsUsage,
Items: &jsonschema.Schema{Type: "string"},
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -50,6 +53,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
deleteTool, func(input subscription.Subscription, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Delete(writer)
},
),
@@ -57,8 +63,8 @@ func init() {
subscriptionCmd.AddCommand(deleteCmd)
deleteCmd.Flags().StringSliceVarP(&ids, "ids", "i", []string{}, deleteIdsUsage)
deleteCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = deleteCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(deleteCmd)
}
var deleteCmd = &cobra.Command{
@@ -66,12 +72,13 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Example: deleteExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(c, "Would delete subscription(s): %s", strings.Join(ids, ", "))
if err != nil {
utils.HandleCmdError(err, c)
return
}
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would delete subscription(s): %s", strings.Join(ids, ", "),
)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := subscription.NewSubscription(
subscription.WithIds(ids),
)
+11 -8
View File
@@ -5,6 +5,7 @@ package subscription
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -40,6 +41,7 @@ var insertInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -55,6 +57,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
insertTool, func(input subscription.Subscription, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -68,10 +73,9 @@ func init() {
insertCmd.Flags().StringVarP(&channelId, "channelId", "c", "", insertCidUsage)
insertCmd.Flags().StringVarP(&title, "title", "t", "", titleUsage)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("subscriberChannelId")
_ = insertCmd.MarkFlagRequired("channelId")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -79,13 +83,12 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would insert subscription to channel: %s", channelId)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would insert subscription")
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := subscription.NewSubscription(
subscription.WithSubscriberChannelId(subscriberChannelId),
subscription.WithDescription(description),
+1 -1
View File
@@ -14,7 +14,7 @@ const (
scidUsage = "Subscriber's channel id"
descUsage = "Description of the subscription"
fcidUsage = "Return the subscriptions to the subset of these channels that the authenticated user is subscribed to"
forUsage = "mine|myRecentSubscribers|mySubscribers"
forUsage = "mine|myRecentSubscribers|mySubscribers"
orderUsage = "subscriptionOrderUnspecified|relevance|unread|alphabetical"
titleUsage = "Title of the subscription"
)
+23 -13
View File
@@ -4,10 +4,12 @@
package thirdPartyLink
import (
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
"github.com/eat-pray-ai/yutu/cmd"
"github.com/eat-pray-ai/yutu/pkg"
"github.com/eat-pray-ai/yutu/pkg/thirdPartyLink"
"github.com/eat-pray-ai/yutu/pkg/utils"
"github.com/google/jsonschema-go/jsonschema"
@@ -27,9 +29,13 @@ var deleteInSchema = &jsonschema.Schema{
Type: "object",
Required: []string{"linking_token", "type"},
Properties: map[string]*jsonschema.Schema{
"linking_token": {Type: "string", Description: ltUsage},
"type": {Type: "string", Description: typeUsage, Enum: []any{"linkUnspecified", "channelToStoreLink"}},
"linking_token": {Type: "string", Description: ltUsage},
"type": {
Type: "string", Description: typeUsage,
Enum: []any{"linkUnspecified", "channelToStoreLink"},
},
"external_channel_id": {Type: "string", Description: extCidUsage},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -44,7 +50,11 @@ func init() {
ReadOnlyHint: false,
},
}, cobramcp.GenToolHandler(
deleteTool, func(input thirdPartyLink.ThirdPartyLink, writer io.Writer) error {
deleteTool,
func(input thirdPartyLink.ThirdPartyLink, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Delete(writer)
},
),
@@ -53,11 +63,12 @@ func init() {
deleteCmd.Flags().StringVarP(&linkingToken, "linkingToken", "l", "", ltUsage)
deleteCmd.Flags().StringVarP(&linkType, "type", "t", "", typeUsage)
deleteCmd.Flags().StringVarP(&externalChannelId, "externalChannelId", "e", "", extCidUsage)
deleteCmd.Flags().StringVarP(
&externalChannelId, "externalChannelId", "e", "", extCidUsage,
)
deleteCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = deleteCmd.MarkFlagRequired("linkingToken")
_ = deleteCmd.MarkFlagRequired("type")
cmd.AddMutationFlags(deleteCmd)
}
var deleteCmd = &cobra.Command{
@@ -65,12 +76,11 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Example: deleteExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(c, "Would delete third-party link: %s", linkingToken)
if err != nil {
utils.HandleCmdError(err, c)
return
}
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would delete third-party link: %s", linkingToken)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := thirdPartyLink.NewThirdPartyLink(
thirdPartyLink.WithLinkingToken(linkingToken),
thirdPartyLink.WithType(linkType),
@@ -78,4 +88,4 @@ var deleteCmd = &cobra.Command{
)
utils.HandleCmdError(input.Delete(c.OutOrStdout()), c)
},
}
}
+17 -11
View File
@@ -5,6 +5,7 @@ package thirdPartyLink
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -42,6 +43,7 @@ var insertInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -56,7 +58,11 @@ func init() {
ReadOnlyHint: false,
},
}, cobramcp.GenToolHandler(
insertTool, func(input thirdPartyLink.ThirdPartyLink, writer io.Writer) error {
insertTool,
func(input thirdPartyLink.ThirdPartyLink, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -66,15 +72,16 @@ func init() {
insertCmd.Flags().StringVarP(&linkingToken, "linkingToken", "l", "", ltUsage)
insertCmd.Flags().StringVarP(&linkType, "type", "t", "", typeUsage)
insertCmd.Flags().StringVarP(&linkStatus, "linkStatus", "s", "", statusUsage)
insertCmd.Flags().StringVarP(&externalChannelId, "externalChannelId", "e", "", extCidUsage)
insertCmd.Flags().StringVarP(
&externalChannelId, "externalChannelId", "e", "", extCidUsage,
)
insertCmd.Flags().StringSliceVarP(
&parts, "parts", "p", []string{"snippet", "status"}, pkg.PartsUsage,
)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("linkingToken")
_ = insertCmd.MarkFlagRequired("type")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -82,13 +89,12 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would insert third-party link: %s", linkingToken)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would insert third-party link")
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := thirdPartyLink.NewThirdPartyLink(
thirdPartyLink.WithLinkingToken(linkingToken),
thirdPartyLink.WithType(linkType),
@@ -99,4 +105,4 @@ var insertCmd = &cobra.Command{
)
utils.HandleCmdError(input.Insert(c.OutOrStdout()), c)
},
}
}
+8 -5
View File
@@ -33,8 +33,8 @@ var listInSchema = &jsonschema.Schema{
Type: "object",
Required: []string{},
Properties: map[string]*jsonschema.Schema{
"linking_token": {Type: "string", Description: ltUsage},
"type": {Type: "string", Description: typeUsage, Enum: []any{"linkUnspecified", "channelToStoreLink"}},
"linking_token": {Type: "string", Description: ltUsage},
"type": {Type: "string", Description: typeUsage, Enum: []any{"linkUnspecified", "channelToStoreLink"}},
"external_channel_id": {Type: "string", Description: extCidUsage},
"parts": {
Type: "array", Description: pkg.PartsUsage,
@@ -59,7 +59,8 @@ func init() {
ReadOnlyHint: true,
},
}, cobramcp.GenToolHandler(
listTool, func(input thirdPartyLink.ThirdPartyLink, writer io.Writer) error {
listTool,
func(input thirdPartyLink.ThirdPartyLink, writer io.Writer) error {
return input.List(writer)
},
),
@@ -68,7 +69,9 @@ func init() {
listCmd.Flags().StringVarP(&linkingToken, "linkingToken", "l", "", ltUsage)
listCmd.Flags().StringVarP(&linkType, "type", "t", "", typeUsage)
listCmd.Flags().StringVarP(&externalChannelId, "externalChannelId", "e", "", extCidUsage)
listCmd.Flags().StringVarP(
&externalChannelId, "externalChannelId", "e", "", extCidUsage,
)
listCmd.Flags().StringSliceVarP(
&parts, "parts", "p", []string{"snippet", "status"}, pkg.PartsUsage,
)
@@ -91,4 +94,4 @@ var listCmd = &cobra.Command{
)
utils.HandleCmdError(input.List(cmd.OutOrStdout()), cmd)
},
}
}
+7 -7
View File
@@ -9,12 +9,12 @@ import (
)
const (
short = "Manage YouTube third-party links"
long = "Manage YouTube third-party links. Use this tool to list, insert, update, or delete links between a YouTube channel and a third-party service."
ltUsage = "Linking token that identifies the YouTube account and channel"
typeUsage = "Type of the link: linkUnspecified|channelToStoreLink"
statusUsage = "Status of the link: unknown|failed|pending|linked"
extCidUsage = "Channel ID to which changes should be applied, for delegation"
short = "Manage YouTube third-party links"
long = "Manage YouTube third-party links. Use this tool to list, insert, update, or delete links between a YouTube channel and a third-party service."
ltUsage = "Linking token that identifies the YouTube account and channel"
typeUsage = "Type of the link: linkUnspecified|channelToStoreLink"
statusUsage = "Status of the link: unknown|failed|pending|linked"
extCidUsage = "Channel ID to which changes should be applied, for delegation"
)
var (
@@ -36,4 +36,4 @@ var thirdPartyLinkCmd = &cobra.Command{
func init() {
cmd.RootCmd.AddCommand(thirdPartyLinkCmd)
}
}
+17 -11
View File
@@ -5,6 +5,7 @@ package thirdPartyLink
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -44,6 +45,7 @@ var updateInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -58,7 +60,11 @@ func init() {
ReadOnlyHint: false,
},
}, cobramcp.GenToolHandler(
updateTool, func(input thirdPartyLink.ThirdPartyLink, writer io.Writer) error {
updateTool,
func(input thirdPartyLink.ThirdPartyLink, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Update(writer)
},
),
@@ -68,14 +74,15 @@ func init() {
updateCmd.Flags().StringVarP(&linkingToken, "linkingToken", "l", "", ltUsage)
updateCmd.Flags().StringVarP(&linkType, "type", "t", "", typeUsage)
updateCmd.Flags().StringVarP(&linkStatus, "linkStatus", "s", "", statusUsage)
updateCmd.Flags().StringVarP(&externalChannelId, "externalChannelId", "e", "", extCidUsage)
updateCmd.Flags().StringVarP(
&externalChannelId, "externalChannelId", "e", "", extCidUsage,
)
updateCmd.Flags().StringSliceVarP(
&parts, "parts", "p", []string{"snippet", "status"}, pkg.PartsUsage,
)
updateCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
updateCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = updateCmd.MarkFlagRequired("linkingToken")
cmd.AddMutationFlags(updateCmd)
}
var updateCmd = &cobra.Command{
@@ -83,13 +90,12 @@ var updateCmd = &cobra.Command{
Short: updateShort,
Long: updateLong,
Example: updateExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would update third-party link: %s", linkingToken)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would update third-party link: %s", linkingToken)
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := thirdPartyLink.NewThirdPartyLink(
thirdPartyLink.WithLinkingToken(linkingToken),
thirdPartyLink.WithType(linkType),
@@ -100,4 +106,4 @@ var updateCmd = &cobra.Command{
)
utils.HandleCmdError(input.Update(c.OutOrStdout()), c)
},
}
}
+11 -8
View File
@@ -5,6 +5,7 @@ package thumbnail
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -37,6 +38,7 @@ var setInSchema = &jsonschema.Schema{
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -52,6 +54,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
setTool, func(input thumbnail.Thumbnail, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Set(writer)
},
),
@@ -61,10 +66,9 @@ func init() {
setCmd.Flags().StringVarP(&file, "file", "f", "", fileUsage)
setCmd.Flags().StringVarP(&videoId, "videoId", "v", "", vidUsage)
setCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
setCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = setCmd.MarkFlagRequired("file")
_ = setCmd.MarkFlagRequired("videoId")
cmd.AddMutationFlags(setCmd)
}
var setCmd = &cobra.Command{
@@ -72,13 +76,12 @@ var setCmd = &cobra.Command{
Short: setShort,
Long: setLong,
Example: setExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would set thumbnail for video: %s", videoId)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would set thumbnail for video: %s", videoId)
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := thumbnail.NewThumbnail(
thumbnail.WithFile(file),
thumbnail.WithVideoId(videoId),
+12 -7
View File
@@ -4,11 +4,13 @@
package video
import (
"fmt"
"io"
"strings"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
"github.com/eat-pray-ai/yutu/cmd"
"github.com/eat-pray-ai/yutu/pkg"
"github.com/eat-pray-ai/yutu/pkg/utils"
"github.com/eat-pray-ai/yutu/pkg/video"
"github.com/google/jsonschema-go/jsonschema"
@@ -35,6 +37,7 @@ var deleteInSchema = &jsonschema.Schema{
Type: "array", Description: deleteIdsUsage,
Items: &jsonschema.Schema{Type: "string"},
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -50,6 +53,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
deleteTool, func(input video.Video, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Delete(writer)
},
),
@@ -57,8 +63,8 @@ func init() {
videoCmd.AddCommand(deleteCmd)
deleteCmd.Flags().StringSliceVarP(&ids, "ids", "i", []string{}, deleteIdsUsage)
deleteCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = deleteCmd.MarkFlagRequired("ids")
cmd.AddMutationFlags(deleteCmd)
}
var deleteCmd = &cobra.Command{
@@ -66,12 +72,11 @@ var deleteCmd = &cobra.Command{
Short: deleteShort,
Long: deleteLong,
Example: deleteExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(c, "Would delete video(s): %s", strings.Join(ids, ", "))
if err != nil {
utils.HandleCmdError(err, c)
return
}
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would delete video(s): %s", strings.Join(ids, ", "))
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := video.NewVideo(video.WithIds(ids))
utils.HandleCmdError(input.Delete(c.OutOrStdout()), c)
},
-1
View File
@@ -67,7 +67,6 @@ func init() {
&onBehalfOfContentOwner, "onBehalfOfContentOwner", "b", "", pkg.OBOCOUsage,
)
getRatingCmd.Flags().StringP("output", "o", "", pkg.TableUsage)
_ = getRatingCmd.MarkFlagRequired("ids")
}
+11 -8
View File
@@ -5,6 +5,7 @@ package video
import (
"encoding/json"
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -63,6 +64,7 @@ var insertInSchema = &jsonschema.Schema{
"stabilize": {Type: "boolean", Description: stabilizeUsage},
"notify_subscribers": {Type: "boolean", Description: nsUsage},
"public_stats_viewable": {Type: "boolean", Description: psvUsage},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
"on_behalf_of_content_owner": {
Type: "string",
@@ -91,6 +93,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
insertTool, func(input video.Video, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Insert(writer)
},
),
@@ -135,11 +140,10 @@ func init() {
pkg.OBOCOCUsage,
)
insertCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
insertCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = insertCmd.MarkFlagRequired("file")
_ = insertCmd.MarkFlagRequired("categoryId")
_ = insertCmd.MarkFlagRequired("privacy")
cmd.AddMutationFlags(insertCmd)
}
var insertCmd = &cobra.Command{
@@ -147,13 +151,12 @@ var insertCmd = &cobra.Command{
Short: insertShort,
Long: insertLong,
Example: insertExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would insert video: %s", file)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would insert video")
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := video.NewVideo(
video.WithAutoLevels(autoLevels),
video.WithFile(file),
+14 -8
View File
@@ -4,11 +4,13 @@
package video
import (
"fmt"
"io"
"strings"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
"github.com/eat-pray-ai/yutu/cmd"
"github.com/eat-pray-ai/yutu/pkg"
"github.com/eat-pray-ai/yutu/pkg/utils"
"github.com/eat-pray-ai/yutu/pkg/video"
"github.com/google/jsonschema-go/jsonschema"
@@ -42,6 +44,7 @@ var rateInSchema = &jsonschema.Schema{
Type: "string", Description: rateRUsage,
Enum: []any{"like", "dislike", "none"},
},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -57,6 +60,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
rateTool, func(input video.Video, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Rate(writer)
},
),
@@ -65,10 +71,9 @@ func init() {
rateCmd.Flags().StringSliceVarP(&ids, "ids", "i", []string{}, rateIdsUsage)
rateCmd.Flags().StringVarP(&rating, "rating", "r", "", rateRUsage)
rateCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = rateCmd.MarkFlagRequired("ids")
_ = rateCmd.MarkFlagRequired("rating")
cmd.AddMutationFlags(rateCmd)
}
var rateCmd = &cobra.Command{
@@ -76,12 +81,13 @@ var rateCmd = &cobra.Command{
Short: rateShort,
Long: rateLong,
Example: rateExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(c, "Would rate video(s): %s as %s", strings.Join(ids, ", "), rating)
if err != nil {
utils.HandleCmdError(err, c)
return
}
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would rate video(s): %s as %s", strings.Join(ids, ", "), rating,
)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := video.NewVideo(
video.WithIds(ids),
video.WithRating(rating),
+13 -8
View File
@@ -4,6 +4,7 @@
package video
import (
"fmt"
"io"
"strings"
@@ -44,6 +45,7 @@ var reportAbuseInSchema = &jsonschema.Schema{
"comments": {Type: "string", Description: commentsUsage},
"language": {Type: "string", Description: raLangUsage},
"on_behalf_of_content_owner": {Type: "string", Description: pkg.OBOCOUsage},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -60,6 +62,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
reportAbuseTool, func(input video.Video, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.ReportAbuse(writer)
},
),
@@ -80,10 +85,9 @@ func init() {
reportAbuseCmd.Flags().StringVarP(
&onBehalfOfContentOwner, "onBehalfOfContentOwner", "b", "", pkg.OBOCOUsage,
)
reportAbuseCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = reportAbuseCmd.MarkFlagRequired("ids")
_ = reportAbuseCmd.MarkFlagRequired("reasonId")
cmd.AddMutationFlags(reportAbuseCmd)
}
var reportAbuseCmd = &cobra.Command{
@@ -91,12 +95,13 @@ var reportAbuseCmd = &cobra.Command{
Short: reportAbuseShort,
Long: reportAbuseLong,
Example: reportAbuseExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(c, "Would report abuse on video(s): %s", strings.Join(ids, ", "))
if err != nil {
utils.HandleCmdError(err, c)
return
}
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf(
"Would report abuse on video(s): %s", strings.Join(ids, ", "),
)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := video.NewVideo(
video.WithIds(ids),
video.WithReasonId(reasonId),
+11 -8
View File
@@ -5,6 +5,7 @@ package video
import (
"encoding/json"
"fmt"
"io"
"strings"
@@ -64,6 +65,7 @@ var updateInSchema = &jsonschema.Schema{
"embeddable": {Type: "boolean", Description: embeddableUsage},
"contains_synthetic_media": {Type: "boolean", Description: csmUsage},
"recording_date": {Type: "string", Description: rdUsage},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
"output": {
Type: "string", Enum: []any{"json", "yaml", "silent"},
Description: pkg.SilentUsage, Default: json.RawMessage(`"yaml"`),
@@ -83,6 +85,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
updateTool, func(input video.Video, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
input.MaxResults = 1
return input.Update(writer)
},
@@ -109,9 +114,8 @@ func init() {
)
updateCmd.Flags().StringVarP(&recordingDate, "recordingDate", "D", "", rdUsage)
updateCmd.Flags().StringP("output", "o", "", pkg.SilentUsage)
updateCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = updateCmd.MarkFlagRequired("id")
cmd.AddMutationFlags(updateCmd)
}
var updateCmd = &cobra.Command{
@@ -119,13 +123,12 @@ var updateCmd = &cobra.Command{
Short: updateShort,
Long: updateLong,
Example: updateExample,
Run: func(c *cobra.Command, args []string) {
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would update video: %s", strings.Join(ids, ", "))
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
output, _ := c.Flags().GetString("output")
err := cmd.Confirm(c, "Would update video: %s", strings.Join(ids, ", "))
if err != nil {
utils.HandleCmdError(err, c)
return
}
input := video.NewVideo(
video.WithIds(ids),
video.WithTitle(title),
@@ -15,8 +15,8 @@ const (
)
var (
hl string
parts []string
hl string
parts []string
)
var videoAbuseReportReasonCmd = &cobra.Command{
+11 -8
View File
@@ -4,6 +4,7 @@
package watermark
import (
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
@@ -40,6 +41,7 @@ var setInSchema = &jsonschema.Schema{
},
"duration_ms": {Type: "number", Description: dmUsage},
"offset_ms": {Type: "number", Description: omUsage},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
"offset_type": {
Type: "string", Description: otUsage,
Enum: []any{"offsetFromStart", "offsetFromEnd"},
@@ -60,6 +62,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
setTool, func(input watermark.Watermark, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Set(writer)
},
),
@@ -77,10 +82,9 @@ func init() {
setCmd.Flags().StringVarP(
&onBehalfOfContentOwner, "onBehalfOfContentOwner", "b", "", pkg.OBOCOUsage,
)
setCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = setCmd.MarkFlagRequired("channelId")
_ = setCmd.MarkFlagRequired("file")
cmd.AddMutationFlags(setCmd)
}
var setCmd = &cobra.Command{
@@ -88,12 +92,11 @@ var setCmd = &cobra.Command{
Short: setShort,
Long: setLong,
Example: setExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(c, "Would set watermark for channel: %s", channelId)
if err != nil {
utils.HandleCmdError(err, c)
return
}
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would set watermark for channel: %s", channelId)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := watermark.NewWatermark(
watermark.WithChannelId(channelId),
watermark.WithFile(file),
+12 -7
View File
@@ -4,10 +4,12 @@
package watermark
import (
"fmt"
"io"
cobramcp "github.com/eat-pray-ai/cobra-mcp"
"github.com/eat-pray-ai/yutu/cmd"
"github.com/eat-pray-ai/yutu/pkg"
"github.com/eat-pray-ai/yutu/pkg/utils"
"github.com/eat-pray-ai/yutu/pkg/watermark"
"github.com/google/jsonschema-go/jsonschema"
@@ -28,6 +30,7 @@ var unsetInSchema = &jsonschema.Schema{
Required: []string{"channel_id"},
Properties: map[string]*jsonschema.Schema{
"channel_id": {Type: "string", Description: cidUsage},
"confirmed": {Type: "boolean", Description: pkg.ConfirmedUsage},
},
}
@@ -43,6 +46,9 @@ func init() {
},
}, cobramcp.GenToolHandler(
unsetTool, func(input watermark.Watermark, writer io.Writer) error {
if !input.Confirmed {
return utils.ErrNotConfirmed
}
return input.Unset(writer)
},
),
@@ -50,8 +56,8 @@ func init() {
watermarkCmd.AddCommand(unsetCmd)
unsetCmd.Flags().StringVarP(&channelId, "channelId", "c", "", cidUsage)
unsetCmd.Flags().Bool("yes", false, pkg.ConfirmedUsage)
_ = unsetCmd.MarkFlagRequired("channelId")
cmd.AddMutationFlags(unsetCmd)
}
var unsetCmd = &cobra.Command{
@@ -59,12 +65,11 @@ var unsetCmd = &cobra.Command{
Short: unsetShort,
Long: unsetLong,
Example: unsetExample,
Run: func(c *cobra.Command, args []string) {
err := cmd.Confirm(c, "Would unset watermark for channel: %s", channelId)
if err != nil {
utils.HandleCmdError(err, c)
return
}
PreRunE: func(c *cobra.Command, _ []string) error {
msg := fmt.Sprintf("Would unset watermark for channel: %s", channelId)
return utils.ConfirmPreRun(c, msg)
},
Run: func(c *cobra.Command, _ []string) {
input := watermark.NewWatermark(watermark.WithChannelId(channelId))
utils.HandleCmdError(input.Unset(c.OutOrStdout()), c)
},
+1
View File
@@ -33,6 +33,7 @@ type Fields struct {
Service *youtube.Service `yaml:"-" json:"-"`
RedirectURL string `yaml:"-" json:"-"`
Ids []string `yaml:"ids" json:"ids,omitempty"`
Confirmed bool `yaml:"-" json:"confirmed,omitempty"`
MaxResults int64 `yaml:"max_results" json:"max_results,omitempty"`
Hl string `yaml:"hl" json:"hl,omitempty"`
ChannelId string `yaml:"channel_id" json:"channel_id,omitempty"`
+10 -10
View File
@@ -8,16 +8,16 @@ import (
)
const (
PartsUsage = "Comma separated parts"
MRUsage = "The maximum number of items that should be returned, 0 for no limit"
TableUsage = "json|yaml|table"
SilentUsage = "json|yaml|silent"
JsonMIME = "application/json"
PerPage = 20
OBOUsage = "ID of the YouTube account that the content owner is acting on behalf of"
OBOCOUsage = "ID of the content owner, for YouTube content partners"
OBOCOCUsage = "YouTube channel ID linked to the content owner"
PartsUsage = "Comma separated parts"
MRUsage = "The maximum number of items that should be returned, 0 for no limit"
TableUsage = "json|yaml|table"
SilentUsage = "json|yaml|silent"
JsonMIME = "application/json"
PerPage = 20
OBOUsage = "ID of the YouTube account that the content owner is acting on behalf of"
OBOCOUsage = "ID of the content owner, for YouTube content partners"
OBOCOCUsage = "YouTube channel ID linked to the content owner"
ConfirmedUsage = "Confirm the operation"
getWdFailed = "failed to get working directory"
openRootFailed = "failed to open root directory"
)
+29 -6
View File
@@ -4,6 +4,7 @@
package utils
import (
"bufio"
"crypto/rand"
"encoding/base64"
"encoding/json"
@@ -25,11 +26,11 @@ import (
"gopkg.in/yaml.v3"
)
var isInteractive = func(writer io.Writer) bool {
var IsInteractive = func(v any) bool {
if os.Getenv("CI") != "" {
return false
}
if f, ok := writer.(*os.File); ok {
if f, ok := v.(*os.File); ok {
return term.IsTerminal(int(f.Fd()))
}
return false
@@ -37,7 +38,7 @@ var isInteractive = func(writer io.Writer) bool {
func PrintJSON(data any, writer io.Writer) {
var marshalled []byte
if isInteractive(writer) {
if IsInteractive(writer) {
marshalled, _ = json.MarshalIndent(data, "", " ")
} else {
marshalled, _ = json.Marshal(data)
@@ -117,11 +118,33 @@ func ExtractHl(uri string) string {
return ""
}
// ErrDryRun is returned when --dry-run is set; HandleCmdError silently ignores it.
var ErrDryRun = errors.New("dry run")
var ErrNotConfirmed = errors.New("operation not confirmed (pass confirm: true or rerun with --yes)")
func ConfirmPreRun(cmd *cobra.Command, msg string) error {
if yes, _ := cmd.Flags().GetBool("yes"); yes {
return nil
}
if !IsInteractive(cmd.InOrStdin()) {
_, _ = fmt.Fprintln(cmd.ErrOrStderr(), msg)
return ErrNotConfirmed
}
_, _ = fmt.Fprintf(cmd.ErrOrStderr(), "%s [y/N] ", msg)
scanner := bufio.NewScanner(cmd.InOrStdin())
if !scanner.Scan() {
return ErrNotConfirmed
}
answer := strings.TrimSpace(scanner.Text())
if answer != "y" && answer != "Y" {
return ErrNotConfirmed
}
return nil
}
func HandleCmdError(err error, cmd *cobra.Command) {
if err == nil || errors.Is(err, ErrDryRun) {
if err == nil {
return
}
_ = cmd.Help()
+84 -12
View File
@@ -9,6 +9,7 @@ import (
"io"
"os"
"reflect"
"strings"
"testing"
"github.com/spf13/cobra"
@@ -171,8 +172,8 @@ func TestIsInteractive(t *testing.T) {
if tt.ci != "" {
t.Setenv("CI", tt.ci)
}
if got := isInteractive(tt.writer); got != tt.want {
t.Errorf("isInteractive() = %v, want %v", got, tt.want)
if got := IsInteractive(tt.writer); got != tt.want {
t.Errorf("IsInteractive() = %v, want %v", got, tt.want)
}
})
}
@@ -213,9 +214,9 @@ func TestPrintJSON(t *testing.T) {
for _, tt := range tests {
t.Run(
tt.name, func(t *testing.T) {
orig := isInteractive
isInteractive = func(io.Writer) bool { return tt.interactive }
defer func() { isInteractive = orig }()
orig := IsInteractive
IsInteractive = func(any) bool { return tt.interactive }
defer func() { IsInteractive = orig }()
writer := &bytes.Buffer{}
PrintJSON(tt.data, writer)
@@ -391,13 +392,84 @@ func TestRandomStage(t *testing.T) {
}
}
func TestHandleCmdError_DryRun(t *testing.T) {
c := &cobra.Command{Use: "test"}
var stderr bytes.Buffer
c.SetErr(&stderr)
HandleCmdError(ErrDryRun, c)
if stderr.Len() != 0 {
t.Errorf("expected no error output for ErrDryRun, got %q", stderr.String())
func TestConfirmPreRun(t *testing.T) {
tests := []struct {
name string
yes bool
input string
interactive bool
wantErr error
}{
{
name: "yes flag bypasses prompt",
yes: true,
wantErr: nil,
},
{
name: "non-interactive without yes flag",
yes: false,
interactive: false,
wantErr: ErrNotConfirmed,
},
{
name: "interactive confirm with y",
yes: false,
interactive: true,
input: "y\n",
wantErr: nil,
},
{
name: "interactive confirm with Y",
yes: false,
interactive: true,
input: "Y\n",
wantErr: nil,
},
{
name: "interactive deny with n",
yes: false,
interactive: true,
input: "n\n",
wantErr: ErrNotConfirmed,
},
{
name: "interactive deny with empty",
yes: false,
interactive: true,
input: "\n",
wantErr: ErrNotConfirmed,
},
{
name: "interactive deny with EOF",
yes: false,
interactive: true,
input: "",
wantErr: ErrNotConfirmed,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
orig := IsInteractive
IsInteractive = func(any) bool { return tt.interactive }
defer func() { IsInteractive = orig }()
cmd := &cobra.Command{Use: "test"}
cmd.Flags().Bool("yes", false, "")
if tt.yes {
_ = cmd.Flags().Set("yes", "true")
}
var errBuf bytes.Buffer
cmd.SetErr(&errBuf)
cmd.SetIn(strings.NewReader(tt.input))
err := ConfirmPreRun(cmd, "Would do something")
if err != tt.wantErr {
t.Errorf("ConfirmPreRun() error = %v, want %v", err, tt.wantErr)
}
})
}
}