2020-07-11 13:49:07 -04:00
|
|
|
package reddit
|
2020-04-23 22:57:47 -04:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
2020-05-03 17:31:35 -04:00
|
|
|
"net/url"
|
2020-04-29 15:59:18 -04:00
|
|
|
"strings"
|
2020-04-23 22:57:47 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// SubredditService handles communication with the subreddit
|
2020-06-27 23:53:59 -04:00
|
|
|
// related methods of the Reddit API.
|
|
|
|
//
|
|
|
|
// Reddit API docs: https://www.reddit.com/dev/api/#section_subreddits
|
2020-07-21 23:05:24 -04:00
|
|
|
type SubredditService struct {
|
|
|
|
client *Client
|
|
|
|
}
|
2020-04-23 22:57:47 -04:00
|
|
|
|
2020-07-12 22:53:19 -04:00
|
|
|
type rootSubreddit struct {
|
|
|
|
Kind string `json:"kind,omitempty"`
|
|
|
|
Data *Subreddit `json:"data,omitempty"`
|
|
|
|
}
|
|
|
|
|
2020-07-21 23:59:53 -04:00
|
|
|
type rootSubredditNames struct {
|
|
|
|
Names []string `json:"names,omitempty"`
|
|
|
|
}
|
|
|
|
|
2020-08-11 14:51:47 -04:00
|
|
|
// Relationship holds information about a relationship (friend/blocked).
|
|
|
|
type Relationship struct {
|
|
|
|
ID string `json:"rel_id,omitempty"`
|
|
|
|
User string `json:"name,omitempty"`
|
|
|
|
UserID string `json:"id,omitempty"`
|
|
|
|
Created *Timestamp `json:"date,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Relationships is a listing of relationships.
|
|
|
|
type Relationships struct {
|
|
|
|
Relationships []*Relationship `json:"relationships"`
|
|
|
|
After string `json:"after"`
|
|
|
|
Before string `json:"before"`
|
2020-07-11 23:26:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Moderator is a user who moderates a subreddit.
|
|
|
|
type Moderator struct {
|
2020-08-11 14:51:47 -04:00
|
|
|
*Relationship
|
2020-07-11 23:26:14 -04:00
|
|
|
Permissions []string `json:"mod_permissions"`
|
|
|
|
}
|
|
|
|
|
2020-08-11 14:51:47 -04:00
|
|
|
// Ban represents a banned relationship.
|
2020-08-11 00:44:19 -04:00
|
|
|
type Ban struct {
|
2020-08-11 14:51:47 -04:00
|
|
|
*Relationship
|
2020-08-11 00:44:19 -04:00
|
|
|
// nil means the ban is permanent
|
|
|
|
DaysLeft *int `json:"days_left"`
|
|
|
|
Note string `json:"note,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bans is a listing of bans.
|
|
|
|
type Bans struct {
|
|
|
|
Bans []*Ban `json:"bans"`
|
|
|
|
After string `json:"after"`
|
|
|
|
Before string `json:"before"`
|
|
|
|
}
|
|
|
|
|
2020-08-22 00:32:59 -04:00
|
|
|
// todo: interface{}, seriously?
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) getPosts(ctx context.Context, sort string, subreddit string, opts interface{}) ([]*Post, *Response, error) {
|
2020-07-28 11:01:50 -04:00
|
|
|
path := sort
|
2020-08-02 13:42:53 -04:00
|
|
|
if subreddit != "" {
|
|
|
|
path = fmt.Sprintf("r/%s/%s", subreddit, sort)
|
2020-07-25 00:08:28 -04:00
|
|
|
}
|
|
|
|
|
2020-08-05 13:25:09 -04:00
|
|
|
path, err := addOptions(path, opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2020-07-25 00:08:28 -04:00
|
|
|
|
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-29 14:20:30 -04:00
|
|
|
root := new(listing)
|
2020-07-25 00:08:28 -04:00
|
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
|
|
if err != nil {
|
|
|
|
return nil, resp, err
|
|
|
|
}
|
|
|
|
|
2020-08-29 14:20:30 -04:00
|
|
|
return root.Posts, resp, nil
|
2020-07-25 00:08:28 -04:00
|
|
|
}
|
|
|
|
|
2020-08-04 16:42:42 -04:00
|
|
|
// HotPosts returns the hottest posts from the specified subreddit.
|
2020-08-02 13:42:53 -04:00
|
|
|
// To search through multiple, separate the names with a plus (+), e.g. "golang+test".
|
2020-07-25 00:08:28 -04:00
|
|
|
// If none are defined, it returns the ones from your subscribed subreddits.
|
2020-08-21 15:31:15 -04:00
|
|
|
// To search through all, just specify "all".
|
|
|
|
// To search through all and filter out subreddits, provide "all-name1-name2".
|
2020-07-25 00:08:28 -04:00
|
|
|
// Note: when looking for hot posts in a subreddit, it will include the stickied
|
|
|
|
// posts (if any) PLUS posts from the limit parameter (25 by default).
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) HotPosts(ctx context.Context, subreddit string, opts *ListOptions) ([]*Post, *Response, error) {
|
2020-08-05 13:25:09 -04:00
|
|
|
return s.getPosts(ctx, "hot", subreddit, opts)
|
2020-07-25 00:08:28 -04:00
|
|
|
}
|
|
|
|
|
2020-08-04 16:42:42 -04:00
|
|
|
// NewPosts returns the newest posts from the specified subreddit.
|
2020-08-02 13:42:53 -04:00
|
|
|
// To search through multiple, separate the names with a plus (+), e.g. "golang+test".
|
2020-07-25 00:08:28 -04:00
|
|
|
// If none are defined, it returns the ones from your subscribed subreddits.
|
2020-08-21 15:31:15 -04:00
|
|
|
// To search through all, just specify "all".
|
|
|
|
// To search through all and filter out subreddits, provide "all-name1-name2".
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) NewPosts(ctx context.Context, subreddit string, opts *ListOptions) ([]*Post, *Response, error) {
|
2020-08-05 13:25:09 -04:00
|
|
|
return s.getPosts(ctx, "new", subreddit, opts)
|
2020-07-25 00:08:28 -04:00
|
|
|
}
|
|
|
|
|
2020-08-04 16:42:42 -04:00
|
|
|
// RisingPosts returns the rising posts from the specified subreddit.
|
2020-08-02 13:42:53 -04:00
|
|
|
// To search through multiple, separate the names with a plus (+), e.g. "golang+test".
|
2020-07-25 00:08:28 -04:00
|
|
|
// If none are defined, it returns the ones from your subscribed subreddits.
|
2020-08-21 15:31:15 -04:00
|
|
|
// To search through all, just specify "all".
|
|
|
|
// To search through all and filter out subreddits, provide "all-name1-name2".
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) RisingPosts(ctx context.Context, subreddit string, opts *ListOptions) ([]*Post, *Response, error) {
|
2020-08-05 13:25:09 -04:00
|
|
|
return s.getPosts(ctx, "rising", subreddit, opts)
|
2020-07-25 00:08:28 -04:00
|
|
|
}
|
|
|
|
|
2020-08-04 16:42:42 -04:00
|
|
|
// ControversialPosts returns the most controversial posts from the specified subreddit.
|
2020-08-02 13:42:53 -04:00
|
|
|
// To search through multiple, separate the names with a plus (+), e.g. "golang+test".
|
2020-07-25 00:08:28 -04:00
|
|
|
// If none are defined, it returns the ones from your subscribed subreddits.
|
2020-08-21 15:31:15 -04:00
|
|
|
// To search through all, just specify "all".
|
|
|
|
// To search through all and filter out subreddits, provide "all-name1-name2".
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) ControversialPosts(ctx context.Context, subreddit string, opts *ListPostOptions) ([]*Post, *Response, error) {
|
2020-08-05 13:25:09 -04:00
|
|
|
return s.getPosts(ctx, "controversial", subreddit, opts)
|
2020-07-25 00:08:28 -04:00
|
|
|
}
|
|
|
|
|
2020-08-04 16:42:42 -04:00
|
|
|
// TopPosts returns the top posts from the specified subreddit.
|
2020-08-02 13:42:53 -04:00
|
|
|
// To search through multiple, separate the names with a plus (+), e.g. "golang+test".
|
2020-07-25 00:08:28 -04:00
|
|
|
// If none are defined, it returns the ones from your subscribed subreddits.
|
2020-08-21 15:31:15 -04:00
|
|
|
// To search through all, just specify "all".
|
|
|
|
// To search through all and filter out subreddits, provide "all-name1-name2".
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) TopPosts(ctx context.Context, subreddit string, opts *ListPostOptions) ([]*Post, *Response, error) {
|
2020-08-05 13:25:09 -04:00
|
|
|
return s.getPosts(ctx, "top", subreddit, opts)
|
2020-05-16 22:34:01 -04:00
|
|
|
}
|
|
|
|
|
2020-08-27 18:49:30 -04:00
|
|
|
// Get a subreddit by name.
|
2020-07-21 23:59:53 -04:00
|
|
|
func (s *SubredditService) Get(ctx context.Context, name string) (*Subreddit, *Response, error) {
|
|
|
|
if name == "" {
|
2020-08-03 00:00:29 -04:00
|
|
|
return nil, nil, errors.New("name: cannot be empty")
|
2020-04-23 22:57:47 -04:00
|
|
|
}
|
|
|
|
|
2020-07-21 23:59:53 -04:00
|
|
|
path := fmt.Sprintf("r/%s/about", name)
|
2020-04-23 22:57:47 -04:00
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
2020-07-12 22:53:19 -04:00
|
|
|
root := new(rootSubreddit)
|
2020-04-23 22:57:47 -04:00
|
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
|
|
if err != nil {
|
|
|
|
return nil, resp, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return root.Data, resp, nil
|
|
|
|
}
|
2020-04-29 15:59:18 -04:00
|
|
|
|
2020-08-04 16:42:42 -04:00
|
|
|
// Popular returns popular subreddits.
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) Popular(ctx context.Context, opts *ListSubredditOptions) ([]*Subreddit, *Response, error) {
|
2020-04-29 15:59:18 -04:00
|
|
|
return s.getSubreddits(ctx, "subreddits/popular", opts)
|
|
|
|
}
|
|
|
|
|
2020-08-04 16:42:42 -04:00
|
|
|
// New returns new subreddits.
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) New(ctx context.Context, opts *ListSubredditOptions) ([]*Subreddit, *Response, error) {
|
2020-04-29 15:59:18 -04:00
|
|
|
return s.getSubreddits(ctx, "subreddits/new", opts)
|
|
|
|
}
|
|
|
|
|
2020-08-04 16:42:42 -04:00
|
|
|
// Gold returns gold subreddits (i.e. only accessible to users with gold).
|
|
|
|
// It seems like it returns an empty list if you don't have gold.
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) Gold(ctx context.Context, opts *ListSubredditOptions) ([]*Subreddit, *Response, error) {
|
2020-04-29 15:59:18 -04:00
|
|
|
return s.getSubreddits(ctx, "subreddits/gold", opts)
|
|
|
|
}
|
|
|
|
|
2020-08-04 16:42:42 -04:00
|
|
|
// Default returns default subreddits.
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) Default(ctx context.Context, opts *ListSubredditOptions) ([]*Subreddit, *Response, error) {
|
2020-04-29 15:59:18 -04:00
|
|
|
return s.getSubreddits(ctx, "subreddits/default", opts)
|
|
|
|
}
|
|
|
|
|
2020-08-04 16:42:42 -04:00
|
|
|
// Subscribed returns the list of subreddits you are subscribed to.
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) Subscribed(ctx context.Context, opts *ListSubredditOptions) ([]*Subreddit, *Response, error) {
|
2020-04-29 15:59:18 -04:00
|
|
|
return s.getSubreddits(ctx, "subreddits/mine/subscriber", opts)
|
|
|
|
}
|
|
|
|
|
2020-08-04 16:42:42 -04:00
|
|
|
// Approved returns the list of subreddits you are an approved user in.
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) Approved(ctx context.Context, opts *ListSubredditOptions) ([]*Subreddit, *Response, error) {
|
2020-04-29 15:59:18 -04:00
|
|
|
return s.getSubreddits(ctx, "subreddits/mine/contributor", opts)
|
|
|
|
}
|
|
|
|
|
2020-08-04 16:42:42 -04:00
|
|
|
// Moderated returns the list of subreddits you are a moderator of.
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) Moderated(ctx context.Context, opts *ListSubredditOptions) ([]*Subreddit, *Response, error) {
|
2020-06-21 00:13:17 -04:00
|
|
|
return s.getSubreddits(ctx, "subreddits/mine/moderator", opts)
|
2020-04-29 15:59:18 -04:00
|
|
|
}
|
|
|
|
|
2020-06-21 00:13:17 -04:00
|
|
|
// GetSticky1 returns the first stickied post on a subreddit (if it exists).
|
2020-08-14 11:29:13 -04:00
|
|
|
func (s *SubredditService) GetSticky1(ctx context.Context, subreddit string) (*PostAndComments, *Response, error) {
|
|
|
|
return s.getSticky(ctx, subreddit, 1)
|
2020-05-16 11:38:47 -04:00
|
|
|
}
|
2020-05-03 17:31:35 -04:00
|
|
|
|
2020-06-21 00:13:17 -04:00
|
|
|
// GetSticky2 returns the second stickied post on a subreddit (if it exists).
|
2020-08-14 11:29:13 -04:00
|
|
|
func (s *SubredditService) GetSticky2(ctx context.Context, subreddit string) (*PostAndComments, *Response, error) {
|
|
|
|
return s.getSticky(ctx, subreddit, 2)
|
2020-05-16 11:38:47 -04:00
|
|
|
}
|
2020-05-03 17:31:35 -04:00
|
|
|
|
2020-07-21 23:59:53 -04:00
|
|
|
func (s *SubredditService) handleSubscription(ctx context.Context, form url.Values) (*Response, error) {
|
|
|
|
path := "api/subscribe"
|
|
|
|
|
|
|
|
req, err := s.client.NewRequestWithForm(http.MethodPost, path, form)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.client.Do(ctx, req, nil)
|
|
|
|
}
|
|
|
|
|
2020-06-21 00:13:17 -04:00
|
|
|
// Subscribe subscribes to subreddits based on their names.
|
2020-06-27 23:53:59 -04:00
|
|
|
func (s *SubredditService) Subscribe(ctx context.Context, subreddits ...string) (*Response, error) {
|
2020-05-03 17:31:35 -04:00
|
|
|
form := url.Values{}
|
|
|
|
form.Set("action", "sub")
|
2020-05-16 11:38:47 -04:00
|
|
|
form.Set("sr_name", strings.Join(subreddits, ","))
|
2020-05-03 17:31:35 -04:00
|
|
|
return s.handleSubscription(ctx, form)
|
|
|
|
}
|
|
|
|
|
2020-06-21 00:13:17 -04:00
|
|
|
// SubscribeByID subscribes to subreddits based on their id.
|
2020-06-27 23:53:59 -04:00
|
|
|
func (s *SubredditService) SubscribeByID(ctx context.Context, ids ...string) (*Response, error) {
|
2020-05-03 17:31:35 -04:00
|
|
|
form := url.Values{}
|
|
|
|
form.Set("action", "sub")
|
|
|
|
form.Set("sr", strings.Join(ids, ","))
|
|
|
|
return s.handleSubscription(ctx, form)
|
2020-04-29 15:59:18 -04:00
|
|
|
}
|
|
|
|
|
2020-06-21 00:13:17 -04:00
|
|
|
// Unsubscribe unsubscribes from subreddits based on their names.
|
2020-06-27 23:53:59 -04:00
|
|
|
func (s *SubredditService) Unsubscribe(ctx context.Context, subreddits ...string) (*Response, error) {
|
2020-05-03 17:31:35 -04:00
|
|
|
form := url.Values{}
|
|
|
|
form.Set("action", "unsub")
|
2020-05-16 11:38:47 -04:00
|
|
|
form.Set("sr_name", strings.Join(subreddits, ","))
|
2020-05-03 17:31:35 -04:00
|
|
|
return s.handleSubscription(ctx, form)
|
|
|
|
}
|
|
|
|
|
2020-06-21 00:13:17 -04:00
|
|
|
// UnsubscribeByID unsubscribes from subreddits based on their id.
|
2020-06-27 23:53:59 -04:00
|
|
|
func (s *SubredditService) UnsubscribeByID(ctx context.Context, ids ...string) (*Response, error) {
|
2020-05-03 17:31:35 -04:00
|
|
|
form := url.Values{}
|
|
|
|
form.Set("action", "unsub")
|
|
|
|
form.Set("sr", strings.Join(ids, ","))
|
|
|
|
return s.handleSubscription(ctx, form)
|
|
|
|
}
|
|
|
|
|
2020-08-27 18:49:30 -04:00
|
|
|
// Favorite the subreddit.
|
2020-08-11 00:44:19 -04:00
|
|
|
func (s *SubredditService) Favorite(ctx context.Context, subreddit string) (*Response, error) {
|
|
|
|
path := "api/favorite"
|
|
|
|
|
|
|
|
form := url.Values{}
|
|
|
|
form.Set("sr_name", subreddit)
|
|
|
|
form.Set("make_favorite", "true")
|
|
|
|
form.Set("api_type", "json")
|
|
|
|
|
|
|
|
req, err := s.client.NewRequestWithForm(http.MethodPost, path, form)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.client.Do(ctx, req, nil)
|
|
|
|
}
|
|
|
|
|
2020-08-27 18:49:30 -04:00
|
|
|
// Unfavorite the subreddit.
|
2020-08-11 00:44:19 -04:00
|
|
|
func (s *SubredditService) Unfavorite(ctx context.Context, subreddit string) (*Response, error) {
|
|
|
|
path := "api/favorite"
|
|
|
|
|
|
|
|
form := url.Values{}
|
|
|
|
form.Set("sr_name", subreddit)
|
|
|
|
form.Set("make_favorite", "false")
|
|
|
|
form.Set("api_type", "json")
|
|
|
|
|
|
|
|
req, err := s.client.NewRequestWithForm(http.MethodPost, path, form)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.client.Do(ctx, req, nil)
|
|
|
|
}
|
|
|
|
|
2020-08-27 18:49:30 -04:00
|
|
|
// Search for subreddits.
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) Search(ctx context.Context, query string, opts *ListSubredditOptions) ([]*Subreddit, *Response, error) {
|
2020-08-05 13:25:09 -04:00
|
|
|
path := "subreddits/search"
|
|
|
|
path, err := addOptions(path, opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
type params struct {
|
|
|
|
Query string `url:"q"`
|
|
|
|
}
|
|
|
|
path, err = addOptions(path, params{query})
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2020-07-21 23:59:53 -04:00
|
|
|
|
2020-08-01 17:20:26 -04:00
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
2020-05-16 21:46:16 -04:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-29 14:20:30 -04:00
|
|
|
root := new(listing)
|
2020-05-16 21:46:16 -04:00
|
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
|
|
if err != nil {
|
|
|
|
return nil, resp, err
|
|
|
|
}
|
|
|
|
|
2020-08-29 14:20:30 -04:00
|
|
|
return root.Subreddits, resp, nil
|
2020-05-16 21:46:16 -04:00
|
|
|
}
|
|
|
|
|
2020-07-21 23:59:53 -04:00
|
|
|
// SearchNames searches for subreddits with names beginning with the query provided.
|
|
|
|
func (s *SubredditService) SearchNames(ctx context.Context, query string) ([]string, *Response, error) {
|
|
|
|
path := fmt.Sprintf("api/search_reddit_names?query=%s", query)
|
2020-05-16 21:46:16 -04:00
|
|
|
|
2020-07-21 23:59:53 -04:00
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
2020-05-16 21:46:16 -04:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
2020-07-21 23:59:53 -04:00
|
|
|
root := new(rootSubredditNames)
|
2020-05-16 21:46:16 -04:00
|
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
|
|
if err != nil {
|
|
|
|
return nil, resp, err
|
|
|
|
}
|
|
|
|
|
2020-07-21 23:59:53 -04:00
|
|
|
return root.Names, resp, nil
|
2020-04-29 15:59:18 -04:00
|
|
|
}
|
|
|
|
|
2020-08-02 13:42:53 -04:00
|
|
|
// SearchPosts searches for posts in the specified subreddit.
|
|
|
|
// To search through multiple, separate the names with a plus (+), e.g. "golang+test".
|
|
|
|
// If no subreddit is provided, the search is run against r/all.
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) SearchPosts(ctx context.Context, query string, subreddit string, opts *ListPostSearchOptions) ([]*Post, *Response, error) {
|
2020-08-02 13:42:53 -04:00
|
|
|
if subreddit == "" {
|
|
|
|
subreddit = "all"
|
|
|
|
}
|
|
|
|
|
2020-08-05 13:25:09 -04:00
|
|
|
path := fmt.Sprintf("r/%s/search", subreddit)
|
|
|
|
path, err := addOptions(path, opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
2020-08-02 01:06:25 -04:00
|
|
|
}
|
|
|
|
|
2020-08-05 13:25:09 -04:00
|
|
|
type params struct {
|
|
|
|
Query string `url:"q"`
|
|
|
|
RestrictSubreddits bool `url:"restrict_sr,omitempty"`
|
|
|
|
}
|
2020-08-02 01:06:25 -04:00
|
|
|
|
2020-08-05 13:25:09 -04:00
|
|
|
notAll := !strings.EqualFold(subreddit, "all")
|
|
|
|
path, err = addOptions(path, params{query, notAll})
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2020-08-02 01:06:25 -04:00
|
|
|
|
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-29 14:20:30 -04:00
|
|
|
root := new(listing)
|
2020-08-02 01:06:25 -04:00
|
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
|
|
if err != nil {
|
|
|
|
return nil, resp, err
|
|
|
|
}
|
|
|
|
|
2020-08-29 14:20:30 -04:00
|
|
|
return root.Posts, resp, nil
|
2020-08-02 01:06:25 -04:00
|
|
|
}
|
|
|
|
|
2020-08-29 14:20:30 -04:00
|
|
|
func (s *SubredditService) getSubreddits(ctx context.Context, path string, opts *ListSubredditOptions) ([]*Subreddit, *Response, error) {
|
2020-04-29 15:59:18 -04:00
|
|
|
path, err := addOptions(path, opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-29 14:20:30 -04:00
|
|
|
root := new(listing)
|
2020-04-29 15:59:18 -04:00
|
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
|
|
if err != nil {
|
|
|
|
return nil, resp, err
|
|
|
|
}
|
|
|
|
|
2020-08-29 14:20:30 -04:00
|
|
|
return root.Subreddits, resp, nil
|
2020-04-29 15:59:18 -04:00
|
|
|
}
|
|
|
|
|
2020-06-21 00:13:17 -04:00
|
|
|
// 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.
|
2020-07-30 12:22:39 -04:00
|
|
|
func (s *SubredditService) getSticky(ctx context.Context, subreddit string, num int) (*PostAndComments, *Response, error) {
|
2020-08-14 11:29:13 -04:00
|
|
|
type params struct {
|
2020-06-22 21:57:00 -04:00
|
|
|
Num int `url:"num"`
|
2020-04-29 15:59:18 -04:00
|
|
|
}
|
|
|
|
|
2020-05-16 22:34:01 -04:00
|
|
|
path := fmt.Sprintf("r/%s/about/sticky", subreddit)
|
2020-08-14 11:29:13 -04:00
|
|
|
path, err := addOptions(path, params{num})
|
2020-04-29 15:59:18 -04:00
|
|
|
if err != nil {
|
2020-07-30 12:22:39 -04:00
|
|
|
return nil, nil, err
|
2020-04-29 15:59:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
|
|
if err != nil {
|
2020-07-30 12:22:39 -04:00
|
|
|
return nil, nil, err
|
2020-04-29 15:59:18 -04:00
|
|
|
}
|
|
|
|
|
2020-07-29 14:11:06 -04:00
|
|
|
root := new(PostAndComments)
|
2020-04-29 15:59:18 -04:00
|
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
|
|
if err != nil {
|
2020-07-30 12:22:39 -04:00
|
|
|
return nil, resp, err
|
2020-04-29 15:59:18 -04:00
|
|
|
}
|
|
|
|
|
2020-07-30 12:22:39 -04:00
|
|
|
return root, resp, nil
|
2020-05-16 22:34:01 -04:00
|
|
|
}
|
2020-04-29 15:59:18 -04:00
|
|
|
|
2020-07-20 21:03:57 -04:00
|
|
|
// todo: sr_detail's NSFW indicator is over_18 instead of over18
|
|
|
|
func (s *SubredditService) random(ctx context.Context, nsfw bool) (*Subreddit, *Response, error) {
|
|
|
|
path := "r/random"
|
|
|
|
if nsfw {
|
|
|
|
path = "r/randnsfw"
|
|
|
|
}
|
|
|
|
|
2020-08-14 11:29:13 -04:00
|
|
|
type params struct {
|
2020-07-20 21:03:57 -04:00
|
|
|
ExpandSubreddit bool `url:"sr_detail"`
|
|
|
|
Limit int `url:"limit,omitempty"`
|
|
|
|
}
|
|
|
|
|
2020-08-14 11:29:13 -04:00
|
|
|
path, err := addOptions(path, params{true, 1})
|
2020-07-20 21:03:57 -04:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-14 11:29:13 -04:00
|
|
|
root := new(struct {
|
2020-07-20 21:03:57 -04:00
|
|
|
Data struct {
|
|
|
|
Children []struct {
|
|
|
|
Data struct {
|
|
|
|
Subreddit *Subreddit `json:"sr_detail"`
|
|
|
|
} `json:"data"`
|
|
|
|
} `json:"children"`
|
|
|
|
} `json:"data"`
|
2020-08-14 11:29:13 -04:00
|
|
|
})
|
2020-07-20 21:03:57 -04:00
|
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
|
|
if err != nil {
|
|
|
|
return nil, resp, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var sr *Subreddit
|
|
|
|
if len(root.Data.Children) > 0 {
|
|
|
|
sr = root.Data.Children[0].Data.Subreddit
|
|
|
|
}
|
|
|
|
|
|
|
|
return sr, resp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Random returns a random SFW subreddit.
|
|
|
|
func (s *SubredditService) Random(ctx context.Context) (*Subreddit, *Response, error) {
|
|
|
|
return s.random(ctx, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
// RandomNSFW returns a random NSFW subreddit.
|
|
|
|
func (s *SubredditService) RandomNSFW(ctx context.Context) (*Subreddit, *Response, error) {
|
|
|
|
return s.random(ctx, true)
|
|
|
|
}
|
2020-08-01 17:20:26 -04:00
|
|
|
|
|
|
|
// SubmissionText gets the submission text for the subreddit.
|
|
|
|
// This text is set by the subreddit moderators and intended to be displayed on the submission form.
|
|
|
|
func (s *SubredditService) SubmissionText(ctx context.Context, name string) (string, *Response, error) {
|
|
|
|
if name == "" {
|
2020-08-03 00:00:29 -04:00
|
|
|
return "", nil, errors.New("name: cannot be empty")
|
2020-08-01 17:20:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
path := fmt.Sprintf("r/%s/api/submit_text", name)
|
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
|
|
if err != nil {
|
|
|
|
return "", nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-14 11:29:13 -04:00
|
|
|
root := new(struct {
|
2020-08-01 17:20:26 -04:00
|
|
|
Text string `json:"submit_text"`
|
2020-08-14 11:29:13 -04:00
|
|
|
})
|
2020-08-01 17:20:26 -04:00
|
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
|
|
if err != nil {
|
|
|
|
return "", resp, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return root.Text, resp, err
|
|
|
|
}
|
2020-08-11 00:44:19 -04:00
|
|
|
|
|
|
|
// Banned gets banned users from the subreddit.
|
|
|
|
func (s *SubredditService) Banned(ctx context.Context, subreddit string, opts *ListOptions) (*Bans, *Response, error) {
|
|
|
|
path := fmt.Sprintf("r/%s/about/banned", subreddit)
|
|
|
|
|
|
|
|
path, err := addOptions(path, opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-14 11:29:13 -04:00
|
|
|
root := new(struct {
|
2020-08-11 00:44:19 -04:00
|
|
|
Data struct {
|
|
|
|
Bans []*Ban `json:"children"`
|
|
|
|
After string `json:"after"`
|
|
|
|
Before string `json:"before"`
|
|
|
|
} `json:"data"`
|
2020-08-14 11:29:13 -04:00
|
|
|
})
|
|
|
|
resp, err := s.client.Do(ctx, req, root)
|
2020-08-11 00:44:19 -04:00
|
|
|
if err != nil {
|
|
|
|
return nil, resp, err
|
|
|
|
}
|
|
|
|
|
|
|
|
bans := &Bans{
|
|
|
|
Bans: root.Data.Bans,
|
|
|
|
After: root.Data.After,
|
|
|
|
Before: root.Data.Before,
|
|
|
|
}
|
|
|
|
|
|
|
|
return bans, resp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Muted gets muted users from the subreddit.
|
2020-08-11 14:51:47 -04:00
|
|
|
func (s *SubredditService) Muted(ctx context.Context, subreddit string, opts *ListOptions) (*Relationships, *Response, error) {
|
2020-08-11 00:44:19 -04:00
|
|
|
path := fmt.Sprintf("r/%s/about/muted", subreddit)
|
|
|
|
|
|
|
|
path, err := addOptions(path, opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-11 14:51:47 -04:00
|
|
|
root := new(struct {
|
|
|
|
Data struct {
|
|
|
|
Relationships []*Relationship `json:"children"`
|
|
|
|
After string `json:"after"`
|
|
|
|
Before string `json:"before"`
|
|
|
|
} `json:"data"`
|
|
|
|
})
|
|
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
|
|
if err != nil {
|
|
|
|
return nil, resp, err
|
|
|
|
}
|
|
|
|
|
|
|
|
relationships := &Relationships{
|
|
|
|
Relationships: root.Data.Relationships,
|
|
|
|
After: root.Data.After,
|
|
|
|
Before: root.Data.Before,
|
|
|
|
}
|
|
|
|
|
|
|
|
return relationships, resp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// WikiBanned gets banned users from the subreddit.
|
|
|
|
func (s *SubredditService) WikiBanned(ctx context.Context, subreddit string, opts *ListOptions) (*Bans, *Response, error) {
|
|
|
|
path := fmt.Sprintf("r/%s/about/wikibanned", subreddit)
|
|
|
|
|
|
|
|
path, err := addOptions(path, opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-11 00:44:19 -04:00
|
|
|
var root struct {
|
|
|
|
Data struct {
|
2020-08-11 14:51:47 -04:00
|
|
|
Bans []*Ban `json:"children"`
|
|
|
|
After string `json:"after"`
|
|
|
|
Before string `json:"before"`
|
2020-08-11 00:44:19 -04:00
|
|
|
} `json:"data"`
|
|
|
|
}
|
|
|
|
resp, err := s.client.Do(ctx, req, &root)
|
|
|
|
if err != nil {
|
|
|
|
return nil, resp, err
|
|
|
|
}
|
|
|
|
|
2020-08-11 14:51:47 -04:00
|
|
|
bans := &Bans{
|
|
|
|
Bans: root.Data.Bans,
|
2020-08-11 00:44:19 -04:00
|
|
|
After: root.Data.After,
|
|
|
|
Before: root.Data.Before,
|
|
|
|
}
|
|
|
|
|
2020-08-11 14:51:47 -04:00
|
|
|
return bans, resp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Contributors gets contributors (also known as approved users) from the subreddit.
|
|
|
|
func (s *SubredditService) Contributors(ctx context.Context, subreddit string, opts *ListOptions) (*Relationships, *Response, error) {
|
|
|
|
path := fmt.Sprintf("r/%s/about/contributors", subreddit)
|
|
|
|
|
|
|
|
path, err := addOptions(path, opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
root := new(struct {
|
|
|
|
Data struct {
|
|
|
|
Relationships []*Relationship `json:"children"`
|
|
|
|
After string `json:"after"`
|
|
|
|
Before string `json:"before"`
|
|
|
|
} `json:"data"`
|
|
|
|
})
|
|
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
|
|
if err != nil {
|
|
|
|
return nil, resp, err
|
|
|
|
}
|
|
|
|
|
|
|
|
relationships := &Relationships{
|
|
|
|
Relationships: root.Data.Relationships,
|
|
|
|
After: root.Data.After,
|
|
|
|
Before: root.Data.Before,
|
|
|
|
}
|
|
|
|
|
|
|
|
return relationships, resp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// WikiContributors gets contributors of the wiki from the subreddit.
|
|
|
|
func (s *SubredditService) WikiContributors(ctx context.Context, subreddit string, opts *ListOptions) (*Relationships, *Response, error) {
|
|
|
|
path := fmt.Sprintf("r/%s/about/wikicontributors", subreddit)
|
|
|
|
|
|
|
|
path, err := addOptions(path, opts)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
root := new(struct {
|
|
|
|
Data struct {
|
|
|
|
Relationships []*Relationship `json:"children"`
|
|
|
|
After string `json:"after"`
|
|
|
|
Before string `json:"before"`
|
|
|
|
} `json:"data"`
|
|
|
|
})
|
|
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
|
|
if err != nil {
|
|
|
|
return nil, resp, err
|
|
|
|
}
|
|
|
|
|
|
|
|
relationships := &Relationships{
|
|
|
|
Relationships: root.Data.Relationships,
|
|
|
|
After: root.Data.After,
|
|
|
|
Before: root.Data.Before,
|
|
|
|
}
|
|
|
|
|
|
|
|
return relationships, resp, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Moderators gets the moderators of the subreddit.
|
|
|
|
func (s *SubredditService) Moderators(ctx context.Context, subreddit string) ([]*Moderator, *Response, error) {
|
|
|
|
path := fmt.Sprintf("r/%s/about/moderators", subreddit)
|
|
|
|
|
|
|
|
req, err := s.client.NewRequest(http.MethodGet, path, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
root := new(struct {
|
|
|
|
Data struct {
|
|
|
|
Moderators []*Moderator `json:"children"`
|
|
|
|
} `json:"data"`
|
|
|
|
})
|
|
|
|
resp, err := s.client.Do(ctx, req, root)
|
|
|
|
if err != nil {
|
|
|
|
return nil, resp, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return root.Data.Moderators, resp, nil
|
2020-08-11 00:44:19 -04:00
|
|
|
}
|