Idiomdrottning’s homepage

rss-mash

I haven’t been programming for a while but I spent a few minutes putting together a li’l rss-mash utility that takes RSS URLs on the command line and prints a combined XML file of all those items to the standard output.

I made it with zshbrev. Here is the code:

(define (sxml-url (= ->string url))
  (call-with-input-request url #f html->sxml))

(define (rss-mash . (= (c map sxml-url) feeds))
  (serialize-sxml
   `(*TOP* (*PI* xml "version=\"1.0\" encoding=\"utf-8\"")
		   (rss (@ (version "2.0") (xmlns:dc "http://purl.org/dc/elements/1.1/"))
				(channel
				 (title ,(string-intersperse
						 (map (o cadar (sxpath "//channel/title")) feeds)
						 " + "))
				 (description
				  "A mashup of feeds")
				 ,@(sort
					(apply
					 lset-union
					 (bi-each equal? (sxpath "guid"))
					 (map (sxpath "//item") feeds))
					(bi-each > (o (c date '+%s '--date) cadar (sxpath "pubdate")))))))))

I already had sxml-url, which has been pretty useful both at the command line, where it prints an SXML representation of any web page, and in other zshbrev apps, like rss-mash which is the new part.

It’s also hopefully a pretty clear demo of how zshbrev turns command line arguments into function arguments, and function output into stdout in a pretty dwimmy way (it should work regardless of whether your function prints something or returns a value, like a tree or string).

This currently only works with RSS, not Atom. It’s just a li’l hack quickly thrown together.

Installation and usage

First:

apt install chicken
chicken-install brev zshbrev < Paste the code from earlier in this post (the two `define` calls) into `~/.zshbrev/functions`, then:

zshbrev
~/.zshbrev/bin/rss-mash https://the-first/url.xml https://a-second/url.xml

You can add ~/.zshbrev/bin/ to your path if you wanna.

Handling Atom

Okay so it always bugged me that this didn’t handle Atom since Atom is most of what I use so now it does:

(import tree)
(define (sxml-atom? tree) (tree-any? (is? 'feed) tree))

(define (sxml-rss-url (= ->string url))
  (handle-exceptions
      exn #f
      (with (sxml-url url)
        (if (sxml-atom? it)
            (call-with-input-string
             (run/string (/home/sandra/skami/pl/atom2rss/atom2rss ,url))
             html->sxml)
            it))))

And (c map sxml-url) becomes (c filter-map sxml-url). The Perl script is totally vibe coded 😰

#!/usr/bin/perl
use utf8;
use open ':encoding(utf8)';
binmode(STDOUT, ":utf8");
use XML::Feed;
my $atom = XML::Feed->parse(URI->new($ARGV[0]), 'Atom') or die XML::Feed->errstr;
my $rss = $atom->convert('RSS');
print $rss->as_xml;

I think next up I’ll bake in Parabola conversion so it can take a Gemini URL.