cloudhdr_rails 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +3 -0
  3. data/Rakefile +29 -0
  4. data/app/assets/javascripts/cloudhdr/updater.js +115 -0
  5. data/app/assets/stylesheets/cloudhdr/updater.css +8 -0
  6. data/app/controllers/cloudhdr_controller.rb +64 -0
  7. data/app/helpers/cloudhdr_helper.rb +245 -0
  8. data/app/models/cloudhdr_job.rb +189 -0
  9. data/app/views/cloudhdr/_thumbnail_update.html.erb +3 -0
  10. data/app/views/cloudhdr/multi_thumbnail_update.json.erb +7 -0
  11. data/app/views/cloudhdr/thumbnail_update.js.erb +1 -0
  12. data/config/routes.rb +8 -0
  13. data/lib/cloudhdr_rails/acts_as_cloudhdr.rb +1020 -0
  14. data/lib/cloudhdr_rails/engine.rb +4 -0
  15. data/lib/cloudhdr_rails/errors.rb +46 -0
  16. data/lib/cloudhdr_rails/version.rb +3 -0
  17. data/lib/cloudhdr_rails.rb +7 -0
  18. data/lib/generators/cloudhdr_rails/model_update_generator.rb +52 -0
  19. data/lib/generators/cloudhdr_rails/scaffold_generator.rb +94 -0
  20. data/lib/generators/cloudhdr_rails/setup_generator.rb +33 -0
  21. data/lib/generators/cloudhdr_rails/templates/cloudhdr.yml +19 -0
  22. data/lib/generators/cloudhdr_rails/templates/controller.rb +71 -0
  23. data/lib/generators/cloudhdr_rails/templates/helper.rb +5 -0
  24. data/lib/generators/cloudhdr_rails/templates/migration.rb +21 -0
  25. data/lib/generators/cloudhdr_rails/templates/model.rb +15 -0
  26. data/lib/generators/cloudhdr_rails/templates/model_migration.rb +56 -0
  27. data/lib/generators/cloudhdr_rails/templates/model_thumbnail.rb +5 -0
  28. data/lib/generators/cloudhdr_rails/templates/model_update_migration.rb +64 -0
  29. data/lib/generators/cloudhdr_rails/templates/views/_form.html.erb.tt +23 -0
  30. data/lib/generators/cloudhdr_rails/templates/views/index.html.erb.tt +26 -0
  31. data/lib/generators/cloudhdr_rails/templates/views/new.html.erb.tt +5 -0
  32. data/lib/generators/cloudhdr_rails/templates/views/show.html.erb.tt +12 -0
  33. data/lib/tasks/cloudhdr_rails_tasks.rake +19 -0
  34. metadata +212 -0
@@ -0,0 +1,1020 @@
1
+ module ActsAsCloudhdr
2
+
3
+ require 'cloudhdr'
4
+ require 'open-uri'
5
+ require 'aws-sdk'
6
+ require 'mimetype_fu'
7
+ # Storeage mode controls how uploads are handled.
8
+ # Valid options are:
9
+ # offline : For development mode with no net connection. No processing.
10
+ # local : To store images locally but use Cloudhdr for processing.
11
+ # s3 : Store image in S3 and use Cloudhdr for processing.
12
+ # Set this options either in evnironment.rb or
13
+ # in environments/development.rb etc...
14
+
15
+ mattr_accessor :storeage_mode
16
+ self.storeage_mode = "local"
17
+
18
+
19
+ # Processing mode controls when images get sent to cloudhdr
20
+ # Valid options are:
21
+ # automatic : Send to cloudhdr as soon as the file is stored.
22
+ # With 'local' storage mode, this submits the job
23
+ # to cloudhdr while the user is still waiting.
24
+ # delayed : Handle storage/processing in a background process.
25
+ mattr_accessor :processing_mode
26
+ self.processing_mode = "automatic"
27
+
28
+ # This is used as the base address for cloudhdr notifications.
29
+ # When storeage_mode == "local" this is also used to point
30
+ # cloudhdr at the file.
31
+ # It should only be the host.domain portion of the URL
32
+ # no path components.
33
+ mattr_accessor :base_url
34
+ self.base_url = "http://your-domain.com"
35
+
36
+ # The bucket for storing s3 files
37
+ mattr_accessor :s3_bucket_name
38
+ self.s3_bucket_name = "your-bucket"
39
+
40
+ # The cloudfront host or a Proc that returns a cloud front host
41
+ mattr_accessor :cloudfront_host
42
+ self.cloudfront_host = nil
43
+
44
+ # The javascript library to use for updates
45
+ # either 'prototype' or 'jquery'
46
+ mattr_accessor :javascript_library
47
+ self.javascript_library = 'prototype'
48
+
49
+ # The local directory where files should be stored
50
+ mattr_accessor :local_base_dir
51
+ self.local_base_dir = '/tmp'
52
+
53
+ # The config file that tells cloudhdr where to find
54
+ # config options.
55
+ mattr_accessor :config_file
56
+ self.config_file = "config/cloudhdr.yml"
57
+
58
+ # The actual configuration parameters
59
+ mattr_accessor :config
60
+ self.config = nil
61
+
62
+ def self.cloudhdr_config
63
+ #puts "checking cloudhdr_config for #{self.config}"
64
+ self.read_cloudhdr_configuration if self.config.nil?
65
+ self.config
66
+ end
67
+
68
+ def self.read_cloudhdr_configuration
69
+
70
+ config_path = File.join(::Rails.root.to_s, ActsAsCloudhdr.config_file)
71
+ #puts "#{self.config} - looking for a config in #{config_path}"
72
+ self.config = YAML.load(ERB.new(File.read(config_path)).result)[::Rails.env.to_s].symbolize_keys
73
+ self.apply_cloudhdr_configuration
74
+ end
75
+
76
+
77
+ # The list of image content types that are considered web safe
78
+ # These can be displayed directly, skipping processing if in offline mode
79
+ mattr_accessor :web_safe_image_types
80
+ self.web_safe_image_types = [
81
+ 'image/jpeg',
82
+ 'image/jpg',
83
+ 'image/gif',
84
+ 'image/png',
85
+ 'image/x-png',
86
+ 'image/jpg',
87
+ 'application/png',
88
+ 'application/x-png'
89
+ ]
90
+
91
+ # The list of image content types that are not considered web safe
92
+ # These can not be displayed directly
93
+ mattr_accessor :other_image_types
94
+ self.other_image_types = [
95
+ 'image/pjpeg',
96
+ 'image/x-ms-bmp',
97
+ 'image/bmp',
98
+ 'image/x-bmp',
99
+ 'image/x-bitmap',
100
+ 'image/x-xbitmap',
101
+ 'image/x-win-bitmap',
102
+ 'image/x-windows-bmp',
103
+ 'image/ms-bmp',
104
+ 'application/bmp',
105
+ 'application/x-bmp',
106
+ 'application/x-win-bitmap',
107
+ 'application/preview',
108
+ 'image/jp_',
109
+ 'application/jpg',
110
+ 'application/x-jpg',
111
+ 'image/pipeg',
112
+ 'image/vnd.swiftview-jpeg',
113
+ 'image/x-xbitmap',
114
+ 'image/gi_',
115
+ 'image/x-citrix-pjpeg',
116
+ 'image/x-nikon-nef',
117
+ 'image/tiff',
118
+ 'image/x-olympus-orf',
119
+ 'image/x-dcraw',
120
+ 'image/x-adobe-dng'
121
+ ]
122
+
123
+ # The list of content types that will trigger image handling.
124
+ def image_types
125
+ web_safe_image_types + other_image_types
126
+ end
127
+
128
+
129
+ # TODO : This needs to be fixed.
130
+ # It currently matches anything with an 'x' in it
131
+ mattr_accessor :label_size_regex
132
+ self.label_size_regex = /(\d*)x(\d*)(pad|crop|stretch|preserve)?/ #
133
+
134
+ mattr_accessor :size_string_regex
135
+ self.size_string_regex = /(\d*)x(\d*)([!>]?)/
136
+
137
+ def image?(content_type)
138
+ image_types.include?(content_type)
139
+ end
140
+
141
+ def web_safe?(content_type)
142
+ web_safe_image_types.include?(content_type)
143
+ end
144
+
145
+ #def self.storeage_mode
146
+ # @@storeage_mode
147
+ #end
148
+
149
+
150
+ def acts_as_cloudhdr(options = { })
151
+
152
+ include InstanceMethods
153
+ attr_reader :saved_file
154
+ attr_accessor :processing
155
+ after_save :save_local_file
156
+ before_destroy :cleanup #:remove_local_file,:destroy_thumbnails,:remove_s3_file
157
+
158
+ include ActiveSupport::Callbacks
159
+
160
+ define_callbacks :local_file_saved, :file_saved, :file_ready, :process_hdr, :process_hdrhtml, :process_composite, :process_tone_mapping
161
+
162
+ #cattr_accessor :cloudhdr_options
163
+ #self.cloudhdr_options = options
164
+
165
+ cattr_accessor :cloudhdr_thumbnails
166
+ self.cloudhdr_thumbnails = options[:thumbnails] ||= []
167
+
168
+ cattr_accessor :thumbnail_class
169
+ self.thumbnail_class = options[:thumbnail_class] ? options[:thumbnail_class].constantize : self
170
+
171
+ cattr_accessor :parent_class
172
+ self.parent_class = options[:parent_class] ? options[:parent_class].constantize : self
173
+
174
+ has_many :thumbnails, :class_name => "::#{self.thumbnail_class.name}",:as => :parent
175
+ if self.thumbnail_class != self.parent_class
176
+ #we have to do this to get the poster for videos covered
177
+ belongs_to :parent, :polymorphic => true
178
+ else
179
+ belongs_to :parent, :class_name => "::#{self.parent_class.name}" ,:foreign_key => "parent_id"
180
+ end
181
+
182
+
183
+ has_many :cloudhdr_jobs, :as => :image
184
+
185
+ scope :top_level, where({:parent_id=>nil}) if respond_to?(:parent_id)
186
+ scope :top_level, where({}) if !respond_to?(:parent_id)
187
+ # we can't just call this next scope 'parents' because that is already
188
+ # taken and returns an array of parent classes of the ruby object
189
+ scope :parent_items, where({:parent_id=>nil}) if respond_to?(:parent_id)
190
+ scope :parent_items, where({}) if !respond_to?(:parent_id)
191
+
192
+ scope :thumbnails, where("#{base_class.table_name}.parent_id is not null")
193
+
194
+ #just a writer, the reader is below
195
+ #cattr_accessor :cloudhdr_configuration
196
+ #read_cloudhdr_configuration
197
+ end
198
+
199
+ #def config
200
+ #return cloudhdr_configuration if !cloudhdr_configuration.blank?
201
+ #self.read_cloudhdr_configuration
202
+ #end
203
+
204
+ def validates_cloudhdr
205
+ validates_presence_of :content_type, :filename, :if=>lambda{ parent_id.blank? }
206
+ end
207
+
208
+ def update_from_cloudhdr(params)
209
+ Rails.logger.debug "tying to call update from cloudhdr for params = #{params.to_json}"
210
+ if !params[:output].blank?
211
+ Rails.logger.debug "find_by_cloudhdr_output_id #{params[:output][:id]}"
212
+ iu = find_by_cloudhdr_output_id params[:output][:id]
213
+ Rails.logger.debug "the item = #{iu}"
214
+ img_params = params[:output]
215
+ iu.filename = File.basename(params[:output][:url]) #if iu.filename.blank?
216
+ if ActsAsCloudhdr.storeage_mode == "local"
217
+ iu.save_url(params[:output][:url])
218
+ end
219
+ else
220
+ iu = find_by_cloudhdr_input_id params[:input][:id]
221
+ img_params = params[:input]
222
+ end
223
+ [:file_size,:width,:height,:taken_at,:lat,:lng].each do |att|
224
+ setter = att.to_s + "="
225
+ if iu.respond_to? setter and !img_params[att].blank?
226
+ iu.send setter, img_params[att]
227
+ end
228
+ end
229
+
230
+ #iu.file_size = img_params[:file_size]
231
+ #iu.width = img_params[:width]
232
+ #iu.height = img_params[:height]
233
+ iu.cloudhdr_status = "ready"
234
+ iu.save
235
+ iu
236
+ end
237
+
238
+
239
+
240
+ def thumbnail_attributes_for(thumbnail_name = "small")
241
+ atts = self.cloudhdr_thumbnails.select{|atts| atts[:label] == thumbnail_name }.first
242
+ if atts.blank?
243
+ atts = create_atts_from_size_string(thumbnail_name)
244
+ end
245
+ if atts.blank?
246
+ raise ThumbnailAttributesNotFoundError.new("No thumbnail attributes were found for label '#{thumbnail_name}'")
247
+ end
248
+ atts
249
+ end
250
+
251
+ def create_label_from_size_string(size_string)
252
+ if size_string.match ActsAsCloudhdr.size_string_regex
253
+ size_string = size_string.gsub("!","crop")
254
+ size_string = size_string.gsub(">","preserve")
255
+ end
256
+ size_string
257
+ end
258
+
259
+ def create_atts_from_size_string(label_string)
260
+ match = label_string.match ActsAsCloudhdr.label_size_regex
261
+ return nil if match.blank?
262
+ atts = {}
263
+ if !match[1].blank?
264
+ atts[:width] = match[1]
265
+ end
266
+ if !match[2].blank?
267
+ atts[:height] = match[2]
268
+ end
269
+ if !match[3].blank?
270
+ atts[:aspect_mode] = match[3]
271
+ end
272
+ atts[:label] = label_string
273
+ #atts[:label] = "#{atts[:width]}x#{atts[:height]}"
274
+ #atts[:label] += "_#{atts[:aspect_mode]}" if atts[:aspect_mode]
275
+ atts
276
+ end
277
+
278
+
279
+ #def read_cloudhdr_configuration
280
+ ##raise "This method is going away!"
281
+ ##puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
282
+ ##puts "This method is going away!"
283
+ ##puts "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
284
+ #self.cloudhdr_configuration = ActsAsCloudhdr.cloudhdr_config
285
+ #self.apply_cloudhdr_configuration
286
+ #end
287
+
288
+
289
+ def self.cloudhdr_configuration
290
+ self.config
291
+ end
292
+
293
+ def self.apply_cloudhdr_configuration
294
+ if self.cloudhdr_configuration[:base_url]
295
+ ActsAsCloudhdr.base_url = cloudhdr_configuration[:base_url]
296
+ end
297
+ if self.cloudhdr_configuration[:storeage_mode]
298
+ ActsAsCloudhdr.storeage_mode = cloudhdr_configuration[:storeage_mode]
299
+ end
300
+ if self.cloudhdr_configuration[:processing_mode]
301
+ ActsAsCloudhdr.processing_mode = cloudhdr_configuration[:processing_mode]
302
+ end
303
+ if self.cloudhdr_configuration[:s3_bucket_name]
304
+ ActsAsCloudhdr.s3_bucket_name = cloudhdr_configuration[:s3_bucket_name]
305
+ end
306
+ if self.cloudhdr_configuration[:javascript_library]
307
+ ActsAsCloudhdr.javascript_library = cloudhdr_configuration[:javascript_library]
308
+ end
309
+ if self.cloudhdr_configuration[:local_base_dir]
310
+ ActsAsCloudhdr.local_base_dir = cloudhdr_configuration[:local_base_dir]
311
+ end
312
+
313
+ if self.cloudhdr_configuration[:cloudhdr_url]
314
+ ::Cloudhdr.base_url = cloudhdr_configuration[:cloudhdr_url]
315
+ end
316
+ if self.cloudhdr_configuration[:cloudhdr_api_key]
317
+ ::Cloudhdr.api_key = cloudhdr_configuration[:cloudhdr_api_key]
318
+ end
319
+
320
+ end
321
+
322
+
323
+
324
+
325
+
326
+
327
+
328
+ module InstanceMethods
329
+
330
+
331
+
332
+ def image?
333
+ self.class.image?(content_type)
334
+ end
335
+
336
+ def web_safe?
337
+ self.class.web_safe?(content_type)
338
+ end
339
+
340
+ def encode
341
+ if image?
342
+ process
343
+ end
344
+ end
345
+
346
+ def recode
347
+ reload #make sure that we have current thumbs
348
+ destroy_thumbnails
349
+ reload
350
+ encode
351
+ end
352
+
353
+ def ready?
354
+ if ActsAsCloudhdr.storeage_mode == "offline"
355
+ true
356
+ #elsif image?
357
+ # return cloudhdr_status=='ready'
358
+ #else
359
+ # return false
360
+ else
361
+ return cloudhdr_status == "ready"
362
+ end
363
+ end
364
+
365
+ def error?
366
+ if ActsAsCloudhdr.storeage_mode == "offline"
367
+ false
368
+ #elsif image?
369
+ # return cloudhdr_status=='failed'
370
+ #elsif video?
371
+ # return zencoder_status=='failed'
372
+ #else
373
+ # true
374
+ else
375
+ return cloudhdr_status == "ready"
376
+ end
377
+ end
378
+
379
+ def create_thumbnails_from_response(response_thumbs,job_id)
380
+ new_thumbs = []
381
+ response_thumbs.each do |thumb_params|
382
+ #puts "creating a thumb for #{thumb_params["label"]}"
383
+ # we do this the long way around just in case some of these
384
+ # atts are attr_protected
385
+ thumb = nil
386
+ if respond_to?(:parent_id) and !self.parent_id.blank?
387
+ Rails.logger.debug "trying to create a thumb from the parent "
388
+ thumb = self.parent.thumbnails.new()
389
+ self.parent.thumbnails << thumb
390
+ else
391
+ Rails.logger.debug "trying to create a thumb from myself "
392
+ thumb = self.thumbnails.new()
393
+ self.thumbnails << thumb
394
+ end
395
+
396
+
397
+ thumb.thumbnail = thumb_params["label"]
398
+ thumb.filename = thumb_params["filename"]
399
+ thumb.width = thumb_params["width"]
400
+ thumb.height = thumb_params["height"]
401
+ thumb.cloudhdr_status = "processing"
402
+ thumb.save
403
+ new_thumbs << thumb
404
+ Rails.logger.debug " thumb.errors = #{thumb.errors.to_json}"
405
+ #puts " thumb.errors = #{thumb.errors.to_json}"
406
+ end
407
+ new_thumbs
408
+ end
409
+
410
+ def clear_processing
411
+ processing = false
412
+ end
413
+
414
+ def dedupe_input_thumbs(input_thumbs)
415
+ needed_thumbs = []
416
+ input_thumbs.each do |it|
417
+ t = thumbnails.find_by_thumbnail(it[:label])
418
+ if t.blank?
419
+ needed_thumbs << it
420
+ end
421
+ end
422
+ needed_thumbs
423
+ end
424
+
425
+ def create_cloudhdr_job(params)
426
+ response = nil
427
+ tries = 0
428
+ max_tries = 3
429
+ sleeps = [2,4,8]
430
+ while response.blank? do
431
+ begin
432
+ response = Cloudhdr::Job.create(params)
433
+ rescue Exception => e
434
+ if tries < max_tries
435
+ sleep sleeps[tries]
436
+ tries += 1
437
+ response = nil
438
+ else
439
+ raise
440
+ end
441
+ end
442
+ end
443
+ response
444
+ end
445
+
446
+ def process(input_thumbs = self.parent_class.cloudhdr_thumbnails)
447
+ #puts " input_thumbs.count = #{input_thumbs.size}"
448
+ input_thumbs = dedupe_input_thumbs(input_thumbs)
449
+ #puts " after dedupe input_thumbs.count = #{input_thumbs.size}"
450
+ #if self.thumbnails.count >= self.class.cloudhdr_thumbnails.size
451
+ # raise "This item already has thumbnails!"
452
+ # return
453
+ #end
454
+
455
+ return if input_thumbs.size == 0
456
+ # We do this because sometimes save will get called more than once
457
+ # during a single request
458
+ return if processing
459
+ processing = true
460
+
461
+ Rails.logger.debug "trying to process for #{Cloudhdr.base_url} "
462
+ Rails.logger.debug "callback url = #{callback_url}"
463
+ response = create_cloudhdr_job(cloudhdr_params(input_thumbs))
464
+ Rails.logger.debug "the process response = #{response.to_json}" if Rails.env != "test"
465
+ #puts "the process response = #{response.to_json}" if Rails.env != "test"
466
+
467
+ job = self.cloudhdr_jobs.new
468
+ job.tracking_mode = 'job'
469
+ job.cloudhdr_input_id = response.body["job"]["inputs"].first["id"]
470
+ job.cloudhdr_job_id = response.body["job"]["id"]
471
+ job.cloudhdr_status = "processing"
472
+ job.user_id = self.user_id if (self.respond_to?(:user_id) && self.user_id)
473
+ self.cloudhdr_jobs << job
474
+
475
+ self.cloudhdr_status = "processing" unless self.cloudhdr_status == "ready" # the unless clause allows new thumbs to be created on the fly without jacking with the status
476
+ self.save #false need to do save(false) here if we're calling process on after_save
477
+ response_thumbs = response.body["job"]["thumbnails"]
478
+ Rails.logger.debug "trying to decode #{response_thumbs.size} response_thumbs = #{response_thumbs.to_json}"
479
+ #puts "trying to decode #{response_thumbs.size} response_thumbs = #{response_thumbs.to_json}"
480
+ create_thumbnails_from_response(response_thumbs,response.body["job"]["id"])
481
+ end
482
+
483
+ def process_hdr
484
+ #if self.thumbnails.count >= self.class.cloudhdr_thumbnails.size
485
+ # raise "This item already has thumbnails!"
486
+ # return
487
+ #end
488
+
489
+ # We do this because sometimes save will get called more than once
490
+ # during a single request
491
+ return if processing
492
+ processing = true
493
+ run_callbacks :process_hdr do
494
+ Rails.logger.debug "trying to process for #{Cloudhdr.base_url} "
495
+ Rails.logger.debug "callback url = #{callback_url}"
496
+ response = create_cloudhdr_job(cloudhdr_hdr_params)
497
+ Rails.logger.debug "the response from process_hdr = #{response.body.to_json}"
498
+
499
+ job = self.cloudhdr_jobs.new
500
+ job.tracking_mode = 'job'
501
+ job.cloudhdr_output_id = response.body["job"]["hdr"]["id"]
502
+ job.cloudhdr_job_id = response.body["job"]["id"]
503
+ job.cloudhdr_status = "processing"
504
+ job.user_id = self.user_id if (self.respond_to?(:user_id) && self.user_id)
505
+ self.cloudhdr_jobs << job
506
+
507
+ self.cloudhdr_status = "processing"
508
+ self.save #false need to do save(false) here if we're calling process on after_save
509
+ end
510
+
511
+ end
512
+
513
+
514
+ def process_hdrhtml
515
+ #if self.thumbnails.count >= self.class.cloudhdr_thumbnails.size
516
+ # raise "This item already has thumbnails!"
517
+ # return
518
+ #end
519
+
520
+ # We do this because sometimes save will get called more than once
521
+ # during a single request
522
+ return if processing
523
+ processing = true
524
+ run_callbacks :process_hdrhtml do
525
+ Rails.logger.debug "trying to process for #{Cloudhdr.base_url} "
526
+ Rails.logger.debug "callback url = #{callback_url}"
527
+ response = create_cloudhdr_job(cloudhdr_hdrhtml_params)
528
+ Rails.logger.debug "the response from process_hdrhtml = #{response.body.to_json}"
529
+
530
+ job = self.cloudhdr_jobs.new
531
+ job.tracking_mode = 'job'
532
+ job.cloudhdr_output_id = response.body["job"]["hdrhtml"]["id"]
533
+ job.cloudhdr_job_id = response.body["job"]["id"]
534
+ job.cloudhdr_status = "processing"
535
+ job.user_id = self.user_id if (self.respond_to?(:user_id) && self.user_id)
536
+ self.cloudhdr_jobs << job
537
+
538
+ self.cloudhdr_status = "processing"
539
+ self.save #false need to do save(false) here if we're calling process on after_save
540
+ end
541
+
542
+ end
543
+
544
+
545
+ def process_tone_mapping
546
+ #if self.thumbnails.count >= self.class.cloudhdr_thumbnails.size
547
+ # raise "This item already has thumbnails!"
548
+ # return
549
+ #end
550
+
551
+ # We do this because sometimes save will get called more than once
552
+ # during a single request
553
+ return if processing
554
+ processing = true
555
+ run_callbacks :process_tone_mapping do
556
+ destroy_thumbnails
557
+ Rails.logger.debug "trying to process for #{Cloudhdr.base_url} "
558
+ Rails.logger.debug "callback url = #{callback_url}"
559
+ response = create_cloudhdr_job(cloudhdr_tone_mapping_params)
560
+ Rails.logger.debug "tone_mapping response = #{response.body.to_json}"
561
+ #puts "tone_mapping response = #{response.body.to_json}"
562
+
563
+ job = self.cloudhdr_jobs.new
564
+ job.tracking_mode = 'job'
565
+ job.cloudhdr_output_id = response.body["job"]["tone_mapping"]["id"]
566
+ job.cloudhdr_job_id = response.body["job"]["id"]
567
+ job.cloudhdr_status = "processing"
568
+ job.user_id = self.user_id if (self.respond_to?(:user_id) && self.user_id)
569
+ self.cloudhdr_jobs << job
570
+
571
+ self.cloudhdr_status = "processing"
572
+ self.save #false need to do save(false) here if we're calling process on after_save
573
+ response_thumbs = response.body["job"]["thumbnails"]
574
+ Rails.logger.debug "trying to decode #{response_thumbs.size} response_thumbs = #{response_thumbs.to_json}"
575
+ create_thumbnails_from_response(response_thumbs,response.body["job"]["id"])
576
+ end
577
+ end
578
+
579
+
580
+ def process_composite
581
+ #if self.thumbnails.count >= self.class.cloudhdr_thumbnails.size
582
+ # raise "This item already has thumbnails!"
583
+ # return
584
+ #end
585
+
586
+ # We do this because sometimes save will get called more than once
587
+ # during a single request
588
+ return if processing
589
+ processing = true
590
+ run_callbacks :process_composite do
591
+ destroy_thumbnails
592
+ Rails.logger.debug "trying to process for #{Cloudhdr.base_url} "
593
+ Rails.logger.debug "callback url = #{callback_url}"
594
+ response = create_cloudhdr_job(cloudhdr_composite_params)
595
+ Rails.logger.debug "composite response = #{response.body.to_json}"
596
+ #puts "composite response = #{response.body.to_json}"
597
+
598
+ job = self.cloudhdr_jobs.new
599
+ job.tracking_mode = 'job'
600
+ job.cloudhdr_output_id = response.body["job"]["composite"]["id"]
601
+ job.cloudhdr_job_id = response.body["job"]["id"]
602
+ job.cloudhdr_status = "processing"
603
+ job.user_id = self.user_id if (self.respond_to?(:user_id) && self.user_id)
604
+ self.cloudhdr_jobs << job
605
+
606
+ self.cloudhdr_status = "processing"
607
+ self.save #false need to do save(false) here if we're calling process on after_save
608
+ response_thumbs = response.body["job"]["thumbnails"]
609
+ Rails.logger.debug "trying to decode #{response_thumbs.size} response_thumbs = #{response_thumbs.to_json}"
610
+ #puts "trying to decode #{response_thumbs.size} response_thumbs = #{response_thumbs.to_json}"
611
+ create_thumbnails_from_response(response_thumbs,response.body["job"]["id"])
612
+ end
613
+ end
614
+
615
+
616
+ def cloudhdr_extension
617
+ if self.content_type.blank?
618
+ ".jpg"
619
+ else
620
+ self.content_type.match(/png/) ? ".png" : ".jpg"
621
+ end
622
+ end
623
+
624
+ def cloudhdr_params(input_thumbs = self.parent_class.cloudhdr_thumbnails)
625
+ {:input => {:url => self.public_url, :notifications=>[{:url=>callback_url }] },
626
+ :thumbnails => cloudhdr_thumbnail_params(input_thumbs)
627
+ }
628
+ end
629
+
630
+ def cloudhdr_thumbnail_params(input_thumbs = self.parent_class.cloudhdr_thumbnails)
631
+ input_thumbs.map{|thumb|
632
+ thumb_filename = thumb[:label] + "_" + File.basename(self.filename,File.extname(self.filename)) + cloudhdr_extension
633
+ base_url = ActsAsCloudhdr.storeage_mode == "s3" ? "s3://#{self.s3_bucket_name}/#{self.thumbnail_resource_dir}/" : ""
634
+ th = thumb.clone
635
+ th[:base_url] = base_url if !base_url.blank?
636
+ th.merge({
637
+ :filename=>thumb_filename,
638
+ :notifications=>[{:url=>thumbnail_callback_url }]
639
+ })
640
+ }
641
+ end
642
+
643
+
644
+ def cloudhdr_hdr_params
645
+ { }
646
+ end
647
+
648
+ def cloudhdr_hdrhtml_params
649
+ { }
650
+ end
651
+
652
+ def cloudhdr_tone_mapping_params
653
+ { }
654
+ end
655
+
656
+ def cloudhdr_composite_params
657
+ { }
658
+ end
659
+
660
+
661
+
662
+
663
+ def cloudhdr_config
664
+ ActsAsCloudhdr.cloudhdr_config
665
+ end
666
+
667
+ def cloudhdr?
668
+ true
669
+ end
670
+
671
+ def save_url(url)
672
+ Rails.logger.debug "We are about to download : #{url} to #{local_dir} - #{local_path}"
673
+ FileUtils.mkdir_p(local_dir) if !File.exists?(local_dir)
674
+ FileUtils.touch local_path
675
+ writeOut = open(local_path, "wb")
676
+ writeOut.write(open(url).read)
677
+ writeOut.close
678
+ end
679
+
680
+ def destroy_thumbnails
681
+ if self.class.cloudhdr_thumbnails.size == 0
682
+ #puts "we're skipping destory_thumbnails since we don't do any processing "
683
+ return
684
+ end
685
+ #puts "calling destory thumbnails for #{self.thumbnails.count} - #{self.thumbnails.size}"
686
+ self.thumbnails.each do |thumb|
687
+ thumb.destroy
688
+ end
689
+ #puts "calling destory thumbnails for #{self.thumbnails.count}"
690
+ end
691
+
692
+ def create_atts_from_size_string(label_string)
693
+ self.class.create_atts_from_size_string(label_string)
694
+ end
695
+
696
+ def thumbnail_attributes_for(thumbnail_name)
697
+ self.class.thumbnail_attributes_for(thumbnail_name)
698
+ end
699
+
700
+ def thumbnail_for(thumbnail_hash_or_name)
701
+ thumbnail_name = thumbnail_hash_or_name.is_a?(Hash) ? thumbnail_hash_or_name[:label] : thumbnail_hash_or_name
702
+ if thumbnail_name and thumbnail_name.match ActsAsCloudhdr.size_string_regex
703
+ thumbnail_name = self.class.create_label_from_size_string(thumbnail_name)
704
+ end
705
+ if thumbnail_name.blank? and thumbnail_hash_or_name.is_a?(Hash)
706
+ thumbnail_name = "#{thumbnail_hash_or_name[:width]}x#{thumbnail_hash_or_name[:height]}"
707
+ #puts "thumbnail_name = #{thumbnail_name}"
708
+ thumbnail_hash_or_name[:label] = thumbnail_name
709
+ end
710
+ thumb = thumbnails.find_by_thumbnail(thumbnail_name)
711
+ if thumb.blank? and ActsAsCloudhdr.storeage_mode == "offline"
712
+ thumb = self
713
+ elsif thumb.blank? and thumbnail_hash_or_name.is_a? Hash
714
+ thumb = self.process([thumbnail_hash_or_name]).first
715
+ elsif thumb.blank? and thumbnail_hash_or_name.is_a?(String) and thumbnail_hash_or_name.match ActsAsCloudhdr.label_size_regex
716
+ atts = create_atts_from_size_string(thumbnail_name)
717
+ thumb = self.process([atts]).first
718
+ end
719
+ if thumb.blank?
720
+ raise ThumbnailNotFoundError.new("No thumbnail was found for label '#{thumbnail_name}'")
721
+ end
722
+ thumb
723
+ #a dirty hack for now to keep things working.
724
+ #Remove this!!!!!!!!!!!!!!!!!!!!!!!!!!!!
725
+ #Go back to just returning the thumb
726
+ #thumb.blank? ? self : thumb
727
+ end
728
+
729
+ def get_thumbnail(thumbnail_name)
730
+ thumbnail_for(thumbnail_name)
731
+ end
732
+
733
+ def file=(new_file)
734
+ return if new_file.nil?
735
+ Rails.logger.debug "we got a new file of class = #{new_file.class}"
736
+ cleanup
737
+ if new_file.is_a? File
738
+ self.filename = File.basename new_file.path
739
+ self.content_type = MIME::Types.type_for(self.filename).first.content_type
740
+ self.file_size = new_file.size
741
+ else
742
+ self.filename = new_file.original_filename
743
+ self.content_type = new_file.content_type
744
+ self.file_size = new_file.size
745
+ end
746
+ self.content_type = File.mime_type?(self.filename) if (self.content_type.blank? || self.content_type == "[]")
747
+ if new_file.respond_to? :tempfile
748
+ @saved_file = new_file.tempfile
749
+ else
750
+ @saved_file = new_file
751
+ end
752
+ end
753
+
754
+ #compatability method for attachment_fu
755
+ def uploaded_data=(data)
756
+ self.file = data
757
+ end
758
+
759
+ def save_local_file
760
+ return if @saved_file.blank?
761
+ #puts "saving the local file!!!!!!"
762
+ Rails.logger.debug "==================================================================================================="
763
+ Rails.logger.debug "about to save the local file"
764
+ run_callbacks :file_saved do
765
+ run_callbacks :local_file_saved do
766
+ FileUtils.mkdir_p local_dir
767
+ FileUtils.cp @saved_file.path, local_path
768
+ FileUtils.chmod 0755, local_path
769
+ self.cloudhdr_status = "local"
770
+ if self.respond_to? :upload_host
771
+ self.upload_host = %x{hostname}.strip
772
+ end
773
+ @saved_file = nil
774
+ @saved_a_new_file = true
775
+ self.save
776
+ end
777
+ if ActsAsCloudhdr.storeage_mode == "s3" && ActsAsCloudhdr.processing_mode == "automatic"
778
+ self.save_s3_file
779
+ end
780
+ if ActsAsCloudhdr.storeage_mode == "local" && ActsAsCloudhdr.processing_mode == "automatic"
781
+ self.encode
782
+ end
783
+
784
+ end
785
+ end
786
+
787
+ def fire_ready_callback
788
+ run_callbacks :file_ready do
789
+ end
790
+ end
791
+
792
+
793
+ def cleanup
794
+ #puts "calling cleanup!"
795
+ destroy_thumbnails
796
+ remove_local_file
797
+ if ActsAsCloudhdr.storeage_mode == "s3"
798
+ remove_s3_file
799
+ end
800
+ end
801
+
802
+ def remove_local_file
803
+ if local_path and File.exists? local_path
804
+ FileUtils.rm local_path
805
+ if Dir.glob(File.join(local_dir,"*")).size == 0
806
+ FileUtils.rmdir local_dir
807
+ end
808
+ end
809
+ end
810
+
811
+ def path_id
812
+
813
+ #puts "parent_id = #{parent_id}"
814
+ #puts "parent = #{parent}"
815
+ if respond_to?(:parent_id)
816
+ parent_id.blank? ? id : parent.path_id
817
+ else
818
+ id
819
+ end
820
+ end
821
+
822
+ def resource_dir
823
+ File.join(self.class.table_name, path_id.to_s )
824
+ end
825
+
826
+ def thumbnail_resource_dir
827
+ File.join(self.thumbnail_class.table_name, path_id.to_s )
828
+ end
829
+
830
+ def local_dir
831
+ File.join(ActsAsCloudhdr.local_base_dir,resource_dir)
832
+ end
833
+
834
+ def local_path
835
+ filename.blank? ? nil : File.join(local_dir,filename)
836
+ end
837
+
838
+ def local_url
839
+ filename.blank? ? nil : File.join("/",resource_dir,filename)
840
+ end
841
+
842
+ # This should generate a fully qualified http://something-something
843
+ # type of a reference. Depending on storeage_mode/base_url settings.
844
+ def public_url
845
+ #puts "our base_url = #{base_url} and our local_url = #{local_url}"
846
+ if ActsAsCloudhdr.storeage_mode == "local" or ActsAsCloudhdr.storeage_mode == "offline"
847
+ base_url + local_url
848
+ else
849
+ self.class.cloudfront_host.present? ? cloudfront_url : s3_url
850
+ end
851
+ end
852
+
853
+ def public_filename
854
+ public_url
855
+ end
856
+
857
+
858
+ def callback_url
859
+ self.base_url + self.notification_callback_path
860
+ end
861
+
862
+ def thumbnail_callback_url
863
+ self.base_url + self.thumbnail_notification_callback_path
864
+ end
865
+
866
+ def notification_callback_path
867
+ "/cloudhdr/cloudhdr_notifications/#{self.class.name}/#{self.id}.json"
868
+ end
869
+
870
+ def thumbnail_notification_callback_path
871
+ "/cloudhdr/cloudhdr_notifications/#{self.thumbnail_class.name}/#{self.id}.json"
872
+ end
873
+
874
+ def base_url
875
+ self.class.base_url
876
+ end
877
+
878
+ def s3_key
879
+ filename.blank? ? nil : File.join(resource_dir,filename)
880
+ end
881
+
882
+ def s3_url
883
+ "http://#{s3_bucket_name}.s3.amazonaws.com/#{s3_key}"
884
+ end
885
+
886
+ def s3_bucket_name
887
+ self.class.s3_bucket_name
888
+ end
889
+
890
+ def cloudfront_base_host
891
+ host = self.class.cloudfront_host
892
+ host.instance_of?(Proc) ? host.call(s3_key) : host
893
+ end
894
+
895
+ def cloudfront_url
896
+ "#{cloudfront_base_host}/#{s3_key}"
897
+ end
898
+
899
+ def unused_s3_demo_stuff
900
+ s3 = AWS::S3.new
901
+ key,bucket = get_s3_key_and_bucket
902
+ obj = s3.buckets[bucket].objects[key]
903
+ obj.write(Pathname.new(tmpFile),{:acl=>:public_read,"Cache-Control"=>'max-age=315360000'})
904
+ end
905
+
906
+ def s3
907
+ @s3 ||= AWS::S3.new
908
+ end
909
+
910
+ def s3_obj
911
+ s3.buckets[s3_bucket_name].objects[s3_key]
912
+ end
913
+
914
+ def save_s3_file
915
+ #I don't think we need this return check anymore.
916
+ #return if !@saved_a_new_file
917
+ #@saved_a_new_file = false
918
+ #AWS::S3::S3Object.store(
919
+ #s3_key,
920
+ #open(local_path),
921
+ #s3_bucket_name,
922
+ #:access => :public_read,
923
+ #"Cache-Control" => 'max-age=315360000'
924
+ #)
925
+ s3_obj.write(Pathname.new(local_path),{:acl=>:public_read,"Cache-Control"=>'max-age=315360000'})
926
+ self.cloudhdr_status = "s3"
927
+ self.save
928
+ #obj_data = AWS::S3::S3Object.find(s3_key,s3_bucket_name)
929
+ Rails.logger.debug "----------------------------------------------------------------------------------------------------"
930
+ if s3_obj.content_length == file_size # it made it into s3 safely
931
+ Rails.logger.debug " we are about to remove local file!"
932
+ remove_local_file
933
+ else
934
+ msg = "The file was not saved to S3 sucessfully. Orig size: #{file_size} - S3 size: #{obj_data.size}"
935
+ Rails.logger.debug msg
936
+ raise ActsAsCloudhdr::Error.new msg
937
+ end
938
+ self.encode
939
+ end
940
+
941
+
942
+ def remove_s3_file
943
+ #puts "trying to delete #{s3_key} #{s3_bucket_name}"
944
+ #if ActsAsCloudhdr.storeage_mode == "s3"
945
+ #AWS::S3::S3Object.delete s3_key, s3_bucket_name
946
+ #end
947
+ s3_obj.delete
948
+ rescue Exception => e
949
+ #this probably means that the file never made it to S3
950
+ end
951
+
952
+ # Sanitizes a filename.
953
+ def filename=(new_name)
954
+ write_attribute :filename, sanitize_filename(new_name)
955
+ end
956
+
957
+ def sanitize_filename(filename)
958
+ return unless filename
959
+ filename.strip.tap do |name|
960
+ # NOTE: File.basename doesn't work right with Windows paths on Unix
961
+ # get only the filename, not the whole path
962
+ name.gsub! /^.*(\\|\/)/, ''
963
+
964
+ # Finally, replace all non alphanumeric, underscore or periods with underscore
965
+ name.gsub! /[^A-Za-z0-9\.\-]/, '_'
966
+ end
967
+ end
968
+
969
+ # Calculate the width for the target thumbnail atts
970
+ def calc_width(thumbnail_atts)
971
+ tw = thumbnail_atts[:width].blank? ? 100000 : thumbnail_atts[:width].to_f
972
+ th = thumbnail_atts[:height].blank? ? 100000 : thumbnail_atts[:height].to_f
973
+ w = width.to_f
974
+ h = height.to_f
975
+ if w <= tw and h <= th
976
+ w.round
977
+ elsif w > h
978
+ if (h * ( tw / w )).round < tw
979
+ tw .round
980
+ else
981
+ (h * ( tw / w )).round
982
+ end
983
+ else
984
+ if (w * ( th / h )).round < tw
985
+ (w * ( th / h )).round
986
+ else
987
+ tw.round
988
+ end
989
+ end
990
+ end #end calc_width
991
+
992
+
993
+ def calc_height(thumbnail_atts)
994
+ tw = thumbnail_atts[:width].blank? ? 100000 : thumbnail_atts[:width].to_f
995
+ th = thumbnail_atts[:height].blank? ? 100000 : thumbnail_atts[:height].to_f
996
+ w = width.to_f
997
+ h = height.to_f
998
+ if w <= tw and h <= th
999
+ h.round
1000
+ elsif w > h
1001
+ if (h * ( tw / w )).round < th
1002
+ (h * ( tw / w )).round
1003
+ else
1004
+ th.round
1005
+ end
1006
+ else
1007
+ if (w * ( th / h )).round < tw
1008
+ th.round
1009
+ else
1010
+ (h * ( tw / w )).round
1011
+ end
1012
+ end
1013
+ end #end calc_height
1014
+
1015
+
1016
+
1017
+ end#module InstanceMethods
1018
+
1019
+ end
1020
+ ActiveRecord::Base.extend ActsAsCloudhdr