ordbase 1.0.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 +7 -0
- data/CHANGELOG.md +3 -0
- data/Manifest.txt +9 -0
- data/README.md +171 -0
- data/Rakefile +39 -0
- data/bin/ordbase +17 -0
- data/lib/ordbase/collection.rb +268 -0
- data/lib/ordbase/stats.rb +142 -0
- data/lib/ordbase/tool.rb +130 -0
- data/lib/ordbase.rb +16 -0
- metadata +121 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1153ed377c1c27ca1949b44cf8f572eee29f41a22f3cf2bbb212249c08892986
|
4
|
+
data.tar.gz: 13f2cbc4bfcfe29322dff646066ae7b3440791b0ca2d5dfed3548d69c4280b75
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e17fd8a4f60c5f3c41ab648e9460a5829b1d63cad5c2cea04a45b3ee06a09dca8d58065a6f3dc016e440f2bca68a2a0d3be88a34cca0d79c6968467fadcd44f5
|
7
|
+
data.tar.gz: 82ec1b35e9929645401a920605a7b22bc2a5e81e313b56da65615eafed9854abdd307fb974e71a92d69f2ddcf6a778f0a3dd8edad7a2de43995086edfa502803
|
data/CHANGELOG.md
ADDED
data/Manifest.txt
ADDED
data/README.md
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
# ordbase
|
2
|
+
|
3
|
+
ordbase gem - "right-clicker" (off-chain) ordinals (pixel art) command-line tool, machinery & helpers for Bitcoin, Litcoin, Dogecoin & co.
|
4
|
+
|
5
|
+
|
6
|
+
* home :: [github.com/pixelartexchange/artbase](https://github.com/pixelartexchange/artbase)
|
7
|
+
* bugs :: [github.com/pixelartexchange/artbase/issues](https://github.com/pixelartexchange/artbase/issues)
|
8
|
+
* gem :: [rubygems.org/gems/ordbase](https://rubygems.org/gems/ordbase)
|
9
|
+
* rdoc :: [rubydoc.info/gems/ordbase](http://rubydoc.info/gems/ordbase)
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
## Command-Line Usage
|
14
|
+
|
15
|
+
Let's use the 100 Ordinal Punks collection to try out the
|
16
|
+
`ordbase` command-line tool shipping with the ordbase package.
|
17
|
+
|
18
|
+
Tip: New to Ordinal Punks? For some background see [**Awesome 100 Ordinal Punks (Anno 2023) Notes - 24×24 Pixel Art on the (Bitcoin) Blockchain »**](https://github.com/cryptopunksnotdead/cryptopunks/tree/master/awesome-ordinalpunks)
|
19
|
+
|
20
|
+
|
21
|
+
### Step 0: Prepare A Tabular Dataset (List) Of All Ordinals w/ ID
|
22
|
+
|
23
|
+
For now a manual step - prepare a list of all ordinals with id in the comma-separated values (.csv) tabular dataset format.
|
24
|
+
Example - [ordinalpunks/ordinals.csv](https://github.com/pixelartexchange/ordinals.sandbox/blob/master/ordinalpunks/ordinals.csv):
|
25
|
+
|
26
|
+
``` csv
|
27
|
+
num, id
|
28
|
+
1, 96d87d7e59d75ebc0e6144b09fdd96355fcdaa86fd098d64c46f19a424012bbei0
|
29
|
+
2, acda637db995df796b35035fd978cc1a947f1e6fd5215968da88b7e38a7e4b37i0
|
30
|
+
3, 0406654dffdd01a49794bd8531bf33721986cc7c6546f871962adee921a39a9di0
|
31
|
+
4, 2fe9bb034f60db694701acb23a76c3d7d5aba4328dbd315764f6ee406ba41786i0
|
32
|
+
5, dcfa240f2681d1e4a8948120a3a64567262e3c78d5497cb4e97351bfa836b638i0
|
33
|
+
6, 16df62c86321895df2b93236d103c935015ed77e189485be649ce2c7e6ac8a4ei0
|
34
|
+
7, 81e8d9159b8e9a27c692a5bb3ba18ca037757e94e975b53e175eaaeb2c52f15ai0
|
35
|
+
8, c2e15fe87c4b1fd61de65f2804858e6d1152b6316bcb9c2b39b69c9c21638f5di0
|
36
|
+
9, 3ed569f3a92ade9f1b47031eb2db2045e7dee3e00787954a88c67ed2ad9854bbi0
|
37
|
+
...
|
38
|
+
```
|
39
|
+
|
40
|
+
|
41
|
+
### Step 1: Download All Pixel Art Images Via Ordinals.com
|
42
|
+
|
43
|
+
Use
|
44
|
+
|
45
|
+
```
|
46
|
+
$ ordbase ordinalpunks image # or
|
47
|
+
$ ordbase ordinalpunks img
|
48
|
+
```
|
49
|
+
|
50
|
+
to download all images via the ordinals.com (web) service.
|
51
|
+
All images get stored in the (temporary) `token-i/` directory.
|
52
|
+
Resulting in:
|
53
|
+
|
54
|
+
```
|
55
|
+
/ordinalpunks
|
56
|
+
ordinals.csv
|
57
|
+
/token-i
|
58
|
+
1.png
|
59
|
+
2.png
|
60
|
+
3.png
|
61
|
+
...
|
62
|
+
```
|
63
|
+
|
64
|
+

|
65
|
+

|
66
|
+

|
67
|
+

|
68
|
+

|
69
|
+

|
70
|
+
...
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
### Step 2: Downsample ("Pixelate") All Pixel Art Images
|
76
|
+
|
77
|
+
Note: Most pixel art collections upload / inscribe images with a zoom.
|
78
|
+
The ordinal punks, for example, use a 8x zoom factor for the 24×24px originals, thus,
|
79
|
+
resulting in 192×192px.
|
80
|
+
|
81
|
+
|
82
|
+
Add a ["artbase-compatible"](https://github.com/pixelartexchange/artbase) collection configuration file to lists the source format(s)
|
83
|
+
and the minimal true pixel format.
|
84
|
+
Example - [ordinalpunks/collection.yml](https://github.com/pixelartexchange/ordinals.sandbox/blob/master/ordinalpunks/collection.yml):
|
85
|
+
|
86
|
+
``` yaml
|
87
|
+
slug: ordinalpunks
|
88
|
+
count: 100
|
89
|
+
format: 24x24
|
90
|
+
source: 192x192
|
91
|
+
offset: 1
|
92
|
+
```
|
93
|
+
|
94
|
+
Use
|
95
|
+
|
96
|
+
```
|
97
|
+
$ ordbase ordinalpunks pixelate # or
|
98
|
+
$ ordbase ordinalpunks px
|
99
|
+
```
|
100
|
+
|
101
|
+
to downsample ("pixelate") all images
|
102
|
+
in the (temporary) `token-i/` directory.
|
103
|
+
Resulting in a `24x24`/ directory with all images
|
104
|
+
in the "minimal" `24x24` format:
|
105
|
+
|
106
|
+
```
|
107
|
+
/ordinalpunks
|
108
|
+
ordinals.csv
|
109
|
+
collections.yml
|
110
|
+
/24x24
|
111
|
+
1.png
|
112
|
+
2.png
|
113
|
+
3.png
|
114
|
+
...
|
115
|
+
```
|
116
|
+
|
117
|
+

|
118
|
+

|
119
|
+

|
120
|
+

|
121
|
+

|
122
|
+

|
123
|
+
...
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
### Bonus: Step 3: Make An All-In-One Collect'Em All Composite Image
|
128
|
+
|
129
|
+
|
130
|
+
Use
|
131
|
+
|
132
|
+
```
|
133
|
+
$ ordbase ordinalpunks composite # or
|
134
|
+
$ ordbase ordinalpunks comp
|
135
|
+
```
|
136
|
+
|
137
|
+
to make an all-in-one image composite for the complete collection.
|
138
|
+
Resulting in `/tmp/ordinalpunks.png` (~11kb).
|
139
|
+
|
140
|
+
|
141
|
+

|
142
|
+
|
143
|
+
|
144
|
+
That's it for now.
|
145
|
+
|
146
|
+
|
147
|
+
|
148
|
+
|
149
|
+
## Bonus: More Ordinal Pixel Art Collections
|
150
|
+
|
151
|
+
|
152
|
+
See the [**Ordinals (Pixel Art) Sandbox (& Cache)**](https://github.com/pixelartexchange/ordinals.sandbox)
|
153
|
+
for more collections incl. Bitcoin Punks (24×24), Ordinal Mini Doges (24×24),
|
154
|
+
Extra Ordinal Women (32×32), Ordinal Penguins (35×35),
|
155
|
+
Ordinal Birds (42×42), Bitcoin Bears (48×48) and much more.
|
156
|
+
|
157
|
+
Add your sandbox or "right-clicker" ordinal backup / archive / gallery here. Yes, you can.
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
## License
|
162
|
+
|
163
|
+
The scripts are dedicated to the public domain.
|
164
|
+
Use it as you please with no restrictions whatsoever.
|
165
|
+
|
166
|
+
|
167
|
+
## Questions? Comments?
|
168
|
+
|
169
|
+
Post them over at the [Help & Support](https://github.com/geraldb/help) page. Thanks.
|
170
|
+
|
171
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'hoe'
|
2
|
+
|
3
|
+
|
4
|
+
###
|
5
|
+
# hack/ quick fix for broken intuit_values - overwrite with dummy
|
6
|
+
class Hoe
|
7
|
+
def intuit_values( input ); end
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
Hoe.spec 'ordbase' do
|
12
|
+
|
13
|
+
self.version = '1.0.0'
|
14
|
+
|
15
|
+
self.summary = 'ordbase gem - "right-clicker" (off-chain) ordinals (pixel art) command-line tool, machinery & helpers for Bitcoin, Litecoin, Dogecoin & co.'
|
16
|
+
self.description = summary
|
17
|
+
|
18
|
+
self.urls = { home: 'https://github.com/pixelartexchange/artbase' }
|
19
|
+
|
20
|
+
self.author = 'Gerald Bauer'
|
21
|
+
self.email = 'wwwmake@googlegroups.com'
|
22
|
+
|
23
|
+
# switch extension to .markdown for gihub formatting
|
24
|
+
self.readme_file = 'README.md'
|
25
|
+
self.history_file = 'CHANGELOG.md'
|
26
|
+
|
27
|
+
self.extra_deps = [
|
28
|
+
['ordinals'],
|
29
|
+
['pixelart'],
|
30
|
+
]
|
31
|
+
|
32
|
+
self.licenses = ['Public Domain']
|
33
|
+
|
34
|
+
self.spec_extras = {
|
35
|
+
required_ruby_version: '>= 2.3'
|
36
|
+
}
|
37
|
+
|
38
|
+
end
|
39
|
+
|
data/bin/ordbase
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
###################
|
4
|
+
# == DEV TIPS:
|
5
|
+
#
|
6
|
+
# For local testing run like:
|
7
|
+
#
|
8
|
+
# ruby -Ilib bin/ordbase
|
9
|
+
#
|
10
|
+
# Set the executable bit in Linux. Example:
|
11
|
+
#
|
12
|
+
# % chmod a+x bin/ordbase
|
13
|
+
#
|
14
|
+
|
15
|
+
require 'ordinals'
|
16
|
+
|
17
|
+
Ordinals::Tool.main
|
@@ -0,0 +1,268 @@
|
|
1
|
+
|
2
|
+
module Ordinals
|
3
|
+
|
4
|
+
|
5
|
+
class Collection
|
6
|
+
attr_reader :slug,
|
7
|
+
:width, :height,
|
8
|
+
:sources
|
9
|
+
|
10
|
+
|
11
|
+
def initialize( slug )
|
12
|
+
@slug = slug
|
13
|
+
|
14
|
+
## read config if present
|
15
|
+
config_path = "./#{@slug}/collection.yml"
|
16
|
+
if File.exist?( config_path )
|
17
|
+
config = read_yaml( config_path )
|
18
|
+
pp config
|
19
|
+
|
20
|
+
@width, @height = _parse_dimension( config['format'] )
|
21
|
+
|
22
|
+
## note: allow multiple source formats / dimensions
|
23
|
+
### e.g. convert 512x512 into [ [512,512] ]
|
24
|
+
##
|
25
|
+
source = config['source']
|
26
|
+
source = [source] unless source.is_a?( Array )
|
27
|
+
@sources = source.map { |dimension| _parse_dimension( dimension ) }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def ordinals
|
33
|
+
@ordinals ||= begin
|
34
|
+
recs = read_csv( "./#{@slug}/ordinals.csv" )
|
35
|
+
puts " #{recs.size} record(s)"
|
36
|
+
recs
|
37
|
+
end
|
38
|
+
@ordinals
|
39
|
+
end
|
40
|
+
|
41
|
+
def count() ordinals.size; end
|
42
|
+
alias_method :size, :count
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
def each_ordinal( &block )
|
47
|
+
ordinals.each_with_index do |rec, i| ## pass along hash rec for now - why? why not?
|
48
|
+
block.call( rec, i )
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
## add each_source_image or each_token_image or each_original_image or such - why? why not??
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
def each_image( &block )
|
57
|
+
each_ordinal do |rec, i|
|
58
|
+
id = rec['id']
|
59
|
+
num = rec.has_key?('num') ? rec['num'].to_i(10) : i+1
|
60
|
+
|
61
|
+
path = "./#{@slug}/#{@width}x#{@height}/#{num}.png"
|
62
|
+
img = Image.read( path )
|
63
|
+
|
64
|
+
block.call( img, num )
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
def image_dir() "./#{@slug}/token-i"; end
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
## e.g. convert dimension (width x height) "24x24" or "24 x 24" to [24,24]
|
75
|
+
def _parse_dimension( str )
|
76
|
+
str.split( /x/i ).map { |str| str.strip.to_i }
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def pixelate
|
81
|
+
each_ordinal do |rec, i|
|
82
|
+
id = rec['id']
|
83
|
+
num = rec.has_key?('num') ? rec['num'].to_i(10) : i+1
|
84
|
+
|
85
|
+
outpath = "./#{@slug}/#{@width}x#{@height}/#{num}.png"
|
86
|
+
next if File.exist?( outpath )
|
87
|
+
|
88
|
+
path = "#{image_dir}/#{num}.png"
|
89
|
+
puts "==> reading #{path}..."
|
90
|
+
|
91
|
+
img = Image.read( path )
|
92
|
+
puts " #{img.width}x#{img.height}"
|
93
|
+
|
94
|
+
## check for source images
|
95
|
+
if !@sources.include?( [img.width, img.height] )
|
96
|
+
puts " !! ERROR - unexpected image size; sorry - expected:"
|
97
|
+
pp @sources
|
98
|
+
exit 1
|
99
|
+
end
|
100
|
+
|
101
|
+
## check for special case source == format!!
|
102
|
+
if [img.width,img.height] == [@width,@height]
|
103
|
+
puts " note: saving image as is - no downsampling"
|
104
|
+
img.save( outpath )
|
105
|
+
else
|
106
|
+
steps_x = Image.calc_sample_steps( img.width, @width )
|
107
|
+
steps_y = Image.calc_sample_steps( img.height, @height )
|
108
|
+
|
109
|
+
img = img.sample( steps_x, steps_y )
|
110
|
+
img.save( outpath )
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
|
117
|
+
|
118
|
+
def make_composite( limit: nil )
|
119
|
+
|
120
|
+
composite_count = limit ? limit : count
|
121
|
+
|
122
|
+
cols, rows = case composite_count
|
123
|
+
when 10 then [5, 2]
|
124
|
+
when 12 then [4, 3]
|
125
|
+
when 15 then [5, 3]
|
126
|
+
when 20 then [5, 4]
|
127
|
+
when 50 then [10, 5]
|
128
|
+
when 69 then [10, 7]
|
129
|
+
when 80 then [10, 8]
|
130
|
+
when 88 then [10, 9]
|
131
|
+
when 98,99 then [10, 10]
|
132
|
+
when 100 then [10, 10]
|
133
|
+
when 101 then [11, 10]
|
134
|
+
when 111 then [11, 11]
|
135
|
+
when 130 then [10, 13]
|
136
|
+
when 512 then [20, 26]
|
137
|
+
else
|
138
|
+
raise ArgumentError, "sorry - unknown composite count #{composite_count} for now"
|
139
|
+
end
|
140
|
+
|
141
|
+
composite = ImageComposite.new( cols, rows,
|
142
|
+
width: @width,
|
143
|
+
height: @height )
|
144
|
+
|
145
|
+
|
146
|
+
image_count = 0
|
147
|
+
each_image do |img, num|
|
148
|
+
puts "==> #{num}"
|
149
|
+
composite << img
|
150
|
+
|
151
|
+
image_count += 1
|
152
|
+
break if image_count >= composite_count
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
composite.save( "./#{@slug}/tmp/#{@slug}.png" )
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
def convert_images
|
162
|
+
Image.convert( image_dir, from: 'jpg',
|
163
|
+
to: 'png' )
|
164
|
+
|
165
|
+
Image.convert( image_dir, from: 'gif',
|
166
|
+
to: 'png' )
|
167
|
+
|
168
|
+
Image.convert( image_dir, from: 'webp',
|
169
|
+
to: 'png' )
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
|
174
|
+
def fix_images ## todo - find a different names for resaving png images?
|
175
|
+
## "repair" png images
|
176
|
+
## starting w/
|
177
|
+
## - why?
|
178
|
+
##
|
179
|
+
## verify_signature! - ChunkyPNG::SignatureMismatch:
|
180
|
+
## PNG signature not found,
|
181
|
+
## found "RIFF\\xFE\\b\\x00\\x00"
|
182
|
+
## instead of "\\x89PNG\\r\\n\\x1A\\n"
|
183
|
+
|
184
|
+
Image.convert( image_dir, from: 'png',
|
185
|
+
to: 'png' )
|
186
|
+
end
|
187
|
+
|
188
|
+
|
189
|
+
def download_meta ## inscription metadata
|
190
|
+
each_ordinal do |rec, i|
|
191
|
+
id = rec['id']
|
192
|
+
num = rec.has_key?('num') ? rec['num'].to_i(10) : i+1
|
193
|
+
|
194
|
+
chain = Ordinals.config.chain
|
195
|
+
path = "../ordinals.cache/#{chain}/#{id}.json"
|
196
|
+
next if File.exist?( path )
|
197
|
+
|
198
|
+
puts "==> downloading #{chain} inscription meta #{num} w/ id #{id}..."
|
199
|
+
|
200
|
+
data = Ordinals.client.inscription( id )
|
201
|
+
|
202
|
+
write_json( path, data )
|
203
|
+
|
204
|
+
sleep( 1.0 ) ## sleep (delay_in_s)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def dump_stats
|
209
|
+
stats = InscriptionStats.new
|
210
|
+
|
211
|
+
each_ordinal do |rec, i|
|
212
|
+
id = rec['id']
|
213
|
+
|
214
|
+
chain = Ordinals.config.chain
|
215
|
+
path = "../ordinals.cache/#{chain}/#{id}.json"
|
216
|
+
|
217
|
+
data = read_json( path )
|
218
|
+
stats.update( data )
|
219
|
+
end
|
220
|
+
|
221
|
+
pp stats.data
|
222
|
+
puts
|
223
|
+
puts stats.format
|
224
|
+
end
|
225
|
+
|
226
|
+
|
227
|
+
def download_images
|
228
|
+
each_ordinal do |rec, i|
|
229
|
+
id = rec['id']
|
230
|
+
num = rec.has_key?('num') ? rec['num'].to_i(10) : i+1
|
231
|
+
|
232
|
+
## note: add gif too (for check) - add more formats - why? why not?
|
233
|
+
next if File.exist?( "#{image_dir}/#{num}.png" ) ||
|
234
|
+
File.exist?( "#{image_dir}/#{num}.gif" ) ||
|
235
|
+
File.exist?( "#{image_dir}/#{num}.jpg" )
|
236
|
+
|
237
|
+
|
238
|
+
puts "==> downloading image ##{num}..."
|
239
|
+
|
240
|
+
|
241
|
+
content = Ordinals.client.content( id )
|
242
|
+
|
243
|
+
puts " content_type: #{content.type}, content_length: #{content.length}"
|
244
|
+
|
245
|
+
format = if content.type =~ %r{image/jpeg}i
|
246
|
+
'jpg'
|
247
|
+
elsif content.type =~ %r{image/png}i
|
248
|
+
'png'
|
249
|
+
elsif content.type =~ %r{image/gif}i
|
250
|
+
'gif'
|
251
|
+
elsif content.type =~ %r{image/webp}i
|
252
|
+
'webp'
|
253
|
+
else
|
254
|
+
puts "!! ERROR:"
|
255
|
+
puts " unknown image format content type: >#{content.type}<"
|
256
|
+
exit 1
|
257
|
+
end
|
258
|
+
|
259
|
+
## save image - using b(inary) mode
|
260
|
+
write_blob( "#{image_dir}/#{num}.#{format}", content.blob )
|
261
|
+
|
262
|
+
sleep( 1.0 ) ## sleep (delay_in_s)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
end # class Collection
|
267
|
+
end # module Ordinals
|
268
|
+
|
@@ -0,0 +1,142 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class InscriptionStats
|
4
|
+
|
5
|
+
TITLE_RX = /^Inscription[ ]+(?<ord>[0-9]+)$/
|
6
|
+
BYTES_RX = /^(?<bytes>[0-9]+)[ ]+bytes$/
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@stats = {
|
10
|
+
count: 0,
|
11
|
+
ord: { '<1000' => 0,
|
12
|
+
'<10000' => 0,
|
13
|
+
'<100000' => 0,
|
14
|
+
'<1000000' => 0,
|
15
|
+
'min' => nil,
|
16
|
+
'max' => nil, },
|
17
|
+
type: Hash.new(0),
|
18
|
+
bytes: { '<100' => 0,
|
19
|
+
'<1000' => 0,
|
20
|
+
'<10000' => 0,
|
21
|
+
'<100000' => 0,
|
22
|
+
'<1000000' => 0,
|
23
|
+
'min' => nil,
|
24
|
+
'max' => nil, },
|
25
|
+
}
|
26
|
+
|
27
|
+
@days = Hash.new(0)
|
28
|
+
end
|
29
|
+
|
30
|
+
def size() @stats[:count]; end
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
def update( data )
|
35
|
+
data = JSON.parse( data) if data.is_a?( String )
|
36
|
+
|
37
|
+
@stats[ :count ] += 1
|
38
|
+
|
39
|
+
|
40
|
+
ord = nil
|
41
|
+
if m=TITLE_RX.match( data['title'] )
|
42
|
+
ord = m[:ord].to_i(10)
|
43
|
+
else
|
44
|
+
puts "!! ERROR - cannot find ord in inscription title; sorry"
|
45
|
+
pp data
|
46
|
+
exit 1
|
47
|
+
end
|
48
|
+
|
49
|
+
if ord < 1000 then @stats[:ord]['<1000'] += 1
|
50
|
+
elsif ord < 10000 then @stats[:ord]['<10000'] += 1
|
51
|
+
elsif ord < 100000 then @stats[:ord]['<100000'] += 1
|
52
|
+
elsif ord < 1000000 then @stats[:ord]['<1000000'] += 1
|
53
|
+
else
|
54
|
+
puts "!! ERROR ord out-of-bounds"
|
55
|
+
exit 1
|
56
|
+
end
|
57
|
+
|
58
|
+
## update min/max
|
59
|
+
@stats[:ord]['min'] = ord if ord < (@stats[:ord]['min'] || 9999999)
|
60
|
+
@stats[:ord]['max'] = ord if ord > (@stats[:ord]['max'] || -1)
|
61
|
+
|
62
|
+
|
63
|
+
bytes = nil
|
64
|
+
if m=BYTES_RX.match( data['content length'] )
|
65
|
+
bytes = m[:bytes].to_i(10)
|
66
|
+
else
|
67
|
+
puts "!! ERROR - cannot find bytes in inscription content length; sorry"
|
68
|
+
pp data
|
69
|
+
exit 1
|
70
|
+
end
|
71
|
+
|
72
|
+
if bytes < 100 then @stats[:bytes]['<100'] += 1
|
73
|
+
elsif bytes < 1000 then @stats[:bytes]['<1000'] += 1
|
74
|
+
elsif bytes < 10000 then @stats[:bytes]['<10000'] += 1
|
75
|
+
elsif bytes < 100000 then @stats[:bytes]['<100000'] += 1
|
76
|
+
elsif bytes < 1000000 then @stats[:bytes]['<1000000'] += 1
|
77
|
+
else
|
78
|
+
puts "!! ERROR bytes (content-length) out-of-bounds"
|
79
|
+
exit 1
|
80
|
+
end
|
81
|
+
|
82
|
+
## update min/max
|
83
|
+
@stats[:bytes]['min'] = bytes if bytes < (@stats[:bytes]['min'] || 9999999)
|
84
|
+
@stats[:bytes]['max'] = bytes if bytes > (@stats[:bytes]['max'] || -1)
|
85
|
+
|
86
|
+
|
87
|
+
type = data['content type']
|
88
|
+
|
89
|
+
@stats[:type][ type ] += 1
|
90
|
+
|
91
|
+
## "timestamp"=>"2023-02-05 01:45:22 UTC",
|
92
|
+
ts = Time.strptime( data['timestamp'], '%Y-%m-%d %H:%M:%S' )
|
93
|
+
|
94
|
+
@days[ ts.strftime('%Y-%m-%d') ] +=1
|
95
|
+
end # method update
|
96
|
+
|
97
|
+
|
98
|
+
def data ## rename to model or such - why? why not?
|
99
|
+
## sort days
|
100
|
+
days = @days.sort {|l,r| l[0] <=> r[0] }
|
101
|
+
## add to stats
|
102
|
+
@stats[:days] = {}
|
103
|
+
days.each {|k,v| @stats[:days][k] = v }
|
104
|
+
@stats
|
105
|
+
end
|
106
|
+
|
107
|
+
=begin
|
108
|
+
{:count=>101,
|
109
|
+
:ord=>{"<1000"=>0, "<10000"=>0, "<100000"=>101, "<1000000"=>0, "min"=>14343, "max"=>42901},
|
110
|
+
:type=>{"image/png"=>101},
|
111
|
+
:bytes=>{"<100"=>0, "<1000"=>101, "<10000"=>0, "<100000"=>0, "<1000000"=>0, "min"=>274, "max"=>512},
|
112
|
+
:days=>{"2023-02-22"=>10, "2023-02-25"=>17, "2023-02-26"=>74}}
|
113
|
+
=end
|
114
|
+
|
115
|
+
def format ## rename to pretty_print or such - why? why not?
|
116
|
+
stat = data
|
117
|
+
|
118
|
+
buf = String.new('')
|
119
|
+
buf << "#{stat[:count]} inscription(s)\n"
|
120
|
+
|
121
|
+
buf << "- from ##{stat[:ord]['min']} to ##{stat[:ord]['max']} (min. to max.)\n"
|
122
|
+
buf << " - <1000 => #{stat[:ord]['<1000']}\n" if stat[:ord]["<1000"] > 0
|
123
|
+
buf << " - <10000 => #{stat[:ord]['<10000']}\n" if stat[:ord]["<10000"] > 0
|
124
|
+
buf << " - <100000 => #{stat[:ord]['<100000']}\n" if stat[:ord]["<100000"] > 0
|
125
|
+
buf << " - <1000000 => #{stat[:ord]['<1000000']}\n" if stat[:ord]["<1000000"] > 0
|
126
|
+
|
127
|
+
buf << "- format(s)\n"
|
128
|
+
stat[:type].each do |k,v|
|
129
|
+
buf << " - #{k} => #{v}\n"
|
130
|
+
end
|
131
|
+
|
132
|
+
buf << "- day(s)\n"
|
133
|
+
stat[:days].each do |k,v|
|
134
|
+
buf << " - #{k} => #{v}\n"
|
135
|
+
end
|
136
|
+
|
137
|
+
buf
|
138
|
+
end
|
139
|
+
|
140
|
+
end ## class InscriptionStats
|
141
|
+
|
142
|
+
|
data/lib/ordbase/tool.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
module Ordinals
|
2
|
+
class Tool
|
3
|
+
|
4
|
+
def self.main( args=ARGV )
|
5
|
+
puts "==> welcome to the ordbase tool with args:"
|
6
|
+
pp args
|
7
|
+
|
8
|
+
options = {
|
9
|
+
}
|
10
|
+
|
11
|
+
parser = OptionParser.new do |opts|
|
12
|
+
opts.on( "--doge", "--dogecoin", "Use Dogecoin / DOGE") do
|
13
|
+
## switch to doge
|
14
|
+
Ordinals.config.chain = :doge
|
15
|
+
end
|
16
|
+
opts.on( "--ltc", "--litecoin", "Use Litecoin / LTC") do
|
17
|
+
## switch to ltc
|
18
|
+
Ordinals.config.chain = :ltc
|
19
|
+
end
|
20
|
+
opts.on( "--btc", "--bitcoin", "Use Bitcoin / BTC") do
|
21
|
+
## switch to btc (default)
|
22
|
+
Ordinals.config.chain = :btc
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on("--limit NUM", Integer,
|
26
|
+
"Limit collection (default: ∞)") do |num|
|
27
|
+
options[ :limit] = num
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on("-h", "--help", "Prints this help") do
|
31
|
+
puts opts
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
parser.parse!( args )
|
37
|
+
puts "options:"
|
38
|
+
pp options
|
39
|
+
|
40
|
+
puts "args:"
|
41
|
+
pp args
|
42
|
+
|
43
|
+
if args.size < 1
|
44
|
+
puts "!! ERROR - no collection found - use <collection> <command>..."
|
45
|
+
puts ""
|
46
|
+
exit
|
47
|
+
end
|
48
|
+
|
49
|
+
slug = args[0]
|
50
|
+
command = args[1] || 'image'
|
51
|
+
|
52
|
+
if ['m', 'meta'].include?( command )
|
53
|
+
do_download_meta( slug )
|
54
|
+
elsif ['stat', 'stats'].include?( command )
|
55
|
+
do_dump_stats( slug )
|
56
|
+
elsif ['i','img', 'image'].include?( command )
|
57
|
+
do_download_images( slug )
|
58
|
+
elsif ['conv','convert'].include?( command )
|
59
|
+
do_convert_images( slug )
|
60
|
+
elsif ['fix'].include?( command )
|
61
|
+
do_fix_images( slug )
|
62
|
+
elsif ['px','pix', 'pixelate' ].include?( command )
|
63
|
+
do_pixelate( slug )
|
64
|
+
elsif ['comp','composite' ].include?( command )
|
65
|
+
if options.has_key?( :limit )
|
66
|
+
do_make_composite( slug, limit: options[:limit] )
|
67
|
+
else
|
68
|
+
do_make_composite( slug )
|
69
|
+
end
|
70
|
+
else
|
71
|
+
puts "!! ERROR - unknown command >#{command}<, sorry"
|
72
|
+
end
|
73
|
+
|
74
|
+
puts "bye"
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def self.do_dump_stats( slug )
|
79
|
+
puts "==> dump inscription stats for collection >#{slug}<..."
|
80
|
+
|
81
|
+
col = Collection.new( slug )
|
82
|
+
col.dump_stats
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.do_download_meta( slug )
|
86
|
+
puts "==> download meta for collection >#{slug}<..."
|
87
|
+
|
88
|
+
col = Collection.new( slug )
|
89
|
+
col.download_meta
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.do_download_images( slug )
|
93
|
+
puts "==> download images for collection >#{slug}<..."
|
94
|
+
|
95
|
+
col = Collection.new( slug )
|
96
|
+
col.download_images
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
def self.do_convert_images( slug )
|
101
|
+
puts "==> convert images for collection >#{slug}<..."
|
102
|
+
|
103
|
+
col = Collection.new( slug )
|
104
|
+
col.convert_images
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.do_fix_images( slug )
|
108
|
+
puts "==> fix images for collection >#{slug}<..."
|
109
|
+
|
110
|
+
col = Collection.new( slug )
|
111
|
+
col.fix_images
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
def self.do_pixelate( slug )
|
116
|
+
puts "==> downsample / pixelate images for collection >#{slug}<..."
|
117
|
+
|
118
|
+
col = Collection.new( slug )
|
119
|
+
col.pixelate
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.do_make_composite( slug, limit: nil )
|
123
|
+
puts "==> make composite for collection >#{slug}<..."
|
124
|
+
|
125
|
+
col = Collection.new( slug )
|
126
|
+
col.make_composite( limit: limit )
|
127
|
+
end
|
128
|
+
|
129
|
+
end # class Tool
|
130
|
+
end # module Ordinals
|
data/lib/ordbase.rb
ADDED
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ordbase
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gerald Bauer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-03-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ordinals
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pixelart
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rdoc
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.0'
|
48
|
+
- - "<"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '7'
|
51
|
+
type: :development
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '4.0'
|
58
|
+
- - "<"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '7'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: hoe
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '3.23'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.23'
|
75
|
+
description: ordbase gem - "right-clicker" (off-chain) ordinals (pixel art) command-line
|
76
|
+
tool, machinery & helpers for Bitcoin, Litecoin, Dogecoin & co.
|
77
|
+
email: wwwmake@googlegroups.com
|
78
|
+
executables:
|
79
|
+
- ordbase
|
80
|
+
extensions: []
|
81
|
+
extra_rdoc_files:
|
82
|
+
- CHANGELOG.md
|
83
|
+
- Manifest.txt
|
84
|
+
- README.md
|
85
|
+
files:
|
86
|
+
- CHANGELOG.md
|
87
|
+
- Manifest.txt
|
88
|
+
- README.md
|
89
|
+
- Rakefile
|
90
|
+
- bin/ordbase
|
91
|
+
- lib/ordbase.rb
|
92
|
+
- lib/ordbase/collection.rb
|
93
|
+
- lib/ordbase/stats.rb
|
94
|
+
- lib/ordbase/tool.rb
|
95
|
+
homepage: https://github.com/pixelartexchange/artbase
|
96
|
+
licenses:
|
97
|
+
- Public Domain
|
98
|
+
metadata: {}
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options:
|
101
|
+
- "--main"
|
102
|
+
- README.md
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '2.3'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubygems_version: 3.3.7
|
117
|
+
signing_key:
|
118
|
+
specification_version: 4
|
119
|
+
summary: ordbase gem - "right-clicker" (off-chain) ordinals (pixel art) command-line
|
120
|
+
tool, machinery & helpers for Bitcoin, Litecoin, Dogecoin & co.
|
121
|
+
test_files: []
|