photo-helper 0.2.10 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/bin/photo-helper +1 -0
- data/lib/helpers/file_helper.rb +3 -1
- data/lib/helpers/image_helper.rb +13 -4
- data/lib/helpers/smugmug_album.rb +233 -0
- data/lib/helpers/smugmug_api.rb +45 -33
- data/lib/photo-helper/compress.rb +14 -13
- data/lib/photo-helper/screensaver.rb +30 -0
- data/lib/photo-helper/smugmug.rb +11 -11
- data/lib/photo-helper/version.rb +3 -2
- data/lib/photo_helper.rb +12 -7
- data/photo-helper.gemspec +2 -2
- metadata +4 -3
- data/lib/helpers/smugmug.rb +0 -84
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4bbf183dc81a5e29d5e0a0d8007073494144da3
|
4
|
+
data.tar.gz: 53085441c3aec638bd8b4a5e6362dd9f2de88164
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d872ce3085f8282759470f87eeb8acc04e5409d18ec958a1ee3ac557829e223d7ff09165f09fbcbafa419e87b715ee6851d5904f851c20949fe60223c47da45
|
7
|
+
data.tar.gz: a6cc39c361ed40180fa1c030cbec37fb4c51c30c9a1e04dde194bb8aef1f1f7d1b2f2fe3726f434f6d04c6baf1776a4b2abc6fc836fb7debe958f610b9c2b48b
|
data/Gemfile.lock
CHANGED
data/bin/photo-helper
CHANGED
data/lib/helpers/file_helper.rb
CHANGED
data/lib/helpers/image_helper.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
class ImageHelper
|
2
|
-
IMAGE_CLASS_REGEX =
|
3
|
-
RATING_REGEX =
|
4
|
-
|
3
|
+
IMAGE_CLASS_REGEX = /xmp:Label="(.+)"/
|
4
|
+
RATING_REGEX = /xmp:Rating="(.+)"/
|
5
|
+
|
5
6
|
def self.xmp(image)
|
6
7
|
xmp = File.join(File.dirname(image), File.basename(image, ".*") + ".XMP")
|
7
|
-
return unless File.
|
8
|
+
return unless File.exist?(xmp)
|
8
9
|
File.read(xmp)
|
9
10
|
end
|
10
11
|
|
11
12
|
def self.color_class(image)
|
12
13
|
contents = xmp(image)
|
14
|
+
return if contents.nil?
|
13
15
|
matches = contents.match(IMAGE_CLASS_REGEX)
|
14
16
|
matches[1] if matches
|
15
17
|
end
|
@@ -32,4 +34,11 @@ class ImageHelper
|
|
32
34
|
def self.is_5_star?(image)
|
33
35
|
rating(image) == '5'
|
34
36
|
end
|
37
|
+
|
38
|
+
def self.is_jpeg?(path)
|
39
|
+
# remove . from the beginning
|
40
|
+
extension = File.extname(path)[1..-1]
|
41
|
+
return false if extension.nil?
|
42
|
+
JPEG_EXTENSIONS.include? extension.downcase
|
43
|
+
end
|
35
44
|
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "helpers/smugmug_api"
|
3
|
+
require "helpers/image_helper"
|
4
|
+
require "helpers/file_helper"
|
5
|
+
require 'set'
|
6
|
+
|
7
|
+
class SmugmugAlbumHelper
|
8
|
+
attr_accessor :smugmug_api
|
9
|
+
|
10
|
+
# to figure out what to delete, read all xmp files, loop through uploaded files and check xmp file
|
11
|
+
|
12
|
+
PATH_REGEX = %r{^.+Pictures\/.+\/(\d{4})\/(\d{2})_.+\/[^_]+_([^\/]+)}
|
13
|
+
KEYWORD_WHITELITS = %w("instagram exported")
|
14
|
+
|
15
|
+
def initialize(search_path, album = nil)
|
16
|
+
@search_path = Pathname.new(search_path)
|
17
|
+
@smugmug = SmugmugAPI.new
|
18
|
+
|
19
|
+
@album_name = album || album_name
|
20
|
+
|
21
|
+
@album = @smugmug.get_or_create_album(@album_name, album_url: @location&.downcase)
|
22
|
+
|
23
|
+
@dl_album_name = File.join("dl", @album_name)
|
24
|
+
@dl_album = @smugmug.get_or_create_album(@dl_album_name, album_url: @location&.downcase)
|
25
|
+
|
26
|
+
@keyword_list = Set.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_path
|
30
|
+
if matches = "#{@search_path}/".to_s.match(PATH_REGEX)
|
31
|
+
@year = matches[1]
|
32
|
+
@month = Date::MONTHNAMES[matches[2].to_i].capitalize
|
33
|
+
@location = matches[3].split("_").map(&:capitalize).join(' ')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def album_name
|
38
|
+
parse_path
|
39
|
+
if @year && @month && @location
|
40
|
+
album_name_short = "#{@location} #{@month} #{@year}"
|
41
|
+
File.join(@year, @month, album_name_short)
|
42
|
+
else
|
43
|
+
puts 'Unable to determine album from path'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def image_list
|
48
|
+
Dir["#{@search_path}/**/*.{#{IMAGE_EXTENSIONS.join(',')}}"].reject { |p| FileHelper.ingore_file?(p) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def exported_list
|
52
|
+
Dir["#{@search_path}/**/{Exported,exported}/*.{#{IMAGE_EXTENSIONS.join(',')}}"]
|
53
|
+
end
|
54
|
+
|
55
|
+
def instagram_list
|
56
|
+
Dir["#{@search_path}/**/{Instagram,instagram}/*.{#{IMAGE_EXTENSIONS.join(',')}}"]
|
57
|
+
end
|
58
|
+
|
59
|
+
def merge_exported(images = image_list, concat = false)
|
60
|
+
exported = Dir["#{@search_path}/**/{Exported,exported}/*.{#{IMAGE_EXTENSIONS.join(',')}}"]
|
61
|
+
unless concat
|
62
|
+
exported_basenames = exported.map { |p| File.basename(p, ".*") }
|
63
|
+
images = images.reject { |p| exported_basenames.include? File.basename(p, ".*") }
|
64
|
+
end
|
65
|
+
images.concat(exported)
|
66
|
+
end
|
67
|
+
|
68
|
+
def uploaded_to_hash(album)
|
69
|
+
uploaded = @smugmug.images(album[:id])
|
70
|
+
uploaded_hash = {}
|
71
|
+
uploaded.each do |u|
|
72
|
+
filename = File.basename(u[:filename], ".*")
|
73
|
+
push_hash_array(uploaded_hash, filename, u)
|
74
|
+
end
|
75
|
+
uploaded_hash
|
76
|
+
end
|
77
|
+
|
78
|
+
def image_list_to_hash(images)
|
79
|
+
image_list_hash = {}
|
80
|
+
images.each do |i|
|
81
|
+
filename = File.basename(i, ".*")
|
82
|
+
tags = image_dir_keywords(i)
|
83
|
+
@keyword_list.merge(tags) if tags
|
84
|
+
push_hash_array(image_list_hash, filename, file: i,
|
85
|
+
keywords: tags,
|
86
|
+
md5: Digest::MD5.file(i).hexdigest)
|
87
|
+
end
|
88
|
+
image_list_hash
|
89
|
+
end
|
90
|
+
|
91
|
+
def sync(album, image_list_hash, reject_trash = true)
|
92
|
+
uploaded_hash = uploaded_to_hash(album)
|
93
|
+
|
94
|
+
to_upload = {}
|
95
|
+
to_update = {}
|
96
|
+
to_delete = []
|
97
|
+
|
98
|
+
image_list_hash.each do |filename, images|
|
99
|
+
images.each do |image|
|
100
|
+
next unless ImageHelper.is_jpeg?(image[:file])
|
101
|
+
next if reject_trash && ImageHelper.color_class(image[:file]) == "Trash"
|
102
|
+
|
103
|
+
upload_image = true
|
104
|
+
|
105
|
+
if uploaded_hash.key?(filename)
|
106
|
+
!uploaded_hash[filename].each do |uploaded|
|
107
|
+
next unless uploaded_match_requested?(image, uploaded)
|
108
|
+
|
109
|
+
# & returns if in both arrays
|
110
|
+
upload_image = false
|
111
|
+
if uploaded[:md5] != image[:md5]
|
112
|
+
push_hash_array(to_update, image[:keywords], image.merge!(uri: uploaded[:uri]))
|
113
|
+
end
|
114
|
+
break
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
if upload_image
|
119
|
+
push_hash_array(to_upload, image[:keywords], image[:file])
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
uploaded_hash.each do |filename, uploaded_images|
|
125
|
+
uploaded_images.each do |uploaded|
|
126
|
+
if image_list_hash.key?(filename)
|
127
|
+
image_hash = image_list_hash[filename].find do |image|
|
128
|
+
uploaded_match_requested?(image, uploaded)
|
129
|
+
end
|
130
|
+
to_delete.push(uploaded) if image_hash.nil?
|
131
|
+
to_delete.push(uploaded) if reject_trash && ImageHelper.color_class(image_hash[:file]) == "Trash"
|
132
|
+
else
|
133
|
+
to_delete.push(uploaded)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
to_upload.each do |keywords, images|
|
139
|
+
puts keywords
|
140
|
+
upload(album, images, keywords)
|
141
|
+
end
|
142
|
+
|
143
|
+
if to_delete.any?
|
144
|
+
puts "Deleting #{to_delete.count} images"
|
145
|
+
to_delete.each do |uploaded|
|
146
|
+
puts uploaded[:filename]
|
147
|
+
@smugmug.http(:delete, uploaded[:uri])
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
to_update.each do |keywords, images|
|
152
|
+
puts keywords
|
153
|
+
update(album, images, keywords)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def upload(album, pictures, keywords = nil)
|
158
|
+
puts "Uploading #{pictures.count} jpegs"
|
159
|
+
|
160
|
+
headers = {}
|
161
|
+
headers["X-Smug-Keywords"] = keywords.join(",") unless keywords.nil?
|
162
|
+
|
163
|
+
@smugmug.upload_images(pictures, album[:id], headers, workers: 8, filename_as_title: true)
|
164
|
+
end
|
165
|
+
|
166
|
+
def update(album, pictures, keywords = nil)
|
167
|
+
puts "Updating #{pictures.count} jpegs"
|
168
|
+
|
169
|
+
headers = {}
|
170
|
+
headers["X-Smug-Keywords"] = keywords.join(",") unless keywords.nil?
|
171
|
+
|
172
|
+
@smugmug.update_images(pictures, album[:id], headers, workers: 8, filename_as_title: true)
|
173
|
+
end
|
174
|
+
|
175
|
+
def upload_dl
|
176
|
+
@keyword_list = Set.new
|
177
|
+
puts "Uploading all images to album #{@album_name} --> #{@dl_album[:web_uri]}\n"
|
178
|
+
|
179
|
+
@image_list = image_list_to_hash(image_list)
|
180
|
+
@image_list = merge_hash_array(@image_list, image_list_to_hash(exported_list))
|
181
|
+
@image_list = merge_hash_array(@image_list, image_list_to_hash(instagram_list))
|
182
|
+
|
183
|
+
sync(@dl_album, @image_list, true)
|
184
|
+
end
|
185
|
+
|
186
|
+
def upload_select
|
187
|
+
@keyword_list = Set.new
|
188
|
+
|
189
|
+
pictures = image_list
|
190
|
+
pictures = pictures.select { |p| ImageHelper.is_select?(p) }
|
191
|
+
pictures = merge_exported(pictures)
|
192
|
+
|
193
|
+
puts "Uploading selects to album #{@album_name} --> #{@album[:web_uri]}\n"
|
194
|
+
|
195
|
+
@image_list = image_list_to_hash(pictures)
|
196
|
+
|
197
|
+
sync(@album, @image_list, true)
|
198
|
+
end
|
199
|
+
|
200
|
+
private
|
201
|
+
|
202
|
+
def push_hash_array(hash, key, item)
|
203
|
+
hash[key] = [] unless hash.key?(key)
|
204
|
+
hash[key].push(item)
|
205
|
+
hash
|
206
|
+
end
|
207
|
+
|
208
|
+
def merge_hash_array(hash1, hash2)
|
209
|
+
hash2.each do |key, value|
|
210
|
+
hash1[key] = [] unless hash1.key?(key)
|
211
|
+
hash1[key].concat(value)
|
212
|
+
end
|
213
|
+
hash1
|
214
|
+
end
|
215
|
+
|
216
|
+
def image_dir_keywords(image)
|
217
|
+
rel = Pathname.new(image).relative_path_from(@search_path).to_s.split("/")
|
218
|
+
# ignore first and last parts
|
219
|
+
rel &= KEYWORD_WHITELITS
|
220
|
+
return nil if rel.empty?
|
221
|
+
rel
|
222
|
+
end
|
223
|
+
|
224
|
+
def uploaded_match_requested?(image, uploaded)
|
225
|
+
if image[:keywords].nil?
|
226
|
+
# empty from keyword list
|
227
|
+
return true if uploaded[:keywords].nil? || @keyword_list & uploaded[:keywords] == Set.new
|
228
|
+
else
|
229
|
+
return true if image[:keywords] - uploaded[:keywords] == []
|
230
|
+
end
|
231
|
+
false
|
232
|
+
end
|
233
|
+
end
|
data/lib/helpers/smugmug_api.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'helpers/secrets'
|
2
3
|
require 'oauth'
|
3
4
|
require 'uri'
|
@@ -7,16 +8,16 @@ require 'parallel'
|
|
7
8
|
|
8
9
|
class SmugmugAPI
|
9
10
|
attr_accessor :http, :uploader
|
10
|
-
OAUTH_ORIGIN = 'https://secure.smugmug.com'
|
11
|
-
REQUEST_TOKEN_URL = '/services/oauth/1.0a/getRequestToken'
|
12
|
-
ACCESS_TOKEN_URL = '/services/oauth/1.0a/getAccessToken'
|
13
|
-
AUTHORIZE_URL = '/services/oauth/1.0a/authorize'
|
14
|
-
API_ENDPOINT = 'https://api.smugmug.com'
|
15
|
-
UPLOAD_ENDPOINT = 'https://upload.smugmug.com/'
|
11
|
+
OAUTH_ORIGIN = 'https://secure.smugmug.com'
|
12
|
+
REQUEST_TOKEN_URL = '/services/oauth/1.0a/getRequestToken'
|
13
|
+
ACCESS_TOKEN_URL = '/services/oauth/1.0a/getAccessToken'
|
14
|
+
AUTHORIZE_URL = '/services/oauth/1.0a/authorize'
|
15
|
+
API_ENDPOINT = 'https://api.smugmug.com'
|
16
|
+
UPLOAD_ENDPOINT = 'https://upload.smugmug.com/'
|
16
17
|
|
17
18
|
def initialize(ejson_file = '~/.photo_helper.ejson')
|
18
19
|
ejson_file = File.expand_path(ejson_file)
|
19
|
-
@secrets = Secrets.new(ejson_file, %i
|
20
|
+
@secrets = Secrets.new(ejson_file, %i(api_key api_secret))
|
20
21
|
request_access_token if !@secrets["access_token"] || !@secrets["access_secret"]
|
21
22
|
|
22
23
|
@http = get_access_token
|
@@ -69,8 +70,6 @@ class SmugmugAPI
|
|
69
70
|
get('/api/v2!authuser')['User']
|
70
71
|
end
|
71
72
|
|
72
|
-
def images; end
|
73
|
-
|
74
73
|
def folders
|
75
74
|
folder_list = []
|
76
75
|
resp = get('/api/v2/folder/user/bcaldwell!folderlist')
|
@@ -83,7 +82,6 @@ class SmugmugAPI
|
|
83
82
|
def get_or_create_album(path, album_url: nil)
|
84
83
|
folder_path = File.dirname(path).split('/').map(&:capitalize).join('/')
|
85
84
|
album_name = File.basename(path).split(' ').map(&:capitalize).join(' ')
|
86
|
-
puts album_name
|
87
85
|
album = nil
|
88
86
|
|
89
87
|
folder = get_or_create_folder(folder_path)
|
@@ -165,14 +163,14 @@ class SmugmugAPI
|
|
165
163
|
@images.map { |i| i[:filename] }
|
166
164
|
end
|
167
165
|
|
168
|
-
def http(method, url, headers = {},
|
169
|
-
response = http_raw(method, url, headers,
|
166
|
+
def http(method, url, headers = {}, body = nil)
|
167
|
+
response = http_raw(method, url, headers, body)
|
170
168
|
raise 'Request failed' unless response.is_a? Net::HTTPSuccess
|
171
169
|
JSON.parse(response.body)['Response']
|
172
170
|
end
|
173
171
|
|
174
172
|
def get(url, params = nil, headers = {})
|
175
|
-
url.tr
|
173
|
+
url = url.tr(' ', '-')
|
176
174
|
uri = URI.parse(url)
|
177
175
|
uri.query = URI.encode_www_form(params) if params
|
178
176
|
http(:get, uri.to_s, headers)
|
@@ -186,38 +184,53 @@ class SmugmugAPI
|
|
186
184
|
JSON.parse(response.body)['Response']
|
187
185
|
end
|
188
186
|
|
189
|
-
def upload(image_path, album_id, headers = {})
|
187
|
+
def upload(image_path, album_id, headers = {}, filename_as_title: false)
|
190
188
|
image = File.open(image_path)
|
191
189
|
|
192
190
|
headers.merge!('Content-Type' => MimeMagic.by_path(image_path).type,
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
191
|
+
'X-Smug-AlbumUri' => "/api/v2/album/#{album_id}",
|
192
|
+
'X-Smug-ResponseType' => 'JSON',
|
193
|
+
'X-Smug-Version' => 'v2',
|
194
|
+
'charset' => 'UTF-8',
|
195
|
+
'Accept' => 'JSON',
|
196
|
+
'X-Smug-FileName' => File.basename(image_path),
|
197
|
+
'Content-MD5' => Digest::MD5.file(image_path).hexdigest)
|
198
|
+
|
199
|
+
headers['X-Smug-Title'] = File.basename(image_path, ".*") if filename_as_title
|
200
200
|
|
201
201
|
resp = @uploader.post('/', image, headers)
|
202
202
|
resp.body
|
203
203
|
end
|
204
204
|
|
205
|
-
def upload_images(images, album_id, headers = {}, workers: 4)
|
205
|
+
def upload_images(images, album_id, headers = {}, workers: 4, filename_as_title: false)
|
206
|
+
counter = 0
|
207
|
+
Parallel.each(images, in_processes: workers, progress: "Uploading images") do |image|
|
208
|
+
upload(image, album_id, headers, filename_as_title: filename_as_title)
|
209
|
+
# puts "#{counter}/#{images.count / workers}
|
210
|
+
puts "Done #{image}"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def update_images(images, album_id, headers = {}, workers: 4, filename_as_title: false)
|
206
215
|
counter = 0
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
216
|
+
|
217
|
+
Parallel.each(images, in_processes: workers, progress: "Updating images") do |image|
|
218
|
+
# replace not working, delete then upload
|
219
|
+
http(:delete, image[:uri])
|
220
|
+
upload(image[:file], album_id, headers, filename_as_title: filename_as_title)
|
221
|
+
# counter += 1
|
222
|
+
# puts "#{counter}/#{images.count / workers}
|
223
|
+
puts "Done #{image[:file]}"
|
211
224
|
end
|
212
225
|
end
|
213
226
|
|
214
227
|
def request_access_token
|
215
228
|
@consumer = OAuth::Consumer.new(@secrets.api_key, @secrets.api_secret,
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
229
|
+
site: OAUTH_ORIGIN,
|
230
|
+
name: 'photo-helper',
|
231
|
+
request_token_path: REQUEST_TOKEN_URL,
|
232
|
+
authorize_path: AUTHORIZE_URL,
|
233
|
+
access_token_path: ACCESS_TOKEN_URL)
|
221
234
|
|
222
235
|
# Generate request token
|
223
236
|
@request_token = @consumer.get_request_token
|
@@ -244,9 +257,8 @@ class SmugmugAPI
|
|
244
257
|
private
|
245
258
|
|
246
259
|
def http_raw(method, url, headers = {}, _body = nil)
|
247
|
-
url.tr
|
260
|
+
url = url.tr(' ', '-')
|
248
261
|
headers['Accept'] = 'application/json'
|
249
|
-
|
250
262
|
@http.request(method, url, headers)
|
251
263
|
end
|
252
264
|
|
@@ -1,14 +1,14 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'mini_magick'
|
2
|
+
require 'helpers/file_helper'
|
3
3
|
|
4
4
|
module PhotoHelper
|
5
5
|
class Compress < Thor
|
6
6
|
include Thor::Actions
|
7
7
|
|
8
|
-
method_option :recursive, aliases:
|
9
|
-
method_option :overwrite, aliases:
|
10
|
-
desc
|
11
|
-
def images(folder=nil)
|
8
|
+
method_option :recursive, aliases: '-r', type: :boolean, default: false
|
9
|
+
method_option :overwrite, aliases: '-o', type: :boolean, default: false
|
10
|
+
desc 'images', 'compress images in folder'
|
11
|
+
def images(folder = nil)
|
12
12
|
folder ||= options[:folder]
|
13
13
|
|
14
14
|
search_path = File.expand_path(folder)
|
@@ -21,28 +21,29 @@ module PhotoHelper
|
|
21
21
|
end
|
22
22
|
|
23
23
|
files.each do |file|
|
24
|
-
next if File.basename(file,
|
24
|
+
next if File.basename(file, '.*').end_with? '.min'
|
25
25
|
next unless FileHelper.is_jpeg?(file)
|
26
26
|
|
27
27
|
image = MiniMagick::Image.open(file)
|
28
28
|
orig_size = image.size
|
29
29
|
|
30
30
|
image.combine_options do |b|
|
31
|
-
b.sampling_factor
|
31
|
+
b.sampling_factor '4:2:0'
|
32
32
|
b.strip
|
33
|
-
b.interlace
|
34
|
-
b.colorspace
|
33
|
+
b.interlace 'JPEG'
|
34
|
+
b.colorspace 'RGB'
|
35
35
|
b.quality 85
|
36
36
|
end
|
37
|
+
next if orig_size == image.size
|
37
38
|
puts "#{file} (#{(orig_size / image.size) * 100}%)"
|
38
39
|
|
39
|
-
output_path =
|
40
|
+
output_path =
|
40
41
|
if options[:overwrite]
|
41
42
|
file
|
42
43
|
else
|
43
|
-
File.join(
|
44
|
+
File.join(File.dirname(file), File.basename(file, '.*') + '.min' + File.extname(file))
|
44
45
|
end
|
45
|
-
|
46
|
+
|
46
47
|
image.write output_path
|
47
48
|
end
|
48
49
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'helpers/file_helper'
|
2
|
+
require 'photo-helper/compress'
|
3
|
+
|
4
|
+
module PhotoHelper
|
5
|
+
class Screensaver < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
method_option :overwrite, aliases: '-o', type: :boolean, default: false
|
9
|
+
desc 'move', 'Move best photos to screensaver folder and compress'
|
10
|
+
def move
|
11
|
+
files = Dir["#{BEST_OF_ROOT}/**/*"]
|
12
|
+
|
13
|
+
files.each do |file|
|
14
|
+
next unless FileHelper.is_jpeg?(file)
|
15
|
+
dest = File.join(SCREENSAVER_ROOT, File.basename(file))
|
16
|
+
next if File.exist?(dest)
|
17
|
+
puts file
|
18
|
+
FileUtils.copy(file, dest)
|
19
|
+
end
|
20
|
+
|
21
|
+
puts 'Compressing'
|
22
|
+
|
23
|
+
compress = PhotoHelper::Compress.new
|
24
|
+
compress.options = { overwrite: true }
|
25
|
+
compress.images(SCREENSAVER_ROOT)
|
26
|
+
end
|
27
|
+
|
28
|
+
default_task :move
|
29
|
+
end
|
30
|
+
end
|
data/lib/photo-helper/smugmug.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'helpers/smugmug_album'
|
2
3
|
require 'date'
|
3
4
|
require 'helpers/image_helper'
|
4
5
|
|
@@ -11,28 +12,27 @@ module PhotoHelper
|
|
11
12
|
method_option :folder, aliases: '-f', type: :string, default: '.'
|
12
13
|
method_option :recursive, aliases: '-r', type: :boolean, default: false
|
13
14
|
method_option :dry_run, aliases: '-d', type: :boolean, default: false
|
14
|
-
def sync(folder = nil,
|
15
|
+
def sync(folder = nil, _album_name = nil)
|
15
16
|
search_path = File.expand_path(folder)
|
16
17
|
|
17
|
-
@smugmug =
|
18
|
+
@smugmug = SmugmugAlbumHelper.new(search_path)
|
18
19
|
|
19
20
|
@smugmug.upload_select
|
20
21
|
puts("\n")
|
21
|
-
if album_name
|
22
|
-
|
23
|
-
else
|
24
|
-
|
25
|
-
end
|
22
|
+
# if album_name
|
23
|
+
# @smugmug.upload(album_name, @smugmug.image_list)
|
24
|
+
# else
|
25
|
+
@smugmug.upload_dl
|
26
|
+
# end
|
26
27
|
end
|
27
28
|
|
28
29
|
desc 'oauth', "fetch oauth credentials"
|
29
|
-
def oauth
|
30
|
+
def oauth
|
30
31
|
SmugmugAPI.new.request_access_token
|
31
32
|
end
|
32
33
|
|
33
34
|
desc 'albums', "list albums with their weburl"
|
34
|
-
|
35
|
-
def albums(folder = nil, album_name = nil)
|
35
|
+
def albums
|
36
36
|
@smugmug = SmugmugAPI.new
|
37
37
|
albums = @smugmug.albums_long
|
38
38
|
|
data/lib/photo-helper/version.rb
CHANGED
data/lib/photo_helper.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'thor'
|
2
3
|
|
3
4
|
require 'helpers/printer'
|
@@ -9,17 +10,20 @@ require 'photo-helper/move'
|
|
9
10
|
require 'photo-helper/instagram'
|
10
11
|
require 'photo-helper/compress'
|
11
12
|
require 'photo-helper/smugmug'
|
13
|
+
require 'photo-helper/screensaver'
|
12
14
|
|
13
|
-
#
|
15
|
+
# TODO: move to config file
|
14
16
|
RAW_EXTENSION = "dng"
|
15
17
|
RAW_EXTENSIONS = [RAW_EXTENSION, "DNG", "ORF"]
|
16
18
|
JPEG_EXTENSION = "JPG"
|
17
|
-
JPEG_EXTENSIONS =
|
19
|
+
JPEG_EXTENSIONS = %w(JPG jpg jpeg)
|
18
20
|
IMAGE_EXTENSIONS = JPEG_EXTENSIONS.concat([])
|
19
|
-
PHOTOS_ROOT = "
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
PHOTOS_ROOT = File.expand_path("~/Pictures/Pictures")
|
22
|
+
BEST_OF_ROOT = File.expand_path("~/Pictures/Pictures/Best\ of")
|
23
|
+
SCREENSAVER_ROOT = File.expand_path("~/Pictures/screensaver")
|
24
|
+
JPEG_ROOT = File.expand_path("~/Pictures/jpegs")
|
25
|
+
IGNORE_FOLDERS = %w(instagram exported edited)
|
26
|
+
SELECT_COLOR_TAGS = ["Winner", "Winner alt", "Superior", "Superior alt", "Typical", "Typical alt"]
|
23
27
|
|
24
28
|
module PhotoHelper
|
25
29
|
class CLI < Thor
|
@@ -37,6 +41,7 @@ module PhotoHelper
|
|
37
41
|
register PhotoHelper::Instagram, :instagram, "instagram", "Do something else"
|
38
42
|
register PhotoHelper::Move, :move, "move", "Do something else"
|
39
43
|
register PhotoHelper::Compress, :compress, "compress", "Do something else"
|
40
|
-
register PhotoHelper::Smugmug, :smugmug, "smugmug", "Interface with Smugmug"
|
44
|
+
register PhotoHelper::Smugmug, :smugmug, "smugmug", "Interface with Smugmug"
|
45
|
+
register PhotoHelper::Screensaver, :screensaver, "screensaver", "Move best photos to screensaver folder and compress"
|
41
46
|
end
|
42
47
|
end
|
data/photo-helper.gemspec
CHANGED
@@ -5,7 +5,7 @@ require 'photo-helper/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "photo-helper"
|
8
|
-
spec.version =
|
8
|
+
spec.version = PhotoHelper::VERSION
|
9
9
|
spec.authors = ["Benjamin Caldwell"]
|
10
10
|
spec.email = ["caldwellbenjamin8@gmail.com"]
|
11
11
|
|
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency "pry"
|
28
28
|
spec.add_development_dependency "byebug"
|
29
29
|
spec.add_development_dependency "rubocop"
|
30
|
-
|
30
|
+
|
31
31
|
spec.add_dependency "thor"
|
32
32
|
spec.add_dependency "mini_magick"
|
33
33
|
spec.add_dependency "ejson"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: photo-helper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.3'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Caldwell
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-12-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -216,7 +216,7 @@ files:
|
|
216
216
|
- lib/helpers/image_helper.rb
|
217
217
|
- lib/helpers/printer.rb
|
218
218
|
- lib/helpers/secrets.rb
|
219
|
-
- lib/helpers/
|
219
|
+
- lib/helpers/smugmug_album.rb
|
220
220
|
- lib/helpers/smugmug_api.rb
|
221
221
|
- lib/helpers/trash.rb
|
222
222
|
- lib/photo-helper/compress.rb
|
@@ -224,6 +224,7 @@ files:
|
|
224
224
|
- lib/photo-helper/generate.rb
|
225
225
|
- lib/photo-helper/instagram.rb
|
226
226
|
- lib/photo-helper/move.rb
|
227
|
+
- lib/photo-helper/screensaver.rb
|
227
228
|
- lib/photo-helper/smugmug.rb
|
228
229
|
- lib/photo-helper/version.rb
|
229
230
|
- lib/photo_helper.rb
|
data/lib/helpers/smugmug.rb
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
require "helpers/smugmug_api"
|
2
|
-
require "helpers/image_helper"
|
3
|
-
require "helpers/file_helper"
|
4
|
-
|
5
|
-
class SmugmugHelper
|
6
|
-
attr_accessor :smugmug_api
|
7
|
-
|
8
|
-
# to figure out what to delete, read all xmp files, loop through uploaded files and check xmp file
|
9
|
-
|
10
|
-
PATH_REGEX = %r{^.+Pictures\/.+\/(\d{4})\/(\d{2})_.+\/[^_]+_([^\/]+)}
|
11
|
-
|
12
|
-
def initialize(search_path)
|
13
|
-
@search_path = search_path
|
14
|
-
@smugmug = SmugmugAPI.new
|
15
|
-
end
|
16
|
-
|
17
|
-
def parse_path
|
18
|
-
if matches = "#{@search_path}/".to_s.match(PATH_REGEX)
|
19
|
-
@year = matches[1]
|
20
|
-
@month = Date::MONTHNAMES[matches[2].to_i].capitalize
|
21
|
-
@location = matches[3].split("_").map(&:capitalize).join(' ')
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def album_name
|
26
|
-
parse_path
|
27
|
-
if @year && @month && @location
|
28
|
-
folder = "#{@month} #{@year}"
|
29
|
-
album_name_short = "#{@location} #{@month} #{@year}"
|
30
|
-
File.join(@year, @month, album_name_short)
|
31
|
-
else
|
32
|
-
puts 'Unable to determine album from path'
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def image_list
|
37
|
-
# todo: exclude exported path
|
38
|
-
Dir["#{@search_path}/**/*.{#{IMAGE_EXTENSIONS.join(",")}}"].reject{ |p| FileHelper.ingore_file?(p) }
|
39
|
-
end
|
40
|
-
|
41
|
-
def merge_exported(images = image_list)
|
42
|
-
exported = Dir["#{@search_path}/**/{Exported,exported}/*.{#{IMAGE_EXTENSIONS.join(",")}}"]
|
43
|
-
exported_basenames = exported.map{ |p| File.basename(p, ".*") }
|
44
|
-
images = images.reject { |p| exported_basenames.include? File.basename(p, ".*") }
|
45
|
-
images.concat(exported)
|
46
|
-
end
|
47
|
-
|
48
|
-
def upload(album_name, pictures, reject_trash = true)
|
49
|
-
album = @smugmug.get_or_create_album(album_name, album_url: @location&.downcase)
|
50
|
-
puts "#{album[:web_uri]}\n"
|
51
|
-
|
52
|
-
# remove uploaded pictures
|
53
|
-
uploaded = @smugmug.image_list(album[:id])
|
54
|
-
|
55
|
-
pictures = pictures.reject do |p|
|
56
|
-
if reject_trash
|
57
|
-
return true if ImageHelper.color_class(p) == "Trash"
|
58
|
-
end
|
59
|
-
uploaded.include? File.basename(p)
|
60
|
-
end
|
61
|
-
|
62
|
-
puts "Uploading #{pictures.count} jpegs"
|
63
|
-
|
64
|
-
@smugmug.upload_images(pictures, album[:id], workers: 8)
|
65
|
-
end
|
66
|
-
|
67
|
-
def upload_dl
|
68
|
-
@album_name = album_name
|
69
|
-
@album_name = File.join("dl", @album_name)
|
70
|
-
|
71
|
-
puts "Uploading all images to album #{@album_name}"
|
72
|
-
upload(@album_name, image_list)
|
73
|
-
end
|
74
|
-
|
75
|
-
def upload_select
|
76
|
-
@album_name = album_name
|
77
|
-
pictures = image_list
|
78
|
-
pictures = pictures.select{ |p| ImageHelper.is_select?(p)}
|
79
|
-
pictures = merge_exported(pictures)
|
80
|
-
|
81
|
-
puts "Uploading selects to album #{@album_name}"
|
82
|
-
upload(@album_name, pictures)
|
83
|
-
end
|
84
|
-
end
|