feeds: write the basis for a module which reads feed metadata from disk and can (in the future) update it

This commit is contained in:
colin 2023-01-10 03:52:33 +00:00
parent 33967554a5
commit cdc881e887
5 changed files with 63 additions and 1 deletions

View File

@ -4,6 +4,9 @@
# don't put things like fully-specific ~/.config files in here,
# even if they're "relatively unopinionated".
moduleArgs:
{
feeds = import ./feeds moduleArgs;
keys = import ./keys.nix;
}

View File

@ -0,0 +1,58 @@
{ lib, ... }:
let
inherit (builtins) concatLists concatStringsSep foldl' fromJSON map readDir readFile;
inherit (lib) init mapAttrsToList removePrefix removeSuffix splitString;
inherit (lib.attrsets) recursiveUpdate setAttrByPath;
inherit (lib.filesystem) listFilesRecursive;
# given a path to a .json file relative to sources, construct the best feed object we can.
# the .json file could be empty, in which case we make assumptions about the feed based
# on its fs path.
# Type: feedFromSourcePath :: String -> { path = [String]; value = feed; }
feedFromSourcePath = json-path:
let
canonical-name = removeSuffix "/default" (lib.removeSuffix ".json" json-path);
default-url = "https://${canonical-name}";
attr-path = splitString "/" canonical-name;
feed-details = { url = default-url; } // (tryImportJson (./sources/${json-path}));
in { path = attr-path; value = mkFeed feed-details; };
# TODO: for now, feeds are just ordinary Attrs.
# in the future, we'd like to set them up with an update script.
mkFeed = { url, ... }@details: details;
# return an AttrSet representing the json at the provided path,
# or {} if the path is empty.
tryImportJson = path:
let
as-str = readFile path;
in
if as-str == "" then
{}
else
fromJSON as-str;
sources = enumerateFilePaths ./sources;
# like `lib.listFilesRecursive` but does not mangle paths.
# Type: enumerateFilePaths :: path -> [String]
enumerateFilePaths = base:
concatLists (
mapAttrsToList
(name: type:
if type == "directory" then
# enumerate this directory and then prefix each result with the directory's name
map (e: "${name}/${e}") (enumerateFilePaths (base + "/${name}"))
else
[ name ]
)
(readDir base)
);
# like listToAttrs, except takes { path, value } pairs instead of { name, value } pairs.
# Type: listToAttrsByPath :: [{ path = [String]; value = Any; }] -> Attrs
listToAttrsByPath = items:
foldl' (acc: { path, value }: recursiveUpdate acc (setAttrByPath path value)) {} items;
in
listToAttrsByPath (map feedFromSourcePath sources)

View File

@ -18,6 +18,6 @@
_module.args = {
sane-lib = import ./lib { inherit lib utils; };
sane-data = import ./data;
sane-data = import ./data { inherit lib; };
};
}

View File

@ -14,6 +14,7 @@ let
};
format = mkOption {
type = types.enum [ "text" "image" "podcast" ];
default = "text";
};
url = mkOption {
type = types.str;