photo_folder 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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