twitter 8.2.0 → 8.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.md +1 -1
- data/README.md +172 -10
- data/lib/twitter/arguments.rb +14 -1
- data/lib/twitter/base.rb +72 -11
- data/lib/twitter/basic_user.rb +7 -1
- data/lib/twitter/client.rb +94 -3
- data/lib/twitter/creatable.rb +11 -2
- data/lib/twitter/cursor.rb +58 -11
- data/lib/twitter/direct_message.rb +32 -4
- data/lib/twitter/direct_message_event.rb +34 -10
- data/lib/twitter/direct_messages/welcome_message.rb +22 -1
- data/lib/twitter/direct_messages/welcome_message_rule.rb +7 -0
- data/lib/twitter/direct_messages/welcome_message_rule_wrapper.rb +26 -3
- data/lib/twitter/direct_messages/welcome_message_wrapper.rb +36 -11
- data/lib/twitter/entities.rb +84 -8
- data/lib/twitter/entity/hashtag.rb +7 -1
- data/lib/twitter/entity/symbol.rb +7 -1
- data/lib/twitter/entity/uri.rb +2 -1
- data/lib/twitter/entity/user_mention.rb +20 -1
- data/lib/twitter/entity.rb +7 -1
- data/lib/twitter/enumerable.rb +20 -3
- data/lib/twitter/error.rb +137 -61
- data/lib/twitter/factory.rb +9 -5
- data/lib/twitter/geo/point.rb +37 -5
- data/lib/twitter/geo/polygon.rb +1 -0
- data/lib/twitter/geo.rb +16 -2
- data/lib/twitter/geo_factory.rb +7 -3
- data/lib/twitter/geo_results.rb +39 -8
- data/lib/twitter/headers.rb +44 -7
- data/lib/twitter/identity.rb +13 -3
- data/lib/twitter/language.rb +21 -1
- data/lib/twitter/list.rb +101 -11
- data/lib/twitter/media/animated_gif.rb +1 -0
- data/lib/twitter/media/photo.rb +19 -3
- data/lib/twitter/media/video.rb +21 -3
- data/lib/twitter/media/video_info.rb +15 -1
- data/lib/twitter/media_factory.rb +7 -3
- data/lib/twitter/metadata.rb +14 -1
- data/lib/twitter/null_object.rb +16 -14
- data/lib/twitter/oembed.rb +56 -2
- data/lib/twitter/place.rb +74 -6
- data/lib/twitter/premium_search_results.rb +87 -18
- data/lib/twitter/profile.rb +100 -44
- data/lib/twitter/profile_banner.rb +9 -4
- data/lib/twitter/rate_limit.rb +32 -3
- data/lib/twitter/relationship.rb +8 -5
- data/lib/twitter/rest/account_activity.rb +55 -26
- data/lib/twitter/rest/api.rb +2 -0
- data/lib/twitter/rest/client.rb +18 -0
- data/lib/twitter/rest/direct_messages/welcome_messages.rb +89 -18
- data/lib/twitter/rest/direct_messages.rb +158 -94
- data/lib/twitter/rest/favorites.rb +57 -21
- data/lib/twitter/rest/form_encoder.rb +57 -17
- data/lib/twitter/rest/friends_and_followers.rb +101 -35
- data/lib/twitter/rest/help.rb +13 -3
- data/lib/twitter/rest/lists.rb +133 -45
- data/lib/twitter/rest/oauth.rb +23 -17
- data/lib/twitter/rest/places_and_geo.rb +44 -28
- data/lib/twitter/rest/premium_search.rb +18 -13
- data/lib/twitter/rest/request.rb +171 -53
- data/lib/twitter/rest/saved_searches.rb +22 -7
- data/lib/twitter/rest/search.rb +20 -16
- data/lib/twitter/rest/spam_reporting.rb +5 -1
- data/lib/twitter/rest/suggested_users.rb +14 -5
- data/lib/twitter/rest/timelines.rb +92 -52
- data/lib/twitter/rest/trends.rb +31 -12
- data/lib/twitter/rest/tweets.rb +145 -88
- data/lib/twitter/rest/undocumented.rb +11 -2
- data/lib/twitter/rest/upload_utils.rb +42 -26
- data/lib/twitter/rest/users.rb +150 -71
- data/lib/twitter/rest/utils.rb +135 -39
- data/lib/twitter/saved_search.rb +23 -2
- data/lib/twitter/search_results.rb +62 -17
- data/lib/twitter/settings.rb +37 -11
- data/lib/twitter/size.rb +37 -3
- data/lib/twitter/source_user.rb +4 -3
- data/lib/twitter/streaming/client.rb +60 -8
- data/lib/twitter/streaming/connection.rb +55 -8
- data/lib/twitter/streaming/deleted_tweet.rb +8 -0
- data/lib/twitter/streaming/event.rb +43 -1
- data/lib/twitter/streaming/friend_list.rb +1 -0
- data/lib/twitter/streaming/message_parser.rb +20 -10
- data/lib/twitter/streaming/response.rb +31 -5
- data/lib/twitter/streaming/stall_warning.rb +23 -0
- data/lib/twitter/suggestion.rb +25 -1
- data/lib/twitter/target_user.rb +2 -1
- data/lib/twitter/trend.rb +29 -1
- data/lib/twitter/trend_results.rb +50 -7
- data/lib/twitter/tweet.rb +180 -21
- data/lib/twitter/user.rb +289 -53
- data/lib/twitter/utils.rb +12 -13
- data/lib/twitter/variant.rb +12 -1
- data/lib/twitter/version.rb +66 -29
- data/lib/twitter.rb +6 -1
- metadata +23 -57
- data/.yardopts +0 -16
- data/CHANGELOG.md +0 -1040
- data/CONTRIBUTING.md +0 -49
- data/twitter.gemspec +0 -40
data/lib/twitter/rest/tweets.rb
CHANGED
|
@@ -9,66 +9,81 @@ require "twitter/utils"
|
|
|
9
9
|
|
|
10
10
|
module Twitter
|
|
11
11
|
module REST
|
|
12
|
+
# Methods for working with tweets
|
|
12
13
|
module Tweets
|
|
13
14
|
include Twitter::REST::UploadUtils
|
|
14
15
|
include Twitter::REST::Utils
|
|
15
16
|
include Twitter::Utils
|
|
17
|
+
|
|
18
|
+
# Maximum tweets per request
|
|
16
19
|
MAX_TWEETS_PER_REQUEST = 100
|
|
17
20
|
|
|
18
21
|
# Returns up to 100 of the first retweets of a given tweet
|
|
19
22
|
#
|
|
23
|
+
# @api public
|
|
20
24
|
# @see https://dev.twitter.com/rest/reference/get/statuses/retweets/:id
|
|
21
25
|
# @rate_limited Yes
|
|
22
26
|
# @authentication Requires user context
|
|
23
27
|
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
|
|
28
|
+
# @example
|
|
29
|
+
# client.retweets(25938088801)
|
|
24
30
|
# @return [Array<Twitter::Tweet>]
|
|
25
31
|
# @param tweet [Integer, String, URI, Twitter::Tweet] A Tweet ID, URI, or object.
|
|
26
32
|
# @param options [Hash] A customizable set of options.
|
|
27
|
-
# @option options [Integer] :count Specifies the number of records to retrieve.
|
|
28
|
-
# @option options [Boolean, String, Integer] :trim_user
|
|
33
|
+
# @option options [Integer] :count Specifies the number of records to retrieve.
|
|
34
|
+
# @option options [Boolean, String, Integer] :trim_user Include only the author's ID.
|
|
29
35
|
def retweets(tweet, options = {})
|
|
30
|
-
perform_get_with_objects("/1.1/statuses/retweets/#{extract_id(tweet)}.json", options,
|
|
36
|
+
perform_get_with_objects("/1.1/statuses/retweets/#{extract_id(tweet)}.json", options, Tweet)
|
|
31
37
|
end
|
|
32
38
|
|
|
33
|
-
#
|
|
39
|
+
# Shows up to 100 users who retweeted the Tweet
|
|
34
40
|
#
|
|
41
|
+
# @api public
|
|
35
42
|
# @see https://dev.twitter.com/rest/reference/get/statuses/retweets/:id
|
|
36
43
|
# @rate_limited Yes
|
|
37
44
|
# @authentication Requires user context
|
|
38
45
|
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
|
|
46
|
+
# @example
|
|
47
|
+
# client.retweeters_of(25938088801)
|
|
39
48
|
# @return [Array]
|
|
40
49
|
# @param tweet [Integer, String, URI, Twitter::Tweet] A Tweet ID, URI, or object.
|
|
41
50
|
# @param options [Hash] A customizable set of options.
|
|
42
|
-
# @option options [Integer] :count Specifies the number of records to retrieve.
|
|
43
|
-
# @option options [Boolean, String, Integer] :trim_user
|
|
44
|
-
# @option options [Boolean] :ids_only
|
|
51
|
+
# @option options [Integer] :count Specifies the number of records to retrieve.
|
|
52
|
+
# @option options [Boolean, String, Integer] :trim_user Include only the author's ID.
|
|
53
|
+
# @option options [Boolean] :ids_only Only return user IDs.
|
|
45
54
|
def retweeters_of(tweet, options = {})
|
|
46
55
|
options = options.dup
|
|
47
|
-
ids_only =
|
|
56
|
+
ids_only = options.delete(:ids_only)
|
|
48
57
|
retweeters = retweets(tweet, options).collect(&:user)
|
|
49
58
|
ids_only ? retweeters.collect(&:id) : retweeters
|
|
50
59
|
end
|
|
51
60
|
|
|
52
61
|
# Returns a Tweet
|
|
53
62
|
#
|
|
63
|
+
# @api public
|
|
54
64
|
# @see https://dev.twitter.com/rest/reference/get/statuses/show/:id
|
|
55
65
|
# @rate_limited Yes
|
|
56
66
|
# @authentication Requires user context
|
|
57
67
|
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
|
|
58
68
|
# @raise [Twitter::Error::Forbidden] Error raised when supplied status is over 280 characters.
|
|
69
|
+
# @example
|
|
70
|
+
# client.status(25938088801)
|
|
59
71
|
# @return [Twitter::Tweet] The requested Tweet.
|
|
60
72
|
# @param tweet [Integer, String, URI, Twitter::Tweet] A Tweet ID, URI, or object.
|
|
61
73
|
# @param options [Hash] A customizable set of options.
|
|
62
|
-
# @option options [Boolean, String, Integer] :trim_user
|
|
74
|
+
# @option options [Boolean, String, Integer] :trim_user Include only the author's ID.
|
|
63
75
|
def status(tweet, options = {})
|
|
64
|
-
perform_get_with_object("/1.1/statuses/show/#{extract_id(tweet)}.json", options,
|
|
76
|
+
perform_get_with_object("/1.1/statuses/show/#{extract_id(tweet)}.json", options, Tweet)
|
|
65
77
|
end
|
|
66
78
|
|
|
67
79
|
# Returns Tweets
|
|
68
80
|
#
|
|
81
|
+
# @api public
|
|
69
82
|
# @see https://dev.twitter.com/rest/reference/get/statuses/lookup
|
|
70
83
|
# @rate_limited Yes
|
|
71
84
|
# @authentication Required
|
|
85
|
+
# @example
|
|
86
|
+
# client.statuses(25938088801, 25938088802)
|
|
72
87
|
# @return [Array<Twitter::Tweet>] The requested Tweets.
|
|
73
88
|
# @overload statuses(*tweets)
|
|
74
89
|
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
|
|
@@ -77,19 +92,22 @@ module Twitter
|
|
|
77
92
|
# @param options [Hash] A customizable set of options.
|
|
78
93
|
# @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
|
|
79
94
|
def statuses(*args)
|
|
80
|
-
arguments =
|
|
95
|
+
arguments = Arguments.new(args)
|
|
81
96
|
flat_pmap(arguments.each_slice(MAX_TWEETS_PER_REQUEST)) do |tweets|
|
|
82
|
-
perform_post_with_objects("/1.1/statuses/lookup.json", arguments.options.merge(id: tweets.collect { |u| extract_id(u) }.join(",")),
|
|
97
|
+
perform_post_with_objects("/1.1/statuses/lookup.json", arguments.options.merge(id: tweets.collect { |u| extract_id(u) }.join(",")), Tweet)
|
|
83
98
|
end
|
|
84
99
|
end
|
|
85
100
|
|
|
86
101
|
# Destroys the specified Tweets
|
|
87
102
|
#
|
|
103
|
+
# @api public
|
|
88
104
|
# @see https://dev.twitter.com/rest/reference/post/statuses/destroy/:id
|
|
89
105
|
# @note The authenticating user must be the author of the specified Tweets.
|
|
90
106
|
# @rate_limited No
|
|
91
107
|
# @authentication Requires user context
|
|
92
108
|
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
|
|
109
|
+
# @example
|
|
110
|
+
# client.destroy_status(25938088801)
|
|
93
111
|
# @return [Array<Twitter::Tweet>] The deleted Tweets.
|
|
94
112
|
# @overload destroy_status(*tweets)
|
|
95
113
|
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
|
|
@@ -98,71 +116,82 @@ module Twitter
|
|
|
98
116
|
# @param options [Hash] A customizable set of options.
|
|
99
117
|
# @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
|
|
100
118
|
def destroy_status(*args)
|
|
101
|
-
arguments =
|
|
119
|
+
arguments = Arguments.new(args)
|
|
102
120
|
pmap(arguments) do |tweet|
|
|
103
|
-
perform_post_with_object("/1.1/statuses/destroy/#{extract_id(tweet)}.json", arguments.options,
|
|
121
|
+
perform_post_with_object("/1.1/statuses/destroy/#{extract_id(tweet)}.json", arguments.options, Tweet)
|
|
104
122
|
end
|
|
105
123
|
end
|
|
106
|
-
|
|
124
|
+
# @!method destroy_tweet
|
|
125
|
+
# @api public
|
|
126
|
+
# @see #destroy_status
|
|
127
|
+
alias_method :destroy_tweet, :destroy_status
|
|
107
128
|
|
|
108
129
|
# Updates the authenticating user's status
|
|
109
130
|
#
|
|
131
|
+
# @api public
|
|
110
132
|
# @see https://dev.twitter.com/rest/reference/post/statuses/update
|
|
111
|
-
# @note
|
|
133
|
+
# @note Duplicate statuses are ignored to prevent duplicates.
|
|
112
134
|
# @rate_limited No
|
|
113
135
|
# @authentication Requires user context
|
|
114
136
|
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
|
|
115
|
-
# @
|
|
137
|
+
# @example
|
|
138
|
+
# client.update('I just posted a status update!')
|
|
139
|
+
# @return [Twitter::Tweet] The created Tweet.
|
|
116
140
|
# @param status [String] The text of your status update, up to 280 characters.
|
|
117
141
|
# @param options [Hash] A customizable set of options.
|
|
118
|
-
# @option options [Boolean, String, Integer] :possibly_sensitive
|
|
119
|
-
# @option options [Twitter::Tweet] :in_reply_to_status An existing status
|
|
120
|
-
# @option options [Integer] :in_reply_to_status_id The ID of
|
|
121
|
-
# @option options [Float] :lat The latitude of the location
|
|
122
|
-
# @option options [Float] :long The longitude of the location
|
|
123
|
-
# @option options [Twitter::Place] :place A place in the world.
|
|
124
|
-
# @option options [String] :place_id A place
|
|
125
|
-
# @option options [String] :display_coordinates
|
|
126
|
-
# @option options [Boolean, String, Integer] :trim_user
|
|
142
|
+
# @option options [Boolean, String, Integer] :possibly_sensitive Sensitive content flag.
|
|
143
|
+
# @option options [Twitter::Tweet] :in_reply_to_status An existing status to reply to.
|
|
144
|
+
# @option options [Integer] :in_reply_to_status_id The ID of a status to reply to.
|
|
145
|
+
# @option options [Float] :lat The latitude of the location.
|
|
146
|
+
# @option options [Float] :long The longitude of the location.
|
|
147
|
+
# @option options [Twitter::Place] :place A place in the world.
|
|
148
|
+
# @option options [String] :place_id A place ID.
|
|
149
|
+
# @option options [String] :display_coordinates Pin on exact coordinates.
|
|
150
|
+
# @option options [Boolean, String, Integer] :trim_user Include only the author's ID.
|
|
127
151
|
def update(status, options = {})
|
|
128
152
|
update!(status, options)
|
|
129
|
-
rescue
|
|
130
|
-
user_timeline(count: 1).first
|
|
153
|
+
rescue Error::DuplicateStatus
|
|
154
|
+
user_timeline(count: 1).first # steep:ignore NoMethod
|
|
131
155
|
end
|
|
132
156
|
|
|
133
|
-
# Updates the authenticating user's status
|
|
157
|
+
# Updates the authenticating user's status, raising an error on duplicate
|
|
134
158
|
#
|
|
159
|
+
# @api public
|
|
135
160
|
# @see https://dev.twitter.com/rest/reference/post/statuses/update
|
|
136
|
-
# @note A status update with text identical to the authenticating user's current status will be ignored to prevent duplicates.
|
|
137
161
|
# @rate_limited No
|
|
138
162
|
# @authentication Requires user context
|
|
139
163
|
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
|
|
140
164
|
# @raise [Twitter::Error::DuplicateStatus] Error raised when a duplicate status is posted.
|
|
165
|
+
# @example
|
|
166
|
+
# client.update!('I just posted a status update!')
|
|
141
167
|
# @return [Twitter::Tweet] The created Tweet.
|
|
142
168
|
# @param status [String] The text of your status update, up to 280 characters.
|
|
143
169
|
# @param options [Hash] A customizable set of options.
|
|
144
|
-
# @option options [Boolean, String, Integer] :possibly_sensitive
|
|
145
|
-
# @option options [Twitter::Tweet] :in_reply_to_status An existing status
|
|
146
|
-
# @option options [Integer] :in_reply_to_status_id The ID of
|
|
147
|
-
# @option options [Float] :lat The latitude of the location
|
|
148
|
-
# @option options [Float] :long The longitude of the location
|
|
149
|
-
# @option options [Twitter::Place] :place A place in the world.
|
|
150
|
-
# @option options [String] :place_id A place
|
|
151
|
-
# @option options [String] :display_coordinates
|
|
152
|
-
# @option options [Boolean, String, Integer] :trim_user
|
|
170
|
+
# @option options [Boolean, String, Integer] :possibly_sensitive Sensitive content flag.
|
|
171
|
+
# @option options [Twitter::Tweet] :in_reply_to_status An existing status to reply to.
|
|
172
|
+
# @option options [Integer] :in_reply_to_status_id The ID of a status to reply to.
|
|
173
|
+
# @option options [Float] :lat The latitude of the location.
|
|
174
|
+
# @option options [Float] :long The longitude of the location.
|
|
175
|
+
# @option options [Twitter::Place] :place A place in the world.
|
|
176
|
+
# @option options [String] :place_id A place ID.
|
|
177
|
+
# @option options [String] :display_coordinates Pin on exact coordinates.
|
|
178
|
+
# @option options [Boolean, String, Integer] :trim_user Include only the author's ID.
|
|
153
179
|
def update!(status, options = {})
|
|
154
180
|
hash = options.dup
|
|
155
181
|
hash[:in_reply_to_status_id] = hash.delete(:in_reply_to_status).id unless hash[:in_reply_to_status].nil?
|
|
156
182
|
hash[:place_id] = hash.delete(:place).woeid unless hash[:place].nil?
|
|
157
|
-
perform_post_with_object("/1.1/statuses/update.json", hash.merge(status:),
|
|
183
|
+
perform_post_with_object("/1.1/statuses/update.json", hash.merge(status:), Tweet)
|
|
158
184
|
end
|
|
159
185
|
|
|
160
186
|
# Retweets the specified Tweets as the authenticating user
|
|
161
187
|
#
|
|
188
|
+
# @api public
|
|
162
189
|
# @see https://dev.twitter.com/rest/reference/post/statuses/retweet/:id
|
|
163
190
|
# @rate_limited Yes
|
|
164
191
|
# @authentication Requires user context
|
|
165
192
|
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
|
|
193
|
+
# @example
|
|
194
|
+
# client.retweet(25938088801)
|
|
166
195
|
# @return [Array<Twitter::Tweet>] The original tweets with retweet details embedded.
|
|
167
196
|
# @overload retweet(*tweets)
|
|
168
197
|
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
|
|
@@ -171,22 +200,25 @@ module Twitter
|
|
|
171
200
|
# @param options [Hash] A customizable set of options.
|
|
172
201
|
# @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
|
|
173
202
|
def retweet(*args)
|
|
174
|
-
arguments =
|
|
203
|
+
arguments = Arguments.new(args)
|
|
175
204
|
pmap(arguments) do |tweet|
|
|
176
205
|
post_retweet(extract_id(tweet), arguments.options)
|
|
177
|
-
rescue
|
|
178
|
-
|
|
206
|
+
rescue Error::AlreadyRetweeted, Error::NotFound
|
|
207
|
+
nil
|
|
179
208
|
end.compact
|
|
180
209
|
end
|
|
181
210
|
|
|
182
|
-
# Retweets the specified Tweets
|
|
211
|
+
# Retweets the specified Tweets and raises an error if already retweeted
|
|
183
212
|
#
|
|
213
|
+
# @api public
|
|
184
214
|
# @see https://dev.twitter.com/rest/reference/post/statuses/retweet/:id
|
|
185
215
|
# @rate_limited Yes
|
|
186
216
|
# @authentication Requires user context
|
|
187
217
|
# @raise [Twitter::Error::AlreadyRetweeted] Error raised when tweet has already been retweeted.
|
|
188
218
|
# @raise [Twitter::Error::NotFound] Error raised when tweet does not exist or has been deleted.
|
|
189
219
|
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
|
|
220
|
+
# @example
|
|
221
|
+
# client.retweet!(25938088801)
|
|
190
222
|
# @return [Array<Twitter::Tweet>] The original tweets with retweet details embedded.
|
|
191
223
|
# @overload retweet!(*tweets)
|
|
192
224
|
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
|
|
@@ -195,70 +227,77 @@ module Twitter
|
|
|
195
227
|
# @param options [Hash] A customizable set of options.
|
|
196
228
|
# @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
|
|
197
229
|
def retweet!(*args)
|
|
198
|
-
arguments =
|
|
230
|
+
arguments = Arguments.new(args)
|
|
199
231
|
pmap(arguments) do |tweet|
|
|
200
232
|
post_retweet(extract_id(tweet), arguments.options)
|
|
201
|
-
end
|
|
233
|
+
end
|
|
202
234
|
end
|
|
203
235
|
|
|
204
236
|
# Updates the authenticating user's status with media
|
|
205
237
|
#
|
|
238
|
+
# @api public
|
|
206
239
|
# @see https://dev.twitter.com/rest/reference/post/statuses/update_with_media
|
|
207
|
-
# @note A status update with text/media identical to the authenticating user's current status will NOT be ignored
|
|
208
240
|
# @rate_limited No
|
|
209
241
|
# @authentication Requires user context
|
|
210
242
|
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
|
|
243
|
+
# @example
|
|
244
|
+
# client.update_with_media('I just posted a photo!', File.new('/path/to/image.png'))
|
|
211
245
|
# @return [Twitter::Tweet] The created Tweet.
|
|
212
246
|
# @param status [String] The text of your status update, up to 280 characters.
|
|
213
|
-
# @param media [File, Array<File>] An image file or array of image files
|
|
247
|
+
# @param media [File, Array<File>] An image file or array of image files.
|
|
214
248
|
# @param options [Hash] A customizable set of options.
|
|
215
|
-
# @option options [Boolean, String, Integer] :possibly_sensitive
|
|
216
|
-
# @option options [Twitter::Tweet] :in_reply_to_status An existing status
|
|
217
|
-
# @option options [Integer] :in_reply_to_status_id The ID of
|
|
218
|
-
# @option options [Float] :lat The latitude of the location
|
|
219
|
-
# @option options [Float] :long The longitude of the location
|
|
220
|
-
# @option options [Twitter::Place] :place A place in the world.
|
|
221
|
-
# @option options [String] :place_id A place
|
|
222
|
-
# @option options [String] :display_coordinates
|
|
223
|
-
# @option options [Boolean, String, Integer] :trim_user
|
|
249
|
+
# @option options [Boolean, String, Integer] :possibly_sensitive Sensitive content flag.
|
|
250
|
+
# @option options [Twitter::Tweet] :in_reply_to_status An existing status to reply to.
|
|
251
|
+
# @option options [Integer] :in_reply_to_status_id The ID of a status to reply to.
|
|
252
|
+
# @option options [Float] :lat The latitude of the location.
|
|
253
|
+
# @option options [Float] :long The longitude of the location.
|
|
254
|
+
# @option options [Twitter::Place] :place A place in the world.
|
|
255
|
+
# @option options [String] :place_id A place ID.
|
|
256
|
+
# @option options [String] :display_coordinates Pin on exact coordinates.
|
|
257
|
+
# @option options [Boolean, String, Integer] :trim_user Include only the author's ID.
|
|
224
258
|
def update_with_media(status, media, options = {})
|
|
225
|
-
options = options.dup
|
|
226
259
|
media_ids = pmap(array_wrap(media)) do |medium|
|
|
227
|
-
upload(medium)
|
|
260
|
+
upload(medium).fetch(:media_id)
|
|
228
261
|
end
|
|
229
262
|
update!(status, options.merge(media_ids: media_ids.join(",")))
|
|
230
263
|
end
|
|
231
264
|
|
|
232
265
|
# Returns oEmbed for a Tweet
|
|
233
266
|
#
|
|
267
|
+
# @api public
|
|
234
268
|
# @see https://dev.twitter.com/rest/reference/get/statuses/oembed
|
|
235
269
|
# @rate_limited Yes
|
|
236
270
|
# @authentication Requires user context
|
|
237
271
|
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
|
|
272
|
+
# @example
|
|
273
|
+
# client.oembed(25938088801)
|
|
238
274
|
# @return [Twitter::OEmbed] OEmbed for the requested Tweet.
|
|
239
275
|
# @param tweet [Integer, String, URI, Twitter::Tweet] A Tweet ID, URI, or object.
|
|
240
276
|
# @param options [Hash] A customizable set of options.
|
|
241
|
-
# @option options [Integer] :maxwidth The maximum width in pixels
|
|
242
|
-
# @option options [Boolean, String, Integer] :hide_media
|
|
243
|
-
# @option options [Boolean, String, Integer] :hide_thread
|
|
244
|
-
# @option options [Boolean, String, Integer] :omit_script
|
|
245
|
-
# @option options [String] :align
|
|
246
|
-
# @option options [String] :related
|
|
247
|
-
# @option options [String] :lang Language code for the rendered embed.
|
|
248
|
-
# @option options [String] :widget_type Set to video
|
|
249
|
-
# @option options [Boolean, String] :hide_tweet
|
|
277
|
+
# @option options [Integer] :maxwidth The maximum width in pixels.
|
|
278
|
+
# @option options [Boolean, String, Integer] :hide_media Hide uploaded images.
|
|
279
|
+
# @option options [Boolean, String, Integer] :hide_thread Hide original message for replies.
|
|
280
|
+
# @option options [Boolean, String, Integer] :omit_script Omit widgets.js script element.
|
|
281
|
+
# @option options [String] :align Alignment: left, right, center, or none.
|
|
282
|
+
# @option options [String] :related Related users for Web Intents.
|
|
283
|
+
# @option options [String] :lang Language code for the rendered embed.
|
|
284
|
+
# @option options [String] :widget_type Set to video for video embed.
|
|
285
|
+
# @option options [Boolean, String] :hide_tweet Link directly to Tweet URL.
|
|
250
286
|
def oembed(tweet, options = {})
|
|
251
287
|
options = options.dup
|
|
252
288
|
options[:id] = extract_id(tweet)
|
|
253
|
-
perform_get_with_object("/1.1/statuses/oembed.json", options,
|
|
289
|
+
perform_get_with_object("/1.1/statuses/oembed.json", options, OEmbed)
|
|
254
290
|
end
|
|
255
291
|
|
|
256
292
|
# Returns oEmbeds for Tweets
|
|
257
293
|
#
|
|
294
|
+
# @api public
|
|
258
295
|
# @see https://dev.twitter.com/rest/reference/get/statuses/oembed
|
|
259
296
|
# @rate_limited Yes
|
|
260
297
|
# @authentication Requires user context
|
|
261
298
|
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
|
|
299
|
+
# @example
|
|
300
|
+
# client.oembeds(25938088801, 25938088802)
|
|
262
301
|
# @return [Array<Twitter::OEmbed>] OEmbeds for the requested Tweets.
|
|
263
302
|
# @overload oembed(*tweets)
|
|
264
303
|
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
|
|
@@ -273,18 +312,21 @@ module Twitter
|
|
|
273
312
|
# @option options [String] :related A value for the TWT related parameter, as described in {https://dev.twitter.com/web/intents Web Intents}. This value will be forwarded to all Web Intents calls.
|
|
274
313
|
# @option options [String] :lang Language code for the rendered embed. This will affect the text and localization of the rendered HTML.
|
|
275
314
|
def oembeds(*args)
|
|
276
|
-
arguments =
|
|
315
|
+
arguments = Arguments.new(args)
|
|
277
316
|
pmap(arguments) do |tweet|
|
|
278
|
-
oembed(
|
|
317
|
+
oembed(tweet, arguments.options)
|
|
279
318
|
end
|
|
280
319
|
end
|
|
281
320
|
|
|
282
|
-
# Returns
|
|
321
|
+
# Returns up to 100 user IDs who retweeted the tweet
|
|
283
322
|
#
|
|
323
|
+
# @api public
|
|
284
324
|
# @see https://dev.twitter.com/rest/reference/get/statuses/retweeters/ids
|
|
285
325
|
# @rate_limited Yes
|
|
286
326
|
# @authentication Required
|
|
287
327
|
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
|
|
328
|
+
# @example
|
|
329
|
+
# client.retweeters_ids(25938088801)
|
|
288
330
|
# @return [Twitter::Cursor]
|
|
289
331
|
# @overload retweeters_ids(options)
|
|
290
332
|
# @param options [Hash] A customizable set of options.
|
|
@@ -292,17 +334,20 @@ module Twitter
|
|
|
292
334
|
# @param tweet [Integer, String, URI, Twitter::Tweet] A Tweet ID, URI, or object.
|
|
293
335
|
# @param options [Hash] A customizable set of options.
|
|
294
336
|
def retweeters_ids(*args)
|
|
295
|
-
arguments =
|
|
337
|
+
arguments = Arguments.new(args)
|
|
296
338
|
arguments.options[:id] ||= extract_id(arguments.first)
|
|
297
339
|
perform_get_with_cursor("/1.1/statuses/retweeters/ids.json", arguments.options, :ids)
|
|
298
340
|
end
|
|
299
341
|
|
|
300
342
|
# Untweets a retweeted status as the authenticating user
|
|
301
343
|
#
|
|
344
|
+
# @api public
|
|
302
345
|
# @see https://dev.twitter.com/rest/reference/post/statuses/unretweet/:id
|
|
303
346
|
# @rate_limited Yes
|
|
304
347
|
# @authentication Requires user context
|
|
305
348
|
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
|
|
349
|
+
# @example
|
|
350
|
+
# client.unretweet(25938088801)
|
|
306
351
|
# @return [Array<Twitter::Tweet>] The original tweets with retweet details embedded.
|
|
307
352
|
# @overload unretweet(*tweets)
|
|
308
353
|
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
|
|
@@ -311,32 +356,44 @@ module Twitter
|
|
|
311
356
|
# @param options [Hash] A customizable set of options.
|
|
312
357
|
# @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
|
|
313
358
|
def unretweet(*args)
|
|
314
|
-
arguments =
|
|
359
|
+
arguments = Arguments.new(args)
|
|
315
360
|
pmap(arguments) do |tweet|
|
|
316
361
|
post_unretweet(extract_id(tweet), arguments.options)
|
|
317
|
-
rescue
|
|
318
|
-
|
|
362
|
+
rescue Error::NotFound
|
|
363
|
+
nil
|
|
319
364
|
end.compact
|
|
320
365
|
end
|
|
321
366
|
|
|
322
|
-
|
|
367
|
+
private
|
|
323
368
|
|
|
369
|
+
# Wraps object in an array if not already an array
|
|
370
|
+
#
|
|
371
|
+
# @api private
|
|
372
|
+
# @return [Array]
|
|
324
373
|
def array_wrap(object)
|
|
325
|
-
|
|
326
|
-
object.to_ary || [object]
|
|
327
|
-
else
|
|
328
|
-
[object]
|
|
329
|
-
end
|
|
374
|
+
object.instance_of?(Array) ? object : [object]
|
|
330
375
|
end
|
|
331
376
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
377
|
+
# Posts a retweet
|
|
378
|
+
#
|
|
379
|
+
# @api private
|
|
380
|
+
# @param tweet_id [Integer] The tweet ID to retweet
|
|
381
|
+
# @param options [Hash] Request options
|
|
382
|
+
# @return [Twitter::Tweet]
|
|
383
|
+
def post_retweet(tweet_id, options)
|
|
384
|
+
response = perform_post("/1.1/statuses/retweet/#{tweet_id}.json", options)
|
|
385
|
+
Tweet.new(response)
|
|
335
386
|
end
|
|
336
387
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
388
|
+
# Posts an unretweet
|
|
389
|
+
#
|
|
390
|
+
# @api private
|
|
391
|
+
# @param tweet_id [Integer] The tweet ID to unretweet
|
|
392
|
+
# @param options [Hash] Request options
|
|
393
|
+
# @return [Twitter::Tweet]
|
|
394
|
+
def post_unretweet(tweet_id, options)
|
|
395
|
+
response = perform_post("/1.1/statuses/unretweet/#{tweet_id}.json", options)
|
|
396
|
+
Tweet.new(response)
|
|
340
397
|
end
|
|
341
398
|
end
|
|
342
399
|
end
|
|
@@ -6,13 +6,19 @@ require "twitter/user"
|
|
|
6
6
|
|
|
7
7
|
module Twitter
|
|
8
8
|
module REST
|
|
9
|
+
# Undocumented Twitter API endpoints
|
|
9
10
|
module Undocumented
|
|
10
11
|
include Twitter::REST::Utils
|
|
11
12
|
|
|
13
|
+
# Returns users following followers of the specified user
|
|
14
|
+
#
|
|
15
|
+
# @api public
|
|
12
16
|
# @note Undocumented
|
|
13
17
|
# @rate_limited Yes
|
|
14
18
|
# @authentication Requires user context
|
|
15
19
|
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
|
|
20
|
+
# @example
|
|
21
|
+
# client.following_followers_of('sferik')
|
|
16
22
|
# @return [Twitter::Cursor]
|
|
17
23
|
# @overload following_followers_of(options = {})
|
|
18
24
|
# Returns users following followers of the specified user
|
|
@@ -24,19 +30,22 @@ module Twitter
|
|
|
24
30
|
# @param user [Integer, String, Twitter::User] A Twitter user ID, screen name, URI, or object.
|
|
25
31
|
# @param options [Hash] A customizable set of options.
|
|
26
32
|
def following_followers_of(*args)
|
|
27
|
-
cursor_from_response_with_user(:users,
|
|
33
|
+
cursor_from_response_with_user(:users, User, "/users/following_followers_of.json", args)
|
|
28
34
|
end
|
|
29
35
|
|
|
30
36
|
# Returns Tweets count for a URI
|
|
31
37
|
#
|
|
38
|
+
# @api public
|
|
32
39
|
# @note Undocumented
|
|
33
40
|
# @rate_limited No
|
|
34
41
|
# @authentication Not required
|
|
42
|
+
# @example
|
|
43
|
+
# client.tweet_count('https://twitter.com')
|
|
35
44
|
# @return [Integer]
|
|
36
45
|
# @param url [String, URI] A URL.
|
|
37
46
|
# @param options [Hash] A customizable set of options.
|
|
38
47
|
def tweet_count(url, options = {})
|
|
39
|
-
HTTP.get("https://cdn.api.twitter.com/1/urls/count.json", params: options.merge(url: url.to_s)).parse["count"]
|
|
48
|
+
HTTP.get("https://cdn.api.twitter.com/1/urls/count.json", params: options.merge(url: url.to_s)).parse["count"] # steep:ignore NoMethod
|
|
40
49
|
end
|
|
41
50
|
end
|
|
42
51
|
end
|
|
@@ -2,70 +2,86 @@ require "twitter/rest/request"
|
|
|
2
2
|
|
|
3
3
|
module Twitter
|
|
4
4
|
module REST
|
|
5
|
+
# Utilities for uploading media to Twitter
|
|
6
|
+
#
|
|
7
|
+
# @api private
|
|
5
8
|
module UploadUtils
|
|
6
|
-
|
|
9
|
+
private
|
|
7
10
|
|
|
8
|
-
# Uploads images and videos
|
|
9
|
-
# The only supported video format is mp4.
|
|
11
|
+
# Uploads images and videos to Twitter
|
|
10
12
|
#
|
|
13
|
+
# @api private
|
|
11
14
|
# @see https://developer.twitter.com/en/docs/media/upload-media/uploading-media/media-best-practices
|
|
15
|
+
# @return [Hash]
|
|
12
16
|
def upload(media, media_category_prefix: "tweet")
|
|
13
17
|
ext = File.extname(media)
|
|
14
18
|
return chunk_upload(media, "video/mp4", "#{media_category_prefix}_video") if ext == ".mp4"
|
|
15
19
|
return chunk_upload(media, "video/quicktime", "#{media_category_prefix}_video") if ext == ".mov"
|
|
16
20
|
return chunk_upload(media, "image/gif", "#{media_category_prefix}_gif") if ext == ".gif" && File.size(media) > 5_000_000
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
Request.new(self, :multipart_post, "https://upload.twitter.com/1.1/media/upload.json", key: :media, file: media).perform
|
|
19
23
|
end
|
|
20
24
|
|
|
25
|
+
# Uploads large media in chunks
|
|
26
|
+
#
|
|
27
|
+
# @api private
|
|
21
28
|
# @raise [Twitter::Error::TimeoutError] Error raised when the upload is longer than the value specified in Twitter::Client#timeouts[:upload].
|
|
22
29
|
# @raise [Twitter::Error::MediaError] Error raised when Twitter return an error about a media which is not mapped by the gem.
|
|
23
30
|
# @raise [Twitter::Error::MediaInternalError] Error raised when Twitter returns an InternalError error.
|
|
24
31
|
# @raise [Twitter::Error::InvalidMedia] Error raised when Twitter returns an InvalidMedia error.
|
|
25
32
|
# @raise [Twitter::Error::UnsupportedMedia] Error raised when Twitter returns an UnsupportedMedia error.
|
|
26
33
|
# @see https://developer.twitter.com/en/docs/media/upload-media/uploading-media/chunked-media-upload
|
|
34
|
+
# @return [Hash]
|
|
27
35
|
def chunk_upload(media, media_type, media_category)
|
|
28
|
-
Timeout.timeout(timeouts&.fetch(:upload, nil),
|
|
29
|
-
init =
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
append_media(media, init
|
|
36
|
+
Timeout.timeout(timeouts&.fetch(:upload, nil), Error::TimeoutError) do # steep:ignore UnknownConstant,NoMethod
|
|
37
|
+
init = Request.new(self, :post, "https://upload.twitter.com/1.1/media/upload.json",
|
|
38
|
+
command: "INIT",
|
|
39
|
+
media_type:,
|
|
40
|
+
media_category:,
|
|
41
|
+
total_bytes: media.size).perform
|
|
42
|
+
append_media(media, init.fetch(:media_id))
|
|
35
43
|
media.close
|
|
36
|
-
finalize_media(init
|
|
44
|
+
finalize_media(init.fetch(:media_id))
|
|
37
45
|
end
|
|
38
46
|
end
|
|
39
47
|
|
|
48
|
+
# Appends media chunks
|
|
49
|
+
#
|
|
50
|
+
# @api private
|
|
40
51
|
# @see https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-append
|
|
52
|
+
# @return [void]
|
|
41
53
|
def append_media(media, media_id)
|
|
42
54
|
until media.eof?
|
|
43
55
|
chunk = media.read(5_000_000)
|
|
44
56
|
seg ||= -1
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
57
|
+
Request.new(self, :multipart_post, "https://upload.twitter.com/1.1/media/upload.json",
|
|
58
|
+
command: "APPEND",
|
|
59
|
+
media_id:,
|
|
60
|
+
segment_index: seg += 1,
|
|
61
|
+
key: :media,
|
|
62
|
+
file: StringIO.new(chunk)).perform
|
|
51
63
|
end
|
|
52
64
|
end
|
|
53
65
|
|
|
66
|
+
# Finalizes a media upload
|
|
67
|
+
#
|
|
68
|
+
# @api private
|
|
54
69
|
# @see https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-upload-finalize
|
|
55
70
|
# @see https://developer.twitter.com/en/docs/media/upload-media/api-reference/get-media-upload-status
|
|
71
|
+
# @return [Hash]
|
|
56
72
|
def finalize_media(media_id)
|
|
57
|
-
response =
|
|
58
|
-
|
|
59
|
-
|
|
73
|
+
response = Request.new(self, :post, "https://upload.twitter.com/1.1/media/upload.json",
|
|
74
|
+
command: "FINALIZE", media_id:).perform
|
|
75
|
+
terminal_states = %w[failed succeeded]
|
|
60
76
|
|
|
61
77
|
loop do
|
|
62
|
-
|
|
78
|
+
processing_info = response[:processing_info]
|
|
79
|
+
return response if !processing_info || terminal_states.include?(processing_info[:state])
|
|
63
80
|
|
|
64
|
-
sleep(
|
|
65
|
-
response =
|
|
66
|
-
|
|
81
|
+
sleep(processing_info.fetch(:check_after_secs))
|
|
82
|
+
response = Request.new(self, :get, "https://upload.twitter.com/1.1/media/upload.json",
|
|
83
|
+
command: "STATUS", media_id:).perform
|
|
67
84
|
end
|
|
68
|
-
response
|
|
69
85
|
end
|
|
70
86
|
end
|
|
71
87
|
end
|