gallerize-cli 0.1.1 → 0.2.0
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.
- checksums.yaml +4 -4
- data/README.md +13 -30
- data/config/global.yml.example +1 -1
- data/lib/gallerize.rb +163 -103
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fc69d889c2a6a376cc872a33e4b6bd60637a49a7
|
4
|
+
data.tar.gz: b3d1c67446924666c5d0bafe39e52dbadc04f08a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e9f3ee1e12f19706935e26052da9d640e479864154d6957547975c20f7d97082e3f0c847a62be699e04860ee22f141875ee73e35dd06cf53d26f2d07721efdbb
|
7
|
+
data.tar.gz: 805f18c473d8c70de3c8053729581a153d9ae347d8fe33d2cde9f22f095443c5ae2452460afb6ba14b0b09fda586139b946fada42098f1f1d91b6cc9097215cf
|
data/README.md
CHANGED
@@ -1,52 +1,35 @@
|
|
1
|
-
###
|
1
|
+
### Example
|
2
|
+
|
3
|
+
http://examples.hilscher.ca/gallerize/
|
2
4
|
|
3
|
-
Generate a static gallery from a folder of images.
|
4
5
|
|
5
|
-
|
6
|
+
### Overview
|
6
7
|
|
8
|
+
* generate a static gallery from a folder of images
|
7
9
|
* responsive layout
|
8
10
|
* thumbnails and fullsize are generated automatically
|
9
11
|
* does not alter existing directory
|
10
12
|
|
11
13
|
|
12
|
-
### Example
|
13
|
-
|
14
|
-
http://examples.hilscher.ca/static-gallery-generator/
|
15
|
-
|
16
|
-
|
17
|
-
### Usage
|
18
|
-
|
19
|
-
```
|
20
|
-
$ cd folder-with-pictures
|
21
|
-
$ gallerize
|
22
|
-
```
|
23
|
-
|
24
|
-
|
25
14
|
### Installation
|
26
15
|
|
27
|
-
* Clone or download the repo
|
28
|
-
|
29
16
|
```
|
30
|
-
|
17
|
+
gem install gallerize-cli
|
31
18
|
```
|
32
19
|
|
33
|
-
* Install depedencies
|
34
20
|
|
35
|
-
|
36
|
-
cd static-gallery-generator
|
37
|
-
bundle install
|
38
|
-
```
|
39
|
-
|
40
|
-
* Link bin/gallerize into your PATH
|
21
|
+
### Usage
|
41
22
|
|
42
23
|
```
|
43
|
-
|
24
|
+
$ cd folder-with-pictures
|
25
|
+
$ gallerize
|
26
|
+
$ open gallerize/index.html
|
44
27
|
```
|
45
28
|
|
46
29
|
|
47
30
|
### Configuration
|
48
31
|
|
49
|
-
|
32
|
+
Create .gallerize in the directory that contains your photos with any of these options:
|
50
33
|
|
51
34
|
| Name | Required? | Example Value | Description |
|
52
35
|
| ------------- |:-------------:| -----------------:| -------------------------------------------------------------:|
|
@@ -55,8 +38,8 @@ ln -sf "$(pwd)/bin/gallerize" $HOME/bin/gallerize
|
|
55
38
|
| workers | required | 4 | The number of processes to use when doing CPU intensive work |
|
56
39
|
| image_width | required | 1200 | The fullsize image width |
|
57
40
|
| image_height | required | 800 | The fullsize image height |
|
58
|
-
| thumb_width | required |
|
59
|
-
| thumb_height | required |
|
41
|
+
| thumb_width | required | 400 | The thumbnail image width |
|
42
|
+
| thumb_height | required | 300 | The thumbnail image height |
|
60
43
|
| output_name | optional | gallery | Directory name where the gallery will be created |
|
61
44
|
| tracking | optional | UA-0000000-2 | Enable google analytics by entering a tracking code |
|
62
45
|
|
data/config/global.yml.example
CHANGED
data/lib/gallerize.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
require 'ostruct'
|
2
3
|
require 'active_support/all'
|
3
4
|
require 'parallel'
|
4
5
|
require 'mini_magick'
|
@@ -10,92 +11,80 @@ ROOT = File.expand_path( File.join(__FILE__, '../../') )
|
|
10
11
|
|
11
12
|
class Gallerize
|
12
13
|
|
13
|
-
|
14
|
+
attr_accessor :image_paths
|
14
15
|
|
15
|
-
|
16
|
-
config = YAML.load(File.read(File.join(File.expand_path('.'), '.gallerize.yml')))
|
17
|
-
else
|
18
|
-
config = {}
|
19
|
-
end
|
20
|
-
|
21
|
-
unless File.exists?(File.join(ROOT,'config/global.yml'))
|
22
|
-
FileUtils.cp(File.join(ROOT,'config/global.yml.example'), File.join(ROOT,'config/global.yml'))
|
23
|
-
end
|
24
|
-
|
25
|
-
CONFIG = YAML.load(File.read(File.join(ROOT,'config/global.yml'))).merge(config)
|
26
|
-
|
27
|
-
PER_PAGE = CONFIG['per_page']
|
28
|
-
TRACKING = CONFIG['tracking']
|
29
|
-
IMAGE_TYPES = CONFIG['image_types']
|
30
|
-
WORKERS = CONFIG['workers'].to_i
|
16
|
+
VERSION='0.2.0'
|
31
17
|
|
32
18
|
def self.generate
|
33
19
|
new.perform
|
34
20
|
end
|
35
21
|
|
36
22
|
def perform
|
37
|
-
if
|
38
|
-
puts "no images found in #{
|
23
|
+
if image_paths.blank?
|
24
|
+
puts "no images found in #{source_dir.root} matching #{config.image_types}"
|
39
25
|
else
|
40
|
-
|
26
|
+
prepare_output_directory
|
41
27
|
generate_images
|
42
28
|
ticker = 0
|
43
|
-
images_to_html(images.each_slice(per_page).to_a.first, 0,
|
29
|
+
images_to_html(images.each_slice(config.per_page).to_a.first, 0, output_dir.html_file(:index) )
|
44
30
|
images.each_slice(per_page) do |some_images|
|
45
31
|
images_to_html(some_images, ticker)
|
46
32
|
ticker = ticker + 1
|
47
33
|
end
|
48
|
-
|
49
34
|
end
|
50
35
|
end
|
51
36
|
|
37
|
+
def prepare_output_directory
|
38
|
+
# remove html files
|
39
|
+
Dir.glob( output_dir.html_files ){|f| FileUtils.rm(f) }
|
40
|
+
# ensure output directory
|
41
|
+
FileUtils.mkdir( output_dir.root ) unless File.exists?( output_dir.root )
|
42
|
+
# ensure output/images directory
|
43
|
+
FileUtils.mkdir( output_dir.images ) unless File.exists?( output_dir.images )
|
44
|
+
# copy css and js from gem to output
|
45
|
+
output_dir.copy_from_gem_source( 'css', 'js' )
|
46
|
+
end
|
47
|
+
|
52
48
|
def generate_images
|
53
|
-
|
54
|
-
|
55
|
-
|
49
|
+
generated = []
|
50
|
+
# generate images and skip any that fail
|
51
|
+
Parallel.map( image_paths, in_processes: config.workers.to_i ) do |f|
|
52
|
+
begin
|
53
|
+
generate_fullsize(f)
|
54
|
+
generate_thumbnail(f)
|
55
|
+
generated << f
|
56
|
+
rescue => e
|
57
|
+
# if any error occurs while processing the image, skip it
|
58
|
+
puts "failed to process #{f}. error: #{e} #{e.backtrace.first}"
|
59
|
+
nil
|
60
|
+
end
|
56
61
|
end
|
62
|
+
generated
|
57
63
|
end
|
58
64
|
|
59
65
|
def images_to_html(some_images, ticker=0, name=nil)
|
60
66
|
some_images ||= []
|
61
67
|
navigation = (images.count / per_page.to_f).ceil.times.collect{|r| %Q{<a class="#{'active' if r == ticker}" href="images-#{r}.html">#{r}</a>} }.join("\n")
|
68
|
+
navigation = (images.count > some_images.count) ? %Q{<div class="navigation">#{navigation}</div>} : ""
|
62
69
|
html = %Q{
|
63
70
|
#{body}
|
64
|
-
|
65
|
-
#{navigation}
|
66
|
-
</div>
|
71
|
+
#{navigation}
|
67
72
|
<div id="images-container" class="images">
|
68
73
|
#{some_images.join("\n")}
|
69
74
|
</div>
|
70
|
-
|
71
|
-
#{navigation}
|
72
|
-
</div>
|
75
|
+
#{navigation}
|
73
76
|
#{footer}
|
74
77
|
}
|
75
|
-
name ||=
|
78
|
+
name ||= output_dir.html_file("images-#{ticker}")
|
76
79
|
puts "generate #{name}"
|
77
80
|
File.write(name, html)
|
78
81
|
end
|
79
82
|
|
80
83
|
def images
|
81
84
|
ticker = 0
|
82
|
-
|
83
|
-
|
84
|
-
f =~ /thumbnail/
|
85
|
-
}.reject{|f|
|
86
|
-
begin
|
87
|
-
EXIFR::JPEG.new(f).date_time
|
88
|
-
false
|
89
|
-
rescue
|
90
|
-
true
|
91
|
-
end
|
92
|
-
}.sort_by{|f|
|
93
|
-
# sort by exif date
|
94
|
-
EXIFR::JPEG.new(f).date_time || Time.parse('3000-01-01')
|
95
|
-
}.collect do |f|
|
96
|
-
image_fullsize = generate_image(f)
|
85
|
+
image_paths.collect do |f|
|
86
|
+
image_fullsize = generate_fullsize(f)
|
97
87
|
image_thumbnail = generate_thumbnail(f)
|
98
|
-
|
99
88
|
even = (ticker % 2 == 0) ? 'image-even' : 'image-odd'
|
100
89
|
third = (ticker % 3 == 0) ? 'image-third' : ''
|
101
90
|
fourth = (ticker % 4 == 0) ? 'image-fourth' : ''
|
@@ -111,6 +100,23 @@ class Gallerize
|
|
111
100
|
end
|
112
101
|
end
|
113
102
|
|
103
|
+
def image_paths
|
104
|
+
@image_paths ||= Dir.glob("*.{#{config.image_types}}").reject{|f|
|
105
|
+
# reject thumbnails
|
106
|
+
f =~ /thumbnail/
|
107
|
+
}.reject{|f|
|
108
|
+
begin
|
109
|
+
EXIFR::JPEG.new(f).date_time
|
110
|
+
false
|
111
|
+
rescue
|
112
|
+
true
|
113
|
+
end
|
114
|
+
}.sort_by{|f|
|
115
|
+
# sort by exif date
|
116
|
+
EXIFR::JPEG.new(f).date_time || Time.parse('3000-01-01')
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
114
120
|
def body
|
115
121
|
%Q{
|
116
122
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
@@ -163,11 +169,11 @@ class Gallerize
|
|
163
169
|
end
|
164
170
|
|
165
171
|
def per_page
|
166
|
-
|
172
|
+
config.per_page
|
167
173
|
end
|
168
174
|
|
169
175
|
def tracking_js
|
170
|
-
return if
|
176
|
+
return if config.tracking.blank?
|
171
177
|
%Q{
|
172
178
|
<script>
|
173
179
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
@@ -175,51 +181,52 @@ class Gallerize
|
|
175
181
|
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
176
182
|
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
177
183
|
|
178
|
-
ga('create', '#{
|
184
|
+
ga('create', '#{config.tracking}', 'auto');
|
179
185
|
ga('send', 'pageview');
|
180
186
|
|
181
187
|
</script>
|
182
188
|
}
|
183
189
|
end
|
184
190
|
|
185
|
-
def
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
puts "generate_image #{CONFIG['image_width']}x#{CONFIG['image_height']} #{image_output}"
|
191
|
-
image = MiniMagick::Image.open(image_path)
|
192
|
-
image.auto_orient
|
193
|
-
width,height = image['width'],image['height']
|
194
|
-
if width > height
|
195
|
-
image.resize "#{CONFIG['image_width']}x#{CONFIG['image_height']}"
|
196
|
-
else
|
197
|
-
image.resize "#{CONFIG['image_height']}x#{CONFIG['image_width']}"
|
198
|
-
end
|
199
|
-
image.write image_output
|
200
|
-
end
|
201
|
-
image_output.gsub(output_dir, '')
|
191
|
+
def generate_fullsize(source_path)
|
192
|
+
image = extract_image_extension(source_path)
|
193
|
+
output_path = File.join(output_dir.images, "#{image[:basename]}.#{image[:extension]}")
|
194
|
+
# generate the thumbnail
|
195
|
+
generate_image(source_path, output_path, config.image_width, config.image_height)
|
202
196
|
end
|
203
197
|
|
204
|
-
def generate_thumbnail(
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
198
|
+
def generate_thumbnail(source_path)
|
199
|
+
image = extract_image_extension(source_path)
|
200
|
+
output_path = File.join(output_dir.images, "#{image[:basename]}-thumbnail.#{image[:extension]}")
|
201
|
+
# generate the thumbnail
|
202
|
+
generate_image(source_path, output_path, config.thumb_width, config.thumb_height)
|
203
|
+
end
|
204
|
+
|
205
|
+
def generate_image(source_path, output_path, width, height)
|
206
|
+
# ensure correct types
|
207
|
+
width, height = width.to_i, height.to_i
|
208
|
+
# skip if image exists
|
209
|
+
unless File.exists?(output_path)
|
210
|
+
puts "generate_image #{File.basename(source_path)} #{File.basename(output_path)} #{width} #{height}"
|
211
|
+
image = MiniMagick::Image.open(source_path)
|
213
212
|
image.auto_orient
|
214
|
-
|
215
|
-
if width > height
|
216
|
-
image.resize "#{
|
213
|
+
# landscape?
|
214
|
+
if image['width'] > image['height']
|
215
|
+
image.resize "#{width}x#{height}"
|
217
216
|
else
|
218
|
-
image.resize "#{
|
217
|
+
image.resize "#{height}x#{width.to_i * 1.25}"
|
219
218
|
end
|
220
|
-
image.write
|
219
|
+
image.write output_path
|
221
220
|
end
|
222
|
-
|
221
|
+
# strip the output_dir.root from the path so that the returned path is relative
|
222
|
+
output_path.gsub( output_dir.root, '' )
|
223
|
+
end
|
224
|
+
|
225
|
+
def extract_image_extension(image_path)
|
226
|
+
basename = image_path.split(".")
|
227
|
+
extension = basename.pop.downcase
|
228
|
+
basename = basename.join('.')
|
229
|
+
return { basename: basename, extension: extension }
|
223
230
|
end
|
224
231
|
|
225
232
|
def title
|
@@ -227,27 +234,80 @@ class Gallerize
|
|
227
234
|
end
|
228
235
|
|
229
236
|
def output_dir
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
end
|
236
|
-
|
237
|
-
def
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
237
|
+
@output_dir ||= OutputDir.new( config.output_name )
|
238
|
+
end
|
239
|
+
|
240
|
+
def config
|
241
|
+
@config ||= load_config
|
242
|
+
end
|
243
|
+
|
244
|
+
def load_config
|
245
|
+
config = {}
|
246
|
+
# load config from output directory if present
|
247
|
+
config = YAML.load( File.read( source_dir.config ) ) if source_dir.config?
|
248
|
+
# generate global config from example if missing
|
249
|
+
global_config = File.join(ROOT,'config/global.yml')
|
250
|
+
FileUtils.cp( "#{global_config}.example", global_config ) unless File.exists?( global_config )
|
251
|
+
# load global_config and merge with source config
|
252
|
+
OpenStruct.new(YAML.load(File.read(global_config)).merge(config))
|
253
|
+
end
|
254
|
+
|
255
|
+
def source_dir
|
256
|
+
@source_dir ||= SourceDir.new
|
257
|
+
end
|
258
|
+
|
259
|
+
class SourceDir
|
260
|
+
|
261
|
+
def config?
|
262
|
+
File.exists?(config)
|
250
263
|
end
|
264
|
+
|
265
|
+
def config
|
266
|
+
File.join( root, '.gallerize')
|
267
|
+
end
|
268
|
+
|
269
|
+
def root
|
270
|
+
@root ||= File.expand_path('.')
|
271
|
+
end
|
272
|
+
|
273
|
+
end
|
274
|
+
|
275
|
+
class OutputDir
|
276
|
+
|
277
|
+
attr_accessor :root
|
278
|
+
|
279
|
+
def initialize(path)
|
280
|
+
self.root = path
|
281
|
+
end
|
282
|
+
|
283
|
+
def root=(value)
|
284
|
+
@root = File.join( File.expand_path('.'), (value || 'gallerize') )
|
285
|
+
end
|
286
|
+
|
287
|
+
def html_file(name)
|
288
|
+
name = name.to_s
|
289
|
+
name = "#{name}.html" unless name =~ /\.html/
|
290
|
+
File.join(root, name)
|
291
|
+
end
|
292
|
+
|
293
|
+
def images
|
294
|
+
File.join( root, 'images' )
|
295
|
+
end
|
296
|
+
|
297
|
+
def html_files
|
298
|
+
File.join( root, '*.html')
|
299
|
+
end
|
300
|
+
|
301
|
+
def copy_from_gem_source(*folders)
|
302
|
+
folders.each do |folder|
|
303
|
+
outdir = File.join( root, folder )
|
304
|
+
puts "copy ./#{folder} #{outdir}"
|
305
|
+
FileUtils.rm_rf( outdir )
|
306
|
+
FileUtils.cp_r( File.join( ROOT, folder ), outdir )
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
|
251
311
|
end
|
252
312
|
|
253
313
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gallerize-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Blake Hilscher
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mini_magick
|