Class: X::UploadedMedia

Inherits:
Object
  • Object
show all
Defined in:
x-uploads/lib/x/uploads/uploaded_media.rb

Overview

Media that was uploaded: the response of an upload, or the status of its processing

Both hold the identifier and the media key, and the status of media that X processes, such as a video, holds the state of its processing. The object is frozen, and reads as the Hash it was built from with [], fetch, dig, key?, and to_json, so media works as it did when an upload returned a Hash.

The attributes hold the response as it arrived, so media is the String X sent, and the media writes itself as JSON with the identifier a String, which a reader of JSON that holds numbers as floats reads whole. The identifier is read as an Integer by id alone, as a resource of the object layer reads its own.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attrs) ⇒ UploadedMedia

Initialize uploaded media

The media must hold its identifier under the String key "id", as every upload and status response does, so that the media can be attached to a post, and #id raises for none.

Examples:

Refer to media that was uploaded before

X::UploadedMedia.new({"id" => "1880028106020515840"})

Parameters:

  • attrs (Hash{String => Object}) —

    the data of an upload or status response

Raises:

  • (ArgumentError) —

    if the attributes are not a Hash, or hold no "id" that is a media ID the API takes: an Integer that is not negative, or a String of digits alone, of 1 to 19 digits



84
85
86
87
88
89
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 84

def initialize(attrs)
  @attrs = deep_freeze(Hash.try_convert(attrs) || raise(ArgumentError, "attrs must be a Hash, not #{attrs.inspect}"))
  raise ArgumentError, format(NO_MEDIA_ID, self["id"].inspect) unless media_id?(self["id"])

  freeze
end

Instance Attribute Details

#attrs ⇒ Hash{String => Object} (readonly) Also known as: to_h

The response data the media was built from

Examples:

Get the attributes

media.attrs # => {"id" => "1880028106020515840", "media_key" => "3_1880028106020515840", ...}

Returns:

  • (Hash{String => Object}) —

    the frozen attributes



69
70
71
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 69

def attrs
  @attrs
end

Instance Method Details

#==(other) ⇒ Boolean Also known as: eql?

Check whether another object is the same uploaded media

Examples:

Compare media

media == X::UploadedMedia.new(media.to_h) # => true

Parameters:

  • other (Object) —

    the object to compare

Returns:

  • (Boolean) —

    true if the other object is uploaded media with the same attributes



276
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 276

def ==(other) = other.instance_of?(self.class) && attrs.eql?(other.attrs)

#[](key) ⇒ Object?

Read an attribute of the response, as from the Hash an upload used to return

Examples:

Get the identifier

media["id"] # => "1880028106020515840"

Parameters:

  • key (String) —

    the name of the attribute

Returns:

  • (Object, nil) —

    the value, or nil if the response holds none



215
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 215

def [](key) = attrs[key]

#as_json ⇒ Hash{String => Object}

The attributes of the response, as an encoder asks of an object of its own

Examples:

Store the response of an upload beside a record of it

record.update(upload: media.as_json)

Returns:

  • (Hash{String => Object}) —

    the frozen attributes



256
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 256

def as_json(*) = attrs

#bytesize ⇒ Integer?

The size of the media in bytes

Examples:

Get the size

media.bytesize # => 1048576

Returns:

  • (Integer, nil) —

    the size, if the response reports it



133
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 133

def bytesize = self["size"]

#check_after_secs ⇒ Integer?

The seconds X asks to wait before checking the processing again

Examples:

Get the wait

media.check_after_secs # => 5

Returns:

  • (Integer, nil) —

    the seconds, if X asks for a wait



172
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 172

def check_after_secs = dig("processing_info", "check_after_secs")

#dig(*keys) ⇒ Object?

Read a nested attribute of the response

Examples:

Get the state of the processing

media.dig("processing_info", "state") # => "succeeded"

Parameters:

  • keys (Array<String, Integer>) —

    the names that lead to the attribute

Returns:

  • (Object, nil) —

    the value, or nil if the response holds none



239
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 239

def dig(*keys) = attrs.dig(*keys)

#encode_with(coder) ⇒ void

This method returns an undefined value.

Write the state Marshal writes as YAML

YAML would write the instance variables of the media, and read them back into one that is not frozen, so it says how it is written: each part of the state Marshal writes, under its name.

Examples:

Write media as YAML

YAML.dump(client.upload_media("image.png"))

Parameters:

  • coder (Psych::Coder) —

    the coder YAML writes the media with



332
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 332

def encode_with(coder) = YAML_KEYS.zip(marshal_dump) { |key, value| coder[key] = value }

#expires_after_secs ⇒ Integer?

The seconds after the response within which the media can be attached to a post

X counts them from when it sent the response, which the media does not hold, so they are read as X reported them: media rebuilt from its attributes later, as from JSON it was stored as, holds the seconds of the response it was built from, not those it has left.

Examples:

Get the time after which media just uploaded can no longer be attached

Time.now + media.expires_after_secs # => 2026-09-19 12:00:00 -0700

Returns:

  • (Integer, nil) —

    the seconds, if the response reports them



145
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 145

def expires_after_secs = self["expires_after_secs"]

#failed? ⇒ Boolean

Check whether the processing of the media failed

Examples:

Check whether a video failed to process

media.failed?

Returns:

  • (Boolean) —

    true if the processing failed



193
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 193

def failed? = state.eql?("failed")

#fetch(key, *default) {|key| ... } ⇒ Object

Fetch an attribute of the response, as from the Hash an upload used to return

Examples:

Fetch the identifier

media.fetch("id") # => "1880028106020515840"

Fetch what a response may hold none of

media.fetch("processing_info", nil)

Parameters:

  • key (String) —

    the name of the attribute

  • default (Array<Object>) —

    the value to return for an attribute the response does not hold, if any

Yield Parameters:

  • key (String) —

    the name of an attribute the response does not hold

Yield Returns:

  • (Object) —

    the value to return in its place

Returns:

  • (Object) —

    the value

Raises:

  • (KeyError) —

    if the response holds no such attribute and neither a default nor a block is given



230
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 230

def fetch(key, *default, &) = attrs.fetch(key, *default, &) # steep:ignore UnresolvedOverloading

#hash ⇒ Integer

The hash code of the media, which equal media share

Examples:

Count the media uploaded

uploads.uniq.size

Returns:

  • (Integer) —

    the hash code



285
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 285

def hash = [self.class, attrs].hash

#id ⇒ Integer

The numeric media ID, which a post attaches the media by

It is the media ID the upload endpoints and a new post take, which #media_id reads too. The X::Media of x-resources, the media of a post as the object layer reads it, is identified by its media key instead, so its id is the media key, which #media_key reads here; both classes answer media_id and media_key alike.

It is read as strictly as x-resources reads an identifier: an Integer as it is, and a String of digits alone, with no sign, underscore, or whitespace, as a decimal number, so that " 1_0 " is no identifier, rather than 10.

Examples:

Get the media ID

media.id # => 1880028106020515840

Returns:

  • (Integer) —

    the media ID, whether the response held it as a String or an Integer



104
105
106
107
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 104

def id
  value = fetch("id")
  value.instance_of?(Integer) ? value : Integer(value, 10)
end

#init_with(coder) ⇒ void

This method returns an undefined value.

Restore media YAML read, frozen, as Marshal restores one

Examples:

Read media written as YAML

YAML.unsafe_load(YAML.dump(media)).media_key

Parameters:

  • coder (Psych::Coder) —

    the coder YAML read the media with

Raises:



342
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 342

def init_with(coder) = marshal_load(coder.map.values_at(*YAML_KEYS))

#inspect ⇒ String

Summarize the media for the console

Examples:

Inspect media

media.inspect # => #<X::UploadedMedia id=1880028106020515840 media_key="3_1880028106020515840" state=nil>

Returns:

  • (String) —

    the class name, identifier, media key, and state



293
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 293

def inspect = "#<#{self.class} id=#{id} media_key=#{media_key.inspect} state=#{state.inspect}>"

#key?(key) ⇒ Boolean

Check whether the response holds an attribute

Examples:

Check whether X processes the media

media.key?("processing_info")

Parameters:

  • key (String) —

    the name of the attribute

Returns:

  • (Boolean) —

    true if the response holds the attribute, whatever its value



248
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 248

def key?(key) = attrs.key?(key)

#marshal_dump ⇒ Array(Integer, Hash{String => Object})

The state Marshal writes

What is written is plain data, led by the number of its format, so that media written by one release of 1.x is read by a later one: its attributes, as the response held them.

Examples:

Cache what an upload returned, to attach it later

Rails.cache.write("upload", client.upload_media("image.png"))

Returns:

  • (Array(Integer, Hash{String => Object})) —

    the number of the format, then the attributes



304
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 304

def marshal_dump = [MARSHAL_FORMAT, attrs]

#marshal_load(state) ⇒ void

This method returns an undefined value.

Restore media Marshal read, built as the constructor builds it, deep-frozen

Examples:

Read what an upload returned from a cache

Marshal.load(Marshal.dump(media)).media_key

Parameters:

  • state (Array) —

    the state Marshal wrote

Raises:

  • (UnsupportedFormat) —

    if the state is of a format this release does not read

  • (ArgumentError) —

    if the attributes of the state are not a Hash, or hold no "id" of the media



315
316
317
318
319
320
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 315

def marshal_load(state)
  format, attrs = state
  raise UnsupportedFormat, "#{self.class} reads format #{MARSHAL_FORMAT} of Marshal, not #{format.inspect}" unless MARSHAL_FORMAT.eql?(format)

  initialize(attrs)
end

#media_id ⇒ Integer

The numeric media ID, as the X::Media of x-resources names it

It is the same as #id, under the name that reads the same on uploaded media and on the media of a post.

Examples:

Get the media ID

media.media_id # => 1880028106020515840

Returns:

  • (Integer) —

    the media ID, whether the response held it as a String or an Integer



117
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 117

def media_id = id

#media_key ⇒ String?

The media key, which names the type of the media and its media ID

Examples:

Get the media key

media.media_key # => "3_1880028106020515840"

Returns:

  • (String, nil) —

    the media key, if the response holds one



125
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 125

def media_key = self["media_key"]

#processing? ⇒ Boolean

Check whether X is still processing the media

Media X processes is still processing until its processing ends, which it does in two states alone: succeeded, which #ready? tells, and failed, which #failed? tells. In any other it is still processing, whether pending or in_progress, a state X does not document, or no state at all, so that a state X adds between the two it has is waited through as they are, rather than read as a failure. Media X does not process is not processing.

Examples:

Check whether a video is still processing

media.processing?

Returns:

  • (Boolean) —

    true if X reports processing of the media that has neither succeeded nor failed



185
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 185

def processing? = !(processing_info.nil? || ENDED_STATES.include?(state))

#processing_info ⇒ Hash{String => Object}?

What X reports of the processing of the media

Examples:

Get how far X has processed the media

media.processing_info&.fetch("progress_percent", nil)

Returns:

  • (Hash{String => Object}, nil) —

    the processing information, or nil for media X does not process



153
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 153

def processing_info = self["processing_info"]

#ready? ⇒ Boolean

Check whether the media can be attached to a post

Media whose processing information names no state, or a state X does not document, is not ready, since X has not said that its processing succeeded: it is still processing, as #processing? tells. Neither is media that holds its identifier and media key alone, as media built from an identifier does, such as the media add_alt_text returns for one, since it holds no response of X to say whether X processes it; await_media_processing checks it.

Examples:

Check whether a video can be posted

media.ready?

Returns:

  • (Boolean) —

    true if a response of X holds no processing of the media, or its processing succeeded



206
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 206

def ready? = processing_info.nil? ? !attrs.except(*IDENTIFYING_KEYS).empty? : state.eql?("succeeded")

#state ⇒ String?

The state of the processing of the media

It is read as X reported it, so a state X adds, which this release knows nothing of, is read as any other.

Examples:

Get the state

media.state # => "succeeded"

Returns:

  • (String, nil) —

    pending, in_progress, succeeded, failed, or any other state X reports, or nil for media X does not process



164
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 164

def state = dig("processing_info", "state")

#to_json(state = nil) ⇒ String

The attributes of the response as JSON

Media written into the body of a request is the response it holds, rather than the object itself.

Examples:

Attach the media to a post

client.post("tweets", {text: "Look at this cat", media: {media_ids: [media.id.to_s]}})

Parameters:

  • state (JSON::State, nil) (defaults to: nil) —

    the state the encoder generating the JSON around it passes

Returns:

  • (String) —

    the JSON of the attributes



267
# File 'x-uploads/lib/x/uploads/uploaded_media.rb', line 267

def to_json(state = nil) = as_json.to_json(state)