313 lines
12 KiB
Go
313 lines
12 KiB
Go
package twitter
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/dghubble/sling"
|
|
)
|
|
|
|
// Tweet represents a Twitter Tweet, previously called a status.
|
|
// https://dev.twitter.com/overview/api/tweets
|
|
type Tweet struct {
|
|
Coordinates *Coordinates `json:"coordinates"`
|
|
CreatedAt string `json:"created_at"`
|
|
CurrentUserRetweet *TweetIdentifier `json:"current_user_retweet"`
|
|
Entities *Entities `json:"entities"`
|
|
FavoriteCount int `json:"favorite_count"`
|
|
Favorited bool `json:"favorited"`
|
|
FilterLevel string `json:"filter_level"`
|
|
ID int64 `json:"id"`
|
|
IDStr string `json:"id_str"`
|
|
InReplyToScreenName string `json:"in_reply_to_screen_name"`
|
|
InReplyToStatusID int64 `json:"in_reply_to_status_id"`
|
|
InReplyToStatusIDStr string `json:"in_reply_to_status_id_str"`
|
|
InReplyToUserID int64 `json:"in_reply_to_user_id"`
|
|
InReplyToUserIDStr string `json:"in_reply_to_user_id_str"`
|
|
Lang string `json:"lang"`
|
|
PossiblySensitive bool `json:"possibly_sensitive"`
|
|
QuoteCount int `json:"quote_count"`
|
|
ReplyCount int `json:"reply_count"`
|
|
RetweetCount int `json:"retweet_count"`
|
|
Retweeted bool `json:"retweeted"`
|
|
RetweetedStatus *Tweet `json:"retweeted_status"`
|
|
Source string `json:"source"`
|
|
Scopes map[string]interface{} `json:"scopes"`
|
|
Text string `json:"text"`
|
|
FullText string `json:"full_text"`
|
|
DisplayTextRange Indices `json:"display_text_range"`
|
|
Place *Place `json:"place"`
|
|
Truncated bool `json:"truncated"`
|
|
User *User `json:"user"`
|
|
WithheldCopyright bool `json:"withheld_copyright"`
|
|
WithheldInCountries []string `json:"withheld_in_countries"`
|
|
WithheldScope string `json:"withheld_scope"`
|
|
ExtendedEntities *ExtendedEntity `json:"extended_entities"`
|
|
ExtendedTweet *ExtendedTweet `json:"extended_tweet"`
|
|
QuotedStatusID int64 `json:"quoted_status_id"`
|
|
QuotedStatusIDStr string `json:"quoted_status_id_str"`
|
|
QuotedStatus *Tweet `json:"quoted_status"`
|
|
}
|
|
|
|
// CreatedAtTime returns the time a tweet was created.
|
|
func (t Tweet) CreatedAtTime() (time.Time, error) {
|
|
return time.Parse(time.RubyDate, t.CreatedAt)
|
|
}
|
|
|
|
// ExtendedTweet represents fields embedded in extended Tweets when served in
|
|
// compatibility mode (default).
|
|
// https://dev.twitter.com/overview/api/upcoming-changes-to-tweets
|
|
type ExtendedTweet struct {
|
|
FullText string `json:"full_text"`
|
|
DisplayTextRange Indices `json:"display_text_range"`
|
|
Entities *Entities `json:"entities"`
|
|
ExtendedEntities *ExtendedEntity `json:"extended_entities"`
|
|
}
|
|
|
|
// Place represents a Twitter Place / Location
|
|
// https://dev.twitter.com/overview/api/places
|
|
type Place struct {
|
|
Attributes map[string]string `json:"attributes"`
|
|
BoundingBox *BoundingBox `json:"bounding_box"`
|
|
Country string `json:"country"`
|
|
CountryCode string `json:"country_code"`
|
|
FullName string `json:"full_name"`
|
|
Geometry *BoundingBox `json:"geometry"`
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
PlaceType string `json:"place_type"`
|
|
Polylines []string `json:"polylines"`
|
|
URL string `json:"url"`
|
|
}
|
|
|
|
// BoundingBox represents the bounding coordinates (longitude, latitutde)
|
|
// defining the bounds of a box containing a Place entity.
|
|
type BoundingBox struct {
|
|
Coordinates [][][2]float64 `json:"coordinates"`
|
|
Type string `json:"type"`
|
|
}
|
|
|
|
// Coordinates are pairs of longitude and latitude locations.
|
|
type Coordinates struct {
|
|
Coordinates [2]float64 `json:"coordinates"`
|
|
Type string `json:"type"`
|
|
}
|
|
|
|
// TweetIdentifier represents the id by which a Tweet can be identified.
|
|
type TweetIdentifier struct {
|
|
ID int64 `json:"id"`
|
|
IDStr string `json:"id_str"`
|
|
}
|
|
|
|
// StatusService provides methods for accessing Twitter status API endpoints.
|
|
type StatusService struct {
|
|
sling *sling.Sling
|
|
}
|
|
|
|
// newStatusService returns a new StatusService.
|
|
func newStatusService(sling *sling.Sling) *StatusService {
|
|
return &StatusService{
|
|
sling: sling.Path("statuses/"),
|
|
}
|
|
}
|
|
|
|
// StatusShowParams are the parameters for StatusService.Show
|
|
type StatusShowParams struct {
|
|
ID int64 `url:"id,omitempty"`
|
|
TrimUser *bool `url:"trim_user,omitempty"`
|
|
IncludeMyRetweet *bool `url:"include_my_retweet,omitempty"`
|
|
IncludeEntities *bool `url:"include_entities,omitempty"`
|
|
TweetMode string `url:"tweet_mode,omitempty"`
|
|
}
|
|
|
|
// Show returns the requested Tweet.
|
|
// https://dev.twitter.com/rest/reference/get/statuses/show/%3Aid
|
|
func (s *StatusService) Show(id int64, params *StatusShowParams) (*Tweet, *http.Response, error) {
|
|
if params == nil {
|
|
params = &StatusShowParams{}
|
|
}
|
|
params.ID = id
|
|
tweet := new(Tweet)
|
|
apiError := new(APIError)
|
|
resp, err := s.sling.New().Get("show.json").QueryStruct(params).Receive(tweet, apiError)
|
|
return tweet, resp, relevantError(err, *apiError)
|
|
}
|
|
|
|
// StatusLookupParams are the parameters for StatusService.Lookup
|
|
type StatusLookupParams struct {
|
|
ID []int64 `url:"id,omitempty,comma"`
|
|
TrimUser *bool `url:"trim_user,omitempty"`
|
|
IncludeEntities *bool `url:"include_entities,omitempty"`
|
|
Map *bool `url:"map,omitempty"`
|
|
TweetMode string `url:"tweet_mode,omitempty"`
|
|
}
|
|
|
|
// Lookup returns the requested Tweets as a slice. Combines ids from the
|
|
// required ids argument and from params.Id.
|
|
// https://dev.twitter.com/rest/reference/get/statuses/lookup
|
|
func (s *StatusService) Lookup(ids []int64, params *StatusLookupParams) ([]Tweet, *http.Response, error) {
|
|
if params == nil {
|
|
params = &StatusLookupParams{}
|
|
}
|
|
params.ID = append(params.ID, ids...)
|
|
tweets := new([]Tweet)
|
|
apiError := new(APIError)
|
|
resp, err := s.sling.New().Get("lookup.json").QueryStruct(params).Receive(tweets, apiError)
|
|
return *tweets, resp, relevantError(err, *apiError)
|
|
}
|
|
|
|
// StatusUpdateParams are the parameters for StatusService.Update
|
|
type StatusUpdateParams struct {
|
|
Status string `url:"status,omitempty"`
|
|
InReplyToStatusID int64 `url:"in_reply_to_status_id,omitempty"`
|
|
PossiblySensitive *bool `url:"possibly_sensitive,omitempty"`
|
|
Lat *float64 `url:"lat,omitempty"`
|
|
Long *float64 `url:"long,omitempty"`
|
|
PlaceID string `url:"place_id,omitempty"`
|
|
DisplayCoordinates *bool `url:"display_coordinates,omitempty"`
|
|
TrimUser *bool `url:"trim_user,omitempty"`
|
|
MediaIds []int64 `url:"media_ids,omitempty,comma"`
|
|
TweetMode string `url:"tweet_mode,omitempty"`
|
|
}
|
|
|
|
// Update updates the user's status, also known as Tweeting.
|
|
// Requires a user auth context.
|
|
// https://dev.twitter.com/rest/reference/post/statuses/update
|
|
func (s *StatusService) Update(status string, params *StatusUpdateParams) (*Tweet, *http.Response, error) {
|
|
if params == nil {
|
|
params = &StatusUpdateParams{}
|
|
}
|
|
params.Status = status
|
|
tweet := new(Tweet)
|
|
apiError := new(APIError)
|
|
resp, err := s.sling.New().Post("update.json").BodyForm(params).Receive(tweet, apiError)
|
|
return tweet, resp, relevantError(err, *apiError)
|
|
}
|
|
|
|
// StatusRetweetParams are the parameters for StatusService.Retweet
|
|
type StatusRetweetParams struct {
|
|
ID int64 `url:"id,omitempty"`
|
|
TrimUser *bool `url:"trim_user,omitempty"`
|
|
TweetMode string `url:"tweet_mode,omitempty"`
|
|
}
|
|
|
|
// Retweet retweets the Tweet with the given id and returns the original Tweet
|
|
// with embedded retweet details.
|
|
// Requires a user auth context.
|
|
// https://dev.twitter.com/rest/reference/post/statuses/retweet/%3Aid
|
|
func (s *StatusService) Retweet(id int64, params *StatusRetweetParams) (*Tweet, *http.Response, error) {
|
|
if params == nil {
|
|
params = &StatusRetweetParams{}
|
|
}
|
|
params.ID = id
|
|
tweet := new(Tweet)
|
|
apiError := new(APIError)
|
|
path := fmt.Sprintf("retweet/%d.json", params.ID)
|
|
resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
|
|
return tweet, resp, relevantError(err, *apiError)
|
|
}
|
|
|
|
// StatusUnretweetParams are the parameters for StatusService.Unretweet
|
|
type StatusUnretweetParams struct {
|
|
ID int64 `url:"id,omitempty"`
|
|
TrimUser *bool `url:"trim_user,omitempty"`
|
|
TweetMode string `url:"tweet_mode,omitempty"`
|
|
}
|
|
|
|
// Unretweet unretweets the Tweet with the given id and returns the original Tweet.
|
|
// Requires a user auth context.
|
|
// https://dev.twitter.com/rest/reference/post/statuses/unretweet/%3Aid
|
|
func (s *StatusService) Unretweet(id int64, params *StatusUnretweetParams) (*Tweet, *http.Response, error) {
|
|
if params == nil {
|
|
params = &StatusUnretweetParams{}
|
|
}
|
|
params.ID = id
|
|
tweet := new(Tweet)
|
|
apiError := new(APIError)
|
|
path := fmt.Sprintf("unretweet/%d.json", params.ID)
|
|
resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
|
|
return tweet, resp, relevantError(err, *apiError)
|
|
}
|
|
|
|
// StatusRetweetsParams are the parameters for StatusService.Retweets
|
|
type StatusRetweetsParams struct {
|
|
ID int64 `url:"id,omitempty"`
|
|
Count int `url:"count,omitempty"`
|
|
TrimUser *bool `url:"trim_user,omitempty"`
|
|
TweetMode string `url:"tweet_mode,omitempty"`
|
|
}
|
|
|
|
// Retweets returns the most recent retweets of the Tweet with the given id.
|
|
// https://dev.twitter.com/rest/reference/get/statuses/retweets/%3Aid
|
|
func (s *StatusService) Retweets(id int64, params *StatusRetweetsParams) ([]Tweet, *http.Response, error) {
|
|
if params == nil {
|
|
params = &StatusRetweetsParams{}
|
|
}
|
|
params.ID = id
|
|
tweets := new([]Tweet)
|
|
apiError := new(APIError)
|
|
path := fmt.Sprintf("retweets/%d.json", params.ID)
|
|
resp, err := s.sling.New().Get(path).QueryStruct(params).Receive(tweets, apiError)
|
|
return *tweets, resp, relevantError(err, *apiError)
|
|
}
|
|
|
|
// StatusDestroyParams are the parameters for StatusService.Destroy
|
|
type StatusDestroyParams struct {
|
|
ID int64 `url:"id,omitempty"`
|
|
TrimUser *bool `url:"trim_user,omitempty"`
|
|
TweetMode string `url:"tweet_mode,omitempty"`
|
|
}
|
|
|
|
// Destroy deletes the Tweet with the given id and returns it if successful.
|
|
// Requires a user auth context.
|
|
// https://dev.twitter.com/rest/reference/post/statuses/destroy/%3Aid
|
|
func (s *StatusService) Destroy(id int64, params *StatusDestroyParams) (*Tweet, *http.Response, error) {
|
|
if params == nil {
|
|
params = &StatusDestroyParams{}
|
|
}
|
|
params.ID = id
|
|
tweet := new(Tweet)
|
|
apiError := new(APIError)
|
|
path := fmt.Sprintf("destroy/%d.json", params.ID)
|
|
resp, err := s.sling.New().Post(path).BodyForm(params).Receive(tweet, apiError)
|
|
return tweet, resp, relevantError(err, *apiError)
|
|
}
|
|
|
|
// OEmbedTweet represents a Tweet in oEmbed format.
|
|
type OEmbedTweet struct {
|
|
URL string `json:"url"`
|
|
ProviderURL string `json:"provider_url"`
|
|
ProviderName string `json:"provider_name"`
|
|
AuthorName string `json:"author_name"`
|
|
Version string `json:"version"`
|
|
AuthorURL string `json:"author_url"`
|
|
Type string `json:"type"`
|
|
HTML string `json:"html"`
|
|
Height int64 `json:"height"`
|
|
Width int64 `json:"width"`
|
|
CacheAge string `json:"cache_age"`
|
|
}
|
|
|
|
// StatusOEmbedParams are the parameters for StatusService.OEmbed
|
|
type StatusOEmbedParams struct {
|
|
ID int64 `url:"id,omitempty"`
|
|
URL string `url:"url,omitempty"`
|
|
Align string `url:"align,omitempty"`
|
|
MaxWidth int64 `url:"maxwidth,omitempty"`
|
|
HideMedia *bool `url:"hide_media,omitempty"`
|
|
HideThread *bool `url:"hide_media,omitempty"`
|
|
OmitScript *bool `url:"hide_media,omitempty"`
|
|
WidgetType string `url:"widget_type,omitempty"`
|
|
HideTweet *bool `url:"hide_tweet,omitempty"`
|
|
}
|
|
|
|
// OEmbed returns the requested Tweet in oEmbed format.
|
|
// https://dev.twitter.com/rest/reference/get/statuses/oembed
|
|
func (s *StatusService) OEmbed(params *StatusOEmbedParams) (*OEmbedTweet, *http.Response, error) {
|
|
oEmbedTweet := new(OEmbedTweet)
|
|
apiError := new(APIError)
|
|
resp, err := s.sling.New().Get("oembed.json").QueryStruct(params).Receive(oEmbedTweet, apiError)
|
|
return oEmbedTweet, resp, relevantError(err, *apiError)
|
|
}
|