flickrage 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+ module Flickrage
3
+ module Worker
4
+ class Download < Base
5
+ def call(image_list)
6
+ raise Flickrage::DownloadError, 'Not enough images for download' if image_list&.size < 1
7
+
8
+ speaker.add_padding
9
+ logger.debug('Downloading process')
10
+ logger.info("Scheduled to download #{image_list.size} images")
11
+
12
+ init_output
13
+
14
+ @spin = spinner(message: 'Downloading')
15
+ files = image_list.images.map do |image|
16
+ Concurrent
17
+ .future(thread_pool) do
18
+ update_spin(spin, title: "Downloading image ID##{image.id}")
19
+ service.run(image)
20
+ end
21
+ .then do |r|
22
+ update_spin(spin, title: "Downloaded image ID##{r.id}")
23
+ r
24
+ end
25
+ .rescue { |_| nil }
26
+ end
27
+
28
+ result = Concurrent.zip(*files).value
29
+ result = result.compact.flatten if result
30
+
31
+ total = result.count(&:downloaded?)
32
+
33
+ if total.positive?
34
+ spin.success
35
+ else
36
+ spin.error('(failed: Not enough images downloaded)')
37
+ raise Flickrage::DownloadError
38
+ end
39
+
40
+ speaker.add_padding
41
+ logger.info("Downloaded #{total} images:")
42
+ speaker.print_table([PRINT_IMAGE_HEADERS_LITE + %w(path downloaded?)] + result.map do |i|
43
+ [i.keyword, i.id, i.local_path, i.downloaded?]
44
+ end)
45
+
46
+ image_list.merge_images result
47
+ ensure
48
+ clean_thread_pool
49
+ spin&.stop
50
+ end
51
+
52
+ private
53
+
54
+ def service
55
+ @service ||= Service::Downloader.new
56
+ end
57
+
58
+ def init_output
59
+ return if validate_output
60
+
61
+ output = speaker.ask('Please enter the path of the output directory:',
62
+ path: true)
63
+
64
+ unless valid_output?(output)
65
+ increment_error_counter(Flickrage::PathError, output)
66
+ return init_output
67
+ end
68
+
69
+ reset_error_counter
70
+
71
+ Flickrage.config.output = output
72
+ end
73
+
74
+ def validate_output
75
+ return false unless Flickrage.config.output
76
+ return true if valid_output?(Flickrage.config.output)
77
+ Flickrage.config.output = nil
78
+ false
79
+ end
80
+
81
+ def valid_output?(value)
82
+ return false unless value
83
+ Dir.exist?(value)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+ module Flickrage
3
+ module Worker
4
+ class Resize < Base
5
+ MIN_IMAGE_SIZE = 100
6
+ MAX_IMAGE_SIZE = 500
7
+
8
+ def call(image_list)
9
+ raise Flickrage::ResizeError, 'Not enough images for resize' if image_list.downloaded&.size < 1
10
+
11
+ speaker.add_padding
12
+ logger.debug('Resizing process')
13
+
14
+ init_crop_value('width')
15
+ init_crop_value('height')
16
+
17
+ @spin = spinner(message: 'Resizing images')
18
+ files = image_list.downloaded.map do |image|
19
+ Concurrent
20
+ .future(thread_pool) do
21
+ update_spin(spin, title: "Resizing image #{image.id}")
22
+ service.run(image)
23
+ end
24
+ .then do |r|
25
+ update_spin(spin, title: "Resized image #{r.id}")
26
+ r
27
+ end
28
+ .rescue { |_| nil }
29
+ end
30
+
31
+ result = Concurrent.zip(*files).value
32
+ result = result.compact.flatten if result
33
+
34
+ total = result.count(&:resized?)
35
+
36
+ if total > 2
37
+ spin.success
38
+ else
39
+ spin.error('(failed: Not enough images resized)')
40
+ raise Flickrage::ResizeError
41
+ end
42
+
43
+ speaker.add_padding
44
+ logger.info("Resized #{result.count(&:resized?)} images:")
45
+ speaker.print_table([PRINT_IMAGE_HEADERS_LITE + %w(path resized?)] + result.map do |i|
46
+ [i.keyword, i.id, i.resize_path, i.resized?]
47
+ end)
48
+
49
+ image_list.merge_images result
50
+ ensure
51
+ clean_thread_pool
52
+ spin&.stop
53
+ end
54
+
55
+ private
56
+
57
+ def service
58
+ return @service unless @service.nil?
59
+ @service = Service::Resizer.new(Flickrage.config.width, Flickrage.config.height)
60
+ end
61
+
62
+ def init_crop_value(name)
63
+ return true if valid_value?(Flickrage.config[name])
64
+
65
+ value = speaker.ask("Please enter image resize #{name}:")
66
+ value = String(value).to_i
67
+
68
+ unless valid_value?(value)
69
+ increment_error_counter(Flickrage::NumberError,
70
+ "#{value} >= #{MIN_IMAGE_SIZE}, #{value} =< #{MAX_IMAGE_SIZE}")
71
+ return init_crop_value(name)
72
+ end
73
+
74
+ reset_error_counter
75
+
76
+ Flickrage.config[name] = value
77
+ end
78
+
79
+ def valid_value?(value)
80
+ return false unless value
81
+ value >= MIN_IMAGE_SIZE && value <= MAX_IMAGE_SIZE
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+ module Flickrage
3
+ module Worker
4
+ class Search < Base
5
+ include Flickrage::Helpers::Dict
6
+
7
+ SYSTEM_TIMEOUT = 20
8
+
9
+ def call
10
+ keywords = opts['keywords'] || %w()
11
+
12
+ keywords += sample_words(Flickrage.config.max - keywords.size) if keywords.size < Flickrage.config.max
13
+ keys = keywords.join(', ')
14
+
15
+ speaker.add_padding
16
+ logger.debug('Searching process')
17
+ logger.info("Received keywords: [#{keys}]")
18
+
19
+ @spin = spinner(message: 'Searching ')
20
+
21
+ image_list = finder(keywords, spin)
22
+
23
+ if image_list.valid?
24
+ spin.success
25
+ else
26
+ spin.error('(nothing found)')
27
+ raise Flickrage::SearchError
28
+ end
29
+
30
+ speaker.add_padding
31
+ logger.info("Found #{image_list.total} images:")
32
+ speaker.print_table([PRINT_IMAGE_HEADERS] + image_list.images.map do |i|
33
+ [i.keyword, i.id, i.url, i.title, i.width, i.height]
34
+ end)
35
+
36
+ if Flickrage.config.verbose
37
+ logger.info('Not found keywords:')
38
+ speaker.print_table(image_list.not_founds.map do |word|
39
+ [word]
40
+ end)
41
+ end
42
+
43
+ image_list
44
+ ensure
45
+ clean_thread_pool
46
+ spin&.stop
47
+ end
48
+
49
+ private
50
+
51
+ def time
52
+ @time ||= Time.now.to_i
53
+ end
54
+
55
+ def timeout?
56
+ (Time.now.to_i - time) > SYSTEM_TIMEOUT
57
+ end
58
+
59
+ def service
60
+ @service ||= Service::Search.new
61
+ end
62
+
63
+ def finder(keywords, spin, image_list = nil)
64
+ files = keywords.map do |k|
65
+ Concurrent
66
+ .future(thread_pool) do
67
+ update_spin(spin, title: "Searching (keyword: #{k})")
68
+ service.run(k)
69
+ end
70
+ .then do |r|
71
+ update_spin(spin, title: "Searching (found image ID##{r.id})") if r
72
+ r
73
+ end
74
+ .rescue { |_| nil }
75
+ end
76
+
77
+ result = Concurrent.zip(*files).value
78
+ result = result.compact.flatten if result
79
+
80
+ if image_list
81
+ image_list.combine(result)
82
+ image_list.clean
83
+ else
84
+ image_list = Flickrage::Entity::ImageList.new(images: result,
85
+ total: result.size)
86
+ end
87
+
88
+ return image_list if image_list.valid?
89
+
90
+ fail_on_timeout
91
+ success_keywords = result.map(&:keyword)
92
+ not_founds = keywords - success_keywords
93
+ image_list.merge_not_founds(not_founds)
94
+
95
+ keywords = sample_words_strict(not_founds&.size || 0, except: image_list.not_founds)
96
+ return image_list if keywords.size.zero?
97
+
98
+ finder(keywords, spin, image_list)
99
+ end
100
+
101
+ def fail_on_timeout
102
+ raise Flickrage::SystemTimeout if timeout?
103
+ end
104
+ end
105
+ end
106
+ end
File without changes
File without changes
metadata ADDED
@@ -0,0 +1,322 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flickrage
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Merkulov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-08-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.19'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.19'
27
+ - !ruby/object:Gem::Dependency
28
+ name: flickraw
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.9.9
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.9.9
41
+ - !ruby/object:Gem::Dependency
42
+ name: mini_magick
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 4.5.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 4.5.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: dry-configurable
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.7
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.1.7
69
+ - !ruby/object:Gem::Dependency
70
+ name: dry-types
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.8.1
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.8.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: concurrent-ruby-edge
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: tty-spinner
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.3.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.3.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: pastel
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.6.0
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.6.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: bundler
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.12'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.12'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rake
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '10.0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '10.0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: json
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: 1.8.1
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: 1.8.1
167
+ - !ruby/object:Gem::Dependency
168
+ name: rspec
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: 3.5.0
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: 3.5.0
181
+ - !ruby/object:Gem::Dependency
182
+ name: rspec-core
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: 3.5.0
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: 3.5.0
195
+ - !ruby/object:Gem::Dependency
196
+ name: rspec-expectations
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: 3.5.0
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: 3.5.0
209
+ - !ruby/object:Gem::Dependency
210
+ name: rspec-mocks
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - "~>"
214
+ - !ruby/object:Gem::Version
215
+ version: 3.5.0
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - "~>"
221
+ - !ruby/object:Gem::Version
222
+ version: 3.5.0
223
+ - !ruby/object:Gem::Dependency
224
+ name: webmock
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - "~>"
228
+ - !ruby/object:Gem::Version
229
+ version: 2.1.0
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - "~>"
235
+ - !ruby/object:Gem::Version
236
+ version: 2.1.0
237
+ - !ruby/object:Gem::Dependency
238
+ name: coveralls
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - "~>"
242
+ - !ruby/object:Gem::Version
243
+ version: 0.8.15
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - "~>"
249
+ - !ruby/object:Gem::Version
250
+ version: 0.8.15
251
+ description: Little tool with idea of downloading random top-n pictures from the Flickr,
252
+ resize it properly & build collage from them!
253
+ email:
254
+ - sasha@merqlove.ru
255
+ executables:
256
+ - console
257
+ - flickrage
258
+ - setup
259
+ extensions: []
260
+ extra_rdoc_files: []
261
+ files:
262
+ - ".gitignore"
263
+ - ".rspec"
264
+ - ".rubocop.yml"
265
+ - ".ruby-version"
266
+ - ".travis.yml"
267
+ - Gemfile
268
+ - LICENSE.txt
269
+ - README.md
270
+ - Rakefile
271
+ - bin/console
272
+ - bin/flickrage
273
+ - bin/setup
274
+ - flickrage.gemspec
275
+ - lib/flickrage.rb
276
+ - lib/flickrage/cli.rb
277
+ - lib/flickrage/entity.rb
278
+ - lib/flickrage/entity/image.rb
279
+ - lib/flickrage/entity/image_list.rb
280
+ - lib/flickrage/helpers.rb
281
+ - lib/flickrage/log.rb
282
+ - lib/flickrage/pipeline.rb
283
+ - lib/flickrage/service.rb
284
+ - lib/flickrage/service/composer.rb
285
+ - lib/flickrage/service/downloader.rb
286
+ - lib/flickrage/service/resizer.rb
287
+ - lib/flickrage/service/search.rb
288
+ - lib/flickrage/types.rb
289
+ - lib/flickrage/version.rb
290
+ - lib/flickrage/worker.rb
291
+ - lib/flickrage/worker/base.rb
292
+ - lib/flickrage/worker/compose.rb
293
+ - lib/flickrage/worker/download.rb
294
+ - lib/flickrage/worker/resize.rb
295
+ - lib/flickrage/worker/search.rb
296
+ - log/.keep
297
+ - tmp/.keep
298
+ homepage: https://github.com/merqlove/flickrage
299
+ licenses:
300
+ - MIT
301
+ metadata: {}
302
+ post_install_message:
303
+ rdoc_options: []
304
+ require_paths:
305
+ - lib
306
+ required_ruby_version: !ruby/object:Gem::Requirement
307
+ requirements:
308
+ - - ">="
309
+ - !ruby/object:Gem::Version
310
+ version: 2.3.0
311
+ required_rubygems_version: !ruby/object:Gem::Requirement
312
+ requirements:
313
+ - - ">="
314
+ - !ruby/object:Gem::Version
315
+ version: '0'
316
+ requirements: []
317
+ rubyforge_project:
318
+ rubygems_version: 2.5.1
319
+ signing_key:
320
+ specification_version: 4
321
+ summary: Another one Flickr collage maker.
322
+ test_files: []