gallerize-cli 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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