Class: ActiveStorage::Crucible::Transformer

Inherits:
AsyncVariants::Transformer
  • Object
show all
Defined in:
lib/active_storage/crucible/transformer.rb

Instance Method Summary collapse

Instance Method Details

#initiate(source_url:, callback_url:, variant_record_id:, **options) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/active_storage/crucible/transformer.rb', line 8

def initiate(source_url:, callback_url:, variant_record_id:, **options)
  variant_record = ActiveStorage::VariantRecord.find(variant_record_id)
  blob = variant_record.blob

  rotation = blob.["rotation"].to_i
  video_format = blob.["video_format"]

  source_url = PresignedUrl.for(blob, method: :get)
  dimensions = extract_dimensions(options)

  if blob.video? && !video_output_format?(options[:format])
    output_blob = create_output_blob(blob, variant_record, options)
    variant_url = PresignedUrl.for(output_blob, method: :put)

    preview_blob = ActiveStorage::Blob.create_before_direct_upload!(
      filename: "#{blob.filename.base}.jpg",
      content_type: "image/jpeg",
      service_name: blob.service_name,
      byte_size: 0,
      checksum: "0",
    )
    preview_blob.[:analyzed] = true

    # Pass the requested variant format so Crucible writes the right
    # file extension via vips and PUTs with a Content-Type that matches
    # what we signed the variant URL for (anything else gives
    # 403 SignatureDoesNotMatch). Crucible derives the Content-Type
    # from `format` via Marcel so there's a single source of truth.
    Client.new.post("#{endpoint}/video/preview", {
      blob_url: source_url,
      dimensions: dimensions,
      rotation: rotation,
      format: options[:format]&.to_s,
      preview_image_url: PresignedUrl.for(preview_blob, method: :put),
      preview_image_variant_url: variant_url,
      callback_url: callback_url,
    })
  elsif blob.video?
    format = video_format || options[:format].to_s
    output_blob = create_output_blob(blob, variant_record, options.merge(format: format))
    variant_url = PresignedUrl.for(output_blob, method: :put)

    # Only pass `format` -- Crucible derives Content-Type from it via
    # the same canonical mapping output_content_type uses on this side,
    # so the PUT header always matches what the URL was signed for.
    Client.new.post("#{endpoint}/video/variant", {
      blob_url: source_url,
      variant_url: variant_url,
      dimensions: dimensions,
      rotation: rotation,
      format: format,
      callback_url: callback_url,
    })
  else
    output_blob = create_output_blob(blob, variant_record, options)
    variant_url = PresignedUrl.for(output_blob, method: :put)

    Client.new.post("#{endpoint}/image/variant", {
      blob_url: source_url,
      variant_url: variant_url,
      dimensions: dimensions,
      rotation: rotation,
      format: options[:format]&.to_s,
      callback_url: callback_url,
    })
  end
end

#process_preview(blob:, variation:) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/active_storage/crucible/transformer.rb', line 76

def process_preview(blob:, variation:)
  return if blob.preview_image.attached?

  preview_image_blob = ActiveStorage::Blob.create_before_direct_upload!(
    filename: "#{blob.filename.base}.jpg",
    content_type: "image/jpeg",
    service_name: blob.service_name,
    byte_size: 0,
    checksum: "0",
  )
  preview_image_blob.[:analyzed] = true
  blob.preview_image.attach(preview_image_blob)

  variant_record = preview_image_blob.variant_records.create_or_find_by!(variation_digest: variation.digest)
  return if variant_record.state.in?(%w[processing processed])
  variant_record.update!(state: "processing")

  variant_blob = ActiveStorage::Blob.create_before_direct_upload!(
    filename: "#{blob.filename.base}.#{variation.format}",
    content_type: variation.content_type,
    service_name: blob.service_name,
    byte_size: 0,
    checksum: "0",
  )
  variant_blob.[:analyzed] = true
  variant_record.image.attach(variant_blob)

  rotation = blob.["rotation"].to_i
  callback_url = ActiveStorage::AsyncVariants.callback_url_for(variant_record)
  Client.new.post("#{endpoint}/video/preview", {
    blob_url: PresignedUrl.for(blob, method: :get),
    dimensions: extract_dimensions(variation.transformations),
    rotation: rotation,
    preview_image_url: PresignedUrl.for(preview_image_blob, method: :put),
    preview_image_variant_url: PresignedUrl.for(variant_blob, method: :put),
    callback_url: callback_url,
  })
end