diff --git a/data.go b/data.go index 3482909..fa47aba 100644 --- a/data.go +++ b/data.go @@ -85,6 +85,7 @@ type Data struct { videoType string image string content string + kind1063Metadata map[string]string } func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, error) { @@ -118,6 +119,7 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e authorRelays := []string{} var content string var templateId TemplateID + var kind1063Metadata map[string]string eventRelays := []string{} for _, relay := range relays { @@ -172,6 +174,41 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e original_nevent, _ := nip19.EncodeEvent((*reposted)[1], []string{}, "") content = "Repost of nostr:" + original_nevent } + case 1063: + templateId = FileMetadata + kind1063Metadata = make(map[string]string) + + keysToExtract := []string{ + "url", + "m", + "aes-256-gcm", + "x", + "size", + "dim", + "magnet", + "i", + "blurhash", + "thumb", + "image", + "summary", + "alt", + } + + for _, tag := range event.Tags { + if len(tag) == 2 { + key := tag[0] + value := tag[1] + + // Check if the key is in the list of keys to extract + for _, k := range keysToExtract { + if key == k { + kind1063Metadata[key] = value + break + } + } + } + } + default: if event.Kind >= 30000 && event.Kind < 40000 { templateId = Other @@ -197,25 +234,34 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e } kindNIP := kindNIPs[event.Kind] - urls := urlMatcher.FindAllString(event.Content, -1) var image string var video string var videoType string - for _, url := range urls { - switch { - case imageExtensionMatcher.MatchString(url): - if image == "" { - image = url - } - case videoExtensionMatcher.MatchString(url): - if video == "" { - video = url - if strings.HasSuffix(video, "mp4") { - videoType = "mp4" - } else if strings.HasSuffix(video, "mov") { - videoType = "mov" - } else { - videoType = "webm" + if event.Kind == 1063 { + if strings.HasPrefix(kind1063Metadata["m"], "image") { + image = kind1063Metadata["url"] + } else if strings.HasPrefix(kind1063Metadata["m"], "video") { + video = kind1063Metadata["url"] + videoType = strings.Split(kind1063Metadata["m"], "/")[1] + } + } else { + urls := urlMatcher.FindAllString(event.Content, -1) + for _, url := range urls { + switch { + case imageExtensionMatcher.MatchString(url): + if image == "" { + image = url + } + case videoExtensionMatcher.MatchString(url): + if video == "" { + video = url + if strings.HasSuffix(video, "mp4") { + videoType = "mp4" + } else if strings.HasSuffix(video, "mov") { + videoType = "mov" + } else { + videoType = "webm" + } } } } @@ -258,5 +304,6 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e videoType: videoType, image: image, content: content, + kind1063Metadata: kind1063Metadata, }, nil } diff --git a/pages.go b/pages.go index dca56a5..8fb489c 100644 --- a/pages.go +++ b/pages.go @@ -17,6 +17,7 @@ const ( Note TemplateID = iota LongForm TelegramInstantView + FileMetadata Other ) @@ -65,6 +66,10 @@ type DetailsPartial struct { Kind int KindNIP string KindDescription string + Magnet string + Dim string + Size string + Summary string } func (*DetailsPartial) TemplateText() string { return tmplDetails } @@ -241,6 +246,59 @@ type ProfilePage struct { func (*ProfilePage) TemplateText() string { return tmplProfile } +var ( + //go:embed templates/file_metadata.html + tmplFileMetadata string + FileMetadataTemplate = tmpl.MustCompile(&FileMetadataPage{}) +) + +type FileMetadataPage struct { + HeadCommonPartial `tmpl:"head_common"` + TopPartial `tmpl:"top"` + DetailsPartial `tmpl:"details"` + ClientsPartial `tmpl:"clients"` + FooterPartial `tmpl:"footer"` + + AuthorLong string + Content template.HTML + CreatedAt string + Description string + Metadata nostr.ProfileMetadata + Npub string + NpubShort string + Oembed string + ParentLink template.HTML + Proxy string + SeenOn []string + Style string + Subject string + TextImageURL string + Title string + TitleizedContent string + TwitterTitle string + Video string + VideoType string + + // Specific Metadata + Url string + M string + Aes256Gcm string + X string + Size string + Dim string + Magnet string + I string + Blurhash string + Thumb string + Image string + Summary string + Alt string + + MType string // The first part of the mime type M +} + +func (*FileMetadataPage) TemplateText() string { return tmplFileMetadata } + var ( //go:embed templates/relay.html tmplRelay string diff --git a/render_event.go b/render_event.go index 981d68d..7662336 100644 --- a/render_event.go +++ b/render_event.go @@ -231,6 +231,10 @@ func renderEvent(w http.ResponseWriter, r *http.Request) { SeenOn: data.relays, Npub: data.npub, Nprofile: data.nprofile, + Magnet: data.kind1063Metadata["magnet"], + Dim: data.kind1063Metadata["dim"], + Size: data.kind1063Metadata["size"], + Summary: data.kind1063Metadata["summary"], } switch data.templateId { @@ -280,6 +284,48 @@ func renderEvent(w http.ResponseWriter, r *http.Request) { Video: data.video, VideoType: data.videoType, }) + case FileMetadata: + thisImage := data.kind1063Metadata["image"] + if thisImage == "" && data.image != "" { + thisImage = data.image + } + err = FileMetadataTemplate.Render(w, &FileMetadataPage{ + HeadCommonPartial: HeadCommonPartial{ + IsProfile: false, + TailwindDebugStuff: tailwindDebugStuff, + NaddrNaked: data.naddrNaked, + NeventNaked: data.neventNaked, + }, + DetailsPartial: detailsData, + ClientsPartial: ClientsPartial{ + Clients: generateClientList(code, data.event), + }, + + AuthorLong: data.authorLong, + CreatedAt: data.createdAt, + Metadata: data.metadata, + Description: description, + Npub: data.npub, + NpubShort: data.npubShort, + Style: style, + Subject: subject, + TextImageURL: textImageURL, + Title: title, + TitleizedContent: titleizedContent, + TwitterTitle: twitterTitle, + Video: data.video, + VideoType: data.videoType, + Url: data.kind1063Metadata["url"], + M: data.kind1063Metadata["m"], + Aes256Gcm: data.kind1063Metadata["aes-256-gcm"], + X: data.kind1063Metadata["x"], + I: data.kind1063Metadata["i"], + Blurhash: data.kind1063Metadata["blurhash"], + Thumb: data.kind1063Metadata["thumb"], + Image: thisImage, + Alt: data.kind1063Metadata["alt"], + MType: strings.Split(data.kind1063Metadata["m"], "/")[0], + }) case Other: err = OtherTemplate.Render(w, &OtherPage{ HeadCommonPartial: HeadCommonPartial{ diff --git a/templates/details.html b/templates/details.html index 4803b74..53a437d 100644 --- a/templates/details.html +++ b/templates/details.html @@ -10,6 +10,34 @@ {{ end }} +{{ if not (eq "" .Summary) }} +
+
Summary
+ {{.Summary}} +
+{{ end }} + +{{ if not (eq "" .Dim) }} +
+
Dimension
+ {{.Dim}} +
+{{ end }} + +{{ if not (eq "" .Size) }} +
+
Size
+ {{.Size}} bytes +
+{{ end }} + +{{ if not (eq "" .Magnet) }} +
+
Magnet URL
+ {{.Magnet}} +
+{{ end }} + {{ if not (eq 0 (len .SeenOn)) }} diff --git a/templates/file_metadata.html b/templates/file_metadata.html new file mode 100644 index 0000000..51945c0 --- /dev/null +++ b/templates/file_metadata.html @@ -0,0 +1,137 @@ + + + + + {{.TitleizedContent}} + + + {{ if eq .Style "twitter" }} + + {{ end }} + + + {{ if not (eq "" .TextImageURL) }} + + + + + {{ else }} + + + {{ if not (eq "" .Image) }} + + + {{ end }} {{ if not (eq "" .Video) }} + + + + {{ end }} {{ end }} + + {{ if not (eq "" .Description) }} + + + {{ end }} + + + {{ if not (eq "" .Oembed) }} + + + {{ end }} + + + {{template "head_common" .HeadCommonPartial}} + + + + {{template "top" .}} + +
+
+
+
+ +
+ +
+
+
+ {{.Metadata.Name}} + + {{if not (eq .Metadata.Name .Metadata.DisplayName)}} + {{.Metadata.DisplayName}} + {{end}} +
+
+ {{.NpubShort}} +
+
+
+
+
+ {{.CreatedAt}} +
+ +
+ {{ if not (eq "" .ParentLink) }} in reply to + {{ .ParentLink }} {{ end }} +
+ +
+ +
+ {{ if (not (eq "" .Subject))}} +

{{.Subject}}

+ {{ else }} +

+ {{.Metadata.Name}} on Nostr: {{.TitleizedContent}} +

+ {{ end }} + + + {{ if (not (eq "" .Image))}} + {{ .Alt }} + {{ else if (eq "image" .MType)}} + {{ .Alt }} + {{ else if (eq "video" .MType)}} + + {{ end }} + + Download file + +
+ + {{template "details" .DetailsPartial}} + +
+
+ + {{template "clients" .ClientsPartial}} +
+
+ + {{template "footer" .}} + + diff --git a/utils.go b/utils.go index a8cd957..34b5714 100644 --- a/utils.go +++ b/utils.go @@ -156,6 +156,12 @@ func generateClientList(code string, event *nostr.Event) []ClientReference { {ID: "highlighter", Name: "Highlighter", URL: template.URL("https://highlighter.com/a/" + code)}, {ID: "blogstack", Name: "Blogstack", URL: template.URL("https://blogstack.io/" + code)}, } + } else if event.Kind == 1063 { + return []ClientReference{ + {ID: "native", Name: "Your native client", URL: template.URL("nostr:" + code)}, + {ID: "snort", Name: "Snort", URL: template.URL("https://snort.social/p/" + code)}, + {ID: "coracle", Name: "Coracle", URL: template.URL("https://coracle.social/" + code)}, + } } return nil }