@@ -171,6 +171,8 @@ pub enum TagKind {
171
171
Title ,
172
172
/// Image (NIP23)
173
173
Image ,
174
+ /// Thumbnail
175
+ Thumb ,
174
176
/// Summary (NIP23)
175
177
Summary ,
176
178
/// PublishedAt (NIP23)
@@ -187,6 +189,8 @@ pub enum TagKind {
187
189
Amount ,
188
190
/// Lnurl (NIP57)
189
191
Lnurl ,
192
+ /// Name tag
193
+ Name ,
190
194
/// Custom tag kind
191
195
Custom ( String ) ,
192
196
}
@@ -210,6 +214,7 @@ impl fmt::Display for TagKind {
210
214
Self :: Challenge => write ! ( f, "challenge" ) ,
211
215
Self :: Title => write ! ( f, "title" ) ,
212
216
Self :: Image => write ! ( f, "image" ) ,
217
+ Self :: Thumb => write ! ( f, "thumb" ) ,
213
218
Self :: Summary => write ! ( f, "summary" ) ,
214
219
Self :: PublishedAt => write ! ( f, "published_at" ) ,
215
220
Self :: Description => write ! ( f, "description" ) ,
@@ -218,6 +223,7 @@ impl fmt::Display for TagKind {
218
223
Self :: Relays => write ! ( f, "relays" ) ,
219
224
Self :: Amount => write ! ( f, "amount" ) ,
220
225
Self :: Lnurl => write ! ( f, "lnurl" ) ,
226
+ Self :: Name => write ! ( f, "name" ) ,
221
227
Self :: Custom ( tag) => write ! ( f, "{tag}" ) ,
222
228
}
223
229
}
@@ -246,6 +252,7 @@ where
246
252
"challenge" => Self :: Challenge ,
247
253
"title" => Self :: Title ,
248
254
"image" => Self :: Image ,
255
+ "thumb" => Self :: Thumb ,
249
256
"summary" => Self :: Summary ,
250
257
"published_at" => Self :: PublishedAt ,
251
258
"description" => Self :: Description ,
@@ -254,6 +261,7 @@ where
254
261
"relays" => Self :: Relays ,
255
262
"amount" => Self :: Amount ,
256
263
"lnurl" => Self :: Lnurl ,
264
+ "name" => Self :: Name ,
257
265
tag => Self :: Custom ( tag. to_string ( ) ) ,
258
266
}
259
267
}
@@ -276,7 +284,7 @@ pub enum Tag {
276
284
kind : Kind ,
277
285
public_key : XOnlyPublicKey ,
278
286
identifier : String ,
279
- relay_url : UncheckedUrl ,
287
+ relay_url : Option < UncheckedUrl > ,
280
288
} ,
281
289
Relay ( UncheckedUrl ) ,
282
290
ContactList {
@@ -300,14 +308,16 @@ pub enum Tag {
300
308
Subject ( String ) ,
301
309
Challenge ( String ) ,
302
310
Title ( String ) ,
303
- Image ( String ) ,
311
+ Image ( String , Option < ( u64 , u64 ) > ) ,
312
+ Thumb ( String , Option < ( u64 , u64 ) > ) ,
304
313
Summary ( String ) ,
305
314
Description ( String ) ,
306
315
Bolt11 ( String ) ,
307
316
Preimage ( String ) ,
308
317
Relays ( Vec < UncheckedUrl > ) ,
309
318
Amount ( u64 ) ,
310
319
Lnurl ( String ) ,
320
+ Name ( String ) ,
311
321
PublishedAt ( Timestamp ) ,
312
322
}
313
323
@@ -349,13 +359,15 @@ impl Tag {
349
359
Tag :: Challenge ( ..) => TagKind :: Challenge ,
350
360
Tag :: Title ( ..) => TagKind :: Title ,
351
361
Tag :: Image ( ..) => TagKind :: Image ,
362
+ Tag :: Thumb ( ..) => TagKind :: Thumb ,
352
363
Tag :: Summary ( ..) => TagKind :: Summary ,
353
364
Tag :: PublishedAt ( ..) => TagKind :: PublishedAt ,
354
365
Tag :: Description ( ..) => TagKind :: Description ,
355
366
Tag :: Bolt11 ( ..) => TagKind :: Bolt11 ,
356
367
Tag :: Preimage ( ..) => TagKind :: Preimage ,
357
368
Tag :: Relays ( ..) => TagKind :: Relays ,
358
369
Tag :: Amount ( ..) => TagKind :: Amount ,
370
+ Tag :: Name ( ..) => TagKind :: Name ,
359
371
Tag :: Lnurl ( ..) => TagKind :: Lnurl ,
360
372
}
361
373
}
@@ -390,7 +402,21 @@ where
390
402
}
391
403
} else if tag_len == 2 {
392
404
let content: & str = & tag[ 1 ] ;
405
+
393
406
match tag_kind {
407
+ TagKind :: A => {
408
+ let kpi: Vec < & str > = tag[ 1 ] . split ( ':' ) . collect ( ) ;
409
+ if kpi. len ( ) == 3 {
410
+ Ok ( Self :: A {
411
+ kind : Kind :: from_str ( kpi[ 0 ] ) ?,
412
+ public_key : XOnlyPublicKey :: from_str ( kpi[ 1 ] ) ?,
413
+ identifier : kpi[ 2 ] . to_string ( ) ,
414
+ relay_url : None ,
415
+ } )
416
+ } else {
417
+ Err ( Error :: InvalidLength )
418
+ }
419
+ }
394
420
TagKind :: P => Ok ( Self :: PubKey ( XOnlyPublicKey :: from_str ( content) ?, None ) ) ,
395
421
TagKind :: E => Ok ( Self :: Event ( EventId :: from_hex ( content) ?, None , None ) ) ,
396
422
TagKind :: R => Ok ( Self :: Reference ( content. to_string ( ) ) ) ,
@@ -405,14 +431,16 @@ where
405
431
TagKind :: Subject => Ok ( Self :: Subject ( content. to_string ( ) ) ) ,
406
432
TagKind :: Challenge => Ok ( Self :: Challenge ( content. to_string ( ) ) ) ,
407
433
TagKind :: Title => Ok ( Self :: Title ( content. to_string ( ) ) ) ,
408
- TagKind :: Image => Ok ( Self :: Image ( content. to_string ( ) ) ) ,
434
+ TagKind :: Image => Ok ( Self :: Image ( content. to_string ( ) , None ) ) ,
435
+ TagKind :: Thumb => Ok ( Self :: Thumb ( content. to_string ( ) , None ) ) ,
409
436
TagKind :: Summary => Ok ( Self :: Summary ( content. to_string ( ) ) ) ,
410
437
TagKind :: PublishedAt => Ok ( Self :: PublishedAt ( Timestamp :: from_str ( content) ?) ) ,
411
438
TagKind :: Description => Ok ( Self :: Description ( content. to_string ( ) ) ) ,
412
439
TagKind :: Bolt11 => Ok ( Self :: Bolt11 ( content. to_string ( ) ) ) ,
413
440
TagKind :: Preimage => Ok ( Self :: Preimage ( content. to_string ( ) ) ) ,
414
441
TagKind :: Amount => Ok ( Self :: Amount ( content. parse ( ) ?) ) ,
415
442
TagKind :: Lnurl => Ok ( Self :: Lnurl ( content. to_string ( ) ) ) ,
443
+ TagKind :: Name => Ok ( Self :: Name ( content. to_string ( ) ) ) ,
416
444
_ => Ok ( Self :: Generic ( tag_kind, vec ! [ content. to_string( ) ] ) ) ,
417
445
}
418
446
} else if tag_len == 3 {
@@ -457,12 +485,32 @@ where
457
485
kind : Kind :: from_str ( kpi[ 0 ] ) ?,
458
486
public_key : XOnlyPublicKey :: from_str ( kpi[ 1 ] ) ?,
459
487
identifier : kpi[ 2 ] . to_string ( ) ,
460
- relay_url : UncheckedUrl :: from ( tag[ 2 ] . clone ( ) ) ,
488
+ relay_url : Some ( UncheckedUrl :: from ( tag[ 2 ] . clone ( ) ) ) ,
461
489
} )
462
490
} else {
463
491
Err ( Error :: InvalidLength )
464
492
}
465
493
}
494
+ TagKind :: Image => {
495
+ let image = tag[ 1 ] . clone ( ) ;
496
+ let dimensions: Vec < & str > = tag[ 2 ] . split ( 'x' ) . collect ( ) ;
497
+ if dimensions. len ( ) == 2 {
498
+ let ( width, height) = ( dimensions[ 0 ] , dimensions[ 1 ] ) ;
499
+ Ok ( Self :: Image ( image, Some ( ( width. parse ( ) ?, height. parse ( ) ?) ) ) )
500
+ } else {
501
+ Err ( Error :: InvalidLength )
502
+ }
503
+ }
504
+ TagKind :: Thumb => {
505
+ let thumb = tag[ 1 ] . clone ( ) ;
506
+ let dimensions: Vec < & str > = tag[ 2 ] . split ( 'x' ) . collect ( ) ;
507
+ if dimensions. len ( ) == 2 {
508
+ let ( width, height) = ( dimensions[ 0 ] , dimensions[ 1 ] ) ;
509
+ Ok ( Self :: Thumb ( thumb, Some ( ( width. parse ( ) ?, height. parse ( ) ?) ) ) )
510
+ } else {
511
+ Err ( Error :: InvalidLength )
512
+ }
513
+ }
466
514
_ => Ok ( Self :: Generic ( tag_kind, tag[ 1 ..] . to_vec ( ) ) ) ,
467
515
}
468
516
} else if tag_len == 4 {
@@ -536,11 +584,16 @@ impl From<Tag> for Vec<String> {
536
584
public_key,
537
585
identifier,
538
586
relay_url,
539
- } => vec ! [
540
- TagKind :: A . to_string( ) ,
541
- format!( "{}:{public_key}:{identifier}" , kind. as_u64( ) ) ,
542
- relay_url. to_string( ) ,
543
- ] ,
587
+ } => {
588
+ let mut vec = vec ! [
589
+ TagKind :: A . to_string( ) ,
590
+ format!( "{}:{public_key}:{identifier}" , kind. as_u64( ) ) ,
591
+ ] ;
592
+ if let Some ( relay) = relay_url {
593
+ vec. push ( relay. to_string ( ) ) ;
594
+ }
595
+ vec
596
+ }
544
597
Tag :: Relay ( url) => vec ! [ TagKind :: Relay . to_string( ) , url. to_string( ) ] ,
545
598
Tag :: ContactList {
546
599
pk,
@@ -580,7 +633,22 @@ impl From<Tag> for Vec<String> {
580
633
Tag :: Subject ( sub) => vec ! [ TagKind :: Subject . to_string( ) , sub] ,
581
634
Tag :: Challenge ( challenge) => vec ! [ TagKind :: Challenge . to_string( ) , challenge] ,
582
635
Tag :: Title ( title) => vec ! [ TagKind :: Title . to_string( ) , title] ,
583
- Tag :: Image ( image) => vec ! [ TagKind :: Image . to_string( ) , image] ,
636
+ Tag :: Image ( image, dimensions) => match dimensions {
637
+ None => vec ! [ TagKind :: Image . to_string( ) , image] ,
638
+ Some ( ( width, height) ) => vec ! [
639
+ TagKind :: Image . to_string( ) ,
640
+ image,
641
+ format!( "{}x{}" , height, width) ,
642
+ ] ,
643
+ } ,
644
+ Tag :: Thumb ( thumb, dimensions) => match dimensions {
645
+ None => vec ! [ TagKind :: Thumb . to_string( ) , thumb] ,
646
+ Some ( ( width, height) ) => vec ! [
647
+ TagKind :: Thumb . to_string( ) ,
648
+ thumb,
649
+ format!( "{}x{}" , height, width) ,
650
+ ] ,
651
+ } ,
584
652
Tag :: Summary ( summary) => vec ! [ TagKind :: Summary . to_string( ) , summary] ,
585
653
Tag :: PublishedAt ( timestamp) => {
586
654
vec ! [ TagKind :: PublishedAt . to_string( ) , timestamp. to_string( ) ]
@@ -601,6 +669,9 @@ impl From<Tag> for Vec<String> {
601
669
Tag :: Amount ( amount) => {
602
670
vec ! [ TagKind :: Amount . to_string( ) , amount. to_string( ) ]
603
671
}
672
+ Tag :: Name ( name) => {
673
+ vec ! [ TagKind :: Name . to_string( ) , name]
674
+ }
604
675
Tag :: Lnurl ( lnurl) => {
605
676
vec ! [ TagKind :: Lnurl . to_string( ) , lnurl]
606
677
}
@@ -846,7 +917,7 @@ mod tests {
846
917
"a695f6b60119d9521934a691347d9f78e8770b56da16bb255ee286ddf9fda919"
847
918
) ?,
848
919
identifier: String :: from( "ipsum" ) ,
849
- relay_url: UncheckedUrl :: from ( "wss://relay.nostr.org" )
920
+ relay_url: Some ( UncheckedUrl :: from_str ( "wss://relay.nostr.org" ) ? )
850
921
}
851
922
. as_vec( )
852
923
) ;
@@ -1067,7 +1138,7 @@ mod tests {
1067
1138
"a695f6b60119d9521934a691347d9f78e8770b56da16bb255ee286ddf9fda919"
1068
1139
) ?,
1069
1140
identifier: String :: from( "ipsum" ) ,
1070
- relay_url: UncheckedUrl :: from ( "wss://relay.nostr.org" )
1141
+ relay_url: Some ( UncheckedUrl :: from_str ( "wss://relay.nostr.org" ) ? )
1071
1142
}
1072
1143
) ;
1073
1144
0 commit comments