simple_tweet 3.0.1 → 3.1.0

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: a6ce5d4a7a448770b21c18cc4b68f25adc7f21d8814a02970864efc4c487d071
4
- data.tar.gz: 6dfec2f42eff6f04cd8e0dc59571b31bc558b027fc20efdc87c59dd8402a47a1
3
+ metadata.gz: eda2472eda06f1ddc2348a30e194c498e0cd9998036e7dabdbdee4850e1098dc
4
+ data.tar.gz: 50c944ffd64e0f687f968d254389bd2fab8b521b959c5433fbe2aecfe772507e
5
5
  SHA512:
6
- metadata.gz: bef5b277879212fc6c8a6c542ed70d71fd35e5c8e12ab0ab9119d50c3969e271b99b95f812b990eb4bb5ef93c9bc6b9726cb6e71fcf974112789e20da94e0b6f
7
- data.tar.gz: '09771d8edada2fba52358e1f897410a620703d91fe87a6f1b602ec846c56e9771b4a3289908d4bcded74da60c396a235d074ae3388e61917da067422852346f5'
6
+ metadata.gz: a24c2848c3164782c1e424ac6fa6504fb4c1df5b1d720e92323cea4c8298d9327d1878fc49e1b13091c1a043bd612efd06a409ad2bc218c82cb650b962222f3c
7
+ data.tar.gz: e03a4050dc75280addf7a86cad0faa1cc9541c39abbe2f9d1adca6a6fd4cb4898712ff68d7411b0c382de6d85bb6aab4c29f13ae305bd33fce31afd61662a108
data/.rubocop.yml CHANGED
@@ -9,6 +9,9 @@ Style/StringLiteralsInInterpolation:
9
9
  Enabled: true
10
10
  EnforcedStyle: double_quotes
11
11
 
12
+ Style/FrozenStringLiteralComment:
13
+ Enabled: false
14
+
12
15
  Layout/LineLength:
13
16
  Max: 120
14
17
 
@@ -21,5 +24,6 @@ Metrics/MethodLength:
21
24
  Metrics/AbcSize:
22
25
  Max: 30
23
26
 
24
- Style/FrozenStringLiteralComment:
25
- Enabled: false
27
+ Metrics/BlockLength:
28
+ Exclude:
29
+ - 'spec/**/*'
data/Gemfile CHANGED
@@ -9,3 +9,4 @@ gem "rake", "~> 13.0"
9
9
  gem "rspec", "~> 3.0"
10
10
  gem "rubocop", "~> 1.56"
11
11
  gem "steep"
12
+ gem "webmock"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- simple_tweet (3.0.1)
4
+ simple_tweet (3.1.0)
5
5
  multipart-post (>= 2.2.3)
6
6
  oauth (~> 1.1.0)
7
7
 
@@ -13,13 +13,18 @@ GEM
13
13
  i18n (>= 1.6, < 2)
14
14
  minitest (>= 5.1)
15
15
  tzinfo (~> 2.0)
16
+ addressable (2.8.5)
17
+ public_suffix (>= 2.0.2, < 6.0)
16
18
  ast (2.4.2)
17
19
  base64 (0.1.1)
18
20
  concurrent-ruby (1.2.2)
21
+ crack (0.4.5)
22
+ rexml
19
23
  csv (3.2.7)
20
24
  diff-lcs (1.5.0)
21
25
  ffi (1.15.5)
22
26
  fileutils (1.7.1)
27
+ hashdiff (1.0.1)
23
28
  hashie (5.0.0)
24
29
  i18n (1.14.1)
25
30
  concurrent-ruby (~> 1.0)
@@ -41,6 +46,7 @@ GEM
41
46
  parser (3.2.2.3)
42
47
  ast (~> 2.4.1)
43
48
  racc
49
+ public_suffix (5.0.3)
44
50
  racc (1.7.1)
45
51
  rainbow (3.1.1)
46
52
  rake (13.0.6)
@@ -104,6 +110,10 @@ GEM
104
110
  concurrent-ruby (~> 1.0)
105
111
  unicode-display_width (2.4.2)
106
112
  version_gem (1.1.3)
113
+ webmock (3.19.1)
114
+ addressable (>= 2.8.0)
115
+ crack (>= 0.3.2)
116
+ hashdiff (>= 0.4.0, < 2.0.0)
107
117
 
108
118
  PLATFORMS
109
119
  arm64-darwin-21
@@ -115,6 +125,7 @@ DEPENDENCIES
115
125
  rubocop (~> 1.56)
116
126
  simple_tweet!
117
127
  steep
128
+ webmock
118
129
 
119
130
  BUNDLED WITH
120
131
  2.3.24
@@ -66,6 +66,21 @@ module SimpleTweet
66
66
  end
67
67
  end
68
68
 
69
+ def request_with_retry(req:, expected_status_code:, error_kind_message:, retry_count: 3)
70
+ res = request(req)
71
+ return res if expected_status_code === res.code # rubocop:disable Style/CaseEquality
72
+ raise UploadMediaError.new(error_kind_message, response: res) unless retry_count.positive?
73
+
74
+ @client = nil # reset client
75
+ sleep 1 << (3 - retry_count)
76
+ request_with_retry(
77
+ req: req,
78
+ expected_status_code: expected_status_code,
79
+ error_kind_message: error_kind_message,
80
+ retry_count: retry_count - 1
81
+ )
82
+ end
83
+
69
84
  # https://developer.twitter.com/en/docs/twitter-api/v1/media/upload-media/api-reference/post-media-upload
70
85
  ## maybe todo: multiple image
71
86
  # ここはv1のAPIを叩いている。
@@ -88,55 +103,46 @@ module SimpleTweet
88
103
  total_bytes: video.size,
89
104
  media_type: "video/mp4"
90
105
  )
91
- init_res = request(init_req)
92
- raise UploadMediaError.new("init failed", response: init_res) unless init_res.code == "202"
93
-
106
+ init_res = request_with_retry(req: init_req, expected_status_code: "202", error_kind_message: "init failed")
94
107
  ::JSON.parse(init_res.body)
95
108
  end
96
109
 
97
- def append(video:, media_id:, index:, retry_count: 0)
98
- append_req = ::Net::HTTP::Post::Multipart.new(
110
+ def append(video:, media_id:, index:)
111
+ req = ::Net::HTTP::Post::Multipart.new(
99
112
  TW_MEDIA_UPLOAD_PATH,
100
113
  command: "APPEND",
101
114
  media_id: media_id,
102
115
  media: video.read(APPEND_PER),
103
116
  segment_index: index
104
117
  )
105
- res = request(append_req)
106
- return if res.code == "204"
107
- raise UploadMediaError.new("append failed", response: res) unless retry_count <= @max_append_retry_
108
-
109
- append(video: video, media_id: media_id, index: index, retry_count: retry_count + 1)
118
+ request_with_retry(req: req, expected_status_code: "204", error_kind_message: "append failed")
110
119
  end
111
120
 
112
121
  def finalize(media_id:)
113
- finalize_req = ::Net::HTTP::Post::Multipart.new(
122
+ req = ::Net::HTTP::Post::Multipart.new(
114
123
  TW_MEDIA_UPLOAD_PATH,
115
124
  command: "FINALIZE",
116
125
  media_id: media_id
117
126
  )
118
- finalize_res = request(finalize_req)
119
- raise UploadMediaError.new("finalize failed", response: finalize_res) unless finalize_res.code == "201"
120
-
121
- ::JSON.parse(finalize_res.body)
127
+ # finalizeは201が帰ってきてても、processing_infoにretry_afterが入っている場合がある(upload_video中で処理)
128
+ res = request_with_retry(req: req, expected_status_code: /^20\d$/, error_kind_message: "finalize failed")
129
+ ::JSON.parse(res.body)
122
130
  end
123
131
 
124
132
  def status(media_id:)
125
- status_req = ::Net::HTTP::Post::Multipart.new(
126
- TW_MEDIA_UPLOAD_PATH,
127
- command: "STATUS",
128
- media_id: media_id
129
- )
130
- status_res = request(status_req)
131
- raise UploadMediaError.new("status failed", response: status_res) unless status_res.code == "200"
132
-
133
- ::JSON.parse(status_res.body)
133
+ # https://developer.twitter.com/en/docs/twitter-api/v1/media/upload-media/api-reference/get-media-upload-status
134
+ # これはGET
135
+ uri = ::URI.parse(TW_UPLOAD_ORIGIN + TW_MEDIA_UPLOAD_PATH)
136
+ uri.query = ::URI.encode_www_form(command: "STATUS", media_id: media_id)
137
+ req = ::Net::HTTP::Get.new(uri)
138
+ res = request_with_retry(req: req, expected_status_code: "200", error_kind_message: "status failed")
139
+ ::JSON.parse(res.body)
134
140
  end
135
141
 
136
142
  # https://developer.twitter.com/en/docs/twitter-api/v1/media/upload-media/api-reference/post-media-upload-init
137
143
  def upload_video(video:)
138
144
  init_res = init(video: video)
139
- media_id = init_res["media_id_string"]
145
+ media_id = init_res["media_id_string"] # : String
140
146
 
141
147
  chunks_needed = (video.size - 1) / APPEND_PER + 1
142
148
  chunks_needed.times do |i|
@@ -171,10 +177,7 @@ module SimpleTweet
171
177
  header = { "content-type" => "application/json; charset=UTF-8" } # : ::Hash[::String, ::String]
172
178
  req = ::Net::HTTP::Post.new(TW_METADATA_CREATE_PATH, header)
173
179
  req.body = { media_id: media_id, alt_text: { text: alt_text } }.to_json
174
- res = request(req)
175
- raise UploadMediaError.new("create_media_metadata failed", response: res) if res.code != "200"
176
-
177
- res
180
+ request_with_retry(req: req, expected_status_code: "200", error_kind_message: "create_media_metadata failed")
178
181
  end
179
182
  end
180
183
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SimpleTweet
4
- VERSION = "3.0.1"
4
+ VERSION = "3.1.0"
5
5
  end
data/sig/simple_tweet.rbs CHANGED
@@ -12,8 +12,8 @@ module SimpleTweet
12
12
  APPEND_PER: Integer
13
13
 
14
14
  def initialize: (consumer_key: String, consumer_secret: String, access_token: String, access_token_secret: String, ?max_append_retry: Integer) -> void
15
- def tweet: (message: String, ?media_ids: Array[String]) -> untyped
16
- def tweet_with_media: (message: String, media_type: String, media: untyped, ?alt_text: String?) -> untyped
15
+ def tweet: (message: String, ?media_ids: Array[String]) -> Net::HTTPResponse
16
+ def tweet_with_media: (message: String, media_type: String, media: untyped, ?alt_text: String?) -> Net::HTTPResponse
17
17
 
18
18
  @consumer_key_: String
19
19
  @consumer_secret_: String
@@ -24,14 +24,15 @@ module SimpleTweet
24
24
 
25
25
  private
26
26
  def access_token: (?site: String) -> untyped
27
- def request: (untyped req) -> untyped
28
- def upload_media: (media_type: untyped, media: untyped) -> [untyped]
29
- def init: (video: untyped) -> untyped
30
- def append: (video: untyped, media_id: untyped, index: untyped, ?retry_count: Integer) -> nil
31
- def finalize: (media_id: untyped) -> untyped
32
- def status: (media_id: untyped) -> untyped
33
- def upload_video: (video: untyped) -> [untyped]
34
- def create_media_metadata: (media_id: String, alt_text: String?) -> untyped
27
+ def request: (Net::HTTPRequest req) -> Net::HTTPResponse
28
+ def request_with_retry: (req: Net::HTTPRequest, expected_status_code: String | Regexp, error_kind_message: String, ?retry_count: Integer) -> Net::HTTPResponse
29
+ def upload_media: (media_type: String, media: untyped) -> [String]
30
+ def init: (video: untyped) -> Hash[String, untyped]
31
+ def append: (video: untyped, media_id: String, index: untyped) -> Net::HTTPResponse
32
+ def finalize: (media_id: String) -> Hash[String, untyped]
33
+ def status: (media_id: String) -> Hash[String, untyped]
34
+ def upload_video: (video: untyped) -> [String]
35
+ def create_media_metadata: (media_id: String, alt_text: String?) -> Net::HTTPResponse
35
36
  end
36
37
  end
37
38
 
@@ -39,7 +40,7 @@ module SimpleTweet
39
40
  end
40
41
 
41
42
  class UploadMediaError < Error
42
- attr_reader response: nil
43
- def initialize: (?String? message, ?response: nil) -> void
43
+ attr_reader response: Net::HTTPResponse?
44
+ def initialize: (?String? message, ?response: Net::HTTPResponse?) -> void
44
45
  end
45
46
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_tweet
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kugayama Nana
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-09-13 00:00:00.000000000 Z
11
+ date: 2023-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multipart-post