diff --git a/comment.go b/comment.go index f527cea..994d788 100644 --- a/comment.go +++ b/comment.go @@ -71,7 +71,7 @@ func (s *CommentService) LoadMoreReplies(ctx context.Context, comment *Comment) return nil, errors.New("comment: cannot be nil") } - if !comment.hasMore() { + if !comment.HasMore() { return nil, nil } @@ -108,23 +108,17 @@ func (s *CommentService) LoadMoreReplies(ctx context.Context, comment *Comment) } comments := root.JSON.Data.Things.Comments + mores := root.JSON.Data.Things.More + for _, c := range comments { - addCommentToReplies(comment, c) + comment.addCommentToReplies(c) + } + + if len(mores) > 0 { + comment.Replies.More = mores[0] + } else { + comment.Replies.More = nil } - comment.Replies.More = nil return resp, nil } - -// addCommentToReplies traverses the comment tree to find the one -// that the 2nd comment is replying to. It then adds it to its replies. -func addCommentToReplies(parent *Comment, comment *Comment) { - if parent.FullID == comment.ParentID { - parent.Replies.Comments = append(parent.Replies.Comments, comment) - return - } - - for _, reply := range parent.Replies.Comments { - addCommentToReplies(reply, comment) - } -} diff --git a/post.go b/post.go index 66bd076..35370d8 100644 --- a/post.go +++ b/post.go @@ -439,26 +439,23 @@ func (s *PostService) LoadMoreComments(ctx context.Context, pc *PostAndComments) return nil, errors.New("pc: cannot be nil") } - if !pc.hasMore() { + if !pc.HasMore() { return nil, nil } postID := pc.Post.FullID - commentIDs := pc.moreComments.Children + commentIDs := pc.MoreComments.Children - type query struct { - PostID string `url:"link_id"` - IDs []string `url:"children,comma"` - APIType string `url:"api_type"` - } + form := url.Values{} + form.Set("api_type", "json") + form.Set("link_id", postID) + form.Set("children", strings.Join(commentIDs, ",")) path := "api/morechildren" - path, err := addOptions(path, query{postID, commentIDs, "json"}) - if err != nil { - return nil, err - } - req, err := s.client.NewRequest(http.MethodGet, path, nil) + // This was originally a GET, but with POST you can send a bigger payload + // since it's in the body and not the URI. + req, err := s.client.NewRequestWithForm(http.MethodPost, path, form) if err != nil { return nil, err } @@ -477,24 +474,26 @@ func (s *PostService) LoadMoreComments(ctx context.Context, pc *PostAndComments) comments := root.JSON.Data.Things.Comments for _, c := range comments { - addCommentToTree(pc, c) + pc.addCommentToTree(c) + } + + noMore := true + + mores := root.JSON.Data.Things.More + for _, m := range mores { + if strings.HasPrefix(m.ParentID, kindPost+"_") { + noMore = false + } + pc.addMoreToTree(m) + } + + if noMore { + pc.MoreComments = nil } - pc.moreComments = nil return resp, nil } -func addCommentToTree(pc *PostAndComments, comment *Comment) { - if pc.Post.FullID == comment.ParentID { - pc.Comments = append(pc.Comments, comment) - return - } - - for _, reply := range pc.Comments { - addCommentToReplies(reply, comment) - } -} - func (s *PostService) random(ctx context.Context, subreddits ...string) (*PostAndComments, *Response, error) { path := "random" if len(subreddits) > 0 { diff --git a/things.go b/things.go index ce2ad34..ac97171 100644 --- a/things.go +++ b/things.go @@ -176,16 +176,41 @@ type Comment struct { Replies Replies `json:"replies"` } -func (c *Comment) hasMore() bool { +// HasMore determines whether the comment has more replies to load in its reply tree. +func (c *Comment) HasMore() bool { return c.Replies.More != nil && len(c.Replies.More.Children) > 0 } +// addCommentToReplies traverses the comment tree to find the one +// that the 2nd comment is replying to. It then adds it to its replies. +func (c *Comment) addCommentToReplies(comment *Comment) { + if c.FullID == comment.ParentID { + c.Replies.Comments = append(c.Replies.Comments, comment) + return + } + + for _, reply := range c.Replies.Comments { + reply.addCommentToReplies(comment) + } +} + +func (c *Comment) addMoreToReplies(more *More) { + if c.FullID == more.ParentID { + c.Replies.More = more + return + } + + for _, reply := range c.Replies.Comments { + reply.addMoreToReplies(more) + } +} + // Replies holds replies to a comment. // It contains both comments and "more" comments, which are entrypoints to other // comments that were left out. type Replies struct { Comments []*Comment `json:"comments,omitempty"` - More *More `json:"more,omitempty"` + More *More `json:"-"` } // UnmarshalJSON implements the json.Unmarshaler interface. @@ -208,6 +233,14 @@ func (r *Replies) UnmarshalJSON(data []byte) error { return nil } +// MarshalJSON implements the json.Marshaler interface. +func (r *Replies) MarshalJSON() ([]byte, error) { + if r == nil || len(r.Comments) == 0 { + return []byte(`null`), nil + } + return json.Marshal(r.Comments) +} + // todo: should we implement json.Marshaler? // More holds information @@ -381,7 +414,7 @@ type ModActions struct { type PostAndComments struct { Post *Post `json:"post"` Comments []*Comment `json:"comments"` - moreComments *More + MoreComments *More `json:"-"` } // UnmarshalJSON implements the json.Unmarshaler interface. @@ -402,11 +435,33 @@ func (pc *PostAndComments) UnmarshalJSON(data []byte) error { pc.Post = post pc.Comments = comments - pc.moreComments = moreComments + pc.MoreComments = moreComments return nil } -func (pc *PostAndComments) hasMore() bool { - return pc.moreComments != nil && len(pc.moreComments.Children) > 0 +// HasMore determines whether the post has more replies to load in its reply tree. +func (pc *PostAndComments) HasMore() bool { + return pc.MoreComments != nil && len(pc.MoreComments.Children) > 0 +} + +func (pc *PostAndComments) addCommentToTree(comment *Comment) { + if pc.Post.FullID == comment.ParentID { + pc.Comments = append(pc.Comments, comment) + return + } + + for _, reply := range pc.Comments { + reply.addCommentToReplies(comment) + } +} + +func (pc *PostAndComments) addMoreToTree(more *More) { + if pc.Post.FullID == more.ParentID { + pc.MoreComments = more + } + + for _, reply := range pc.Comments { + reply.addMoreToReplies(more) + } }