ordinals 1.1.2 → 1.2.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/CHANGELOG.md +1 -1
- data/Manifest.txt +2 -0
- data/README.md +79 -21
- data/Rakefile +2 -1
- data/lib/ordinals/api.rb +81 -4
- data/lib/ordinals/cache.rb +208 -0
- data/lib/ordinals/version.rb +20 -0
- data/lib/ordinals.rb +63 -2
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4dbc3bf008b7d878df205f804f9a30887c0602afc3e16ccb64ed3749be911d82
|
|
4
|
+
data.tar.gz: a5562501103ac3be5d475216c7c1ae45c5f4c1e519105dcdd8adf1250fe5184a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0140e9330cff62dc983f91a5a851cbfc3d188d3711537304e538d3ea8664d7cfebc76d9f19596db60f51b9d23f117f18ec44e9fcebb5dfdf6e72131a8b87b8f6
|
|
7
|
+
data.tar.gz: 7605cf138cf69f8e7b1cf3f8e7e06c837623e1720c558b85f345bb02eb8da07b48c4882a8822ec6e7c9992756a8cb1d04089a27164e71374a26e1f3784e07943
|
data/CHANGELOG.md
CHANGED
data/Manifest.txt
CHANGED
|
@@ -4,8 +4,10 @@ README.md
|
|
|
4
4
|
Rakefile
|
|
5
5
|
lib/ordinals.rb
|
|
6
6
|
lib/ordinals/api.rb
|
|
7
|
+
lib/ordinals/cache.rb
|
|
7
8
|
lib/ordinals/recursive/composite.rb
|
|
8
9
|
lib/ordinals/recursive/generator.rb
|
|
9
10
|
lib/ordinals/recursive/image.rb
|
|
10
11
|
lib/ordinals/sandbox.rb
|
|
11
12
|
lib/ordinals/stats.rb
|
|
13
|
+
lib/ordinals/version.rb
|
data/README.md
CHANGED
|
@@ -13,12 +13,15 @@ ordinals gem - ordinals (inscription) api wrapper & helpers for Bitcoin, Litcoin
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
For now ordinal inscription api queries are supported on
|
|
16
|
-
- Bitcoin (via <https://ordinals.com>)
|
|
17
|
-
- Litecoin (via <https://ordinalslite.com>)
|
|
18
|
-
- Dogecoin (via <https://doginals.com>)
|
|
16
|
+
- Bitcoin (via <https://ordinals.com>) and
|
|
17
|
+
- Litecoin (via <https://ordinalslite.com>)
|
|
19
18
|
|
|
19
|
+
<!--
|
|
20
|
+
chekc if doginals still in operation???
|
|
21
|
+
- Dogecoin (via <https://doginals.com>)
|
|
22
|
+
-->
|
|
20
23
|
|
|
21
|
-
Let's start querying for bitcoin (btc) ordinal inscriptions:
|
|
24
|
+
Let's start querying for bitcoin (btc) ordinal inscriptions by id:
|
|
22
25
|
|
|
23
26
|
``` ruby
|
|
24
27
|
require 'ordinals'
|
|
@@ -44,20 +47,50 @@ pp data
|
|
|
44
47
|
# "address"=>"bc1pyncs638hxfhaqjvnedw2lyc2jta6zuvr9erj6m9cwlghp6qqwvhqeq574l",
|
|
45
48
|
# "output value"=>"9667",
|
|
46
49
|
# "sat"=>"1391087135005306",
|
|
47
|
-
# "
|
|
48
|
-
# "content"=>"
|
|
49
|
-
# "content length"=>"3072 bytes",
|
|
50
|
-
# "content type"=>"image/png",
|
|
50
|
+
# "content-length"=>"3072 bytes",
|
|
51
|
+
# "content-type"=>"image/png",
|
|
51
52
|
# "timestamp"=>"2023-02-18 03:02:18 UTC",
|
|
52
|
-
# "genesis
|
|
53
|
-
# "genesis
|
|
54
|
-
# "genesis
|
|
53
|
+
# "genesis-height"=>"777099",
|
|
54
|
+
# "genesis-fee"=>"1814",
|
|
55
|
+
# "genesis-transaction"=>"c41021cb11dce003e6a20a3420cf5954a1d104a1fe314393b915a62f020dcd0a",
|
|
55
56
|
# "location"=>"6a57dedb854c9bcac3fd2daab1172dd9a45f24c366dd8db33fe80557f11c6b39:22:0",
|
|
56
57
|
# "output"=>"6a57dedb854c9bcac3fd2daab1172dd9a45f24c366dd8db33fe80557f11c6b39:22",
|
|
57
58
|
# "offset"=>"0"}
|
|
58
59
|
```
|
|
59
60
|
|
|
60
61
|
|
|
62
|
+
Or by number (starting at 0):
|
|
63
|
+
|
|
64
|
+
``` ruby
|
|
65
|
+
data = Ordinals.inscription( 21_000_000 )
|
|
66
|
+
pp data
|
|
67
|
+
# GET https://ordinals.com/inscription/4825a59486fa91ee88b6dd58caf0f9ba0f7273e2f30d9eccf9bfdabee55028d2i0...
|
|
68
|
+
#=> {"title"=>"Inscription 21000000",
|
|
69
|
+
# "id"=>"4825a59486fa91ee88b6dd58caf0f9ba0f7273e2f30d9eccf9bfdabee55028d2i0",
|
|
70
|
+
# "address"=>"bc1qq7dx8c9842jm6kf4gn83mft07jqtvye0gm5sq9",
|
|
71
|
+
# "output-value"=>"330",
|
|
72
|
+
# "sat"=>"1894095647358032",
|
|
73
|
+
# "content-length"=>"57 bytes",
|
|
74
|
+
# "content-type"=>"text/plain",
|
|
75
|
+
# "timestamp"=>"2023-08-02 11:00:22 UTC",
|
|
76
|
+
# "genesis-height"=>"801343",
|
|
77
|
+
# "genesis-fee"=>"842",
|
|
78
|
+
# "genesis-transaction"=>"4825a59486fa91ee88b6dd58caf0f9ba0f7273e2f30d9eccf9bfdabee55028d2",
|
|
79
|
+
# "location"=>"4825a59486fa91ee88b6dd58caf0f9ba0f7273e2f30d9eccf9bfdabee55028d2:0:0",
|
|
80
|
+
# "output"=>"4825a59486fa91ee88b6dd58caf0f9ba0f7273e2f30d9eccf9bfdabee55028d2:0",
|
|
81
|
+
# "offset"=>"0"}
|
|
82
|
+
|
|
83
|
+
content = Ordinals.content( 21_000_000 )
|
|
84
|
+
pp content
|
|
85
|
+
# GET https://ordinals.com/content/4825a59486fa91ee88b6dd58caf0f9ba0f7273e2f30d9eccf9bfdabee55028d2i0...
|
|
86
|
+
#=> <Ordinals::Api::Content:0x0000028bd4c1ff18
|
|
87
|
+
# @data="{\"p\":\"brc-20\",\"op\":\"mint\",\"tick\":\"sats\",\"amt\":\"99999999\"}",
|
|
88
|
+
# @length=nil,
|
|
89
|
+
# @type="text/plain">
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
61
94
|
Let's try querying for litecoin (ltc) ordinal inscriptions:
|
|
62
95
|
|
|
63
96
|
``` ruby
|
|
@@ -83,18 +116,43 @@ pp data
|
|
|
83
116
|
#=> {"title"=>"Inscription 642",
|
|
84
117
|
# "id"=>"f2b6adf7b2d0f128fb14817ff37f5f36e9176b17571e20c49871875553f937b4i0",
|
|
85
118
|
# "address"=>"LSDz4fM4mLFyAZVoDuKyMHYq3af6cSZGSY",
|
|
86
|
-
# "output
|
|
87
|
-
# "
|
|
88
|
-
# "content"=>"
|
|
89
|
-
# "content length"=>"816 bytes",
|
|
90
|
-
# "content type"=>"image/png",
|
|
119
|
+
# "output-value"=>"9878",
|
|
120
|
+
# "content-length"=>"816 bytes",
|
|
121
|
+
# "content-type"=>"image/png",
|
|
91
122
|
# "timestamp"=>"2023-02-21 05:29:33 UTC",
|
|
92
|
-
# "genesis
|
|
93
|
-
# "genesis
|
|
94
|
-
# "genesis
|
|
123
|
+
# "genesis-height"=>"2426201",
|
|
124
|
+
# "genesis-fee"=>"361",
|
|
125
|
+
# "genesis-transaction"=>"f2b6adf7b2d0f128fb14817ff37f5f36e9176b17571e20c49871875553f937b4",
|
|
95
126
|
# "location"=>"6802c71b49f18aab91d0b363762b24afb1bf00c4820a5f782de6dd1b1cfbd68a:0:0",
|
|
96
127
|
# "output"=>"6802c71b49f18aab91d0b363762b24afb1bf00c4820a5f782de6dd1b1cfbd68a:0",
|
|
97
128
|
# "offset"=>"0"}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
content = Ordinals.content( 0 )
|
|
132
|
+
pp content
|
|
133
|
+
# GET https://ordinalslite.com/content/71e0f6dc87a473aa69787fff8e09e5eddfdca96e587928a5b1a25c0ae16dc0eei0...
|
|
134
|
+
#=> <Ordinals::Api::Content:0x00000242a9a874e0
|
|
135
|
+
# @data="%PDF-1.3\...",
|
|
136
|
+
# @length=nil,
|
|
137
|
+
# @type="application/pdf">
|
|
138
|
+
|
|
139
|
+
data = Ordinals.inscription( 0 )
|
|
140
|
+
pp data
|
|
141
|
+
# GET https://ordinalslite.com/inscription/71e0f6dc87a473aa69787fff8e09e5eddfdca96e587928a5b1a25c0ae16dc0eei0...
|
|
142
|
+
#=> {"title"=>"Inscription 0",
|
|
143
|
+
# "id"=>"71e0f6dc87a473aa69787fff8e09e5eddfdca96e587928a5b1a25c0ae16dc0eei0",
|
|
144
|
+
# "address"=>"ltc1qz7qy4m8nhfqggxrtj308njs52lu9f5l9v7d5wd",
|
|
145
|
+
# "output-value"=>"10000",
|
|
146
|
+
# "sat"=>"906691404536244",
|
|
147
|
+
# "content-length"=>"57237 bytes",
|
|
148
|
+
# "content-type"=>"application/pdf",
|
|
149
|
+
# "timestamp"=>"2023-02-19 20:26:43 UTC",
|
|
150
|
+
# "genesis-height"=>"2425370",
|
|
151
|
+
# "genesis-fee"=>"15968",
|
|
152
|
+
# "genesis-transaction"=>"71e0f6dc87a473aa69787fff8e09e5eddfdca96e587928a5b1a25c0ae16dc0ee",
|
|
153
|
+
# "location"=>"71e0f6dc87a473aa69787fff8e09e5eddfdca96e587928a5b1a25c0ae16dc0ee:0:0",
|
|
154
|
+
# "output"=>"71e0f6dc87a473aa69787fff8e09e5eddfdca96e587928a5b1a25c0ae16dc0ee:0",
|
|
155
|
+
# "offset"=>"0"}
|
|
98
156
|
```
|
|
99
157
|
|
|
100
158
|
That's it.
|
|
@@ -267,7 +325,7 @@ composite = RecursiveImageComposite.new( 10, 10, width: 96,
|
|
|
267
325
|
data = read_json( "./ordinalpunks.json" )
|
|
268
326
|
puts " #{data['items'].size} inscribe(s)"
|
|
269
327
|
|
|
270
|
-
data['items'].
|
|
328
|
+
data['items'].each do |rec|
|
|
271
329
|
id = rec['inscription_id']
|
|
272
330
|
comment = rec['name']
|
|
273
331
|
|
|
@@ -353,7 +411,7 @@ Use it as you please with no restrictions whatsoever.
|
|
|
353
411
|
## Questions? Comments?
|
|
354
412
|
|
|
355
413
|
Join us in the [Ordgen / ORC-721 discord (chat server)](https://discord.gg/dDhvHKjm2t). Yes you can.
|
|
356
|
-
Your questions and
|
|
414
|
+
Your questions and commentary welcome.
|
|
357
415
|
|
|
358
416
|
|
|
359
417
|
Or post them over at the [Help & Support](https://github.com/geraldb/help) page. Thanks.
|
data/Rakefile
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'hoe'
|
|
2
|
+
require './lib/ordinals/version.rb'
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
###
|
|
@@ -10,7 +11,7 @@ require 'hoe'
|
|
|
10
11
|
|
|
11
12
|
Hoe.spec 'ordinals' do
|
|
12
13
|
|
|
13
|
-
self.version =
|
|
14
|
+
self.version = Ordinals::VERSION
|
|
14
15
|
|
|
15
16
|
self.summary = 'ordinals gem - ordinals (inscription) api wrapper & helpers for Bitcoin, Litecoin, Dogecoin & co.'
|
|
16
17
|
self.description = summary
|
data/lib/ordinals/api.rb
CHANGED
|
@@ -24,9 +24,13 @@ class Api ## change/rename Api to Client - why? why not?
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
|
|
27
|
+
def config() Ordinals.config; end ## convenience shortcut helper
|
|
28
|
+
|
|
27
29
|
def initialize( base, inscription: 'inscription' )
|
|
28
|
-
@base
|
|
29
|
-
@inscription
|
|
30
|
+
@base = base
|
|
31
|
+
@inscription = inscription
|
|
32
|
+
@requests = 0 ## count requests (for delay_in_s sleeping/throttling)
|
|
33
|
+
@pages = {} ## (0-)99, (100-)199, (200-)299 etc.
|
|
30
34
|
end
|
|
31
35
|
|
|
32
36
|
|
|
@@ -46,8 +50,9 @@ class Content
|
|
|
46
50
|
end ## (nested) class Content
|
|
47
51
|
|
|
48
52
|
|
|
53
|
+
def content( num_or_id )
|
|
54
|
+
id = num_or_id.is_a?( Integer ) ? _num_to_id( num_or_id ) : num_or_id
|
|
49
55
|
|
|
50
|
-
def content( id )
|
|
51
56
|
src = "#{@base}/content/#{id}"
|
|
52
57
|
res = get( src )
|
|
53
58
|
|
|
@@ -67,6 +72,56 @@ end ## (nested) class Content
|
|
|
67
72
|
end
|
|
68
73
|
|
|
69
74
|
|
|
75
|
+
INSCRIBE_ID_RX = %r{
|
|
76
|
+
inscription/(?<id>[a-fi0-9]+)
|
|
77
|
+
}ix
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def inscription_ids( offset: ) ## note: page size is for now fixed 100
|
|
81
|
+
ids = []
|
|
82
|
+
|
|
83
|
+
src = "#{@base}/inscriptions/#{offset}"
|
|
84
|
+
res = get( src )
|
|
85
|
+
|
|
86
|
+
page = res.text ### assumes utf-8 for now
|
|
87
|
+
page.scan( INSCRIBE_ID_RX ) do |_|
|
|
88
|
+
m = Regexp.last_match
|
|
89
|
+
ids << m[:id]
|
|
90
|
+
end
|
|
91
|
+
puts " #{ids.size} inscribe id(s)"
|
|
92
|
+
ids = ids.reverse ## assume latest inscribe id is on top (reverse)
|
|
93
|
+
ids
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def sub10k_ids
|
|
97
|
+
ids = []
|
|
98
|
+
limit = 100
|
|
99
|
+
|
|
100
|
+
100.times do |i| ## fetch first hundred (100*100=10000) inscribe ids
|
|
101
|
+
offset = 99 + limit*i
|
|
102
|
+
puts "==> #{i} - @ #{offset}..."
|
|
103
|
+
ids += inscription_ids( offset: offset )
|
|
104
|
+
end
|
|
105
|
+
puts " #{ids.size} inscribe id(s) - total"
|
|
106
|
+
ids
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _num_to_id( num )
|
|
111
|
+
limit = 100
|
|
112
|
+
page, i = num.divmod( limit )
|
|
113
|
+
offset = 99+limit*page
|
|
114
|
+
## e.g. 100.divmod( 100 ) => [1,0]
|
|
115
|
+
## 100.divmod( 100 ) => [0,0]
|
|
116
|
+
## 99.divmod( 100 ) => [0,99]
|
|
117
|
+
## etc.
|
|
118
|
+
|
|
119
|
+
## auto-add to page cache
|
|
120
|
+
ids = @pages[ offset ] ||= inscription_ids( offset: offset )
|
|
121
|
+
ids[i]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
|
|
70
125
|
=begin
|
|
71
126
|
<dl>
|
|
72
127
|
<dt>id</dt>
|
|
@@ -158,7 +213,9 @@ offset: 0
|
|
|
158
213
|
|
|
159
214
|
=end
|
|
160
215
|
|
|
161
|
-
def inscription(
|
|
216
|
+
def inscription( num_or_id )
|
|
217
|
+
id = num_or_id.is_a?( Integer ) ? _num_to_id( num_or_id ) : num_or_id
|
|
218
|
+
|
|
162
219
|
src = "#{@base}/#{@inscription}/#{id}"
|
|
163
220
|
res = get( src )
|
|
164
221
|
|
|
@@ -203,14 +260,34 @@ offset: 0
|
|
|
203
260
|
data[ k ] = v
|
|
204
261
|
end
|
|
205
262
|
data
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
## post process to convert to headers format
|
|
266
|
+
## e.g. replace space with -
|
|
267
|
+
## and remove/exclude content & preview
|
|
268
|
+
h = {}
|
|
269
|
+
data.each do |k,v|
|
|
270
|
+
next if ['preview', 'content'].include?( k )
|
|
271
|
+
h[ k.gsub( ' ', '-') ] = v
|
|
272
|
+
end
|
|
273
|
+
h
|
|
206
274
|
end
|
|
207
275
|
|
|
208
276
|
|
|
209
277
|
def get( src )
|
|
278
|
+
@requests += 1
|
|
279
|
+
|
|
280
|
+
if @requests > 1 && config.delay_in_s
|
|
281
|
+
puts "request no. #{@requests}@#{@base}; sleeping #{config.delay_in_s} sec(s)..."
|
|
282
|
+
sleep( config.delay_in_s )
|
|
283
|
+
end
|
|
284
|
+
|
|
210
285
|
res = Webclient.get( src )
|
|
286
|
+
|
|
211
287
|
if res.status.ok?
|
|
212
288
|
res
|
|
213
289
|
else
|
|
290
|
+
## todo/fix: raise exception here!!!!
|
|
214
291
|
puts "!! ERROR - HTTP #{res.status.code} #{res.status.message} - failed web request >#{src}<; sorry"
|
|
215
292
|
exit 1
|
|
216
293
|
end
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
|
|
2
|
+
module Ordinals
|
|
3
|
+
|
|
4
|
+
class Cache
|
|
5
|
+
|
|
6
|
+
def initialize( dir )
|
|
7
|
+
@dir = dir
|
|
8
|
+
@force = false
|
|
9
|
+
@delay_in_s = 0.5 ## wait 0.5s before next (possible) request
|
|
10
|
+
@requests = 0
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def json_to_txt( data )
|
|
16
|
+
buf = ''
|
|
17
|
+
data.each do |k,v|
|
|
18
|
+
next if ['preview', 'content'].include?( k )
|
|
19
|
+
buf << "#{k.gsub( ' ', '-')}: #{v}\n"
|
|
20
|
+
end
|
|
21
|
+
buf
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _find_blobs
|
|
27
|
+
## note: *.{txt,json,png} will also include *.meta.txt
|
|
28
|
+
### CANNOT use, thus, try *i?.*
|
|
29
|
+
Dir.glob( "#{@dir}/**/*i?.{txt,json,png}" )
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def _find_meta
|
|
33
|
+
Dir.glob( "#{@dir}/**/*.meta.txt" )
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def stats
|
|
37
|
+
paths = _find_meta
|
|
38
|
+
puts " #{paths.size} inscribe metadatafile(s) found"
|
|
39
|
+
|
|
40
|
+
paths = _find_blobs
|
|
41
|
+
puts " #{paths.size} inscribe blob(s) found"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def add( id )
|
|
50
|
+
## step 1) get metadata records
|
|
51
|
+
meta_path = "#{@dir}/#{id[0,2]}/#{id[2..-1]}.meta.txt"
|
|
52
|
+
|
|
53
|
+
meta = nil
|
|
54
|
+
if !@force && File.exist?( meta_path )
|
|
55
|
+
meta = read_headers( meta_path )
|
|
56
|
+
print "."
|
|
57
|
+
else
|
|
58
|
+
print " meta-#{id} "
|
|
59
|
+
sleep( @delay_in_s ) if @delay_in_s && @requests > 0
|
|
60
|
+
|
|
61
|
+
## fetch and cache in cache
|
|
62
|
+
meta = Ordinals.inscription( id )
|
|
63
|
+
pp meta
|
|
64
|
+
meta_txt = json_to_txt( meta )
|
|
65
|
+
|
|
66
|
+
write_text( meta_path, meta_txt )
|
|
67
|
+
@requests += 1
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
content_type = meta['content-type']
|
|
72
|
+
extname = if content_type.start_with?( 'text/plain' )
|
|
73
|
+
'.txt'
|
|
74
|
+
elsif content_type.start_with?( 'application/json' )
|
|
75
|
+
'.json'
|
|
76
|
+
elsif content_type.start_with?( 'image/png' )
|
|
77
|
+
'.png'
|
|
78
|
+
else
|
|
79
|
+
puts "!! ERROR - unexpected content type; got: #{content_type}"
|
|
80
|
+
## pp meta
|
|
81
|
+
exit 1
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
path = "#{@dir}/#{id[0,2]}/#{id[2..-1]}#{extname}"
|
|
86
|
+
if !@force && File.exist?( path )
|
|
87
|
+
## puts " in cache"
|
|
88
|
+
print "."
|
|
89
|
+
else
|
|
90
|
+
print " blob-#{id} "
|
|
91
|
+
sleep( @delay_in_s ) if @delay_in_s && @requests > 0
|
|
92
|
+
|
|
93
|
+
## note: save text as blob - byte-by-byte as is (might be corrupt text)
|
|
94
|
+
content = Ordinals.content( id )
|
|
95
|
+
## pp content
|
|
96
|
+
## puts "data:"
|
|
97
|
+
## puts content.data
|
|
98
|
+
|
|
99
|
+
write_blob( path, content.data )
|
|
100
|
+
end
|
|
101
|
+
end # method add
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _prepare_csv( path )
|
|
105
|
+
ids = []
|
|
106
|
+
recs = read_csv( path )
|
|
107
|
+
recs.each do |rec|
|
|
108
|
+
ids << rec['id']
|
|
109
|
+
end
|
|
110
|
+
ids
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def add_csv( path )
|
|
114
|
+
ids = _prepare_csv( path )
|
|
115
|
+
ids = ids.uniq ## make uniq by default - why? why not?
|
|
116
|
+
puts " #{ids.size} inscribe id(s)"
|
|
117
|
+
ids.each { |id| add(id) }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
## get inscription links
|
|
123
|
+
## e.g.
|
|
124
|
+
## inscription/e8830c5fbdfc2f529350fd04a2ac20bb097dce98f159223837513ae3c8d05714i0
|
|
125
|
+
|
|
126
|
+
=begin
|
|
127
|
+
INSCRIBE_ID_RX = %r{
|
|
128
|
+
/b # boundry (non-alphanum)
|
|
129
|
+
(?<id>[a-f0-9]{64}i[0-9])
|
|
130
|
+
/b # boundry (non-alphanum)
|
|
131
|
+
}ix
|
|
132
|
+
=end
|
|
133
|
+
|
|
134
|
+
INSCRIBE_ID_RX = %r{
|
|
135
|
+
inscription/(?<id>[a-fi0-9]+)
|
|
136
|
+
}ix
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
##
|
|
140
|
+
## strict rx gets:
|
|
141
|
+
## 168 inscribe id(s)
|
|
142
|
+
## 118 inscribe id(s) - unique
|
|
143
|
+
##
|
|
144
|
+
## loose gets:
|
|
145
|
+
## 300 inscribe id(s)
|
|
146
|
+
## 250 inscribe id(s) - unique
|
|
147
|
+
##
|
|
148
|
+
## /b for boundray NOT working - why? why not?
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _prepare_html( path )
|
|
152
|
+
ids = []
|
|
153
|
+
txt = read_text( path )
|
|
154
|
+
txt.scan( INSCRIBE_ID_RX ) do |_|
|
|
155
|
+
m = Regexp.last_match
|
|
156
|
+
|
|
157
|
+
ids << m[:id]
|
|
158
|
+
end
|
|
159
|
+
ids
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def add_html( path )
|
|
163
|
+
ids = _prepare_html( path )
|
|
164
|
+
ids = ids.uniq ## make uniq by default - why? why not?
|
|
165
|
+
puts " #{ids.size} inscribe id(s)"
|
|
166
|
+
ids.each { |id| add(id) }
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def _prepare_dir( dir )
|
|
170
|
+
ids = []
|
|
171
|
+
|
|
172
|
+
## in html format
|
|
173
|
+
pages = Dir.glob( "#{dir}/**/*.html")
|
|
174
|
+
pages.each do |path|
|
|
175
|
+
ids += _prepare_html( path )
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
### in csv format
|
|
179
|
+
datasets = Dir.glob( "#{dir}/**/*.csv")
|
|
180
|
+
datasets.each do |path|
|
|
181
|
+
ids += _prepare_csv( path )
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
ids
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def add_dir( dir )
|
|
188
|
+
ids = _prepare_dir( dir )
|
|
189
|
+
puts " #{ids.size} inscribe id(s)"
|
|
190
|
+
## turn into symbol (to make uniq work ??)
|
|
191
|
+
ids = ids.uniq
|
|
192
|
+
pp ids
|
|
193
|
+
puts " #{ids.size} inscribe id(s) - unique"
|
|
194
|
+
ids.each { |id| add(id) }
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def read( id )
|
|
200
|
+
_read_inscribe( "#{@dir}/#{id[0,2]}/#{id[2..-1]}.meta.txt" )
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def _read_inscribe( path )
|
|
204
|
+
read_headers( path )
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
end # class Cache
|
|
208
|
+
end # module Ordinals
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
module Ordinals
|
|
3
|
+
# sync version w/ sport.db n friends - why? why not?
|
|
4
|
+
MAJOR = 1 ## todo: namespace inside version or something - why? why not??
|
|
5
|
+
MINOR = 2
|
|
6
|
+
PATCH = 0
|
|
7
|
+
VERSION = [MAJOR,MINOR,PATCH].join('.')
|
|
8
|
+
|
|
9
|
+
def self.version
|
|
10
|
+
VERSION
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.banner
|
|
14
|
+
"ordinals/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}] in >#{root}<"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.root
|
|
18
|
+
File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )
|
|
19
|
+
end
|
|
20
|
+
end
|
data/lib/ordinals.rb
CHANGED
|
@@ -5,6 +5,49 @@ require 'nokogiri'
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
### todo/fix:
|
|
9
|
+
### move upstream - read_headers
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# note: key only supports a-z0-9 AND dash(-)
|
|
13
|
+
# no underscore(_) or dot(.)
|
|
14
|
+
#
|
|
15
|
+
# follow HTTP headers and domain names format
|
|
16
|
+
##
|
|
17
|
+
|
|
18
|
+
HEADER_RX = /\A(?<key>[a-z][a-z0-9-]*)
|
|
19
|
+
:
|
|
20
|
+
[ ]*
|
|
21
|
+
(?<value>.+?) ## non-greedy
|
|
22
|
+
\z
|
|
23
|
+
/x
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def read_headers( path )
|
|
27
|
+
txt = read_text( path )
|
|
28
|
+
h = {}
|
|
29
|
+
txt.each_line do |line|
|
|
30
|
+
line = line.strip
|
|
31
|
+
## skip empty and comment lines
|
|
32
|
+
next if line.empty? || line.start_with?( '#' )
|
|
33
|
+
|
|
34
|
+
if m=HEADER_RX.match(line)
|
|
35
|
+
key = m[:key]
|
|
36
|
+
value = m[:value]
|
|
37
|
+
|
|
38
|
+
h[key] = value
|
|
39
|
+
else
|
|
40
|
+
puts "!! ERROR - parse error - no header pattern match for:"
|
|
41
|
+
puts line
|
|
42
|
+
exit 1
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
h
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
8
51
|
|
|
9
52
|
module Ordinals
|
|
10
53
|
class Configuration
|
|
@@ -43,6 +86,15 @@ module Ordinals
|
|
|
43
86
|
self.chain = 'btc' unless defined?( @client )
|
|
44
87
|
@client
|
|
45
88
|
end
|
|
89
|
+
|
|
90
|
+
def delay_in_s
|
|
91
|
+
## note - default to 1 (sec) if not set
|
|
92
|
+
self.delay_in_s = 1 unless defined?( @delay_in_s )
|
|
93
|
+
@delay_in_s
|
|
94
|
+
end
|
|
95
|
+
def delay_in_s=(value) @delay_in_s = value; end
|
|
96
|
+
alias_method :sleep, :delay_in_s ## add sleep alias (or wait) - why? why not?
|
|
97
|
+
alias_method :sleep=, :delay_in_s=
|
|
46
98
|
end # class Configuration
|
|
47
99
|
|
|
48
100
|
|
|
@@ -76,16 +128,21 @@ module Ordinals
|
|
|
76
128
|
|
|
77
129
|
###################
|
|
78
130
|
### more convenience shortcuts
|
|
79
|
-
def self.inscription(
|
|
80
|
-
def self.content(
|
|
131
|
+
def self.inscription( num_or_id ) client.inscription( num_or_id ); end
|
|
132
|
+
def self.content( num_or_id ) client.content( num_or_id ); end
|
|
133
|
+
|
|
134
|
+
def self.inscription_ids( offset: ) client.inscription_ids( offset: offset ); end
|
|
135
|
+
def self.sub10k_ids() client.sub10k_ids; end
|
|
81
136
|
end # module Ordinals
|
|
82
137
|
|
|
83
138
|
|
|
84
139
|
|
|
85
140
|
|
|
86
141
|
## our own code
|
|
142
|
+
require_relative 'ordinals/version'
|
|
87
143
|
require_relative 'ordinals/api'
|
|
88
144
|
|
|
145
|
+
require_relative 'ordinals/cache'
|
|
89
146
|
require_relative 'ordinals/sandbox' ## (blob) "flat" content cache by inscribe id (./content)
|
|
90
147
|
require_relative 'ordinals/stats'
|
|
91
148
|
|
|
@@ -100,3 +157,7 @@ require_relative 'ordinals/recursive/generator'
|
|
|
100
157
|
RcsvImage = RecursiveImage
|
|
101
158
|
RcsvImageComposite = RecursiveImageComposite
|
|
102
159
|
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
# say hello
|
|
163
|
+
puts Ordinals.banner ## if defined?($RUBYCOCOS_DEBUG) && $RUBCOCOS_DEBUG
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ordinals
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gerald Bauer
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-
|
|
11
|
+
date: 2023-08-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: cocos
|
|
@@ -88,11 +88,13 @@ files:
|
|
|
88
88
|
- Rakefile
|
|
89
89
|
- lib/ordinals.rb
|
|
90
90
|
- lib/ordinals/api.rb
|
|
91
|
+
- lib/ordinals/cache.rb
|
|
91
92
|
- lib/ordinals/recursive/composite.rb
|
|
92
93
|
- lib/ordinals/recursive/generator.rb
|
|
93
94
|
- lib/ordinals/recursive/image.rb
|
|
94
95
|
- lib/ordinals/sandbox.rb
|
|
95
96
|
- lib/ordinals/stats.rb
|
|
97
|
+
- lib/ordinals/version.rb
|
|
96
98
|
homepage: https://github.com/ordbase/ordbase
|
|
97
99
|
licenses:
|
|
98
100
|
- Public Domain
|