birdsong 0.1.1 → 0.1.2
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/lib/birdsong/tweet.rb +34 -92
- data/lib/birdsong/user.rb +29 -32
- data/lib/birdsong/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a632c977970e4e7b014373f08dc819091aece69e59292295711ddfce261ded9c
|
4
|
+
data.tar.gz: ee9d3a05780af53011a3f9018c512a2f6e6dfe733824c2a0401c873b9b529188
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ad9eff7a7a99201eed5821aa897dd232733510cb088e074c56a31102329a751766498800ca62a62c5327d05797e976114e173a685acc35743c82c0ca644d0cc
|
7
|
+
data.tar.gz: f930c1ff617cdfb255771510a1eb3fd4588dc84c0f513f8d74900c62bb7c7680047238c7ba31345f6ddbb8154fef90467be179e32db3f899d76fb335141aaa95
|
data/lib/birdsong/tweet.rb
CHANGED
@@ -9,16 +9,13 @@ module Birdsong
|
|
9
9
|
# Check that the ids are at least real ids
|
10
10
|
ids.each { |id| raise Birdsong::InvalidIdError if !/\A\d+\z/.match(id) }
|
11
11
|
|
12
|
-
response = self.
|
13
|
-
raise Birdsong::AuthorizationError, "Invalid response code #{response.code}" unless response.code == 200
|
12
|
+
response = ids.map { |id| self.retrieve_data_v1(id) }
|
14
13
|
|
15
|
-
json_response = JSON.parse(
|
14
|
+
json_response = response.map { |r| JSON.parse(r.body) }
|
16
15
|
check_for_errors(json_response)
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
json_response["data"].map do |json_tweet|
|
21
|
-
Tweet.new(json_tweet, json_response["includes"])
|
17
|
+
json_response.map do |json_tweet|
|
18
|
+
Tweet.new(json_tweet)
|
22
19
|
end
|
23
20
|
end
|
24
21
|
|
@@ -38,23 +35,21 @@ module Birdsong
|
|
38
35
|
|
39
36
|
private
|
40
37
|
|
41
|
-
def initialize(json_tweet
|
38
|
+
def initialize(json_tweet)
|
42
39
|
@json = json_tweet
|
43
|
-
parse(json_tweet
|
40
|
+
parse(json_tweet)
|
44
41
|
end
|
45
42
|
|
46
|
-
def parse(json_tweet
|
47
|
-
@id = json_tweet["id"]
|
43
|
+
def parse(json_tweet)
|
44
|
+
@id = json_tweet["id"].to_s
|
48
45
|
@created_at = DateTime.parse(json_tweet["created_at"])
|
49
|
-
@text = json_tweet["
|
46
|
+
@text = json_tweet["full_text"]
|
50
47
|
@language = json_tweet["lang"]
|
51
|
-
@author_id = json_tweet["
|
48
|
+
@author_id = json_tweet["user"]["id"]
|
52
49
|
|
53
50
|
# A sanity check to make sure we have media in there correctly
|
54
|
-
if
|
55
|
-
media_items =
|
56
|
-
json_tweet["attachments"]["media_keys"].include? media_item["media_key"]
|
57
|
-
end
|
51
|
+
if json_tweet["extended_entities"]&.has_key?("media")
|
52
|
+
media_items = json_tweet["extended_entities"]["media"]
|
58
53
|
else
|
59
54
|
media_items = []
|
60
55
|
end
|
@@ -69,8 +64,8 @@ module Birdsong
|
|
69
64
|
|
70
65
|
# If the media is video we need to fall back to V1 of the API since V2 doesn't support
|
71
66
|
# videos yet. This is dumb, but not a big deal.
|
72
|
-
media_url =
|
73
|
-
media_preview_url =
|
67
|
+
media_url = get_largest_variant_url(media_items)
|
68
|
+
media_preview_url = media_items.first["media_url_https"]
|
74
69
|
@video_file_type = media_item["type"]
|
75
70
|
|
76
71
|
# We're returning an array because, in the case that someday more videos are available our
|
@@ -80,23 +75,7 @@ module Birdsong
|
|
80
75
|
|
81
76
|
# Look up the author given the new id.
|
82
77
|
# NOTE: This doesn't *seem* like the right place for this, but I"m not sure where else
|
83
|
-
@author = User.lookup(@author_id).first
|
84
|
-
end
|
85
|
-
|
86
|
-
# Used to extract a GIF or video URL from the extended entities object in the Twiter API response
|
87
|
-
# Assumes (as is the case right now) that a Tweet cannot have more than one GIF/video
|
88
|
-
def get_media_url_from_extended_entities
|
89
|
-
response = Tweet.retrieve_data_v1(@id)
|
90
|
-
response = JSON.parse(response.body)
|
91
|
-
get_largest_variant_url(response["extended_entities"]["media"])
|
92
|
-
end
|
93
|
-
|
94
|
-
# Used to extract a GIF or video preview URL from the extended entities object in the Twiter API response
|
95
|
-
# Assumes (as is the case right now) that a Tweet cannot have more than one GIF/video
|
96
|
-
def get_media_preview_url_from_extended_entities
|
97
|
-
response = Tweet.retrieve_data_v1(@id)
|
98
|
-
response = JSON.parse(response.body)
|
99
|
-
response["extended_entities"]["media"].first["media_url_https"]
|
78
|
+
@author = User.lookup(@author_id.to_s).first
|
100
79
|
end
|
101
80
|
|
102
81
|
def get_largest_variant_url(media_items)
|
@@ -118,55 +97,6 @@ module Birdsong
|
|
118
97
|
largest_bitrate_variant["url"]
|
119
98
|
end
|
120
99
|
|
121
|
-
def self.retrieve_data_v2(ids)
|
122
|
-
bearer_token = Birdsong.twitter_bearer_token
|
123
|
-
|
124
|
-
tweet_lookup_url = "https://api.twitter.com/2/tweets"
|
125
|
-
|
126
|
-
# Specify the Tweet IDs that you want to lookup below (to 100 per request)
|
127
|
-
tweet_ids = ids.join(",")
|
128
|
-
|
129
|
-
# Add or remove optional parameters values from the params object below. Full list of parameters and their values can be found in the docs:
|
130
|
-
# https://developer.twitter.com/en/docs/twitter-api/tweets/lookup/api-reference
|
131
|
-
params = {
|
132
|
-
"ids": tweet_ids,
|
133
|
-
"expansions": "attachments.media_keys,author_id,referenced_tweets.id",
|
134
|
-
"tweet.fields": Birdsong.tweet_fields,
|
135
|
-
"user.fields": Birdsong.user_fields,
|
136
|
-
"media.fields": "duration_ms,height,media_key,preview_image_url,public_metrics,type,url,width",
|
137
|
-
"place.fields": "country_code",
|
138
|
-
"poll.fields": "options"
|
139
|
-
}
|
140
|
-
|
141
|
-
response = tweet_lookup_v2(tweet_lookup_url, bearer_token, params)
|
142
|
-
raise Birdsong::AuthorizationError, "Invalid response code #{response.code}" unless response.code === 200
|
143
|
-
|
144
|
-
response
|
145
|
-
end
|
146
|
-
|
147
|
-
def self.tweet_lookup_v2(url, bearer_token, params)
|
148
|
-
options = {
|
149
|
-
method: "get",
|
150
|
-
headers: {
|
151
|
-
"User-Agent": "v2TweetLookupRuby",
|
152
|
-
"Authorization": "Bearer #{bearer_token}"
|
153
|
-
},
|
154
|
-
params: params
|
155
|
-
}
|
156
|
-
|
157
|
-
request = Typhoeus::Request.new(url, options)
|
158
|
-
response = request.run
|
159
|
-
|
160
|
-
raise Birdsong::RateLimitExceeded.new(
|
161
|
-
response.headers["x-rate-limit-limit"],
|
162
|
-
response.headers["x-rate-limit-remaining"],
|
163
|
-
response.headers["x-rate-limit-reset"]
|
164
|
-
) if response.code === 429
|
165
|
-
raise Birdsong::AuthorizationError, "Invalid response code #{response.code}" unless response.code === 200
|
166
|
-
|
167
|
-
response
|
168
|
-
end
|
169
|
-
|
170
100
|
# Note that unlike the V2 this only supports one url at a time
|
171
101
|
def self.retrieve_data_v1(id)
|
172
102
|
bearer_token = Birdsong.twitter_bearer_token
|
@@ -204,6 +134,16 @@ module Birdsong
|
|
204
134
|
response.headers["x-rate-limit-remaining"],
|
205
135
|
response.headers["x-rate-limit-reset"]
|
206
136
|
) if response.code === 429
|
137
|
+
|
138
|
+
raise Birdsong::NoTweetFoundError, "Tweet with id #{url} not found" if response.code === 404
|
139
|
+
if response.code === 403
|
140
|
+
json = JSON.parse(response.body)
|
141
|
+
if json.has_key?("errors")
|
142
|
+
json["errors"].each do |error|
|
143
|
+
raise Birdsong::NoTweetFoundError, "User with id #{url} suspended" if error["code"] == 63
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
207
147
|
raise Birdsong::AuthorizationError, "Invalid response code #{response.code}" unless response.code === 200
|
208
148
|
|
209
149
|
response
|
@@ -211,13 +151,15 @@ module Birdsong
|
|
211
151
|
|
212
152
|
|
213
153
|
def self.check_for_errors(parsed_json)
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
154
|
+
parsed_json.each do |json|
|
155
|
+
next unless json.key?("errors")
|
156
|
+
next if json["errors"].empty?
|
157
|
+
|
158
|
+
json["errors"].each do |error|
|
159
|
+
# If the tweet is removed, or if the user is suspended you get an Authorization Error
|
160
|
+
if error["title"] == "Not Found Error" || error["title"] == "Authorization Error"
|
161
|
+
raise Birdsong::NoTweetFoundError, "Tweet with id #{error["value"]} not found"
|
162
|
+
end
|
221
163
|
end
|
222
164
|
end
|
223
165
|
false
|
data/lib/birdsong/user.rb
CHANGED
@@ -43,9 +43,9 @@ module Birdsong
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def parse(json_user)
|
46
|
-
@id = json_user["id"]
|
46
|
+
@id = json_user["id"].to_s
|
47
47
|
@name = json_user["name"]
|
48
|
-
@username = json_user["
|
48
|
+
@username = json_user["screen_name"]
|
49
49
|
@created_at = DateTime.parse(json_user["created_at"])
|
50
50
|
@location = json_user["location"]
|
51
51
|
|
@@ -55,52 +55,48 @@ module Birdsong
|
|
55
55
|
@description = json_user["description"]
|
56
56
|
@url = json_user["url"]
|
57
57
|
@url = "https://www.twitter.com/#{@username}" if @url.nil?
|
58
|
-
|
59
|
-
@
|
60
|
-
@
|
61
|
-
@
|
62
|
-
@
|
58
|
+
|
59
|
+
@followers_count = json_user["followers_count"]
|
60
|
+
@following_count = json_user["friends_count"]
|
61
|
+
@tweet_count = json_user["statuses_count"]
|
62
|
+
@listed_count = json_user["listed_count"]
|
63
|
+
@verified = json_user["verified"] # this will always be `false` but we're keeping it here for compatibility
|
63
64
|
@profile_image_file_name = Birdsong.retrieve_media(@profile_image_url)
|
64
65
|
end
|
65
66
|
|
66
|
-
def self.lookup_primative(usernames:
|
67
|
-
raise Birdsong::InvalidIdError if usernames.
|
68
|
-
raise Birdsong::InvalidIdError if usernames.nil? == false && ids.nil? == false # don't pass in both
|
69
|
-
|
70
|
-
response = self.retrieve_data(ids: ids, usernames: usernames)
|
67
|
+
def self.lookup_primative(usernames: [], ids: [])
|
68
|
+
raise Birdsong::InvalidIdError if usernames.empty? && ids.empty? # can't pass in nothing
|
71
69
|
|
72
|
-
|
70
|
+
if usernames.empty? == false
|
71
|
+
response = usernames.map { |username| self.retrieve_data(username: username) }
|
72
|
+
elsif ids.empty? == false
|
73
|
+
response = ids.map { |id| self.retrieve_data(id: id) }
|
74
|
+
else
|
75
|
+
raise Birdsong::InvalidIdError
|
76
|
+
end
|
73
77
|
|
74
|
-
json_response = JSON.parse(
|
75
|
-
return [] if json_response["data"].nil?
|
78
|
+
json_response = response.map { |r| JSON.parse(r.body) }
|
76
79
|
|
77
|
-
json_response
|
80
|
+
json_response.map do |json_user|
|
78
81
|
User.new(json_user)
|
79
82
|
end
|
80
83
|
end
|
81
84
|
|
82
|
-
def self.retrieve_data(
|
85
|
+
def self.retrieve_data(username: nil, id: nil)
|
83
86
|
bearer_token = Birdsong.twitter_bearer_token
|
84
87
|
|
85
|
-
raise Birdsong::InvalidIdError if
|
86
|
-
raise Birdsong::InvalidIdError if
|
88
|
+
raise Birdsong::InvalidIdError if username.nil? && id.nil? # can't pass in nothing
|
89
|
+
raise Birdsong::InvalidIdError if username.nil? == false && id.nil? == false # don't pass in both
|
87
90
|
|
88
|
-
|
89
|
-
# https://developer.twitter.com/en/docs/twitter-api/tweets/lookup/api-reference
|
90
|
-
params = {
|
91
|
-
"expansions": "pinned_tweet_id",
|
92
|
-
"tweet.fields": Birdsong.tweet_fields,
|
93
|
-
"user.fields": Birdsong.user_fields,
|
94
|
-
}
|
91
|
+
user_lookup_url = "https://api.twitter.com/1.1/users/show.json"
|
95
92
|
|
96
|
-
|
97
|
-
|
93
|
+
params = {}
|
94
|
+
if username.nil? == false
|
98
95
|
# Specify the Usernames that you want to lookup below (to 100 per request)
|
99
|
-
params["
|
100
|
-
elsif
|
101
|
-
user_lookup_url = "https://api.twitter.com/2/users"
|
96
|
+
params["screen_name"] = username
|
97
|
+
elsif id.nil? == false
|
102
98
|
# Specify the User IDs that you want to lookup below (to 100 per request)
|
103
|
-
params["
|
99
|
+
params["user_id"] = id
|
104
100
|
end
|
105
101
|
|
106
102
|
response = self.user_lookup(user_lookup_url, bearer_token, params)
|
@@ -110,6 +106,7 @@ module Birdsong
|
|
110
106
|
response.headers["x-rate-limit-remaining"],
|
111
107
|
response.headers["x-rate-limit-reset"]
|
112
108
|
) if response.code === 429
|
109
|
+
raise Birdsong::NoTweetFoundError, "User with id #{id} or username #{username} not found" if response.code === 404
|
113
110
|
raise Birdsong::AuthorizationError, "Invalid response code #{response.code}" unless response.code == 200
|
114
111
|
|
115
112
|
response
|
data/lib/birdsong/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: birdsong
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christopher Guess
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-07-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: typhoeus
|
@@ -197,7 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
197
197
|
- !ruby/object:Gem::Version
|
198
198
|
version: '0'
|
199
199
|
requirements: []
|
200
|
-
rubygems_version: 3.
|
200
|
+
rubygems_version: 3.4.14
|
201
201
|
signing_key:
|
202
202
|
specification_version: 4
|
203
203
|
summary: A gem to interface with Twitter's API V2
|