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 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