mirror of https://github.com/jlelse/GoBlog
Improve ActivityPub replies
This commit is contained in:
parent
d5e3d9e216
commit
47a42e1c55
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-fed/httpsig"
|
"github.com/go-fed/httpsig"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/samber/lo"
|
||||||
"go.goblog.app/app/pkgs/bufferpool"
|
"go.goblog.app/app/pkgs/bufferpool"
|
||||||
"go.goblog.app/app/pkgs/contenttype"
|
"go.goblog.app/app/pkgs/contenttype"
|
||||||
)
|
)
|
||||||
|
@ -34,12 +35,16 @@ func (a *goBlog) initActivityPub() error {
|
||||||
}
|
}
|
||||||
// Add hooks
|
// Add hooks
|
||||||
a.pPostHooks = append(a.pPostHooks, func(p *post) {
|
a.pPostHooks = append(a.pPostHooks, func(p *post) {
|
||||||
if p.isPublishedSectionPost() {
|
if p.isPublishedSectionPost() && (p.Visibility == visibilityPublic || p.Visibility == visibilityUnlisted) {
|
||||||
|
a.apCheckMentions(p)
|
||||||
|
a.apCheckActivityPubReply(p)
|
||||||
a.apPost(p)
|
a.apPost(p)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
a.pUpdateHooks = append(a.pUpdateHooks, func(p *post) {
|
a.pUpdateHooks = append(a.pUpdateHooks, func(p *post) {
|
||||||
if p.isPublishedSectionPost() {
|
if p.isPublishedSectionPost() && (p.Visibility == visibilityPublic || p.Visibility == visibilityUnlisted) {
|
||||||
|
a.apCheckMentions(p)
|
||||||
|
a.apCheckActivityPubReply(p)
|
||||||
a.apUpdate(p)
|
a.apUpdate(p)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -47,7 +52,7 @@ func (a *goBlog) initActivityPub() error {
|
||||||
a.apDelete(p)
|
a.apDelete(p)
|
||||||
})
|
})
|
||||||
a.pUndeleteHooks = append(a.pUndeleteHooks, func(p *post) {
|
a.pUndeleteHooks = append(a.pUndeleteHooks, func(p *post) {
|
||||||
if p.isPublishedSectionPost() {
|
if p.isPublishedSectionPost() && (p.Visibility == visibilityPublic || p.Visibility == visibilityUnlisted) {
|
||||||
a.apUndelete(p)
|
a.apUndelete(p)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -149,6 +154,57 @@ func (a *goBlog) apHandleWebfinger(w http.ResponseWriter, r *http.Request) {
|
||||||
_ = a.min.Get().Minify(contenttype.JSON, w, buf)
|
_ = a.min.Get().Minify(contenttype.JSON, w, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const activityPubMentionsParameter = "activitypubmentions"
|
||||||
|
|
||||||
|
func (a *goBlog) apCheckMentions(p *post) {
|
||||||
|
contentBuf := bufferpool.Get()
|
||||||
|
a.postHtmlToWriter(contentBuf, &postHtmlOptions{p: p})
|
||||||
|
links, err := allLinksFromHTML(contentBuf, a.fullPostURL(p))
|
||||||
|
bufferpool.Put(contentBuf)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Failed to extract links from post: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
apc := a.apHttpClients[p.Blog]
|
||||||
|
mentions := []string{}
|
||||||
|
for _, link := range lo.Uniq(links) {
|
||||||
|
act, err := apc.Actor(context.Background(), ap.IRI(link))
|
||||||
|
if err != nil || act == nil || act.Type != ap.PersonType {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mentions = append(mentions, link)
|
||||||
|
}
|
||||||
|
if p.Parameters == nil {
|
||||||
|
p.Parameters = map[string][]string{}
|
||||||
|
}
|
||||||
|
p.Parameters[activityPubMentionsParameter] = mentions
|
||||||
|
_ = a.db.replacePostParam(p.Path, activityPubMentionsParameter, mentions)
|
||||||
|
}
|
||||||
|
|
||||||
|
const activityPubReplyActorParameter = "activitypubreplyactor"
|
||||||
|
|
||||||
|
func (a *goBlog) apCheckActivityPubReply(p *post) {
|
||||||
|
replyLink := a.replyLink(p)
|
||||||
|
if replyLink == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
apc := a.apHttpClients[p.Blog]
|
||||||
|
item, err := apc.LoadIRI(ap.IRI(replyLink))
|
||||||
|
if err != nil || item == nil || !ap.IsObject(item) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
obj, err := ap.ToObject(item)
|
||||||
|
if err != nil || obj == nil || obj.GetLink() == "" || obj.AttributedTo == nil || obj.AttributedTo.GetLink() == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
replyLinkActor := []string{obj.AttributedTo.GetLink().String()}
|
||||||
|
if p.Parameters == nil {
|
||||||
|
p.Parameters = map[string][]string{}
|
||||||
|
}
|
||||||
|
p.Parameters[activityPubReplyActorParameter] = replyLinkActor
|
||||||
|
_ = a.db.replacePostParam(p.Path, activityPubReplyActorParameter, replyLinkActor)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *goBlog) apHandleInbox(w http.ResponseWriter, r *http.Request) {
|
func (a *goBlog) apHandleInbox(w http.ResponseWriter, r *http.Request) {
|
||||||
blogName := chi.URLParam(r, "blog")
|
blogName := chi.URLParam(r, "blog")
|
||||||
blog, ok := a.cfg.Blogs[blogName]
|
blog, ok := a.cfg.Blogs[blogName]
|
||||||
|
@ -400,7 +456,7 @@ func (a *goBlog) apPost(p *post) {
|
||||||
c := ap.CreateNew(a.apNewID(blogConfig), a.toAPNote(p))
|
c := ap.CreateNew(a.apNewID(blogConfig), a.toAPNote(p))
|
||||||
c.Actor = a.apAPIri(blogConfig)
|
c.Actor = a.apAPIri(blogConfig)
|
||||||
c.Published = time.Now()
|
c.Published = time.Now()
|
||||||
a.apSendToAllFollowers(p.Blog, c)
|
a.apSendToAllFollowers(p.Blog, c, append(p.Parameters[activityPubMentionsParameter], p.firstParameter(activityPubReplyActorParameter))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) apUpdate(p *post) {
|
func (a *goBlog) apUpdate(p *post) {
|
||||||
|
@ -408,7 +464,7 @@ func (a *goBlog) apUpdate(p *post) {
|
||||||
u := ap.UpdateNew(a.apNewID(blogConfig), a.toAPNote(p))
|
u := ap.UpdateNew(a.apNewID(blogConfig), a.toAPNote(p))
|
||||||
u.Actor = a.apAPIri(blogConfig)
|
u.Actor = a.apAPIri(blogConfig)
|
||||||
u.Published = time.Now()
|
u.Published = time.Now()
|
||||||
a.apSendToAllFollowers(p.Blog, u)
|
a.apSendToAllFollowers(p.Blog, u, append(p.Parameters[activityPubMentionsParameter], p.firstParameter(activityPubReplyActorParameter))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) apDelete(p *post) {
|
func (a *goBlog) apDelete(p *post) {
|
||||||
|
@ -416,7 +472,7 @@ func (a *goBlog) apDelete(p *post) {
|
||||||
d := ap.DeleteNew(a.apNewID(blogConfig), a.activityPubId(p))
|
d := ap.DeleteNew(a.apNewID(blogConfig), a.activityPubId(p))
|
||||||
d.Actor = a.apAPIri(blogConfig)
|
d.Actor = a.apAPIri(blogConfig)
|
||||||
d.Published = time.Now()
|
d.Published = time.Now()
|
||||||
a.apSendToAllFollowers(p.Blog, d)
|
a.apSendToAllFollowers(p.Blog, d, append(p.Parameters[activityPubMentionsParameter], p.firstParameter(activityPubReplyActorParameter))...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) apUndelete(p *post) {
|
func (a *goBlog) apUndelete(p *post) {
|
||||||
|
@ -470,21 +526,36 @@ func (a *goBlog) apSendProfileUpdates() {
|
||||||
update := ap.UpdateNew(a.apNewID(config), person)
|
update := ap.UpdateNew(a.apNewID(config), person)
|
||||||
update.Actor = a.apAPIri(config)
|
update.Actor = a.apAPIri(config)
|
||||||
update.Published = time.Now()
|
update.Published = time.Now()
|
||||||
|
update.To.Append(ap.PublicNS, a.apGetFollowersCollectionId(blog, config))
|
||||||
a.apSendToAllFollowers(blog, update)
|
a.apSendToAllFollowers(blog, update)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) apSendToAllFollowers(blog string, activity *ap.Activity) {
|
func (a *goBlog) apSendToAllFollowers(blog string, activity *ap.Activity, mentions ...string) {
|
||||||
inboxes, err := a.db.apGetAllInboxes(blog)
|
inboxes, err := a.db.apGetAllInboxes(blog)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Failed to retrieve inboxes:", err.Error())
|
log.Println("Failed to retrieve follower inboxes:", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
a.apSendTo(a.apIri(a.cfg.Blogs[blog]), activity, inboxes)
|
for _, m := range mentions {
|
||||||
|
go func(m string) {
|
||||||
|
if m == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
apc := a.apHttpClients[blog]
|
||||||
|
actor, err := apc.Actor(context.Background(), ap.IRI(m))
|
||||||
|
if err != nil || actor == nil || actor.Inbox == nil || actor.Inbox.GetLink() == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
inbox := actor.Inbox.GetLink().String()
|
||||||
|
a.apSendTo(a.apIri(a.cfg.Blogs[blog]), activity, inbox)
|
||||||
|
}(m)
|
||||||
|
}
|
||||||
|
a.apSendTo(a.apIri(a.cfg.Blogs[blog]), activity, inboxes...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) apSendTo(blogIri string, activity *ap.Activity, inboxes []string) {
|
func (a *goBlog) apSendTo(blogIri string, activity *ap.Activity, inboxes ...string) {
|
||||||
for _, i := range inboxes {
|
for _, i := range lo.Uniq(inboxes) {
|
||||||
go func(inbox string) {
|
go func(inbox string) {
|
||||||
_ = a.apQueueSendSigned(blogIri, inbox, activity)
|
_ = a.apQueueSendSigned(blogIri, inbox, activity)
|
||||||
}(i)
|
}(i)
|
||||||
|
|
|
@ -44,18 +44,28 @@ func (a *goBlog) serveActivityStreamsPost(p *post, w http.ResponseWriter, r *htt
|
||||||
func (a *goBlog) toAPNote(p *post) *ap.Note {
|
func (a *goBlog) toAPNote(p *post) *ap.Note {
|
||||||
// Create a Note object
|
// Create a Note object
|
||||||
note := ap.ObjectNew(ap.NoteType)
|
note := ap.ObjectNew(ap.NoteType)
|
||||||
note.To.Append(ap.PublicNS)
|
|
||||||
note.MediaType = ap.MimeType(contenttype.HTML)
|
|
||||||
note.ID = a.activityPubId(p)
|
note.ID = a.activityPubId(p)
|
||||||
note.URL = ap.IRI(a.fullPostURL(p))
|
note.URL = ap.IRI(a.fullPostURL(p))
|
||||||
note.AttributedTo = a.apAPIri(a.getBlogFromPost(p))
|
note.AttributedTo = a.apAPIri(a.getBlogFromPost(p))
|
||||||
|
// Audience
|
||||||
|
switch p.Visibility {
|
||||||
|
case visibilityPublic:
|
||||||
|
note.To.Append(ap.PublicNS, a.apGetFollowersCollectionId(p.Blog, a.getBlogFromPost(p)))
|
||||||
|
case visibilityUnlisted:
|
||||||
|
note.To.Append(a.apGetFollowersCollectionId(p.Blog, a.getBlogFromPost(p)))
|
||||||
|
note.CC.Append(ap.PublicNS)
|
||||||
|
}
|
||||||
|
for _, m := range p.Parameters[activityPubMentionsParameter] {
|
||||||
|
note.CC.Append(ap.IRI(m))
|
||||||
|
}
|
||||||
// Name and Type
|
// Name and Type
|
||||||
if title := p.RenderedTitle; title != "" {
|
if title := p.RenderedTitle; title != "" {
|
||||||
note.Type = ap.ArticleType
|
note.Type = ap.ArticleType
|
||||||
note.Name.Add(ap.DefaultLangRef(title))
|
note.Name.Add(ap.DefaultLangRef(title))
|
||||||
}
|
}
|
||||||
// Content
|
// Content
|
||||||
note.Content.Add(ap.DefaultLangRef(a.postHtml(p, true)))
|
note.MediaType = ap.MimeType(contenttype.HTML)
|
||||||
|
note.Content.Add(ap.DefaultLangRef(a.postHtml(&postHtmlOptions{p: p, absolute: true, activityPub: true})))
|
||||||
// Attachments
|
// Attachments
|
||||||
if images := p.Parameters[a.cfg.Micropub.PhotoParam]; len(images) > 0 {
|
if images := p.Parameters[a.cfg.Micropub.PhotoParam]; len(images) > 0 {
|
||||||
var attachments ap.ItemCollection
|
var attachments ap.ItemCollection
|
||||||
|
@ -75,6 +85,17 @@ func (a *goBlog) toAPNote(p *post) *ap.Note {
|
||||||
note.Tag.Append(apTag)
|
note.Tag.Append(apTag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Mentions
|
||||||
|
for _, mention := range p.Parameters[activityPubMentionsParameter] {
|
||||||
|
apMention := ap.MentionNew(ap.IRI(mention))
|
||||||
|
apMention.Href = ap.IRI(mention)
|
||||||
|
note.Tag.Append(apMention)
|
||||||
|
}
|
||||||
|
if replyLinkActor := p.firstParameter(activityPubReplyActorParameter); replyLinkActor != "" {
|
||||||
|
apMention := ap.MentionNew(ap.IRI(replyLinkActor))
|
||||||
|
apMention.Href = ap.IRI(replyLinkActor)
|
||||||
|
note.Tag.Append(apMention)
|
||||||
|
}
|
||||||
// Dates
|
// Dates
|
||||||
if p.Published != "" {
|
if p.Published != "" {
|
||||||
if t, err := dateparse.ParseLocal(p.Published); err == nil {
|
if t, err := dateparse.ParseLocal(p.Published); err == nil {
|
||||||
|
|
2
check.go
2
check.go
|
@ -129,7 +129,7 @@ func (a *goBlog) checkLinks(w io.Writer, posts ...*post) error {
|
||||||
func (a *goBlog) allLinks(posts ...*post) (allLinks []*stringPair, err error) {
|
func (a *goBlog) allLinks(posts ...*post) (allLinks []*stringPair, err error) {
|
||||||
for _, p := range posts {
|
for _, p := range posts {
|
||||||
contentBuf := bufferpool.Get()
|
contentBuf := bufferpool.Get()
|
||||||
a.postHtmlToWriter(contentBuf, p, true)
|
a.postHtmlToWriter(contentBuf, &postHtmlOptions{p: p, absolute: true})
|
||||||
links, err := allLinksFromHTML(contentBuf, a.fullPostURL(p))
|
links, err := allLinksFromHTML(contentBuf, a.fullPostURL(p))
|
||||||
bufferpool.Put(contentBuf)
|
bufferpool.Put(contentBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -18,7 +18,7 @@ func (a *goBlog) initIndexNow() {
|
||||||
// Add hooks
|
// Add hooks
|
||||||
hook := func(p *post) {
|
hook := func(p *post) {
|
||||||
// Check if post is published
|
// Check if post is published
|
||||||
if !p.isPublishedSectionPost() {
|
if !p.isPublicPublishedSectionPost() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Send IndexNow request
|
// Send IndexNow request
|
||||||
|
|
|
@ -20,6 +20,10 @@ func (a *goBlog) checkPost(p *post, new bool) (err error) {
|
||||||
}
|
}
|
||||||
now := time.Now().Local()
|
now := time.Now().Local()
|
||||||
nowString := now.Format(time.RFC3339)
|
nowString := now.Format(time.RFC3339)
|
||||||
|
// Add parameters map
|
||||||
|
if p.Parameters == nil {
|
||||||
|
p.Parameters = map[string][]string{}
|
||||||
|
}
|
||||||
// Maybe add blog
|
// Maybe add blog
|
||||||
if p.Blog == "" {
|
if p.Blog == "" {
|
||||||
p.Blog = a.cfg.DefaultBlog
|
p.Blog = a.cfg.DefaultBlog
|
||||||
|
|
|
@ -39,33 +39,41 @@ func (p *post) addParameter(parameter, value string) {
|
||||||
p.Parameters[parameter] = append(p.Parameters[parameter], value)
|
p.Parameters[parameter] = append(p.Parameters[parameter], value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) postHtml(p *post, absolute bool) (res string) {
|
type postHtmlOptions struct {
|
||||||
|
p *post
|
||||||
|
absolute bool
|
||||||
|
activityPub bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *goBlog) postHtml(o *postHtmlOptions) (res string) {
|
||||||
buf := bufferpool.Get()
|
buf := bufferpool.Get()
|
||||||
a.postHtmlToWriter(buf, p, absolute)
|
a.postHtmlToWriter(buf, o)
|
||||||
res = buf.String()
|
res = buf.String()
|
||||||
bufferpool.Put(buf)
|
bufferpool.Put(buf)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) postHtmlToWriter(w io.Writer, p *post, absolute bool) {
|
func (a *goBlog) postHtmlToWriter(w io.Writer, o *postHtmlOptions) {
|
||||||
// Build HTML
|
// Build HTML
|
||||||
hb := htmlbuilder.NewHtmlBuilder(w)
|
hb := htmlbuilder.NewHtmlBuilder(w)
|
||||||
// Add audio to the top
|
// Add audio to the top
|
||||||
for _, a := range p.Parameters[a.cfg.Micropub.AudioParam] {
|
for _, a := range o.p.Parameters[a.cfg.Micropub.AudioParam] {
|
||||||
hb.WriteElementOpen("audio", "controls", "preload", "none")
|
hb.WriteElementOpen("audio", "controls", "preload", "none")
|
||||||
hb.WriteElementOpen("source", "src", a)
|
hb.WriteElementOpen("source", "src", a)
|
||||||
hb.WriteElementClose("source")
|
hb.WriteElementClose("source")
|
||||||
hb.WriteElementClose("audio")
|
hb.WriteElementClose("audio")
|
||||||
}
|
}
|
||||||
// Add IndieWeb context
|
// Add IndieWeb context
|
||||||
a.renderPostReplyContext(hb, p)
|
if !o.activityPub || o.p.firstParameter(activityPubReplyActorParameter) == "" {
|
||||||
a.renderPostLikeContext(hb, p)
|
a.renderPostReplyContext(hb, o.p)
|
||||||
|
}
|
||||||
|
a.renderPostLikeContext(hb, o.p)
|
||||||
// Render markdown
|
// Render markdown
|
||||||
hb.WriteElementOpen("div", "class", "e-content")
|
hb.WriteElementOpen("div", "class", "e-content")
|
||||||
_ = a.renderMarkdownToWriter(w, p.Content, absolute)
|
_ = a.renderMarkdownToWriter(w, o.p.Content, o.absolute)
|
||||||
hb.WriteElementClose("div")
|
hb.WriteElementClose("div")
|
||||||
// Add bookmark links to the bottom
|
// Add bookmark links to the bottom
|
||||||
for _, l := range p.Parameters[a.cfg.Micropub.BookmarkParam] {
|
for _, l := range o.p.Parameters[a.cfg.Micropub.BookmarkParam] {
|
||||||
hb.WriteElementOpen("p")
|
hb.WriteElementOpen("p")
|
||||||
hb.WriteElementOpen("a", "class", "u-bookmark-of", "href", l, "target", "_blank", "rel", "noopener noreferrer")
|
hb.WriteElementOpen("a", "class", "u-bookmark-of", "href", l, "target", "_blank", "rel", "noopener noreferrer")
|
||||||
hb.WriteEscaped(l)
|
hb.WriteEscaped(l)
|
||||||
|
@ -84,7 +92,7 @@ func (a *goBlog) feedHtml(w io.Writer, p *post) {
|
||||||
hb.WriteElementClose("audio")
|
hb.WriteElementClose("audio")
|
||||||
}
|
}
|
||||||
// Add post HTML
|
// Add post HTML
|
||||||
a.postHtmlToWriter(hb, p, true)
|
a.postHtmlToWriter(hb, &postHtmlOptions{p: p, absolute: true})
|
||||||
// Add link to interactions and comments
|
// Add link to interactions and comments
|
||||||
blogConfig := a.getBlogFromPost(p)
|
blogConfig := a.getBlogFromPost(p)
|
||||||
if cc := blogConfig.Comments; cc != nil && cc.Enabled {
|
if cc := blogConfig.Comments; cc != nil && cc.Enabled {
|
||||||
|
@ -99,7 +107,7 @@ func (a *goBlog) feedHtml(w io.Writer, p *post) {
|
||||||
func (a *goBlog) minFeedHtml(w io.Writer, p *post) {
|
func (a *goBlog) minFeedHtml(w io.Writer, p *post) {
|
||||||
hb := htmlbuilder.NewHtmlBuilder(w)
|
hb := htmlbuilder.NewHtmlBuilder(w)
|
||||||
// Add post HTML
|
// Add post HTML
|
||||||
a.postHtmlToWriter(hb, p, true)
|
a.postHtmlToWriter(hb, &postHtmlOptions{p: p, absolute: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
const summaryDivider = "<!--more-->"
|
const summaryDivider = "<!--more-->"
|
||||||
|
@ -145,7 +153,11 @@ func (a *goBlog) postTranslations(p *post) []*post {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *post) isPublishedSectionPost() bool {
|
func (p *post) isPublishedSectionPost() bool {
|
||||||
return p.Published != "" && p.Section != "" && p.Status == statusPublished && p.Visibility == visibilityPublic
|
return p.Section != "" && p.Status == statusPublished
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *post) isPublicPublishedSectionPost() bool {
|
||||||
|
return p.isPublishedSectionPost() && p.Visibility == visibilityPublic
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *goBlog) postToMfItem(p *post) *microformatItem {
|
func (a *goBlog) postToMfItem(p *post) *microformatItem {
|
||||||
|
|
|
@ -26,7 +26,7 @@ func (tg *configTelegram) enabled() bool {
|
||||||
|
|
||||||
func (a *goBlog) tgPost(silent bool) func(*post) {
|
func (a *goBlog) tgPost(silent bool) func(*post) {
|
||||||
return func(p *post) {
|
return func(p *post) {
|
||||||
if tg := a.getBlogFromPost(p).Telegram; tg.enabled() && p.isPublishedSectionPost() {
|
if tg := a.getBlogFromPost(p).Telegram; tg.enabled() && p.isPublicPublishedSectionPost() {
|
||||||
tgChat := p.firstParameter("telegramchat")
|
tgChat := p.firstParameter("telegramchat")
|
||||||
tgMsg := p.firstParameter("telegrammsg")
|
tgMsg := p.firstParameter("telegrammsg")
|
||||||
if tgChat != "" && tgMsg != "" {
|
if tgChat != "" && tgMsg != "" {
|
||||||
|
|
4
tts.go
4
tts.go
|
@ -28,7 +28,7 @@ func (a *goBlog) initTTS() {
|
||||||
}
|
}
|
||||||
createOrUpdate := func(p *post) {
|
createOrUpdate := func(p *post) {
|
||||||
// Automatically create audio for published section posts only
|
// Automatically create audio for published section posts only
|
||||||
if !p.isPublishedSectionPost() {
|
if !p.isPublicPublishedSectionPost() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Check if there is already a tts audio file
|
// Check if there is already a tts audio file
|
||||||
|
@ -69,7 +69,7 @@ func (a *goBlog) createPostTTSAudio(p *post) error {
|
||||||
parts = append(parts, a.renderMdTitle(title))
|
parts = append(parts, a.renderMdTitle(title))
|
||||||
}
|
}
|
||||||
// Add body split into paragraphs because of 5000 character limit
|
// Add body split into paragraphs because of 5000 character limit
|
||||||
parts = append(parts, strings.Split(htmlText(a.postHtml(p, false)), "\n\n")...)
|
parts = append(parts, strings.Split(htmlText(a.postHtml(&postHtmlOptions{p: p})), "\n\n")...)
|
||||||
|
|
||||||
// Create TTS audio for each part
|
// Create TTS audio for each part
|
||||||
partWriters := make([]io.Writer, len(parts))
|
partWriters := make([]io.Writer, len(parts))
|
||||||
|
|
6
ui.go
6
ui.go
|
@ -38,7 +38,7 @@ func (a *goBlog) wrapUiPlugins(t plugintypes.RenderType, d plugintypes.RenderDat
|
||||||
func (a *goBlog) renderEditorPreview(hb *htmlbuilder.HtmlBuilder, bc *configBlog, p *post) {
|
func (a *goBlog) renderEditorPreview(hb *htmlbuilder.HtmlBuilder, bc *configBlog, p *post) {
|
||||||
a.renderPostTitle(hb, p)
|
a.renderPostTitle(hb, p)
|
||||||
a.renderPostMeta(hb, p, bc, "preview")
|
a.renderPostMeta(hb, p, bc, "preview")
|
||||||
a.postHtmlToWriter(hb, p, true)
|
a.postHtmlToWriter(hb, &postHtmlOptions{p: p, absolute: true})
|
||||||
// a.renderPostGPX(hb, p, bc)
|
// a.renderPostGPX(hb, p, bc)
|
||||||
a.renderPostTax(hb, p, bc)
|
a.renderPostTax(hb, p, bc)
|
||||||
}
|
}
|
||||||
|
@ -931,7 +931,7 @@ func (a *goBlog) renderPost(hb *htmlbuilder.HtmlBuilder, rd *renderData) {
|
||||||
// Old content warning
|
// Old content warning
|
||||||
a.renderOldContentWarning(hb, p, rd.Blog)
|
a.renderOldContentWarning(hb, p, rd.Blog)
|
||||||
// Content
|
// Content
|
||||||
a.postHtmlToWriter(hb, p, false)
|
a.postHtmlToWriter(hb, &postHtmlOptions{p: p})
|
||||||
// External Videp
|
// External Videp
|
||||||
a.renderPostVideo(hb, p)
|
a.renderPostVideo(hb, p)
|
||||||
// GPS Track
|
// GPS Track
|
||||||
|
@ -1008,7 +1008,7 @@ func (a *goBlog) renderStaticHome(hb *htmlbuilder.HtmlBuilder, rd *renderData) {
|
||||||
// Content
|
// Content
|
||||||
if p.Content != "" {
|
if p.Content != "" {
|
||||||
// Content
|
// Content
|
||||||
a.postHtmlToWriter(hb, p, false)
|
a.postHtmlToWriter(hb, &postHtmlOptions{p: p})
|
||||||
}
|
}
|
||||||
// Author
|
// Author
|
||||||
a.renderAuthor(hb)
|
a.renderAuthor(hb)
|
||||||
|
|
|
@ -53,7 +53,7 @@ func (a *goBlog) renderSummary(hb *htmlbuilder.HtmlBuilder, bc *configBlog, p *p
|
||||||
a.renderPostMeta(hb, p, bc, "summary")
|
a.renderPostMeta(hb, p, bc, "summary")
|
||||||
if typ != photoSummary && a.showFull(p) {
|
if typ != photoSummary && a.showFull(p) {
|
||||||
// Show full content
|
// Show full content
|
||||||
a.postHtmlToWriter(hb, p, false)
|
a.postHtmlToWriter(hb, &postHtmlOptions{p: p})
|
||||||
} else {
|
} else {
|
||||||
// Show IndieWeb context
|
// Show IndieWeb context
|
||||||
a.renderPostReplyContext(hb, p)
|
a.renderPostReplyContext(hb, p)
|
||||||
|
|
|
@ -32,18 +32,13 @@ func (a *goBlog) sendWebmentions(p *post) error {
|
||||||
// Ignore this post
|
// Ignore this post
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
links := []string{}
|
|
||||||
contentBuf := bufferpool.Get()
|
contentBuf := bufferpool.Get()
|
||||||
a.postHtmlToWriter(contentBuf, p, false)
|
a.postHtmlToWriter(contentBuf, &postHtmlOptions{p: p})
|
||||||
contentLinks, err := allLinksFromHTML(contentBuf, a.fullPostURL(p))
|
links, err := allLinksFromHTML(contentBuf, a.fullPostURL(p))
|
||||||
bufferpool.Put(contentBuf)
|
bufferpool.Put(contentBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
links = append(links, contentLinks...)
|
|
||||||
if mpc := a.cfg.Micropub; mpc != nil {
|
|
||||||
links = append(links, p.firstParameter(a.cfg.Micropub.LikeParam), p.firstParameter(a.cfg.Micropub.ReplyParam), p.firstParameter(a.cfg.Micropub.BookmarkParam))
|
|
||||||
}
|
|
||||||
for _, link := range lo.Uniq(links) {
|
for _, link := range lo.Uniq(links) {
|
||||||
if link == "" {
|
if link == "" {
|
||||||
continue
|
continue
|
||||||
|
|
Loading…
Reference in New Issue