💾 Archived View for auragem.letz.dev › devlog › 20220720.gmi captured on 2024-07-09 at 02:06:17. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2024-03-21)

-=-=-=-=-=-=-

2022-07-20 AuraGem's Go Code for Converting Gemsub Feed to Atom

There was recent talk about converting Gemsub Feeds to Atom Feeds:

proposal for an RSS proxy

So, I wanted to post some code I have. Well over a year ago, one of the first things I did on AuraGem (previously Ponix) was write code that converted a Gemsub Feed to an Atom Feed. Everytime someone clicks on AuraGem's Atom feed, it is automatically generated on-demand with the code below. It is extremely simple, and certainly can be improved, but it works for my uses. One thing that can be added is the subtitle line (marked by the second-level heading just under the feed title), as described in the Gemsub Feed companion spec.

Gemsub Feed Companion Spec

type AtomPost struct {
	link  string
	date  time.Time
	title string
}

func generateAtomFrom(file string, domain string, baseurl string, authorName string, authorEmail string) string {
	feedTitle := ""
	var posts []AtomPost
	last_updated, _ := time.Parse("2006-01-02T15:04:05Z", "2006-01-02T15:04:05Z")

	gemini, err := ioutil.ReadFile(file)
	if err != nil {
		panic(err)
	}
	geminiLines := strings.Split(strings.TrimSuffix(string(gemini), "\n"), "\n")
	for _, line := range geminiLines {
		if strings.HasPrefix(line, "=> ") {
			parts := strings.SplitN(strings.Replace(line, "=> ", "", 1), " ", 3)

			t, err := time.Parse(time.RFC3339, parts[1])
			if err != nil {
				t, err = time.Parse("2006-01-02", parts[1])
				if err != nil {
					continue
				}
			}

			if t.After(last_updated) {
				last_updated = t
			}

			if len(parts) >= 3 {
				posts = append(posts, AtomPost{domain + parts[0], t, parts[2]})
			}
		} else if strings.HasPrefix(line, "# ") && feedTitle == "" {
			feedTitle = strings.Replace(line, "# ", "", 1)
		}
	}

	last_updated_string := last_updated.Format("2006-01-02T15:04:05Z")

	var builder strings.Builder
	fmt.Fprintf(&builder, `<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<id>%s</id>
	<title>%s</title>
	<updated>%s</updated>
	<link href="%s"/>
	<author>
		<name>%s</name>
		<email>%s</email>
	</author>
`, baseurl, html.EscapeString(feedTitle), last_updated_string, baseurl+"/atom.xml", html.EscapeString(authorName), html.EscapeString(authorEmail))

	for _, post := range posts {
		post_date_string := post.date.Format(time.RFC3339)

		fmt.Fprintf(&builder,
			`	<entry>
		<title>%s</title>
		<link rel="alternate" href="%s"/>
		<id>%s</id>
		<updated>%s</updated>
	</entry>
`, html.EscapeString(post.title), post.link, post.link, post_date_string)
	}

	fmt.Fprintf(&builder, `</feed>`)

	return builder.String()
}