#lang racket/base ; SPDX-License-Identifier: BlueOak-1.0.0 ; This file is licensed under the Blue Oak Model License 1.0.0. ;; Generates an Atom feed from the SQLite cache (require txexpr racket/match racket/file racket/date racket/string db/base "dust.rkt" "crystalize.rkt") (provide main) (define feed-author default-authorname) (define feed-author-email "joel@jdueck.net") (define feed-title "The Local Yarn (Beta)") (define feed-site-url "https://thelocalyarn.com") (define feed-item-limit 50) (define (as-cdata string) (cdata #f #f (format "" string))) ; cdata from xml package via txexpr (define (email-encode str) (map char->integer (string->list str))) ;; Atom feeds require dates to be in RFC 3339 format ;; Our published/updated dates only give year-month-day. No need to bother about time zones or DST. ;; So, arbitrarily, everything happens at a quarter of noon UTC. (define (ymd->rfc3339 datestr) (format "~aT11:45:00Z" datestr)) ;; For the feed "updated" value, we do want a complete timestamp. (define (current-rfc3339) ;; #f argument to seconds->date forces a UTC timestamp (define now (seconds->date (* 0.001 (current-inexact-milliseconds)) #f)) (define timestamp (parameterize [(date-display-format 'iso-8601)] (date->string now #t))) (string-append timestamp "Z")) ;; Get the data out of the SQLite cache as vectors (define (fetch-rows) (define fields '(pagenode title_plain published updated author doc_html)) (define select #<<--- SELECT `path`, `title`, `published`, `updated`, `author`, `entry_contents` FROM (SELECT `page` AS `path`, `title_plain` AS `title`, `published`, `updated`, `author`, `doc_html` AS `entry_contents` FROM `articles` UNION SELECT `page` || '#' || `html_anchor` AS `path`, `title_plain` AS `title`, `published`, "" AS `updated`, `author`, `content_html` as `entry_contents` FROM `notes`) ORDER BY `published` DESC LIMIT ~a --- ) (query-rows cache-conn (format select feed-item-limit))) (define (vector->rss-item vec) (match-define (vector path title published updated author contents) vec) (define entry-url (string-append feed-site-url web-root path)) (define update-ts (cond [(non-empty-string? updated) updated] [else published])) `(entry (author (name ,author)) (published ,(ymd->rfc3339 published)) (updated ,(ymd->rfc3339 update-ts)) (title ,title) (link [[rel "alternate"] [href ,entry-url]]) (id ,entry-url) (summary [[type "html"]] ,(as-cdata contents)))) (define (rss-feed) (define feed-xpr `(feed [[xml:lang "en-us"] [xmlns "http://www.w3.org/2005/Atom"]] (title ,feed-title) (link [[rel "self"] [href ,(string-append feed-site-url web-root "feed.xml")]]) (generator [[uri "http://pollenpub.com/"]] "Pollen") (id ,(string-append feed-site-url web-root)) (updated ,(current-rfc3339)) (author (name ,feed-author) (email ,@(email-encode feed-author-email))) ,@(map vector->rss-item (fetch-rows)))) (string-append "\n" (xexpr->string feed-xpr))) (define (main) (display-to-file (rss-feed) "feed.xml" #:mode 'text #:exists 'replace))