From 97ff66116b7633066375bbc6cc88be5b8587453b Mon Sep 17 00:00:00 2001 From: grunfink Date: Wed, 28 May 2025 07:48:47 +0200 Subject: New file rss.c. --- rss.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 rss.c (limited to 'rss.c') diff --git a/rss.c b/rss.c new file mode 100644 index 0000000..61620fa --- /dev/null +++ b/rss.c @@ -0,0 +1,105 @@ +/* snac - A simple, minimalistic ActivityPub instance */ +/* copyright (c) 2025 grunfink et al. / MIT license */ + +#include "xs.h" +#include "xs_html.h" +#include "xs_regex.h" +#include "xs_time.h" + +#include "snac.h" + +xs_str *rss_from_timeline(snac *user, const xs_list *timeline, + const char *title, const char *link, const char *desc) +/* converts a timeline to rss */ +{ + xs_html *rss = xs_html_tag("rss", + xs_html_attr("xmlns:content", "http:/" "/purl.org/rss/1.0/modules/content/"), + xs_html_attr("version", "2.0"), + xs_html_attr("xmlns:atom", "http:/" "/www.w3.org/2005/Atom")); + + xs_html *channel = xs_html_tag("channel", + xs_html_tag("title", + xs_html_text(title)), + xs_html_tag("language", + xs_html_text("en")), + xs_html_tag("link", + xs_html_text(link)), + xs_html_sctag("atom:link", + xs_html_attr("href", link), + xs_html_attr("rel", "self"), + xs_html_attr("type", "application/rss+xml")), + xs_html_tag("generator", + xs_html_text(USER_AGENT)), + xs_html_tag("description", + xs_html_text(desc))); + + xs_html_add(rss, channel); + + int cnt = 0; + const char *v; + + xs_list_foreach(timeline, v) { + xs *msg = NULL; + + if (user) { + if (!valid_status(timeline_get_by_md5(user, v, &msg))) + continue; + } + else { + if (!valid_status(object_get_by_md5(v, &msg))) + continue; + } + + const char *id = xs_dict_get(msg, "id"); + const char *content = xs_dict_get(msg, "content"); + const char *published = xs_dict_get(msg, "published"); + + if (user && !xs_startswith(id, user->actor)) + continue; + + if (!id || !content || !published) + continue; + + /* create a title with the first line of the content */ + xs *title = xs_replace(content, "
", "\n"); + title = xs_regex_replace_i(title, "<[^>]+>", " "); + title = xs_regex_replace_i(title, "&[^;]+;", " "); + int i; + + for (i = 0; title[i] && title[i] != '\n' && i < 50; i++); + + if (title[i] != '\0') { + title[i] = '\0'; + title = xs_str_cat(title, "..."); + } + + title = xs_strip_i(title); + + /* convert the date */ + time_t t = xs_parse_iso_date(published, 0); + xs *rss_date = xs_str_utctime(t, "%a, %d %b %Y %T +0000"); + + /* if it's the first one, add it to the header */ + if (cnt == 0) + xs_html_add(channel, + xs_html_tag("lastBuildDate", + xs_html_text(rss_date))); + + xs_html_add(channel, + xs_html_tag("item", + xs_html_tag("title", + xs_html_text(title)), + xs_html_tag("link", + xs_html_text(id)), + xs_html_tag("guid", + xs_html_text(id)), + xs_html_tag("pubDate", + xs_html_text(rss_date)), + xs_html_tag("description", + xs_html_text(content)))); + + cnt++; + } + + return xs_html_render_s(rss, "\n"); +} -- cgit v1.2.3