photo_folder 1.0.5 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,297 @@
1
+ #external libraries
2
+ require 'rubygems'
3
+ gem 'sqlite3-ruby'
4
+ gem 'activerecord'
5
+ require 'active_record'
6
+ require 'fileutils'
7
+ require 'tempfile'
8
+ require 'pstore'
9
+ require 'set'
10
+ require 'ftools'
11
+ require 'digest/md5'
12
+ require 'yaml'
13
+
14
+ #internal libraries
15
+ current_dir = File.expand_path(File.dirname(__FILE__))
16
+ require File.join(current_dir,'..','vendor','acts_as_tree.rb')
17
+ require File.join(current_dir,'..','vendor','acts_as_list.rb')
18
+ require File.join(current_dir,'..','vendor','mini_exiftool.rb')
19
+ require File.join(current_dir,'models','photo.rb')
20
+ require File.join(current_dir,'models','photo_tag.rb')
21
+ require File.join(current_dir,'models','photo_tagging.rb')
22
+ require File.join(current_dir,'models','photo_collection.rb')
23
+
24
+ unless Numeric.instance_methods.include? 'to_a'
25
+ class Numeric
26
+ def to_a
27
+ [self]
28
+ end
29
+ end
30
+ end
31
+
32
+ module PhotoFolder
33
+ def self.setup_database(database_location)
34
+ ActiveRecord::Base.establish_connection(
35
+ :adapter => "sqlite3",
36
+ :database => database_location,
37
+ :timeout => 5000
38
+ )
39
+ PhotoFolder::create_schema
40
+ end
41
+
42
+ def self.create_schema
43
+ if !Photo.table_exists?
44
+ ActiveRecord::Base.connection.create_table("photos") do |t|
45
+ t.integer "photo_collection_id"
46
+ t.integer "position"
47
+ t.integer "height"
48
+ t.integer "width"
49
+ t.string "guid"
50
+ t.string "path"
51
+ t.string "name"
52
+ t.datetime "date"
53
+ t.string "location"
54
+ t.string "f_stop"
55
+ t.string "shutter_speed"
56
+ t.string "focal_length"
57
+ t.string "iso"
58
+ t.string "camera"
59
+ t.string "lens"
60
+ t.text "caption"
61
+ t.datetime "last_modified"
62
+ t.integer "nsfw"
63
+ t.integer "featured"
64
+ end
65
+ end
66
+
67
+ if !PhotoCollection.table_exists?
68
+ ActiveRecord::Base.connection.create_table("photo_collections") do |t|
69
+ t.string "name"
70
+ t.string "path"
71
+ t.integer "parent_id"
72
+ t.integer "position"
73
+ t.text "meta"
74
+ end
75
+ end
76
+
77
+ if !PhotoTag.table_exists?
78
+ ActiveRecord::Base.connection.create_table("photo_tags") do |t|
79
+ t.string "tag"
80
+ end
81
+ end
82
+
83
+ if !PhotoTagging.table_exists?
84
+ ActiveRecord::Base.connection.create_table("photo_taggings") do |t|
85
+ t.integer "photo_tag_id"
86
+ t.integer "photo_id"
87
+ end
88
+ end
89
+ end
90
+
91
+ def self.photos_list
92
+ return @photos_list if !@photos_list.nil?
93
+ @photos_list = Dir[PhotoFolder.source_directory_location + '/**/*.{png,jpg}']
94
+ end
95
+
96
+ def self.all_paths_in_database
97
+ return @all_paths_in_database if !@all_paths_in_database.nil?
98
+ @all_paths_in_database = Photo.find(:all).collect(&:path)
99
+ end
100
+
101
+ def self.all_paths_in_filesystem
102
+ return @all_paths_in_filesystem if !@all_paths_in_filesystem.nil?
103
+ @all_paths_in_filesystem = PhotoFolder::photos_list.collect{|file| file.gsub(PhotoFolder.source_directory_location + '/','')}
104
+ end
105
+
106
+ def self.flush_cached_path_information
107
+ @all_paths_in_filesystem = nil
108
+ @all_paths_in_database = nil
109
+ end
110
+
111
+ def self.scan_photos
112
+ to_add = []
113
+ to_update = []
114
+ to_remove = []
115
+
116
+ PhotoFolder::all_paths_in_filesystem.each do |path_in_filesystem|
117
+ to_add.push(path_in_filesystem) if !PhotoFolder::all_paths_in_database.select{|path_in_database| path_in_database == path_in_filesystem}[0]
118
+ end
119
+
120
+ PhotoFolder::all_paths_in_database.each do |path_in_database|
121
+ to_remove.push(path_in_database) if !PhotoFolder::all_paths_in_filesystem.select{|path_in_filesystem| path_in_filesystem == path_in_database}[0]
122
+ end
123
+
124
+ PhotoFolder::all_paths_in_filesystem.each do |path_in_filesystem|
125
+ if !to_add.include?(path_in_filesystem) && !to_remove.include?(path_in_filesystem)
126
+ entry = Photo.find_by_path(path_in_filesystem)
127
+ if entry && File.mtime(entry.full_path) > entry.last_modified
128
+ to_update.push(path_in_filesystem)
129
+ end
130
+ elsif to_add.include?(path_in_filesystem)
131
+ #cleaned = Photo.clean_filename(path_in_filesystem)
132
+ entry = Photo.find_by_path(path_in_filesystem)
133
+ if entry
134
+ to_update.push(path_in_filesystem)
135
+ end
136
+ end
137
+ end
138
+
139
+ to_add.reject!{|item| to_update.include?(item)}
140
+
141
+ [to_add,to_update,to_remove]
142
+ end
143
+
144
+ def self.scan_photo_collections
145
+ collection_paths_in_database = PhotoCollection.find(:all).collect(&:path)
146
+
147
+ collection_paths_in_filesystem = []
148
+ PhotoFolder::all_paths_in_database.each do |path|
149
+ collection = path.gsub(/\/[^\/]+$/,'')
150
+ collection_bits = collection.split('/')
151
+ collection_bits.each_with_index do |part,i|
152
+ joined = collection_bits[0,i].join('/')
153
+ collection_paths_in_filesystem.push(joined) if !collection_paths_in_filesystem.include?(joined) && joined != ''
154
+ end
155
+ collection_paths_in_filesystem.push(collection) if !collection_paths_in_filesystem.include?(collection)
156
+ end
157
+
158
+ to_add = []
159
+ to_remove = []
160
+
161
+ collection_paths_in_filesystem.each do |path_in_filesystem|
162
+ to_add.push(path_in_filesystem) if !collection_paths_in_database.include?(path_in_filesystem)
163
+ end
164
+
165
+ collection_paths_in_database.each do |path_in_database|
166
+ to_remove.push(path_in_database) if !collection_paths_in_filesystem.include?(path_in_database)
167
+ end
168
+
169
+ [to_add,to_remove]
170
+ end
171
+
172
+ def self.hash_from_database
173
+ {
174
+ :photo_collections => PhotoCollection,
175
+ :photos => Photo,
176
+ :photo_tags => PhotoTag,
177
+ :photo_taggings => PhotoTagging
178
+ }.inject(Hash.new) do |result,key_name_and_model|
179
+ key_name = key_name_and_model[0]
180
+ model = key_name_and_model[1]
181
+ result[key_name] = model.find(:all).inject(Hash.new) do |inner_result,item|
182
+ inner_result[item.id.to_s] = item.attributes.inject(Hash.new) do |attribute_result,key_and_value|
183
+ key = key_and_value[0]
184
+ value = key_and_value[1]
185
+ attribute_result[key.to_s] = value.to_s
186
+ attribute_result
187
+ end
188
+ inner_result
189
+ end
190
+ result
191
+ end
192
+ end
193
+
194
+ def self.write_database_to_file(path)
195
+ File.open(path,'w'){|f| f.write(PhotoFolder::hash_from_database.to_json) }
196
+ end
197
+
198
+ def self.source_directory_location
199
+ @source_directory_location
200
+ end
201
+
202
+ def self.generate(source_directory_location,database_location,json_location,include_nsfw = false,exif_tool_location = 'exiftool')
203
+ Photo.send(:with_scope, :find => {:conditions => include_nsfw ? "nsfw = 1 OR nsfw = 0" : "nsfw = 0"}) do
204
+
205
+ @source_directory_location = source_directory_location
206
+
207
+ begin
208
+ MiniExiftool.configure(exif_tool_location)
209
+ rescue
210
+ puts "WARNING: Could not configure MiniExifTool, EXIF data will not be parsed."
211
+ end
212
+
213
+ puts "PhotoFolder Database Generator"
214
+ puts "=============================="
215
+
216
+ PhotoFolder::setup_database(database_location)
217
+ photos_list = PhotoFolder::photos_list
218
+ puts "Scanning #{photos_list.length} photos in #{source_directory_location}"
219
+
220
+ photos_to_add, photos_to_update, photos_to_remove = PhotoFolder::scan_photos
221
+
222
+ Photo.transaction do
223
+ if photos_to_add.length > 0
224
+ photos_to_add.each do |path|
225
+ puts "Adding photo: #{path}"
226
+ Photo.create :path => path
227
+ end
228
+ else
229
+ puts "No photos to add."
230
+ end
231
+
232
+ if photos_to_update.length > 0
233
+ photos_to_update.each do |path|
234
+ puts "Updating photo: #{path}"
235
+ photo = Photo.find_by_path(path)
236
+ photo.update_meta if photo
237
+ end
238
+ else
239
+ puts "No photos to update."
240
+ end
241
+
242
+ if photos_to_remove.length > 0
243
+ photos_to_remove.each do |path|
244
+ puts "Removing photo: #{path}"
245
+ Photo.find_all_by_path(path).each(&:destroy)
246
+ end
247
+ else
248
+ puts "No photos to remove."
249
+ end
250
+ end
251
+
252
+ PhotoFolder::flush_cached_path_information
253
+ collections_to_add, collections_to_remove = PhotoFolder::scan_photo_collections
254
+
255
+ PhotoCollection.transaction do
256
+ if collections_to_add.length > 0
257
+ collections_to_add.sort_by{|path| path.split('/').pop}.each do |path|
258
+ puts "Adding collection: #{path}"
259
+ PhotoCollection.create :path => path
260
+ end
261
+ else
262
+ puts "No photo collections to add."
263
+ end
264
+
265
+ if collections_to_remove.length > 0
266
+ collections_to_remove.each do |path|
267
+ puts "Removing collection: #{path}"
268
+ PhotoCollection.find_by_path(path).destroy if PhotoCollection.find_by_path(path)
269
+ end
270
+ else
271
+ puts "No photo collections to remove."
272
+ end
273
+
274
+ puts "Ensuring correct tree structure of photo collections."
275
+ PhotoCollection.find(:all).each(&:set_parent_id)
276
+
277
+ puts "Ensuring correct position of photos and photo collections."
278
+ if PhotoCollection.positions
279
+ puts "Setting positions for root collections from #{PhotoCollection.positions_file_path}"
280
+ end
281
+ PhotoCollection.set_correct_positions(PhotoCollection.find_all_by_parent_id(0))
282
+ PhotoCollection.find(:all).each do |photo_collection|
283
+ if photo_collection.positions
284
+ puts "Setting positions for #{photo_collection.name} from #{photo_collection.positions_file_path}"
285
+ photo_collection.set_correct_positions
286
+ end
287
+ if photo_collection.set_meta
288
+ puts "Setting meta data for #{photo_collection.name} from #{photo_collection.meta_file_path}"
289
+ end
290
+ end
291
+ end
292
+
293
+ puts "Writing database to #{json_location}"
294
+ PhotoFolder::write_database_to_file(json_location)
295
+ end
296
+ end
297
+ end
data/photo_folder.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "photo_folder"
3
- s.version = "1.0.5"
3
+ s.version = "1.0.6"
4
4
  s.date = "2010-05-11"
5
5
  s.summary = "JavaScript gallery"
6
6
  s.email = "ryan@syntacticx.com"
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
11
11
  s.files = [
12
12
  "README.markdown",
13
13
  "photo_folder.gemspec"] +
14
- Dir['models/**/*'] +
14
+ Dir['lib/**/*'] +
15
15
  Dir['vendor/**/*']
16
16
  s.add_dependency("sqlite3-ruby", ["> 0.0.0"])
17
17
  s.add_dependency("activerecord", ["> 0.0.0"])
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: photo_folder
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 5
10
- version: 1.0.5
9
+ - 6
10
+ version: 1.0.6
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ryan Johnson
@@ -61,10 +61,11 @@ extra_rdoc_files: []
61
61
  files:
62
62
  - README.markdown
63
63
  - photo_folder.gemspec
64
- - models/photo.rb
65
- - models/photo_collection.rb
66
- - models/photo_tag.rb
67
- - models/photo_tagging.rb
64
+ - lib/models/photo.rb
65
+ - lib/models/photo_collection.rb
66
+ - lib/models/photo_tag.rb
67
+ - lib/models/photo_tagging.rb
68
+ - lib/photo_folder.rb
68
69
  - vendor/acts_as_list.rb
69
70
  - vendor/acts_as_tree.rb
70
71
  - vendor/mini_exiftool.rb