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



247
248
249
250
251
252
253
254
# File 'lib/ordlite/models/inscribe.rb', line 247

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



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/ordlite/models/inscribe.rb', line 209

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



236
237
238
239
240
241
242
243
# File 'lib/ordlite/models/inscribe.rb', line 236

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



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

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

.avifObject



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

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

.block_countsObject Also known as: counts_by_block



147
148
149
150
# File 'lib/ordlite/models/inscribe.rb', line 147

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

.block_with_timestamp_countsObject Also known as: counts_by_block_with_timestamp



152
153
154
155
# File 'lib/ordlite/models/inscribe.rb', line 152

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



157
158
159
160
# File 'lib/ordlite/models/inscribe.rb', line 157

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



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

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

.date_countsObject Also known as: counts_by_date, counts_by_day



163
164
165
166
167
# File 'lib/ordlite/models/inscribe.rb', line 163

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



83
84
85
86
87
88
89
90
91
# File 'lib/ordlite/models/inscribe.rb', line 83

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

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

.deploys_by(slug:) ⇒ Object



93
94
95
96
97
98
99
100
101
102
# File 'lib/ordlite/models/inscribe.rb', line 93

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).text.where( where_clause ).order( 'num' )
end

.gifObject



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

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

.hour_countsObject Also known as: counts_by_hour



175
176
177
178
179
# File 'lib/ordlite/models/inscribe.rb', line 175

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

.htmlObject



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

def self.html
    where( content_type: [
       'text/html;charset=utf-8',
       'text/html',
      ])
end

.imageObject



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

def self.image  
     ## change to/or add alias e.g. image/images - why? why not
    where( content_type: [
        'image/png',
        'image/jpeg',
        'image/gif',
        'image/webp',
        'image/svg+xml',
        'image/avif',
        ])
end

.import(id_or_ids, content: true) ⇒ Object



267
268
269
# File 'lib/ordlite/importer.rb', line 267

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

.jpgObject Also known as: jpeg



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

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

.jsObject Also known as: javascript



51
52
53
54
55
56
# File 'lib/ordlite/models/inscribe.rb', line 51

def self.js
    where( content_type: [
       'text/javascript',
       'application/javascript',
      ])
end

.largestObject Also known as: biggest



138
139
140
# File 'lib/ordlite/models/inscribe.rb', line 138

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

.mintsObject



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

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

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

.mints_by(slug:) ⇒ Object



114
115
116
117
118
119
120
121
122
123
# File 'lib/ordlite/models/inscribe.rb', line 114

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).text.where( where_clause ).order( 'num' )
end

.month_countsObject Also known as: counts_by_month



169
170
171
172
173
# File 'lib/ordlite/models/inscribe.rb', line 169

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

scope like helpers



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

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

.search(q) ⇒ Object

“full-text” search helper



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

def self.search( q )   ## "full-text" search helper
    ##  rename to text_search - why? why not?        
    ## auto-sort by num - why? why not?
    joins(:blob).text.where( "content LIKE '%#{q}%'" ).order('num')
end

.sub100kObject



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

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

.sub10kObject



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

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

.sub10mObject



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

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

.sub1kObject



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

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

.sub1mObject



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

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

.sub20kObject



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

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

.sub20mObject



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

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

.sub21mObject



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

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

.sub2kObject



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

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

.sub2mObject



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

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

.svgObject



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

def self.svg()  where( content_type: 'image/svg+xml' ); end

.textObject



62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/ordlite/models/inscribe.rb', line 62

def self.text
    ## change to/or add alias e.g. text/texts - why? why not
    ## include html or svg in text-only inscription - why? why not?
    ##  include markdown in text-only inscription - why? why not?
    ##   make content_type lower case with lower() - why? why not?
    where( content_type: [
              'text/plain',
              'text/plain;charset=utf-8',
              'text/plain;charset=us-ascii',
              'application/json',
         ])
end

.webpObject



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

def self.webp() where( content_type: 'image/webp' ); 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



324
325
326
327
328
329
330
331
332
333
# File 'lib/ordlite/models/inscribe.rb', line 324

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



320
321
322
323
# File 'lib/ordlite/models/inscribe.rb', line 320

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

#extnameObject

instance methods



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/ordlite/models/inscribe.rb', line 260

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