artbase 0.1.0 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -3
- data/Manifest.txt +3 -6
- data/README.md +272 -39
- data/Rakefile +40 -29
- data/bin/artbase +17 -17
- data/lib/artbase/attributes.rb +83 -83
- data/lib/artbase/collection/base.rb +329 -0
- data/lib/artbase/collection/image.rb +39 -39
- data/lib/artbase/collection/opensea.rb +297 -484
- data/lib/artbase/collection/token.rb +400 -72
- data/lib/artbase/collection.rb +12 -12
- data/lib/artbase/helper.rb +169 -149
- data/lib/artbase/image/sample.rb +31 -0
- data/lib/artbase/image.rb +31 -75
- data/lib/artbase/retry.rb +41 -0
- data/lib/artbase/tool.rb +220 -159
- data/lib/artbase/version.rb +21 -22
- data/lib/artbase.rb +78 -42
- metadata +50 -12
- data/LICENSE.md +0 -116
- data/lib/artbase/image/24x24.rb +0 -68
- data/lib/artbase/image/32x32.rb +0 -43
- data/lib/artbase/image/60x60.rb +0 -70
- data/lib/artbase/image/80x80.rb +0 -90
- data/lib/artbase/opensea.rb +0 -144
data/lib/artbase/helper.rb
CHANGED
@@ -1,149 +1,169 @@
|
|
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
files.
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
if
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
if
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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
|
+
|
@@ -0,0 +1,31 @@
|
|
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
CHANGED
@@ -1,75 +1,31 @@
|
|
1
|
-
######################
|
2
|
-
# pixelart image extensions
|
3
|
-
# move upstream!!!!!
|
4
|
-
|
5
|
-
|
6
|
-
module Pixelart
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
dest
|
34
|
-
end
|
35
|
-
alias_method :pixelate, :sample
|
36
|
-
end # class Image
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
class ImageComposite
|
41
|
-
def add_glob( glob )
|
42
|
-
files = Dir.glob( glob )
|
43
|
-
puts "#{files.size} file(s) found matching >#{glob}<"
|
44
|
-
|
45
|
-
|
46
|
-
files = files.sort
|
47
|
-
## puts files.inspect
|
48
|
-
|
49
|
-
files.each_with_index do |file,i|
|
50
|
-
puts "==> [#{i+1}/#{files.size}] - #{file}"
|
51
|
-
img = Image.read( file )
|
52
|
-
|
53
|
-
self << img ## todo/check: use add alias - why? why not?
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end # class ImageComposite
|
57
|
-
end # module Pixelart
|
58
|
-
|
59
|
-
|
60
|
-
###
|
61
|
-
# add common
|
62
|
-
# pixel(ate) offsets (for sampling)
|
63
|
-
PIXEL_OFFSETS = {}
|
64
|
-
|
65
|
-
module Pixelart
|
66
|
-
class Image
|
67
|
-
PIXEL_OFFSETS = ::PIXEL_OFFSETS
|
68
|
-
end
|
69
|
-
end # module Pixelart
|
70
|
-
|
71
|
-
|
72
|
-
require_relative 'image/24x24'
|
73
|
-
require_relative 'image/32x32'
|
74
|
-
require_relative 'image/60x60'
|
75
|
-
require_relative 'image/80x80'
|
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
|
+
|
@@ -0,0 +1,41 @@
|
|
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
|