mirror of
https://github.com/aljazceru/njump.git
synced 2026-01-31 03:34:37 +01:00
move some things to enhanced_event.go, that makes more sense.
This commit is contained in:
@@ -13,9 +13,9 @@ func formatPartecipants(partecipants []nip52.Participant) string {
|
||||
for _, p := range partecipants {
|
||||
nreplace, _ := nip19.EncodePublicKey(p.PubKey)
|
||||
bytes := []byte(p.Role)
|
||||
bytes[0] = byte(unicode.ToUpper(rune(bytes[0])))
|
||||
role := string(bytes)
|
||||
nreplace = replaceNostrURLsWithHTMLTags(nostrNpubNprofileMatcher, "nostr:" + nreplace)
|
||||
bytes[0] = byte(unicode.ToUpper(rune(bytes[0])))
|
||||
role := string(bytes)
|
||||
nreplace = replaceNostrURLsWithHTMLTags(nostrNpubNprofileMatcher, "nostr:"+nreplace)
|
||||
if p.Role != "" {
|
||||
nreplace = nreplace + " as " + role
|
||||
}
|
||||
@@ -27,10 +27,9 @@ func formatPartecipants(partecipants []nip52.Participant) string {
|
||||
templ calendarEventTemplate(params CalendarPageParams) {
|
||||
<!DOCTYPE html>
|
||||
@eventPageTemplate(
|
||||
"Calendar Event: " + params.CalendarEvent.Title,
|
||||
"Calendar Event: "+params.CalendarEvent.Title,
|
||||
params.OpenGraphParams,
|
||||
params.HeadParams,
|
||||
params.Metadata,
|
||||
params.Clients,
|
||||
params.Details,
|
||||
params.Event,
|
||||
@@ -58,13 +57,13 @@ templ calendarEventTemplate(params CalendarPageParams) {
|
||||
</div>
|
||||
</div>
|
||||
if params.EndAtTime != "" {
|
||||
<div class="sm:w-auto sm:grow xl:grow-0 xl:w-1/3">
|
||||
<div class="font-semibold text-sm ml-2">End date</div>
|
||||
<div class="py-2 px-4 bg-strongpink text-white rounded-md">
|
||||
<div class="whitespace-nowrap">{ params.EndAtDate }</div>
|
||||
<div class="text-sm">{ params.EndAtTime } ({ params.TimeZone })</div>
|
||||
<div class="sm:w-auto sm:grow xl:grow-0 xl:w-1/3">
|
||||
<div class="font-semibold text-sm ml-2">End date</div>
|
||||
<div class="py-2 px-4 bg-strongpink text-white rounded-md">
|
||||
<div class="whitespace-nowrap">{ params.EndAtDate }</div>
|
||||
<div class="text-sm">{ params.EndAtTime } ({ params.TimeZone })</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
if params.CalendarEvent.Locations[0] != "" {
|
||||
@@ -76,7 +75,6 @@ templ calendarEventTemplate(params CalendarPageParams) {
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="mb-4 pt-6">
|
||||
if len(params.CalendarEvent.Participants) != 0 {
|
||||
<div class="pb-4">
|
||||
@@ -85,11 +83,10 @@ templ calendarEventTemplate(params CalendarPageParams) {
|
||||
</div>
|
||||
}
|
||||
if params.CalendarEvent.Image != "" {
|
||||
<img class="w-full mt-2" src={ params.CalendarEvent.Image } />
|
||||
<img class="w-full mt-2" src={ params.CalendarEvent.Image }/>
|
||||
}
|
||||
@templ.Raw(params.Content)
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
for _, v := range params.CalendarEvent.Hashtags {
|
||||
<span class="mr-2 whitespace-nowrap rounded bg-neutral-200 px-2 dark:bg-neutral-700 dark:text-white">
|
||||
@@ -98,4 +95,4 @@ templ calendarEventTemplate(params CalendarPageParams) {
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package main
|
||||
|
||||
import "github.com/nbd-wtf/nostr-sdk"
|
||||
|
||||
var compileTimeTs string
|
||||
|
||||
templ headCommonTemplate(params HeadParams) {
|
||||
@@ -37,7 +39,7 @@ on load get [navigator.userAgent.includes('Safari'), navigator.userAgent.include
|
||||
</script>
|
||||
}
|
||||
|
||||
templ authorHeaderTemplate(metadata Metadata) {
|
||||
templ authorHeaderTemplate(metadata sdk.ProfileMetadata) {
|
||||
<header
|
||||
itemprop="author"
|
||||
itemscope
|
||||
|
||||
33
data.go
33
data.go
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/nbd-wtf/go-nostr/nip52"
|
||||
"github.com/nbd-wtf/go-nostr/nip53"
|
||||
"github.com/nbd-wtf/go-nostr/nip94"
|
||||
sdk "github.com/nbd-wtf/nostr-sdk"
|
||||
)
|
||||
|
||||
type Data struct {
|
||||
@@ -26,9 +25,7 @@ type Data struct {
|
||||
createdAt string
|
||||
modifiedAt string
|
||||
parentLink template.HTML
|
||||
metadata Metadata
|
||||
authorRelaysPretty []string
|
||||
authorLong string
|
||||
renderableLastNotes []EnhancedEvent
|
||||
kindDescription string
|
||||
kindNIP string
|
||||
@@ -65,10 +62,7 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e
|
||||
}
|
||||
|
||||
data := &Data{
|
||||
event: EnhancedEvent{
|
||||
Event: event,
|
||||
relays: relays,
|
||||
},
|
||||
event: NewEnhancedEvent(ctx, event, relays),
|
||||
}
|
||||
|
||||
data.authorRelaysPretty = make([]string, 0, len(relays))
|
||||
@@ -85,9 +79,6 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e
|
||||
}
|
||||
data.authorRelaysPretty = unique(data.authorRelaysPretty)
|
||||
|
||||
npub, _ := nip19.EncodePublicKey(event.PubKey)
|
||||
npubShort := npub[:8] + "…" + npub[len(npub)-4:]
|
||||
data.authorLong = npub // hopefully will be replaced later
|
||||
data.nevent, _ = nip19.EncodeEvent(event.ID, relaysForNip19, event.PubKey)
|
||||
data.neventNaked, _ = nip19.EncodeEvent(event.ID, nil, event.PubKey)
|
||||
data.naddr = ""
|
||||
@@ -110,7 +101,7 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e
|
||||
lastNotes := authorLastNotes(ctx, event.PubKey, isProfileSitemap)
|
||||
data.renderableLastNotes = make([]EnhancedEvent, len(lastNotes))
|
||||
for i, levt := range lastNotes {
|
||||
data.renderableLastNotes[i] = EnhancedEvent{levt, []string{}}
|
||||
data.renderableLastNotes[i] = NewEnhancedEvent(ctx, levt, []string{})
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -146,25 +137,7 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e
|
||||
data.templateId = Other
|
||||
}
|
||||
|
||||
if event.Kind == 0 {
|
||||
data.nprofile, _ = nip19.EncodeProfile(event.PubKey, limitAt(relays, 2))
|
||||
spm, _ := sdk.ParseMetadata(event)
|
||||
data.metadata = Metadata{spm}
|
||||
} else {
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second*3)
|
||||
defer cancel()
|
||||
author, relays, _ := getEvent(ctx, npub, relaysForNip19)
|
||||
if author == nil {
|
||||
data.metadata = Metadata{sdk.ProfileMetadata{PubKey: event.PubKey}}
|
||||
} else {
|
||||
spm, _ := sdk.ParseMetadata(author)
|
||||
data.metadata = Metadata{spm}
|
||||
if data.metadata.Name != "" {
|
||||
data.authorLong = fmt.Sprintf("%s (%s)", data.metadata.Name, npubShort)
|
||||
}
|
||||
}
|
||||
data.nprofile, _ = nip19.EncodeProfile(event.PubKey, limitAt(relays, 2))
|
||||
}
|
||||
data.nprofile, _ = nip19.EncodeProfile(event.PubKey, limitAt(relays, 2))
|
||||
|
||||
data.kindDescription = kindNames[event.Kind]
|
||||
if data.kindDescription == "" {
|
||||
|
||||
246
enhanced_event.go
Normal file
246
enhanced_event.go
Normal file
@@ -0,0 +1,246 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html"
|
||||
"html/template"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
"github.com/nbd-wtf/go-nostr/nip10"
|
||||
"github.com/nbd-wtf/go-nostr/nip19"
|
||||
sdk "github.com/nbd-wtf/nostr-sdk"
|
||||
"github.com/texttheater/golang-levenshtein/levenshtein"
|
||||
)
|
||||
|
||||
type EnhancedEvent struct {
|
||||
*nostr.Event
|
||||
relays []string
|
||||
subject string
|
||||
summary string
|
||||
author sdk.ProfileMetadata
|
||||
}
|
||||
|
||||
func NewEnhancedEvent(
|
||||
ctx context.Context,
|
||||
event *nostr.Event,
|
||||
relays []string,
|
||||
) EnhancedEvent {
|
||||
ee := EnhancedEvent{
|
||||
Event: event,
|
||||
relays: relays,
|
||||
}
|
||||
|
||||
for _, tag := range event.Tags {
|
||||
if tag[0] == "subject" || tag[0] == "title" {
|
||||
ee.subject = tag[1]
|
||||
}
|
||||
if tag[0] == "summary" {
|
||||
ee.summary = tag[1]
|
||||
}
|
||||
}
|
||||
|
||||
if ctx != nil {
|
||||
if event.Kind == 0 {
|
||||
spm, _ := sdk.ParseMetadata(event)
|
||||
ee.author = spm
|
||||
} else {
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second*3)
|
||||
defer cancel()
|
||||
ee.author = sys.FetchProfileMetadata(ctx, event.PubKey)
|
||||
}
|
||||
}
|
||||
|
||||
return ee
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) authorLong() string {
|
||||
if ee.author.Name != "" {
|
||||
return fmt.Sprintf("%s (%s)", ee.author.Name, ee.author.NpubShort())
|
||||
}
|
||||
return ee.author.Npub()
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) getParentNevent() string {
|
||||
parentNevent := ""
|
||||
switch ee.Kind {
|
||||
case 1, 1063:
|
||||
replyTag := nip10.GetImmediateReply(ee.Tags)
|
||||
if replyTag != nil {
|
||||
var relays []string
|
||||
if (len(*replyTag) > 2) && ((*replyTag)[2] != "") {
|
||||
relays = []string{(*replyTag)[2]}
|
||||
}
|
||||
eventId := (*replyTag)[1]
|
||||
if (*replyTag)[0] == "a" { // Reply to a ndaddr event
|
||||
eventId = strings.Split(eventId, ":")[1]
|
||||
kind, _ := strconv.Atoi(strings.Split((*replyTag)[1], ":")[0])
|
||||
identifier := strings.Split((*replyTag)[1], ":")[2]
|
||||
var relays []string
|
||||
if (len(*replyTag) > 2) && ((*replyTag)[2] != "") {
|
||||
relays = []string{(*replyTag)[2]}
|
||||
}
|
||||
parentNevent, _ = nip19.EncodeEntity(
|
||||
eventId,
|
||||
kind,
|
||||
identifier,
|
||||
relays)
|
||||
} else {
|
||||
parentNevent, _ = nip19.EncodeEvent(eventId, relays, "")
|
||||
}
|
||||
}
|
||||
case 1311:
|
||||
if atag := ee.Tags.GetFirst([]string{"a", ""}); atag != nil {
|
||||
parts := strings.Split((*atag)[1], ":")
|
||||
kind, _ := strconv.Atoi(parts[0])
|
||||
var relays []string
|
||||
if (len(*atag) > 2) && ((*atag)[2] != "") {
|
||||
relays = []string{(*atag)[2]}
|
||||
}
|
||||
parentNevent, _ = nip19.EncodeEntity(parts[1], kind, parts[2], relays)
|
||||
}
|
||||
}
|
||||
|
||||
return parentNevent
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) isReply() bool {
|
||||
return nip10.GetImmediateReply(ee.Event.Tags) != nil
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) Preview() template.HTML {
|
||||
lines := strings.Split(html.EscapeString(ee.Event.Content), "\n")
|
||||
var processedLines []string
|
||||
for _, line := range lines {
|
||||
if strings.TrimSpace(line) == "" {
|
||||
continue
|
||||
}
|
||||
processedLine := shortenNostrURLs(line)
|
||||
processedLines = append(processedLines, processedLine)
|
||||
}
|
||||
|
||||
return template.HTML(strings.Join(processedLines, "<br/>"))
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) RssTitle() string {
|
||||
regex := regexp.MustCompile(`(?i)<br\s?/?>`)
|
||||
replacedString := regex.ReplaceAllString(string(ee.Preview()), " ")
|
||||
words := strings.Fields(replacedString)
|
||||
title := ""
|
||||
for i, word := range words {
|
||||
if len(title)+len(word)+1 <= 65 { // +1 for space
|
||||
if title != "" {
|
||||
title += " "
|
||||
}
|
||||
title += word
|
||||
} else {
|
||||
if i > 1 { // the first word len is > 65
|
||||
title = title + " ..."
|
||||
} else {
|
||||
title = ""
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
content := ee.RssContent()
|
||||
distance := levenshtein.DistanceForStrings([]rune(title), []rune(content), levenshtein.DefaultOptions)
|
||||
similarityThreshold := 5
|
||||
if distance <= similarityThreshold {
|
||||
return ""
|
||||
} else {
|
||||
return title
|
||||
}
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) RssContent() string {
|
||||
content := ee.Event.Content
|
||||
content = basicFormatting(html.EscapeString(content), true, false, false)
|
||||
content = renderQuotesAsHTML(context.Background(), content, false)
|
||||
if nevent := ee.getParentNevent(); nevent != "" {
|
||||
neventShort := nevent[:8] + "…" + nevent[len(nevent)-4:]
|
||||
content = "In reply to <a href='/" + nevent + "'>" + neventShort + "</a><br/>_________________________<br/><br/>" + content
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) Thumb() string {
|
||||
imgRegex := regexp.MustCompile(`(https?://[^\s]+\.(?:png|jpe?g|gif|bmp|svg)(?:/[^\s]*)?)`)
|
||||
matches := imgRegex.FindAllStringSubmatch(ee.Event.Content, -1)
|
||||
if len(matches) > 0 {
|
||||
// The first match group captures the image URL
|
||||
return matches[0][1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) Npub() string {
|
||||
npub, _ := nip19.EncodePublicKey(ee.Event.PubKey)
|
||||
return npub
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) NpubShort() string {
|
||||
npub := ee.Npub()
|
||||
return npub[:8] + "…" + npub[len(npub)-4:]
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) Nevent() string {
|
||||
nevent, _ := nip19.EncodeEvent(ee.Event.ID, ee.relays, ee.Event.PubKey)
|
||||
return nevent
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) CreatedAtStr() string {
|
||||
return time.Unix(int64(ee.Event.CreatedAt), 0).Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) ModifiedAtStr() string {
|
||||
return time.Unix(int64(ee.Event.CreatedAt), 0).Format("2006-01-02T15:04:05Z07:00")
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) ToJSONHTML() template.HTML {
|
||||
tagsHTML := "["
|
||||
for t, tag := range ee.Tags {
|
||||
tagsHTML += "\n ["
|
||||
for i, item := range tag {
|
||||
cls := `"text-zinc-500 dark:text-zinc-50"`
|
||||
if i == 0 {
|
||||
cls = `"text-amber-500 dark:text-amber-200"`
|
||||
}
|
||||
itemJSON, _ := json.Marshal(item)
|
||||
tagsHTML += "\n <span class=" + cls + ">" + html.EscapeString(string(itemJSON))
|
||||
if i < len(tag)-1 {
|
||||
tagsHTML += ","
|
||||
} else {
|
||||
tagsHTML += "\n "
|
||||
}
|
||||
}
|
||||
tagsHTML += "]"
|
||||
if t < len(ee.Tags)-1 {
|
||||
tagsHTML += ","
|
||||
} else {
|
||||
tagsHTML += "\n "
|
||||
}
|
||||
}
|
||||
tagsHTML += "]"
|
||||
|
||||
contentJSON, _ := json.Marshal(ee.Content)
|
||||
|
||||
keyCls := "text-purple-700 dark:text-purple-300"
|
||||
|
||||
return template.HTML(fmt.Sprintf(
|
||||
`{
|
||||
<span class="`+keyCls+`">"id":</span> <span class="text-zinc-500 dark:text-zinc-50">"%s"</span>,
|
||||
<span class="`+keyCls+`">"pubkey":</span> <span class="text-zinc-500 dark:text-zinc-50">"%s"</span>,
|
||||
<span class="`+keyCls+`">"created_at":</span> <span class="text-green-600">%d</span>,
|
||||
<span class="`+keyCls+`">"kind":</span> <span class="text-amber-500 dark:text-amber-200">%d</span>,
|
||||
<span class="`+keyCls+`">"tags":</span> %s,
|
||||
<span class="`+keyCls+`">"content":</span> <span class="text-zinc-500 dark:text-zinc-50">%s</span>,
|
||||
<span class="`+keyCls+`">"sig":</span> <span class="text-zinc-500 dark:text-zinc-50 content">"%s"</span>
|
||||
}`, ee.ID, ee.PubKey, ee.CreatedAt, ee.Kind, tagsHTML, html.EscapeString(string(contentJSON)), ee.Sig),
|
||||
)
|
||||
}
|
||||
@@ -4,7 +4,6 @@ templ eventPageTemplate(
|
||||
title string,
|
||||
og OpenGraphParams,
|
||||
head HeadParams,
|
||||
author Metadata,
|
||||
clients []ClientReference,
|
||||
details DetailsParams,
|
||||
event EnhancedEvent,
|
||||
@@ -25,7 +24,7 @@ templ eventPageTemplate(
|
||||
class="w-full max-w-screen-2xl justify-between gap-10 overflow-visible print:w-full sm:flex sm:w-11/12 sm:px-4 md:w-10/12 lg:w-9/12 lg:gap-48vw"
|
||||
>
|
||||
<div class="w-full break-words print:w-full sm:w-3/4">
|
||||
@authorHeaderTemplate(author)
|
||||
@authorHeaderTemplate(event.author)
|
||||
<div itemprop="dateCreated" class="w-full text-right text-sm text-stone-400">
|
||||
{ event.CreatedAtStr() }
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,6 @@ templ fileMetadataTemplate(params FileMetadataPageParams) {
|
||||
"File Metadata",
|
||||
params.OpenGraphParams,
|
||||
params.HeadParams,
|
||||
params.Metadata,
|
||||
params.Clients,
|
||||
params.Details,
|
||||
params.Event,
|
||||
|
||||
4
go.mod
4
go.mod
@@ -19,8 +19,8 @@ require (
|
||||
github.com/kelseyhightower/envconfig v1.4.0
|
||||
github.com/microcosm-cc/bluemonday v1.0.24
|
||||
github.com/nbd-wtf/emoji v0.0.3
|
||||
github.com/nbd-wtf/go-nostr v0.32.0
|
||||
github.com/nbd-wtf/nostr-sdk v0.2.1
|
||||
github.com/nbd-wtf/go-nostr v0.33.0
|
||||
github.com/nbd-wtf/nostr-sdk v0.2.3
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/pemistahl/lingua-go v1.4.0
|
||||
|
||||
8
go.sum
8
go.sum
@@ -182,10 +182,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/nbd-wtf/emoji v0.0.3 h1:YtkT7MVPXvqU1SQjvC/CShlWexnREzqNCxmhUnL00CA=
|
||||
github.com/nbd-wtf/emoji v0.0.3/go.mod h1:tS6D9iI34qwBmWc5g8X7tVDkWXulqbTJRsvsM6QsS88=
|
||||
github.com/nbd-wtf/go-nostr v0.32.0 h1:ShRerjhXvqZbiVUc11iPqxLuOImxqbJQ0zTz4t6Tjps=
|
||||
github.com/nbd-wtf/go-nostr v0.32.0/go.mod h1:NZQkxl96ggbO8rvDpVjcsojJqKTPwqhP4i82O7K5DJs=
|
||||
github.com/nbd-wtf/nostr-sdk v0.2.1 h1:Ae1186pm//Byy5gOIsB3Nhy6EQfTzOHeU9enRWVd204=
|
||||
github.com/nbd-wtf/nostr-sdk v0.2.1/go.mod h1:iYZYgu0lilem16G8fk08FipgMOzsQs2bO1j6uEnRhvA=
|
||||
github.com/nbd-wtf/go-nostr v0.33.0 h1:6hZx25JAgwEOY49gCjrVZYFno7Z8L7HIwF6IMDGPjaU=
|
||||
github.com/nbd-wtf/go-nostr v0.33.0/go.mod h1:NZQkxl96ggbO8rvDpVjcsojJqKTPwqhP4i82O7K5DJs=
|
||||
github.com/nbd-wtf/nostr-sdk v0.2.3 h1:wQrr92VwYhOl+r1Cg3hUvggQT4S2wcTRRFHMD3znbe4=
|
||||
github.com/nbd-wtf/nostr-sdk v0.2.3/go.mod h1:AZZW6QzMk3Tc14fXRPktHFEEAAywLZ/TZf+Wdkr2ksI=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
|
||||
@@ -3,10 +3,9 @@ package main
|
||||
templ liveEventTemplate(params LiveEventPageParams) {
|
||||
<!DOCTYPE html>
|
||||
@eventPageTemplate(
|
||||
params.LiveEvent.title(),
|
||||
params.LiveEvent.title(),
|
||||
params.OpenGraphParams,
|
||||
params.HeadParams,
|
||||
params.Metadata,
|
||||
params.Clients,
|
||||
params.Details,
|
||||
params.Event,
|
||||
|
||||
@@ -3,10 +3,9 @@ package main
|
||||
templ liveEventMessageTemplate(params LiveEventMessagePageParams) {
|
||||
<!DOCTYPE html>
|
||||
@eventPageTemplate(
|
||||
params.TitleizedContent,
|
||||
params.TitleizedContent,
|
||||
params.OpenGraphParams,
|
||||
params.HeadParams,
|
||||
params.Metadata,
|
||||
params.Clients,
|
||||
params.Details,
|
||||
params.Event,
|
||||
|
||||
@@ -6,7 +6,6 @@ templ noteTemplate(params NotePageParams) {
|
||||
params.TitleizedContent,
|
||||
params.OpenGraphParams,
|
||||
params.HeadParams,
|
||||
params.Metadata,
|
||||
params.Clients,
|
||||
params.Details,
|
||||
params.Event,
|
||||
@@ -15,7 +14,7 @@ templ noteTemplate(params NotePageParams) {
|
||||
<h1 class="text-2xl" itemprop="headline">{ params.Subject }</h1>
|
||||
} else {
|
||||
<h1 class="hidden">
|
||||
{ params.Metadata.ShortName() } on Nostr: { params.TitleizedContent }
|
||||
{ params.Event.author.ShortName() } on Nostr: { params.TitleizedContent }
|
||||
</h1>
|
||||
}
|
||||
if params.Cover != "" {
|
||||
|
||||
@@ -62,9 +62,9 @@ func renderOEmbed(w http.ResponseWriter, r *http.Request) {
|
||||
Version: "1.0",
|
||||
ProviderName: "njump",
|
||||
ProviderURL: "https://" + host,
|
||||
Title: data.metadata.Name + " wrote",
|
||||
AuthorName: data.authorLong,
|
||||
AuthorURL: fmt.Sprintf("https://%s/%s", host, data.metadata.Npub()),
|
||||
Title: data.event.author.Name + " wrote",
|
||||
AuthorName: data.event.authorLong(),
|
||||
AuthorURL: fmt.Sprintf("https://%s/%s", host, data.event.Npub()),
|
||||
}
|
||||
|
||||
switch {
|
||||
|
||||
20
pages.go
20
pages.go
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/a-h/templ"
|
||||
"github.com/nbd-wtf/go-nostr/nip11"
|
||||
sdk "github.com/nbd-wtf/nostr-sdk"
|
||||
)
|
||||
|
||||
type TemplateID int
|
||||
@@ -48,7 +49,7 @@ type DetailsParams struct {
|
||||
HideDetails bool
|
||||
CreatedAt string
|
||||
EventJSON template.HTML
|
||||
Metadata Metadata
|
||||
Metadata sdk.ProfileMetadata
|
||||
Nevent string
|
||||
Nprofile string
|
||||
SeenOn []string
|
||||
@@ -75,7 +76,7 @@ type TelegramInstantViewParams struct {
|
||||
Content template.HTML
|
||||
Description string
|
||||
Subject string
|
||||
Metadata Metadata
|
||||
Metadata sdk.ProfileMetadata
|
||||
AuthorLong string
|
||||
CreatedAt string
|
||||
ParentNevent string
|
||||
@@ -95,7 +96,7 @@ type AboutParams struct {
|
||||
type EmbeddedNoteParams struct {
|
||||
Content template.HTML
|
||||
CreatedAt string
|
||||
Metadata Metadata
|
||||
Metadata sdk.ProfileMetadata
|
||||
SeenOn []string
|
||||
Subject string
|
||||
Url string
|
||||
@@ -110,7 +111,7 @@ type ProfilePageParams struct {
|
||||
CreatedAt string
|
||||
Domain string
|
||||
LastNotes []EnhancedEvent
|
||||
Metadata Metadata
|
||||
Metadata sdk.ProfileMetadata
|
||||
NormalizedAuthorWebsiteURL string
|
||||
RenderedAuthorAboutText template.HTML
|
||||
Nevent string
|
||||
@@ -125,7 +126,7 @@ type EmbeddedProfileParams struct {
|
||||
Content string
|
||||
CreatedAt string
|
||||
Domain string
|
||||
Metadata Metadata
|
||||
Metadata sdk.ProfileMetadata
|
||||
NormalizedAuthorWebsiteURL string
|
||||
RenderedAuthorAboutText template.HTML
|
||||
Nevent string
|
||||
@@ -137,7 +138,7 @@ type EmbeddedProfileParams struct {
|
||||
type RelayPageParams struct {
|
||||
HeadParams
|
||||
|
||||
Info *nip11.RelayInformationDocument
|
||||
Info nip11.RelayInformationDocument
|
||||
Hostname string
|
||||
Proxy string
|
||||
LastNotes []EnhancedEvent
|
||||
@@ -171,10 +172,9 @@ func (e *ErrorPageParams) MessageHTML() template.HTML {
|
||||
}
|
||||
|
||||
type BaseEventPageParams struct {
|
||||
Event EnhancedEvent
|
||||
Metadata Metadata
|
||||
Style Style
|
||||
Alt string
|
||||
Event EnhancedEvent
|
||||
Style Style
|
||||
Alt string
|
||||
}
|
||||
|
||||
type NotePageParams struct {
|
||||
|
||||
@@ -46,16 +46,16 @@ func renderEmbedded(w http.ResponseWriter, r *http.Request, code string) {
|
||||
component = embeddedNoteTemplate(EmbeddedNoteParams{
|
||||
Content: template.HTML(data.content),
|
||||
CreatedAt: data.createdAt,
|
||||
Metadata: data.metadata,
|
||||
Metadata: data.event.author,
|
||||
Subject: subject,
|
||||
Url: code,
|
||||
})
|
||||
|
||||
case Profile:
|
||||
component = embeddedProfileTemplate(EmbeddedProfileParams{
|
||||
Metadata: data.metadata,
|
||||
NormalizedAuthorWebsiteURL: normalizeWebsiteURL(data.metadata.Website),
|
||||
RenderedAuthorAboutText: template.HTML(basicFormatting(html.EscapeString(data.metadata.About), false, false, true)),
|
||||
Metadata: data.event.author,
|
||||
NormalizedAuthorWebsiteURL: normalizeWebsiteURL(data.event.author.Website),
|
||||
RenderedAuthorAboutText: template.HTML(basicFormatting(html.EscapeString(data.event.author.About), false, false, true)),
|
||||
AuthorRelays: data.authorRelaysPretty,
|
||||
})
|
||||
default:
|
||||
|
||||
@@ -96,7 +96,7 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// if the result is a kind:0 render this as a profile
|
||||
if data.event.Kind == 0 {
|
||||
renderProfile(w, r, data.metadata.Npub())
|
||||
renderProfile(w, r, data.event.author.Npub())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -136,17 +136,6 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
host = r.Host
|
||||
}
|
||||
|
||||
var subject string
|
||||
var summary string
|
||||
for _, tag := range data.event.Tags {
|
||||
if tag[0] == "subject" || tag[0] == "title" {
|
||||
subject = tag[1]
|
||||
}
|
||||
if tag[0] == "summary" {
|
||||
summary = tag[1]
|
||||
}
|
||||
}
|
||||
|
||||
useTextImage := false
|
||||
|
||||
if data.event.Kind == 1 || data.event.Kind == 30023 {
|
||||
@@ -188,10 +177,10 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
} else {
|
||||
subscript = fmt.Sprintf("kind:%d event", data.event.Kind)
|
||||
}
|
||||
if subject != "" {
|
||||
subscript += " (" + subject + ")"
|
||||
if data.event.subject != "" {
|
||||
subscript += " (" + data.event.subject + ")"
|
||||
}
|
||||
subscript += " by " + data.metadata.ShortName()
|
||||
subscript += " by " + data.event.author.ShortName()
|
||||
if data.event.isReply() {
|
||||
subscript += " (reply)"
|
||||
}
|
||||
@@ -205,17 +194,17 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
description := ""
|
||||
if useTextImage {
|
||||
textImageURL = fmt.Sprintf("https://%s/njump/image/%s?%s", host, code, r.URL.RawQuery)
|
||||
if subject != "" {
|
||||
if data.event.subject != "" {
|
||||
if seenOnRelays != "" {
|
||||
description = fmt.Sprintf("%s -- %s", subject, seenOnRelays)
|
||||
description = fmt.Sprintf("%s -- %s", data.event.subject, seenOnRelays)
|
||||
} else {
|
||||
description = subject
|
||||
description = data.event.subject
|
||||
}
|
||||
} else {
|
||||
description = seenOnRelays
|
||||
}
|
||||
} else if summary != "" {
|
||||
description = summary
|
||||
} else if data.event.summary != "" {
|
||||
description = data.event.summary
|
||||
} else {
|
||||
// if content is valid JSON, parse that and print as TOML for easier readability
|
||||
var parsedJson any
|
||||
@@ -280,7 +269,7 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
if data.event.Kind == 30023 || data.event.Kind == 30024 {
|
||||
// Remove duplicate title inside the body
|
||||
data.content = strings.ReplaceAll(data.content, "# "+subject, "")
|
||||
data.content = strings.ReplaceAll(data.content, "# "+data.event.subject, "")
|
||||
data.content = mdToHTML(data.content, data.templateId == TelegramInstantView, false)
|
||||
} else {
|
||||
// first we run basicFormatting, which turns URLs into their appropriate HTML tags
|
||||
@@ -322,7 +311,7 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
EventJSON: data.event.ToJSONHTML(),
|
||||
Kind: data.event.Kind,
|
||||
SeenOn: data.event.relays,
|
||||
Metadata: data.metadata,
|
||||
Metadata: data.event.author,
|
||||
}
|
||||
|
||||
opengraph := OpenGraphParams{
|
||||
@@ -332,17 +321,16 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
VideoType: data.videoType,
|
||||
ProxiedImage: "https://" + host + "/njump/proxy?src=" + data.image,
|
||||
|
||||
Superscript: data.authorLong,
|
||||
Superscript: data.event.authorLong(),
|
||||
Subscript: subscript,
|
||||
Text: strings.TrimSpace(description),
|
||||
}
|
||||
|
||||
var component templ.Component
|
||||
baseEventPageParams := BaseEventPageParams{
|
||||
Event: data.event,
|
||||
Metadata: data.metadata,
|
||||
Style: style,
|
||||
Alt: data.alt,
|
||||
Event: data.event,
|
||||
Style: style,
|
||||
Alt: data.alt,
|
||||
}
|
||||
|
||||
switch data.templateId {
|
||||
@@ -351,12 +339,12 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
Video: data.video,
|
||||
VideoType: data.videoType,
|
||||
Image: data.image,
|
||||
Summary: template.HTML(summary),
|
||||
Summary: template.HTML(data.event.summary),
|
||||
Content: template.HTML(data.content),
|
||||
Description: description,
|
||||
Subject: subject,
|
||||
Metadata: data.metadata,
|
||||
AuthorLong: data.authorLong,
|
||||
Subject: data.event.subject,
|
||||
Metadata: data.event.author,
|
||||
AuthorLong: data.event.authorLong(),
|
||||
CreatedAt: data.createdAt,
|
||||
ParentNevent: data.event.getParentNevent(),
|
||||
})
|
||||
@@ -399,12 +387,10 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
NaddrNaked: data.naddrNaked,
|
||||
NeventNaked: data.neventNaked,
|
||||
},
|
||||
|
||||
Clients: generateClientList(data.event.Kind, enhancedCode),
|
||||
Details: detailsData,
|
||||
Content: template.HTML(content),
|
||||
Cover: data.cover,
|
||||
Subject: subject,
|
||||
TitleizedContent: titleizedContent,
|
||||
})
|
||||
case FileMetadata:
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/fogleman/gg"
|
||||
"github.com/go-text/typesetting/shaping"
|
||||
"github.com/golang/freetype/truetype"
|
||||
sdk "github.com/nbd-wtf/nostr-sdk"
|
||||
"github.com/nfnt/resize"
|
||||
xfont "golang.org/x/image/font"
|
||||
)
|
||||
@@ -70,7 +71,7 @@ func renderImage(w http.ResponseWriter, r *http.Request) {
|
||||
"",
|
||||
)
|
||||
|
||||
img, err := drawImage(paragraphs, getPreviewStyle(r), data.metadata, data.createdAt)
|
||||
img, err := drawImage(paragraphs, getPreviewStyle(r), data.event.author, data.createdAt)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("failed to draw paragraphs as image")
|
||||
http.Error(w, "error writing image!", 500)
|
||||
@@ -86,7 +87,12 @@ func renderImage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func drawImage(paragraphs []string, style Style, metadata Metadata, date string) (image image.Image, err error) {
|
||||
func drawImage(
|
||||
paragraphs []string,
|
||||
style Style,
|
||||
metadata sdk.ProfileMetadata,
|
||||
date string,
|
||||
) (image image.Image, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("panic while drawing image")
|
||||
|
||||
@@ -44,7 +44,7 @@ func renderProfile(w http.ResponseWriter, r *http.Request, code string) {
|
||||
err = RSSTemplate.Render(w, &RSSPage{
|
||||
Host: s.Domain,
|
||||
ModifiedAt: data.modifiedAt,
|
||||
Metadata: data.metadata,
|
||||
Metadata: data.event.author,
|
||||
LastNotes: data.renderableLastNotes,
|
||||
})
|
||||
} else {
|
||||
@@ -59,11 +59,11 @@ func renderProfile(w http.ResponseWriter, r *http.Request, code string) {
|
||||
KindNIP: data.kindNIP,
|
||||
EventJSON: data.event.ToJSONHTML(),
|
||||
Kind: data.event.Kind,
|
||||
Metadata: data.metadata,
|
||||
Metadata: data.event.author,
|
||||
},
|
||||
Metadata: data.metadata,
|
||||
NormalizedAuthorWebsiteURL: normalizeWebsiteURL(data.metadata.Website),
|
||||
RenderedAuthorAboutText: template.HTML(basicFormatting(html.EscapeString(data.metadata.About), false, false, false)),
|
||||
Metadata: data.event.author,
|
||||
NormalizedAuthorWebsiteURL: normalizeWebsiteURL(data.event.author.Website),
|
||||
RenderedAuthorAboutText: template.HTML(basicFormatting(html.EscapeString(data.event.author.About), false, false, false)),
|
||||
Nprofile: data.nprofile,
|
||||
AuthorRelays: data.authorRelaysPretty,
|
||||
LastNotes: data.renderableLastNotes,
|
||||
@@ -75,7 +75,7 @@ func renderProfile(w http.ResponseWriter, r *http.Request, code string) {
|
||||
if c == primalWeb {
|
||||
s = strings.Replace(
|
||||
strings.Replace(s, "/e/", "/p/", 1),
|
||||
data.nprofile, data.metadata.Npub(), 1)
|
||||
data.nprofile, data.event.author.Npub(), 1)
|
||||
}
|
||||
return s
|
||||
},
|
||||
|
||||
@@ -30,20 +30,9 @@ func renderRelayPage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// relay metadata
|
||||
info, err := nip11.Fetch(r.Context(), hostname)
|
||||
if err != nil {
|
||||
w.Header().Set("Cache-Control", "max-age=60")
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
errorTemplate(ErrorPageParams{
|
||||
Message: "The relay you are looking for does not exist or is offline; check the name in the url or try later",
|
||||
Errors: err.Error(),
|
||||
}).Render(r.Context(), w)
|
||||
return
|
||||
}
|
||||
if info == nil {
|
||||
info = &nip11.RelayInformationDocument{
|
||||
Name: hostname,
|
||||
}
|
||||
info, _ := nip11.Fetch(r.Context(), hostname)
|
||||
if info.Name == "" {
|
||||
info.Name = hostname
|
||||
}
|
||||
|
||||
// last notes
|
||||
@@ -54,7 +43,7 @@ func renderRelayPage(w http.ResponseWriter, r *http.Request) {
|
||||
lastEventAt = time.Unix(int64(lastNotes[0].CreatedAt), 0)
|
||||
}
|
||||
for i, levt := range lastNotes {
|
||||
renderableLastNotes[i] = EnhancedEvent{levt, []string{"wss://" + hostname}}
|
||||
renderableLastNotes[i] = NewEnhancedEvent(nil, levt, []string{"wss://" + hostname})
|
||||
}
|
||||
|
||||
if len(renderableLastNotes) != 0 {
|
||||
|
||||
@@ -1,224 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html"
|
||||
"html/template"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
"github.com/nbd-wtf/go-nostr/nip10"
|
||||
"github.com/nbd-wtf/go-nostr/nip19"
|
||||
"github.com/nbd-wtf/go-nostr/nip52"
|
||||
"github.com/nbd-wtf/go-nostr/nip53"
|
||||
"github.com/nbd-wtf/go-nostr/nip94"
|
||||
sdk "github.com/nbd-wtf/nostr-sdk"
|
||||
"github.com/texttheater/golang-levenshtein/levenshtein"
|
||||
)
|
||||
|
||||
type Metadata struct {
|
||||
sdk.ProfileMetadata
|
||||
}
|
||||
|
||||
func (m Metadata) Npub() string {
|
||||
npub, _ := nip19.EncodePublicKey(m.PubKey)
|
||||
return npub
|
||||
}
|
||||
|
||||
func (m Metadata) NpubShort() string {
|
||||
npub := m.Npub()
|
||||
return npub[:8] + "…" + npub[len(npub)-4:]
|
||||
}
|
||||
|
||||
type EnhancedEvent struct {
|
||||
*nostr.Event
|
||||
relays []string
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) getParentNevent() string {
|
||||
parentNevent := ""
|
||||
switch ee.Kind {
|
||||
case 1, 1063:
|
||||
replyTag := nip10.GetImmediateReply(ee.Tags)
|
||||
if replyTag != nil {
|
||||
var relays []string
|
||||
if (len(*replyTag) > 2) && ((*replyTag)[2] != "") {
|
||||
relays = []string{(*replyTag)[2]}
|
||||
}
|
||||
eventId := (*replyTag)[1]
|
||||
if (*replyTag)[0] == "a" { // Reply to a ndaddr event
|
||||
eventId = strings.Split(eventId, ":")[1]
|
||||
kind, _ := strconv.Atoi(strings.Split((*replyTag)[1], ":")[0])
|
||||
identifier := strings.Split((*replyTag)[1], ":")[2]
|
||||
var relays []string
|
||||
if (len(*replyTag) > 2) && ((*replyTag)[2] != "") {
|
||||
relays = []string{(*replyTag)[2]}
|
||||
}
|
||||
parentNevent, _ = nip19.EncodeEntity(
|
||||
eventId,
|
||||
kind,
|
||||
identifier,
|
||||
relays)
|
||||
} else {
|
||||
parentNevent, _ = nip19.EncodeEvent(eventId, relays, "")
|
||||
}
|
||||
}
|
||||
case 1311:
|
||||
if atag := ee.Tags.GetFirst([]string{"a", ""}); atag != nil {
|
||||
parts := strings.Split((*atag)[1], ":")
|
||||
kind, _ := strconv.Atoi(parts[0])
|
||||
var relays []string
|
||||
if (len(*atag) > 2) && ((*atag)[2] != "") {
|
||||
relays = []string{(*atag)[2]}
|
||||
}
|
||||
parentNevent, _ = nip19.EncodeEntity(parts[1], kind, parts[2], relays)
|
||||
}
|
||||
}
|
||||
|
||||
return parentNevent
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) isReply() bool {
|
||||
return nip10.GetImmediateReply(ee.Event.Tags) != nil
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) Preview() template.HTML {
|
||||
lines := strings.Split(html.EscapeString(ee.Event.Content), "\n")
|
||||
var processedLines []string
|
||||
for _, line := range lines {
|
||||
if strings.TrimSpace(line) == "" {
|
||||
continue
|
||||
}
|
||||
processedLine := shortenNostrURLs(line)
|
||||
processedLines = append(processedLines, processedLine)
|
||||
}
|
||||
|
||||
return template.HTML(strings.Join(processedLines, "<br/>"))
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) RssTitle() string {
|
||||
regex := regexp.MustCompile(`(?i)<br\s?/?>`)
|
||||
replacedString := regex.ReplaceAllString(string(ee.Preview()), " ")
|
||||
words := strings.Fields(replacedString)
|
||||
title := ""
|
||||
for i, word := range words {
|
||||
if len(title)+len(word)+1 <= 65 { // +1 for space
|
||||
if title != "" {
|
||||
title += " "
|
||||
}
|
||||
title += word
|
||||
} else {
|
||||
if i > 1 { // the first word len is > 65
|
||||
title = title + " ..."
|
||||
} else {
|
||||
title = ""
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
content := ee.RssContent()
|
||||
distance := levenshtein.DistanceForStrings([]rune(title), []rune(content), levenshtein.DefaultOptions)
|
||||
similarityThreshold := 5
|
||||
if distance <= similarityThreshold {
|
||||
return ""
|
||||
} else {
|
||||
return title
|
||||
}
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) RssContent() string {
|
||||
content := ee.Event.Content
|
||||
content = basicFormatting(html.EscapeString(content), true, false, false)
|
||||
content = renderQuotesAsHTML(context.Background(), content, false)
|
||||
if nevent := ee.getParentNevent(); nevent != "" {
|
||||
neventShort := nevent[:8] + "…" + nevent[len(nevent)-4:]
|
||||
content = "In reply to <a href='/" + nevent + "'>" + neventShort + "</a><br/>_________________________<br/><br/>" + content
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) Thumb() string {
|
||||
imgRegex := regexp.MustCompile(`(https?://[^\s]+\.(?:png|jpe?g|gif|bmp|svg)(?:/[^\s]*)?)`)
|
||||
matches := imgRegex.FindAllStringSubmatch(ee.Event.Content, -1)
|
||||
if len(matches) > 0 {
|
||||
// The first match group captures the image URL
|
||||
return matches[0][1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) Npub() string {
|
||||
npub, _ := nip19.EncodePublicKey(ee.Event.PubKey)
|
||||
return npub
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) NpubShort() string {
|
||||
npub := ee.Npub()
|
||||
return npub[:8] + "…" + npub[len(npub)-4:]
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) Nevent() string {
|
||||
nevent, _ := nip19.EncodeEvent(ee.Event.ID, ee.relays, ee.Event.PubKey)
|
||||
return nevent
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) CreatedAtStr() string {
|
||||
return time.Unix(int64(ee.Event.CreatedAt), 0).Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) ModifiedAtStr() string {
|
||||
return time.Unix(int64(ee.Event.CreatedAt), 0).Format("2006-01-02T15:04:05Z07:00")
|
||||
}
|
||||
|
||||
func (ee EnhancedEvent) ToJSONHTML() template.HTML {
|
||||
tagsHTML := "["
|
||||
for t, tag := range ee.Tags {
|
||||
tagsHTML += "\n ["
|
||||
for i, item := range tag {
|
||||
cls := `"text-zinc-500 dark:text-zinc-50"`
|
||||
if i == 0 {
|
||||
cls = `"text-amber-500 dark:text-amber-200"`
|
||||
}
|
||||
itemJSON, _ := json.Marshal(item)
|
||||
tagsHTML += "\n <span class=" + cls + ">" + html.EscapeString(string(itemJSON))
|
||||
if i < len(tag)-1 {
|
||||
tagsHTML += ","
|
||||
} else {
|
||||
tagsHTML += "\n "
|
||||
}
|
||||
}
|
||||
tagsHTML += "]"
|
||||
if t < len(ee.Tags)-1 {
|
||||
tagsHTML += ","
|
||||
} else {
|
||||
tagsHTML += "\n "
|
||||
}
|
||||
}
|
||||
tagsHTML += "]"
|
||||
|
||||
contentJSON, _ := json.Marshal(ee.Content)
|
||||
|
||||
keyCls := "text-purple-700 dark:text-purple-300"
|
||||
|
||||
return template.HTML(fmt.Sprintf(
|
||||
`{
|
||||
<span class="`+keyCls+`">"id":</span> <span class="text-zinc-500 dark:text-zinc-50">"%s"</span>,
|
||||
<span class="`+keyCls+`">"pubkey":</span> <span class="text-zinc-500 dark:text-zinc-50">"%s"</span>,
|
||||
<span class="`+keyCls+`">"created_at":</span> <span class="text-green-600">%d</span>,
|
||||
<span class="`+keyCls+`">"kind":</span> <span class="text-amber-500 dark:text-amber-200">%d</span>,
|
||||
<span class="`+keyCls+`">"tags":</span> %s,
|
||||
<span class="`+keyCls+`">"content":</span> <span class="text-zinc-500 dark:text-zinc-50">%s</span>,
|
||||
<span class="`+keyCls+`">"sig":</span> <span class="text-zinc-500 dark:text-zinc-50 content">"%s"</span>
|
||||
}`, ee.ID, ee.PubKey, ee.CreatedAt, ee.Kind, tagsHTML, html.EscapeString(string(contentJSON)), ee.Sig),
|
||||
)
|
||||
}
|
||||
|
||||
type Kind1063Metadata struct {
|
||||
nip94.FileMetadata
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
_ "embed"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr/nip11"
|
||||
sdk "github.com/nbd-wtf/nostr-sdk"
|
||||
"github.com/tylermmorton/tmpl"
|
||||
)
|
||||
|
||||
@@ -18,11 +19,11 @@ type SitemapPage struct {
|
||||
ModifiedAt string
|
||||
|
||||
// for the profile sitemap
|
||||
Metadata Metadata
|
||||
Metadata sdk.ProfileMetadata
|
||||
|
||||
// for the relay sitemap
|
||||
RelayHostname string
|
||||
Info *nip11.RelayInformationDocument
|
||||
Info nip11.RelayInformationDocument
|
||||
|
||||
// for the profile and relay sitemaps
|
||||
LastNotes []EnhancedEvent
|
||||
@@ -59,11 +60,11 @@ type RSSPage struct {
|
||||
Title string
|
||||
|
||||
// for the profile RSS
|
||||
Metadata Metadata
|
||||
Metadata sdk.ProfileMetadata
|
||||
|
||||
// for the relay RSS
|
||||
RelayHostname string
|
||||
Info *nip11.RelayInformationDocument
|
||||
Info nip11.RelayInformationDocument
|
||||
|
||||
// for the profile and relay RSSs
|
||||
LastNotes []EnhancedEvent
|
||||
|
||||
Reference in New Issue
Block a user