feeds: refactor

This commit is contained in:
2022-10-14 22:37:02 -07:00
parent 8a1ea79f1f
commit 75ae16aaab
2 changed files with 145 additions and 126 deletions

View File

@@ -1,148 +1,175 @@
{ lib }: { lib }:
rec { let
# TODO: fold this into RSS, with an `audio` category
podcastUrls = [
"https://lexfridman.com/feed/podcast/"
## Astral Codex Ten
"http://feeds.libsyn.com/108018/rss"
## Econ Talk
"https://feeds.simplecast.com/wgl4xEgL"
## Cory Doctorow
"https://feeds.feedburner.com/doctorow_podcast"
"https://congressionaldish.libsyn.com/rss"
## Civboot
"https://anchor.fm/s/34c7232c/podcast/rss"
"https://feeds.feedburner.com/80000HoursPodcast"
"https://allinchamathjason.libsyn.com/rss"
"https://acquired.libsyn.com/rss"
"https://rss.acast.com/deconstructed"
## The Daily
"https://feeds.simplecast.com/54nAGcIl"
"https://rss.acast.com/intercepted-with-jeremy-scahill"
"https://podcast.posttv.com/itunes/post-reports.xml"
## Eric Weinstein
"https://rss.art19.com/the-portal"
"https://feeds.megaphone.fm/darknetdiaries"
"http://feeds.wnyc.org/radiolab"
"https://wakingup.libsyn.com/rss"
## 99% Invisible
"https://feeds.simplecast.com/BqbsxVfO"
"https://rss.acast.com/ft-tech-tonic"
"https://feeds.feedburner.com/dancarlin/history?format=xml"
## 60 minutes (NB: this features more than *just* audio?)
"https://www.cbsnews.com/latest/rss/60-minutes"
];
rss =
let
hourly = { freq = "hourly"; }; hourly = { freq = "hourly"; };
daily = { freq = "daily"; }; daily = { freq = "daily"; };
weekly = { freq = "weekly"; }; weekly = { freq = "weekly"; };
infrequent = { freq = "infrequent"; }; infrequent = { freq = "infrequent"; };
art = { cat = "art"; };
humor = { cat = "humor"; };
pol = { cat = "pol"; }; # or maybe just "social"
rat = { cat = "rat"; }; rat = { cat = "rat"; };
tech = { cat = "tech"; }; tech = { cat = "tech"; };
pol = { cat = "pol"; };
uncat = { cat = "uncat"; }; uncat = { cat = "uncat"; };
visual = { cat = "visual"; };
in { text = { format = "text"; };
image = { format = "image"; };
podcast = { format = "podcast"; };
mkRss = format: url: { inherit url format; } // uncat // infrequent;
mkText = mkRss text;
mkImg = mkRss image;
mkPod = mkRss podcast;
# merge the attrs `new` into each value of the attrs `addTo`
addAttrs = new: addTo: builtins.mapAttrs (k: v: v // new) addTo;
# for each value in `attrs`, add a value to the child attrs which holds its key within the parent attrs.
withInverseMapping = key: attrs: builtins.mapAttrs (k: v: v // { "${key}" = k; }) attrs;
in rec {
podcasts = [
(mkPod "https://lexfridman.com/feed/podcast/" // rat // weekly)
## Astral Codex Ten
(mkPod "http://feeds.libsyn.com/108018/rss" // rat // daily)
## Econ Talk
(mkPod "https://feeds.simplecast.com/wgl4xEgL" // rat // daily)
## Cory Doctorow
(mkPod "https://feeds.feedburner.com/doctorow_podcast" // pol // infrequent)
(mkPod "https://congressionaldish.libsyn.com/rss" // pol // infrequent)
## Civboot
(mkPod "https://anchor.fm/s/34c7232c/podcast/rss" // tech // infrequent)
(mkPod "https://feeds.feedburner.com/80000HoursPodcast" // rat // weekly)
(mkPod "https://allinchamathjason.libsyn.com/rss" // pol // weekly)
(mkPod "https://acquired.libsyn.com/rss" // tech // infrequent)
(mkPod "https://rss.acast.com/deconstructed" // pol // infrequent)
## The Daily
(mkPod "https://feeds.simplecast.com/54nAGcIl" // pol // daily)
(mkPod "https://rss.acast.com/intercepted-with-jeremy-scahill" // pol // weekly)
(mkPod "https://podcast.posttv.com/itunes/post-reports.xml" // pol // weekly)
## Eric Weinstein
(mkPod "https://rss.art19.com/the-portal" // rat // infrequent)
(mkPod "https://feeds.megaphone.fm/darknetdiaries" // tech // infrequent)
(mkPod "http://feeds.wnyc.org/radiolab" // pol // infrequent)
(mkPod "https://wakingup.libsyn.com/rss" // pol // infrequent)
## 99% Invisible
(mkPod "https://feeds.simplecast.com/BqbsxVfO" // pol // infrequent)
(mkPod "https://rss.acast.com/ft-tech-tonic" // tech // infrequent)
(mkPod "https://feeds.feedburner.com/dancarlin/history?format=xml" // rat // infrequent)
## 60 minutes (NB: this features more than *just* audio?)
(mkPod "https://www.cbsnews.com/latest/rss/60-minutes" // pol // infrequent)
];
texts = [
# AGGREGATORS (> 1 post/day) # AGGREGATORS (> 1 post/day)
"https://www.lesswrong.com/feed.xml" = rat // hourly; (mkText "https://www.lesswrong.com/feed.xml" // rat // hourly)
"http://www.econlib.org/index.xml" = pol // hourly; (mkText "http://www.econlib.org/index.xml" // pol // hourly)
# AGGREGATORS (< 1 post/day) # AGGREGATORS (< 1 post/day)
"https://palladiummag.com/feed" = uncat // weekly; (mkText "https://palladiummag.com/feed" // uncat // weekly)
"https://profectusmag.com/feed" = uncat // weekly; (mkText "https://profectusmag.com/feed" // uncat // weekly)
"https://semiaccurate.com/feed" = tech // weekly; (mkText "https://semiaccurate.com/feed" // tech // weekly)
"https://linuxphoneapps.org/blog/atom.xml" = tech // infrequent; (mkText "https://linuxphoneapps.org/blog/atom.xml" // tech // infrequent)
"https://spectrum.ieee.org/rss" = tech // weekly; (mkText "https://spectrum.ieee.org/rss" // tech // weekly)
## No Moods, Ads or Cutesy Fucking Icons ## No Moods, Ads or Cutesy Fucking Icons
"https://www.rifters.com/crawl/?feed=rss2" = uncat // weekly; (mkText "https://www.rifters.com/crawl/?feed=rss2" // uncat // weekly)
# DEVELOPERS # DEVELOPERS
"https://mg.lol/blog/rss/" = infrequent // tech; (mkText "https://mg.lol/blog/rss/" // infrequent // tech)
## Ken Shirriff ## Ken Shirriff
"https://www.righto.com/feeds/posts/default" = tech // infrequent; (mkText "https://www.righto.com/feeds/posts/default" // tech // infrequent)
## Vitalik Buterin ## Vitalik Buterin
"https://vitalik.ca/feed.xml" = tech // infrequent; (mkText "https://vitalik.ca/feed.xml" // tech // infrequent)
## ian (Sanctuary) ## ian (Sanctuary)
"https://sagacioussuricata.com/feed.xml" = tech // infrequent; (mkText "https://sagacioussuricata.com/feed.xml" // tech // infrequent)
## Bunnie Juang ## Bunnie Juang
"https://www.bunniestudios.com/blog/?feed=rss2" = tech // infrequent; (mkText "https://www.bunniestudios.com/blog/?feed=rss2" // tech // infrequent)
"https://blog.danieljanus.pl/atom.xml" = tech // infrequent; (mkText "https://blog.danieljanus.pl/atom.xml" // tech // infrequent)
"https://ianthehenry.com/feed.xml" = tech // infrequent; (mkText "https://ianthehenry.com/feed.xml" // tech // infrequent)
"https://bitbashing.io/feed.xml" = tech // infrequent; (mkText "https://bitbashing.io/feed.xml" // tech // infrequent)
"https://idiomdrottning.org/feed.xml" = uncat // daily; (mkText "https://idiomdrottning.org/feed.xml" // uncat // daily)
# (TECH; POL) COMMENTATORS # (TECH; POL) COMMENTATORS
"http://benjaminrosshoffman.com/feed" = pol // weekly; (mkText "http://benjaminrosshoffman.com/feed" // pol // weekly)
## Ben Thompson ## Ben Thompson
"https://www.stratechery.com/rss" = pol // weekly; (mkText "https://www.stratechery.com/rss" // pol // weekly)
## Balaji ## Balaji
"https://balajis.com/rss" = pol // weekly; (mkText "https://balajis.com/rss" // pol // weekly)
"https://www.ben-evans.com/benedictevans/rss.xml" = pol // weekly; (mkText "https://www.ben-evans.com/benedictevans/rss.xml" // pol // weekly)
"https://www.lynalden.com/feed" = pol // infrequent; (mkText "https://www.lynalden.com/feed" // pol // infrequent)
"https://austinvernon.site/rss.xml" = tech // infrequent; (mkText "https://austinvernon.site/rss.xml" // tech // infrequent)
"https://oversharing.substack.com/feed" = pol // daily; (mkText "https://oversharing.substack.com/feed" // pol // daily)
"https://doomberg.substack.com/feed" = tech // weekly; (mkText "https://doomberg.substack.com/feed" // tech // weekly)
## David Rosenthal ## David Rosenthal
"https://blog.dshr.org/rss.xml" = pol // weekly; (mkText "https://blog.dshr.org/rss.xml" // pol // weekly)
## Matt Levine ## Matt Levine
"https://www.bloomberg.com/opinion/authors/ARbTQlRLRjE/matthew-s-levine.rss" = pol // weekly; (mkText "https://www.bloomberg.com/opinion/authors/ARbTQlRLRjE/matthew-s-levine.rss" // pol // weekly)
# RATIONALITY/PHILOSOPHY/ETC # RATIONALITY/PHILOSOPHY/ETC
"https://samkriss.substack.com/feed" = uncat // infrequent; # ... satire? phil? (mkText "https://samkriss.substack.com/feed" // humor // infrequent)
"https://unintendedconsequenc.es/feed" = rat // infrequent; (mkText "https://unintendedconsequenc.es/feed" // rat // infrequent)
"https://applieddivinitystudies.com/atom.xml" = rat // weekly; (mkText "https://applieddivinitystudies.com/atom.xml" // rat // weekly)
"https://slimemoldtimemold.com/feed.xml" = rat // weekly; (mkText "https://slimemoldtimemold.com/feed.xml" // rat // weekly)
"https://www.richardcarrier.info/feed" = rat // weekly; (mkText "https://www.richardcarrier.info/feed" // rat // weekly)
"https://www.gwern.net/feed.xml" = uncat // infrequent; (mkText "https://www.gwern.net/feed.xml" // uncat // infrequent)
## Jason Crawford ## Jason Crawford
"https://rootsofprogress.org/feed.xml" = rat // weekly; (mkText "https://rootsofprogress.org/feed.xml" // rat // weekly)
## Robin Hanson ## Robin Hanson
"https://www.overcomingbias.com/feed" = rat // daily; (mkText "https://www.overcomingbias.com/feed" // rat // daily)
## Scott Alexander ## Scott Alexander
"https://astralcodexten.substack.com/feed.xml" = rat // daily; (mkText "https://astralcodexten.substack.com/feed.xml" // rat // daily)
## Paul Christiano ## Paul Christiano
"https://sideways-view.com/feed" = rat // infrequent; (mkText "https://sideways-view.com/feed" // rat // infrequent)
## Sean Carroll ## Sean Carroll
"https://www.preposterousuniverse.com/rss" = rat // infrequent; (mkText "https://www.preposterousuniverse.com/rss" // rat // infrequent)
# COMICS
"https://www.smbc-comics.com/comic/rss" = visual // daily;
"https://xkcd.com/atom.xml" = visual // daily;
"http://dilbert.com/feed" = visual // daily;
# ART
"https://miniature-calendar.com/feed" = visual // daily;
# CODE # CODE
"https://github.com/Kaiteki-Fedi/Kaiteki/commits/master.atom" = tech // infrequent; (mkText "https://github.com/Kaiteki-Fedi/Kaiteki/commits/master.atom" // tech // infrequent)
}; ];
# return only the URLs which match this category images = [
filterCat = cat: builtins.filter (url: rss."${url}".cat == cat) (builtins.attrNames rss); (mkImg "https://www.smbc-comics.com/comic/rss" // humor // daily)
(mkImg "https://xkcd.com/atom.xml" // humor // daily)
(mkImg "http://dilbert.com/feed" // humor // daily)
# ART
(mkImg "https://miniature-calendar.com/feed" // art // daily)
];
all = texts ++ images ++ podcasts;
# return only the feed items which match this category (e.g. "tech")
filterCat = cat: feeds: builtins.filter (item: item.cat == cat) feeds;
# return only the feed items which match this format (e.g. "podcast")
filterFormat = format: feeds: builtins.filter (item: item.format == format) feeds;
# transform a list of feeds into an attrs mapping cat => [ feed0 feed1 ... ]
partitionByCat = feeds: builtins.groupBy (f: f.cat) feeds;
# represents a single RSS feed. # represents a single RSS feed.
opmlTerminal = url: ''<outline xmlUrl="${url}" type="rss"/>''; opmlTerminal = feed: ''<outline xmlUrl="${feed.url}" type="rss"/>'';
# a list of RSS feeds. # a list of RSS feeds.
opmlTerminals = urls: lib.strings.concatStringsSep "\n" (builtins.map opmlTerminal urls); opmlTerminals = feeds: lib.strings.concatStringsSep "\n" (builtins.map opmlTerminal feeds);
# one node which packages some flat grouping of terminals. # one node which packages some flat grouping of terminals.
opmlGroup = title: urls: '' opmlGroup = title: feeds: ''
<outline text="${title}" title="${title}"> <outline text="${title}" title="${title}">
${opmlTerminals urls} ${opmlTerminals feeds}
</outline> </outline>
''; '';
# a list of groups (`groupMap` is an attrs mapping groupName => [ feed0 feed1 ... ]).
opmlGroups = groupMap: lib.strings.concatStringsSep "\n" (
builtins.attrValues (builtins.mapAttrs opmlGroup groupMap)
);
# top-level OPML file which could be consumed by something else. # top-level OPML file which could be consumed by something else.
opmlToplevel = bodies: opmlTopLevel = body: ''
let
body = lib.strings.concatStringsSep "\n" bodies;
in ''
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<opml version="2.0"> <opml version="2.0">
<body>${body} <body>
${body}
</body> </body>
</opml> </opml>
''; '';
# **primary API**: generate a OPML file from the provided feeds
feedsToOpml = feeds: opmlTopLevel (opmlGroups (partitionByCat feeds));
} }

View File

@@ -206,7 +206,9 @@ in
xdg.configFile."vlc/vlcrc".text = xdg.configFile."vlc/vlcrc".text =
let let
podcastUrls = lib.strings.concatStringsSep "|" feeds.podcastUrls; podcastUrls = lib.strings.concatStringsSep "|" (
builtins.map (feed: feed.url) feeds.podcasts
);
in '' in ''
[podcast] [podcast]
podcast-urls=${podcastUrls} podcast-urls=${podcastUrls}
@@ -217,24 +219,22 @@ in
''; '';
xdg.configFile."gpodderFeeds.opml".text = with feeds; xdg.configFile."gpodderFeeds.opml".text = with feeds;
opmlToplevel [(opmlTerminals podcastUrls)]; feedsToOpml feeds.podcasts;
# news-flash RSS viewer # news-flash RSS viewer
xdg.configFile."newsflashFeeds.opml".text = with feeds; xdg.configFile."newsflashFeeds.opml".text = with feeds;
let feedsToOpml (feeds.texts ++ feeds.images);
opmlForCat = cat: opmlGroup cat (filterCat cat);
outlines = [
(opmlForCat "uncat")
(opmlForCat "rat")
(opmlForCat "tech")
(opmlForCat "pol")
(opmlForCat "visual")
];
in opmlToplevel outlines;
# gnome feeds RSS viewer # gnome feeds RSS viewer
xdg.configFile."org.gabmus.gfeeds.json".text = builtins.toJSON { xdg.configFile."org.gabmus.gfeeds.json".text =
feeds = builtins.mapAttrs (r: p: { tags = [ p.cat p.freq ]; }) feeds.rss; let
myFeeds = feeds.texts ++ feeds.images;
in builtins.toJSON {
# feed format is a map from URL to a dict,
# with dict["tags"] a list of string tags.
feeds = builtins.foldl' (acc: feed: acc // {
"${feed.url}".tags = [ feed.cat feed.freq ];
}) {} myFeeds;
dark_reader = false; dark_reader = false;
new_first = true; new_first = true;
# windowsize = { # windowsize = {
@@ -253,17 +253,9 @@ in
open_links_externally = true; open_links_externally = true;
full_feed_name = false; full_feed_name = false;
refresh_on_startup = true; refresh_on_startup = true;
tags = [ tags = lib.lists.unique (
# hourly => aggregator (builtins.catAttrs "cat" myFeeds) ++ (builtins.catAttrs "freq" myFeeds)
# daily => prolifiq writer );
# weekly => i can keep up with most -- but maybe not all -- of their content
# infrequent => i can read everything in this category
"hourly" "daily" "weekly" "infrequent"
# rat[ionality] gets used interchangably with philosophy, here.
# pol[itical] gets used for social commentary and economics as well.
# visual gets used for comics/art
"uncat" "rat" "tech" "pol" "visual"
];
open_youtube_externally = false; open_youtube_externally = false;
media_player = "vlc"; # default: mpv media_player = "vlc"; # default: mpv
}; };