Class: Export::Packagers::Images

Inherits:
Object
  • Object
show all
Defined in:
lib/export/packagers/images.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(query_params:, project_id:) ⇒ Images

Returns a new instance of Images.



12
13
14
15
16
17
# File 'lib/export/packagers/images.rb', line 12

def initialize(query_params:, project_id:)
  @query_params = query_params
  @project_id = project_id
  @file_grouper = Export::FileGrouper.new
  @file_available_cache = {}
end

Instance Attribute Details

#project_idObject (readonly)

Returns the value of attribute project_id.



10
11
12
# File 'lib/export/packagers/images.rb', line 10

def project_id
  @project_id
end

#query_paramsObject (readonly)

Returns the value of attribute query_params.



10
11
12
# File 'lib/export/packagers/images.rb', line 10

def query_params
  @query_params
end

Instance Method Details

#add_manifest_row(image, name, rows) ⇒ Object (private)



117
118
119
120
121
122
123
124
125
# File 'lib/export/packagers/images.rb', line 117

def add_manifest_row(image, name, rows)
  rows << [
    image.id,
    name,
    image.image_file_file_size.to_i,
    image.width,
    image.height
  ]
end

#empty_previewObject (private)



142
143
144
145
146
147
# File 'lib/export/packagers/images.rb', line 142

def empty_preview
  {
    images: [],
    groups: []
  }
end

#file_available?(image) ⇒ Boolean

Returns:

  • (Boolean)


41
42
43
44
45
46
# File 'lib/export/packagers/images.rb', line 41

def file_available?(image)
  @file_available_cache.fetch(image.id) do
    path = image.image_file.path
    @file_available_cache[image.id] = path.present? && File.exist?(path)
  end
end

#file_path(image) ⇒ Object (private)



111
112
113
114
115
# File 'lib/export/packagers/images.rb', line 111

def file_path(image)
  path = image.image_file.path
  return path if path.present? && File.exist?(path)
  nil
end

#group_entries(images, max_bytes) ⇒ Object (private)



71
72
73
74
75
76
77
78
79
# File 'lib/export/packagers/images.rb', line 71

def group_entries(images, max_bytes)
  @file_grouper.group(
    items: images.to_a,
    max_bytes: max_bytes,
    size_extractor: ->(image) {
      file_available?(image) ? image.image_file_file_size.to_i : 0
    }
  )
end

#groups(max_bytes:) ⇒ Object



35
36
37
38
39
# File 'lib/export/packagers/images.rb', line 35

def groups(max_bytes:)
  return [] if image_ids.empty?

  group_entries(images_for_query, max_bytes)
end

#image_idsObject (private)



138
139
140
# File 'lib/export/packagers/images.rb', line 138

def image_ids
  Array(query_params[:image_id]).flatten.compact.map(&:to_i).uniq
end

#images_for_queryObject (private)



65
66
67
68
69
# File 'lib/export/packagers/images.rb', line 65

def images_for_query
  Image.where(project_id: project_id)
    .where(id: image_ids)
    .order(:id)
end

#preview(max_bytes:) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/export/packagers/images.rb', line 19

def preview(max_bytes:)
  return empty_preview if image_ids.empty?

  images = images_for_query
  groups = group_entries(images, max_bytes)
  group_map = @file_grouper.build_group_map(
    groups: groups,
    id_extractor: ->(image) { image.id }
  )

  {
    images: serialize_images(images, group_map),
    groups: serialize_groups(groups)
  }
end

#serialize_groups(groups) ⇒ Object (private)



99
100
101
102
103
104
105
106
107
108
109
# File 'lib/export/packagers/images.rb', line 99

def serialize_groups(groups)
  groups.map.with_index do |group, index|
    available_images = group.select { |image| file_available?(image) }
    {
      index:,
      size: available_images.sum { |image| image.image_file_file_size.to_i },
      image_ids: group.map(&:id),
      available_count: available_images.length
    }
  end
end

#serialize_images(images, group_map) ⇒ Object (private)



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/export/packagers/images.rb', line 81

def serialize_images(images, group_map)
  images.map.with_index(1) do |image, index| # 1-based for UI display
    {
      id: image.id,
      index: index,
      group_index: group_map[image.id],
      size: image.image_file_file_size.to_i,
      name: image.image_file_file_name,
      content_type: image.image_file_content_type,
      width: image.width,
      height: image.height,
      url: image.image_file.url(:original, false),
      thumb_url: image.image_file.url(:thumb, false),
      available: file_available?(image)
    }
  end
end

#stream(entries:, zip_streamer:, group_index:) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/export/packagers/images.rb', line 48

def stream(entries:, zip_streamer:, group_index:)
  Export::ZipStreamer.new.stream(
    entries: entries,
    zip_streamer: zip_streamer,
    file_path: ->(img) { file_path(img) },
    file_name: ->(img) { img.image_file_file_name },
    entry_id: ->(img) { img.id },
    logger_prefix: 'Images packager',
    on_entry: method(:add_manifest_row),
    after_stream: ->(zip, rows, written) {
      write_manifest(zip, rows, written, group_index: group_index)
    }
  )
end

#write_manifest(zip, rows, written, group_index:) ⇒ Object (private)



127
128
129
130
131
132
133
134
135
136
# File 'lib/export/packagers/images.rb', line 127

def write_manifest(zip, rows, written, group_index:)
  return if !written || rows.empty?

  zip.write_deflated_file("images-#{group_index + 1}.tsv") do |sink|
    sink.write("image_id\tfilename\tfile_size_bytes\twidth\theight\n")
    rows.each do |row|
      sink.write("#{row.join("\t")}\n")
    end
  end
end