Implement gemini atom feed
This commit is contained in:
parent
1cfdac5e8c
commit
5b5a043868
@ -37,8 +37,7 @@ type rendererGetPostSeriesNextPreviousRes struct {
|
||||
type renderer struct {
|
||||
url *url.URL
|
||||
postStore post.Store
|
||||
gmiPublicURL *url.URL
|
||||
httpPublicURL *url.URL
|
||||
preprocessFuncs post.PreprocessFunctions
|
||||
}
|
||||
|
||||
func (r renderer) GetPosts(page, count int) (rendererGetPostsRes, error) {
|
||||
@ -91,39 +90,9 @@ func (r renderer) GetPostSeriesNextPrevious(p post.StoredPost) (rendererGetPostS
|
||||
|
||||
func (r renderer) PostBody(p post.StoredPost) (string, error) {
|
||||
|
||||
preprocessFuncs := post.PreprocessFunctions{
|
||||
BlogURL: func(path string) string {
|
||||
return filepath.Join("/", r.gmiPublicURL.Path, path)
|
||||
},
|
||||
AssetURL: func(id string) string {
|
||||
return filepath.Join("/assets", id)
|
||||
},
|
||||
PostURL: func(id string) string {
|
||||
return filepath.Join("/posts", id)
|
||||
},
|
||||
StaticURL: func(path string) string {
|
||||
httpPublicURL := *r.httpPublicURL
|
||||
httpPublicURL.Path = filepath.Join(httpPublicURL.Path, "/static", path)
|
||||
return httpPublicURL.String()
|
||||
},
|
||||
Image: func(args ...string) (string, error) {
|
||||
|
||||
var (
|
||||
id = args[0]
|
||||
descr = "Image"
|
||||
)
|
||||
|
||||
if len(args) > 1 {
|
||||
descr = args[1]
|
||||
}
|
||||
|
||||
return fmt.Sprintf("=> %s %s", filepath.Join("/assets", id), descr), nil
|
||||
},
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
if err := p.PreprocessBody(buf, preprocessFuncs); err != nil {
|
||||
if err := p.PreprocessBody(buf, r.preprocessFuncs); err != nil {
|
||||
return "", fmt.Errorf("preprocessing post body: %w", err)
|
||||
}
|
||||
|
||||
@ -159,8 +128,66 @@ func (r renderer) Add(a, b int) int { return a + b }
|
||||
|
||||
func (a *api) tplHandler() (gemini.Handler, error) {
|
||||
|
||||
blogURL := func(path string, abs bool) string {
|
||||
path = filepath.Join(a.params.PublicURL.Path, path)
|
||||
|
||||
if !abs {
|
||||
return path
|
||||
}
|
||||
|
||||
u := *a.params.PublicURL
|
||||
u.Path = path
|
||||
return u.String()
|
||||
}
|
||||
|
||||
preprocessFuncs := post.PreprocessFunctions{
|
||||
BlogURL: func(path string) string {
|
||||
return blogURL(path, false)
|
||||
},
|
||||
AssetURL: func(id string) string {
|
||||
path := filepath.Join("assets", id)
|
||||
return blogURL(path, false)
|
||||
},
|
||||
PostURL: func(id string) string {
|
||||
path := filepath.Join("posts", id) + ".gmi"
|
||||
return blogURL(path, false)
|
||||
},
|
||||
StaticURL: func(path string) string {
|
||||
httpPublicURL := *a.params.HTTPPublicURL
|
||||
httpPublicURL.Path = filepath.Join(httpPublicURL.Path, "/static", path)
|
||||
return httpPublicURL.String()
|
||||
},
|
||||
Image: func(args ...string) (string, error) {
|
||||
|
||||
var (
|
||||
id = args[0]
|
||||
descr = "Image"
|
||||
)
|
||||
|
||||
if len(args) > 1 {
|
||||
descr = args[1]
|
||||
}
|
||||
|
||||
path := blogURL(filepath.Join("assets", id), false)
|
||||
|
||||
return fmt.Sprintf("=> %s %s", path, descr), nil
|
||||
},
|
||||
}
|
||||
|
||||
allTpls := template.New("")
|
||||
|
||||
allTpls.Funcs(preprocessFuncs.ToFuncsMap())
|
||||
|
||||
allTpls.Funcs(template.FuncMap{
|
||||
"BlogURLAbs": func(path string) string {
|
||||
return blogURL(path, true)
|
||||
},
|
||||
"PostURLAbs": func(id string) string {
|
||||
path := filepath.Join("posts", id) + ".gmi"
|
||||
return blogURL(path, true)
|
||||
},
|
||||
})
|
||||
|
||||
err := fs.WalkDir(tplFS, "tpl", func(path string, d fs.DirEntry, err error) error {
|
||||
|
||||
if err != nil {
|
||||
@ -221,8 +248,7 @@ func (a *api) tplHandler() (gemini.Handler, error) {
|
||||
err := tpl.Execute(buf, renderer{
|
||||
url: r.URL,
|
||||
postStore: a.params.PostStore,
|
||||
gmiPublicURL: a.params.PublicURL,
|
||||
httpPublicURL: a.params.HTTPPublicURL,
|
||||
preprocessFuncs: preprocessFuncs,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
28
src/gmi/tpl/feed.xml
Normal file
28
src/gmi/tpl/feed.xml
Normal file
@ -0,0 +1,28 @@
|
||||
{{ $getPostsRes := .GetPosts 0 15 -}}
|
||||
{{ $posts := $getPostsRes.Posts -}}
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<title>mediocregopher's lil web corner</title>
|
||||
<id>{{ BlogURLAbs "/" }}</id>
|
||||
{{ if gt (len $posts) 0 -}}
|
||||
<updated>{{ (index $posts 0).PublishedAt.Format "2006-01-02T15:04:05Z07:00" }}</updated>
|
||||
{{ end -}}
|
||||
<link href="{{ BlogURLAbs "/" }}"></link>
|
||||
<author>
|
||||
<name>mediocregopher</name>
|
||||
</author>
|
||||
{{ range $posts -}}
|
||||
<entry>
|
||||
<title>{{ .Title }}</title>
|
||||
<updated>{{ .PublishedAt.Format "2006-01-02T15:04:05Z07:00" }}</updated>
|
||||
<id>{{ PostURLAbs .ID }}</id>
|
||||
<link href="{{ PostURLAbs .ID }}" rel="alternate"></link>
|
||||
{{ if .Description -}}
|
||||
<summary type="html">{{ .Description }}</summary>
|
||||
{{ end -}}
|
||||
<author>
|
||||
<name>mediocregopher</name>
|
||||
</author>
|
||||
</entry>
|
||||
{{ end -}}
|
||||
</feed>
|
@ -9,7 +9,7 @@
|
||||
{{ end -}}
|
||||
|
||||
{{ range $getPostsRes.Posts -}}
|
||||
=> /posts/{{ .ID }}.gmi {{ .PublishedAt.Format "2006-01-02" }} - {{ .Title }}
|
||||
=> {{ PostURL .ID }} {{ .PublishedAt.Format "2006-01-02" }} - {{ .Title }}
|
||||
|
||||
{{ end -}}
|
||||
|
||||
|
@ -39,9 +39,8 @@ func (a *api) renderFeedHandler() http.Handler {
|
||||
publicURL := a.params.PublicURL.String()
|
||||
|
||||
feed := feeds.Feed{
|
||||
Title: "Mediocre Blog",
|
||||
Title: "mediocregopher's lil web corner",
|
||||
Link: &feeds.Link{Href: publicURL + "/"},
|
||||
Description: "A mix of tech, art, travel, and who knows what else.",
|
||||
Author: author,
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>mediocregopher's lil web corner</title>
|
||||
<style>{{ StaticInlineCSS "new.css" }}</style>
|
||||
<style>{{ StaticInlineCSS "mediocre.css" }}</style>
|
||||
|
||||
|
@ -37,6 +37,16 @@ type PreprocessFunctions struct {
|
||||
Image func(args ...string) (string, error)
|
||||
}
|
||||
|
||||
func (funcs PreprocessFunctions) ToFuncsMap() template.FuncMap {
|
||||
return template.FuncMap{
|
||||
"BlogURL": funcs.BlogURL,
|
||||
"AssetURL": funcs.AssetURL,
|
||||
"PostURL": funcs.PostURL,
|
||||
"StaticURL": funcs.StaticURL,
|
||||
"Image": funcs.Image,
|
||||
}
|
||||
}
|
||||
|
||||
// PreprocessBody interprets the Post's Body as a text template which may use
|
||||
// any of the functions found in PreprocessFunctions (all must be set). It
|
||||
// executes the template and writes the result to the given writer.
|
||||
@ -44,13 +54,7 @@ func (p Post) PreprocessBody(into io.Writer, funcs PreprocessFunctions) error {
|
||||
|
||||
tpl := template.New("")
|
||||
|
||||
tpl.Funcs(template.FuncMap{
|
||||
"BlogURL": funcs.BlogURL,
|
||||
"AssetURL": funcs.AssetURL,
|
||||
"PostURL": funcs.PostURL,
|
||||
"StaticURL": funcs.StaticURL,
|
||||
"Image": funcs.Image,
|
||||
})
|
||||
tpl.Funcs(funcs.ToFuncsMap())
|
||||
|
||||
tpl, err := tpl.Parse(p.Body)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user