Module: X::Uploader::API

Included in:
Client
Defined in:
x-uploader/lib/x/uploader/api.rb

Overview

The upload methods mixed into a client, each of which calls an uploader with the client

The x gem includes it into X::Client. With x-core and x-uploader alone, include it yourself: X::Client.include(X::Uploader::API). Each method passes the object it is included into to an uploader as its client, which is an X::Client, so it belongs in X::Client or a subclass.

Instance Method Summary collapse

Instance Method Details

#add_alt_text(media, text) ⇒ UploadedMedia

Describe uploaded media with alt text, for people who cannot see it

Examples:

Describe an image

client.add_alt_text(media, "A cat asleep on a keyboard")

Describe an image as it is uploaded

media = client.add_alt_text(client.upload_media("cat.jpg"), "A cat asleep on a keyboard")

Parameters:

  • media (UploadedMedia, Hash, #media_key, String, Integer) —

    the uploaded media, media that has a media key, such as X::Media, the media key, or the media identifier

  • text (String) —

    the alt text, of 1 to 1,000 characters

Returns:

  • (UploadedMedia) —

    the media given, as uploaded media, which a call can be chained to

Raises:

  • (ArgumentError) —

    if the alt text is empty or longer than the API takes, before a request

  • (ArgumentError) —

    if the media given is nil, holds no identifier, or is neither media, a media key, nor a media identifier, or its media key names none

  • (MissingMediaData) —

    if the response holds no metadata or carries no body at all



209
210
211
# File 'x-uploader/lib/x/uploader/api.rb', line 209

def add_alt_text(media, text)
  Metadata.add_alt_text(media, text, client: _ = self)
end

#add_subtitles(video, subtitles, language_code, **options) ⇒ UploadedMedia

Attach uploaded subtitles to an uploaded video

Examples:

Subtitle a video in English

client.add_subtitles(video, subtitles, "EN", display_name: "English")

Parameters:

  • video (UploadedMedia, Hash, #media_key, String, Integer) —

    the uploaded video, media that has a media key, such as X::Media, or its media identifier

  • subtitles (UploadedMedia, Hash, #media_key, String, Integer) —

    the uploaded subtitles, media that has a media key, or their media identifier

  • language_code (String) —

    the language of the subtitles, such as EN

  • options (Hash) —

    the options of Metadata#add_subtitles

Options Hash (**options):

  • :display_name (String, nil) — default: nil —

    the name of the language shown to viewers, such as English, or nil for none

  • :media_category (String, Symbol) — default: "tweet_video" —

    the category the video was uploaded as, tweet_video or amplify_video, in any case, or TweetVideo or AmplifyVideo, as the subtitles endpoint names them

Returns:

  • (UploadedMedia) —

    the video given, as uploaded media, which a call can be chained to

Raises:

  • (ArgumentError) —

    if the media category is neither tweet_video nor amplify_video, or the language code is not two letters

  • (ArgumentError) —

    if the video or the subtitles are nil, hold no identifier, are neither media, a media key, nor a media identifier, have a media key that names none, or an identifier the API does not take

  • (MissingMediaData) —

    if the response holds no metadata or carries no body at all



234
235
236
# File 'x-uploader/lib/x/uploader/api.rb', line 234

def add_subtitles(video, subtitles, language_code, **options) # steep:ignore DifferentMethodParameterKind
  Metadata.add_subtitles(video, subtitles, language_code, client: _ = self, **Utils.without_client(options))
end

#await_media_processing(media, **options) ⇒ UploadedMedia

Wait until media has been processed, whether its processing succeeded or failed

It returns the status X reported, which failed? tells a failure by, and ready? a success by, since a status in no state X documents is neither; await_media_processing! raises for either instead. Media that already says its processing succeeded or failed, or holds an upload response that names no processing, such as that of an image, is returned as it is, without a request.

Examples:

Wait for a video uploaded with chunked_upload_media

video = client.await_media_processing(video)
warn video.processing_info.dig("error", "message") if video.failed?

Parameters:

  • media (UploadedMedia, Hash, #media_key, String, Integer) —

    the uploaded media, media that has a media key, such as X::Media, the media key, or the media identifier

  • options (Hash) —

Options Hash (**options):

  • :processing_timeout (Integer, Float, nil) — default: 600 —

    the seconds from now to wait for processing to finish, checks and all, of at least 0, or nil to wait for as long as processing takes

Returns:

  • (UploadedMedia) —

    the uploaded media, which holds the processing status, failed or not, or the media given, as uploaded media, if its processing has already ended

Raises:

  • (ArgumentError) —

    if the processing timeout is neither nil nor a finite number of seconds of at least 0

  • (ArgumentError) —

    if the media given is nil, holds no identifier, or is neither media, a media key, nor a media identifier, or its media key names none

  • (MissingMediaData) —

    if a status response holds no media or carries no body at all

  • (MediaProcessingTimeout) —

    if the media is still processing once the processing timeout would pass



167
168
169
# File 'x-uploader/lib/x/uploader/api.rb', line 167

def await_media_processing(media, **options) # steep:ignore DifferentMethodParameterKind
  MediaUpload.await_processing(media, client: _ = self, **Utils.without_client(options))
end

#await_media_processing!(media, **options) ⇒ UploadedMedia

Wait until media has been processed, raising if its processing failed

Examples:

Wait for a video uploaded with chunked_upload_media, raising if X could not process it

client.await_media_processing!(video)

Parameters:

  • media (UploadedMedia, Hash, #media_key, String, Integer) —

    the uploaded media, media that has a media key, such as X::Media, the media key, or the media identifier

  • options (Hash) —

Options Hash (**options):

  • :processing_timeout (Integer, Float, nil) — default: 600 —

    the seconds from now to wait for processing to finish, checks and all, of at least 0, or nil to wait for as long as processing takes

Returns:

  • (UploadedMedia) —

    the uploaded media, which holds the processing status, or the media given, as uploaded media, if its processing has already succeeded

Raises:

  • (ArgumentError) —

    if the processing timeout is neither nil nor a finite number of seconds of at least 0

  • (ArgumentError) —

    if the media given is nil, holds no identifier, or is neither media, a media key, nor a media identifier, or its media key names none

  • (MissingMediaData) —

    if a status response holds no media or carries no body at all

  • (MediaProcessingFailed) —

    if media processing failed, or ended in no state X documents, with the status X reported, or the media given, without a request, if it already says its processing failed

  • (MediaProcessingTimeout) —

    if the media is still processing once the processing timeout would pass



190
191
192
# File 'x-uploader/lib/x/uploader/api.rb', line 190

def await_media_processing!(media, **options) # steep:ignore DifferentMethodParameterKind
  MediaUpload.await_processing!(media, client: _ = self, **Utils.without_client(options))
end

#chunked_upload_media(media, **options) ⇒ UploadedMedia

Upload media in chunks, without waiting for it to be processed

It is the way to upload media without waiting for X to process it: #upload_media waits for the processing of media X processes, such as a video, and this does not. It uploads the media as #upload_media uploads a video, a chunk at a time, but returns once the upload is finalized, so that the caller can go on while X processes a long video, and wait for it with #await_media_processing or #await_media_processing! when it needs it. It uploads in chunks whatever the media, an image as well, and adds no alt text. The chunks are sent by threads of their own, so the on_response of the client runs on those threads for the response of each chunk.

Each chunk is a request a rate limit can refuse, which fails the upload with ChunkedUploadFailed unless the client retries it, which it does only max_rate_limit_retries times, 0 by default, so upload a large video with a client whose max_rate_limit_retries is set, such as X::Client.new(max_rate_limit_retries: 3).

Examples:

Upload a long video, and wait for X to process it once it is needed

video = client.chunked_upload_media("talk.mp4", concurrency: 8)
client.create_post("Watch the talk", media_ids: [client.await_media_processing!(video)])

Parameters:

  • media (String, Pathname, IO, StringIO) —

    the path to the media to upload, or an IO open on it

  • options (Hash) —

Options Hash (**options):

  • :media_category (String, Symbol, nil) — default: nil —

    the media category, in any case, inferred when nil from the bytes the media begins with, or else from the name of its file

  • :media_type (String, nil) — default: nil —

    the MIME type of the media, sent as it is given, or inferred from the media and category when nil

  • :chunk_size (Integer, nil) — default: nil —

    the size of each chunk in bytes, of at most 5,242,880, or nil for MediaUpload::DEFAULT_CHUNK_SIZE, or as much more as the media needs

  • :concurrency (Integer) — default: 4 —

    the number of chunks uploaded at once, of 1 to MediaUpload::MAX_CONCURRENCY

  • :shared (Boolean, nil) — default: nil —

    whether the media can be sent in more than one direct message, or nil to leave it to the API

  • :additional_owners (Array<Integer, String>, nil) — default: nil —

    the identifiers of the users, other than the one who uploads it, who may use the media, or nil for none

Returns:

  • (UploadedMedia) —

    the uploaded media, which holds the response that finalized the upload, and the processing status of media that X processes

Raises:

  • (ArgumentError) —

    if the media is neither a path nor an IO, or is a String that holds a NUL byte or a line break, as the contents of media given in place of its path do

  • (InvalidMedia) —

    if the file does not exist, the media cannot be read, or is empty, or it is larger than the API takes of its category

  • (ArgumentError) —

    if the media category is invalid, the chunk size is not a positive Integer, is larger than a segment the API takes, or would need more segments than the API numbers, the concurrency is not 1 to MAX_CONCURRENCY, shared is neither true, false, nor nil, or additional_owners is neither nil nor an Array of at least one user identifier

  • (InvalidMediaType) —

    if no media type is given and none can be inferred, or the one the media is, read from its bytes or else from the name of its file, is not one the category takes

  • (MissingMediaData) —

    if the response that initializes the upload holds no media to append the chunks to

  • (ChunkedUploadFailed) —

    if the upload is initialized, but a chunk cannot be appended, or it cannot be finalized, with the media it initialized



140
141
142
# File 'x-uploader/lib/x/uploader/api.rb', line 140

def chunked_upload_media(media, **options) # steep:ignore DifferentMethodParameterKind
  MediaUpload.chunked_upload(media, client: _ = self, **Utils.without_client(options))
end

#update_profile_banner(media, **options) ⇒ void

This method returns an undefined value.

Update the profile banner of the authenticated user from a file

Examples:

Update the profile banner

client.update_profile_banner("banner.png", width: 1500, height: 500)

Parameters:

  • media (String, Pathname, IO, StringIO) —

    the path to the image, or an IO that reads it

  • options (Hash) —

    the options of X::Uploader::Account#update_profile_banner, which give the region of the image to use

Options Hash (**options):

  • :width (Integer, nil) — default: nil —

    the width of the region, in pixels, of at least 1

  • :height (Integer, nil) — default: nil —

    the height of the region, in pixels, of at least 1

  • :offset_left (Integer, nil) — default: nil —

    the pixels by which the region is offset from the left, of at least 0

  • :offset_top (Integer, nil) — default: nil —

    the pixels by which the region is offset from the top, of at least 0

Raises:

  • (InvalidMedia) —

    if the file does not exist

  • (ArgumentError) —

    if the media is neither a path nor an IO, or a width, height, or offset is neither nil nor an Integer of the pixels it takes

  • (InvalidMedia) —

    if the media cannot be read, is empty, or is larger than the 5 megabytes X takes

  • (InvalidMediaType) —

    if the image does not begin with the signature of a GIF, a JPEG, or a PNG



272
273
274
# File 'x-uploader/lib/x/uploader/api.rb', line 272

def update_profile_banner(media, **options) # steep:ignore DifferentMethodParameterKind
  Account.update_profile_banner(media, client: _ = self, **Utils.without_client(options))
end

#update_profile_image(media) ⇒ void

This method returns an undefined value.

Update the profile image of the authenticated user from a file

Examples:

Update the profile image

client.update_profile_image("avatar.png")

Parameters:

  • media (String, Pathname, IO, StringIO) —

    the path to the image, or an IO that reads it

Raises:

  • (InvalidMedia) —

    if the file does not exist

  • (ArgumentError) —

    if the media is neither a path nor an IO

  • (InvalidMedia) —

    if the media cannot be read, is empty, or is larger than the 700 kilobytes the API takes

  • (InvalidMediaType) —

    if the image does not begin with the signature of a GIF, a JPEG, or a PNG



249
250
251
# File 'x-uploader/lib/x/uploader/api.rb', line 249

def update_profile_image(media)
  Account.update_profile_image(media, client: _ = self)
end

#upload_media(media, **options) ⇒ UploadedMedia

Upload media and wait for it to be processed

The media is a path, or an IO open on it. Media given as a String or a Pathname is read from the file it names, and media given as a File or a Tempfile through that IO, a chunk at a time, so media of any size uploads without being held in memory; media given as any other IO, such as a StringIO, is read to its end and held.

A video or subtitles upload in chunks, which send their media type, as a single request does not. The media category is inferred from the bytes the media begins with, or else from the name of its file, unless media_category says what it is. The chunks are sent by threads of their own, so the on_response of the client runs on those threads for the response of each chunk.

An image, and a GIF that a single request takes, upload in a single request, which takes no chunks and no media type, so chunk_size, concurrency, and media_type are ignored for them: a chunk_size or a concurrency that is not valid still raises, but none is sent. Media given shared: true uploads in chunks, and uses all three.

Each chunk is a request a rate limit can refuse, which fails the upload with ChunkedUploadFailed unless the client retries it, which it does only max_rate_limit_retries times, 0 by default, so upload a large video with a client whose max_rate_limit_retries is set, such as X::Client.new(max_rate_limit_retries: 3).

Examples:

Upload an image with alt text and post it

media = client.upload_media("cat.jpg", alt_text: "A cat asleep on a keyboard")
client.create_post("Look at this cat", media_ids: [media])

Upload an image held in memory, whose category its signature names

client.upload_media(StringIO.new(File.binread("cat.png")))

Upload media of a category no signature names

client.upload_media(StringIO.new(subtitles), media_category: "subtitles")

Parameters:

  • media (String, Pathname, IO, StringIO) —

    the path to the media to upload, or an IO open on it

  • options (Hash) —

    the options of MediaUpload#upload

Options Hash (**options):

  • :media_category (String, Symbol, nil) — default: nil —

    the media category, in any case, inferred when nil from the bytes the media begins with, or else from the name of its file

  • :alt_text (String, nil) — default: nil —

    alt text describing the media, of 1 to 1,000 characters, added once the media is uploaded and processed, or nil for none

  • :processing_timeout (Integer, Float, nil) — default: 600 —

    the seconds to wait for media that X processes, such as a video, to process, of at least 0, or nil to wait for as long as processing takes

  • :media_type (String, nil) — default: nil —

    the MIME type of media uploaded in chunks, inferred from the media and category when nil; ignored for media uploaded in a single request, such as an image

  • :chunk_size (Integer, nil) — default: nil —

    the size of each chunk in bytes, of at most 5,242,880, or nil for MediaUpload::DEFAULT_CHUNK_SIZE, or as much more as the media needs; ignored for media uploaded in a single request, such as an image

  • :concurrency (Integer) — default: 4 —

    the number of chunks uploaded at once, of 1 to MediaUpload::MAX_CONCURRENCY; ignored for media uploaded in a single request, such as an image

  • :shared (Boolean, nil) — default: nil —

    whether the media can be sent in more than one direct message, or nil to leave it to the API; media that is shared uploads in chunks

  • :additional_owners (Array<Integer, String>, nil) — default: nil —

    the identifiers of the users, other than the one who uploads it, who may use the media, or nil for none

Returns:

  • (UploadedMedia) —

    the uploaded media, which holds the upload response, or the processing status of media that X processes

Raises:

  • (ArgumentError) —

    if the media is neither a path nor an IO, or is a String that holds a NUL byte or a line break, as the contents of media given in place of its path do

  • (InvalidMedia) —

    if the file does not exist

  • (InvalidMedia) —

    if the media cannot be read, or is empty, which holds nothing to upload

  • (InvalidMedia) —

    if the media is larger than the API takes of its category, whatever the account: 5 megabytes of an image, 15 of a GIF, and one of subtitles, or larger than the 16 gigabytes it takes of any

  • (ArgumentError) —

    if the media category is invalid, the alt text is empty or longer than the API takes, the chunk size is not a positive Integer, is larger than a segment the API takes, or would need more segments than the API numbers, the concurrency is not 1 to MAX_CONCURRENCY, the processing timeout is neither nil nor a finite number of seconds of at least 0, shared is neither true, false, nor nil, or additional_owners is neither nil nor an Array of at least one user identifier

  • (InvalidMediaType) —

    if no media category is given for media whose type neither its bytes nor the name of its file names, or the category does not take the type of the media

  • (MissingMediaData) —

    if a response of the upload holds no media, or carries no body at all

  • (ChunkedUploadFailed) —

    if media uploaded in chunks is initialized, but a chunk cannot be appended, or it cannot be finalized, with the media it initialized

  • (MediaProcessingFailed) —

    if media processing failed, or ended in no state X documents, with the status X reported

  • (MediaProcessingTimeout) —

    if the media is still processing once the processing timeout would pass

  • (MediaProcessingCheckFailed) —

    if the media is uploaded, but a check of its processing fails, as when the API answers it with an error, with the media it uploaded

  • (AltTextFailed) —

    if the media is uploaded, but its alt text cannot be added, with the media it uploaded



89
90
91
# File 'x-uploader/lib/x/uploader/api.rb', line 89

def upload_media(media, **options) # steep:ignore DifferentMethodParameterKind
  MediaUpload.upload(media, client: _ = self, **Utils.without_client(options))
end