Get post/comments, unmarshal list of comments (replies)
Signed-off-by: Vartan Benohanian <vartanbeno@gmail.com>
This commit is contained in:
@@ -274,18 +274,52 @@ func DoRequestWithClient(ctx context.Context, client *http.Client, req *http.Req
|
|||||||
// JSONErrorResponse is an error response that sometimes gets returned with a 200 code
|
// JSONErrorResponse is an error response that sometimes gets returned with a 200 code
|
||||||
type JSONErrorResponse struct {
|
type JSONErrorResponse struct {
|
||||||
// HTTP response that caused this error
|
// HTTP response that caused this error
|
||||||
Response *http.Response
|
Response *http.Response `json:"-"`
|
||||||
|
|
||||||
JSON *struct {
|
JSON *struct {
|
||||||
Errors [][]string `json:"errors,omitempty"`
|
Errors []RedditError `json:"errors,omitempty"`
|
||||||
} `json:"json,omitempty"`
|
} `json:"json,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RedditError is an error coming from Reddit
|
||||||
|
type RedditError struct {
|
||||||
|
Label string
|
||||||
|
Reason string
|
||||||
|
Field string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *RedditError) Error() string {
|
||||||
|
return fmt.Sprintf("%s: %s because of field %q", e.Label, e.Reason, e.Field)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
|
func (e *RedditError) UnmarshalJSON(data []byte) error {
|
||||||
|
var info []string
|
||||||
|
|
||||||
|
err := json.Unmarshal(data, &info)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(info) != 3 {
|
||||||
|
return fmt.Errorf("got unexpected Reddit error: %v", info)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Label = info[0]
|
||||||
|
e.Reason = info[1]
|
||||||
|
e.Field = info[2]
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *JSONErrorResponse) Error() string {
|
func (r *JSONErrorResponse) Error() string {
|
||||||
var message string
|
var message string
|
||||||
if r.JSON != nil && len(r.JSON.Errors) > 0 {
|
if r.JSON != nil && len(r.JSON.Errors) > 0 {
|
||||||
for _, errList := range r.JSON.Errors {
|
for i, err := range r.JSON.Errors {
|
||||||
message += strings.Join(errList, ", ")
|
message += err.Error()
|
||||||
|
if i < len(r.JSON.Errors)-1 {
|
||||||
|
message += ";"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
|
|||||||
+20
-2
@@ -13,6 +13,7 @@ import (
|
|||||||
type ListingsService interface {
|
type ListingsService interface {
|
||||||
Get(ctx context.Context, ids ...string) ([]Comment, []Link, []Subreddit, *Response, error)
|
Get(ctx context.Context, ids ...string) ([]Comment, []Link, []Subreddit, *Response, error)
|
||||||
GetLinks(ctx context.Context, ids ...string) ([]Link, *Response, error)
|
GetLinks(ctx context.Context, ids ...string) ([]Link, *Response, error)
|
||||||
|
GetLink(ctx context.Context, id string) (*LinkAndComments, *Response, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListingsServiceOp implements the Vote interface
|
// ListingsServiceOp implements the Vote interface
|
||||||
@@ -22,7 +23,7 @@ type ListingsServiceOp struct {
|
|||||||
|
|
||||||
var _ ListingsService = &ListingsServiceOp{}
|
var _ ListingsService = &ListingsServiceOp{}
|
||||||
|
|
||||||
// Get returns comments, link, and subreddits from their IDs
|
// Get returns comments, links, and subreddits from their IDs
|
||||||
func (s *ListingsServiceOp) Get(ctx context.Context, ids ...string) ([]Comment, []Link, []Subreddit, *Response, error) {
|
func (s *ListingsServiceOp) Get(ctx context.Context, ids ...string) ([]Comment, []Link, []Subreddit, *Response, error) {
|
||||||
type query struct {
|
type query struct {
|
||||||
IDs []string `url:"id,comma"`
|
IDs []string `url:"id,comma"`
|
||||||
@@ -52,7 +53,7 @@ func (s *ListingsServiceOp) Get(ctx context.Context, ids ...string) ([]Comment,
|
|||||||
return comments, links, subreddits, resp, nil
|
return comments, links, subreddits, resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLinks returns links from their IDs
|
// GetLinks returns links from their full IDs
|
||||||
func (s *ListingsServiceOp) GetLinks(ctx context.Context, ids ...string) ([]Link, *Response, error) {
|
func (s *ListingsServiceOp) GetLinks(ctx context.Context, ids ...string) ([]Link, *Response, error) {
|
||||||
if len(ids) == 0 {
|
if len(ids) == 0 {
|
||||||
return nil, nil, errors.New("must provide at least 1 id")
|
return nil, nil, errors.New("must provide at least 1 id")
|
||||||
@@ -72,3 +73,20 @@ func (s *ListingsServiceOp) GetLinks(ctx context.Context, ids ...string) ([]Link
|
|||||||
|
|
||||||
return root.getLinks().Links, resp, nil
|
return root.getLinks().Links, resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLink returns a link with its comments
|
||||||
|
func (s *ListingsServiceOp) GetLink(ctx context.Context, id string) (*LinkAndComments, *Response, error) {
|
||||||
|
path := fmt.Sprintf("comments/%s", id)
|
||||||
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(LinkAndComments)
|
||||||
|
resp, err := s.client.Do(ctx, req, root)
|
||||||
|
if err != nil {
|
||||||
|
return nil, resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return root, resp, nil
|
||||||
|
}
|
||||||
|
|||||||
+68
-206
@@ -7,13 +7,12 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SubredditService handles communication with the subreddit
|
// SubredditService handles communication with the subreddit
|
||||||
// related methods of the Reddit API
|
// related methods of the Reddit API
|
||||||
type SubredditService interface {
|
type SubredditService interface {
|
||||||
GetByName(ctx context.Context, name string) (*Subreddit, *Response, error)
|
GetByName(ctx context.Context, subreddit string) (*Subreddit, *Response, error)
|
||||||
|
|
||||||
GetPopular(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
|
GetPopular(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
|
||||||
GetNew(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
|
GetNew(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
|
||||||
@@ -25,22 +24,20 @@ type SubredditService interface {
|
|||||||
GetMineWhereModerator(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
|
GetMineWhereModerator(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
|
||||||
GetMineWhereStreams(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
|
GetMineWhereStreams(ctx context.Context, opts *ListOptions) (*Subreddits, *Response, error)
|
||||||
|
|
||||||
GetHotLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error)
|
GetHotLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error)
|
||||||
GetBestLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error)
|
GetBestLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error)
|
||||||
GetNewLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error)
|
GetNewLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error)
|
||||||
GetRisingLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error)
|
GetRisingLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error)
|
||||||
GetControversialLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error)
|
GetControversialLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error)
|
||||||
GetTopLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error)
|
GetTopLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error)
|
||||||
|
|
||||||
// GetSticky1(ctx context.Context, name string) (interface{}, *Response, error)
|
GetSticky1(ctx context.Context, subreddit string) (*LinkAndComments, *Response, error)
|
||||||
// GetSticky2(ctx context.Context, name string) (interface{}, *Response, error)
|
GetSticky2(ctx context.Context, subreddit string) (*LinkAndComments, *Response, error)
|
||||||
|
|
||||||
Subscribe(ctx context.Context, names ...string) (*Response, error)
|
Subscribe(ctx context.Context, subreddits ...string) (*Response, error)
|
||||||
SubscribeByID(ctx context.Context, ids ...string) (*Response, error)
|
SubscribeByID(ctx context.Context, ids ...string) (*Response, error)
|
||||||
Unsubscribe(ctx context.Context, names ...string) (*Response, error)
|
Unsubscribe(ctx context.Context, subreddits ...string) (*Response, error)
|
||||||
UnsubscribeByID(ctx context.Context, ids ...string) (*Response, error)
|
UnsubscribeByID(ctx context.Context, ids ...string) (*Response, error)
|
||||||
|
|
||||||
StreamLinks(ctx context.Context, names ...string) (<-chan Link, chan<- bool, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubredditServiceOp implements the SubredditService interface
|
// SubredditServiceOp implements the SubredditService interface
|
||||||
@@ -51,12 +48,12 @@ type SubredditServiceOp struct {
|
|||||||
var _ SubredditService = &SubredditServiceOp{}
|
var _ SubredditService = &SubredditServiceOp{}
|
||||||
|
|
||||||
// GetByName gets a subreddit by name
|
// GetByName gets a subreddit by name
|
||||||
func (s *SubredditServiceOp) GetByName(ctx context.Context, name string) (*Subreddit, *Response, error) {
|
func (s *SubredditServiceOp) GetByName(ctx context.Context, subreddit string) (*Subreddit, *Response, error) {
|
||||||
if name == "" {
|
if subreddit == "" {
|
||||||
return nil, nil, errors.New("empty subreddit name provided")
|
return nil, nil, errors.New("empty subreddit name provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
path := fmt.Sprintf("r/%s/about", name)
|
path := fmt.Sprintf("r/%s/about", subreddit)
|
||||||
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -112,68 +109,61 @@ func (s *SubredditServiceOp) GetMineWhereStreams(ctx context.Context, opts *List
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetHotLinks returns the hot links
|
// GetHotLinks returns the hot links
|
||||||
// If no subreddit names are provided, then it runs the search against all those the client is subscribed to
|
// If no subreddit are provided, then it runs the search against all those the client is subscribed to
|
||||||
// IMPORTANT: for subreddits, this will include the stickied posts (if any)
|
// IMPORTANT: for subreddits, this will include the stickied posts (if any)
|
||||||
// PLUS the number of posts from the limit parameter (which is 25 by default)
|
// PLUS the number of posts from the limit parameter (which is 25 by default)
|
||||||
func (s *SubredditServiceOp) GetHotLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) {
|
func (s *SubredditServiceOp) GetHotLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) {
|
||||||
return s.getLinks(ctx, sortHot, opts, names...)
|
return s.getLinks(ctx, sortHot, opts, subreddits...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBestLinks returns the best links
|
// GetBestLinks returns the best links
|
||||||
// If no subreddit names are provided, then it runs the search against all those the client is subscribed to
|
// If no subreddit are provided, then it runs the search against all those the client is subscribed to
|
||||||
// IMPORTANT: for subreddits, this will include the stickied posts (if any)
|
// IMPORTANT: for subreddits, this will include the stickied posts (if any)
|
||||||
// PLUS the number of posts from the limit parameter (which is 25 by default)
|
// PLUS the number of posts from the limit parameter (which is 25 by default)
|
||||||
func (s *SubredditServiceOp) GetBestLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) {
|
func (s *SubredditServiceOp) GetBestLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) {
|
||||||
return s.getLinks(ctx, sortBest, opts, names...)
|
return s.getLinks(ctx, sortBest, opts, subreddits...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNewLinks returns the new links
|
// GetNewLinks returns the new links
|
||||||
// If no subreddit names are provided, then it runs the search against all those the client is subscribed to
|
// If no subreddit are provided, then it runs the search against all those the client is subscribed to
|
||||||
func (s *SubredditServiceOp) GetNewLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) {
|
func (s *SubredditServiceOp) GetNewLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) {
|
||||||
return s.getLinks(ctx, sortNew, opts, names...)
|
return s.getLinks(ctx, sortNew, opts, subreddits...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRisingLinks returns the rising links
|
// GetRisingLinks returns the rising links
|
||||||
// If no subreddit names are provided, then it runs the search against all those the client is subscribed to
|
// If no subreddit are provided, then it runs the search against all those the client is subscribed to
|
||||||
func (s *SubredditServiceOp) GetRisingLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) {
|
func (s *SubredditServiceOp) GetRisingLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) {
|
||||||
return s.getLinks(ctx, sortRising, opts, names...)
|
return s.getLinks(ctx, sortRising, opts, subreddits...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetControversialLinks returns the controversial links
|
// GetControversialLinks returns the controversial links
|
||||||
// If no subreddit names are provided, then it runs the search against all those the client is subscribed to
|
// If no subreddit are provided, then it runs the search against all those the client is subscribed to
|
||||||
func (s *SubredditServiceOp) GetControversialLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) {
|
func (s *SubredditServiceOp) GetControversialLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) {
|
||||||
return s.getLinks(ctx, sortControversial, opts, names...)
|
return s.getLinks(ctx, sortControversial, opts, subreddits...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTopLinks returns the top links
|
// GetTopLinks returns the top links
|
||||||
// If no subreddit names are provided, then it runs the search against all those the client is subscribed to
|
// If no subreddit are provided, then it runs the search against all those the client is subscribed to
|
||||||
func (s *SubredditServiceOp) GetTopLinks(ctx context.Context, opts *ListOptions, names ...string) (*Links, *Response, error) {
|
func (s *SubredditServiceOp) GetTopLinks(ctx context.Context, opts *ListOptions, subreddits ...string) (*Links, *Response, error) {
|
||||||
return s.getLinks(ctx, sortTop, opts, names...)
|
return s.getLinks(ctx, sortTop, opts, subreddits...)
|
||||||
}
|
}
|
||||||
|
|
||||||
type sticky int
|
// GetSticky1 returns the first stickied post on a subreddit (if it exists)
|
||||||
|
func (s *SubredditServiceOp) GetSticky1(ctx context.Context, name string) (*LinkAndComments, *Response, error) {
|
||||||
|
return s.getSticky(ctx, name, sticky1)
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
// GetSticky2 returns the second stickied post on a subreddit (if it exists)
|
||||||
sticky1 sticky = iota + 1
|
func (s *SubredditServiceOp) GetSticky2(ctx context.Context, name string) (*LinkAndComments, *Response, error) {
|
||||||
sticky2
|
return s.getSticky(ctx, name, sticky2)
|
||||||
)
|
}
|
||||||
|
|
||||||
// // GetSticky1 returns the first stickied post on a subreddit (if it exists)
|
// Subscribe subscribes to subreddits based on their names
|
||||||
// func (s *SubredditServiceOp) GetSticky1(ctx context.Context, name string) (interface{}, *Response, error) {
|
|
||||||
// return s.getSticky(ctx, name, sticky1)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // GetSticky2 returns the second stickied post on a subreddit (if it exists)
|
|
||||||
// func (s *SubredditServiceOp) GetSticky2(ctx context.Context, name string) (interface{}, *Response, error) {
|
|
||||||
// return s.getSticky(ctx, name, sticky2)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Subscribe subscribes to subreddits based on their name
|
|
||||||
// Returns {} on success
|
// Returns {} on success
|
||||||
func (s *SubredditServiceOp) Subscribe(ctx context.Context, names ...string) (*Response, error) {
|
func (s *SubredditServiceOp) Subscribe(ctx context.Context, subreddits ...string) (*Response, error) {
|
||||||
form := url.Values{}
|
form := url.Values{}
|
||||||
form.Set("action", "sub")
|
form.Set("action", "sub")
|
||||||
form.Set("sr_name", strings.Join(names, ","))
|
form.Set("sr_name", strings.Join(subreddits, ","))
|
||||||
return s.handleSubscription(ctx, form)
|
return s.handleSubscription(ctx, form)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,12 +176,12 @@ func (s *SubredditServiceOp) SubscribeByID(ctx context.Context, ids ...string) (
|
|||||||
return s.handleSubscription(ctx, form)
|
return s.handleSubscription(ctx, form)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsubscribe unsubscribes from subreddits
|
// Unsubscribe unsubscribes from subreddits based on their names
|
||||||
// Returns {} on success
|
// Returns {} on success
|
||||||
func (s *SubredditServiceOp) Unsubscribe(ctx context.Context, names ...string) (*Response, error) {
|
func (s *SubredditServiceOp) Unsubscribe(ctx context.Context, subreddits ...string) (*Response, error) {
|
||||||
form := url.Values{}
|
form := url.Values{}
|
||||||
form.Set("action", "unsub")
|
form.Set("action", "unsub")
|
||||||
form.Set("sr_name", strings.Join(names, ","))
|
form.Set("sr_name", strings.Join(subreddits, ","))
|
||||||
return s.handleSubscription(ctx, form)
|
return s.handleSubscription(ctx, form)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,10 +237,10 @@ func (s *SubredditServiceOp) getSubreddits(ctx context.Context, path string, opt
|
|||||||
return l, resp, nil
|
return l, resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SubredditServiceOp) getLinks(ctx context.Context, sort sort, opts *ListOptions, names ...string) (*Links, *Response, error) {
|
func (s *SubredditServiceOp) getLinks(ctx context.Context, sort sort, opts *ListOptions, subreddits ...string) (*Links, *Response, error) {
|
||||||
path := sorts[sort]
|
path := sorts[sort]
|
||||||
if len(names) > 0 {
|
if len(subreddits) > 0 {
|
||||||
path = fmt.Sprintf("r/%s/%s", strings.Join(names, "+"), sorts[sort])
|
path = fmt.Sprintf("r/%s/%s", strings.Join(subreddits, "+"), sorts[sort])
|
||||||
}
|
}
|
||||||
|
|
||||||
path, err := addOptions(path, opts)
|
path, err := addOptions(path, opts)
|
||||||
@@ -280,159 +270,31 @@ func (s *SubredditServiceOp) getLinks(ctx context.Context, sort sort, opts *List
|
|||||||
return l, resp, nil
|
return l, resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getSticky returns one of the 2 stickied posts of the subreddit
|
// getSticky returns one of the 2 stickied posts of the subreddit (if they exist)
|
||||||
// Num should be equal to 1 or 2, depending on which one you want
|
// Num should be equal to 1 or 2, depending on which one you want
|
||||||
// If it's <= 1, it's 1
|
// If it's <= 1, it's 1
|
||||||
// If it's >= 2, it's 2
|
// If it's >= 2, it's 2
|
||||||
// todo
|
func (s *SubredditServiceOp) getSticky(ctx context.Context, subreddit string, num sticky) (*LinkAndComments, *Response, error) {
|
||||||
// func (s *SubredditServiceOp) getSticky(ctx context.Context, name string, num sticky) (interface{}, *Response, error) {
|
type query struct {
|
||||||
// type query struct {
|
Num sticky `url:"num"`
|
||||||
// Num sticky `url:"num"`
|
|
||||||
// }
|
|
||||||
|
|
||||||
// path := fmt.Sprintf("r/%s/about/sticky", name)
|
|
||||||
// path, err := addOptions(path, query{num})
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, nil, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, nil, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var root []rootListing
|
|
||||||
// resp, err := s.client.Do(ctx, req, &root)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, resp, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // test, _ := json.MarshalIndent(root, "", " ")
|
|
||||||
// // fmt.Println(string(test))
|
|
||||||
|
|
||||||
// linkRoot := new(linkRoot)
|
|
||||||
|
|
||||||
// link := root[0].Data.Children[0]
|
|
||||||
// byteValue, err := json.Marshal(link)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, resp, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// err = json.Unmarshal(byteValue, linkRoot)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, resp, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // these are all the comments in the post
|
|
||||||
// comments := root[1].Data.Children
|
|
||||||
|
|
||||||
// var commentsRoot []commentRoot
|
|
||||||
// byteValue, err = json.Marshal(comments)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, resp, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// err = json.Unmarshal(byteValue, &commentsRoot)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, resp, err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// test, _ := json.MarshalIndent(commentsRoot, "", " ")
|
|
||||||
// fmt.Println(string(test))
|
|
||||||
|
|
||||||
// for _, comment := range commentsRoot {
|
|
||||||
// if string(comment.Data.RepliesRaw) == `""` {
|
|
||||||
// comment.Data.Replies = nil
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // var
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return commentsRoot, resp, nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func handleComments(comments []commentRoot) {
|
|
||||||
// for _, comment := range comments {
|
|
||||||
// if string(comment.Data.RepliesRaw) == `""` {
|
|
||||||
// comment.Data.Replies = nil
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// StreamLinks returns a channel that receives new submissions from the subreddits
|
|
||||||
// To stop the stream, simply send a bool value to the stop channel
|
|
||||||
func (s *SubredditServiceOp) StreamLinks(ctx context.Context, names ...string) (<-chan Link, chan<- bool, error) {
|
|
||||||
if len(names) == 0 {
|
|
||||||
return nil, nil, errors.New("must specify at least one subreddit")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
submissionCh := make(chan Link)
|
path := fmt.Sprintf("r/%s/about/sticky", subreddit)
|
||||||
stop := make(chan bool, 1)
|
path, err := addOptions(path, query{num})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
||||||
// todo: if the post with the before gets deleted, you keep getting 0 posts
|
if err != nil {
|
||||||
var last *Timestamp
|
return nil, nil, err
|
||||||
for {
|
}
|
||||||
select {
|
|
||||||
case <-stop:
|
|
||||||
close(submissionCh)
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
sl, _, err := s.GetNewLinks(ctx, nil, names...)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var newest *Timestamp
|
root := new(LinkAndComments)
|
||||||
for i, submission := range sl.Links {
|
resp, err := s.client.Do(ctx, req, root)
|
||||||
if i == 0 {
|
if err != nil {
|
||||||
newest = submission.Created
|
return nil, resp, err
|
||||||
}
|
}
|
||||||
if last == nil {
|
|
||||||
submissionCh <- submission
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if last.Before(*submission.Created) {
|
|
||||||
submissionCh <- submission
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last = newest
|
|
||||||
}
|
|
||||||
<-time.After(time.Second * 3)
|
|
||||||
fmt.Println()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// go func() {
|
return root, resp, nil
|
||||||
// var before string
|
|
||||||
// for {
|
|
||||||
// select {
|
|
||||||
// case <-stop:
|
|
||||||
// close(submissionCh)
|
|
||||||
// return
|
|
||||||
// default:
|
|
||||||
// sl, _, err := s.GetSubmissions(ctx, SortNew, &ListOptions{Before: before}, names...)
|
|
||||||
// if err != nil {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
// fmt.Printf("Received %d posts\n", len(sl.Submissions))
|
|
||||||
|
|
||||||
// if len(sl.Submissions) == 0 {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for _, submission := range sl.Submissions {
|
|
||||||
// submissionCh <- submission
|
|
||||||
// }
|
|
||||||
// before = sl.Submissions[0].FullID
|
|
||||||
// }
|
|
||||||
// <-time.After(time.Second * 5)
|
|
||||||
// fmt.Println()
|
|
||||||
// }
|
|
||||||
// }()
|
|
||||||
|
|
||||||
return submissionCh, stop, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package geddit
|
package geddit
|
||||||
|
|
||||||
import "encoding/json"
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
kindComment = "t1"
|
kindComment = "t1"
|
||||||
@@ -40,6 +43,13 @@ var sorts = [...]string{
|
|||||||
"comments",
|
"comments",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type sticky int
|
||||||
|
|
||||||
|
const (
|
||||||
|
sticky1 sticky = iota + 1
|
||||||
|
sticky2
|
||||||
|
)
|
||||||
|
|
||||||
type root struct {
|
type root struct {
|
||||||
Kind string `json:"kind,omitempty"`
|
Kind string `json:"kind,omitempty"`
|
||||||
Data interface{} `json:"data,omitempty"`
|
Data interface{} `json:"data,omitempty"`
|
||||||
@@ -97,6 +107,7 @@ func (l *Things) UnmarshalJSON(b []byte) error {
|
|||||||
for _, child := range children {
|
for _, child := range children {
|
||||||
byteValue, _ := json.Marshal(child)
|
byteValue, _ := json.Marshal(child)
|
||||||
switch child["kind"] {
|
switch child["kind"] {
|
||||||
|
// todo: kindMore
|
||||||
case kindComment:
|
case kindComment:
|
||||||
root := new(commentRoot)
|
root := new(commentRoot)
|
||||||
if err := json.Unmarshal(byteValue, root); err == nil && root.Data != nil {
|
if err := json.Unmarshal(byteValue, root); err == nil && root.Data != nil {
|
||||||
@@ -168,12 +179,27 @@ type Comment struct {
|
|||||||
CanGild bool `json:"can_gild"`
|
CanGild bool `json:"can_gild"`
|
||||||
NSFW bool `json:"over_18"`
|
NSFW bool `json:"over_18"`
|
||||||
|
|
||||||
// If a comment has no replies, its "replies" value is "",
|
Replies Replies `json:"replies"`
|
||||||
// which the unmarshaler doesn't like
|
}
|
||||||
// So we capture this varying field in RepliesRaw, and then
|
|
||||||
// fill it in Replies
|
// Replies are replies to a comment
|
||||||
RepliesRaw json.RawMessage `json:"replies,omitempty"`
|
type Replies []Comment
|
||||||
Replies []commentRoot `json:"-"`
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
|
func (r *Replies) UnmarshalJSON(data []byte) error {
|
||||||
|
// if a comment has no replies, its "replies" field is set to ""
|
||||||
|
if string(data) == `""` {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
root := new(rootListing)
|
||||||
|
err := json.Unmarshal(data, root)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*r = root.getComments().Comments
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link is a submitted post on Reddit
|
// Link is a submitted post on Reddit
|
||||||
@@ -328,3 +354,34 @@ type CommentsLinksSubreddits struct {
|
|||||||
Links []Link `json:"links,omitempty"`
|
Links []Link `json:"links,omitempty"`
|
||||||
Subreddits []Subreddit `json:"subreddits,omitempty"`
|
Subreddits []Subreddit `json:"subreddits,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LinkAndComments is a link and its comments
|
||||||
|
type LinkAndComments struct {
|
||||||
|
Link Link `json:"link,omitempty"`
|
||||||
|
Comments []Comment `json:"comments,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||||
|
// When getting a sticky post, you get an array of 2 Listings
|
||||||
|
// The 1st one contains the single post in its children array
|
||||||
|
// The 2nd one contains the comments to the post
|
||||||
|
func (rl *LinkAndComments) UnmarshalJSON(data []byte) error {
|
||||||
|
var l []rootListing
|
||||||
|
|
||||||
|
err := json.Unmarshal(data, &l)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(l) < 2 {
|
||||||
|
return errors.New("unexpected json response when getting link")
|
||||||
|
}
|
||||||
|
|
||||||
|
stickyLink := l[0].getLinks().Links[0]
|
||||||
|
stickyComments := l[1].getComments().Comments
|
||||||
|
|
||||||
|
rl.Link = stickyLink
|
||||||
|
rl.Comments = stickyComments
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user