artbase 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,68 @@
1
+
2
+
3
+ PIXEL_OFFSETS['24x24'] = {
4
+ ######################
5
+ # 269x269 (24x24)
6
+ # assume 11px per pixel 11x24 = 264 + 5 = 269
7
+ #
8
+ # e.g. 24.times {|i| puts "#{(5+i*11+5.0/24.0*i).to_i} => #{i}," }
9
+ '269x269' => {
10
+ 5 => 0,
11
+ 16 => 1,
12
+ 27 => 2,
13
+ 38 => 3,
14
+ 49 => 4,
15
+ 61 => 5,
16
+ 72 => 6,
17
+ 83 => 7,
18
+ 94 => 8,
19
+ 105 => 9,
20
+ 117 => 10,
21
+ 128 => 11,
22
+ 139 => 12,
23
+ 150 => 13,
24
+ 161 => 14,
25
+ 173 => 15,
26
+ 184 => 16,
27
+ 195 => 17,
28
+ 206 => 18,
29
+ 217 => 19,
30
+ 229 => 20,
31
+ 240 => 21,
32
+ 251 => 22,
33
+ 262 => 23,
34
+ },
35
+
36
+
37
+ ######################
38
+ # 512x512 (24x24)
39
+ # assume 21px per pixel 21x24 = 504 + 8 = 512
40
+ #
41
+ # e.g. 24.times {|i| puts "#{(12+i*21+8.0/24.0*i).to_i} => #{i}," }
42
+ '512x512' => {
43
+ 12 => 0,
44
+ 33 => 1,
45
+ 54 => 2,
46
+ 76 => 3,
47
+ 97 => 4,
48
+ 118 => 5,
49
+ 140 => 6,
50
+ 161 => 7,
51
+ 182 => 8,
52
+ 204 => 9,
53
+ 225 => 10,
54
+ 246 => 11,
55
+ 268 => 12,
56
+ 289 => 13,
57
+ 310 => 14,
58
+ 332 => 15,
59
+ 353 => 16,
60
+ 374 => 17,
61
+ 396 => 18,
62
+ 417 => 19,
63
+ 438 => 20,
64
+ 460 => 21,
65
+ 481 => 22,
66
+ 502 => 23,
67
+ },
68
+ }
@@ -0,0 +1,43 @@
1
+
2
+ PIXEL_OFFSETS['32x32'] = {
3
+ ######################
4
+ # 320x320 (32x32)
5
+ # assume 10px per pixel 10x32 = 320
6
+ #
7
+ # e.g. 32.times {|i| puts "#{5+i*10} => #{i}," }
8
+ '320x320' => {
9
+ 5 => 0,
10
+ 15 => 1,
11
+ 25 => 2,
12
+ 35 => 3,
13
+ 45 => 4,
14
+ 55 => 5,
15
+ 65 => 6,
16
+ 75 => 7,
17
+ 85 => 8,
18
+ 95 => 9,
19
+ 105 => 10,
20
+ 115 => 11,
21
+ 125 => 12,
22
+ 135 => 13,
23
+ 145 => 14,
24
+ 155 => 15,
25
+ 165 => 16,
26
+ 175 => 17,
27
+ 185 => 18,
28
+ 195 => 19,
29
+ 205 => 20,
30
+ 215 => 21,
31
+ 225 => 22,
32
+ 235 => 23,
33
+ 245 => 24,
34
+ 255 => 25,
35
+ 265 => 26,
36
+ 275 => 27,
37
+ 285 => 28,
38
+ 295 => 29,
39
+ 305 => 30,
40
+ 315 => 31,
41
+ },
42
+ }
43
+
@@ -0,0 +1,70 @@
1
+
2
+ PIXEL_OFFSETS['60x60'] = {
3
+ '512x512' => {
4
+ ###########
5
+ # 512x512 (60x60)
6
+ # assume 8px 60*8 = 480 + 32 = 512
7
+ #
8
+ # e.g. 60.times {|i| puts "#{(4+i*8+32.0/60.0*i).to_i} => #{i}," }
9
+ 4 => 0,
10
+ 12 => 1,
11
+ 21 => 2,
12
+ 29 => 3,
13
+ 38 => 4,
14
+ 46 => 5,
15
+ 55 => 6,
16
+ 63 => 7,
17
+ 72 => 8,
18
+ 80 => 9,
19
+ 89 => 10,
20
+ 97 => 11,
21
+ 106 => 12,
22
+ 114 => 13,
23
+ 123 => 14,
24
+ 132 => 15,
25
+ 140 => 16,
26
+ 149 => 17,
27
+ 157 => 18,
28
+ 166 => 19,
29
+ 174 => 20,
30
+ 183 => 21,
31
+ 191 => 22,
32
+ 200 => 23,
33
+ 208 => 24,
34
+ 217 => 25,
35
+ 225 => 26,
36
+ 234 => 27,
37
+ 242 => 28,
38
+ 251 => 29,
39
+ 260 => 30,
40
+ 268 => 31,
41
+ 277 => 32,
42
+ 285 => 33,
43
+ 294 => 34,
44
+ 302 => 35,
45
+ 311 => 36,
46
+ 319 => 37,
47
+ 328 => 38,
48
+ 336 => 39,
49
+ 345 => 40,
50
+ 353 => 41,
51
+ 362 => 42,
52
+ 370 => 43,
53
+ 379 => 44,
54
+ 388 => 45,
55
+ 396 => 46,
56
+ 405 => 47,
57
+ 413 => 48,
58
+ 422 => 49,
59
+ 430 => 50,
60
+ 439 => 51,
61
+ 447 => 52,
62
+ 456 => 53,
63
+ 464 => 54,
64
+ 473 => 55,
65
+ 481 => 56,
66
+ 490 => 57,
67
+ 498 => 58,
68
+ 507 => 59,
69
+ },
70
+ }
@@ -0,0 +1,90 @@
1
+
2
+ PIXEL_OFFSETS['80x80'] = {
3
+ '512x512' => {
4
+ ###########
5
+ # 512x512 (80x80)
6
+ # assume 6px 80*6 = 480 + 32 = 512
7
+ #
8
+ # e.g. 80.times {|i| puts "#{(3+i*6+32.0/80.0*i).to_i} => #{i}," }
9
+ 3 => 0,
10
+ 9 => 1,
11
+ 15 => 2,
12
+ 22 => 3,
13
+ 28 => 4,
14
+ 35 => 5,
15
+ 41 => 6,
16
+ 47 => 7,
17
+ 54 => 8,
18
+ 60 => 9,
19
+ 67 => 10,
20
+ 73 => 11,
21
+ 79 => 12,
22
+ 86 => 13,
23
+ 92 => 14,
24
+ 99 => 15,
25
+ 105 => 16,
26
+ 111 => 17,
27
+ 118 => 18,
28
+ 124 => 19,
29
+ 131 => 20,
30
+ 137 => 21,
31
+ 143 => 22,
32
+ 150 => 23,
33
+ 156 => 24,
34
+ 163 => 25,
35
+ 169 => 26,
36
+ 175 => 27,
37
+ 182 => 28,
38
+ 188 => 29,
39
+ 195 => 30,
40
+ 201 => 31,
41
+ 207 => 32,
42
+ 214 => 33,
43
+ 220 => 34,
44
+ 227 => 35,
45
+ 233 => 36,
46
+ 239 => 37,
47
+ 246 => 38,
48
+ 252 => 39,
49
+ 259 => 40,
50
+ 265 => 41,
51
+ 271 => 42,
52
+ 278 => 43,
53
+ 284 => 44,
54
+ 291 => 45,
55
+ 297 => 46,
56
+ 303 => 47,
57
+ 310 => 48,
58
+ 316 => 49,
59
+ 323 => 50,
60
+ 329 => 51,
61
+ 335 => 52,
62
+ 342 => 53,
63
+ 348 => 54,
64
+ 355 => 55,
65
+ 361 => 56,
66
+ 367 => 57,
67
+ 374 => 58,
68
+ 380 => 59,
69
+ 387 => 60,
70
+ 393 => 61,
71
+ 399 => 62,
72
+ 406 => 63,
73
+ 412 => 64,
74
+ 419 => 65,
75
+ 425 => 66,
76
+ 431 => 67,
77
+ 438 => 68,
78
+ 444 => 69,
79
+ 451 => 70,
80
+ 457 => 71,
81
+ 463 => 72,
82
+ 470 => 73,
83
+ 476 => 74,
84
+ 483 => 75,
85
+ 489 => 76,
86
+ 495 => 77,
87
+ 502 => 78,
88
+ 508 => 79,
89
+ }
90
+ }
@@ -0,0 +1,75 @@
1
+ ######################
2
+ # pixelart image extensions
3
+ # move upstream!!!!!
4
+
5
+
6
+ module Pixelart
7
+
8
+ class Image
9
+ def sample( *args, **kwargs )
10
+ ## note: for now always assume square image (e.g. 24x24, 32x32 and such)
11
+
12
+ offsets = if kwargs[:from] && kwargs[:to]
13
+ PIXEL_OFFSETS[ kwargs[:to] ][ kwargs[ :from ]]
14
+ else
15
+ args[0] ## assume "custom" hash of offsets
16
+ end
17
+
18
+ width = height = offsets.size
19
+
20
+ puts " #{self.width}x#{self.height} => #{width}x#{height}"
21
+
22
+
23
+ dest = Image.new( width, height )
24
+
25
+ offsets.each do |offset_x, x|
26
+ offsets.each do |offset_y, y|
27
+ pixel = self[offset_x,offset_y]
28
+
29
+ dest[x,y] = pixel
30
+ end
31
+ end
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'
@@ -0,0 +1,144 @@
1
+
2
+ module OpenSea
3
+
4
+ #############
5
+ # read meta data into struct
6
+
7
+ class Meta
8
+ def self.read( path )
9
+ txt = File.open( path, 'r:utf-8' ) { |f| f.read }
10
+ data = JSON.parse( txt )
11
+ new( data )
12
+ end
13
+
14
+
15
+ def initialize( data )
16
+ @data = data
17
+
18
+ assets = @data['assets']
19
+ if assets.size != 1
20
+ puts "!! error - expected one asset per file only - got #{assets.size} - sorry"
21
+ exit 1
22
+ end
23
+
24
+ @asset = assets[0]
25
+ end
26
+
27
+ def name
28
+ @name ||= _normalize( @asset['name'] )
29
+ end
30
+
31
+ def description
32
+ @description ||= _normalize( @asset['description'] )
33
+ end
34
+
35
+ ## note: auto-convert "" (empty string) to nil
36
+ def image_original_url() _blank( @asset['image_original_url'] ); end
37
+ def image_url() _blank( @asset['image_url'] ); end
38
+
39
+
40
+ def token_id() @asset['token_id']; end ## note: keep id as string as is - why? why not?
41
+
42
+
43
+ def traits
44
+ @traits ||= begin
45
+ traits = []
46
+ ## keep traits as (simple)
47
+ ## ordered array of pairs for now
48
+ ##
49
+ ## in a step two make lookup via hash table
50
+ ## or such easier / "automagic"
51
+
52
+ @asset[ 'traits' ].each do |t|
53
+ trait_type = t['trait_type'].strip
54
+ trait_value = t['value'].strip
55
+ traits << [trait_type, trait_value]
56
+ end
57
+
58
+ traits
59
+ end
60
+ end
61
+
62
+
63
+
64
+ ### "private" convenience / helper methods
65
+ def _normalize( str )
66
+ return if str.nil? ## check: check for nil - why? why not?
67
+
68
+ ## normalize string
69
+ ## remove leading and trailing spaces
70
+ ## collapse two and more spaces into one
71
+ ## change unicode space to ascii
72
+ str = str.gsub( "\u{00a0}", ' ' )
73
+ str = str.strip.gsub( /[ ]{2,}/, ' ' )
74
+ str
75
+ end
76
+
77
+ def _blank( o ) ## auto-convert "" (empty string) into nil
78
+ if o && o.strip.empty?
79
+ nil
80
+ else
81
+ o
82
+ end
83
+ end
84
+ end # class Meta
85
+
86
+
87
+
88
+ BASE = 'https://api.opensea.io/api/v1/assets?collection={collection}&order_direction=asc&offset={offset}&limit=1'
89
+
90
+ ## todo/check: rename to query or search or such - why? why not?
91
+ ##
92
+ ## add self.collect( collection, offset: 0 ) helper or such - why? why not?
93
+ def self.assets( collection:, offset: 0 )
94
+ src = BASE.sub( '{collection}', collection ).
95
+ sub( '{offset}', offset.to_s )
96
+
97
+ call( src )
98
+ end
99
+
100
+
101
+ def self.call( src ) ## get response as (parsed) json (hash table)
102
+ uri = URI.parse( src )
103
+
104
+ http = Net::HTTP.new( uri.host, uri.port )
105
+
106
+ puts "[debug] GET #{uri.request_uri} uri=#{uri}"
107
+
108
+ headers = {
109
+ 'User-Agent' => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36",
110
+ #'User-Agent' => "ruby v#{RUBY_VERSION}",
111
+ }
112
+
113
+
114
+ request = Net::HTTP::Get.new( uri.request_uri, headers )
115
+ if uri.instance_of? URI::HTTPS
116
+ http.use_ssl = true
117
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
118
+ end
119
+
120
+ response = http.request( request )
121
+
122
+ if response.code == '200'
123
+ puts "#{response.code} #{response.message} - content_type: #{response.content_type}, content_length: #{response.content_length}"
124
+
125
+ text = response.body.to_s
126
+ text = text.force_encoding( Encoding::UTF_8 )
127
+
128
+ data = JSON.parse( text )
129
+ data
130
+ else
131
+ puts "!! ERROR:"
132
+ puts "#{response.code} #{response.message}"
133
+ exit 1
134
+ end
135
+ end
136
+ end # module OpenSea
137
+
138
+
139
+
140
+
141
+ #####
142
+ # add convenience alias
143
+ Opensea = OpenSea
144
+
@@ -0,0 +1,159 @@
1
+
2
+
3
+
4
+ module Artbase
5
+ class Tool
6
+
7
+ def self.collection=(value)
8
+ puts " setting collection to:"
9
+ pp value
10
+
11
+ @collection = value
12
+ end
13
+
14
+
15
+ def self.main( args=ARGV )
16
+ puts "==> welcome to collection tool with args:"
17
+ pp args
18
+
19
+ options = { }
20
+ parser = OptionParser.new do |opts|
21
+
22
+ opts.on("--offset NUM", Integer,
23
+ "Start counting at offset (default: 0)") do |num|
24
+ options[ :offset] = num
25
+ end
26
+
27
+ opts.on("--limit NUM", Integer,
28
+ "Limit collection (default: ∞)") do |num|
29
+ options[ :limit] = num
30
+ end
31
+
32
+ ## todo/fix: unsupported argument type: Range
33
+ ## opts.on("--range RANGE", Range,
34
+ ## "Range of collection (default: 0..∞") do |range|
35
+ ## options[ :range] = range
36
+ ## end
37
+
38
+ opts.on("-h", "--help", "Prints this help") do
39
+ puts opts
40
+ exit
41
+ end
42
+ end
43
+
44
+ parser.parse!( args )
45
+ puts "options:"
46
+ pp options
47
+
48
+ puts "args:"
49
+ pp args
50
+
51
+ if args.size < 2
52
+ puts "!! ERROR - no command found - use <collection> <command>..."
53
+ puts ""
54
+ exit
55
+ end
56
+
57
+ name = args[0] ## todo/check - use collection_name/slug or such?
58
+ command = args[1]
59
+ subcommand = args[2]
60
+
61
+
62
+ path = "./#{name}/config.rb"
63
+ puts "==> reading collection config >#{path}<..."
64
+
65
+ ## note: assume for now global const COLLECTION gets set/defined!!!
66
+ ## use/change to a script/dsl loader/eval later!!!
67
+ load( path )
68
+
69
+ ## pp COLLECTION
70
+
71
+ ## configure collection (note: requires self)
72
+ self.collection = COLLECTION
73
+
74
+
75
+ if ['d','dl','down', 'download'].include?( command )
76
+ if subcommand
77
+ if ['m', 'meta'].include?( subcommand )
78
+ download_meta
79
+ elsif ['i', 'img', 'image', 'images'].include?( subcommand )
80
+ download_images
81
+ end
82
+ else
83
+ download_meta
84
+ download_images
85
+ end
86
+ elsif ['p', 'px', 'pix', 'pixel', 'pixelate'].include?( command )
87
+ pixelate( offset: options[ :offset] )
88
+ elsif ['m', 'meta'].include?( command )
89
+ download_meta
90
+ elsif ['i', 'img', 'image', 'images'].include?( command )
91
+ download_images( offset: options[ :offset] )
92
+ elsif ['a', 'attr', 'attributes'].include?( command )
93
+ dump_attributes
94
+ elsif ['x', 'exp', 'export'].include?( command )
95
+ export_attributes
96
+ elsif ['c', 'composite'].include?( command )
97
+ make_composite
98
+ elsif ['t', 'test'].include?( command )
99
+ puts " testing, testing, testing"
100
+ else
101
+ puts "!! ERROR - unknown command >#{command}<, sorry"
102
+ end
103
+
104
+ puts "bye"
105
+ end
106
+
107
+ def self.make_composite
108
+ puts "==> make composite"
109
+ @collection.make_composite
110
+ end
111
+
112
+ def self.dump_attributes
113
+ puts "==> dump attributes"
114
+ @collection.dump_attributes
115
+ end
116
+
117
+ def self.export_attributes
118
+ puts "==> export attributes"
119
+ @collection.export_attributes
120
+ end
121
+
122
+
123
+ def self.download_meta
124
+ puts "==> download meta"
125
+ @collection.download_meta
126
+ end
127
+
128
+ def self.download_images( offset: )
129
+ puts "==> download images"
130
+
131
+ ## note: use three dots (...) to exclude e.g. count 100 => 0 to 99)
132
+ range = if offset
133
+ (offset...@collection.count)
134
+ else
135
+ (0...@collection.count)
136
+ end
137
+
138
+ @collection.download_images( range )
139
+ end
140
+
141
+ def self.pixelate( offset: )
142
+ puts "==> pixelate"
143
+
144
+ ## note: use three dots (...) to exclude e.g. count 100 => 0 to 99)
145
+ range = if offset
146
+ (offset...@collection.count)
147
+ else
148
+ (0...@collection.count)
149
+ end
150
+
151
+ @collection.pixelate( range )
152
+ end
153
+ end # class Tool
154
+
155
+
156
+ end # module Artbase
157
+
158
+
159
+
@@ -1,10 +1,10 @@
1
1
 
2
2
 
3
- class Artbase
3
+ module Artbase
4
4
 
5
5
  MAJOR = 0
6
- MINOR = 0
7
- PATCH = 1
6
+ MINOR = 1
7
+ PATCH = 0
8
8
  VERSION = [MAJOR,MINOR,PATCH].join('.')
9
9
 
10
10
  def self.version
data/lib/artbase.rb CHANGED
@@ -1,9 +1,42 @@
1
1
  require 'pp'
2
+ require 'time'
3
+ require 'date'
4
+
5
+ require 'uri'
6
+ require 'net/http'
7
+ require 'net/https'
8
+ require 'cgi'
9
+ require 'fileutils'
10
+
11
+ require 'json'
12
+
13
+ require 'optparse'
14
+
15
+
16
+
17
+ ## our own gems
18
+ require 'pixelart'
19
+
20
+
21
+
2
22
 
3
23
 
4
24
  ## our own code
5
25
  require 'artbase/version' # note: let version always go first
6
26
 
27
+ require 'artbase/image'
28
+
29
+
30
+ require 'artbase/helper'
31
+ require 'artbase/opensea'
32
+
33
+ require 'artbase/collection'
34
+ require 'artbase/attributes'
35
+
36
+
37
+ require 'artbase/tool'
38
+
39
+
7
40
 
8
- pp Artbase.banner
9
- pp Artbase.root
41
+ puts Artbase.banner
42
+ puts Artbase.root