telegram instant preview when a note is very big.

This commit is contained in:
fiatjaf
2023-09-13 20:49:24 -03:00
parent ac47270348
commit 7291dd4bed
6 changed files with 128 additions and 77 deletions

View File

@@ -54,7 +54,7 @@ func (c *Cache) Get(key string) ([]byte, bool) {
return nil, false
}
if err != nil {
log.Fatal().Err(err).Msg("")
log.Fatal().Err(err).Str("key", key).Msg("error getting key from cache")
}
return val, true
@@ -84,7 +84,6 @@ func (c *Cache) GetPaginatedkeys(prefix string, page int, size int) []string {
}
return nil
})
if err != nil {
log.Fatal().Err(err).Msg("")
}

37
main.go
View File

@@ -28,7 +28,7 @@ var templates embed.FS
var (
s Settings
tmpl *template.Template
templateMapping = make(map[string]string)
templateMapping map[string]string
log = zerolog.New(os.Stderr).Output(zerolog.ConsoleWriter{Out: os.Stdout}).With().Timestamp().Logger()
)
@@ -61,25 +61,25 @@ func main() {
// initialize templates
// use a mapping to expressly link the templates and share them between more kinds/types
templateMapping["homepage"] = "homepage.html"
templateMapping["profile"] = "profile.html"
templateMapping["profile_sitemap"] = "sitemap.xml"
templateMapping["note"] = "note.html"
templateMapping["address"] = "other.html"
templateMapping["relay"] = "relay.html"
templateMapping["relay_sitemap"] = "sitemap.xml"
templateMapping["archive"] = "archive.html"
templateMapping["archive_sitemap"] = "sitemap.xml"
templateMapping["robots"] = "robots.txt"
templateMapping = map[string]string{
"homepage": "homepage.html",
"profile": "profile.html",
"profile_sitemap": "sitemap.xml",
"note": "note.html",
"telegram_instant_view": "telegram_instant_view.html",
"address": "other.html",
"relay": "relay.html",
"relay_sitemap": "sitemap.xml",
"archive": "archive.html",
"archive_sitemap": "sitemap.xml",
"robots": "robots.txt",
}
funcMap := template.FuncMap{
"basicFormatting": basicFormatting,
"renderInlineMentions": renderInlineMentions,
"mdToHTML": mdToHTML,
"escapeString": html.EscapeString,
"sanitizeXSS": sanitizeXSS,
"trimProtocol": trimProtocol,
"titleize": titleize,
"basicFormatting": basicFormatting,
"escapeString": html.EscapeString,
"sanitizeXSS": sanitizeXSS,
"trimProtocol": trimProtocol,
}
tmpl = template.Must(
@@ -106,5 +106,4 @@ func main() {
}
select {}
}

View File

@@ -5,6 +5,7 @@ import (
_ "embed"
"encoding/json"
"fmt"
"html"
"net/http"
"regexp"
"strings"
@@ -224,6 +225,14 @@ func render(w http.ResponseWriter, r *http.Request) {
useTextImage := (event.Kind == 1 || event.Kind == 30023) &&
image == "" && video == "" && len(event.Content) > 120
if style == "telegram" {
if event.Kind == 30023 ||
(event.Kind == 1 && len(event.Content) > 650) {
typ = "telegram_instant_view"
useTextImage = false
}
}
if style == "slack" || style == "discord" {
useTextImage = false
}
@@ -279,6 +288,7 @@ func render(w http.ResponseWriter, r *http.Request) {
}
}
// content massaging
for index, value := range event.Tags {
placeholderTag := "#[" + fmt.Sprintf("%d", index) + "]"
nreplace := ""
@@ -291,43 +301,47 @@ func render(w http.ResponseWriter, r *http.Request) {
}
content = strings.ReplaceAll(content, placeholderTag, "nostr:"+nreplace)
}
eventJSON, _ := json.MarshalIndent(event, "", " ")
if event.Kind == 30023 || event.Kind == 30024 {
content = mdToHTML(content)
} else {
content = renderInlineMentions(basicFormatting(html.EscapeString(content)))
}
params := map[string]any{
"createdAt": createdAt,
"modifiedAt": modifiedAt,
"clients": generateClientList(code, event),
"type": typ,
"title": title,
"twitterTitle": twitterTitle,
"npub": npub,
"npubShort": npubShort,
"nevent": nevent,
"naddr": naddr,
"metadata": metadata,
"authorLong": authorLong,
"subject": subject,
"description": description,
"content": content,
"textImageURL": textImageURL,
"videoType": videoType,
"image": image,
"video": video,
"proxy": "https://" + hostname + "/njump/proxy?src=",
"eventJSON": string(eventJSON),
"kindID": event.Kind,
"kindDescription": kindDescription,
"kindNIP": kindNIP,
"lastNotes": renderableLastNotes,
"parentNevent": parentNevent,
"authorRelays": authorRelays,
"CanonicalHost": s.CanonicalHost,
"createdAt": createdAt,
"modifiedAt": modifiedAt,
"clients": generateClientList(code, event),
"type": typ,
"title": title,
"twitterTitle": twitterTitle,
"npub": npub,
"npubShort": npubShort,
"nevent": nevent,
"naddr": naddr,
"metadata": metadata,
"authorLong": authorLong,
"subject": subject,
"description": description,
"event": event,
"content": content,
"titleizedContent": titleize(content),
"textImageURL": textImageURL,
"videoType": videoType,
"image": image,
"video": video,
"proxy": "https://" + hostname + "/njump/proxy?src=",
"kindDescription": kindDescription,
"kindNIP": kindNIP,
"lastNotes": renderableLastNotes,
"parentNevent": parentNevent,
"authorRelays": authorRelays,
"CanonicalHost": s.CanonicalHost,
}
// if a mapping is not found fallback to raw
if templateMapping[typ] == "" {
templateMapping[typ] = "other.html"
currentTemplate, ok := templateMapping[typ]
if !ok {
currentTemplate = "other.html"
}
if strings.Contains(typ, "profile") && len(renderableLastNotes) != 0 {
@@ -338,7 +352,7 @@ func render(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "max-age=60")
}
if err := tmpl.ExecuteTemplate(w, templateMapping[typ], params); err != nil {
if err := tmpl.ExecuteTemplate(w, currentTemplate, params); err != nil {
log.Error().Err(err).Msg("error rendering")
return
}

View File

@@ -5,7 +5,7 @@
<div class="field {{if not ( or (eq .type "other") (eq .type "address"))}}advanced{{end}}">
<div class="label">Kind type</div>
{{.kindID}}
{{.event.Kind}}
{{ if not (eq .kindNIP "")}}
- <a href="https://github.com/nostr-protocol/nips/blob/master/{{.kindNIP | escapeString}}.md">{{.kindDescription | escapeString}}</a>
{{ end }}
@@ -13,10 +13,10 @@
<div class="field {{if not ( or (eq .type "other") (eq .type "address"))}}advanced{{end}}">
<div class="label">Nevent</div>
<div>{{.nevent | escapeString}}</div>
<div>{{.nevent}}</div>
</div>
<div class="field {{if not ( or (eq .type "other") (eq .type "address"))}}advanced{{end}} boxed">
<div class="label">Event JSON</div>
<div class="json">{{.eventJSON}}</div>
</div>
<div class="json">{{.event}}</div>
</div>

View File

@@ -2,12 +2,14 @@
<html class="theme--default">
<meta charset="UTF-8" />
<head>
<title>{{.content | escapeString | titleize}}</title>
<title>{{.nevent | escapeString}} by {{.metadata.Name | escapeString}} is this note nostr ”nevent"</title>
<title>{{.titleizedContent}}</title>
<title>
{{.nevent | escapeString}} by {{.metadata.Name | escapeString}} is this
note nostr ”nevent"
</title>
<meta property="og:title" content="{{.title | escapeString}}" />
<meta name="twitter:title" content="{{.twitterTitle | escapeString}}" />
<meta property="og:site_name" content="{{.authorLong | escapeString}}" />
<meta property="og:site_name" content="{{.authorLong | escapeString}}" />
{{ if .textImageURL }}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@nostrprotocol" />
@@ -19,20 +21,29 @@
{{ if .image }}
<meta property="og:image" content="{{.image | escapeString}}" />
<meta name="twitter:image" content="{{.proxy}}{{.image | escapeString}}" />
{{end}} {{ if .video }}
{{ end }} {{ if .video }}
<meta property="og:video" content="{{.video | escapeString}}" />
<meta property="og:video:secure_url" content="{{.video | escapeString}}" />
<meta property="og:video:type" content="video/{{.videoType | escapeString}}" />
{{end}}
{{end}}
<meta
property="og:video:type"
content="video/{{.videoType | escapeString}}"
/>
{{ end }} {{ end }}
<!---->
{{ if .description }}
<meta property="og:description" content="{{.description | escapeString}}" />
<meta name="twitter:description" content="{{.description | escapeString}}" />
{{end}}
<meta
name="twitter:description"
content="{{.description | escapeString}}"
/>
{{ end }}
<link rel="canonical" href="https://{{.CanonicalHost}}/{{.nevent | escapeString }}" />
<link
rel="canonical"
href="https://{{.CanonicalHost}}/{{.nevent | escapeString }}"
/>
{{template "head_common.html" }}
{{template "head_common.html"}}
</head>
<body class="note">
@@ -70,15 +81,14 @@
<article class="field content">
{{ if (not (eq .subject ""))}}
<h1>{{.subject | escapeString}}</h1>
<h1>{{.subject | escapeString}}</h1>
{{ else }}
<h1 class="h">{{.metadata.Name | escapeString}} wrote: {{.content | escapeString | titleize}}</h1>
{{ end }}
{{ if (or (eq .kindID 30023) (eq .kindID 30024))}}
{{.content | mdToHTML }}
{{ else }}
{{.content | renderInlineMentions | escapeString | basicFormatting}}
<h1 class="h">
{{.metadata.Name | escapeString}} wrote: {{.titleizedContent}}
</h1>
{{ end }}
<!-- main content -->
{{ .content }}
</article>
<div class="field separator"></div>

View File

@@ -0,0 +1,29 @@
<meta charset="UTF-8" />
<!-- check https://nikstar.me/post/instant-view/ for more information on how this was set up -->
<!-- required stuff so telegram treats us like a medium.com article -->
<meta property="al:android:app_name" content="Medium" />
<meta property="article:published_time" content="{{.createdAt}}" />
<!-- stuff that goes in the actual telegram message preview -->
<meta property="og:site_name" content="{{.authorLong | escapeString}}" />
{{ if .description }}
<meta property="og:description" content="{{.description | escapeString}}" />
{{ end }}
<!---->
{{ if .image }}
<meta property="og:image" content="{{.image | escapeString}}" />
{{ end }}
<!-- stuff that affects the content inside the preview window -->
<meta name="author" content="{{.metadata.Name}}" />
<meta name="telegram:channel" content="@nostr_protocol" />
<!-- basic content of the preview window -->
<article>
<h1>
{{ if (not (eq .subject ""))}} {{.subject | escapeString}} {{ else }}
{{.metadata.Name | escapeString}} wrote: {{ end }}
</h1>
{{.content}}
</article>