- removed ioutils in some spots

- fixed rate limit headers
- added poll data to post
- changed random os to windows for surf client
This commit is contained in:
2026-05-25 16:21:13 -05:00
parent 76c46f0a0d
commit d4a435b52f
2 changed files with 49 additions and 33 deletions
+20 -32
View File
@@ -2,12 +2,10 @@ package reddit
import ( import (
"bytes" "bytes"
"compress/gzip"
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"reflect" "reflect"
@@ -36,9 +34,9 @@ const (
headerAccept = "Accept" headerAccept = "Accept"
headerUserAgent = "User-Agent" headerUserAgent = "User-Agent"
headerRateLimitRemaining = "x-ratelimit-remaining" headerRateLimitRemaining = "X-Ratelimit-Remaining"
headerRateLimitUsed = "x-ratelimit-used" headerRateLimitUsed = "X-Ratelimit-Used"
headerRateLimitReset = "x-ratelimit-reset" headerRateLimitReset = "X-Ratelimit-Reset"
) )
var defaultClient, _ = NewReadonlyClient() var defaultClient, _ = NewReadonlyClient()
@@ -115,13 +113,14 @@ func newClient() *Client {
surf_client := surf.NewClient(). surf_client := surf.NewClient().
Builder(). Builder().
Impersonate(). Impersonate().
RandomOS(). Windows().
Firefox(). Firefox().
Session(). Session().
Build(). Build().
Unwrap() Unwrap().
Std()
client := &Client{client: surf_client.Std(), BaseURL: baseURL, TokenURL: tokenURL} client := &Client{client: surf_client, BaseURL: baseURL, TokenURL: tokenURL}
client.Account = &AccountService{client: client} client.Account = &AccountService{client: client}
client.Collection = &CollectionService{client: client} client.Collection = &CollectionService{client: client}
@@ -377,32 +376,21 @@ func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Res
return response, err return response, err
} }
body, err := ResponseReader(resp)
if err != nil {
return response, err
}
w, ok := v.(io.Writer) w, ok := v.(io.Writer)
if ok { if ok {
_, err = io.Copy(w, response.Body) _, err = io.Copy(w, body)
if err != nil { if err != nil {
return response, err return response, err
} }
} else { } else {
if response.Header.Get("Content-Encoding") == "gzip" { err = json.NewDecoder(body).Decode(v)
gzipReader, err := gzip.NewReader(resp.Body) if err != nil {
if err != nil { return response, err
return response, fmt.Errorf("Error creating gzip reader: %s", err)
}
defer gzipReader.Close()
b, err := io.ReadAll(gzipReader)
if err != nil {
return response, fmt.Errorf("Error decoding gzip json: %s", err)
}
err = json.Unmarshal(b, v)
if err != nil {
return response, fmt.Errorf("Error unmarshalling json: %s", err)
}
} else {
err = json.NewDecoder(response.Body).Decode(v)
if err != nil {
return response, err
}
} }
} }
@@ -425,7 +413,7 @@ func (c *Client) checkRateLimitBeforeDo(req *http.Request) *RateLimitError {
StatusCode: http.StatusTooManyRequests, StatusCode: http.StatusTooManyRequests,
Request: req, Request: req,
Header: make(http.Header), Header: make(http.Header),
Body: ioutil.NopCloser(strings.NewReader("")), Body: io.NopCloser(strings.NewReader("")),
} }
return &RateLimitError{ return &RateLimitError{
Rate: rate, Rate: rate,
@@ -478,7 +466,7 @@ func CheckResponse(r *http.Response) error {
jsonErrorResponse := &JSONErrorResponse{Response: r} jsonErrorResponse := &JSONErrorResponse{Response: r}
data, err := ioutil.ReadAll(r.Body) data, err := io.ReadAll(r.Body)
if err == nil && len(data) > 0 { if err == nil && len(data) > 0 {
json.Unmarshal(data, jsonErrorResponse) json.Unmarshal(data, jsonErrorResponse)
if len(jsonErrorResponse.JSON.Errors) > 0 { if len(jsonErrorResponse.JSON.Errors) > 0 {
@@ -487,14 +475,14 @@ func CheckResponse(r *http.Response) error {
} }
// reset response body // reset response body
r.Body = ioutil.NopCloser(bytes.NewBuffer(data)) r.Body = io.NopCloser(bytes.NewBuffer(data))
if c := r.StatusCode; c >= 200 && c <= 299 { if c := r.StatusCode; c >= 200 && c <= 299 {
return nil return nil
} }
errorResponse := &ErrorResponse{Response: r} errorResponse := &ErrorResponse{Response: r}
data, err = ioutil.ReadAll(r.Body) data, err = io.ReadAll(r.Body)
if err == nil && len(data) > 0 { if err == nil && len(data) > 0 {
err := json.Unmarshal(data, errorResponse) err := json.Unmarshal(data, errorResponse)
if err != nil { if err != nil {
+29 -1
View File
@@ -434,6 +434,10 @@ type Comment struct {
CanGild bool `json:"can_gild"` CanGild bool `json:"can_gild"`
NSFW bool `json:"over_18"` NSFW bool `json:"over_18"`
Distinguished string `json:"distinguished"`
Depth int `json:"depth"`
BodyHtml string `json:"body_html"`
Replies Replies `json:"replies"` Replies Replies `json:"replies"`
} }
@@ -442,6 +446,11 @@ func (c *Comment) HasMore() bool {
return c.Replies.More != nil && len(c.Replies.More.Children) > 0 return c.Replies.More != nil && len(c.Replies.More.Children) > 0
} }
// Denotes whether the comment was written by a moderator
func (c *Comment) IsModerator() bool {
return c.Distinguished == "moderator"
}
// addCommentToReplies traverses the comment tree to find the one // addCommentToReplies traverses the comment tree to find the one
// that the 2nd comment is replying to. It then adds it to its replies. // that the 2nd comment is replying to. It then adds it to its replies.
func (c *Comment) addCommentToReplies(comment *Comment) { func (c *Comment) addCommentToReplies(comment *Comment) {
@@ -569,13 +578,32 @@ type Post struct {
PollData *PollData `json:"poll_data"` PollData *PollData `json:"poll_data"`
} }
type PollData struct { type PollDataInner struct {
Timestamp int `json:"voting_end_timestamp"` Timestamp int `json:"voting_end_timestamp"`
Options []PollOption `json:"options"` Options []PollOption `json:"options"`
IsPrediction bool `json:"is_prediction"` IsPrediction bool `json:"is_prediction"`
TotalVoteCount int `json:"total_vote_count"` TotalVoteCount int `json:"total_vote_count"`
} }
type PollData struct {
PollDataInner
}
func (d *PollData) UnmarshalJSON(data []byte) error {
var junk bool
err := json.Unmarshal(data, &junk)
if err == nil {
return nil
}
inner := new(PollDataInner)
err = json.Unmarshal(data, inner)
if err != nil {
return err
}
d.PollDataInner = *inner
return nil
}
type PollOption struct { type PollOption struct {
Text string `json:"text"` Text string `json:"text"`
Id string `json:"id"` Id string `json:"id"`