x 0.9.1 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -1
- data/lib/x/client.rb +3 -0
- data/lib/x/connection.rb +21 -7
- data/lib/x/errors/error.rb +1 -4
- data/lib/x/errors/internal_server_error.rb +5 -0
- data/lib/x/errors/network_error.rb +2 -2
- data/lib/x/errors/payload_too_large_error.rb +5 -0
- data/lib/x/media_upload.rb +125 -0
- data/lib/x/redirect_handler.rb +1 -3
- data/lib/x/request_builder.rb +7 -0
- data/lib/x/response_handler.rb +13 -4
- data/lib/x/version.rb +1 -1
- data/sig/x.rbs +86 -11
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a01e8a21951f3b998cfae0253c4d35c5412ac39f94681283b9059d4a196651e
|
4
|
+
data.tar.gz: 5b4a5bb02d86b27391b005acb329893025222c20e9d0c99b88ed0d7e6322dc5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8972eafdb4c041a61258f409fef5a93dc0ff56b70e5c8dd384e126652c1ab32a4e52dc56bd253d7c204ea6313e3ac321e93c7245c722c0d5491b59443c63435a
|
7
|
+
data.tar.gz: 4a5dfb958b61b78cdcf9312250d3ba00182894241da1c3e9114f08f1029fb174be07043f607a864986e3d09d6d308dfac4d13549e2483d5746235b34c4dd05a2
|
data/CHANGELOG.md
CHANGED
data/lib/x/client.rb
CHANGED
@@ -19,6 +19,9 @@ module X
|
|
19
19
|
def_delegators :@request_builder, :content_type=, :user_agent=
|
20
20
|
def_delegators :@response_handler, :array_class, :object_class
|
21
21
|
def_delegators :@response_handler, :array_class=, :object_class=
|
22
|
+
alias_method :base_url, :base_uri
|
23
|
+
alias_method :base_url=, :base_uri=
|
24
|
+
attr_accessor :authenticator, :connection, :request_builder, :redirect_handler, :response_handler
|
22
25
|
|
23
26
|
def initialize(bearer_token: nil,
|
24
27
|
api_key: nil, api_key_secret: nil, access_token: nil, access_token_secret: nil,
|
data/lib/x/connection.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "forwardable"
|
2
2
|
require "net/http"
|
3
|
+
require "openssl"
|
3
4
|
require "uri"
|
4
5
|
require_relative "errors/network_error"
|
5
6
|
|
@@ -16,8 +17,10 @@ module X
|
|
16
17
|
DEFAULT_WRITE_TIMEOUT = 60 # seconds
|
17
18
|
NETWORK_ERRORS = [
|
18
19
|
Errno::ECONNREFUSED,
|
20
|
+
Errno::ECONNRESET,
|
19
21
|
Net::OpenTimeout,
|
20
|
-
Net::ReadTimeout
|
22
|
+
Net::ReadTimeout,
|
23
|
+
OpenSSL::SSL::SSLError
|
21
24
|
].freeze
|
22
25
|
|
23
26
|
attr_reader :base_uri, :proxy_uri, :http_client
|
@@ -39,9 +42,9 @@ module X
|
|
39
42
|
end
|
40
43
|
|
41
44
|
def send_request(request)
|
42
|
-
@http_client.request(request)
|
45
|
+
response = @http_client.request(request)
|
43
46
|
rescue *NETWORK_ERRORS => e
|
44
|
-
raise NetworkError
|
47
|
+
raise NetworkError.new("Network error: #{e.message}", response: response)
|
45
48
|
end
|
46
49
|
|
47
50
|
def base_uri=(base_url)
|
@@ -56,6 +59,17 @@ module X
|
|
56
59
|
@http_client.instance_variable_get(:@debug_output)
|
57
60
|
end
|
58
61
|
|
62
|
+
def configuration
|
63
|
+
{
|
64
|
+
base_url: base_uri.to_s,
|
65
|
+
open_timeout: open_timeout,
|
66
|
+
read_timeout: read_timeout,
|
67
|
+
write_timeout: write_timeout,
|
68
|
+
proxy_url: proxy_uri.to_s,
|
69
|
+
debug_output: debug_output
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
59
73
|
private
|
60
74
|
|
61
75
|
def apply_http_client_settings(open_timeout:, read_timeout:, write_timeout:, debug_output:)
|
@@ -84,15 +98,15 @@ module X
|
|
84
98
|
end
|
85
99
|
|
86
100
|
def build_http_client(host:, port:)
|
87
|
-
if @proxy_uri
|
88
|
-
Net::HTTP.new(host, port)
|
89
|
-
else
|
101
|
+
if defined?(@proxy_uri)
|
90
102
|
Net::HTTP.new(host, port, @proxy_uri&.host, @proxy_uri&.port, @proxy_uri&.user, @proxy_uri&.password)
|
103
|
+
else
|
104
|
+
Net::HTTP.new(host, port)
|
91
105
|
end
|
92
106
|
end
|
93
107
|
|
94
108
|
def conditionally_apply_http_client_settings
|
95
|
-
if @http_client
|
109
|
+
if defined?(@http_client)
|
96
110
|
settings = current_http_client_settings
|
97
111
|
yield
|
98
112
|
apply_http_client_settings(**settings)
|
data/lib/x/errors/error.rb
CHANGED
@@ -1,15 +1,12 @@
|
|
1
1
|
require "json"
|
2
|
-
require "net/http"
|
3
2
|
|
4
3
|
module X
|
5
4
|
# Base error class
|
6
5
|
class Error < ::StandardError
|
7
|
-
JSON_CONTENT_TYPE_REGEXP = %r{application/(problem\+|)json}
|
8
|
-
|
9
6
|
attr_reader :object
|
10
7
|
|
11
8
|
def initialize(msg, response:)
|
12
|
-
@object = JSON.parse(response.body
|
9
|
+
@object = JSON.parse(response.body) if response&.body && !response.body.empty?
|
13
10
|
super(msg)
|
14
11
|
end
|
15
12
|
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
|
3
|
+
module X
|
4
|
+
# Helper module for uploading images and videos
|
5
|
+
module MediaUpload
|
6
|
+
extend self
|
7
|
+
|
8
|
+
MAX_RETRIES = 3
|
9
|
+
BYTES_PER_MB = 1_048_576
|
10
|
+
MEDIA_CATEGORIES = %w[dm_gif dm_image dm_video subtitles tweet_gif tweet_image tweet_video].freeze
|
11
|
+
DM_GIF, DM_IMAGE, DM_VIDEO, SUBTITLES, TWEET_GIF, TWEET_IMAGE, TWEET_VIDEO = MEDIA_CATEGORIES
|
12
|
+
DEFAULT_MIME_TYPE = "application/octet-stream".freeze
|
13
|
+
MIME_TYPES = %w[image/gif image/jpeg video/mp4 image/png application/x-subrip image/webp].freeze
|
14
|
+
GIF_MIME_TYPE, JPEG_MIME_TYPE, MP4_MIME_TYPE, PNG_MIME_TYPE, SUBRIP_MIME_TYPE, WEBP_MIME_TYPE = MIME_TYPES
|
15
|
+
MIME_TYPE_MAP = {"gif" => GIF_MIME_TYPE, "jpg" => JPEG_MIME_TYPE, "jpeg" => JPEG_MIME_TYPE, "mp4" => MP4_MIME_TYPE,
|
16
|
+
"png" => PNG_MIME_TYPE, "srt" => SUBRIP_MIME_TYPE, "webp" => WEBP_MIME_TYPE}.freeze
|
17
|
+
|
18
|
+
def media_upload(client:, file_path:, media_category:, media_type: infer_media_type(file_path, media_category),
|
19
|
+
boundary: SecureRandom.hex)
|
20
|
+
validate!(file_path: file_path, media_category: media_category)
|
21
|
+
upload_client = client.dup.tap { |c| c.base_uri = "https://upload.twitter.com/1.1/" }
|
22
|
+
upload_body = construct_upload_body(file_path, media_type, boundary)
|
23
|
+
upload_client.content_type = "multipart/form-data, boundary=#{boundary}"
|
24
|
+
upload_client.post("media/upload.json?media_category=#{media_category}", upload_body)
|
25
|
+
end
|
26
|
+
|
27
|
+
def chunked_media_upload(client:, file_path:, media_category:, media_type: infer_media_type(file_path,
|
28
|
+
media_category), boundary: SecureRandom.hex, chunk_size_mb: 8)
|
29
|
+
validate!(file_path: file_path, media_category: media_category)
|
30
|
+
upload_client = client.dup.tap { |c| c.base_uri = "https://upload.twitter.com/1.1/" }
|
31
|
+
media = init(upload_client, file_path, media_type, media_category)
|
32
|
+
chunk_size = chunk_size_mb * BYTES_PER_MB
|
33
|
+
chunk_paths = split(file_path, chunk_size)
|
34
|
+
append(upload_client, chunk_paths, media, media_type, boundary)
|
35
|
+
upload_client.post("media/upload.json?command=FINALIZE&media_id=#{media["media_id"]}")
|
36
|
+
end
|
37
|
+
|
38
|
+
def await_processing(client:, media:)
|
39
|
+
upload_client = client.dup.tap { |c| c.base_uri = "https://upload.twitter.com/1.1/" }
|
40
|
+
loop do
|
41
|
+
status = upload_client.get("media/upload.json?command=STATUS&media_id=#{media["media_id"]}")
|
42
|
+
return status if status["processing_info"]["state"] == "succeeded"
|
43
|
+
|
44
|
+
sleep status["processing_info"]["check_after_secs"].to_i
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def validate!(file_path:, media_category:)
|
51
|
+
raise "File not found: #{file_path}" unless File.exist?(file_path)
|
52
|
+
|
53
|
+
return if MEDIA_CATEGORIES.include?(media_category.downcase)
|
54
|
+
|
55
|
+
raise ArgumentError, "Invalid media_category: #{media_category}. Valid values: #{MEDIA_CATEGORIES.join(", ")}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def infer_media_type(file_path, media_category)
|
59
|
+
case media_category.downcase
|
60
|
+
when TWEET_GIF, DM_GIF then GIF_MIME_TYPE
|
61
|
+
when TWEET_VIDEO, DM_VIDEO then MP4_MIME_TYPE
|
62
|
+
when SUBTITLES then SUBRIP_MIME_TYPE
|
63
|
+
else MIME_TYPE_MAP[File.extname(file_path).delete(".").downcase] || DEFAULT_MIME_TYPE
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def init(upload_client, file_path, media_type, media_category)
|
68
|
+
total_bytes = File.size(file_path)
|
69
|
+
query = "command=INIT&media_type=#{media_type}&media_category=#{media_category}&total_bytes=#{total_bytes}"
|
70
|
+
upload_client.post("media/upload.json?#{query}")
|
71
|
+
end
|
72
|
+
|
73
|
+
def split(file_path, chunk_size)
|
74
|
+
file_number = -1
|
75
|
+
|
76
|
+
[].tap do |chunk_paths|
|
77
|
+
File.open(file_path, "rb") do |f|
|
78
|
+
while (chunk = f.read(chunk_size))
|
79
|
+
chunk_paths << "#{Dir.mktmpdir}/x#{format("%03d", file_number += 1)}".tap do |path|
|
80
|
+
File.write(path, chunk)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def append(upload_client, chunk_paths, media, media_type, boundary = SecureRandom.hex)
|
88
|
+
threads = chunk_paths.map.with_index do |chunk_path, index|
|
89
|
+
Thread.new do
|
90
|
+
upload_body = construct_upload_body(chunk_path, media_type, boundary)
|
91
|
+
query = "command=APPEND&media_id=#{media["media_id"]}&segment_index=#{index}"
|
92
|
+
upload_chunk(upload_client, query, upload_body, chunk_path, boundary)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
threads.each(&:join)
|
96
|
+
end
|
97
|
+
|
98
|
+
def upload_chunk(upload_client, query, upload_body, chunk_path, boundary)
|
99
|
+
# Initialize a new client to avoid shared connection issues
|
100
|
+
client = upload_client.dup
|
101
|
+
client.connection = Connection.new(**upload_client.connection.configuration.merge(base_url: "https://upload.twitter.com/1.1/"))
|
102
|
+
client.content_type = "multipart/form-data, boundary=#{boundary}"
|
103
|
+
client.post("media/upload.json?#{query}", upload_body)
|
104
|
+
rescue NetworkError, ServerError
|
105
|
+
retries ||= 0
|
106
|
+
((retries += 1) < MAX_RETRIES) ? retry : raise
|
107
|
+
ensure
|
108
|
+
cleanup_chunk(chunk_path)
|
109
|
+
end
|
110
|
+
|
111
|
+
def cleanup_chunk(chunk_path)
|
112
|
+
dirname = File.dirname(chunk_path)
|
113
|
+
File.delete(chunk_path)
|
114
|
+
Dir.delete(dirname) if Dir.empty?(dirname)
|
115
|
+
end
|
116
|
+
|
117
|
+
def construct_upload_body(file_path, media_type, boundary = SecureRandom.hex)
|
118
|
+
"--#{boundary}\r\n" \
|
119
|
+
"Content-Disposition: form-data; name=\"media\"; filename=\"#{File.basename(file_path)}\"\r\n" \
|
120
|
+
"Content-Type: #{media_type}\r\n\r\n" \
|
121
|
+
"#{File.read(file_path)}\r\n" \
|
122
|
+
"--#{boundary}--\r\n"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/lib/x/redirect_handler.rb
CHANGED
@@ -47,9 +47,7 @@ module X
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def send_new_request(new_uri, new_request)
|
50
|
-
@connection = Connection.new(base_url: new_uri
|
51
|
-
read_timeout: connection.read_timeout, write_timeout: connection.write_timeout,
|
52
|
-
debug_output: connection.debug_output, proxy_url: connection.proxy_uri)
|
50
|
+
@connection = Connection.new(**connection.configuration.merge(base_url: new_uri))
|
53
51
|
connection.send_request(new_request)
|
54
52
|
end
|
55
53
|
end
|
data/lib/x/request_builder.rb
CHANGED
data/lib/x/response_handler.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require "json"
|
2
2
|
require "net/http"
|
3
|
-
require_relative "errors/bad_request_error"
|
4
3
|
require_relative "errors/authentication_error"
|
4
|
+
require_relative "errors/bad_request_error"
|
5
5
|
require_relative "errors/forbidden_error"
|
6
6
|
require_relative "errors/not_found_error"
|
7
|
-
require_relative "errors/
|
8
|
-
require_relative "errors/
|
7
|
+
require_relative "errors/payload_too_large_error"
|
8
|
+
require_relative "errors/internal_server_error"
|
9
9
|
require_relative "errors/service_unavailable_error"
|
10
|
+
require_relative "errors/too_many_requests_error"
|
10
11
|
|
11
12
|
module X
|
12
13
|
# Process HTTP responses
|
@@ -18,8 +19,9 @@ module X
|
|
18
19
|
401 => AuthenticationError,
|
19
20
|
403 => ForbiddenError,
|
20
21
|
404 => NotFoundError,
|
22
|
+
413 => PayloadTooLargeError,
|
21
23
|
429 => TooManyRequestsError,
|
22
|
-
500 =>
|
24
|
+
500 => InternalServerError,
|
23
25
|
503 => ServiceUnavailableError
|
24
26
|
}.freeze
|
25
27
|
JSON_CONTENT_TYPE_REGEXP = %r{application/(problem\+|)json}
|
@@ -41,6 +43,13 @@ module X
|
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
46
|
+
def configuration
|
47
|
+
{
|
48
|
+
array_class: array_class,
|
49
|
+
object_class: object_class
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
44
53
|
private
|
45
54
|
|
46
55
|
def success?(response)
|
data/lib/x/version.rb
CHANGED
data/sig/x.rbs
CHANGED
@@ -36,8 +36,8 @@ module X
|
|
36
36
|
class Error < StandardError
|
37
37
|
JSON_CONTENT_TYPE_REGEXP: Regexp
|
38
38
|
|
39
|
-
attr_reader object:
|
40
|
-
def initialize: (String msg, response: Net::HTTPResponse) -> void
|
39
|
+
attr_reader object: untyped
|
40
|
+
def initialize: (String msg, response: Net::HTTPResponse?) -> void
|
41
41
|
|
42
42
|
private
|
43
43
|
def json_response?: (Net::HTTPResponse response) -> bool
|
@@ -55,9 +55,15 @@ module X
|
|
55
55
|
class ForbiddenError < ClientError
|
56
56
|
end
|
57
57
|
|
58
|
+
class InternalServerError < ServerError
|
59
|
+
end
|
60
|
+
|
58
61
|
class NotFoundError < ClientError
|
59
62
|
end
|
60
63
|
|
64
|
+
class PayloadTooLargeError < ClientError
|
65
|
+
end
|
66
|
+
|
61
67
|
class TooManyRedirectsError < ClientError
|
62
68
|
end
|
63
69
|
|
@@ -87,7 +93,8 @@ module X
|
|
87
93
|
DEFAULT_OPEN_TIMEOUT: Integer
|
88
94
|
DEFAULT_READ_TIMEOUT: Integer
|
89
95
|
DEFAULT_WRITE_TIMEOUT: Integer
|
90
|
-
NETWORK_ERRORS: Array[(singleton(
|
96
|
+
NETWORK_ERRORS: Array[(singleton(Errno::ECONNREFUSED) | singleton(Errno::ECONNRESET) | singleton(Net::OpenTimeout) | singleton(Net::ReadTimeout) | singleton(OpenSSL::SSL::SSLError))]
|
97
|
+
|
91
98
|
extend Forwardable
|
92
99
|
@http_client: Net::HTTP
|
93
100
|
|
@@ -100,6 +107,7 @@ module X
|
|
100
107
|
def send_request: (Net::HTTPRequest request) -> Net::HTTPResponse
|
101
108
|
def base_uri=: (URI::Generic | String base_url) -> void
|
102
109
|
def debug_output: -> IO?
|
110
|
+
def configuration: -> Hash[Symbol, untyped]
|
103
111
|
|
104
112
|
private
|
105
113
|
def apply_http_client_settings: (open_timeout: Float | Integer, read_timeout: Float | Integer, write_timeout: Float | Integer, debug_output: IO?) -> untyped
|
@@ -121,6 +129,7 @@ module X
|
|
121
129
|
attr_accessor user_agent: String
|
122
130
|
def initialize: (?content_type: String, ?user_agent: String) -> void
|
123
131
|
def build: (BearerTokenAuthenticator | OauthAuthenticator authenticator, Symbol http_method, URI::Generic uri, ?body: String?) -> (Net::HTTPRequest)
|
132
|
+
def configuration: -> Hash[Symbol, untyped]
|
124
133
|
|
125
134
|
private
|
126
135
|
def create_request: (Symbol http_method, URI::Generic uri, String? body) -> (Net::HTTPRequest)
|
@@ -149,13 +158,14 @@ module X
|
|
149
158
|
class ResponseHandler
|
150
159
|
DEFAULT_ARRAY_CLASS: Class
|
151
160
|
DEFAULT_OBJECT_CLASS: Class
|
152
|
-
ERROR_CLASSES: Hash[Integer, singleton(AuthenticationError) | singleton(BadRequestError) | singleton(ForbiddenError) | singleton(NotFoundError) | singleton(
|
161
|
+
ERROR_CLASSES: Hash[Integer, singleton(AuthenticationError) | singleton(BadRequestError) | singleton(ForbiddenError) | singleton(InternalServerError) | singleton(NotFoundError) | singleton(PayloadTooLargeError) | singleton(ServiceUnavailableError) | singleton(TooManyRequestsError)]
|
153
162
|
JSON_CONTENT_TYPE_REGEXP: Regexp
|
154
163
|
|
155
164
|
attr_accessor array_class: Class
|
156
165
|
attr_accessor object_class: Class
|
157
166
|
def initialize: (?array_class: Class, ?object_class: Class) -> void
|
158
|
-
def handle: (Net::HTTPResponse response) ->
|
167
|
+
def handle: (Net::HTTPResponse response) -> untyped
|
168
|
+
def configuration: -> Hash[Symbol, Class]
|
159
169
|
|
160
170
|
private
|
161
171
|
def success?: (Net::HTTPResponse response) -> bool
|
@@ -170,15 +180,80 @@ module X
|
|
170
180
|
@redirect_handler: RedirectHandler
|
171
181
|
@response_handler: ResponseHandler
|
172
182
|
|
173
|
-
|
183
|
+
attr_accessor access_token: String
|
184
|
+
attr_accessor access_token_secret: String
|
185
|
+
attr_accessor api_key: String
|
186
|
+
attr_accessor api_key_secret: String
|
187
|
+
attr_accessor bearer_token: String
|
188
|
+
attr_accessor base_uri: URI::Generic | String
|
189
|
+
attr_accessor open_timeout: Float | Integer
|
190
|
+
attr_accessor read_timeout: Float | Integer
|
191
|
+
attr_accessor write_timeout: Float | Integer
|
192
|
+
attr_accessor proxy_url: String
|
193
|
+
attr_accessor content_type: String
|
194
|
+
attr_accessor user_agent: String
|
195
|
+
attr_accessor debug_output: IO?
|
196
|
+
attr_accessor array_class: Class
|
197
|
+
attr_accessor object_class: Class
|
198
|
+
attr_accessor max_redirects: Integer
|
199
|
+
attr_accessor authenticator: BearerTokenAuthenticator | OauthAuthenticator
|
200
|
+
attr_accessor connection: Connection
|
201
|
+
attr_accessor request_builder: RequestBuilder
|
202
|
+
attr_accessor redirect_handler: RedirectHandler
|
203
|
+
attr_accessor response_handler: ResponseHandler
|
204
|
+
alias base_url base_uri
|
205
|
+
|
206
|
+
|
174
207
|
def initialize: (?bearer_token: String?, ?api_key: String?, ?api_key_secret: String?, ?access_token: String?, ?access_token_secret: String?, ?base_url: URI::Generic | String, ?content_type: String, ?user_agent: String, ?open_timeout: Float | Integer, ?read_timeout: Float | Integer, ?write_timeout: Float | Integer, ?proxy_url: URI::Generic? | String?, ?debug_output: IO?, ?array_class: Class, ?object_class: Class, ?max_redirects: Integer) -> void
|
175
|
-
def get: (String endpoint) ->
|
176
|
-
def post: (String endpoint, ?
|
177
|
-
def put: (String endpoint, ?
|
178
|
-
def delete: (String endpoint) ->
|
208
|
+
def get: (String endpoint) -> untyped
|
209
|
+
def post: (String endpoint, ?String? body) -> untyped
|
210
|
+
def put: (String endpoint, ?String? body) -> untyped
|
211
|
+
def delete: (String endpoint) -> untyped
|
179
212
|
|
180
213
|
private
|
181
214
|
def initialize_authenticator: (String? bearer_token, String? api_key, String? api_key_secret, String? access_token, String? access_token_secret) -> (BearerTokenAuthenticator | OauthAuthenticator)
|
182
|
-
def send_request: (Symbol http_method, String endpoint, ?
|
215
|
+
def send_request: (Symbol http_method, String endpoint, ?String? body) -> untyped
|
183
216
|
end
|
217
|
+
|
218
|
+
module MediaUpload
|
219
|
+
MAX_RETRIES: Integer
|
220
|
+
BYTES_PER_MB: Integer
|
221
|
+
MEDIA_CATEGORIES: Array[String]
|
222
|
+
DM_GIF: String
|
223
|
+
DM_IMAGE: String
|
224
|
+
DM_VIDEO: String
|
225
|
+
SUBTITLES: String
|
226
|
+
TWEET_GIF: String
|
227
|
+
TWEET_IMAGE: String
|
228
|
+
TWEET_VIDEO: String
|
229
|
+
DEFAULT_MIME_TYPE: String
|
230
|
+
MIME_TYPES: Array[String]
|
231
|
+
GIF_MIME_TYPE: String
|
232
|
+
JPEG_MIME_TYPE: String
|
233
|
+
MP4_MIME_TYPE: String
|
234
|
+
PNG_MIME_TYPE: String
|
235
|
+
SUBRIP_MIME_TYPE: String
|
236
|
+
WEBP_MIME_TYPE: String
|
237
|
+
MIME_TYPE_MAP: Hash[String, String]
|
238
|
+
extend MediaUpload
|
239
|
+
|
240
|
+
def media_upload: (client: Client, file_path: String, media_category: String, ?media_type: String, ?boundary: String) -> untyped
|
241
|
+
def chunked_media_upload: (client: Client, file_path: String, media_category: String, ?media_type: String, ?boundary: String, ?chunk_size_mb: Integer) -> untyped
|
242
|
+
def await_processing: (client: Client, media: untyped) -> untyped
|
243
|
+
|
244
|
+
private
|
245
|
+
def validate!: (file_path: String, media_category: String) -> nil
|
246
|
+
def infer_media_type: (String file_path, String media_category) -> String
|
247
|
+
def init: (Client upload_client, String file_path, String media_type, String media_category) -> untyped
|
248
|
+
def split: (String file_path, Integer chunk_size) -> Array[String]
|
249
|
+
def append: (Client upload_client, Array[String] chunk_paths, untyped media, String media_type, ?String boundary) -> Array[String]
|
250
|
+
def upload_chunk: (Client upload_client, String query, String chunk_path, String media_type, String boundary) -> Integer?
|
251
|
+
def cleanup_chunk: (String chunk_path) -> Integer?
|
252
|
+
def finalize: (Client upload_client, untyped media) -> untyped
|
253
|
+
def construct_upload_body: (String file_path, String media_type, ?String boundary) -> String
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
class Dir
|
258
|
+
def self.mktmpdir: (?String? prefix_suffix) -> String
|
184
259
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: x
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Erik Berlin
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-10-
|
11
|
+
date: 2023-10-08 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -31,12 +31,15 @@ files:
|
|
31
31
|
- lib/x/errors/client_error.rb
|
32
32
|
- lib/x/errors/error.rb
|
33
33
|
- lib/x/errors/forbidden_error.rb
|
34
|
+
- lib/x/errors/internal_server_error.rb
|
34
35
|
- lib/x/errors/network_error.rb
|
35
36
|
- lib/x/errors/not_found_error.rb
|
37
|
+
- lib/x/errors/payload_too_large_error.rb
|
36
38
|
- lib/x/errors/server_error.rb
|
37
39
|
- lib/x/errors/service_unavailable_error.rb
|
38
40
|
- lib/x/errors/too_many_redirects_error.rb
|
39
41
|
- lib/x/errors/too_many_requests_error.rb
|
42
|
+
- lib/x/media_upload.rb
|
40
43
|
- lib/x/oauth_authenticator.rb
|
41
44
|
- lib/x/redirect_handler.rb
|
42
45
|
- lib/x/request_builder.rb
|