Module: X::MediaUploader
Overview
Uploads media files to the X API
Constant Summary collapse
- MAX_RETRIES =
Maximum number of retry attempts for failed uploads
3- BYTES_PER_MB =
Number of bytes per megabyte
1_048_576- MIME_TYPES =
Supported MIME types
%w[image/gif image/jpeg video/mp4 image/png application/x-subrip image/webp].freeze
- MIME_TYPE_MAP =
Mapping of file extensions to MIME types
{"gif" => GIF_MIME_TYPE, "jpg" => JPEG_MIME_TYPE, "jpeg" => JPEG_MIME_TYPE, "mp4" => MP4_MIME_TYPE, "png" => PNG_MIME_TYPE, "srt" => SUBRIP_MIME_TYPE, "webp" => WEBP_MIME_TYPE}.freeze
- PROCESSING_INFO_STATES =
Processing states that indicate completion
%w[failed succeeded].freeze
Instance Method Summary collapse
-
#await_processing(client:, media:) ⇒ Hash?
Wait for media processing to complete.
-
#await_processing!(client:, media:) ⇒ Hash?
Wait for media processing and raise on failure.
-
#chunked_upload(client:, file_path:, media_category:, media_type: infer_media_type(file_path, media_category), boundary: SecureRandom.hex, chunk_size_mb: 1) ⇒ Hash?
Perform a chunked upload for large files.
-
#infer_media_type(file_path, media_category) ⇒ String
Infer the media type from file path and category.
-
#upload(client:, file_path:, media_category:, boundary: SecureRandom.hex) ⇒ Hash?
Upload a file to the X API.
-
#upload_binary(client:, content:, media_category:, boundary: SecureRandom.hex) ⇒ Hash?
Upload binary content to the X API.
Instance Method Details
#await_processing(client:, media:) ⇒ Hash?
Wait for media processing to complete
95 96 97 98 99 100 101 102 |
# File 'lib/x/media_uploader.rb', line 95 def await_processing(client:, media:) loop do status = client.get("media/upload?command=STATUS&media_id=#{media["id"]}")&.fetch("data") return status if status.nil? || !status["processing_info"] || PROCESSING_INFO_STATES.include?(status["processing_info"]["state"]) sleep status["processing_info"]["check_after_secs"].to_i end end |
#await_processing!(client:, media:) ⇒ Hash?
Wait for media processing and raise on failure
113 114 115 116 117 118 |
# File 'lib/x/media_uploader.rb', line 113 def await_processing!(client:, media:) status = await_processing(client:, media:) raise "Media processing failed" if status&.dig("processing_info", "state") == "failed" status end |
#chunked_upload(client:, file_path:, media_category:, media_type: infer_media_type(file_path, media_category), boundary: SecureRandom.hex, chunk_size_mb: 1) ⇒ Hash?
Perform a chunked upload for large files
77 78 79 80 81 82 83 84 85 |
# File 'lib/x/media_uploader.rb', line 77 def chunked_upload(client:, file_path:, media_category:, media_type: infer_media_type(file_path, media_category), boundary: SecureRandom.hex, chunk_size_mb: 1) MediaUploadValidator.validate_file_path!(file_path:) MediaUploadValidator.validate_media_category!(media_category:) media = init(client:, file_path:, media_type:, media_category:) chunk_size = chunk_size_mb * BYTES_PER_MB append(client:, file_paths: split(file_path, chunk_size), media:, boundary:) client.post("media/upload/#{media["id"]}/finalize")&.fetch("data") end |
#infer_media_type(file_path, media_category) ⇒ String
Infer the media type from file path and category
128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/x/media_uploader.rb', line 128 def infer_media_type(file_path, media_category) case media_category.downcase when TWEET_GIF, DM_GIF then GIF_MIME_TYPE when TWEET_VIDEO, DM_VIDEO then MP4_MIME_TYPE when SUBTITLES then SUBRIP_MIME_TYPE else extension = File.extname(file_path).delete(".").downcase MIME_TYPE_MAP.fetch(extension) do raise InvalidMediaType, "unable to determine MIME type from file extension: #{file_path.inspect}" end end end |
#upload(client:, file_path:, media_category:, boundary: SecureRandom.hex) ⇒ Hash?
Upload a file to the X API
40 41 42 43 |
# File 'lib/x/media_uploader.rb', line 40 def upload(client:, file_path:, media_category:, boundary: SecureRandom.hex) MediaUploadValidator.validate_file_path!(file_path:) upload_binary(client:, content: File.binread(file_path), media_category:, boundary:) end |
#upload_binary(client:, content:, media_category:, boundary: SecureRandom.hex) ⇒ Hash?
Upload binary content to the X API
56 57 58 59 60 61 |
# File 'lib/x/media_uploader.rb', line 56 def upload_binary(client:, content:, media_category:, boundary: SecureRandom.hex) MediaUploadValidator.validate_media_category!(media_category:) upload_body = construct_upload_body(content:, media_category:, boundary:) headers = {"Content-Type" => "multipart/form-data; boundary=#{boundary}"} client.post("media/upload", upload_body, headers:)&.fetch("data") end |