artbase 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Manifest.txt +0 -10
- data/Rakefile +4 -3
- data/lib/artbase/tool.rb +28 -13
- data/lib/artbase/version.rb +2 -2
- data/lib/artbase.rb +12 -78
- metadata +11 -21
- data/lib/artbase/attributes.rb +0 -83
- data/lib/artbase/collection/base.rb +0 -329
- data/lib/artbase/collection/image.rb +0 -39
- data/lib/artbase/collection/opensea.rb +0 -297
- data/lib/artbase/collection/token.rb +0 -400
- data/lib/artbase/collection.rb +0 -12
- data/lib/artbase/helper.rb +0 -169
- data/lib/artbase/image/sample.rb +0 -31
- data/lib/artbase/image.rb +0 -31
- data/lib/artbase/retry.rb +0 -41
@@ -1,400 +0,0 @@
|
|
1
|
-
|
2
|
-
class TokenCollection < Artbase::Base
|
3
|
-
|
4
|
-
|
5
|
-
#############
|
6
|
-
# (nested) Meta classes
|
7
|
-
# read meta data into struct
|
8
|
-
class Meta
|
9
|
-
def self.read( path )
|
10
|
-
new( read_json( path ))
|
11
|
-
end
|
12
|
-
|
13
|
-
|
14
|
-
def initialize( data )
|
15
|
-
@data = data
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
def name
|
20
|
-
## note: name might be an integer number e.g. 0/1/2 etc.
|
21
|
-
## e.g. see crypto pudgy punks and others?
|
22
|
-
## always auto-convert to string
|
23
|
-
@name ||= _normalize( @data['name'].to_s )
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
def description
|
28
|
-
@description ||= _normalize( @data['description'] )
|
29
|
-
end
|
30
|
-
|
31
|
-
## note: auto-convert "" (empty string) to nil
|
32
|
-
def image() _blank( @data['image'] ); end
|
33
|
-
alias_method :image_url, :image ## add image_url alias - why? why not?
|
34
|
-
|
35
|
-
|
36
|
-
def attributes
|
37
|
-
@attributes ||= begin
|
38
|
-
traits = []
|
39
|
-
## keep traits as (simple)
|
40
|
-
## ordered array of pairs for now
|
41
|
-
##
|
42
|
-
## in a step two make lookup via hash table
|
43
|
-
## or such easier / "automagic"
|
44
|
-
|
45
|
-
@data[ 'attributes' ].each do |t|
|
46
|
-
trait_type = t['trait_type'].strip
|
47
|
-
trait_value = t['value'].strip
|
48
|
-
traits << [trait_type, trait_value]
|
49
|
-
end
|
50
|
-
|
51
|
-
traits
|
52
|
-
end
|
53
|
-
end
|
54
|
-
alias_method :traits, :attributes ## keep traits alias - why? why not?
|
55
|
-
|
56
|
-
### "private" convenience / helper methods
|
57
|
-
def _normalize( str )
|
58
|
-
return if str.nil? ## check: check for nil - why? why not?
|
59
|
-
|
60
|
-
## normalize string
|
61
|
-
## remove leading and trailing spaces
|
62
|
-
## collapse two and more spaces into one
|
63
|
-
## change unicode space to ascii
|
64
|
-
str = str.gsub( "\u{00a0}", ' ' )
|
65
|
-
str = str.strip.gsub( /[ ]{2,}/, ' ' )
|
66
|
-
str
|
67
|
-
end
|
68
|
-
|
69
|
-
def _blank( o ) ## auto-convert "" (empty string) into nil
|
70
|
-
if o && o.strip.empty?
|
71
|
-
nil
|
72
|
-
else
|
73
|
-
o
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end # (nested) class Meta
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
attr_reader :slug, :count
|
82
|
-
|
83
|
-
def initialize( slug, count,
|
84
|
-
token_base:,
|
85
|
-
image_base: nil,
|
86
|
-
image_base_id_format: nil,
|
87
|
-
format:,
|
88
|
-
source:,
|
89
|
-
top_x: 0,
|
90
|
-
top_y: 0,
|
91
|
-
center_x: true,
|
92
|
-
center_y: true,
|
93
|
-
excludes: [],
|
94
|
-
offset: 0 ) # check: rename count to items or such - why? why not?
|
95
|
-
@slug = slug
|
96
|
-
@count = count
|
97
|
-
@offset = offset ## starting by default at 0 (NOT 1 or such)
|
98
|
-
|
99
|
-
@token_base = token_base
|
100
|
-
@image_base = image_base
|
101
|
-
@image_base_id_format = image_base_id_format
|
102
|
-
|
103
|
-
@width, @height = _parse_dimension( format )
|
104
|
-
|
105
|
-
|
106
|
-
## note: allow multiple source formats / dimensions
|
107
|
-
### e.g. convert 512x512 into [ [512,512] ]
|
108
|
-
##
|
109
|
-
source = [source] unless source.is_a?( Array )
|
110
|
-
@sources = source.map { |dimension| _parse_dimension( dimension ) }
|
111
|
-
|
112
|
-
@top_x = top_x ## more (down)sampling / pixelate options
|
113
|
-
@top_y = top_y
|
114
|
-
@center_x = center_x
|
115
|
-
@center_y = center_y
|
116
|
-
|
117
|
-
@excludes = excludes
|
118
|
-
end
|
119
|
-
|
120
|
-
|
121
|
-
## e.g. convert dimension (width x height) "24x24" or "24 x 24" to [24,24]
|
122
|
-
def _parse_dimension( str )
|
123
|
-
str.split( /x/i ).map { |str| str.strip.to_i }
|
124
|
-
end
|
125
|
-
|
126
|
-
|
127
|
-
def _range( offset: 0 ) ## return "default" range - make "private" helper public - why? why not?
|
128
|
-
## note: range uses three dots (...) exclusive (NOT inclusive) range
|
129
|
-
## e.g. 0...100 => [0,..,99]
|
130
|
-
## 1...101 => [1,..,100]
|
131
|
-
##
|
132
|
-
## note: allow offset argument
|
133
|
-
## (to start with different offset - note: in addition to builtin 0/1 offset)
|
134
|
-
|
135
|
-
(0+@offset+offset...@count+@offset)
|
136
|
-
end
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
def each_image( range=_range,
|
141
|
-
exclude: true, &blk )
|
142
|
-
range.each do |id|
|
143
|
-
####
|
144
|
-
# filter out/skip
|
145
|
-
# if exclude && @excludes.include?( id )
|
146
|
-
# puts " skipping / exclude #{id}..."
|
147
|
-
# next
|
148
|
-
# end
|
149
|
-
|
150
|
-
puts "==> #{id}"
|
151
|
-
img = Image.read( "./#{@slug}/#{@width}x#{@height}/#{id}.png" )
|
152
|
-
blk.call( img, id )
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
|
157
|
-
def each_meta( range=_range,
|
158
|
-
exclude: true, &blk )
|
159
|
-
range.each do |id| ## check: change/rename id to index - why? why not?
|
160
|
-
meta = Meta.read( "./#{@slug}/token/#{id}.json" )
|
161
|
-
|
162
|
-
####
|
163
|
-
# filter out/skip
|
164
|
-
# if exclude && @excludes.include?( meta.name )
|
165
|
-
# puts " skipping / exclude #{id} >#{meta.name}<..."
|
166
|
-
# next
|
167
|
-
# end
|
168
|
-
|
169
|
-
blk.call( meta, id )
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
def pixelate( range=_range, exclude: true,
|
178
|
-
force: false,
|
179
|
-
debug: false,
|
180
|
-
zoom: nil,
|
181
|
-
faster: false )
|
182
|
-
|
183
|
-
range.each do |id|
|
184
|
-
|
185
|
-
if exclude && @excludes.include?( id )
|
186
|
-
puts " skipping #{id}; listed in excludes #{@excludes.inspect}"
|
187
|
-
next
|
188
|
-
end
|
189
|
-
|
190
|
-
outpath = "./#{@slug}/#{@width}x#{@height}/#{id}.png"
|
191
|
-
if !force && File.exist?( outpath )
|
192
|
-
next ## note: skip if file already exists
|
193
|
-
end
|
194
|
-
|
195
|
-
center_x = if @center_x.is_a?( Proc ) then @center_x.call( id ); else @center_x; end
|
196
|
-
center_y = if @center_y.is_a?( Proc ) then @center_y.call( id ); else @center_y; end
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
puts "==> #{id} - reading / decoding #{id} ..."
|
201
|
-
|
202
|
-
|
203
|
-
if faster
|
204
|
-
## note: faster for now only supports
|
205
|
-
## single /one source format
|
206
|
-
## always will use first source format from array for now
|
207
|
-
cmd = "./pixelator "
|
208
|
-
cmd << "./#{@slug}/token-i/#{id}.png"
|
209
|
-
cmd << " " + @sources[0][0].to_s
|
210
|
-
cmd << " " + @sources[0][1].to_s
|
211
|
-
cmd << " " + outpath
|
212
|
-
cmd << " " + @width.to_s
|
213
|
-
cmd << " " + @height.to_s
|
214
|
-
puts "==> #{cmd}..."
|
215
|
-
ret = system( cmd )
|
216
|
-
if ret
|
217
|
-
puts "OK"
|
218
|
-
else
|
219
|
-
puts "!! FAIL"
|
220
|
-
if ret.nil?
|
221
|
-
puts " command not found"
|
222
|
-
else
|
223
|
-
puts " exit code: #{$?}"
|
224
|
-
end
|
225
|
-
end
|
226
|
-
else
|
227
|
-
start = Time.now
|
228
|
-
|
229
|
-
img = Image.read( "./#{@slug}/token-i/#{id}.png" )
|
230
|
-
|
231
|
-
stop = Time.now
|
232
|
-
diff = stop - start
|
233
|
-
|
234
|
-
puts " in #{diff} sec(s)\n"
|
235
|
-
|
236
|
-
|
237
|
-
source = nil
|
238
|
-
@sources.each do |source_width, source_height|
|
239
|
-
if img.width == source_width && img.height == source_height
|
240
|
-
source = [source_width, source_height]
|
241
|
-
break
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
|
246
|
-
if source
|
247
|
-
source_width = source[0]
|
248
|
-
source_height = source[1]
|
249
|
-
|
250
|
-
steps_x = Image.calc_sample_steps( source_width-@top_x, @width, center: center_x )
|
251
|
-
steps_y = Image.calc_sample_steps( source_height-@top_y, @height, center: center_y )
|
252
|
-
|
253
|
-
pix = if debug
|
254
|
-
img.pixelate_debug( steps_x, steps_y,
|
255
|
-
top_x: @top_x,
|
256
|
-
top_y: @top_y )
|
257
|
-
else
|
258
|
-
img.pixelate( steps_x, steps_y,
|
259
|
-
top_x: @top_x,
|
260
|
-
top_y: @top_y )
|
261
|
-
end
|
262
|
-
## todo/check: keep usingu slug e.g. 0001.png or "plain" 1.png - why? why not?
|
263
|
-
## slug = "%04d" % id
|
264
|
-
pix.save( outpath )
|
265
|
-
|
266
|
-
if zoom
|
267
|
-
outpath = "./#{@slug}/#{@width}x#{@height}/#{id}@#{zoom}x.png"
|
268
|
-
pix.zoom( zoom ).save( outpath )
|
269
|
-
end
|
270
|
-
else
|
271
|
-
puts "!! ERROR - unknown/unsupported dimension - #{img.width}x#{img.height}; sorry - tried:"
|
272
|
-
pp @sources
|
273
|
-
exit 1
|
274
|
-
end
|
275
|
-
end
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
def meta_url( id: )
|
282
|
-
src = @token_base.gsub( '{id}', id.to_s )
|
283
|
-
|
284
|
-
## quick ipfs (interplanetary file system) hack - make more reusabele!!!
|
285
|
-
src = handle_ipfs( src )
|
286
|
-
src
|
287
|
-
end
|
288
|
-
alias_method :token_url, :meta_url
|
289
|
-
|
290
|
-
|
291
|
-
def image_url( id:,
|
292
|
-
direct: @image_base ? true : false )
|
293
|
-
src = if direct && @image_base
|
294
|
-
###
|
295
|
-
## todo/fix:
|
296
|
-
## change image_base_id_format
|
297
|
-
## to image_base proc with para id and call proc!!!!
|
298
|
-
if @image_base_id_format
|
299
|
-
@image_base.gsub( '{id}', @image_base_id_format % id )
|
300
|
-
else
|
301
|
-
@image_base.gsub( '{id}', id.to_s )
|
302
|
-
end
|
303
|
-
else
|
304
|
-
## todo/check - change/rename data to meta - why? why not?
|
305
|
-
data = Meta.read( "./#{@slug}/token/#{id}.json" )
|
306
|
-
|
307
|
-
meta_name = data.name
|
308
|
-
meta_image = data.image
|
309
|
-
|
310
|
-
puts "==> #{id} - #{@slug}..."
|
311
|
-
puts " name: #{meta_name}"
|
312
|
-
puts " image: #{meta_image}"
|
313
|
-
meta_image
|
314
|
-
end
|
315
|
-
src
|
316
|
-
|
317
|
-
## quick ipfs (interplanetary file system) hack - make more reusabele!!!
|
318
|
-
src = handle_ipfs( src )
|
319
|
-
src
|
320
|
-
end
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
def download_meta( range=_range, force: false )
|
325
|
-
start = Time.now
|
326
|
-
delay_in_s = 0.3
|
327
|
-
|
328
|
-
range.each do |id|
|
329
|
-
outpath = "./#{@slug}/token/#{id}.json"
|
330
|
-
if !force && File.exist?( outpath )
|
331
|
-
next ## note: skip if file already exists
|
332
|
-
end
|
333
|
-
|
334
|
-
dirname = File.dirname( outpath )
|
335
|
-
FileUtils.mkdir_p( dirname ) unless Dir.exist?( dirname )
|
336
|
-
|
337
|
-
puts "==> #{id} - #{@slug}..."
|
338
|
-
|
339
|
-
token_src = meta_url( id: id )
|
340
|
-
copy_json( token_src, outpath )
|
341
|
-
|
342
|
-
stop = Time.now
|
343
|
-
diff = stop - start
|
344
|
-
puts " download token metadata in #{diff} sec(s)"
|
345
|
-
|
346
|
-
mins = diff / 60 ## todo - use floor or such?
|
347
|
-
secs = diff % 60
|
348
|
-
puts "up #{mins} mins #{secs} secs (total #{diff} secs)"
|
349
|
-
|
350
|
-
puts "sleeping #{delay_in_s}s..."
|
351
|
-
sleep( delay_in_s )
|
352
|
-
end
|
353
|
-
end
|
354
|
-
|
355
|
-
|
356
|
-
## note: default to direct true if image_base present/availabe
|
357
|
-
## otherwise to false
|
358
|
-
## todo/check: change/rename force para to overwrite - why? why not?
|
359
|
-
def download_images( range=_range, force: false,
|
360
|
-
direct: @image_base ? true : false )
|
361
|
-
start = Time.now
|
362
|
-
delay_in_s = 0.3
|
363
|
-
|
364
|
-
range.each do |id|
|
365
|
-
|
366
|
-
## note: skip if (downloaded) file already exists
|
367
|
-
skip = false
|
368
|
-
if !force
|
369
|
-
['png', 'gif', 'jgp', 'svg'].each do |format|
|
370
|
-
if File.exist?( "./#{@slug}/token-i/#{id}.#{format}" )
|
371
|
-
skip = true
|
372
|
-
break
|
373
|
-
end
|
374
|
-
end
|
375
|
-
end
|
376
|
-
next if skip
|
377
|
-
|
378
|
-
image_src = image_url( id: id, direct: direct )
|
379
|
-
|
380
|
-
## note: will auto-add format file extension (e.g. .png, .jpg)
|
381
|
-
## depending on http content type!!!!!
|
382
|
-
start_copy = Time.now
|
383
|
-
copy_image( image_src, "./#{@slug}/token-i/#{id}" )
|
384
|
-
|
385
|
-
stop = Time.now
|
386
|
-
|
387
|
-
diff = stop - start_copy
|
388
|
-
puts " download image in #{diff} sec(s)"
|
389
|
-
|
390
|
-
diff = stop - start
|
391
|
-
mins = diff / 60 ## todo - use floor or such?
|
392
|
-
secs = diff % 60
|
393
|
-
puts "up #{mins} mins #{secs} secs (total #{diff} secs)"
|
394
|
-
|
395
|
-
puts "sleeping #{delay_in_s}s..."
|
396
|
-
sleep( delay_in_s )
|
397
|
-
end
|
398
|
-
end
|
399
|
-
|
400
|
-
end # class TokenCollection
|
data/lib/artbase/collection.rb
DELETED
data/lib/artbase/helper.rb
DELETED
@@ -1,169 +0,0 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
def slugify( name )
|
5
|
-
name.downcase.gsub( /[^a-z0-9 ()$_-]/ ) do |_|
|
6
|
-
puts " !! WARN: asciify - found (and removing) non-ascii char >#{Regexp.last_match}<"
|
7
|
-
'' ## remove - use empty string
|
8
|
-
end.gsub( ' ', '_')
|
9
|
-
end
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
=begin
|
14
|
-
moved/ use Image.convert !!! remove here
|
15
|
-
def convert_images( collection, from: 'jpg',
|
16
|
-
to: 'png',
|
17
|
-
dir: 'i',
|
18
|
-
overwrite: true )
|
19
|
-
files = Dir.glob( "./#{collection}/#{dir}/*.#{from}" )
|
20
|
-
puts "==> converting #{files.size} image(s) from #{from} to #{to}"
|
21
|
-
|
22
|
-
files.each_with_index do |file,i|
|
23
|
-
dirname = File.dirname( file )
|
24
|
-
extname = File.extname( file )
|
25
|
-
basename = File.basename( file, extname )
|
26
|
-
|
27
|
-
## skip convert if target / dest file already exists
|
28
|
-
next if overwrite == false && File.exist?( "#{dirname}/#{basename}.#{to}" )
|
29
|
-
|
30
|
-
|
31
|
-
cmd = "magick convert #{dirname}/#{basename}.#{from} #{dirname}/#{basename}.#{to}"
|
32
|
-
|
33
|
-
puts " [#{i+1}/#{files.size}] - #{cmd}"
|
34
|
-
system( cmd )
|
35
|
-
|
36
|
-
if from == 'gif'
|
37
|
-
## assume multi-images for gif
|
38
|
-
## save image-0.png to image.png
|
39
|
-
path0 = "#{dirname}/#{basename}-0.#{to}"
|
40
|
-
path = "#{dirname}/#{basename}.#{to}"
|
41
|
-
|
42
|
-
puts " saving #{path0} to #{path}..."
|
43
|
-
|
44
|
-
blob = File.open( path0, 'rb' ) { |f| f.read }
|
45
|
-
File.open( path, 'wb' ) { |f| f.write( blob ) }
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
=end
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
def copy_json( src, dest )
|
58
|
-
uri = URI.parse( src )
|
59
|
-
|
60
|
-
http = Net::HTTP.new( uri.host, uri.port )
|
61
|
-
|
62
|
-
puts "[debug] GET #{uri.request_uri} uri=#{uri}"
|
63
|
-
|
64
|
-
headers = { 'User-Agent' => "ruby v#{RUBY_VERSION}" }
|
65
|
-
|
66
|
-
|
67
|
-
request = Net::HTTP::Get.new( uri.request_uri, headers )
|
68
|
-
if uri.instance_of? URI::HTTPS
|
69
|
-
http.use_ssl = true
|
70
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
71
|
-
end
|
72
|
-
|
73
|
-
response = http.request( request )
|
74
|
-
|
75
|
-
if response.code == '200'
|
76
|
-
puts "#{response.code} #{response.message}"
|
77
|
-
puts " content_type: #{response.content_type}, content_length: #{response.content_length}"
|
78
|
-
|
79
|
-
text = response.body.to_s
|
80
|
-
text = text.force_encoding( Encoding::UTF_8 )
|
81
|
-
|
82
|
-
data = JSON.parse( text )
|
83
|
-
|
84
|
-
File.open( dest, "w:utf-8" ) do |f|
|
85
|
-
f.write( JSON.pretty_generate( data ) )
|
86
|
-
end
|
87
|
-
else
|
88
|
-
puts "!! error:"
|
89
|
-
puts "#{response.code} #{response.message}"
|
90
|
-
exit 1
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
|
95
|
-
def copy_image( src, dest,
|
96
|
-
dump_headers: false )
|
97
|
-
uri = URI.parse( src )
|
98
|
-
|
99
|
-
http = Net::HTTP.new( uri.host, uri.port )
|
100
|
-
|
101
|
-
puts "[debug] GET #{uri.request_uri} uri=#{uri}"
|
102
|
-
|
103
|
-
headers = { 'User-Agent' => "ruby v#{RUBY_VERSION}" }
|
104
|
-
|
105
|
-
request = Net::HTTP::Get.new( uri.request_uri, headers )
|
106
|
-
if uri.instance_of? URI::HTTPS
|
107
|
-
http.use_ssl = true
|
108
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
109
|
-
end
|
110
|
-
|
111
|
-
response = http.request( request )
|
112
|
-
|
113
|
-
if response.code == '200'
|
114
|
-
puts "#{response.code} #{response.message}"
|
115
|
-
|
116
|
-
content_type = response.content_type
|
117
|
-
content_length = response.content_length
|
118
|
-
puts " content_type: #{content_type}, content_length: #{content_length}"
|
119
|
-
|
120
|
-
if dump_headers ## for debugging dump headers
|
121
|
-
headers = response.each_header.to_h
|
122
|
-
puts "htttp respone headers:"
|
123
|
-
pp headers
|
124
|
-
end
|
125
|
-
|
126
|
-
|
127
|
-
format = if content_type =~ %r{image/jpeg}i
|
128
|
-
'jpg'
|
129
|
-
elsif content_type =~ %r{image/png}i
|
130
|
-
'png'
|
131
|
-
elsif content_type =~ %r{image/gif}i
|
132
|
-
'gif'
|
133
|
-
elsif content_type =~ %r{image/svg}i
|
134
|
-
'svg'
|
135
|
-
else
|
136
|
-
puts "!! error:"
|
137
|
-
puts " unknown image format content type: >#{content_type}<"
|
138
|
-
exit 1
|
139
|
-
end
|
140
|
-
|
141
|
-
## make sure path exits - autocreate dirs
|
142
|
-
## make sure path exists
|
143
|
-
dirname = File.dirname( "#{dest}.#{format}" )
|
144
|
-
FileUtils.mkdir_p( dirname ) unless Dir.exist?( dirname )
|
145
|
-
|
146
|
-
if format == 'svg'
|
147
|
-
## save as text (note: assume utf-8 encoding for now)
|
148
|
-
text = response.body.to_s
|
149
|
-
text = text.force_encoding( Encoding::UTF_8 )
|
150
|
-
|
151
|
-
File.open( "#{dest}.svg", 'w:utf-8' ) do |f|
|
152
|
-
f.write( text )
|
153
|
-
end
|
154
|
-
else
|
155
|
-
## save as binary
|
156
|
-
File.open( "#{dest}.#{format}", 'wb' ) do |f|
|
157
|
-
f.write( response.body )
|
158
|
-
end
|
159
|
-
end
|
160
|
-
else
|
161
|
-
puts "!! error:"
|
162
|
-
puts "#{response.code} #{response.message}"
|
163
|
-
exit 1
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
data/lib/artbase/image/sample.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
module Pixelart
|
2
|
-
|
3
|
-
class Image
|
4
|
-
|
5
|
-
###
|
6
|
-
# add common
|
7
|
-
# pixel(ate) steps/offsets (for re/down/sampling)
|
8
|
-
DOwNSAMPLING_STEPS = {
|
9
|
-
'24x24' => {
|
10
|
-
'269x269' => Image.calc_sample_steps( 269, 24 ), # width (269px), new_width (24px)
|
11
|
-
'512x512' => Image.calc_sample_steps( 512, 24 ), # width (512px), new_width (24px)
|
12
|
-
},
|
13
|
-
'32x32' => {
|
14
|
-
'320x320' => Image.calc_sample_steps( 320, 32 ),
|
15
|
-
'512x512' => Image.calc_sample_steps( 512, 32 ),
|
16
|
-
},
|
17
|
-
'35x35' => {
|
18
|
-
'512x512' => Image.calc_sample_steps( 512, 35 ),
|
19
|
-
},
|
20
|
-
'60x60' => {
|
21
|
-
'512x512' => Image.calc_sample_steps( 512, 60 ),
|
22
|
-
},
|
23
|
-
'80x80' => {
|
24
|
-
'512x512' => Image.calc_sample_steps( 512, 80 ),
|
25
|
-
},
|
26
|
-
}
|
27
|
-
|
28
|
-
end # class Image
|
29
|
-
end # module Pixelart
|
30
|
-
|
31
|
-
|
data/lib/artbase/image.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
######################
|
2
|
-
# pixelart image extensions
|
3
|
-
# move upstream!!!!!
|
4
|
-
|
5
|
-
|
6
|
-
module Pixelart
|
7
|
-
class ImageComposite
|
8
|
-
def add_glob( glob )
|
9
|
-
files = Dir.glob( glob )
|
10
|
-
puts "#{files.size} file(s) found matching >#{glob}<"
|
11
|
-
|
12
|
-
|
13
|
-
files = files.sort
|
14
|
-
## puts files.inspect
|
15
|
-
|
16
|
-
files.each_with_index do |file,i|
|
17
|
-
puts "==> [#{i+1}/#{files.size}] - #{file}"
|
18
|
-
img = Image.read( file )
|
19
|
-
|
20
|
-
self << img ## todo/check: use add alias - why? why not?
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end # class ImageComposite
|
24
|
-
end # module Pixelart
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
require_relative 'image/sample' ## check - change to downsample/pixelate - why? why not?
|
29
|
-
|
30
|
-
|
31
|
-
|
data/lib/artbase/retry.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
|
2
|
-
## for more ideas on retry
|
3
|
-
## see https://github.com/ooyala/retries
|
4
|
-
|
5
|
-
|
6
|
-
## todo/check: use a different name than retry - why? why not?
|
7
|
-
def retry_on_error( max_tries: 3, &block )
|
8
|
-
errors = []
|
9
|
-
delay = 3 ## 3 secs
|
10
|
-
|
11
|
-
begin
|
12
|
-
block.call
|
13
|
-
|
14
|
-
## note: add more exception here (separated by comma) like
|
15
|
-
## rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED => e
|
16
|
-
rescue Net::ReadTimeout => e
|
17
|
-
## (re)raise (use raise with arguments or such - why? why not?)
|
18
|
-
raise if errors.size >= max_tries
|
19
|
-
|
20
|
-
## ReadTimeout, a subclass of Timeout::Error, is raised if a chunk of the response cannot be read within the read_timeout.
|
21
|
-
## subclass of RuntimeError
|
22
|
-
## subclass of StandardError
|
23
|
-
## subclass of Exception
|
24
|
-
puts "!! ERROR - #{e}:"
|
25
|
-
pp e
|
26
|
-
|
27
|
-
errors << e
|
28
|
-
|
29
|
-
puts
|
30
|
-
puts "==> retrying (count=#{errors.size}, max_tries=#{max_tries}) in #{delay} sec(s)..."
|
31
|
-
sleep( delay )
|
32
|
-
retry
|
33
|
-
end
|
34
|
-
|
35
|
-
if errors.size > 0
|
36
|
-
puts " #{errors.size} retry attempt(s) on error(s):"
|
37
|
-
pp errors
|
38
|
-
end
|
39
|
-
|
40
|
-
errors
|
41
|
-
end
|