diff --git a/pkg/yutuber/commentThread/commentThread.go b/pkg/yutuber/commentThread/commentThread.go new file mode 100644 index 0000000..a0f2ace --- /dev/null +++ b/pkg/yutuber/commentThread/commentThread.go @@ -0,0 +1,216 @@ +package commentThread + +import ( + "errors" + "fmt" + "github.com/eat-pray-ai/yutu/pkg/auth" + "github.com/eat-pray-ai/yutu/pkg/utils" + "google.golang.org/api/youtube/v3" + "log" +) + +var ( + service *youtube.Service + errGetCommentThread = errors.New("failed to get comment thread") + errInsertCommentThread = errors.New("failed to insert comment thread") +) + +type commentThread struct { + AllThreadsRelatedToChannelId string `yaml:"all_threads_related_to_channel_id" json:"all_threads_related_to_channel_id"` + AuthorChannelId string `yaml:"author_channel_id" json:"author_channel_id"` + ChannelId string `yaml:"channel_id" json:"channel_id"` + ID string `yaml:"id" json:"id"` + MaxResults int64 `yaml:"max_results" json:"max_results"` + ModerationStatus string `yaml:"moderation_status" json:"moderation_status"` + Order string `yaml:"order" json:"order"` + SearchTerms string `yaml:"search_terms" json:"search_terms"` + TextFormat string `yaml:"text_format" json:"text_format"` + TextOriginal string `yaml:"text_original" json:"text_original"` + VideoId string `yaml:"video_id" json:"video_id"` +} + +type CommentThread interface { + get([]string) []*youtube.CommentThread + List([]string, string) + Insert(silent bool) +} + +type Option func(*commentThread) + +func NewCommentThread(opts ...Option) CommentThread { + c := &commentThread{} + + for _, opt := range opts { + opt(c) + } + + return c +} + +func (c *commentThread) get(parts []string) []*youtube.CommentThread { + call := service.CommentThreads.List(parts) + + if c.AllThreadsRelatedToChannelId != "" { + call = call.AllThreadsRelatedToChannelId(c.AllThreadsRelatedToChannelId) + } + + if c.ChannelId != "" { + call = call.ChannelId(c.ChannelId) + } + + if c.ID != "" { + call = call.Id(c.ID) + } + + if c.MaxResults <= 0 { + c.MaxResults = 1 + } + call = call.MaxResults(c.MaxResults) + + if c.ModerationStatus != "" { + call = call.ModerationStatus(c.ModerationStatus) + } + + if c.Order != "" { + call = call.Order(c.Order) + } + + if c.SearchTerms != "" { + call = call.SearchTerms(c.SearchTerms) + } + + if c.TextFormat != "" { + call = call.TextFormat(c.TextFormat) + } + + if c.VideoId != "" { + call = call.VideoId(c.VideoId) + } + + res, err := call.Do() + if err != nil { + utils.PrintJSON(c) + log.Fatalln(errors.Join(errGetCommentThread, err)) + } + + return res.Items +} + +func (c *commentThread) List(parts []string, output string) { + commentThreads := c.get(parts) + switch output { + case "json": + utils.PrintJSON(commentThreads) + case "yaml": + utils.PrintYAML(commentThreads) + default: + fmt.Println("ID\tTopLevelCommentID") + for _, commentThread := range commentThreads { + fmt.Printf("%s\t%s\n", commentThread.Id, commentThread.Snippet.TopLevelComment.Id) + } + } +} + +func (c *commentThread) Insert(silent bool) { + ct := &youtube.CommentThread{ + Snippet: &youtube.CommentThreadSnippet{ + ChannelId: c.ChannelId, + TopLevelComment: &youtube.Comment{ + Snippet: &youtube.CommentSnippet{ + AuthorChannelId: &youtube.CommentSnippetAuthorChannelId{ + Value: c.AuthorChannelId, + }, + ChannelId: c.ChannelId, + TextOriginal: c.TextOriginal, + VideoId: c.VideoId, + }, + }, + }, + } + + res, err := service.CommentThreads.Insert([]string{"snippet"}, ct).Do() + if err != nil { + utils.PrintJSON(ct) + log.Fatalln(errors.Join(errInsertCommentThread, err)) + } + + if !silent { + fmt.Printf("Comment thread %s inserted\n", res.Id) + } +} + +func WithAllThreadsRelatedToChannelId(allThreadsRelatedToChannelId string) Option { + return func(c *commentThread) { + c.AllThreadsRelatedToChannelId = allThreadsRelatedToChannelId + } +} + +func WithAuthorChannelId(authorChannelId string) Option { + return func(c *commentThread) { + c.AuthorChannelId = authorChannelId + } +} + +func WithChannelId(channelId string) Option { + return func(c *commentThread) { + c.ChannelId = channelId + } +} + +func WithID(id string) Option { + return func(c *commentThread) { + c.ID = id + } +} + +func WithMaxResults(maxResults int64) Option { + return func(c *commentThread) { + c.MaxResults = maxResults + } +} + +func WithModerationStatus(moderationStatus string) Option { + return func(c *commentThread) { + c.ModerationStatus = moderationStatus + } +} + +func WithOrder(order string) Option { + return func(c *commentThread) { + c.Order = order + } +} + +func WithSearchTerms(searchTerms string) Option { + return func(c *commentThread) { + c.SearchTerms = searchTerms + } +} + +func WithTextFormat(textFormat string) Option { + return func(c *commentThread) { + c.TextFormat = textFormat + } +} + +func WithTextOriginal(textOriginal string) Option { + return func(c *commentThread) { + c.TextOriginal = textOriginal + } +} + +func WithVideoId(videoId string) Option { + return func(c *commentThread) { + c.VideoId = videoId + } +} + +func WithService(svc *youtube.Service) Option { + return func(c *commentThread) { + if svc != nil { + service = svc + } else { + service = auth.NewY2BService() + } + } +}