artbase 0.2.2 → 0.3.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 +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,39 +0,0 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
class ImageCollection
|
4
|
-
|
5
|
-
attr_reader :slug, :count
|
6
|
-
|
7
|
-
def initialize( slug, count,
|
8
|
-
image_base: ) # check: rename count to items or such - why? why not?
|
9
|
-
@slug = slug
|
10
|
-
@count = count
|
11
|
-
@image_base = image_base
|
12
|
-
end
|
13
|
-
|
14
|
-
def download_images( range=(0...@count) )
|
15
|
-
start = Time.now
|
16
|
-
delay_in_s = 0.3
|
17
|
-
|
18
|
-
range.each do |offset|
|
19
|
-
image_src = @image_base.sub( '{id}', offset.to_s )
|
20
|
-
|
21
|
-
puts "==> #{offset} - #{@slug}..."
|
22
|
-
|
23
|
-
## note: will auto-add format file extension (e.g. .png, .jpg)
|
24
|
-
## depending on http content type!!!!!
|
25
|
-
copy_image( image_src, "./#{@slug}/image-i/#{offset}" )
|
26
|
-
|
27
|
-
stop = Time.now
|
28
|
-
diff = stop - start
|
29
|
-
|
30
|
-
mins = diff / 60 ## todo - use floor or such?
|
31
|
-
secs = diff % 60
|
32
|
-
puts "up #{mins} mins #{secs} secs (total #{diff} secs)"
|
33
|
-
|
34
|
-
puts "sleeping #{delay_in_s}s..."
|
35
|
-
sleep( delay_in_s )
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end # class ImageCollection
|
39
|
-
|
@@ -1,297 +0,0 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
class Collection ## todo/check - change to OpenseaCollection or such - why? why not?
|
4
|
-
|
5
|
-
attr_reader :slug, :count
|
6
|
-
|
7
|
-
# check: rename count to items or such - why? why not?
|
8
|
-
# default format to '24x24' - why? why not?
|
9
|
-
def initialize( slug, count,
|
10
|
-
meta_slugify: nil,
|
11
|
-
image_pixelate: nil,
|
12
|
-
patch: nil,
|
13
|
-
exclude: [],
|
14
|
-
format:,
|
15
|
-
source: )
|
16
|
-
@slug = slug
|
17
|
-
@count = count
|
18
|
-
|
19
|
-
@meta_slugify = meta_slugify
|
20
|
-
@image_pixelate = image_pixelate
|
21
|
-
|
22
|
-
@patch = patch
|
23
|
-
|
24
|
-
@exclude = exclude
|
25
|
-
|
26
|
-
@width, @height = _parse_dimension( format )
|
27
|
-
|
28
|
-
|
29
|
-
## note: allow multiple source formats / dimensions
|
30
|
-
### e.g. convert 512x512 into [ [512,512] ]
|
31
|
-
##
|
32
|
-
source = [source] unless source.is_a?( Array )
|
33
|
-
@sources = source.map { |dimension| _parse_dimension( dimension ) }
|
34
|
-
end
|
35
|
-
|
36
|
-
## e.g. convert dimension (width x height) "24x24" or "24 x 24" to [24,24]
|
37
|
-
def _parse_dimension( str )
|
38
|
-
str.split( /x/i ).map { |str| str.strip.to_i }
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
def _image_pixelate( img )
|
43
|
-
if @image_pixelate
|
44
|
-
@image_pixelate.call( img )
|
45
|
-
else
|
46
|
-
@sources.each do |source_width, source_height|
|
47
|
-
if img.width == source_width && img.height == source_height
|
48
|
-
from = "#{source_width}x#{source_height}"
|
49
|
-
to = "#{@width}x#{@height}"
|
50
|
-
steps = (Image::DOwNSAMPLING_STEPS[ to ] || {})[ from ]
|
51
|
-
if steps.nil?
|
52
|
-
puts "!! ERROR - no sampling steps defined for #{from} to #{to}; sorry"
|
53
|
-
exit 1
|
54
|
-
end
|
55
|
-
|
56
|
-
return img.pixelate( steps )
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
puts "!! ERROR - unknown image dimension #{img.width}x#{img.height}; sorry"
|
61
|
-
puts " supported source dimensions include: #{@sources.inspect}"
|
62
|
-
exit 1
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
def download_meta( range=(0...@count) )
|
70
|
-
self.class.download_meta( range, @slug )
|
71
|
-
end
|
72
|
-
|
73
|
-
def download_images( range=(0...@count) )
|
74
|
-
self.class.download_images( range, @slug )
|
75
|
-
end
|
76
|
-
|
77
|
-
def download( range=(0...@count) )
|
78
|
-
download_meta( range )
|
79
|
-
download_images( range )
|
80
|
-
end
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
def _meta_slugify_match( regex, meta, index )
|
87
|
-
if m=regex.match( meta.name )
|
88
|
-
captures = m.named_captures ## get named captures in match data as hash (keys as strings)
|
89
|
-
# e.g.
|
90
|
-
#=> {"num"=>"3"}
|
91
|
-
#=> {"num"=>"498", "name"=>"Doge"}
|
92
|
-
pp captures
|
93
|
-
|
94
|
-
num = captures['num'] ? captures['num'].to_i( 10 ) : nil ## note: add base 10 (e.g. 015=>15)
|
95
|
-
name = captures['name'] ? captures['name'].strip : nil
|
96
|
-
|
97
|
-
slug = ''
|
98
|
-
if num
|
99
|
-
slug << "%06d" % num ## todo/check: always fill/zero-pad with six 000000's - why? why not?
|
100
|
-
end
|
101
|
-
|
102
|
-
if name
|
103
|
-
slug << "-" if num ## add separator
|
104
|
-
slug << slugify( name )
|
105
|
-
end
|
106
|
-
slug
|
107
|
-
else
|
108
|
-
nil ## note: return nil if no match / slug
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def _do_meta_slugify( meta_slugify, meta, index )
|
113
|
-
if meta_slugify.is_a?( Regexp )
|
114
|
-
_meta_slugify_match( meta_slugify, meta, index )
|
115
|
-
elsif meta_slugify.is_a?( Proc )
|
116
|
-
meta_slugify.call( meta, index )
|
117
|
-
else
|
118
|
-
raise ArgumentError, "meta_slugify - unsupported type: #{meta_slugify.class.name}"
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
|
123
|
-
def _meta_slugify( meta, index )
|
124
|
-
slug = nil
|
125
|
-
|
126
|
-
if @meta_slugify.is_a?( Array )
|
127
|
-
@meta_slugify.each do |meta_slugify|
|
128
|
-
slug = _do_meta_slugify( meta_slugify, meta, index )
|
129
|
-
return slug if slug ## note: short-circuit on first match
|
130
|
-
## use break instead of return - why? why not?
|
131
|
-
end
|
132
|
-
else ## assume object e.g. Regexp, Proc, etc.
|
133
|
-
slug = _do_meta_slugify( @meta_slugify, meta, index )
|
134
|
-
end
|
135
|
-
|
136
|
-
## do nothing
|
137
|
-
if slug.nil?
|
138
|
-
puts "!! ERROR - cannot find id in >#{meta.name}<:"
|
139
|
-
pp meta
|
140
|
-
exit 1
|
141
|
-
end
|
142
|
-
|
143
|
-
slug
|
144
|
-
end
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
def each_meta( range=(0...@count),
|
149
|
-
exclude: true, &blk )
|
150
|
-
range.each do |id| ## todo/fix: change id to index
|
151
|
-
meta = OpenSea::Meta.read( "./#{@slug}/meta/#{id}.json" )
|
152
|
-
|
153
|
-
####
|
154
|
-
# filter out/skip
|
155
|
-
if exclude && @exclude.include?( meta.name )
|
156
|
-
puts " skipping / exclude #{id} >#{meta.name}<..."
|
157
|
-
next
|
158
|
-
end
|
159
|
-
|
160
|
-
blk.call( meta, id )
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
def pixelate( range=(0...@count) )
|
168
|
-
|
169
|
-
meta_slugs = Hash.new( 0 ) ## deduplicate (auto-add counter if duplicate)
|
170
|
-
|
171
|
-
### todo/fix: must read slugs starting at 0
|
172
|
-
### to work for deduplicate!!!!!!
|
173
|
-
|
174
|
-
|
175
|
-
range.each do |id|
|
176
|
-
meta = OpenSea::Meta.read( "./#{@slug}/meta/#{id}.json" )
|
177
|
-
|
178
|
-
####
|
179
|
-
# filter out/skip
|
180
|
-
if @exclude.include?( meta.name )
|
181
|
-
puts " skipping / exclude #{id} >#{meta.name}<..."
|
182
|
-
next
|
183
|
-
end
|
184
|
-
|
185
|
-
puts meta.name
|
186
|
-
|
187
|
-
|
188
|
-
meta_slug = _meta_slugify( meta, id )
|
189
|
-
count = meta_slugs[ meta_slug ] += 1
|
190
|
-
|
191
|
-
meta_slug = "#{meta_slug}_(#{count})" if count > 1
|
192
|
-
|
193
|
-
|
194
|
-
img = Image.read( "./#{@slug}/i/#{id}.png" )
|
195
|
-
|
196
|
-
pix = _image_pixelate( img )
|
197
|
-
|
198
|
-
path = "./#{@slug}/ii/#{meta_slug}.png"
|
199
|
-
puts " saving to >#{path}<..."
|
200
|
-
pix.save( path )
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
################################
|
207
|
-
# private (static) helpers
|
208
|
-
#
|
209
|
-
|
210
|
-
def self.download_images( range, collection,
|
211
|
-
original: false )
|
212
|
-
start = Time.now
|
213
|
-
delay_in_s = 0.3
|
214
|
-
|
215
|
-
range.each do |offset|
|
216
|
-
meta = OpenSea::Meta.read( "./#{collection}/meta/#{offset}.json" )
|
217
|
-
|
218
|
-
puts "==> #{offset}.json - #{meta.name}"
|
219
|
-
|
220
|
-
image_src = if original
|
221
|
-
meta.image_original_url
|
222
|
-
else
|
223
|
-
meta.image_url
|
224
|
-
end
|
225
|
-
|
226
|
-
puts " >#{image_src}<"
|
227
|
-
if image_src.nil?
|
228
|
-
puts "!! ERROR - no image url found (use original: #{original}):"
|
229
|
-
pp meta
|
230
|
-
exit 1
|
231
|
-
end
|
232
|
-
|
233
|
-
## note: use a different directory to avoid size confusion!!!
|
234
|
-
img_slug = if original
|
235
|
-
'i_org'
|
236
|
-
else
|
237
|
-
'i'
|
238
|
-
end
|
239
|
-
|
240
|
-
## note: will auto-add format file extension (e.g. .png, .jpg)
|
241
|
-
## depending on http content type!!!!!
|
242
|
-
copy_image( image_src, "./#{collection}/#{img_slug}/#{offset}" )
|
243
|
-
|
244
|
-
stop = Time.now
|
245
|
-
diff = stop - start
|
246
|
-
|
247
|
-
mins = diff / 60 ## todo - use floor or such?
|
248
|
-
secs = diff % 60
|
249
|
-
puts "up #{mins} mins #{secs} secs (total #{diff} secs)"
|
250
|
-
|
251
|
-
puts "sleeping #{delay_in_s}s..."
|
252
|
-
sleep( delay_in_s )
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
|
257
|
-
def self.download_meta( range, collection )
|
258
|
-
start = Time.now
|
259
|
-
delay_in_s = 0.3
|
260
|
-
|
261
|
-
range.each do |offset|
|
262
|
-
|
263
|
-
dest = "./#{collection}/meta/#{offset}.json"
|
264
|
-
meta = nil
|
265
|
-
|
266
|
-
puts "==> #{offset} / #{collection} (#{dest})..."
|
267
|
-
|
268
|
-
data = OpenSea.assets( collection: collection,
|
269
|
-
offset: offset )
|
270
|
-
meta = OpenSea::Meta.new( data )
|
271
|
-
puts " name: >#{meta.name}<"
|
272
|
-
puts " image_url: >#{meta.image_url}<"
|
273
|
-
|
274
|
-
|
275
|
-
## make sure path exists
|
276
|
-
dirname = File.dirname( dest )
|
277
|
-
FileUtils.mkdir_p( dirname ) unless Dir.exist?( dirname )
|
278
|
-
|
279
|
-
File.open( dest, "w:utf-8" ) do |f|
|
280
|
-
f.write( JSON.pretty_generate( data ) )
|
281
|
-
end
|
282
|
-
|
283
|
-
|
284
|
-
stop = Time.now
|
285
|
-
diff = stop - start
|
286
|
-
|
287
|
-
mins = diff / 60 ## todo - use floor or such?
|
288
|
-
secs = diff % 60
|
289
|
-
puts "up #{mins} mins #{secs} secs (total #{diff} secs)"
|
290
|
-
|
291
|
-
puts " sleeping #{delay_in_s}s..."
|
292
|
-
sleep( delay_in_s )
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
|
297
|
-
end # class Collection
|