jekyll-flickr-utils 0.1.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 +7 -0
- data/LICENSE +21 -0
- data/lib/flickr_downloader.rb +172 -0
- data/lib/jekyll-flickr-utils.rb +5 -0
- data/lib/post_image.rb +92 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5ecf9cfe481ab49cbdbe3cdda762544467f75be8b88f548fa4504953e804067e
|
4
|
+
data.tar.gz: 258a913fb9833ad2d12608860f6b3a9d0e4a542ca4c3f04b198223aae824a9c6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d23949729a14f7375428dc8d9731f0adee3f8b88e98743abaf6eddd8d488af3ddf8309773163bfcfd9484172cf282eb1a45032e0d086ef6f41496f53500a1d6d
|
7
|
+
data.tar.gz: 39eb671a361ab019ffe80b50f50caeff39b58f41ec2759c5f31280406e4f304abcfb8665d51a58acd22d853cef0c5e11ae92a5832a456f0d631bb67c82d90cd7
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014-present Alfred Xing and the jekyll-archives contributors
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'down'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'flickr'
|
7
|
+
require 'jekyll'
|
8
|
+
require 'open-uri'
|
9
|
+
require 'sorbet-runtime'
|
10
|
+
require 'yaml'
|
11
|
+
|
12
|
+
module FlickrDownloader
|
13
|
+
class Generator < Jekyll::Generator
|
14
|
+
extend T::Sig
|
15
|
+
|
16
|
+
LOG_TOPIC = 'Flickr Downloader:'
|
17
|
+
JEKYLL_ROOT = T.let(Jekyll.configuration.source({}), String)
|
18
|
+
MANIFEST_FILE_PATH = T.let("#{JEKYLL_ROOT}/_data/flickr_photosets.yaml", String)
|
19
|
+
|
20
|
+
ConfigType = T.type_alias { T::Hash[String, T.untyped] }
|
21
|
+
ManifestType = T.type_alias { T::Hash[String, T::Hash[String, String]] }
|
22
|
+
|
23
|
+
DEFAULTS = T.let(
|
24
|
+
{
|
25
|
+
'enabled' => false,
|
26
|
+
'image_root' => 'assets/images/flickr_photosets',
|
27
|
+
'force_refresh' => false,
|
28
|
+
'image_size' => 'url_k'
|
29
|
+
}.freeze,
|
30
|
+
ConfigType
|
31
|
+
)
|
32
|
+
|
33
|
+
sig { params(config: ConfigType).void }
|
34
|
+
def initialize(config = {})
|
35
|
+
super
|
36
|
+
|
37
|
+
@config = T.let(DEFAULTS.merge(config.fetch('flickr_downloader', {})), ConfigType)
|
38
|
+
|
39
|
+
@flickr = T.let(nil, T.nilable(Flickr))
|
40
|
+
|
41
|
+
return unless enabled?
|
42
|
+
|
43
|
+
@flickr = Flickr.new(@config['api_key'], @config['shared_secret'])
|
44
|
+
@flickr.access_token = @config['access_token']
|
45
|
+
@flickr.access_secret = @config['access_secret']
|
46
|
+
end
|
47
|
+
|
48
|
+
sig { returns(T::Boolean) }
|
49
|
+
def enabled?
|
50
|
+
@config['enabled']
|
51
|
+
end
|
52
|
+
|
53
|
+
sig { params(site: Jekyll::Site).void }
|
54
|
+
def generate(site)
|
55
|
+
unless enabled?
|
56
|
+
Jekyll.logger.warn(LOG_TOPIC, 'Plugin disabled via config!')
|
57
|
+
return
|
58
|
+
end
|
59
|
+
|
60
|
+
posts = site.posts.docs.select do |post|
|
61
|
+
!post.data.fetch('disable_flickr_download', false) && post.data.fetch('flickr_photoset_id', nil)
|
62
|
+
end
|
63
|
+
|
64
|
+
FileUtils.touch(MANIFEST_FILE_PATH) if posts && !File.exist?(MANIFEST_FILE_PATH)
|
65
|
+
|
66
|
+
posts.each do |post|
|
67
|
+
flickr_photoset_id = post.data['flickr_photoset_id']
|
68
|
+
|
69
|
+
if flickr_photoset_id.is_a?(Array)
|
70
|
+
flickr_photoset_id.each { |photoset_id| download_photoset(photoset_id.to_s, post) }
|
71
|
+
elsif flickr_photoset_id
|
72
|
+
download_photoset(flickr_photoset_id.to_s, post)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
sig { params(flickr_photoset_id: String).returns(T::Boolean) }
|
78
|
+
private def should_download?(flickr_photoset_id)
|
79
|
+
data = YAML.load_file(MANIFEST_FILE_PATH) || {}
|
80
|
+
# Ensure we treat the photoset ID as a String instead of an integer
|
81
|
+
data = data.transform_keys(&:to_s)
|
82
|
+
data.fetch(flickr_photoset_id, nil).nil? || @config['force_refresh']
|
83
|
+
end
|
84
|
+
|
85
|
+
sig { params(url: String, destination: String).void }
|
86
|
+
private def download_photo(url, destination)
|
87
|
+
Down.download(url, destination: "#{JEKYLL_ROOT}/#{destination}")
|
88
|
+
end
|
89
|
+
|
90
|
+
sig { params(manifest: ManifestType).void }
|
91
|
+
private def write_manifest_file(manifest)
|
92
|
+
data = YAML.load_file(MANIFEST_FILE_PATH) || {}
|
93
|
+
data = data.merge(manifest)
|
94
|
+
File.write(MANIFEST_FILE_PATH, YAML.dump(data))
|
95
|
+
end
|
96
|
+
|
97
|
+
sig { params(photoset_id: String, directory: String).returns(ManifestType) }
|
98
|
+
private def download_photoset_photos(photoset_id, directory)
|
99
|
+
directory = directory.chomp('/')
|
100
|
+
|
101
|
+
Jekyll.logger.info(LOG_TOPIC, "Downloading photos from Flickr photoset #{photoset_id} to #{directory}...")
|
102
|
+
|
103
|
+
image_size = @config['image_size']
|
104
|
+
# NOTE: Sorbet cannot find the dynamically-generated methods.
|
105
|
+
photoset = T.let(@flickr, T.untyped).photosets.getPhotos(
|
106
|
+
photoset_id: photoset_id,
|
107
|
+
extras: "description,url_o,#{image_size}"
|
108
|
+
)
|
109
|
+
|
110
|
+
manifest_images = {}
|
111
|
+
primary_photo_id = photoset.primary
|
112
|
+
primary_photo_filename = T.let(nil, T.nilable(String))
|
113
|
+
|
114
|
+
photoset.photo.each_with_index do |photo, index|
|
115
|
+
# NOTE: If the image is too small, Flickr may not have a URL matching the requested size.
|
116
|
+
# Fall back to the original size in such cases.
|
117
|
+
url = photo[image_size] || photo['url_o']
|
118
|
+
filename = format("#{directory}/%03d.jpg", (index + 1))
|
119
|
+
|
120
|
+
primary_photo_filename = filename if photo.id == primary_photo_id
|
121
|
+
|
122
|
+
manifest_images[filename] = {
|
123
|
+
'metadata' => {
|
124
|
+
'title' => photo.title,
|
125
|
+
'description' => photo.description
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
download_photo(url, filename)
|
130
|
+
end
|
131
|
+
|
132
|
+
manifest = {
|
133
|
+
photoset_id => {
|
134
|
+
'title' => photoset.title,
|
135
|
+
'primary_image' => primary_photo_filename,
|
136
|
+
'images' => manifest_images
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
Jekyll
|
141
|
+
.logger
|
142
|
+
.info(
|
143
|
+
LOG_TOPIC,
|
144
|
+
"Finished downloading #{manifest_images.length} photos from Flickr photoset #{photoset_id} to #{directory}."
|
145
|
+
)
|
146
|
+
|
147
|
+
manifest
|
148
|
+
end
|
149
|
+
|
150
|
+
sig { params(flickr_photoset_id: String, post: T.untyped).void }
|
151
|
+
private def download_photoset(flickr_photoset_id, post)
|
152
|
+
unless should_download?(flickr_photoset_id)
|
153
|
+
post_name = T.must(%r{_posts/(?<name>.+)\.md}.match(post.relative_path))['name']
|
154
|
+
Jekyll
|
155
|
+
.logger
|
156
|
+
.warn(
|
157
|
+
LOG_TOPIC,
|
158
|
+
# rubocop: disable Layout/LineLength
|
159
|
+
"Photos already downloaded for Flickr photoset #{flickr_photoset_id}, referenced by #{post_name}. Moving on."
|
160
|
+
# rubocop: enable Layout/LineLength
|
161
|
+
)
|
162
|
+
return
|
163
|
+
end
|
164
|
+
|
165
|
+
post_image_root = "#{@config['image_root']}/#{flickr_photoset_id}"
|
166
|
+
FileUtils.mkdir_p(post_image_root)
|
167
|
+
|
168
|
+
manifest = download_photoset_photos(flickr_photoset_id, post_image_root)
|
169
|
+
write_manifest_file(manifest)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
data/lib/post_image.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'sorbet-runtime'
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
module FlickrHelpers
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
PhotosetId = T.type_alias { Integer }
|
11
|
+
|
12
|
+
sig { params(photoset_id: T.any(PhotosetId, T::Array[PhotosetId])).returns(PhotosetId) }
|
13
|
+
def self.get_first_photoset_id(photoset_id)
|
14
|
+
photoset_id = T.must(photoset_id.first) if photoset_id.is_a?(Array)
|
15
|
+
|
16
|
+
photoset_id
|
17
|
+
end
|
18
|
+
|
19
|
+
sig { params(photoset_id: PhotosetId).returns(T.nilable(String)) }
|
20
|
+
def self.get_photoset_primary_photo(photoset_id)
|
21
|
+
path = Jekyll.sites.first.data['flickr_photosets'].fetch(photoset_id, {}).fetch('primary_image', nil)
|
22
|
+
path.nil? ? nil : "/#{path}"
|
23
|
+
rescue KeyError
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module PostImage
|
29
|
+
extend T::Sig
|
30
|
+
|
31
|
+
JEKYLL_ROOT = T.let(Jekyll.configuration.source({}), String)
|
32
|
+
|
33
|
+
sig { params(post: T.untyped).returns(T.nilable(String)) }
|
34
|
+
def post_image(post)
|
35
|
+
item_id = post.fetch('relative_path')
|
36
|
+
Jekyll.logger.info('Post Image:', "Retrieving post image for #{item_id}")
|
37
|
+
|
38
|
+
image = post.fetch('image') { flickr_primary_photo(post) }
|
39
|
+
image = nil unless image && file_exists?(image)
|
40
|
+
|
41
|
+
if image.nil? && item_id.start_with?('_posts')
|
42
|
+
Jekyll.logger.warn('Post Image:', "Missing post image for #{item_id}")
|
43
|
+
end
|
44
|
+
|
45
|
+
image
|
46
|
+
end
|
47
|
+
|
48
|
+
sig { params(post: T.untyped).returns(T::Boolean) }
|
49
|
+
def post_has_image(post)
|
50
|
+
post_image = post_image(post)
|
51
|
+
!!post_image && file_exists?(post_image)
|
52
|
+
rescue KeyError
|
53
|
+
false
|
54
|
+
end
|
55
|
+
|
56
|
+
sig { params(post: T.untyped).returns(T::Boolean) }
|
57
|
+
def show_flickr_gallery(post)
|
58
|
+
post.key?('flickr_photoset_id') && !post.fetch('hide_flickr_gallery',
|
59
|
+
false) && !post.fetch('hide_post_gallery', false)
|
60
|
+
end
|
61
|
+
|
62
|
+
sig { params(post: T.untyped).returns(T::Boolean) }
|
63
|
+
def show_post_gallery(post)
|
64
|
+
!post.fetch('hide_post_gallery', false)
|
65
|
+
end
|
66
|
+
|
67
|
+
sig { params(path: String).returns(T::Boolean) }
|
68
|
+
private def file_exists?(path)
|
69
|
+
full_path = "#{JEKYLL_ROOT}#{path}"
|
70
|
+
File.exist?(full_path)
|
71
|
+
end
|
72
|
+
|
73
|
+
sig { params(post: T.untyped).returns(T.nilable(String)) }
|
74
|
+
private def flickr_primary_photo(post)
|
75
|
+
photoset_id = FlickrHelpers.get_first_photoset_id(post.fetch('flickr_photoset_id'))
|
76
|
+
FlickrHelpers.get_photoset_primary_photo(photoset_id)
|
77
|
+
rescue KeyError
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
Liquid::Template.register_filter(Jekyll::PostImage)
|
84
|
+
|
85
|
+
Jekyll::Hooks.register :posts, :pre_render do |post|
|
86
|
+
# Set the image field from Flickr data so jekyll-seo-tag renders the correct meta tags.
|
87
|
+
if !post.data.key?('image') && post.data.key?('flickr_photoset_id')
|
88
|
+
photoset_id = Jekyll::FlickrHelpers.get_first_photoset_id(post.data.fetch('flickr_photoset_id'))
|
89
|
+
image_path = Jekyll::FlickrHelpers.get_photoset_primary_photo(photoset_id)
|
90
|
+
post.data['image'] = image_path
|
91
|
+
end
|
92
|
+
end
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jekyll-flickr-utils
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Clinton Blackburn
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-11-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: jekyll
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.3'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '5.0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '4.3'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5.0'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: down
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '5.0'
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '6.0'
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '5.0'
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '6.0'
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: flickr
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '2.0'
|
60
|
+
- - "<"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '3.0'
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '2.0'
|
70
|
+
- - "<"
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '3.0'
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: sorbet-runtime
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
type: :runtime
|
81
|
+
prerelease: false
|
82
|
+
version_requirements: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
description:
|
88
|
+
email:
|
89
|
+
executables: []
|
90
|
+
extensions: []
|
91
|
+
extra_rdoc_files: []
|
92
|
+
files:
|
93
|
+
- LICENSE
|
94
|
+
- lib/flickr_downloader.rb
|
95
|
+
- lib/jekyll-flickr-utils.rb
|
96
|
+
- lib/post_image.rb
|
97
|
+
homepage:
|
98
|
+
licenses:
|
99
|
+
- MIT
|
100
|
+
metadata: {}
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 2.7.0
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubygems_version: 3.1.6
|
117
|
+
signing_key:
|
118
|
+
specification_version: 4
|
119
|
+
summary: Download images from Flickr
|
120
|
+
test_files: []
|