photo_folder 1.0.6 → 1.0.7
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.
- data/lib/models/photo.rb +43 -18
- data/lib/models/photo_collection.rb +33 -1
- data/lib/photo_folder.rb +33 -6
- data/photo_folder.gemspec +2 -1
- data/vendor/jpeg_meta_info.rb +39 -0
- metadata +20 -3
data/lib/models/photo.rb
CHANGED
@@ -50,27 +50,52 @@ class Photo < ActiveRecord::Base
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def set_exif_data
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
[:focal_length,:iso,:shutter_speed,:f_stop,:camera,:caption,:location,:height,:width].each do |key|
|
57
|
-
self.send(key.to_s + '=',exif[key] || nil)
|
58
|
-
end
|
59
|
-
|
60
|
-
#date,title,lens and tags are special cases
|
61
|
-
if exif[:date].is_a? Time
|
62
|
-
self.date = exif[:date]
|
53
|
+
if full_path.match(/\.(png|jpg)$/)
|
54
|
+
if PhotoFolder.mini_exiftool_available?
|
55
|
+
set_exif_data_with_mini_exiftool
|
63
56
|
else
|
64
|
-
|
65
|
-
self.date = Time.mktime(date_match[1],date_match[2],date_match[3],date_match[4],date_match[5],date_match[6]) if date_match
|
57
|
+
set_exif_data_without_mini_exiftool
|
66
58
|
end
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
59
|
+
else
|
60
|
+
set_default_exif_data
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def set_default_exif_data
|
65
|
+
self.height = 0
|
66
|
+
self.width = 0
|
67
|
+
@tags = []
|
68
|
+
end
|
69
|
+
|
70
|
+
def set_exif_data_with_mini_exiftool
|
71
|
+
exif = EXIFData.new(MiniExiftool.new(full_path),logger)
|
72
|
+
[:focal_length,:iso,:shutter_speed,:f_stop,:camera,:caption,:location,:height,:width].each do |key|
|
73
|
+
self.send(key.to_s + '=',exif[key] || nil)
|
74
|
+
end
|
75
|
+
#date,title,lens and tags are special cases
|
76
|
+
if exif[:date].is_a? Time
|
77
|
+
self.date = exif[:date]
|
78
|
+
else
|
79
|
+
date_match = (exif[:date] || '').match(/([\d]+):([\d]+):([\d]+) ([\d]+):([\d]+):([\d]+)/)
|
80
|
+
self.date = Time.mktime(date_match[1],date_match[2],date_match[3],date_match[4],date_match[5],date_match[6]) if date_match
|
81
|
+
end
|
82
|
+
self.name = exif[:title] || full_path.split('/').pop.gsub(/\.[a-zA-Z]{1,4}/,'')
|
83
|
+
self.lens = exif[:lens] ? exif[:lens] : nil
|
84
|
+
@tags = exif[:tags] || []
|
85
|
+
end
|
86
|
+
|
87
|
+
def set_exif_data_without_mini_exiftool
|
88
|
+
self.name = full_path.split('/').pop.gsub(/\.[a-zA-Z]{1,4}/,'')
|
89
|
+
if(full_path.match(/\.png$/))
|
90
|
+
width, height = File.read(full_path)[0x10..0x18].unpack('NN')
|
91
|
+
else
|
92
|
+
jpeg_meta_info = JPEGMetaInfo.new(full_path)
|
93
|
+
width = jpeg_meta_info.width
|
94
|
+
height = jpeg_meta_info.height
|
73
95
|
end
|
96
|
+
self.width = width
|
97
|
+
self.height = height
|
98
|
+
@tags = []
|
74
99
|
end
|
75
100
|
|
76
101
|
class EXIFData
|
@@ -37,6 +37,23 @@ class PhotoCollection < ActiveRecord::Base
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
+
def self.title_card_path
|
41
|
+
File.join(PhotoFolder.source_directory_location,'index.markdown')
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.add_title_card
|
45
|
+
if File.exists?(PhotoCollection.title_card_path)
|
46
|
+
truncated_title_card_path = title_card_path[PhotoFolder.source_directory_location.length + 1,title_card_path.length]
|
47
|
+
title_card = Photo.find_by_photo_collection_id_and_path(0,truncated_title_card_path) || Photo.create(
|
48
|
+
:photo_collection_id => 0,
|
49
|
+
:path => truncated_title_card_path
|
50
|
+
)
|
51
|
+
title_card.update_attribute :caption, Maruku.new(File.read(title_card_path)).to_html
|
52
|
+
else
|
53
|
+
false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
40
57
|
def set_children_parent_id
|
41
58
|
PhotoFolder::all_paths_in_database.select{|path| self.path.underscore.gsub(/\s/,'_') == path.gsub(/\/[^\/]+$/,'').underscore.gsub(/\s/,'_')}.each do |path|
|
42
59
|
Photo.update_all("photo_collection_id = #{self.id}","path = '#{path}'")
|
@@ -82,6 +99,21 @@ class PhotoCollection < ActiveRecord::Base
|
|
82
99
|
meta_data
|
83
100
|
end
|
84
101
|
|
102
|
+
def title_card_path
|
103
|
+
File.join(full_path,'index.markdown')
|
104
|
+
end
|
105
|
+
|
106
|
+
def add_title_card
|
107
|
+
if File.exists?(title_card_path)
|
108
|
+
truncated_title_card_path = title_card_path[PhotoFolder.source_directory_location.length + 1,title_card_path.length]
|
109
|
+
title_card = photos.find_by_path(truncated_title_card_path) || photos.create(:path => truncated_title_card_path)
|
110
|
+
title_card.update_attribute :caption, Maruku.new(File.read(title_card_path)).to_html
|
111
|
+
title_card.move_to_top
|
112
|
+
else
|
113
|
+
false
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
85
117
|
def set_correct_positions
|
86
118
|
positions.each_with_index do |file_name,i|
|
87
119
|
photo = photos.find_by_path("#{path}/#{file_name}")
|
@@ -93,4 +125,4 @@ class PhotoCollection < ActiveRecord::Base
|
|
93
125
|
end
|
94
126
|
end
|
95
127
|
end
|
96
|
-
end
|
128
|
+
end
|
data/lib/photo_folder.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
require 'rubygems'
|
3
3
|
gem 'sqlite3-ruby'
|
4
4
|
gem 'activerecord'
|
5
|
+
gem 'maruku'
|
5
6
|
require 'active_record'
|
6
7
|
require 'fileutils'
|
7
8
|
require 'tempfile'
|
@@ -10,12 +11,14 @@ require 'set'
|
|
10
11
|
require 'ftools'
|
11
12
|
require 'digest/md5'
|
12
13
|
require 'yaml'
|
14
|
+
require 'maruku'
|
13
15
|
|
14
16
|
#internal libraries
|
15
17
|
current_dir = File.expand_path(File.dirname(__FILE__))
|
16
18
|
require File.join(current_dir,'..','vendor','acts_as_tree.rb')
|
17
19
|
require File.join(current_dir,'..','vendor','acts_as_list.rb')
|
18
20
|
require File.join(current_dir,'..','vendor','mini_exiftool.rb')
|
21
|
+
require File.join(current_dir,'..','vendor','jpeg_meta_info.rb')
|
19
22
|
require File.join(current_dir,'models','photo.rb')
|
20
23
|
require File.join(current_dir,'models','photo_tag.rb')
|
21
24
|
require File.join(current_dir,'models','photo_tagging.rb')
|
@@ -30,16 +33,16 @@ unless Numeric.instance_methods.include? 'to_a'
|
|
30
33
|
end
|
31
34
|
|
32
35
|
module PhotoFolder
|
33
|
-
def self.
|
36
|
+
def self.establish_database_connection(database_location)
|
34
37
|
ActiveRecord::Base.establish_connection(
|
35
38
|
:adapter => "sqlite3",
|
36
39
|
:database => database_location,
|
37
40
|
:timeout => 5000
|
38
41
|
)
|
39
|
-
PhotoFolder::create_schema
|
40
42
|
end
|
41
43
|
|
42
44
|
def self.create_schema
|
45
|
+
schema_created = false
|
43
46
|
if !Photo.table_exists?
|
44
47
|
ActiveRecord::Base.connection.create_table("photos") do |t|
|
45
48
|
t.integer "photo_collection_id"
|
@@ -62,6 +65,7 @@ module PhotoFolder
|
|
62
65
|
t.integer "nsfw"
|
63
66
|
t.integer "featured"
|
64
67
|
end
|
68
|
+
schema_created = true
|
65
69
|
end
|
66
70
|
|
67
71
|
if !PhotoCollection.table_exists?
|
@@ -72,12 +76,14 @@ module PhotoFolder
|
|
72
76
|
t.integer "position"
|
73
77
|
t.text "meta"
|
74
78
|
end
|
79
|
+
schema_created = true
|
75
80
|
end
|
76
81
|
|
77
82
|
if !PhotoTag.table_exists?
|
78
83
|
ActiveRecord::Base.connection.create_table("photo_tags") do |t|
|
79
84
|
t.string "tag"
|
80
85
|
end
|
86
|
+
schema_created = true
|
81
87
|
end
|
82
88
|
|
83
89
|
if !PhotoTagging.table_exists?
|
@@ -85,12 +91,15 @@ module PhotoFolder
|
|
85
91
|
t.integer "photo_tag_id"
|
86
92
|
t.integer "photo_id"
|
87
93
|
end
|
94
|
+
schema_created = true
|
88
95
|
end
|
96
|
+
|
97
|
+
schema_created
|
89
98
|
end
|
90
99
|
|
91
100
|
def self.photos_list
|
92
101
|
return @photos_list if !@photos_list.nil?
|
93
|
-
@photos_list = Dir[PhotoFolder.source_directory_location + '/**/*.{png,jpg}']
|
102
|
+
@photos_list = Dir[PhotoFolder.source_directory_location + '/**/*.{png,jpg,markdown}']
|
94
103
|
end
|
95
104
|
|
96
105
|
def self.all_paths_in_database
|
@@ -138,6 +147,9 @@ module PhotoFolder
|
|
138
147
|
|
139
148
|
to_add.reject!{|item| to_update.include?(item)}
|
140
149
|
|
150
|
+
to_add.reject!{|item| item.match(/index\.markdown$/)}
|
151
|
+
to_update.reject!{|item| item.match(/index\.markdown$/)}
|
152
|
+
|
141
153
|
[to_add,to_update,to_remove]
|
142
154
|
end
|
143
155
|
|
@@ -199,21 +211,30 @@ module PhotoFolder
|
|
199
211
|
@source_directory_location
|
200
212
|
end
|
201
213
|
|
214
|
+
def self.mini_exiftool_available?
|
215
|
+
@mini_exiftool_available
|
216
|
+
end
|
217
|
+
|
202
218
|
def self.generate(source_directory_location,database_location,json_location,include_nsfw = false,exif_tool_location = 'exiftool')
|
203
219
|
Photo.send(:with_scope, :find => {:conditions => include_nsfw ? "nsfw = 1 OR nsfw = 0" : "nsfw = 0"}) do
|
220
|
+
puts "PhotoFolder Database Generator"
|
221
|
+
puts "=============================="
|
204
222
|
|
205
223
|
@source_directory_location = source_directory_location
|
206
224
|
|
207
225
|
begin
|
208
226
|
MiniExiftool.configure(exif_tool_location)
|
227
|
+
@mini_exiftool_available = true
|
209
228
|
rescue
|
229
|
+
@mini_exiftool_available = false
|
210
230
|
puts "WARNING: Could not configure MiniExifTool, EXIF data will not be parsed."
|
211
231
|
end
|
212
232
|
|
213
|
-
|
214
|
-
|
233
|
+
PhotoFolder::establish_database_connection(database_location)
|
234
|
+
if PhotoFolder::create_schema
|
235
|
+
puts "Generated schema in #{database_location}"
|
236
|
+
end
|
215
237
|
|
216
|
-
PhotoFolder::setup_database(database_location)
|
217
238
|
photos_list = PhotoFolder::photos_list
|
218
239
|
puts "Scanning #{photos_list.length} photos in #{source_directory_location}"
|
219
240
|
|
@@ -278,6 +299,9 @@ module PhotoFolder
|
|
278
299
|
if PhotoCollection.positions
|
279
300
|
puts "Setting positions for root collections from #{PhotoCollection.positions_file_path}"
|
280
301
|
end
|
302
|
+
if PhotoCollection.add_title_card
|
303
|
+
puts "Adding title card to root from #{PhotoCollection.title_card_path}"
|
304
|
+
end
|
281
305
|
PhotoCollection.set_correct_positions(PhotoCollection.find_all_by_parent_id(0))
|
282
306
|
PhotoCollection.find(:all).each do |photo_collection|
|
283
307
|
if photo_collection.positions
|
@@ -287,6 +311,9 @@ module PhotoFolder
|
|
287
311
|
if photo_collection.set_meta
|
288
312
|
puts "Setting meta data for #{photo_collection.name} from #{photo_collection.meta_file_path}"
|
289
313
|
end
|
314
|
+
if photo_collection.add_title_card
|
315
|
+
puts "Adding title card to #{photo_collection.name} from #{photo_collection.title_card_path}"
|
316
|
+
end
|
290
317
|
end
|
291
318
|
end
|
292
319
|
|
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.
|
3
|
+
s.version = "1.0.7"
|
4
4
|
s.date = "2010-05-11"
|
5
5
|
s.summary = "JavaScript gallery"
|
6
6
|
s.email = "ryan@syntacticx.com"
|
@@ -15,4 +15,5 @@ Gem::Specification.new do |s|
|
|
15
15
|
Dir['vendor/**/*']
|
16
16
|
s.add_dependency("sqlite3-ruby", ["> 0.0.0"])
|
17
17
|
s.add_dependency("activerecord", ["> 0.0.0"])
|
18
|
+
s.add_dependency("maruku", ["> 0.0.0"])
|
18
19
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class JPEGMetaInfo
|
2
|
+
attr_reader :width, :height, :bits
|
3
|
+
|
4
|
+
def initialize(file)
|
5
|
+
if file.kind_of? IO
|
6
|
+
examine(file)
|
7
|
+
else
|
8
|
+
File.open(file, 'rb') { |io| examine(io) }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def examine(io)
|
14
|
+
raise 'malformed JPEG' unless io.getc == 0xFF && io.getc == 0xD8 # SOI
|
15
|
+
|
16
|
+
class << io
|
17
|
+
def readint; (readchar << 8) + readchar; end
|
18
|
+
def readframe; read(readint - 2); end
|
19
|
+
def readsof; [readint, readchar, readint, readint, readchar]; end
|
20
|
+
def next
|
21
|
+
c = readchar while c != 0xFF
|
22
|
+
c = readchar while c == 0xFF
|
23
|
+
c
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
while marker = io.next
|
28
|
+
case marker
|
29
|
+
when 0xC0..0xC3, 0xC5..0xC7, 0xC9..0xCB, 0xCD..0xCF # SOF markers
|
30
|
+
length, @bits, @height, @width, components = io.readsof
|
31
|
+
raise 'malformed JPEG' unless length == 8 + components * 3
|
32
|
+
when 0xD9, 0xDA: break # EOI, SOS
|
33
|
+
when 0xFE: @comment = io.readframe # COM
|
34
|
+
when 0xE1: io.readframe # APP1, contains EXIF tag
|
35
|
+
else io.readframe # ignore frame
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
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:
|
4
|
+
hash: 25
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 1.0.
|
9
|
+
- 7
|
10
|
+
version: 1.0.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ryan Johnson
|
@@ -50,6 +50,22 @@ dependencies:
|
|
50
50
|
version: 0.0.0
|
51
51
|
type: :runtime
|
52
52
|
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: maruku
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 31
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
- 0
|
65
|
+
- 0
|
66
|
+
version: 0.0.0
|
67
|
+
type: :runtime
|
68
|
+
version_requirements: *id003
|
53
69
|
description: JavaScript gallery
|
54
70
|
email: ryan@syntacticx.com
|
55
71
|
executables: []
|
@@ -68,6 +84,7 @@ files:
|
|
68
84
|
- lib/photo_folder.rb
|
69
85
|
- vendor/acts_as_list.rb
|
70
86
|
- vendor/acts_as_tree.rb
|
87
|
+
- vendor/jpeg_meta_info.rb
|
71
88
|
- vendor/mini_exiftool.rb
|
72
89
|
has_rdoc: true
|
73
90
|
homepage: http://photofolder.org/
|