birdsong 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '03486db7a9efbfce2f7d423f25e33506332bad5a7ceb481da98e68c81b0a75fa'
4
- data.tar.gz: 7a46972f68f413a3d3e0cb81b06ece6b9a3a8f9593be5a68664ce0364ab366ec
3
+ metadata.gz: a632c977970e4e7b014373f08dc819091aece69e59292295711ddfce261ded9c
4
+ data.tar.gz: ee9d3a05780af53011a3f9018c512a2f6e6dfe733824c2a0401c873b9b529188
5
5
  SHA512:
6
- metadata.gz: 68eb9d33bac12dc765b776ad32024992640b1363612f99b2cc0b500c6000fd3ef7351d8cc70218d2d21bb681ec40b233b24fdd7062694426891ce3fa22088e62
7
- data.tar.gz: 8ceddb1eb88a57dec49116653f0be80be47d29d395894ea35a28aafa84eee72d5aa13deca419e569861f715f5cceff93732473fe5cc9e32ed29ed0cd4ae0eb4b
6
+ metadata.gz: 5ad9eff7a7a99201eed5821aa897dd232733510cb088e074c56a31102329a751766498800ca62a62c5327d05797e976114e173a685acc35743c82c0ca644d0cc
7
+ data.tar.gz: f930c1ff617cdfb255771510a1eb3fd4588dc84c0f513f8d74900c62bb7c7680047238c7ba31345f6ddbb8154fef90467be179e32db3f899d76fb335141aaa95
@@ -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.retrieve_data_v2(ids)
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(response.body)
14
+ json_response = response.map { |r| JSON.parse(r.body) }
16
15
  check_for_errors(json_response)
17
16
 
18
- return [] if json_response["data"].nil?
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, includes)
38
+ def initialize(json_tweet)
42
39
  @json = json_tweet
43
- parse(json_tweet, includes)
40
+ parse(json_tweet)
44
41
  end
45
42
 
46
- def parse(json_tweet, includes)
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["text"]
46
+ @text = json_tweet["full_text"]
50
47
  @language = json_tweet["lang"]
51
- @author_id = json_tweet["author_id"]
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 includes.has_key? "media"
55
- media_items = includes["media"].filter do |media_item|
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 = get_media_url_from_extended_entities
73
- media_preview_url = get_media_preview_url_from_extended_entities
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
- return false unless parsed_json.key?("errors")
215
- return false if parsed_json["errors"].empty?
216
-
217
- parsed_json["errors"].each do |error|
218
- # If the tweet is removed, or if the user is suspended you get an Authorization Error
219
- if error["title"] == "Not Found Error" || error["title"] == "Authorization Error"
220
- raise Birdsong::NoTweetFoundError, "Tweet with id #{error["value"]} not found"
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["username"]
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
- @followers_count = json_user["public_metrics"]["followers_count"]
59
- @following_count = json_user["public_metrics"]["following_count"]
60
- @tweet_count = json_user["public_metrics"]["tweet_count"]
61
- @listed_count = json_user["public_metrics"]["listed_count"]
62
- @verified = json_user["verified"]
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: nil, ids: nil)
67
- raise Birdsong::InvalidIdError if usernames.nil? && ids.nil? # can't pass in nothing
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
- raise Birdsong::AuthorizationError, "Invalid response code #{response.code}" unless response.code == 200
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(response.body)
75
- return [] if json_response["data"].nil?
78
+ json_response = response.map { |r| JSON.parse(r.body) }
76
79
 
77
- json_response["data"].map do |json_user|
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(usernames: nil, ids: nil)
85
+ def self.retrieve_data(username: nil, id: nil)
83
86
  bearer_token = Birdsong.twitter_bearer_token
84
87
 
85
- raise Birdsong::InvalidIdError if usernames.nil? && ids.nil? # can't pass in nothing
86
- raise Birdsong::InvalidIdError if usernames.nil? == false && ids.nil? == false # don't pass in both
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
- # Add or remove optional parameters values from the params object below. Full list of parameters and their values can be found in the docs:
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
- if usernames.nil? == false
97
- user_lookup_url = "https://api.twitter.com/2/users/by"
93
+ params = {}
94
+ if username.nil? == false
98
95
  # Specify the Usernames that you want to lookup below (to 100 per request)
99
- params["usernames"] = usernames.join(",")
100
- elsif ids.nil? == false
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["ids"] = ids.join(",")
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Birdsong
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.2"
5
5
  end
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.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-05-23 00:00:00.000000000 Z
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.3.26
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