piccle 0.1.0.rc1 → 0.1.1.pre

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
  SHA256:
3
- metadata.gz: db3f8798e1dfc0e62bf41b3cdda06bd2f9b55f2331cdf43355734d64b62b2a71
4
- data.tar.gz: af3016c01de9d25f078369ea6c0c83865bae176c08230009097fca586792505e
3
+ metadata.gz: 81cf1f58e254874d67a158e428edc3c308557bdcaa1f890c845c1a579faac74d
4
+ data.tar.gz: '04148646454d3b3b5b882fa56c8a0f563dd8e6fc311316e20f63e3170998264d'
5
5
  SHA512:
6
- metadata.gz: ea4bac152db471cf72aaaab4df57779d6fb756657581e4cc86fa425e29d0627793c0d6dde08c4f88a9b593afeed75e65a28792f034ac4846003d9ba4eda8a5f9
7
- data.tar.gz: 4cbc517e96ab3b3a49cd7100ad515f3334a9a097bccb7ae10f559e8bc8fdd8b2b8b7a49bdf799167876381c76bac7a2edb2046ba9a29fec6e23fccead6e03ca4
6
+ metadata.gz: 7ea526664d305b466eaa894817ebc5066391e6d24c51b4287227a7b12a2b7189c96875e572bd900df38ac6d08a26f9898996e0000daba5e92016dbca0bd489fb
7
+ data.tar.gz: 90d41a1d0d0517b56fe945d672213edf662b59daa5ea864cfebb07e8d0604bc3b13c068ed08571ed7f86be1ec22700d9e3960bf5f57b106bd2dff513e3db30dd
File without changes
data/NOTES.md CHANGED
@@ -2,44 +2,38 @@
2
2
 
3
3
  ## Roadmap
4
4
 
5
- v0.1
6
- - Test it works on other computers
7
- - Better iPad display
8
- - Update readme
9
-
10
5
  v0.2
11
- - Paginated indexes
12
6
  - Render subnav (ie. if you're in 2020 view, it'll show the months)
13
- - People browser
14
7
  - Show most recently added photos
15
8
 
16
9
  v0.3
17
10
  - Track hash changes, generate redirects and htaccess file
18
- - Collapsible events on the front page (maybe)
19
11
  - Better display of streams on photo show page
20
12
 
21
13
  v0.4
22
14
  - Client-side rendering
23
15
 
16
+ v0.5
17
+ - Section browse pages
18
+
24
19
 
25
20
  ## Bugs
26
21
  - Don't fail horribly if there are no images.
27
22
  - More useful error output if the given images directory does not exist.
23
+ - Figure out timezones around collapsed events
28
24
 
29
25
 
30
26
  ## Improvements
31
27
 
28
+ - Add "section browse" pages?
29
+ - Collapse "collapsed" sections everywhere, EXCEPT that particular stream.
32
30
  - Add ordering to all the various substreams. Almost done, apart from sorting days and months in the datestream.
33
- - Update the photo update method so it also REMOVES keywords from files.
34
- - Store changed MD5 hashes, generate redirect pages for those.
31
+ - Store changed MD5 hashes, generate redirect pages for those.
35
32
  - Add a cleanup function that removes old images/HTML.
36
- - Make keywords case insensitive.
37
- - Write a readme.
38
- - Add "collapsed" view for events so they show up in one tile.
39
- - Add links to event tiles that link to the event page.
40
33
  - Can we detect fixed focal length cameras in the metadata?
41
34
  - Maybe combine substream path with include prefix? So we don't have to do two {{foo}}{{bar}} on every link.
42
35
  - Put current stream first on photo page
36
+ - Generally improve the stream display on photo page. Filter out samey streams, maybe only show a maximum of 4?
43
37
  - Update nav to render subnav too, for current section.
44
38
  - Finish commenting the BaseStream.
45
39
 
@@ -52,14 +46,11 @@ v0.4
52
46
  ----- All the notes below are kind of outdated ------
53
47
 
54
48
  - JS slideshow at the top of the index page??
55
- - Convert database.rake tasks over to the Sequel way of doing things
56
49
  - Our current find-or-create for photos relates to the file name/path. It should probably use that, and/or the MD5.
57
50
  - Focal length is currently available as a fraction in the EXIF, but we're storing it as a float. Maybe we'd like to store it as a fraction instead?
58
51
 
59
52
  # Development notes
60
53
 
61
- - The EXIF tag calls the camera model "model", but in the DB schema we called it "camera_name". We might want to unify this.
62
- - NB. Sequel will throw a wobbly if we use "model" as a method name.
63
54
  - Add a meaningful "alt" tag in the photo thumbnail.
64
55
 
65
56
  - Streams should maybe be able to generate "top-level" pages, so we could have paths like "example.com/2008" rather than "example.com/by-date/2008".
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ ![Piccle logo](https://github.com/creature/piccle/blob/master/assets/icons/android-chrome-192x192.png?raw=true)
2
+
1
3
  # Piccle
2
4
 
3
5
  Piccle is a static photo gallery generator. Purposefully designed with no admin interface, it builds the gallery from
@@ -17,10 +19,24 @@ though these are unlikely to be added unless you set them up first.
17
19
 
18
20
  ## Getting started
19
21
 
22
+ ### Quickstart
23
+
24
+ ```bash
25
+ gem install piccle --pre
26
+ piccle generate -i path/to/your/image/dir # Produces a site in generated/
27
+ piccle help # To see more options
28
+ ```
29
+
30
+ ### Installing Piccle
31
+
20
32
  Piccle requires a modern(ish) version of Ruby. If you don't have one already, then I like [rbenv](https://github.com/rbenv/rbenv#readme)
21
33
  as a Ruby version manager.
22
34
 
23
- 1. Run `gem install piccle` to install the software.
35
+ The default renderer relies on [NodeJS](https://nodejs.org/en/) being available in your `$PATH`. If this isn't possible
36
+ for you, you can run Piccle with `--ruby-renderer` – but this is typically 10 times slower.
37
+
38
+
39
+ 1. Run `gem install piccle --pre` to install the software.
24
40
  1. Piccle can run from anywhere, but things will be easier if you created a dedicated directory for it:
25
41
  ```bash
26
42
  mkdir -p piccle/images
@@ -37,6 +53,8 @@ as a Ruby version manager.
37
53
  open `generated/index.html` in your browser.
38
54
  1. You're done!
39
55
 
56
+ ## Available Options
57
+
40
58
  Piccle has two subcommands, `generate` and `geocode`. `generate` is the default task and is the same as running
41
59
  without specifying a subcommand. `geocode` uses the Data Science Toolkit to look up locations in the database.
42
60
  `piccle help generate` will display the various options:
@@ -54,6 +72,8 @@ without specifying a subcommand. `geocode` uses the Data Science Toolkit to look
54
72
  (so people can subscribe to updates) and OpenGraph tags (which give nice embeds on social media) require a full URL.
55
73
  They won't be generated if this is not set.
56
74
  * `--debug` turns on debug mode, which adds some extra logging.
75
+ * `--ruby-renderer` uses a rendering engine that does not require your system to have NodeJS installed (instead, it
76
+ uses a [wrapper for libv8](https://github.com/rubyjs/therubyracer)). The output is the same, but it's much slower.
57
77
 
58
78
 
59
79
  ## Metadata Used
@@ -64,6 +84,33 @@ without specifying a subcommand. `geocode` uses the Data Science Toolkit to look
64
84
  * **Keywords** are shown, and exposed as "topics".
65
85
  * **Location** is shown. If your photos have a city/state/country specified in their data, then that's used; otherwise,
66
86
  Piccle will attempt to geocode them based on embedded latitude/longitude.
87
+ * **People** are browsable, based on the "Person Shown" IPTC field.
88
+
89
+
90
+ ## Events
91
+
92
+ Piccle allows you to create named events in a separate [YAML file](https://learnxinyminutes.com/docs/yaml/). Each event
93
+ gets a dedicated index page, and a callout on the main index. It's useful for highlighting pictures from a particular
94
+ photoshoot, or drawing attention to a trip.
95
+
96
+ Events must have a name, and must either be `at` a particular date or within a particular date span (`from` and `to`).
97
+ Events may also be marked as `collapsed`; collapsed events don't show all their photos on an index page. Instead, they
98
+ show a quilt tile with some of the photos. It's a good way to avoid flooding your front page with a lot of
99
+ similar-looking photos.
100
+
101
+ This `events.yaml` file defines two events: a photoshoot I did themed around googly eyes, and a trip to the UK in 2019.
102
+ (The example shows dates only, but you can include times too.)
103
+
104
+ ```yaml
105
+ -
106
+ name: Googly Eyes
107
+ at: 2019-03-23
108
+ collapsed: true
109
+ -
110
+ name: UK 2019
111
+ from: 2019-01-24
112
+ to: 2019-02-09
113
+ ```
67
114
 
68
115
  -------
69
116
 
@@ -71,8 +118,9 @@ without specifying a subcommand. `geocode` uses the Data Science Toolkit to look
71
118
 
72
119
  Geolocation is provided by the free [Data Science Toolkit API](http://www.datasciencetoolkit.org/developerdocs#coordinates2politics).
73
120
  The test images are public domain images by [Sasin Tipchai](https://pixabay.com/photos/elephant-animals-asia-large-1822636/),
74
- [Timo Schlüter](https://pixabay.com/photos/kingfisher-bird-blue-plumage-1905255/), and
75
- [Jill Wellington](https://pixabay.com/photos/spring-bird-bird-spring-blue-2295431/).
121
+ [Timo Schlüter](https://pixabay.com/photos/kingfisher-bird-blue-plumage-1905255/),
122
+ [Jill Wellington](https://pixabay.com/photos/spring-bird-bird-spring-blue-2295431/), and
123
+ [Pascal Vannevel](https://pixabay.com/photos/usa-canyonlands-mesa-arch-natuur-5009894/).
76
124
 
77
125
 
78
126
  ## License
@@ -96,37 +144,37 @@ tool for managing metadata yet, but here are some options:
96
144
  ### Adobe Bridge
97
145
 
98
146
  Pros
99
- : Available for free, without a paid Creative Cloud subscription
100
- : Lets you build a library of keywords, with a nested heirarchy, so it's easier to use a set of standard tags with your photos
101
- : Can [edit titles, descriptions, and locations](https://helpx.adobe.com/ca/bridge/using/metadata-adobe-bridge.html)
102
- : Good filtering support: it's easy to find pictures lacking metadata
147
+ - Available for free, without a paid Creative Cloud subscription
148
+ - Lets you build a library of keywords, with a nested heirarchy, so it's easier to use a set of standard tags with your photos
149
+ - Can [edit titles, descriptions, and locations](https://helpx.adobe.com/ca/bridge/using/metadata-adobe-bridge.html)
150
+ - Good filtering support: it's easy to find pictures lacking metadata
103
151
 
104
152
  Cons
105
- : You still need a Creative Cloud account to download it
106
- : You must install the Adobe Creative Cloud stuff to get Bridge
107
- : Can't place photos on a map for adding latitude/longitude.
153
+ - You still need a Creative Cloud account to download it
154
+ - You must install the Adobe Creative Cloud stuff to get Bridge
155
+ - Can't place photos on a map for adding latitude/longitude.
108
156
 
109
157
 
110
158
  ### macOS Preview
111
159
 
112
160
  Pros
113
- : If you use macOS you already have it
114
- : Access the inspector (⌘-I or File → Inspect) and choose the "Keywords" panel to add/remove keywords
161
+ - If you use macOS you already have it
162
+ - Access the inspector (⌘-I or File → Inspect) and choose the "Keywords" panel to add/remove keywords
115
163
 
116
164
  Cons
117
- : Can't edit title, description, or location
118
- : Can't build a library of tags
165
+ - Can't edit title, description, or location
166
+ - Can't build a library of tags
119
167
 
120
168
 
121
169
  ### Affinity Photo
122
170
 
123
171
  Pros
124
- : Lets you edit titles, descriptions, locations, keywords, and add latitude/longitude via a map
125
- : Is generally a delightful image editor
172
+ - Lets you edit titles, descriptions, locations, keywords, and add latitude/longitude via a map
173
+ - Is generally a delightful image editor
126
174
 
127
175
  Cons
128
- : Longwinded for bulk edits: open photo, switch to Develop mode, change to metadata tab, switch between "File" and "IPTC (Image)" sections
129
- : No tag library - you must type in a comma-separated string
176
+ - Longwinded for bulk edits: open photo, switch to Develop mode, change to metadata tab, switch between "File" and "IPTC (Image)" sections
177
+ - No tag library - you must type in a comma-separated string
130
178
 
131
179
 
132
180
  ## Automation
@@ -10,22 +10,6 @@ a {
10
10
  color: #7b6240;
11
11
  }
12
12
 
13
- ul li a {
14
- transition: opacity ease-in 0.22s;
15
- color: #444444;
16
- text-decoration: none;
17
- }
18
-
19
- ul:hover a {
20
- opacity: 0.5;
21
- }
22
-
23
- ul:hover a:hover {
24
- opacity: 1;
25
- text-decoration: underline;
26
- }
27
-
28
-
29
13
  header, footer {
30
14
  max-width: 960px;
31
15
  margin-right: auto;
@@ -110,12 +94,27 @@ nav li a {
110
94
  display: block;
111
95
  }
112
96
 
97
+ nav ul li a {
98
+ transition: opacity ease-in 0.22s;
99
+ color: #444444;
100
+ text-decoration: none;
101
+ }
102
+
103
+ nav ul:hover a {
104
+ opacity: 0.5;
105
+ }
106
+
107
+ nav ul:hover a:hover {
108
+ opacity: 1;
109
+ text-decoration: underline;
110
+ }
111
+
113
112
  section h2 {
114
113
  font-size: 1em;
115
114
  }
116
115
 
117
116
  /* This is both a flexbox item (of the main element) and a Flexbox container itself (for the photos). */
118
- .photos {
117
+ #photos {
119
118
  flex: auto;
120
119
  display: grid;
121
120
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
@@ -123,7 +122,7 @@ section h2 {
123
122
  align-content: start;
124
123
  }
125
124
 
126
- .photos a img {
125
+ #photos a img {
127
126
  width: 100%;
128
127
  height: auto;
129
128
  }
@@ -143,9 +142,16 @@ section h2 {
143
142
  overflow: hidden;
144
143
  }
145
144
 
145
+ .event_block:hover a {
146
+ color: #fff;
147
+ text-decoration: underline;
148
+ }
149
+
150
+
146
151
  .event_block a {
147
152
  color: #ddd;
148
153
  text-decoration: none;
154
+ transition: all 0.22s;
149
155
  }
150
156
 
151
157
  .event_block.event_start {
@@ -166,6 +172,33 @@ section h2 {
166
172
  padding-left: 1rem;
167
173
  }
168
174
 
175
+ .event_block.collapsed {
176
+ background-size: cover;
177
+ }
178
+
179
+ .event_block.collapsed a {
180
+ -webkit-backdrop-filter: blur(5px) contrast(40%);
181
+ backdrop-filter: blur(5px);
182
+ border-radius: 5px;
183
+ padding: 1rem;
184
+ }
185
+
186
+ .pagination {
187
+ display: flex;
188
+ margin: 2rem;
189
+ justify-content: center;
190
+ }
191
+
192
+ .pagination ol {
193
+ list-style-type: none;
194
+ margin: 0 1rem;
195
+ padding: 0;
196
+ }
197
+
198
+ .pagination ol li {
199
+ display: inline-block;
200
+ }
201
+
169
202
  .keywords {
170
203
  margin: 72px 72px 18px;
171
204
  line-height: 2;
@@ -300,6 +333,7 @@ ul.location li:last-of-type:after {
300
333
  object-fit: contain;
301
334
  min-width: 0;
302
335
  max-width: 100%;
336
+ max-height: 100vh;
303
337
  }
304
338
 
305
339
  /* --------- Mobile styles ---------- */
@@ -363,10 +397,18 @@ ul.location li:last-of-type:after {
363
397
  width: 50%;
364
398
  }
365
399
 
366
- .photos {
400
+ #photos {
367
401
  grid-template-columns: repeat(3, 1fr);
368
402
  }
369
403
 
404
+ .pagination {
405
+ justify-content: space-evenly;
406
+ }
407
+
408
+ .pagination ol { /* No page numbers on tiny displays, just next/previous */
409
+ display: none;
410
+ }
411
+
370
412
  .event_block {
371
413
  font-size: 18px;
372
414
  }
@@ -393,5 +435,31 @@ ul.location li:last-of-type:after {
393
435
  margin-left: 1rem;
394
436
  margin-right: 1rem;
395
437
  }
438
+ }
439
+
440
+ /* Smaller margins on smallish displays (like iPads) */
441
+ @media(min-width: 689px) and (max-width: 1024px) {
442
+ body {
443
+ margin: 0 30px;
444
+ }
445
+
446
+ nav {
447
+ margin-right: 15px;
448
+ max-width: 150px;
449
+ }
450
+ }
451
+
452
+ /* More room for pages on smallish screens (ie. phones or tablets, probably) */
453
+ @media(max-width: 1024px) {
454
+ .pagination {
455
+ justify-content: space-between;
456
+ }
457
+
458
+ .pagination ol li {
459
+ margin-right: 1rem;
460
+ }
396
461
 
462
+ .pagination ol li:last-child {
463
+ margin-right: 0;
464
+ }
397
465
  }
data/bin/piccle CHANGED
@@ -163,6 +163,9 @@ class CLI < Thor
163
163
  start_time = Time.now
164
164
  puts "Generating website..."
165
165
 
166
+ FileUtils.mkdir_p(Piccle.config.output_dir)
167
+ generate_templates
168
+
166
169
  parser = new_parser_with_streams
167
170
  parse_photos(parser)
168
171
  renderer = if Piccle.config.ruby_renderer?
@@ -171,8 +174,6 @@ class CLI < Thor
171
174
  Piccle::JsRenderer.new(parser)
172
175
  end
173
176
 
174
- FileUtils.mkdir_p(Piccle.config.output_dir)
175
- generate_templates(renderer)
176
177
  generate_atom_feeds(parser, renderer)
177
178
  generate_html_indexes(parser, renderer)
178
179
  generate_html_photos(parser, renderer)
@@ -190,6 +191,7 @@ class CLI < Thor
190
191
  p.add_stream(Piccle::Streams::LocationStream)
191
192
  p.add_stream(Piccle::Streams::EventStream)
192
193
  p.add_stream(Piccle::Streams::CameraStream)
194
+ p.add_stream(Piccle::Streams::PersonStream)
193
195
  p.add_stream(Piccle::Streams::KeywordStream)
194
196
  end
195
197
  end
@@ -206,16 +208,24 @@ class CLI < Thor
206
208
  # Given a parser object, generate some HTML index pages from the data it contains.
207
209
  def generate_html_indexes(parser, renderer)
208
210
  puts " ... generating HTML indexes ..."
209
- print " ... generating main index ... "
210
- File.write(File.join(Piccle.config.output_dir, "index.html"), renderer.render_main_index)
211
+ print " ... generating main index "
212
+ paginated_main_index = renderer.render_main_index
213
+ print "(#{paginated_main_index.count} page(s)) ... "
214
+ paginated_main_index.each_with_index do |page, index|
215
+ File.write(File.join(Piccle.config.output_dir, "#{renderer.index_page_name_for(index)}.html"), page)
216
+ end
211
217
  puts "Done."
212
218
 
213
219
  parser.subsections.each do |subsection|
214
220
  if parser.subsection_photo_hashes(subsection).any?
215
221
  subdir = File.join(Piccle.config.output_dir, *subsection)
216
- print " ... generating #{subdir} index ... "
222
+ print " ... generating #{subdir} index "
217
223
  FileUtils.mkdir_p(subdir)
218
- File.write(File.join(subdir, "index.html"), renderer.render_index(subsection))
224
+ paginated_subsection_index = renderer.render_index(subsection)
225
+ print "(#{paginated_subsection_index.count} page(s)) ... "
226
+ paginated_subsection_index.each_with_index do |page, index|
227
+ File.write(File.join(subdir, "#{renderer.index_page_name_for(index)}.html"), page)
228
+ end
219
229
  puts "Done."
220
230
  end
221
231
  end
@@ -295,6 +305,10 @@ class CLI < Thor
295
305
  # Generates "quilts" - stitched together images for each section, which we use in OpenGraph tags.
296
306
  def generate_quilts(parser)
297
307
  puts "Generating gallery quilts (preview images for sharing galleries on social media)..."
308
+ unless Piccle.config.open_graph?
309
+ puts " Not generating most quilts, because no home URL is set."
310
+ end
311
+
298
312
  if Piccle.config.open_graph?
299
313
  thumbnail_path_proc = Proc.new { |k, v| File.join(Piccle.config.output_dir, "images", "thumbnails", "#{v[:hash]}.#{v[:file_name]}") }
300
314
 
@@ -303,23 +317,22 @@ class CLI < Thor
303
317
  main_quilt = Piccle::QuiltGenerator.generate_for(main_thumbnails)
304
318
  main_quilt.write(File.join(Piccle.config.output_dir, "quilt.jpg"))
305
319
  puts " Done."
320
+ end
306
321
 
307
- parser.subsections.each do |subsection|
308
- thumbnails = parser.subsection_photos(subsection).map(&thumbnail_path_proc)
309
- if thumbnails.any?
310
- output_path = File.join(Piccle.config.output_dir, *subsection, "quilt.jpg")
311
- print " ... Creating gallery quilt #{output_path}..."
312
- quilt = Piccle::QuiltGenerator.generate_for(thumbnails.first(9))
313
- quilt.write(output_path)
314
- puts " Done."
315
- end
322
+ parser.subsections.each do |subsection|
323
+ thumbnails = parser.subsection_photos(subsection).map(&thumbnail_path_proc)
324
+ # All sections get quilts if we're rendering OpenGraph tags; otherwise just collapsed sections.
325
+ if thumbnails.any? && (Piccle.config.open_graph? || parser.subsection_collapsed?(subsection))
326
+ output_path = File.join(Piccle.config.output_dir, *subsection, "quilt.jpg")
327
+ print " ... Creating gallery quilt #{output_path}..."
328
+ quilt = Piccle::QuiltGenerator.generate_for(thumbnails.first(9))
329
+ quilt.write(output_path)
330
+ puts " Done."
316
331
  end
317
- else
318
- puts " Not generating gallery quilt images, because no home URL is set."
319
332
  end
320
333
  end
321
334
 
322
- def generate_templates(_renderer)
335
+ def generate_templates
323
336
  puts " ... generating templates..."
324
337
  FileUtils.mkdir_p(File.join(Piccle.config.output_dir, "js"))
325
338
  File.write(File.join(Piccle.config.output_dir, "js", "index.handlebars"), Piccle::TemplateHelpers.compile_template("index"))