Class: OrdDb::Model::Inscribe

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
lib/ordlite/importer.rb,
lib/ordlite/models/forward.rb,
lib/ordlite/models/inscribe.rb

Constant Summary collapse

TITLE_RX =

“title”: “Inscription 9992615”,

/^Inscription (?<num>[0-9]+)$/i
CONTENT_LENGTH_RX =
/^(?<num>[0-9]+) bytes$/i

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

._content_length_to_bytes(str) ⇒ Object



195
196
197
198
199
200
201
202
# File 'lib/ordlite/models/inscribe.rb', line 195

def self._content_length_to_bytes( str )
    if m=CONTENT_LENGTH_RX.match( str )
       m[:num].to_i(10)    ## use base 10
    else
       puts "!! ERROR - bytes found in content lenght >#{str}<"
       exit 1   ## not found - raise exception - why? why not?
    end
end

._parse_api(data) ⇒ Object

parse api json data



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/ordlite/models/inscribe.rb', line 157

def self._parse_api( data )   ## parse api json data
   ## num via title
   attributes = {
    id:  data['id'],
    num: _title_to_num( data['title'] ),
    bytes: _content_length_to_bytes( data['content-length'] ), 
    sat:  data['sat'].to_i(10),
    content_type:  data['content-type'],
    block: data['genesis-height'].to_i(10),
    fee: data['genesis-fee'].to_i(10),
    tx: data['genesis-transaction'],
    address: data['address'],
    output: data['output'],
    value: data['output-value'].to_i(10),
    offset: data['offset'].to_i(10),
    # "2023-06-01 05:00:57 UTC"
    date:  DateTime.strptime( data['timestamp'], 
                              '%Y-%m-%d %H:%M:%S %z')
  }

  attributes
end

._title_to_num(str) ⇒ Object



184
185
186
187
188
189
190
191
# File 'lib/ordlite/models/inscribe.rb', line 184

def self._title_to_num( str )
   if m=TITLE_RX.match( str )
      m[:num].to_i(10)    ## use base 10
   else
     puts "!! ERROR - no inscribe num found in title >#{str}<"
     exit 1   ## not found - raise exception - why? why not?
   end
end

.address_countsObject Also known as: counts_by_address



79
80
81
82
# File 'lib/ordlite/models/inscribe.rb', line 79

def self.address_counts
    group( 'address' )
     .order( Arel.sql( 'COUNT(*) DESC')).count
end

.block_countsObject Also known as: counts_by_block



84
85
86
87
# File 'lib/ordlite/models/inscribe.rb', line 84

def self.block_counts
    group( 'block' )
     .order( 'block').count
end

.block_with_timestamp_countsObject Also known as: counts_by_block_with_timestamp



89
90
91
92
# File 'lib/ordlite/models/inscribe.rb', line 89

def self.block_with_timestamp_counts
    group( Arel.sql( "block || ' @ ' || date" ))
     .order( Arel.sql( "block || ' @ ' || date" ) ).count
end

.content_type_countsObject Also known as: counts_by_content_type



94
95
96
97
# File 'lib/ordlite/models/inscribe.rb', line 94

def self.content_type_counts
    group( 'content_type' )
    .order( Arel.sql( 'COUNT(*) DESC, content_type')).count
end

.create_from_api(data) ⇒ Object Also known as: create_from_cache



151
# File 'lib/ordlite/models/inscribe.rb', line 151

def self.create_from_api( data ) create( _parse_api( data )); end

.date_countsObject Also known as: counts_by_date, counts_by_day



100
101
102
103
104
# File 'lib/ordlite/models/inscribe.rb', line 100

def self.date_counts
    ## note: strftime is SQLite specific/only!!!
   group( Arel.sql("strftime('%Y-%m-%d', date)"))
     .order( Arel.sql("strftime('%Y-%m-%d', date)")).count
end

.deploysObject

scope like helpers



21
22
23
24
25
26
27
28
29
# File 'lib/ordlite/models/inscribe.rb', line 21

def self.deploys 
  where_clause =<<SQL 
content LIKE '%deploy%' 
AND (   content LIKE '%orc-721%' 
 OR content LIKE '%og%')
SQL

   joins(:blob).where( where_clause ).order( 'num' )
end

.deploys_by(slug:) ⇒ Object



31
32
33
34
35
36
37
38
39
40
# File 'lib/ordlite/models/inscribe.rb', line 31

def self.deploys_by( slug: )
         where_clause =<<SQL 
content LIKE '%deploy%' 
AND (   content LIKE '%orc-721%' 
 OR content LIKE '%og%')
AND content LIKE '%#{slug}%'     
SQL

  joins(:blob).where( where_clause ).order( 'num' )
end

.hour_countsObject Also known as: counts_by_hour



112
113
114
115
116
# File 'lib/ordlite/models/inscribe.rb', line 112

def self.hour_counts
   ## note: strftime is SQLite specific/only!!!
    group( Arel.sql("strftime('%Y-%m-%d %Hh', date)"))
    .order( Arel.sql("strftime('%Y-%m-%d %Hh', date)")).count
end

.import(id_or_ids, content: true) ⇒ Object



211
212
213
# File 'lib/ordlite/importer.rb', line 211

def self.import( id_or_ids, content: true )
    OrdDb.importer.import( id_or_ids, content: content )
end

.largestObject Also known as: biggest



75
76
77
# File 'lib/ordlite/models/inscribe.rb', line 75

def self.largest
   order( 'bytes DESC' )
end

.mintsObject



42
43
44
45
46
47
48
49
50
# File 'lib/ordlite/models/inscribe.rb', line 42

def self.mints 
  where_clause =<<SQL 
content LIKE '%mint%' 
AND (   content LIKE '%orc-721%' 
 OR content LIKE '%og%')
SQL

   joins(:blob).where( where_clause ).order( 'num' )
end

.mints_by(slug:) ⇒ Object



52
53
54
55
56
57
58
59
60
61
# File 'lib/ordlite/models/inscribe.rb', line 52

def self.mints_by( slug: ) 
  where_clause =<<SQL 
content LIKE '%mint%' 
AND (   content LIKE '%orc-721%' 
 OR content LIKE '%og%')
AND content LIKE '%#{slug}%'     
SQL

   joins(:blob).where( where_clause ).order( 'num' )
end

.month_countsObject Also known as: counts_by_month



106
107
108
109
110
# File 'lib/ordlite/models/inscribe.rb', line 106

def self.month_counts
   ## note: strftime is SQLite specific/only!!!
   group( Arel.sql("strftime('%Y-%m', date)"))
    .order( Arel.sql("strftime('%Y-%m', date)")).count
end

.pngObject



145
# File 'lib/ordlite/models/inscribe.rb', line 145

def self.png() where( content_type: 'image/png' ); end

.sub100kObject



67
# File 'lib/ordlite/models/inscribe.rb', line 67

def self.sub100k()  where( 'num < 100000' ); end

.sub10kObject



65
# File 'lib/ordlite/models/inscribe.rb', line 65

def self.sub10k()  where( 'num < 10000' ); end

.sub10mObject



70
# File 'lib/ordlite/models/inscribe.rb', line 70

def self.sub10m()  where( 'num < 10000000' ); end

.sub1kObject



63
# File 'lib/ordlite/models/inscribe.rb', line 63

def self.sub1k()  where( 'num < 1000' ); end

.sub1mObject



68
# File 'lib/ordlite/models/inscribe.rb', line 68

def self.sub1m()  where( 'num < 1000000' ); end

.sub20kObject



66
# File 'lib/ordlite/models/inscribe.rb', line 66

def self.sub20k()  where( 'num < 20000' ); end

.sub20mObject



71
# File 'lib/ordlite/models/inscribe.rb', line 71

def self.sub20m()  where( 'num < 20000000' ); end

.sub21mObject



72
# File 'lib/ordlite/models/inscribe.rb', line 72

def self.sub21m()  where( 'num < 21000000' ); end

.sub2kObject



64
# File 'lib/ordlite/models/inscribe.rb', line 64

def self.sub2k()  where( 'num < 2000' ); end

.sub2mObject



69
# File 'lib/ordlite/models/inscribe.rb', line 69

def self.sub2m()  where( 'num < 2000000' ); end

.textObject



132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/ordlite/models/inscribe.rb', line 132

def self.text
   ## note: for now include:
   ##   - text/plain (all variants)
   ##   - text/json (all variants)
   ##   - text/markdown
   where( content_type: 
            ['text/plain',
             'text/plain;charset=utf-8',
             'text/markdown',
             'application/json',
            ]
        )
end

Instance Method Details

#contentObject

convernience helper

forward to blob.content
  blob.content - encoding is BINARY (ASCII-7BIT)
  blob.text    - force_encoding is UTF-8 (return a copy)


15
# File 'lib/ordlite/models/inscribe.rb', line 15

def content() blob.content; end

#export(path = export_path) ⇒ Object



272
273
274
275
276
277
278
279
280
281
# File 'lib/ordlite/models/inscribe.rb', line 272

def export( path=export_path )
   if blob
     write_blob( path, blob.content )
   else
      ## todo/fix: raise exception - no content
      puts "!! ERROR - inscribe has no content (blob); sorry:"
      pp self
      exit 1
   end
end

#export_pathObject

default export path



268
269
270
271
# File 'lib/ordlite/models/inscribe.rb', line 268

def export_path  ## default export path
   numstr = "%08d" % num   ###  e.g. 00000001  
   "./tmp/#{numstr}#{extname}" 
end

#extnameObject

instance methods



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/ordlite/models/inscribe.rb', line 208

def extname
  ## map mime type to file extname
  ## see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
  ##  for real-world usage, see https://dune.com/dgtl_assets/bitcoin-ordinals-analysis
  ##  https://github.com/casey/ord/blob/master/src/media.rs

   if content_type.start_with?( 'text/plain' )
      '.txt'
   elsif content_type.start_with?( 'text/markdown' )
      '.md'
   elsif content_type.start_with?( 'text/html' )
      '.html'
   elsif content_type.start_with?( 'text/javascript' ) ||
         content_type.start_with?( 'application/javascript' )
      ## note: application/javascript is considered bad practice/legacy
      '.js'
   elsif content_type.start_with?( 'image/png' )
       ## Portable Network Graphics (PNG)
      '.png'
   elsif content_type.start_with?( 'image/jpeg' )
        ##  Joint Photographic Expert Group image (JPEG) 
       '.jpg'   ## use jpeg - why? why not?
   elsif content_type.start_with?( 'image/webp' )
        ## Web Picture format (WEBP)
       '.webp'   ## note: no three-letter extension available
   elsif content_type.start_with?( 'image/svg' )
        ## Scalable Vector Graphics (SVG) 
       '.svg'
   elsif content_type.start_with?( 'image/gif' ) 
       ##  Graphics Interchange Format (GIF)
       '.gif'
   elsif content_type.start_with?( 'image/avif' )  
       ## AV1 Image File Format (AVIF)
       '.avif'
   elsif content_type.start_with?( 'application/epub' )
       '.epub'
   elsif content_type.start_with?( 'application/pdf' )
       '.pdf'
   elsif content_type.start_with?( 'application/json' )
       '.json'
   elsif content_type.start_with?( 'application/pgp-signature' )
       '.sig'
   elsif content_type.start_with?( 'audio/mpeg' )
       '.mp3'
   elsif content_type.start_with?( 'audio/midi' )
       '.midi'
   elsif content_type.start_with?( 'video/mp4' )
       '.mp4'
   elsif content_type.start_with?( 'video/webm' )
       '.wepm'
   elsif content_type.start_with?( 'audio/mod' )  
      ## is typo? possible? only one inscription in 20m?
       '.mod'   ## check/todo/fix if is .wav?? 
   else
      puts "!! ERROR - no file extension configured for content type >#{content_type}<; sorry:"
      pp self
      exit 1
   end
end

#factoryObject

optional (auto-added via og/orc-721 deploy)



8
# File 'lib/ordlite/models/inscribe.rb', line 8

has_one :factory

#textObject



16
# File 'lib/ordlite/models/inscribe.rb', line 16

def text() blob.text; end