mirror of
https://github.com/aljazceru/njump.git
synced 2026-01-31 11:44:34 +01:00
telegram instant preview when a note is very big.
This commit is contained in:
3
cache.go
3
cache.go
@@ -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
37
main.go
@@ -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 {}
|
||||
|
||||
}
|
||||
|
||||
80
render.go
80
render.go
@@ -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
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
29
templates/telegram_instant_view.html
Normal file
29
templates/telegram_instant_view.html
Normal 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>
|
||||
Reference in New Issue
Block a user