phocoder-rails 0.0.33

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/.autotest +46 -0
  2. data/.document +5 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +44 -0
  5. data/LICENSE.txt +20 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.rdoc +3 -0
  8. data/Rakefile +56 -0
  9. data/VERSION +5 -0
  10. data/app/controllers/phocoder_controller.rb +118 -0
  11. data/app/helpers/phocoder_helper.rb +320 -0
  12. data/app/models/encodable_job.rb +91 -0
  13. data/app/views/phocoder/_offline_video_embed.html.erb +19 -0
  14. data/app/views/phocoder/_thumbnail_update.html.erb +3 -0
  15. data/app/views/phocoder/_video_embed.html.erb +23 -0
  16. data/app/views/phocoder/multi_thumbnail_update.json.erb +7 -0
  17. data/app/views/phocoder/thumbnail_update.js.erb +9 -0
  18. data/config/routes.rb +8 -0
  19. data/lib/generators/phocoder_rails/model_update_generator.rb +52 -0
  20. data/lib/generators/phocoder_rails/scaffold_generator.rb +94 -0
  21. data/lib/generators/phocoder_rails/setup_generator.rb +33 -0
  22. data/lib/generators/phocoder_rails/templates/controller.rb +71 -0
  23. data/lib/generators/phocoder_rails/templates/helper.rb +5 -0
  24. data/lib/generators/phocoder_rails/templates/migration.rb +24 -0
  25. data/lib/generators/phocoder_rails/templates/model.rb +20 -0
  26. data/lib/generators/phocoder_rails/templates/model_migration.rb +56 -0
  27. data/lib/generators/phocoder_rails/templates/model_thumbnail.rb +5 -0
  28. data/lib/generators/phocoder_rails/templates/model_update_migration.rb +64 -0
  29. data/lib/generators/phocoder_rails/templates/phocodable.yml +28 -0
  30. data/lib/generators/phocoder_rails/templates/views/_form.html.erb.tt +23 -0
  31. data/lib/generators/phocoder_rails/templates/views/index.html.erb.tt +26 -0
  32. data/lib/generators/phocoder_rails/templates/views/new.html.erb.tt +5 -0
  33. data/lib/generators/phocoder_rails/templates/views/show.html.erb.tt +12 -0
  34. data/lib/phocoder_rails.rb +12 -0
  35. data/lib/phocoder_rails/acts_as_phocodable.rb +1153 -0
  36. data/lib/phocoder_rails/engine.rb +24 -0
  37. data/lib/phocoder_rails/errors.rb +46 -0
  38. data/phocoder-rails.gemspec +219 -0
  39. data/public/images/building.gif +0 -0
  40. data/public/images/error.png +0 -0
  41. data/public/images/play_small.png +0 -0
  42. data/public/images/storing.gif +0 -0
  43. data/public/images/waiting.gif +0 -0
  44. data/public/javascripts/phocodable.js +110 -0
  45. data/public/javascripts/video-js-2.0.2/.DS_Store +0 -0
  46. data/public/javascripts/video-js-2.0.2/LICENSE.txt +165 -0
  47. data/public/javascripts/video-js-2.0.2/README.markdown +202 -0
  48. data/public/javascripts/video-js-2.0.2/demo-subtitles.srt +13 -0
  49. data/public/javascripts/video-js-2.0.2/demo.html +101 -0
  50. data/public/javascripts/video-js-2.0.2/skins/hu.css +116 -0
  51. data/public/javascripts/video-js-2.0.2/skins/tube.css +111 -0
  52. data/public/javascripts/video-js-2.0.2/skins/vim.css +89 -0
  53. data/public/javascripts/video-js-2.0.2/video-js.css +242 -0
  54. data/public/javascripts/video-js-2.0.2/video.js +1758 -0
  55. data/public/stylesheets/phocodable.css +19 -0
  56. data/spec/controllers/phocoder_controller_spec.rb +123 -0
  57. data/spec/dummy/Rakefile +7 -0
  58. data/spec/dummy/app/controllers/application_controller.rb +7 -0
  59. data/spec/dummy/app/controllers/images_controller.rb +72 -0
  60. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  61. data/spec/dummy/app/helpers/images_helper.rb +5 -0
  62. data/spec/dummy/app/models/image.rb +20 -0
  63. data/spec/dummy/app/models/image_thumbnail.rb +5 -0
  64. data/spec/dummy/app/models/image_upload.rb +11 -0
  65. data/spec/dummy/app/views/images/_form.html.erb +23 -0
  66. data/spec/dummy/app/views/images/index.html.erb +26 -0
  67. data/spec/dummy/app/views/images/new.html.erb +5 -0
  68. data/spec/dummy/app/views/images/show.html.erb +12 -0
  69. data/spec/dummy/app/views/layouts/application.html.erb +18 -0
  70. data/spec/dummy/config.ru +4 -0
  71. data/spec/dummy/config/application.rb +45 -0
  72. data/spec/dummy/config/boot.rb +10 -0
  73. data/spec/dummy/config/database.yml +25 -0
  74. data/spec/dummy/config/environment.rb +8 -0
  75. data/spec/dummy/config/environments/development.rb +26 -0
  76. data/spec/dummy/config/environments/production.rb +49 -0
  77. data/spec/dummy/config/environments/test.rb +40 -0
  78. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  79. data/spec/dummy/config/initializers/inflections.rb +10 -0
  80. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  81. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  82. data/spec/dummy/config/initializers/session_store.rb +8 -0
  83. data/spec/dummy/config/locales/en.yml +5 -0
  84. data/spec/dummy/config/routes.rb +60 -0
  85. data/spec/dummy/db/migrate/001_create_image_uploads.rb +37 -0
  86. data/spec/dummy/db/migrate/20110523165213_add_parent_type_to_image_uploads.rb +11 -0
  87. data/spec/dummy/db/migrate/20110523165522_create_encodable_jobs.rb +24 -0
  88. data/spec/dummy/db/migrate/20111101024507_create_images.rb +56 -0
  89. data/spec/dummy/db/schema.rb +99 -0
  90. data/spec/dummy/public/404.html +26 -0
  91. data/spec/dummy/public/422.html +26 -0
  92. data/spec/dummy/public/500.html +26 -0
  93. data/spec/dummy/public/favicon.ico +0 -0
  94. data/spec/dummy/public/index.html +239 -0
  95. data/spec/dummy/public/javascripts/application.js +2 -0
  96. data/spec/dummy/public/javascripts/controls.js +965 -0
  97. data/spec/dummy/public/javascripts/dragdrop.js +974 -0
  98. data/spec/dummy/public/javascripts/effects.js +1123 -0
  99. data/spec/dummy/public/javascripts/jquery-1.6.4.js +9046 -0
  100. data/spec/dummy/public/javascripts/prototype.js +6001 -0
  101. data/spec/dummy/public/javascripts/rails.js +175 -0
  102. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  103. data/spec/dummy/script/rails +6 -0
  104. data/spec/engine_spec.rb +12 -0
  105. data/spec/fixtures/big_eye_tiny.jpg +0 -0
  106. data/spec/fixtures/octologo.png +0 -0
  107. data/spec/fixtures/test.txt +2 -0
  108. data/spec/fixtures/video-test.mov +0 -0
  109. data/spec/helpers/phocoder_helper_spec.rb +421 -0
  110. data/spec/integration/navigation_spec.rb +10 -0
  111. data/spec/models/acts_as_phocodable_spec.rb +664 -0
  112. data/spec/models/encodable_job_spec.rb +50 -0
  113. data/spec/phocoder_rails_spec.rb +8 -0
  114. data/spec/routing/phocoder_routing_spec.rb +19 -0
  115. data/spec/spec_helper.rb +75 -0
  116. metadata +375 -0
@@ -0,0 +1,20 @@
1
+ class <%= name.classify %> < ActiveRecord::Base
2
+
3
+ acts_as_phocodable :thumbnail_class => "<%= name.classify %>Thumbnail",
4
+ :thumbnails => [
5
+ {:label=>"small",:width=>100,:height=>100 },
6
+ {:label=>"medium",:width=>400,:height=>400,
7
+ :frame=>{ :width=>20, :bottom=>50, :color=>'003' },
8
+ :annotations=>[
9
+ {:text=>"Annotation Testing",:pointsize=>30,:fill_color=>'fff',:gravity=>"South",:y=>10},
10
+ {:text=>"Howdy!",:pointsize=>10,:fill_color=>'ccc',:gravity=>"North",:y=>5}
11
+ ]
12
+ }
13
+ ],
14
+
15
+ :videos => [ {:label => 'mp4',:video_codec=>"h264" }, #, :thumbnails=>{ :number=>1, :start_at_first_frame=>1 }
16
+ {:label => 'webm', :video_codec=>"vp8" },
17
+ {:label => 'ogv', :video_codec=>"theora" }
18
+ ]
19
+
20
+ end
@@ -0,0 +1,56 @@
1
+ class Create<%= name.classify.pluralize %> < ActiveRecord::Migration
2
+ def self.up
3
+
4
+ create_table :<%= name.pluralize %> do |t|
5
+ t.string "filename"
6
+ t.string "content_type"
7
+ t.integer "duration_in_ms"
8
+ t.integer "width"
9
+ t.integer "height"
10
+ t.integer "file_size"
11
+ t.string "upload_host"
12
+ t.datetime "created_at"
13
+ t.datetime "updated_at"
14
+ t.datetime "taken_at"
15
+ t.float "lat"
16
+ t.float "lng"
17
+ t.string "encodable_status"
18
+
19
+ t.timestamps
20
+ end
21
+
22
+ add_index :<%= name.pluralize %>, :id
23
+
24
+
25
+ create_table :<%= name.singularize %>_thumbnails do |t|
26
+ t.string "filename"
27
+ t.string "content_type"
28
+ t.integer "duration_in_ms"
29
+ t.integer "width"
30
+ t.integer "height"
31
+ t.integer "file_size"
32
+ t.string "upload_host"
33
+ t.datetime "created_at"
34
+ t.datetime "updated_at"
35
+ t.datetime "taken_at"
36
+ t.float "lat"
37
+ t.float "lng"
38
+ t.string "encodable_status"
39
+
40
+ t.string "thumbnail"
41
+ t.integer "parent_id"
42
+ t.string "parent_type"
43
+
44
+ t.timestamps
45
+ end
46
+
47
+ add_index :<%= name.singularize %>_thumbnails, :id
48
+ add_index :<%= name.singularize %>_thumbnails, :parent_id
49
+
50
+ end
51
+
52
+ def self.down
53
+ drop_table :<%= name.pluralize %>
54
+ drop_table :<%= name.singularize %>_thumbnails
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ class <%= name.classify %>Thumbnail < ActiveRecord::Base
2
+
3
+ acts_as_phocodable :parent_class => "<%= name.classify %>"
4
+
5
+ end
@@ -0,0 +1,64 @@
1
+ class Make<%= name.classify.pluralize %>Encodable < ActiveRecord::Migration
2
+ def self.up
3
+
4
+
5
+ add_column :<%= name.pluralize %>, :filename, :string
6
+ add_column :<%= name.pluralize %>, :content_type, :string
7
+ add_column :<%= name.pluralize %>, :duration_in_ms, :integer
8
+ add_column :<%= name.pluralize %>, :width, :integer
9
+ add_column :<%= name.pluralize %>, :height, :integer
10
+ add_column :<%= name.pluralize %>, :file_size, :integer
11
+ add_column :<%= name.pluralize %>, :upload_host, :string
12
+ add_column :<%= name.pluralize %>, :taken_at, :datetime
13
+ add_column :<%= name.pluralize %>, :lat, :float
14
+ add_column :<%= name.pluralize %>, :lng, :float
15
+ add_column :<%= name.pluralize %>, :encodable_status, :string
16
+
17
+
18
+
19
+ create_table :<%= name.singularize %>_thumbnails do |t|
20
+ t.string "filename"
21
+ t.string "content_type"
22
+ t.integer "duration_in_ms"
23
+ t.integer "width"
24
+ t.integer "height"
25
+ t.integer "file_size"
26
+ t.string "upload_host"
27
+ t.datetime "created_at"
28
+ t.datetime "updated_at"
29
+ t.datetime "taken_at"
30
+ t.float "lat"
31
+ t.float "lng"
32
+ t.string "encodable_status"
33
+
34
+ t.string "thumbnail"
35
+ t.integer "parent_id"
36
+ t.string "parent_type"
37
+
38
+ t.timestamps
39
+ end
40
+
41
+ add_index :<%= name.singularize %>_thumbnails, :id
42
+ add_index :<%= name.singularize %>_thumbnails, :parent_id
43
+
44
+ end
45
+
46
+ def self.down
47
+
48
+ remove_column :<%= name.pluralize %>, :filename
49
+ remove_column :<%= name.pluralize %>, :content_type
50
+ remove_column :<%= name.pluralize %>, :duration_in_ms
51
+ remove_column :<%= name.pluralize %>, :width
52
+ remove_column :<%= name.pluralize %>, :height
53
+ remove_column :<%= name.pluralize %>, :file_size
54
+ remove_column :<%= name.pluralize %>, :upload_host
55
+ remove_column :<%= name.pluralize %>, :created_at
56
+ remove_column :<%= name.pluralize %>, :updated_at
57
+ remove_column :<%= name.pluralize %>, :taken_at
58
+ remove_column :<%= name.pluralize %>, :lat
59
+ remove_column :<%= name.pluralize %>, :lng
60
+ remove_column :<%= name.pluralize %>, :encodable_status
61
+
62
+ drop_table :<%= name.singularize %>_thumbnails
63
+ end
64
+ end
@@ -0,0 +1,28 @@
1
+ development:
2
+ phocoder_api_key: asdf
3
+ zencoder_api_key: asdf
4
+ base_url: http://your.host.test.com
5
+ storeage_mode : s3
6
+ s3_bucket_name: bucket.name
7
+ s3_access_key_id: asdf
8
+ s3_secret_access_key: asdf
9
+
10
+ test:
11
+ phocoder_api_key: asdf
12
+ zencoder_api_key: asdf
13
+ phocoder_url: http://photoapi.chaos.webapeel.com
14
+ base_url: http://your.host.test.com
15
+ storeage_mode : local
16
+ s3_bucket_name: bucket.name
17
+ s3_access_key_id: asdf
18
+ s3_secret_access_key: asdf
19
+
20
+ production:
21
+ phocoder_api_key: asdf
22
+ zencoder_api_key: asdf
23
+ base_url: http://your.host.test.com
24
+ storeage_mode : s3
25
+ processing_mode : resque
26
+ s3_bucket_name: bucket.name
27
+ s3_access_key_id: asdf
28
+ s3_secret_access_key: asdf
@@ -0,0 +1,23 @@
1
+ <%%= form_for( @<%= file_name.singularize %>, :html => { :multipart => true } ) do |f| %>
2
+
3
+ <%% if @<%= file_name.singularize %>.errors.any? %>
4
+ <div id="error_explanation">
5
+ <h2><%%= pluralize(@<%= file_name.singularize %>.errors.count, "error") %> prohibited this encodable from being saved:</h2>
6
+ <ul>
7
+ <%% @<%= file_name.singularize %>.errors.full_messages.each do |msg| %>
8
+ <li><%%= msg %></li>
9
+ <%% end %>
10
+ </ul>
11
+ </div>
12
+ <%% end %>
13
+
14
+ <div class="field">
15
+ <%%= f.label :file, "Upload image file" %>
16
+ <%%= f.file_field :file %>
17
+ </div>
18
+
19
+ <div class="actions">
20
+ <%%= f.submit %>
21
+ </div>
22
+
23
+ <%% end %>
@@ -0,0 +1,26 @@
1
+ <h1>Listing <%= file_name %></h1>
2
+
3
+ <table>
4
+ <tr>
5
+ <th>Filename</th>
6
+ <th></th>
7
+ <th></th>
8
+
9
+ </tr>
10
+
11
+ <%% @<%= file_name %>.each do |<%= file_name.singularize %>| %>
12
+ <tr>
13
+ <td>
14
+ <%%= phocoder_thumbnail <%= file_name.singularize %>,"small",false %><br/>
15
+ <%%= <%= file_name.singularize %>.filename %>
16
+ </td>
17
+ <td><%%= link_to 'Show', <%= file_name.singularize %> %></td>
18
+
19
+ <td><%%= link_to 'Destroy', <%= file_name.singularize %>, :confirm => 'Are you sure?', :method => :delete %></td>
20
+ </tr>
21
+ <%% end %>
22
+ </table>
23
+
24
+ <br />
25
+
26
+ <%%= link_to 'New <%= file_name.singularize %>', new_<%= file_name.singularize %>_path %>
@@ -0,0 +1,5 @@
1
+ <h1>New <%= file_name.singularize %></h1>
2
+
3
+ <%%= render 'form' %>
4
+
5
+ <%%= link_to 'Back', <%= file_name %>_path %>
@@ -0,0 +1,12 @@
1
+ <p id="notice"><%%= notice %></p>
2
+
3
+ <p>
4
+ <b>Filename:</b>
5
+ <%%= @<%= file_name.singularize %>.filename %>
6
+ </p>
7
+
8
+ <%%= phocoder_thumbnail @<%= file_name.singularize %>,"medium" %>
9
+
10
+ <br/>
11
+
12
+ <%%= link_to 'Back', <%= file_name %>_path %>
@@ -0,0 +1,12 @@
1
+ module PhocoderRails
2
+ require 'phocoder_rails/engine' if defined?(Rails)
3
+
4
+ require 'active_record'
5
+ #require 'action_pack'
6
+ #require 'active_support'
7
+ require 'aws/s3'
8
+
9
+ require 'phocoder_rails/acts_as_phocodable'
10
+ require 'phocoder_rails/errors'
11
+ #require 'phocoder_rails/base'
12
+ end
@@ -0,0 +1,1153 @@
1
+ module ActsAsPhocodable
2
+
3
+ require 'phocoder'
4
+ require 'zencoder'
5
+ require 'open-uri'
6
+ # Storeage mode controls how uploads are handled.
7
+ # Valid options are:
8
+ # offline : For development mode with no net connection. No processing.
9
+ # local : To store images locally but use Phocoder for processing.
10
+ # s3 : Store image in S3 and use Phocoder for processing.
11
+ # Set this options either in evnironment.rb or
12
+ # in environments/development.rb etc...
13
+
14
+ mattr_accessor :storeage_mode
15
+ self.storeage_mode = "local"
16
+
17
+
18
+ # Processing mode controls when images get sent to phocoder
19
+ # Valid options are:
20
+ # automatic : Send to phocoder as soon as the file is stored.
21
+ # With 'local' storage mode, this submits the job
22
+ # to phocoder while the user is still waiting.
23
+ # delayed : Handle storage/phocoding in a background process.
24
+ # spawn : Use the Spawn library to fork a new process to store/phocode.
25
+ mattr_accessor :processing_mode
26
+ self.processing_mode = "automatic"
27
+
28
+ # This is used as the base address for phocoder notifications.
29
+ # When storeage_mode == "local" this is also used to point
30
+ # phocoder 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 access_key_id for storing s3 files
41
+ mattr_accessor :s3_access_key_id
42
+ self.s3_access_key_id = "your-access-key-id"
43
+
44
+ # The secret_access_key for storing s3 files
45
+ mattr_accessor :s3_secret_access_key
46
+ self.s3_secret_access_key = "your-secret-access-key"
47
+
48
+ # The javascript library to use for updates
49
+ # either 'prototype' or 'jquery'
50
+ mattr_accessor :javascript_library
51
+ self.javascript_library = 'prototype'
52
+
53
+ # The local directory where files should be stored
54
+ mattr_accessor :local_base_dir
55
+ self.local_base_dir = '/tmp'
56
+
57
+ # The config file that tells phocoder where to find
58
+ # config options.
59
+ mattr_accessor :config_file
60
+ self.config_file = "config/phocodable.yml"
61
+
62
+
63
+ # The list of image content types that are considered web safe
64
+ # These can be displayed directly, skipping processing if in offline mode
65
+ mattr_accessor :web_safe_image_types
66
+ self.web_safe_image_types = [
67
+ 'image/jpeg',
68
+ 'image/jpg',
69
+ 'image/gif',
70
+ 'image/png',
71
+ 'image/x-png',
72
+ 'image/jpg',
73
+ 'application/png',
74
+ 'application/x-png'
75
+ ]
76
+
77
+ # The list of image content types that are not considered web safe
78
+ # These can not be displayed directly
79
+ mattr_accessor :other_image_types
80
+ self.other_image_types = [
81
+ 'image/pjpeg',
82
+ 'image/x-ms-bmp',
83
+ 'image/bmp',
84
+ 'image/x-bmp',
85
+ 'image/x-bitmap',
86
+ 'image/x-xbitmap',
87
+ 'image/x-win-bitmap',
88
+ 'image/x-windows-bmp',
89
+ 'image/ms-bmp',
90
+ 'application/bmp',
91
+ 'application/x-bmp',
92
+ 'application/x-win-bitmap',
93
+ 'application/preview',
94
+ 'image/jp_',
95
+ 'application/jpg',
96
+ 'application/x-jpg',
97
+ 'image/pipeg',
98
+ 'image/vnd.swiftview-jpeg',
99
+ 'image/x-xbitmap',
100
+ 'image/gi_',
101
+ 'image/x-citrix-pjpeg',
102
+ 'image/x-nikon-nef',
103
+ 'image/tiff',
104
+ 'image/x-olympus-orf',
105
+ 'image/x-dcraw'
106
+ ]
107
+
108
+ # The list of content types that will trigger image handling.
109
+ def image_types
110
+ web_safe_image_types + other_image_types
111
+ end
112
+
113
+
114
+ # The list of content types that will trigger video handling.
115
+ mattr_accessor :video_types
116
+ self.video_types = [
117
+ 'application/x-flash-video',
118
+ 'video/avi',
119
+ 'video/mp4',
120
+ 'video/ogg',
121
+ 'video/quicktime',
122
+ 'video/3gp',
123
+ 'video/3gpp',
124
+ 'video/vnd.objectvideo',
125
+ 'video/x-ms-wmv',
126
+ 'video/x-ms-asf',
127
+ 'video/x-ms-wvx',
128
+ 'video/x-ms-wm',
129
+ 'video/x-ms-wmx'
130
+ ]
131
+
132
+ # Mapping for generating a file extension
133
+ # based on the codec passed in for zencoder
134
+ mattr_accessor :video_extensions
135
+ self.video_extensions = {
136
+ "h264" => "mp4",
137
+ "vp6" => "vp6",
138
+ "vp8" => "webm",
139
+ "theora" => "ogv",
140
+ "mpeg4" => "mpg",
141
+ "wmv" => "wmv"
142
+ }
143
+
144
+ # TODO : This needs to be fixed.
145
+ # It currently matches anything with an 'x' in it
146
+ mattr_accessor :label_size_regex
147
+ self.label_size_regex = /(\d*)x(\d*)(pad|crop|stretch|preserve)?/ #
148
+
149
+ mattr_accessor :size_string_regex
150
+ self.size_string_regex = /(\d*)x(\d*)([!>]?)/
151
+
152
+ def image?(content_type)
153
+ image_types.include?(content_type)
154
+ end
155
+
156
+ def web_safe?(content_type)
157
+ web_safe_image_types.include?(content_type)
158
+ end
159
+
160
+ def video?(content_type)
161
+ video_types.include?(content_type)
162
+ end
163
+
164
+
165
+ #def self.storeage_mode
166
+ # @@storeage_mode
167
+ #end
168
+
169
+
170
+ def acts_as_phocodable(options = { })
171
+
172
+ include InstanceMethods
173
+ include Spawn
174
+ attr_reader :saved_file
175
+ attr_accessor :phocoding
176
+ after_save :save_local_file
177
+ before_destroy :cleanup #:remove_local_file,:destroy_thumbnails,:remove_s3_file
178
+
179
+ include ActiveSupport::Callbacks
180
+
181
+ define_callbacks :local_file_saved, :file_saved, :file_ready, :phocode_hdr, :phocode_composite, :phocode_tone_mapping
182
+
183
+ #cattr_accessor :phocoder_options
184
+ #self.phocoder_options = options
185
+
186
+ cattr_accessor :phocoder_thumbnails
187
+ self.phocoder_thumbnails = options[:thumbnails] ||= []
188
+
189
+ cattr_accessor :zencoder_videos
190
+ self.zencoder_videos = options[:videos] ||= []
191
+
192
+ cattr_accessor :thumbnail_class
193
+ self.thumbnail_class = options[:thumbnail_class] ? options[:thumbnail_class].constantize : self
194
+
195
+ cattr_accessor :parent_class
196
+ self.parent_class = options[:parent_class] ? options[:parent_class].constantize : self
197
+
198
+ has_many :thumbnails, :class_name => "::#{self.thumbnail_class.name}",:as => :parent
199
+ if self.thumbnail_class != self.parent_class
200
+ #we have to do this to get the poster for videos covered
201
+ belongs_to :parent, :polymorphic => true
202
+ else
203
+ belongs_to :parent, :class_name => "::#{self.parent_class.name}" ,:foreign_key => "parent_id"
204
+ end
205
+
206
+
207
+ has_many :encodable_jobs, :as => :encodable
208
+
209
+ scope :top_level, where({:parent_id=>nil}) if respond_to?(:parent_id)
210
+ scope :top_level, where({}) if !respond_to?(:parent_id)
211
+ # we can't just call this next scope 'parents' because that is already
212
+ # taken and returns an array of parent classes of the ruby object
213
+ scope :parent_items, where({:parent_id=>nil}) if respond_to?(:parent_id)
214
+ scope :parent_items, where({}) if !respond_to?(:parent_id)
215
+
216
+ scope :thumbnails, where("#{base_class.table_name}.parent_id is not null")
217
+
218
+ #just a writer, the reader is below
219
+ cattr_accessor :phocodable_configuration
220
+ read_phocodable_configuration
221
+ end
222
+
223
+ def config
224
+ return phocodable_configuration if !phocodable_configuration.blank?
225
+ self.read_phocodable_configuration
226
+ end
227
+
228
+ def validates_phocodable
229
+ validates_presence_of :content_type, :filename, :if=>lambda{ parent_id.blank? }
230
+ end
231
+
232
+ def update_from_phocoder(params)
233
+ Rails.logger.debug "tying to call update from phocoder for params = #{params.to_json}"
234
+ if !params[:output].blank?
235
+ Rails.logger.debug "find_by_phocoder_output_id #{params[:output][:id]}"
236
+ iu = find_by_phocoder_output_id params[:output][:id]
237
+ Rails.logger.debug "the item = #{iu}"
238
+ img_params = params[:output]
239
+ iu.filename = File.basename(params[:output][:url]) #if iu.filename.blank?
240
+ if ActsAsPhocodable.storeage_mode == "local"
241
+ iu.save_url(params[:output][:url])
242
+ end
243
+ else
244
+ iu = find_by_phocoder_input_id params[:input][:id]
245
+ img_params = params[:input]
246
+ end
247
+ [:file_size,:width,:height,:taken_at,:lat,:lng].each do |att|
248
+ setter = att.to_s + "="
249
+ if iu.respond_to? setter and !img_params[att].blank?
250
+ iu.send setter, img_params[att]
251
+ end
252
+ end
253
+
254
+ #iu.file_size = img_params[:file_size]
255
+ #iu.width = img_params[:width]
256
+ #iu.height = img_params[:height]
257
+ iu.phocoder_status = "ready"
258
+ iu.save
259
+ iu
260
+ end
261
+
262
+
263
+ # Updating from zencoder is a two pass operation.
264
+ # This method gets called for each output when it's ready.
265
+ # Once all outputs are ready, we call parent.check_zencoder_details
266
+ def update_from_zencoder(params)
267
+ Rails.logger.debug "tying to call update from zencoder for params = #{params}"
268
+ iu = find_by_zencoder_output_id params[:output][:id]
269
+ if params[:output][:url].match /%2F(.*)\?/
270
+ iu.filename = $1
271
+ else
272
+ iu.filename = File.basename(params[:output][:url].match(/(.*)\??/)[1])
273
+ end
274
+ #iu.filename = File.basename(params[:output][:url].match(/(.*)\??/)[1]) if iu.filename.blank?
275
+ if ActsAsPhocodable.storeage_mode == "local"
276
+ iu.save_url(params[:output][:url])
277
+ end
278
+ iu.zencoder_status = "ready"
279
+ iu.save
280
+ iu.parent.check_zencoder_details
281
+ end
282
+
283
+ def thumbnail_attributes_for(thumbnail_name = "small")
284
+ atts = self.phocoder_thumbnails.select{|atts| atts[:label] == thumbnail_name }.first
285
+ if atts.blank?
286
+ atts = create_atts_from_size_string(thumbnail_name)
287
+ end
288
+ if atts.blank?
289
+ raise ThumbnailAttributesNotFoundError.new("No thumbnail attributes were found for label '#{thumbnail_name}'")
290
+ end
291
+ atts
292
+ end
293
+
294
+ def create_label_from_size_string(size_string)
295
+ if size_string.match ActsAsPhocodable.size_string_regex
296
+ size_string = size_string.gsub("!","crop")
297
+ size_string = size_string.gsub(">","preserve")
298
+ end
299
+ size_string
300
+ end
301
+
302
+ def create_atts_from_size_string(label_string)
303
+ match = label_string.match ActsAsPhocodable.label_size_regex
304
+ return nil if match.blank?
305
+ atts = {}
306
+ if !match[1].blank?
307
+ atts[:width] = match[1]
308
+ end
309
+ if !match[2].blank?
310
+ atts[:height] = match[2]
311
+ end
312
+ if !match[3].blank?
313
+ atts[:aspect_mode] = match[3]
314
+ end
315
+ atts[:label] = label_string
316
+ #atts[:label] = "#{atts[:width]}x#{atts[:height]}"
317
+ #atts[:label] += "_#{atts[:aspect_mode]}" if atts[:aspect_mode]
318
+ atts
319
+ end
320
+
321
+
322
+
323
+ def read_phocodable_configuration
324
+ config_path = File.join(::Rails.root.to_s, ActsAsPhocodable.config_file)
325
+ puts "looking for a config in #{config_path}"
326
+ self.phocodable_configuration = YAML.load(ERB.new(File.read(config_path)).result)[::Rails.env.to_s].symbolize_keys
327
+ self.apply_phocodable_configuration
328
+ end
329
+
330
+ def apply_phocodable_configuration
331
+ if self.phocodable_configuration[:base_url]
332
+ ActsAsPhocodable.base_url = phocodable_configuration[:base_url]
333
+ end
334
+ if self.phocodable_configuration[:storeage_mode]
335
+ ActsAsPhocodable.storeage_mode = phocodable_configuration[:storeage_mode]
336
+ end
337
+ if self.phocodable_configuration[:processing_mode]
338
+ ActsAsPhocodable.processing_mode = phocodable_configuration[:processing_mode]
339
+ end
340
+ if self.phocodable_configuration[:s3_bucket_name]
341
+ ActsAsPhocodable.s3_bucket_name = phocodable_configuration[:s3_bucket_name]
342
+ end
343
+ if self.phocodable_configuration[:s3_access_key_id]
344
+ ActsAsPhocodable.s3_access_key_id = phocodable_configuration[:s3_access_key_id]
345
+ end
346
+ if self.phocodable_configuration[:s3_secret_access_key]
347
+ ActsAsPhocodable.s3_secret_access_key = phocodable_configuration[:s3_secret_access_key]
348
+ end
349
+ if self.phocodable_configuration[:javascript_library]
350
+ ActsAsPhocodable.javascript_library = phocodable_configuration[:javascript_library]
351
+ end
352
+ if self.phocodable_configuration[:local_base_dir]
353
+ ActsAsPhocodable.local_base_dir = phocodable_configuration[:local_base_dir]
354
+ end
355
+
356
+
357
+ if self.phocodable_configuration[:phocoder_url]
358
+ ::Phocoder.base_url = phocodable_configuration[:phocoder_url]
359
+ end
360
+ if self.phocodable_configuration[:phocoder_api_key]
361
+ ::Phocoder.api_key = phocodable_configuration[:phocoder_api_key]
362
+ end
363
+ if self.phocodable_configuration[:zencoder_api_key]
364
+ ::Zencoder.api_key = phocodable_configuration[:zencoder_api_key]
365
+ end
366
+ if ActsAsPhocodable.storeage_mode == "s3"
367
+ self.establish_aws_connection
368
+ end
369
+ end
370
+
371
+ def establish_aws_connection
372
+ AWS::S3::Base.establish_connection!(
373
+ :access_key_id => ActsAsPhocodable.s3_access_key_id,
374
+ :secret_access_key => ActsAsPhocodable.s3_secret_access_key
375
+ )
376
+ end
377
+
378
+
379
+
380
+
381
+
382
+
383
+ module InstanceMethods
384
+
385
+
386
+
387
+ def image?
388
+ self.class.image?(content_type)
389
+ end
390
+
391
+ def web_safe?
392
+ self.class.web_safe?(content_type)
393
+ end
394
+
395
+ def video?
396
+ self.class.video?(content_type)
397
+ end
398
+
399
+ def encode
400
+ if image?
401
+ phocode
402
+ elsif video?
403
+ zencode
404
+ end
405
+ end
406
+
407
+ def recode
408
+ reload #make sure that we have current thumbs
409
+ destroy_thumbnails
410
+ reload
411
+ encode
412
+ end
413
+
414
+ def ready?
415
+ if ActsAsPhocodable.storeage_mode == "offline"
416
+ true
417
+ #elsif image?
418
+ # return phocoder_status=='ready'
419
+ #elsif video?
420
+ # return zencoder_status=='ready'
421
+ #else
422
+ # return false
423
+ else
424
+ return encodable_status == "ready"
425
+ end
426
+ end
427
+
428
+ def error?
429
+ if ActsAsPhocodable.storeage_mode == "offline"
430
+ false
431
+ #elsif image?
432
+ # return phocoder_status=='failed'
433
+ #elsif video?
434
+ # return zencoder_status=='failed'
435
+ #else
436
+ # true
437
+ else
438
+ return encodable_status == "ready"
439
+ end
440
+ end
441
+
442
+ def create_thumbnails_from_response(response_thumbs,job_id)
443
+ new_thumbs = []
444
+ response_thumbs.each do |thumb_params|
445
+ puts "creating a thumb for #{thumb_params["label"]}"
446
+ # we do this the long way around just in case some of these
447
+ # atts are attr_protected
448
+ thumb = nil
449
+ if respond_to?(:parent_id) and !self.parent_id.blank?
450
+ Rails.logger.debug "trying to create a thumb from the parent "
451
+ thumb = self.parent.thumbnails.new()
452
+ self.parent.thumbnails << thumb
453
+ else
454
+ Rails.logger.debug "trying to create a thumb from myself "
455
+ thumb = self.thumbnails.new()
456
+ self.thumbnails << thumb
457
+ end
458
+
459
+
460
+ thumb.thumbnail = thumb_params["label"]
461
+ thumb.filename = thumb_params["filename"]
462
+ thumb.width = thumb_params["width"]
463
+ thumb.height = thumb_params["height"]
464
+ tjob = thumb.encodable_jobs.new
465
+
466
+ tjob.phocoder_output_id = thumb_params["id"]
467
+ tjob.phocoder_job_id = job_id
468
+ #thumb.parent_id = self.id
469
+ tjob.phocoder_status = "phocoding"
470
+ thumb.encodable_jobs << tjob
471
+ thumb.encodable_status = "phocoding"
472
+ thumb.save
473
+ new_thumbs << thumb
474
+ Rails.logger.debug " thumb.errors = #{thumb.errors.to_json}"
475
+ puts " thumb.errors = #{thumb.errors.to_json}"
476
+ end
477
+ new_thumbs
478
+ end
479
+
480
+ def clear_phocoding
481
+ phocoding = false
482
+ end
483
+
484
+ def dedupe_input_thumbs(input_thumbs)
485
+ needed_thumbs = []
486
+ input_thumbs.each do |it|
487
+ t = thumbnails.find_by_thumbnail(it[:label])
488
+ if t.blank?
489
+ needed_thumbs << it
490
+ end
491
+ end
492
+ needed_thumbs
493
+ end
494
+
495
+ def phocode(input_thumbs = self.parent_class.phocoder_thumbnails)
496
+ puts " input_thumbs.count = #{input_thumbs.size}"
497
+ input_thumbs = dedupe_input_thumbs(input_thumbs)
498
+ puts " after dedupe input_thumbs.count = #{input_thumbs.size}"
499
+ #if self.thumbnails.count >= self.class.phocoder_thumbnails.size
500
+ # raise "This item already has thumbnails!"
501
+ # return
502
+ #end
503
+
504
+ return if input_thumbs.size == 0
505
+ # We do this because sometimes save will get called more than once
506
+ # during a single request
507
+ return if phocoding
508
+ phocoding = true
509
+
510
+ Rails.logger.debug "trying to phocode for #{Phocoder.base_url} "
511
+ Rails.logger.debug "callback url = #{callback_url}"
512
+ response = Phocoder::Job.create(phocoder_params(input_thumbs))
513
+ Rails.logger.debug "the phocode response = #{response.to_json}" if Rails.env != "test"
514
+ puts "the phocode response = #{response.to_json}" if Rails.env != "test"
515
+ job = self.encodable_jobs.new
516
+ job.phocoder_input_id = response.body["job"]["inputs"].first["id"]
517
+ job.phocoder_job_id = response.body["job"]["id"]
518
+ job.phocoder_status = "phocoding"
519
+ self.encodable_jobs << job
520
+ self.encodable_status = "phocoding" unless self.encodable_status == "ready" # the unless clause allows new thumbs to be created on the fly without jacking with the status
521
+ self.save #false need to do save(false) here if we're calling phocode on after_save
522
+ response_thumbs = response.body["job"]["thumbnails"]
523
+ Rails.logger.debug "trying to decode #{response_thumbs.size} response_thumbs = #{response_thumbs.to_json}"
524
+ puts "trying to decode #{response_thumbs.size} response_thumbs = #{response_thumbs.to_json}"
525
+ create_thumbnails_from_response(response_thumbs,response.body["job"]["id"])
526
+ end
527
+
528
+ def phocode_hdr
529
+ #if self.thumbnails.count >= self.class.phocoder_thumbnails.size
530
+ # raise "This item already has thumbnails!"
531
+ # return
532
+ #end
533
+
534
+ # We do this because sometimes save will get called more than once
535
+ # during a single request
536
+ return if phocoding
537
+ phocoding = true
538
+ run_callbacks :phocode_hdr do
539
+ Rails.logger.debug "trying to phocode for #{Phocoder.base_url} "
540
+ Rails.logger.debug "callback url = #{callback_url}"
541
+ response = Phocoder::Job.create(phocoder_hdr_params)
542
+ Rails.logger.debug "the response from phocode_hdr = #{response.body.to_json}"
543
+ job = self.encodable_jobs.new
544
+ job.phocoder_output_id = response.body["job"]["hdr"]["id"]
545
+ job.phocoder_job_id = response.body["job"]["id"]
546
+ job.phocoder_status = "phocoding"
547
+ self.encodable_jobs << job
548
+ self.encodable_status = "phocoding"
549
+ self.save #false need to do save(false) here if we're calling phocode on after_save
550
+ end
551
+
552
+ end
553
+
554
+
555
+ def phocode_tone_mapping
556
+ #if self.thumbnails.count >= self.class.phocoder_thumbnails.size
557
+ # raise "This item already has thumbnails!"
558
+ # return
559
+ #end
560
+
561
+ # We do this because sometimes save will get called more than once
562
+ # during a single request
563
+ return if phocoding
564
+ phocoding = true
565
+ run_callbacks :phocode_tone_mapping do
566
+ destroy_thumbnails
567
+ Rails.logger.debug "trying to phocode for #{Phocoder.base_url} "
568
+ Rails.logger.debug "callback url = #{callback_url}"
569
+ response = Phocoder::Job.create(phocoder_tone_mapping_params)
570
+ Rails.logger.debug "tone_mapping response = #{response.body.to_json}"
571
+ puts "tone_mapping response = #{response.body.to_json}"
572
+ job = self.encodable_jobs.new
573
+ job.phocoder_output_id = response.body["job"]["tone_mapping"]["id"]
574
+ job.phocoder_job_id = response.body["job"]["id"]
575
+ job.phocoder_status = "phocoding"
576
+ self.encodable_jobs << job
577
+ self.encodable_status = "phocoding"
578
+ self.save #false need to do save(false) here if we're calling phocode on after_save
579
+ response_thumbs = response.body["job"]["thumbnails"]
580
+ Rails.logger.debug "trying to decode #{response_thumbs.size} response_thumbs = #{response_thumbs.to_json}"
581
+ create_thumbnails_from_response(response_thumbs,response.body["job"]["id"])
582
+ end
583
+ end
584
+
585
+
586
+ def phocode_composite
587
+ #if self.thumbnails.count >= self.class.phocoder_thumbnails.size
588
+ # raise "This item already has thumbnails!"
589
+ # return
590
+ #end
591
+
592
+ # We do this because sometimes save will get called more than once
593
+ # during a single request
594
+ return if phocoding
595
+ phocoding = true
596
+ run_callbacks :phocode_composite do
597
+ destroy_thumbnails
598
+ Rails.logger.debug "trying to phocode for #{Phocoder.base_url} "
599
+ Rails.logger.debug "callback url = #{callback_url}"
600
+ response = Phocoder::Job.create(phocoder_composite_params)
601
+ Rails.logger.debug "composite response = #{response.body.to_json}"
602
+ puts "composite response = #{response.body.to_json}"
603
+ job = self.encodable_jobs.new
604
+ job.phocoder_output_id = response.body["job"]["composite"]["id"]
605
+ job.phocoder_job_id = response.body["job"]["id"]
606
+ job.phocoder_status = "phocoding"
607
+ self.encodable_jobs << job
608
+ self.encodable_status = "phocoding"
609
+ self.save #false need to do save(false) here if we're calling phocode on after_save
610
+ response_thumbs = response.body["job"]["thumbnails"]
611
+ Rails.logger.debug "trying to decode #{response_thumbs.size} response_thumbs = #{response_thumbs.to_json}"
612
+ puts "trying to decode #{response_thumbs.size} response_thumbs = #{response_thumbs.to_json}"
613
+ create_thumbnails_from_response(response_thumbs,response.body["job"]["id"])
614
+ end
615
+ end
616
+
617
+
618
+ def zencode
619
+ # We do this because sometimes save will get called more than once
620
+ # during a single request
621
+ return if @zencoding
622
+ @zencoding = true
623
+
624
+ Rails.logger.debug "trying to zencode!!!!!"
625
+ Rails.logger.debug "callback url = #{callback_url}"
626
+ response = Zencoder::Job.create(zencoder_params)
627
+ Rails.logger.debug "response from Zencoder = #{response.body.to_json}"
628
+ job = self.encodable_jobs.new
629
+ job.zencoder_job_id = response.body["id"]
630
+ self.encodable_jobs << job
631
+
632
+ response.body["outputs"].each do |output_params|
633
+ thumb = self.thumbnails.new()
634
+ thumb.thumbnail = output_params["label"]
635
+
636
+ tjob = thumb.encodable_jobs.new
637
+ tjob.zencoder_output_id = output_params["id"]
638
+ tjob.zencoder_url = output_params["url"]
639
+ tjob.zencoder_job_id = response.body["id"]
640
+ tjob.zencoder_status = "zencoding"
641
+ thumb.encodable_jobs << tjob
642
+
643
+ self.thumbnails << thumb
644
+ thumb.encodable_status = "zencoding"
645
+ thumb.save
646
+ puts " thumb.errors = #{thumb.errors.to_json}"
647
+ end
648
+
649
+ self.save
650
+ end
651
+
652
+ def phocoder_extension
653
+ if self.content_type.blank?
654
+ ".jpg"
655
+ else
656
+ self.content_type.match(/png/) ? ".png" : ".jpg"
657
+ end
658
+ end
659
+
660
+ def phocoder_params(input_thumbs = self.parent_class.phocoder_thumbnails)
661
+ {:input => {:url => self.public_url, :notifications=>[{:url=>callback_url }] },
662
+ :thumbnails => phocoder_thumbnail_params(input_thumbs)
663
+ }
664
+ end
665
+
666
+ def phocoder_thumbnail_params(input_thumbs = self.parent_class.phocoder_thumbnails)
667
+ input_thumbs.map{|thumb|
668
+ thumb_filename = thumb[:label] + "_" + File.basename(self.filename,File.extname(self.filename)) + phocoder_extension
669
+ base_url = ActsAsPhocodable.storeage_mode == "s3" ? "s3://#{self.s3_bucket_name}/#{self.thumbnail_resource_dir}/" : ""
670
+ th = thumb.clone
671
+ th[:base_url] = base_url if !base_url.blank?
672
+ th.merge({
673
+ :filename=>thumb_filename,
674
+ :notifications=>[{:url=>thumbnail_callback_url }]
675
+ })
676
+ }
677
+ end
678
+
679
+
680
+ def phocoder_hdr_params
681
+ { }
682
+ end
683
+
684
+ def phocoder_tone_mapping_params
685
+ { }
686
+ end
687
+
688
+ def phocoder_composite_params
689
+ { }
690
+ end
691
+
692
+ def zencoder_params
693
+ base_url = ActsAsPhocodable.storeage_mode == "s3" ? "s3://#{self.s3_bucket_name}/#{self.thumbnail_resource_dir}/" : ""
694
+ params = {:input => self.public_url ,
695
+ :outputs => self.class.zencoder_videos.map{|video|
696
+ vid_filename = self.new_zencoder_filename( video[:video_codec] )
697
+ vid = video.clone
698
+ if vid[:thumbnails] and vid[:thumbnails].is_a? Array
699
+ vid[:thumbnails].each do |thumb|
700
+ thumb[:base_url] = base_url if !base_url.blank?
701
+ end
702
+ elsif vid[:thumbnails]
703
+ vid[:thumbnails][:base_url] = base_url if !base_url.blank?
704
+ end
705
+
706
+ vid[:base_url] = base_url if !base_url.blank?
707
+ vid.merge({
708
+ :filename=>vid_filename,
709
+ :public=>1,
710
+ :notifications=>[{:url=>zencoder_thumbnail_callback_url }]
711
+ })
712
+ }
713
+ }
714
+ params[:outputs][0][:thumbnails] = { :number=>1, :start_at_first_frame=>1,:public=>1 }
715
+ params[:outputs][0][:thumbnails][:base_url] = base_url if !base_url.blank?
716
+ Rails.logger.debug "for zencoder the params = #{params.to_json}"
717
+ #puts "for zencoder the params = #{params.to_json}"
718
+ params
719
+ end
720
+
721
+ def new_zencoder_filename(format)
722
+ filename + "." + self.class.video_extensions[format]
723
+ end
724
+
725
+
726
+ def check_zencoder_details
727
+ # we don't get a lot of info from zencoder, so we have to ask for details
728
+ shouldCheck = true
729
+ thumbnails.each do |t|
730
+ if t.encodable_status != 'ready'
731
+ shouldCheck = false
732
+ end
733
+ end
734
+
735
+ return if !shouldCheck
736
+
737
+ details = Zencoder::Job.details(self.encodable_jobs.last.zencoder_job_id)
738
+
739
+ #puts "in check_zencoder_details the details.body = #{details.body.to_json}"
740
+
741
+ if details.body["job"]["state"] != 'finished'
742
+ self.encodable_jobs.last.zencoder_status = details.body["job"]["state"]
743
+ save
744
+ return
745
+ end
746
+
747
+ self.encodable_jobs.last.zencoder_status = self.encodable_status = "ready"
748
+ self.width = details.body["job"]["input_media_file"]["width"]
749
+ self.height = details.body["job"]["input_media_file"]["height"]
750
+ self.duration_in_ms = details.body["job"]["input_media_file"]["duration_in_ms"]
751
+ self.file_size = details.body["job"]["input_media_file"]["file_size_bytes"]
752
+ self.save
753
+
754
+ #puts "the output files = #{details.body["job"]["output_media_files"]}"
755
+
756
+ update_zencoder_outputs(details)
757
+
758
+ # Now create the image thumb
759
+ create_zencoder_image_thumb(details)
760
+
761
+ end
762
+
763
+
764
+ def update_zencoder_outputs(details)
765
+ details.body["job"]["output_media_files"].each do |output|
766
+ #puts "updating for output = #{output.to_json}"
767
+ job = EncodableJob.find_by_zencoder_output_id output["id"]
768
+ thumb = job.encodable
769
+ thumb.width = output["width"]
770
+ thumb.height = output["height"]
771
+ thumb.file_size = output["file_size_bytes"]
772
+ thumb.duration_in_ms = output["duration_in_ms"]
773
+ thumb.save
774
+ end
775
+ end
776
+
777
+ def create_zencoder_image_thumb(details)
778
+
779
+ # for now we should only have one thumbnail
780
+ output = details.body["job"]["thumbnails"].first
781
+ return if output.blank?
782
+ thumb = thumbnails.new
783
+ thumb.thumbnail = "poster"
784
+ thumb.width = output["width"]
785
+ thumb.height = output["height"]
786
+ thumb.file_size = output["file_size_bytes"]
787
+ thumb.filename = "frame_0000.png" #File.basename(output["url"])
788
+ thumb.content_type = "image/png"
789
+ if ActsAsPhocodable.storeage_mode == "local"
790
+ thumb.save_url(output["url"])
791
+ end
792
+ thumb.save
793
+ #now get thumbnails for the poster
794
+ thumb.phocode
795
+ end
796
+
797
+ def phocodable_config
798
+ puts "looking for config!"
799
+ self.class.config
800
+ end
801
+
802
+ def phocodable?
803
+ true
804
+ end
805
+
806
+ def save_url(url)
807
+ Rails.logger.debug "We are about to download : #{url} to #{local_dir} - #{local_path}"
808
+ FileUtils.mkdir_p(local_dir) if !File.exists?(local_dir)
809
+ FileUtils.touch local_path
810
+ writeOut = open(local_path, "wb")
811
+ writeOut.write(open(url).read)
812
+ writeOut.close
813
+ end
814
+
815
+ def destroy_thumbnails
816
+ if self.class.phocoder_thumbnails.size == 0 and self.class.zencoder_videos.size == 0
817
+ puts "we're skipping destory_thumbnails since we don't do any processing "
818
+ return
819
+ end
820
+ #puts "calling destory thumbnails for #{self.thumbnails.count} - #{self.thumbnails.size}"
821
+ self.thumbnails.each do |thumb|
822
+ thumb.destroy
823
+ end
824
+ #puts "calling destory thumbnails for #{self.thumbnails.count}"
825
+ end
826
+
827
+ def create_atts_from_size_string(label_string)
828
+ self.class.create_atts_from_size_string(label_string)
829
+ end
830
+
831
+ def thumbnail_attributes_for(thumbnail_name)
832
+ self.class.thumbnail_attributes_for(thumbnail_name)
833
+ end
834
+
835
+ def thumbnail_for(thumbnail_hash_or_name)
836
+ thumbnail_name = thumbnail_hash_or_name.is_a?(Hash) ? thumbnail_hash_or_name[:label] : thumbnail_hash_or_name
837
+ if thumbnail_name and thumbnail_name.match ActsAsPhocodable.size_string_regex
838
+ thumbnail_name = self.class.create_label_from_size_string(thumbnail_name)
839
+ end
840
+ if thumbnail_name.blank? and thumbnail_hash_or_name.is_a?(Hash)
841
+ thumbnail_name = "#{thumbnail_hash_or_name[:width]}x#{thumbnail_hash_or_name[:height]}"
842
+ puts "thumbnail_name = #{thumbnail_name}"
843
+ thumbnail_hash_or_name[:label] = thumbnail_name
844
+ end
845
+ thumb = thumbnails.find_by_thumbnail(thumbnail_name)
846
+ if thumb.blank? and ActsAsPhocodable.storeage_mode == "offline"
847
+ thumb = self
848
+ elsif thumb.blank? and thumbnail_hash_or_name.is_a? Hash
849
+ thumb = self.phocode([thumbnail_hash_or_name]).first
850
+ elsif thumb.blank? and thumbnail_hash_or_name.is_a?(String) and thumbnail_hash_or_name.match ActsAsPhocodable.label_size_regex
851
+ atts = create_atts_from_size_string(thumbnail_name)
852
+ thumb = self.phocode([atts]).first
853
+ end
854
+ if thumb.blank?
855
+ raise ThumbnailNotFoundError.new("No thumbnail was found for label '#{thumbnail_name}'")
856
+ end
857
+ thumb
858
+ #a dirty hack for now to keep things working.
859
+ #Remove this!!!!!!!!!!!!!!!!!!!!!!!!!!!!
860
+ #Go back to just returning the thumb
861
+ #thumb.blank? ? self : thumb
862
+ end
863
+
864
+ def get_thumbnail(thumbnail_name)
865
+ thumbnail_for(thumbnail_name)
866
+ end
867
+
868
+ def file=(new_file)
869
+ return if new_file.nil?
870
+ Rails.logger.debug "we got a new file of class = #{new_file.class}"
871
+ cleanup
872
+ if new_file.is_a? File
873
+ self.filename = File.basename new_file.path
874
+ self.content_type = MIME::Types.type_for(self.filename).first.content_type
875
+ self.file_size = new_file.size
876
+ else
877
+ self.filename = new_file.original_filename
878
+ self.content_type = new_file.content_type
879
+ self.file_size = new_file.size
880
+ end
881
+
882
+ if new_file.respond_to? :tempfile
883
+ @saved_file = new_file.tempfile
884
+ else
885
+ @saved_file = new_file
886
+ end
887
+ end
888
+
889
+ #compatability method for attachment_fu
890
+ def uploaded_data=(data)
891
+ self.file = data
892
+ end
893
+
894
+ def save_local_file
895
+ return if @saved_file.blank?
896
+ puts "saving the local file!!!!!!"
897
+ Rails.logger.debug "==================================================================================================="
898
+ Rails.logger.debug "about to save the local file"
899
+ run_callbacks :file_saved do
900
+ run_callbacks :local_file_saved do
901
+ FileUtils.mkdir_p local_dir
902
+ FileUtils.cp @saved_file.path, local_path
903
+ FileUtils.chmod 0755, local_path
904
+ self.encodable_status = "local"
905
+ if self.respond_to? :upload_host
906
+ self.upload_host = %x{hostname}.strip
907
+ end
908
+ @saved_file = nil
909
+ @saved_a_new_file = true
910
+ self.save
911
+ end
912
+ if ActsAsPhocodable.storeage_mode == "s3" and ActsAsPhocodable.processing_mode == "automatic"
913
+ self.save_s3_file
914
+ end
915
+ if ActsAsPhocodable.storeage_mode == "s3" and ActsAsPhocodable.processing_mode == "spawn"
916
+ spawn do # :method => :thread # <-- I think that should be set at the config/environment level
917
+ Rails.logger.debug "------------beginning of spawn block"
918
+ puts "------------beginning of spawn block"
919
+ self.save_s3_file
920
+ Rails.logger.debug "------------end of spawn block"
921
+ puts "------------end of spawn block"
922
+ end
923
+ end
924
+ if ActsAsPhocodable.storeage_mode == "local" and ActsAsPhocodable.processing_mode == "automatic"
925
+ self.encode
926
+ end
927
+
928
+ end
929
+ end
930
+
931
+ def fire_ready_callback
932
+ run_callbacks :file_ready do
933
+ end
934
+ end
935
+
936
+
937
+ def cleanup
938
+ #puts "calling cleanup!"
939
+ destroy_thumbnails
940
+ remove_local_file
941
+ if ActsAsPhocodable.storeage_mode == "s3"
942
+ remove_s3_file
943
+ end
944
+ end
945
+
946
+ def remove_local_file
947
+ if local_path and File.exists? local_path
948
+ FileUtils.rm local_path
949
+ if Dir.glob(File.join(local_dir,"*")).size == 0
950
+ FileUtils.rmdir local_dir
951
+ end
952
+ end
953
+ end
954
+
955
+ def path_id
956
+
957
+ #puts "parent_id = #{parent_id}"
958
+ #puts "parent = #{parent}"
959
+ if respond_to?(:parent_id)
960
+ parent_id.blank? ? id : parent.path_id
961
+ else
962
+ id
963
+ end
964
+ end
965
+
966
+ def resource_dir
967
+ File.join(self.class.table_name, path_id.to_s )
968
+ end
969
+
970
+ def thumbnail_resource_dir
971
+ File.join(self.thumbnail_class.table_name, path_id.to_s )
972
+ end
973
+
974
+ def local_dir
975
+ File.join(ActsAsPhocodable.local_base_dir,resource_dir)
976
+ end
977
+
978
+ def local_path
979
+ filename.blank? ? nil : File.join(local_dir,filename)
980
+ end
981
+
982
+ def local_url
983
+ filename.blank? ? nil : File.join("/",resource_dir,filename)
984
+ end
985
+
986
+ # This should generate a fully qualified http://something-something
987
+ # type of a reference. Depending on storeage_mode/base_url settings.
988
+ def public_url
989
+ puts "our base_url = #{base_url} and our local_url = #{local_url}"
990
+ if ActsAsPhocodable.storeage_mode == "local" or ActsAsPhocodable.storeage_mode == "offline"
991
+ base_url + local_url
992
+ else
993
+ s3_url
994
+ end
995
+ end
996
+
997
+ def public_filename
998
+ public_url
999
+ end
1000
+
1001
+
1002
+ def callback_url
1003
+ self.base_url + self.notification_callback_path
1004
+ end
1005
+
1006
+ def zencoder_callback_url
1007
+ self.base_url + self.zencoder_notification_callback_path
1008
+ end
1009
+
1010
+ def thumbnail_callback_url
1011
+ self.base_url + self.thumbnail_notification_callback_path
1012
+ end
1013
+
1014
+ def zencoder_thumbnail_callback_url
1015
+ self.base_url + self.zencoder_thumbnail_notification_callback_path
1016
+ end
1017
+
1018
+ def notification_callback_path
1019
+ "/phocoder/phocoder_notifications/#{self.class.name}/#{self.id}.json"
1020
+ end
1021
+
1022
+ def zencoder_notification_callback_path
1023
+ "/phocoder/zencoder_notifications/#{self.class.name}/#{self.id}.json"
1024
+ end
1025
+
1026
+ def thumbnail_notification_callback_path
1027
+ "/phocoder/phocoder_notifications/#{self.thumbnail_class.name}/#{self.id}.json"
1028
+ end
1029
+
1030
+ def zencoder_thumbnail_notification_callback_path
1031
+ "/phocoder/zencoder_notifications/#{self.thumbnail_class.name}/#{self.id}.json"
1032
+ end
1033
+
1034
+ def base_url
1035
+ self.class.base_url
1036
+ end
1037
+
1038
+ def s3_key
1039
+ filename.blank? ? nil : File.join(resource_dir,filename)
1040
+ end
1041
+
1042
+ def s3_url
1043
+ "http://#{s3_bucket_name}.s3.amazonaws.com/#{s3_key}"
1044
+ end
1045
+
1046
+ def s3_bucket_name
1047
+ self.class.s3_bucket_name
1048
+ end
1049
+
1050
+ def save_s3_file
1051
+ #I don't think we need this return check anymore.
1052
+ #return if !@saved_a_new_file
1053
+ #@saved_a_new_file = false
1054
+ AWS::S3::S3Object.store(
1055
+ s3_key,
1056
+ open(local_path),
1057
+ s3_bucket_name,
1058
+ :access => :public_read
1059
+ )
1060
+ self.encodable_status = "s3"
1061
+ self.save
1062
+ obj_data = AWS::S3::S3Object.find(s3_key,s3_bucket_name)
1063
+ Rails.logger.debug "----------------------------------------------------------------------------------------------------"
1064
+ if obj_data.size == file_size # it made it into s3 safely
1065
+ Rails.logger.debug " we are about to remove local file!"
1066
+ remove_local_file
1067
+ else
1068
+ msg = "The file was not saved to S3 sucessfully. Orig size: #{file_size} - S3 size: #{obj_data.size}"
1069
+ Rails.logger.debug msg
1070
+ raise ActsAsPhocodable::Error.new msg
1071
+ end
1072
+ self.encode
1073
+ end
1074
+
1075
+
1076
+ def remove_s3_file
1077
+ #puts "trying to delete #{s3_key} #{s3_bucket_name}"
1078
+ #if ActsAsPhocodable.storeage_mode == "s3"
1079
+ AWS::S3::S3Object.delete s3_key, s3_bucket_name
1080
+ #end
1081
+ rescue Exception => e
1082
+ #this probably means that the file never made it to S3
1083
+ end
1084
+
1085
+ # Sanitizes a filename.
1086
+ def filename=(new_name)
1087
+ write_attribute :filename, sanitize_filename(new_name)
1088
+ end
1089
+
1090
+ def sanitize_filename(filename)
1091
+ return unless filename
1092
+ filename.strip.tap do |name|
1093
+ # NOTE: File.basename doesn't work right with Windows paths on Unix
1094
+ # get only the filename, not the whole path
1095
+ name.gsub! /^.*(\\|\/)/, ''
1096
+
1097
+ # Finally, replace all non alphanumeric, underscore or periods with underscore
1098
+ name.gsub! /[^A-Za-z0-9\.\-]/, '_'
1099
+ end
1100
+ end
1101
+
1102
+ # Calculate the width for the target thumbnail atts
1103
+ def calc_width(thumbnail_atts)
1104
+ tw = thumbnail_atts[:width].blank? ? 100000 : thumbnail_atts[:width].to_f
1105
+ th = thumbnail_atts[:height].blank? ? 100000 : thumbnail_atts[:height].to_f
1106
+ w = width.to_f
1107
+ h = height.to_f
1108
+ if w <= tw and h <= th
1109
+ w.round
1110
+ elsif w > h
1111
+ if (h * ( tw / w )).round < tw
1112
+ tw .round
1113
+ else
1114
+ (h * ( tw / w )).round
1115
+ end
1116
+ else
1117
+ if (w * ( th / h )).round < tw
1118
+ (w * ( th / h )).round
1119
+ else
1120
+ tw.round
1121
+ end
1122
+ end
1123
+ end #end calc_width
1124
+
1125
+
1126
+ def calc_height(thumbnail_atts)
1127
+ tw = thumbnail_atts[:width].blank? ? 100000 : thumbnail_atts[:width].to_f
1128
+ th = thumbnail_atts[:height].blank? ? 100000 : thumbnail_atts[:height].to_f
1129
+ w = width.to_f
1130
+ h = height.to_f
1131
+ if w <= tw and h <= th
1132
+ h.round
1133
+ elsif w > h
1134
+ if (h * ( tw / w )).round < th
1135
+ (h * ( tw / w )).round
1136
+ else
1137
+ th.round
1138
+ end
1139
+ else
1140
+ if (w * ( th / h )).round < tw
1141
+ th.round
1142
+ else
1143
+ (h * ( tw / w )).round
1144
+ end
1145
+ end
1146
+ end #end calc_height
1147
+
1148
+
1149
+
1150
+ end#module InstanceMethods
1151
+
1152
+ end
1153
+ ActiveRecord::Base.extend ActsAsPhocodable