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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b51bfcfc0d4acd441ddc56c58903df3f57cc28b2
4
- data.tar.gz: 8c433292f6b43525884823a02ee1dcb16a19ed09
3
+ metadata.gz: fc69d889c2a6a376cc872a33e4b6bd60637a49a7
4
+ data.tar.gz: b3d1c67446924666c5d0bafe39e52dbadc04f08a
5
5
  SHA512:
6
- metadata.gz: 63b1c6a27417b1527b9e94b8e6101cb7107cbff9b9e3ed160b286890f15fd1c95e75c89783d07f35bc8768801d3852fcaf0f8e5df4a7f75f01890950398b4016
7
- data.tar.gz: 19561f6e1deb571d0e742b021f2f2f77ad17d8144bf2676def3db701effd9cda00d7b7cc0d9193ae60c3f3b788e984eb942c96922ac5c481190b05104ec70692
6
+ metadata.gz: e9f3ee1e12f19706935e26052da9d640e479864154d6957547975c20f7d97082e3f0c847a62be699e04860ee22f141875ee73e35dd06cf53d26f2d07721efdbb
7
+ data.tar.gz: 805f18c473d8c70de3c8053729581a153d9ae347d8fe33d2cde9f22f095443c5ae2452460afb6ba14b0b09fda586139b946fada42098f1f1d91b6cc9097215cf
data/README.md CHANGED
@@ -1,52 +1,35 @@
1
- ### Overview
1
+ ### Example
2
+
3
+ http://examples.hilscher.ca/gallerize/
2
4
 
3
- Generate a static gallery from a folder of images.
4
5
 
5
- **Highlights**
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
- git clone https://github.com/blakehilscher/static-gallery-generator.git
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
- ln -sf "$(pwd)/bin/gallerize" $HOME/bin/gallerize
24
+ $ cd folder-with-pictures
25
+ $ gallerize
26
+ $ open gallerize/index.html
44
27
  ```
45
28
 
46
29
 
47
30
  ### Configuration
48
31
 
49
- * configure in config/global.yml
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 | 1200 | The thumbnail image width |
59
- | thumb_height | required | 800 | The thumbnail image height |
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
 
@@ -6,4 +6,4 @@ image_width: 1200
6
6
  image_height: 800
7
7
  thumb_width: 400
8
8
  thumb_height: 300
9
- output_name: static-gallery
9
+ output_name: gallerize
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
- VERSION='0.1.1'
14
+ attr_accessor :image_paths
14
15
 
15
- if File.exists?(File.join(File.expand_path('.'), '.gallerize.yml'))
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 Dir.glob("*.{#{IMAGE_TYPES}}").reject{|f| f =~ /thumbnail/ }.blank?
38
- puts "no images found in #{File.expand_path('.')} matching #{IMAGE_TYPES}"
23
+ if image_paths.blank?
24
+ puts "no images found in #{source_dir.root} matching #{config.image_types}"
39
25
  else
40
- reset
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, File.join(output_dir, 'index.html'))
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
- Parallel.map( Dir.glob("*.{#{IMAGE_TYPES}}").reject{|f| f =~ /thumbnail/ }, in_processes: WORKERS ) do |f|
54
- generate_image(f)
55
- generate_thumbnail(f)
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
- <div class="navigation">
65
- #{navigation}
66
- </div>
71
+ #{navigation}
67
72
  <div id="images-container" class="images">
68
73
  #{some_images.join("\n")}
69
74
  </div>
70
- <div class="navigation">
71
- #{navigation}
72
- </div>
75
+ #{navigation}
73
76
  #{footer}
74
77
  }
75
- name ||= File.join( output_dir, "images-#{ticker}.html" )
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
- @images ||= Dir.glob("*.{#{IMAGE_TYPES}}").reject{|f|
83
- # reject thumbnails
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
- PER_PAGE
172
+ config.per_page
167
173
  end
168
174
 
169
175
  def tracking_js
170
- return if TRACKING == ''
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', '#{TRACKING}', 'auto');
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 generate_image(image_path)
186
-
187
- image_output = File.join(output_dir, 'images', image_path.downcase)
188
-
189
- unless File.exists?(image_output)
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(f)
205
- image_basename = f.downcase.split(".")
206
- image_ext = image_basename.pop
207
- image_basename = image_basename.join('.')
208
- image_thumbnail = File.join(output_dir, 'images', "#{image_basename}-thumbnail.#{image_ext}")
209
-
210
- unless File.exists?(image_thumbnail)
211
- puts "generate_thumbnail #{CONFIG['thumb_width']}x#{CONFIG['thumb_height']} #{image_thumbnail}"
212
- image = MiniMagick::Image.open(f)
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
- width,height = image['width'],image['height']
215
- if width > height
216
- image.resize "#{CONFIG['thumb_width']}x#{CONFIG['thumb_height']}"
213
+ # landscape?
214
+ if image['width'] > image['height']
215
+ image.resize "#{width}x#{height}"
217
216
  else
218
- image.resize "#{CONFIG['thumb_height']}x#{CONFIG['thumb_width'].to_i * 1.25}"
217
+ image.resize "#{height}x#{width.to_i * 1.25}"
219
218
  end
220
- image.write image_thumbnail
219
+ image.write output_path
221
220
  end
222
- image_thumbnail.gsub(output_dir, '')
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
- return CONFIG['output_name'] if CONFIG['output_name'].present?
231
- dir = File.basename(File.expand_path('.'))
232
- dir = "#{Date.today.strftime('%Y-%m')}-#{dir}" unless dir =~ /^[0-9]{4}/
233
- dir = dir.downcase.underscore.gsub('_','-')
234
- dir
235
- end
236
-
237
- def reset
238
- Dir.glob(File.join(output_dir, '*.html')){|f| FileUtils.rm(f) }
239
- FileUtils.mkdir(output_dir) unless File.exists?(output_dir)
240
- FileUtils.mkdir(File.join(output_dir,'images')) unless File.exists?(File.join(output_dir,'images'))
241
- copy('css', 'js')
242
- end
243
-
244
- def copy(*folders)
245
- folders.each do |folder|
246
- outdir = File.join( output_dir, folder )
247
- puts "copy #{File.join( ROOT, folder )} #{outdir}"
248
- FileUtils.rm_rf( outdir )
249
- FileUtils.cp_r( File.join( ROOT, folder ), outdir )
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.1.1
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-16 00:00:00.000000000 Z
11
+ date: 2014-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mini_magick