mirror of
https://github.com/aljazceru/njump.git
synced 2025-12-18 23:04:21 +01:00
modularizing opengraph headers and fixing a bunch of small things on there.
This commit is contained in:
15
data.go
15
data.go
@@ -2,7 +2,6 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html"
|
||||
"html/template"
|
||||
@@ -75,7 +74,7 @@ type Data struct {
|
||||
createdAt string
|
||||
modifiedAt string
|
||||
parentLink template.HTML
|
||||
metadata sdk.ProfileMetadata
|
||||
metadata *sdk.ProfileMetadata
|
||||
authorRelays []string
|
||||
authorLong string
|
||||
authorShort string
|
||||
@@ -139,6 +138,9 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e
|
||||
}
|
||||
|
||||
data.npub, _ = nip19.EncodePublicKey(event.PubKey)
|
||||
data.npubShort = data.npub[:8] + "…" + data.npub[len(data.npub)-4:]
|
||||
data.authorLong = data.npub // hopefully will be replaced later
|
||||
data.authorShort = data.npubShort // 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 = ""
|
||||
@@ -256,13 +258,14 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e
|
||||
|
||||
if event.Kind == 0 {
|
||||
data.nprofile, _ = nip19.EncodeProfile(event.PubKey, limitAt(relays, 2))
|
||||
json.Unmarshal([]byte(event.Content), &data.metadata)
|
||||
data.metadata, _ = sdk.ParseMetadata(event)
|
||||
} else {
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second*3)
|
||||
defer cancel()
|
||||
author, relays, _ := getEvent(ctx, data.npub, relaysForNip19)
|
||||
if author != nil {
|
||||
if err := json.Unmarshal([]byte(author.Content), &data.metadata); err == nil {
|
||||
data.metadata, _ = sdk.ParseMetadata(author)
|
||||
if data.metadata != nil {
|
||||
data.authorLong = fmt.Sprintf("%s (%s)", data.metadata.Name, data.npub)
|
||||
data.authorShort = fmt.Sprintf("%s (%s)", data.metadata.Name, data.npubShort)
|
||||
}
|
||||
@@ -308,9 +311,5 @@ func grabData(ctx context.Context, code string, isProfileSitemap bool) (*Data, e
|
||||
}
|
||||
}
|
||||
|
||||
data.npubShort = data.npub[:8] + "…" + data.npub[len(data.npub)-4:]
|
||||
data.authorLong = data.npub
|
||||
data.authorShort = data.npubShort
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
33
pages.go
33
pages.go
@@ -29,17 +29,20 @@ var (
|
||||
|
||||
//tmpl:bind head_common.html
|
||||
type OpenGraphPartial struct {
|
||||
IsTwitter bool
|
||||
TitleizedContent string
|
||||
Title string
|
||||
TwitterTitle string
|
||||
Proxy string
|
||||
AuthorLong string
|
||||
TextImageURL string
|
||||
Video string
|
||||
VideoType string
|
||||
Image string
|
||||
Description string
|
||||
SingleTitle string
|
||||
// x (we will always render just the singletitle if we have that)
|
||||
Superscript string
|
||||
Subscript string
|
||||
|
||||
BigImage string
|
||||
// x (we will always render just the bigimage if we have that)
|
||||
Video string
|
||||
VideoType string
|
||||
Image string
|
||||
ProxiedImage string
|
||||
|
||||
// this is the main text we should always have
|
||||
Text string
|
||||
}
|
||||
|
||||
func (*OpenGraphPartial) TemplateText() string { return tmplOpenGraph }
|
||||
@@ -135,7 +138,7 @@ type TelegramInstantViewPage struct {
|
||||
Content template.HTML
|
||||
Description string
|
||||
Subject string
|
||||
Metadata sdk.ProfileMetadata
|
||||
Metadata *sdk.ProfileMetadata
|
||||
AuthorLong string
|
||||
CreatedAt string
|
||||
}
|
||||
@@ -217,7 +220,7 @@ type NotePage struct {
|
||||
|
||||
Content template.HTML
|
||||
CreatedAt string
|
||||
Metadata sdk.ProfileMetadata
|
||||
Metadata *sdk.ProfileMetadata
|
||||
Npub string
|
||||
NpubShort string
|
||||
ParentLink template.HTML
|
||||
@@ -246,7 +249,7 @@ type ProfilePage struct {
|
||||
CreatedAt string
|
||||
Domain string
|
||||
LastNotes []EnhancedEvent
|
||||
Metadata sdk.ProfileMetadata
|
||||
Metadata *sdk.ProfileMetadata
|
||||
NormalizedAuthorWebsiteURL string
|
||||
RenderedAuthorAboutText template.HTML
|
||||
Nevent string
|
||||
@@ -275,7 +278,7 @@ type FileMetadataPage struct {
|
||||
|
||||
Content template.HTML
|
||||
CreatedAt string
|
||||
Metadata sdk.ProfileMetadata
|
||||
Metadata *sdk.ProfileMetadata
|
||||
Npub string
|
||||
NpubShort string
|
||||
ParentLink template.HTML
|
||||
|
||||
@@ -96,32 +96,24 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
title := ""
|
||||
twitterTitle := title
|
||||
if data.event.Kind == 0 && data.metadata.Name != "" {
|
||||
title = data.metadata.Name
|
||||
} else {
|
||||
if data.event.Kind >= 30000 && data.event.Kind < 40000 {
|
||||
tValue := "~"
|
||||
for _, tag := range data.event.Tags {
|
||||
if tag[0] == "t" {
|
||||
tValue = tag[1]
|
||||
break
|
||||
}
|
||||
if data.event.Kind >= 30000 && data.event.Kind < 40000 {
|
||||
tValue := "~"
|
||||
for _, tag := range data.event.Tags {
|
||||
if tag[0] == "t" {
|
||||
tValue = tag[1]
|
||||
break
|
||||
}
|
||||
title = fmt.Sprintf("%s: %s", kindNames[data.event.Kind], tValue)
|
||||
} else if kindName, ok := kindNames[data.event.Kind]; ok {
|
||||
title = kindName
|
||||
} else {
|
||||
title = fmt.Sprintf("kind:%d event", data.event.Kind)
|
||||
}
|
||||
if subject != "" {
|
||||
title += " (" + subject + ")"
|
||||
}
|
||||
twitterTitle += " by " + data.authorShort
|
||||
date := data.event.CreatedAt.Time().UTC().Format("2006-01-02 15:04")
|
||||
title += " at " + date
|
||||
twitterTitle += " at " + date
|
||||
title = fmt.Sprintf("%s: %s", kindNames[data.event.Kind], tValue)
|
||||
} else if kindName, ok := kindNames[data.event.Kind]; ok {
|
||||
title = kindName
|
||||
} else {
|
||||
title = fmt.Sprintf("kind:%d event", data.event.Kind)
|
||||
}
|
||||
if subject != "" {
|
||||
title += " (" + subject + ")"
|
||||
}
|
||||
title += " by " + data.authorShort
|
||||
|
||||
seenOnRelays := ""
|
||||
if len(data.relays) > 0 {
|
||||
@@ -255,6 +247,18 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
FileMetadata: data.kind1063Metadata,
|
||||
}
|
||||
|
||||
opengraph := OpenGraphPartial{
|
||||
BigImage: textImageURL,
|
||||
Image: data.image,
|
||||
Video: data.video,
|
||||
VideoType: data.videoType,
|
||||
ProxiedImage: "https://" + host + "/njump/proxy?src=" + data.image,
|
||||
|
||||
Superscript: data.authorLong,
|
||||
Subscript: title,
|
||||
Text: description,
|
||||
}
|
||||
|
||||
switch data.templateId {
|
||||
case TelegramInstantView:
|
||||
err = TelegramInstantViewTemplate.Render(w, &TelegramInstantViewPage{
|
||||
@@ -270,20 +274,12 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
CreatedAt: data.createdAt,
|
||||
})
|
||||
case Note:
|
||||
if style == StyleTwitter {
|
||||
opengraph.SingleTitle = "by " + data.authorShort + " at " + humanDate(data.event.CreatedAt)
|
||||
}
|
||||
|
||||
err = NoteTemplate.Render(w, &NotePage{
|
||||
OpenGraphPartial: OpenGraphPartial{
|
||||
IsTwitter: style == StyleTwitter,
|
||||
Proxy: "https://" + host + "/njump/proxy?src=",
|
||||
Title: title,
|
||||
TwitterTitle: twitterTitle,
|
||||
TitleizedContent: titleizedContent,
|
||||
TextImageURL: textImageURL,
|
||||
Image: data.image,
|
||||
Video: data.video,
|
||||
VideoType: data.videoType,
|
||||
Description: description,
|
||||
AuthorLong: data.authorLong,
|
||||
},
|
||||
OpenGraphPartial: opengraph,
|
||||
HeadCommonPartial: HeadCommonPartial{
|
||||
IsProfile: false,
|
||||
Oembed: oembed,
|
||||
@@ -306,20 +302,10 @@ func renderEvent(w http.ResponseWriter, r *http.Request) {
|
||||
TitleizedContent: titleizedContent,
|
||||
})
|
||||
case FileMetadata:
|
||||
opengraph.Image = data.kind1063Metadata.DisplayImage()
|
||||
|
||||
err = FileMetadataTemplate.Render(w, &FileMetadataPage{
|
||||
OpenGraphPartial: OpenGraphPartial{
|
||||
IsTwitter: style == StyleTwitter,
|
||||
Proxy: "https://" + host + "/njump/proxy?src=",
|
||||
TitleizedContent: titleizedContent,
|
||||
TwitterTitle: twitterTitle,
|
||||
Title: title,
|
||||
TextImageURL: textImageURL,
|
||||
Video: data.video,
|
||||
VideoType: data.videoType,
|
||||
Image: data.kind1063Metadata.DisplayImage(),
|
||||
Description: description,
|
||||
AuthorLong: data.authorLong,
|
||||
},
|
||||
OpenGraphPartial: opengraph,
|
||||
HeadCommonPartial: HeadCommonPartial{
|
||||
IsProfile: false,
|
||||
TailwindDebugStuff: tailwindDebugStuff,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<html class="theme--default text-lg font-light print:text-base sm:text-xl">
|
||||
<meta charset="UTF-8" />
|
||||
<head>
|
||||
<title>File Metadata</title>
|
||||
{{template "opengraph" .OpenGraphPartial}}
|
||||
<!---->
|
||||
{{template "head_common" .HeadCommonPartial}}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
<html class="theme--default text-lg font-light print:text-base sm:text-xl">
|
||||
<meta charset="UTF-8" />
|
||||
<head>
|
||||
<title>{{.TitleizedContent}}</title>
|
||||
|
||||
{{template "opengraph" .OpenGraphPartial}}
|
||||
<!---->
|
||||
{{template "head_common" .HeadCommonPartial}}
|
||||
|
||||
@@ -1,29 +1,39 @@
|
||||
<title>{{.TitleizedContent}}</title>
|
||||
|
||||
<meta property="og:title" content="{{.Title}}" />
|
||||
{{ if .IsTwitter }}
|
||||
<meta name="twitter:title" content="{{.TwitterTitle}}" />
|
||||
{{ if not (eq "" .SingleTitle)}}
|
||||
<!-- we only display this on twitter as a single title -->
|
||||
<meta name="twitter:title" content="{{.SingleTitle}}" />
|
||||
{{ else }}
|
||||
<!-- these are not shown by twitter at all, so let's not even give them -->
|
||||
<meta property="og:site_name" content="{{.Superscript}}" />
|
||||
<meta property="og:title" content="{{.Subscript}}" />
|
||||
{{ end }}
|
||||
|
||||
<meta property="og:site_name" content="{{.AuthorLong}}" />
|
||||
{{ if not (eq "" .TextImageURL) }}
|
||||
<!-- this is used for when we want to take over the entire screen on twitter,
|
||||
mostly for the big "text-to-image" images -->
|
||||
{{ if not (eq "" .BigImage) }}
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:site" content="@nostrprotocol" />
|
||||
<meta property="og:image" content="{{.TextImageURL}}" />
|
||||
<meta name="twitter:image" content="{{.TextImageURL}}" />
|
||||
<meta property="og:image" content="{{.BigImage}}" />
|
||||
<meta name="twitter:image" content="{{.BigImage}}" />
|
||||
{{ else }}
|
||||
<!---->
|
||||
<!-- otherwise we tell twitter to display it as a normal text-based embed.
|
||||
these distinctions don't seem to make any difference in other platforms,
|
||||
maybe telegram -->
|
||||
<meta property="twitter:card" content="summary" />
|
||||
{{ if not (eq "" .Image) }}
|
||||
<meta property="og:image" content="{{.Image}}" />
|
||||
<meta name="twitter:image" content="{{.Proxy}}{{.Image}}" />
|
||||
{{ end }} {{ if not (eq "" .Video) }}
|
||||
<meta name="twitter:image" content="{{.ProxiedImage}}" />
|
||||
{{ end }}
|
||||
<!---->
|
||||
{{ if not (eq "" .Video) }}
|
||||
<meta property="og:video" content="{{.Video}}" />
|
||||
<meta property="og:video:secure_url" content="{{.Video}}" />
|
||||
<meta property="og:video:type" content="video/{{.VideoType}}" />
|
||||
{{ end }} {{ end }}
|
||||
<!---->
|
||||
{{ if not (eq "" .Description) }}
|
||||
<meta property="og:description" content="{{.Description}}" />
|
||||
<meta name="twitter:description" content="{{.Description}}" />
|
||||
{{ end }}
|
||||
<!-- end the BigImage /if above -->
|
||||
{{ end }}
|
||||
|
||||
<!-- now just display the short text if we have any (which we always should) -->
|
||||
{{ if not (eq "" .Text) }}
|
||||
<meta property="og:description" content="{{.Text}}" />
|
||||
<meta name="twitter:description" content="{{.Text}}" />
|
||||
{{ end }}
|
||||
|
||||
14
utils.go
14
utils.go
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
html "html"
|
||||
"html"
|
||||
"html/template"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -549,3 +549,15 @@ func limitAt[V any](list []V, n int) []V {
|
||||
}
|
||||
return list[0:n]
|
||||
}
|
||||
|
||||
func humanDate(createdAt nostr.Timestamp) string {
|
||||
ts := createdAt.Time()
|
||||
now := time.Now()
|
||||
if ts.Before(now.AddDate(0, -9, 0)) {
|
||||
return ts.UTC().Format("02 Jan 2006")
|
||||
} else if ts.Before(now.AddDate(0, 0, -6)) {
|
||||
return ts.UTC().Format("Jan _2")
|
||||
} else {
|
||||
return ts.UTC().Format("Mon, Jan _2 15:04 UTC")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user