Documentation ¶
Index ¶
- Variables
- func CreateClient(config Config)
- type AccessToken
- type Client
- func (c *Client) AccessToken() *AccessToken
- func (c *Client) AddRateLimit(bindingName string, rateLimit api.RateLimit)
- func (c *Client) LatestRateLimit(bindingName string) api.RateLimit
- func (c *Client) Log(msg string)
- func (c *Client) RateLimits() *sync.Map
- func (c *Client) RefreshToken() (err error)
- func (c *Client) RequestsMadeWithinPeriod(period time.Duration) uint32
- func (c *Client) Run(ctx context.Context, bindingName string, attrs map[string]any, req api.Request, ...) (err error)
- func (c *Client) SleepUntilReset(bindingName string)
- type Comment
- type Config
- type Error
- type Listing
- type Me
- type More
- type Post
- type PostAndComments
- type PostsAndComments
- type RateLimit
- type RateLimitConfig
- type Replies
- type Sort
- type Thing
- type Things
- type TimePeriod
- type Timestamp
- type User
- type UserWhereType
Constants ¶
This section is empty.
Variables ¶
var API = api.NewAPI(nil, api.Schema{ "access_token": api.WrapBinding(api.NewBindingChain(func(binding api.Binding[accessTokenResponse, AccessToken], args ...any) (request api.Request) { client := binding.Attrs()["client"].(*Client) data := url.Values{ "grant_type": {"password"}, "username": {client.Config.RedditUsername()}, "password": {client.Config.RedditPassword()}, } req, _ := http.NewRequest(http.MethodPost, "https://www.reddit.com/api/v1/access_token", strings.NewReader(data.Encode())) req.SetBasicAuth(client.Config.RedditPersonalUseScript(), client.Config.RedditSecret()) return api.HTTPRequest{Request: req} }).SetResponseMethod(func(binding api.Binding[accessTokenResponse, AccessToken], response accessTokenResponse, args ...any) AccessToken { client := binding.Attrs()["client"].(*Client) client.setAccessToken(response) return *client.AccessToken() }).AddAttrs( func(client api.Client) (string, any) { return "client", client }, ).SetName("access_token")), "me": api.WrapBinding(api.NewBindingChain(func(binding api.Binding[Me, Me], args ...any) (request api.Request) { req, _ := http.NewRequest(http.MethodGet, "https://oauth.reddit.com/api/v1/me", http.NoBody) return api.HTTPRequest{Request: req} }).SetName("me")), "top": api.WrapBinding(api.NewBindingChain(func(binding api.Binding[listingWrapper, *Listing], args ...any) (request api.Request) { subreddit := args[0].(string) timePeriod := args[1].(TimePeriod) limit := args[2].(int) after := args[3].(string) req, _ := http.NewRequest( http.MethodGet, fmt.Sprintf( "https://oauth.reddit.com/r/%s/top.json?t=%s&limit=%d&after=%s", subreddit, timePeriod, limit, after, ), http.NoBody, ) return api.HTTPRequest{Request: req} }).SetResponseMethod(func(binding api.Binding[listingWrapper, *Listing], response listingWrapper, args ...any) *Listing { return &response.Data }).SetParamsMethod(func(binding api.Binding[listingWrapper, *Listing]) []api.BindingParam { return api.Params( "subreddit", "", true, "timePeriod", Day, "limit", 25, "after", "", ) }).SetPaginated(true).SetName("top")), "comments": api.WrapBinding(api.NewBindingChain(func(binding api.Binding[commentResponse, *PostAndComments], args ...any) (request api.Request) { article := args[0].(string) subreddit := args[1].(*string) pc := args[2].(*PostAndComments) subredditURL := "" if subreddit != nil { subredditURL = fmt.Sprintf("r/%s/", *subreddit) } if pc == nil { req, _ := http.NewRequest( http.MethodGet, fmt.Sprintf("https://oauth.reddit.com/%scomments/%s.json", subredditURL, article), http.NoBody, ) return api.HTTPRequest{Request: req} } postID := pc.Post.FullID commentIDs := pc.More.Children form := url.Values{} form.Set("api_type", "json") form.Set("link_id", postID) form.Set("children", strings.Join(commentIDs, ",")) req, _ := http.NewRequest(http.MethodPost, "https://oauth.reddit.com/api/morechildren.json", strings.NewReader(form.Encode())) return api.HTTPRequest{Request: req} }).SetResponseMethod(func(binding api.Binding[commentResponse, *PostAndComments], response commentResponse, args ...any) *PostAndComments { pc := args[2].(*PostAndComments) if pc != nil { response.postAndComments = pc comments := response.more.JSON.Data.Things.Comments for _, c := range comments { response.postAndComments.addCommentToTree(c) } noMore := true mores := response.more.JSON.Data.Things.Mores for _, m := range mores { if strings.HasPrefix(m.ParentID, kindPost+"_") { noMore = false } response.postAndComments.addMoreToTree(m) } if noMore { response.postAndComments.More = nil } } return response.postAndComments }).SetParamsMethod(func(binding api.Binding[commentResponse, *PostAndComments]) []api.BindingParam { return api.Params( "article", "", true, "subreddit", (*string)(nil), "after", (*PostAndComments)(nil), ) }).SetPaginated(true).SetName("comments")), "user_about": api.WrapBinding(api.NewBindingChain(func(binding api.Binding[Thing, *User], args ...any) (request api.Request) { username := args[0].(string) req, _ := http.NewRequest( http.MethodGet, fmt.Sprintf("https://oauth.reddit.com/user/%s/about.json", username), http.NoBody, ) return api.HTTPRequest{Request: req} }).SetResponseMethod(func(binding api.Binding[Thing, *User], response Thing, args ...any) *User { return response.Data.(*User) }).SetParamsMethod(func(binding api.Binding[Thing, *User]) []api.BindingParam { return api.Params("username", "", true) }).SetName("user_about")), "user_where": api.WrapBinding(api.NewBindingChain(func(binding api.Binding[listingWrapper, *Listing], args ...any) (request api.Request) { username := args[0].(string) where := args[1].(UserWhereType) sort := args[2].(Sort) timePeriod := args[3].(TimePeriod) limit := args[4].(int) after := args[5].(string) req, _ := http.NewRequest( http.MethodGet, fmt.Sprintf( "https://oauth.reddit.com/user/%s/%s.json?sort=%s&t=%s&limit=%d&after=%s", username, where, sort, timePeriod, limit, after, ), http.NoBody, ) return api.HTTPRequest{Request: req} }).SetResponseMethod(func(binding api.Binding[listingWrapper, *Listing], response listingWrapper, args ...any) *Listing { return &response.Data }).SetParamsMethod(func(binding api.Binding[listingWrapper, *Listing]) []api.BindingParam { return api.Params( "username", "", true, "where", Overview, true, "sort", Hot, "timePeriod", Day, "limit", 25, "after", "", ) }).SetPaginated(true).SetName("user_where")), })
Functions ¶
func CreateClient ¶
func CreateClient(config Config)
Types ¶
type AccessToken ¶
type AccessToken struct { FetchedTime time.Time ExpireTime time.Time // contains filtered or unexported fields }
func (AccessToken) Expired ¶
func (at AccessToken) Expired() bool
func (AccessToken) Headers ¶
func (at AccessToken) Headers() http.Header
type Client ¶
type Client struct { Config Config // contains filtered or unexported fields }
var DefaultClient *Client
func (*Client) AccessToken ¶
func (c *Client) AccessToken() *AccessToken
func (*Client) AddRateLimit ¶
func (*Client) LatestRateLimit ¶
func (*Client) RateLimits ¶
func (*Client) RefreshToken ¶
func (*Client) RequestsMadeWithinPeriod ¶
RequestsMadeWithinPeriod returns the number of Reddit API requests made within the given time period.
func (*Client) SleepUntilReset ¶
SleepUntilReset will sleep until the binding of the given name's rate limit has reset, if the number of requests remaining is 0. No sleep will occur otherwise.
type Comment ¶
type Comment struct { ID string `json:"id,omitempty"` FullID string `json:"name,omitempty"` Created *Timestamp `json:"created_utc,omitempty"` Edited *Timestamp `json:"edited,omitempty"` ParentID string `json:"parent_id,omitempty"` Permalink string `json:"permalink,omitempty"` Body string `json:"body,omitempty"` BodyHTML string `json:"body_html,omitempty"` Author string `json:"author,omitempty"` AuthorID string `json:"author_fullname,omitempty"` AuthorFlairText string `json:"author_flair_text,omitempty"` AuthorFlairID string `json:"author_flair_template_id,omitempty"` SubredditName string `json:"subreddit,omitempty"` SubredditNamePrefixed string `json:"subreddit_name_prefixed,omitempty"` SubredditID string `json:"subreddit_id,omitempty"` // Indicates if you've upvote/downvoted (true/false). // If neither, it will be nil. Likes *bool `json:"likes"` Score int `json:"score"` Controversiality int `json:"controversiality"` PostID string `json:"link_id,omitempty"` // This doesn't appear consistently. PostTitle string `json:"link_title,omitempty"` // This doesn't appear consistently. PostPermalink string `json:"link_permalink,omitempty"` // This doesn't appear consistently. PostAuthor string `json:"link_author,omitempty"` // This doesn't appear consistently. PostNumComments *int `json:"num_comments,omitempty"` IsSubmitter bool `json:"is_submitter"` ScoreHidden bool `json:"score_hidden"` Saved bool `json:"saved"` Stickied bool `json:"stickied"` Locked bool `json:"locked"` CanGild bool `json:"can_gild"` NSFW bool `json:"over_18"` Replies Replies `json:"replies"` }
Comment is a comment on a post.
type Error ¶
type Error struct { Message string `json:"message"` Code int `json:"error"` // contains filtered or unexported fields }
Error is a JSON serialised error that can be returned by the Reddit API if there is an error. It also implements the error interface so that it can be returned by Client.Run.
type Listing ¶
type Listing struct { Before string `json:"before"` Children Things `json:"children"` Dist int `json:"dist"` GeoFilter string `json:"geo_filter"` Modhash string `json:"modhash"` // contains filtered or unexported fields }
func (*Listing) UnmarshalJSON ¶
UnmarshalJSON implements the json.Unmarshaler interface.
type Me ¶
type Me struct { IsEmployee bool `json:"is_employee"` SeenLayoutSwitch bool `json:"seen_layout_switch"` HasVisitedNewProfile bool `json:"has_visited_new_profile"` PrefNoProfanity bool `json:"pref_no_profanity"` HasExternalAccount bool `json:"has_external_account"` PrefGeopopular string `json:"pref_geopopular"` SeenRedesignModal bool `json:"seen_redesign_modal"` PrefShowTrending bool `json:"pref_show_trending"` Subreddit struct { DefaultSet bool `json:"default_set"` UserIsContributor bool `json:"user_is_contributor"` BannerImg string `json:"banner_img"` RestrictPosting bool `json:"restrict_posting"` UserIsBanned bool `json:"user_is_banned"` FreeFormReports bool `json:"free_form_reports"` CommunityIcon any `json:"community_icon"` ShowMedia bool `json:"show_media"` IconColor string `json:"icon_color"` UserIsMuted any `json:"user_is_muted"` DisplayName string `json:"display_name"` HeaderImg any `json:"header_img"` Title string `json:"title"` Coins int `json:"coins"` PreviousNames []any `json:"previous_names"` Over18 bool `json:"over_18"` IconSize []int `json:"icon_size"` PrimaryColor string `json:"primary_color"` IconImg string `json:"icon_img"` Description string `json:"description"` AllowedMediaInComments []any `json:"allowed_media_in_comments"` SubmitLinkLabel string `json:"submit_link_label"` HeaderSize any `json:"header_size"` RestrictCommenting bool `json:"restrict_commenting"` Subscribers int `json:"subscribers"` SubmitTextLabel string `json:"submit_text_label"` IsDefaultIcon bool `json:"is_default_icon"` LinkFlairPosition string `json:"link_flair_position"` DisplayNamePrefixed string `json:"display_name_prefixed"` KeyColor string `json:"key_color"` Name string `json:"name"` IsDefaultBanner bool `json:"is_default_banner"` URL string `json:"url"` Quarantine bool `json:"quarantine"` BannerSize any `json:"banner_size"` UserIsModerator bool `json:"user_is_moderator"` AcceptFollowers bool `json:"accept_followers"` PublicDescription string `json:"public_description"` LinkFlairEnabled bool `json:"link_flair_enabled"` DisableContributorRequests bool `json:"disable_contributor_requests"` SubredditType string `json:"subreddit_type"` UserIsSubscriber bool `json:"user_is_subscriber"` } `json:"subreddit"` PrefShowPresence bool `json:"pref_show_presence"` SnoovatarImg string `json:"snoovatar_img"` SnoovatarSize []int `json:"snoovatar_size"` GoldExpiration any `json:"gold_expiration"` HasGoldSubscription bool `json:"has_gold_subscription"` IsSponsor bool `json:"is_sponsor"` NumFriends int `json:"num_friends"` Features struct { ModmailHarassmentFilter bool `json:"modmail_harassment_filter"` ModServiceMuteWrites bool `json:"mod_service_mute_writes"` PromotedTrendBlanks bool `json:"promoted_trend_blanks"` ShowAmpLink bool `json:"show_amp_link"` Chat bool `json:"chat"` IsEmailPermissionRequired bool `json:"is_email_permission_required"` ModAwards bool `json:"mod_awards"` ExpensiveCoinsPackage bool `json:"expensive_coins_package"` MwebXpromoRevampV2 struct { Owner string `json:"owner"` Variant string `json:"variant"` ExperimentID int `json:"experiment_id"` } `json:"mweb_xpromo_revamp_v2"` AwardsOnStreams bool `json:"awards_on_streams"` MwebXpromoModalListingClickDailyDismissibleIos bool `json:"mweb_xpromo_modal_listing_click_daily_dismissible_ios"` ChatSubreddit bool `json:"chat_subreddit"` CookieConsentBanner bool `json:"cookie_consent_banner"` ModlogCopyrightRemoval bool `json:"modlog_copyright_removal"` ShowNpsSurvey bool `json:"show_nps_survey"` DoNotTrack bool `json:"do_not_track"` ImagesInComments bool `json:"images_in_comments"` ModServiceMuteReads bool `json:"mod_service_mute_reads"` ChatUserSettings bool `json:"chat_user_settings"` UsePrefAccountDeployment bool `json:"use_pref_account_deployment"` MwebXpromoInterstitialCommentsIos bool `json:"mweb_xpromo_interstitial_comments_ios"` MwebXpromoModalListingClickDailyDismissibleAndroid bool `json:"mweb_xpromo_modal_listing_click_daily_dismissible_android"` PremiumSubscriptionsTable bool `json:"premium_subscriptions_table"` MwebXpromoInterstitialCommentsAndroid bool `json:"mweb_xpromo_interstitial_comments_android"` CrowdControlForPost bool `json:"crowd_control_for_post"` MwebSharingWebShareAPI struct { Owner string `json:"owner"` Variant string `json:"variant"` ExperimentID int `json:"experiment_id"` } `json:"mweb_sharing_web_share_api"` ChatGroupRollout bool `json:"chat_group_rollout"` ResizedStylesImages bool `json:"resized_styles_images"` NoreferrerToNoopener bool `json:"noreferrer_to_noopener"` } `json:"features"` CanEditName bool `json:"can_edit_name"` Verified bool `json:"verified"` NewModmailExists any `json:"new_modmail_exists"` PrefAutoplay bool `json:"pref_autoplay"` Coins int `json:"coins"` HasPaypalSubscription bool `json:"has_paypal_subscription"` HasSubscribedToPremium bool `json:"has_subscribed_to_premium"` ID string `json:"id"` HasStripeSubscription bool `json:"has_stripe_subscription"` OauthClientID string `json:"oauth_client_id"` CanCreateSubreddit bool `json:"can_create_subreddit"` Over18 bool `json:"over_18"` IsGold bool `json:"is_gold"` IsMod bool `json:"is_mod"` AwarderKarma int `json:"awarder_karma"` SuspensionExpirationUtc any `json:"suspension_expiration_utc"` HasVerifiedEmail bool `json:"has_verified_email"` IsSuspended bool `json:"is_suspended"` PrefVideoAutoplay bool `json:"pref_video_autoplay"` InChat bool `json:"in_chat"` HasAndroidSubscription bool `json:"has_android_subscription"` InRedesignBeta bool `json:"in_redesign_beta"` IconImg string `json:"icon_img"` HasModMail bool `json:"has_mod_mail"` PrefNightmode bool `json:"pref_nightmode"` AwardeeKarma int `json:"awardee_karma"` HideFromRobots bool `json:"hide_from_robots"` PasswordSet bool `json:"password_set"` LinkKarma int `json:"link_karma"` ForcePasswordReset bool `json:"force_password_reset"` TotalKarma int `json:"total_karma"` SeenGiveAwardTooltip bool `json:"seen_give_award_tooltip"` InboxCount int `json:"inbox_count"` SeenPremiumAdblockModal bool `json:"seen_premium_adblock_modal"` PrefTopKarmaSubreddits bool `json:"pref_top_karma_subreddits"` HasMail bool `json:"has_mail"` PrefShowSnoovatar bool `json:"pref_show_snoovatar"` Name string `json:"name"` PrefClickgadget int `json:"pref_clickgadget"` Created float64 `json:"created"` GoldCreddits int `json:"gold_creddits"` CreatedUtc float64 `json:"created_utc"` HasIosSubscription bool `json:"has_ios_subscription"` PrefShowTwitter bool `json:"pref_show_twitter"` InBeta bool `json:"in_beta"` CommentKarma int `json:"comment_karma"` AcceptFollowers bool `json:"accept_followers"` HasSubscribed bool `json:"has_subscribed"` LinkedIdentities []any `json:"linked_identities"` SeenSubredditChatFtux bool `json:"seen_subreddit_chat_ftux"` }
type More ¶
type More struct { ID string `json:"id"` FullID string `json:"name"` ParentID string `json:"parent_id"` // Count is the total number of replies to the parent + replies to those replies (recursively). Count int `json:"count"` // Depth is the number of comment nodes from the parent down to the furthest comment node. Depth int `json:"depth"` Children []string `json:"children"` }
More holds information used to retrieve additional comments omitted from a base comment tree.
type Post ¶
type Post struct { ID string `json:"id,omitempty"` FullID string `json:"name,omitempty"` Created *Timestamp `json:"created_utc,omitempty"` Edited *Timestamp `json:"edited,omitempty"` Permalink string `json:"permalink,omitempty"` URL string `json:"url,omitempty"` Title string `json:"title,omitempty"` Body string `json:"selftext,omitempty"` BodyHTML string `json:"selftext_html,omitempty"` // Indicates if you've upvoted/downvoted (true/false). // If neither, it will be nil. Likes *bool `json:"likes"` Ups int `json:"ups"` Downs int `json:"downs"` Score int `json:"score"` UpvoteRatio float32 `json:"upvote_ratio"` NumberOfComments int `json:"num_comments"` SubredditName string `json:"subreddit,omitempty"` SubredditNamePrefixed string `json:"subreddit_name_prefixed,omitempty"` SubredditID string `json:"subreddit_id,omitempty"` SubredditSubscribers int `json:"subreddit_subscribers"` Author string `json:"author,omitempty"` AuthorID string `json:"author_fullname,omitempty"` Spoiler bool `json:"spoiler"` Locked bool `json:"locked"` NSFW bool `json:"over_18"` IsSelfPost bool `json:"is_self"` Saved bool `json:"saved"` Stickied bool `json:"stickied"` }
Post represents a post on a subreddit.
type PostAndComments ¶
type PostAndComments struct { Post *Post `json:"post"` Comments []*Comment `json:"comments"` More *More `json:"-"` }
PostAndComments is a post and its comments.
func (*PostAndComments) After ¶
func (pc *PostAndComments) After() any
func (*PostAndComments) Count ¶
func (pc *PostAndComments) Count() int
func (*PostAndComments) HasMore ¶
func (pc *PostAndComments) HasMore() bool
HasMore determines whether the post has more replies to load in its reply tree.
func (*PostAndComments) Merge ¶
func (pc *PostAndComments) Merge(postAndComments any) (err error)
Merge for PostAndComments doesn't do anything because everything is already achieved in api.Binding.Response
func (*PostAndComments) UnmarshalJSON ¶
func (pc *PostAndComments) UnmarshalJSON(data []byte) error
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
type PostsAndComments ¶
type RateLimit ¶
type RateLimit struct {
// contains filtered or unexported fields
}
func RateLimitFromHeader ¶
RateLimitFromHeader returns a new RateLimit instance from the given http.Header by fetching and parsing the values for the following headers:
- X-Ratelimit-Remaining
- X-Ratelimit-Reset
- X-Ratelimit-Used
If not all headers are found, nil will be returned.
type RateLimitConfig ¶
type Replies ¶
Replies holds replies to a comment. It contains both comments and "more" comments, which are entrypoints to other comments that were left out.
func (*Replies) MarshalJSON ¶
MarshalJSON implements the json.Marshaler interface.
func (*Replies) UnmarshalJSON ¶
UnmarshalJSON implements the json.Unmarshaler interface.
type Thing ¶
func (*Thing) UnmarshalJSON ¶
UnmarshalJSON implements the json.Unmarshaler interface.
type Things ¶
func (*Things) UnmarshalJSON ¶
UnmarshalJSON implements the json.Unmarshaler interface.
type TimePeriod ¶
type TimePeriod string
const ( Hour TimePeriod = "hour" Day TimePeriod = "day" Week TimePeriod = "week" Month TimePeriod = "month" Year TimePeriod = "year" All TimePeriod = "all" )
func (TimePeriod) Name ¶
func (tp TimePeriod) Name() string
func (TimePeriod) String ¶
func (tp TimePeriod) String() string
type Timestamp ¶
Timestamp represents a time that can be unmarshalled from a JSON string formatted as either an RFC3339 or Unix timestamp.
func (*Timestamp) MarshalJSON ¶
MarshalJSON implements the json.Marshaler interface.
func (*Timestamp) UnmarshalJSON ¶
UnmarshalJSON implements the json.Unmarshaler interface. Time is expected in RFC3339 or Unix format.
type User ¶
type User struct { // this is not the full ID, watch out. ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` Created *Timestamp `json:"created_utc,omitempty"` PostKarma int `json:"link_karma"` CommentKarma int `json:"comment_karma"` IsFriend bool `json:"is_friend"` IsEmployee bool `json:"is_employee"` HasVerifiedEmail bool `json:"has_verified_email"` NSFW bool `json:"over_18"` IsSuspended bool `json:"is_suspended"` }
User represents a Reddit user.
type UserWhereType ¶
type UserWhereType string
const ( Overview UserWhereType = "overview" Submitted UserWhereType = "submitted" Comments UserWhereType = "comments" Upvoted UserWhereType = "upvoted" Downvoted UserWhereType = "downvoted" Hidden UserWhereType = "hidden" Saved UserWhereType = "saved" Gilded UserWhereType = "gilded" )
func (UserWhereType) Name ¶
func (uwt UserWhereType) Name() string
func (UserWhereType) String ¶
func (uwt UserWhereType) String() string