cloudhdr_rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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