diff options
author | Gregor Kleen <gkleen@yggdrasil.li> | 2025-05-14 10:50:27 +0200 |
---|---|---|
committer | Gregor Kleen <gkleen@yggdrasil.li> | 2025-05-14 10:50:27 +0200 |
commit | 43c9825e49d25fbd2c19abcdeb8f73aee8be2a4c (patch) | |
tree | c1cc8a034395c9bb8188651f6835922b38887f32 /user-profiles/feeds | |
parent | 03d49aa8ec6f51c8f51bfb628e614ac537cca8e0 (diff) | |
download | nixos-43c9825e49d25fbd2c19abcdeb8f73aee8be2a4c.tar nixos-43c9825e49d25fbd2c19abcdeb8f73aee8be2a4c.tar.gz nixos-43c9825e49d25fbd2c19abcdeb8f73aee8be2a4c.tar.bz2 nixos-43c9825e49d25fbd2c19abcdeb8f73aee8be2a4c.tar.xz nixos-43c9825e49d25fbd2c19abcdeb8f73aee8be2a4c.zip |
...
Diffstat (limited to 'user-profiles/feeds')
-rw-r--r-- | user-profiles/feeds/alot.config | 50 | ||||
-rw-r--r-- | user-profiles/feeds/default.nix | 11 | ||||
-rw-r--r-- | user-profiles/feeds/imm-notmuch-insert.py | 52 | ||||
-rw-r--r-- | user-profiles/feeds/module.nix | 236 |
4 files changed, 0 insertions, 349 deletions
diff --git a/user-profiles/feeds/alot.config b/user-profiles/feeds/alot.config deleted file mode 100644 index a14d4539..00000000 --- a/user-profiles/feeds/alot.config +++ /dev/null | |||
@@ -1,50 +0,0 @@ | |||
1 | attachment_prefix="~/Downloads" | ||
2 | bug_on_exit=true | ||
3 | editor_cmd="false" | ||
4 | tabwidth=2 | ||
5 | timestamp_format="%a %d %b %H:%M:%S %Y UTC%z" | ||
6 | auto_remove_unread=True | ||
7 | #initial_command="search ( tag:inbox ) AND NOT ( tag:killed )" | ||
8 | initial_command="search ( tag:inbox ) AND NOT ( is:link OR is:media OR is:killed )" | ||
9 | |||
10 | [accounts] | ||
11 | [[private]] | ||
12 | realname = @realname@ | ||
13 | address = @address@ | ||
14 | |||
15 | [bindings] | ||
16 | j = | ||
17 | k = | ||
18 | 'g g' = | ||
19 | G = | ||
20 | I = search ( tag:inbox ) AND NOT ( is:killed ) | ||
21 | U = search ( tag:inbox ) AND NOT ( is:link OR is:media OR is:killed ) | ||
22 | V = search ( tag:inbox AND is:media OR ( is:live AND date:12h.. AND NOT is:unread ) ) AND NOT ( is:killed ) | ||
23 | W = search ( is:media ) AND NOT ( tag:inbox OR is:killed OR is:highlight ) | ||
24 | L = search ( tag:inbox AND is:link ) AND NOT ( is:killed ) | ||
25 | |||
26 | h = move first | ||
27 | t = move up | ||
28 | n = move down | ||
29 | s = move last | ||
30 | [[search]] | ||
31 | a = | ||
32 | s = | ||
33 | |||
34 | u = toggletags unread | ||
35 | i = toggletags inbox | ||
36 | j = untag unread,inbox | ||
37 | r = toggletags later | ||
38 | [[thread]] | ||
39 | s = | ||
40 | S = | ||
41 | n = | ||
42 | 'g j' = | ||
43 | 'g k' = | ||
44 | 'g l' = | ||
45 | w = save | ||
46 | W = save --all | ||
47 | 'g h' = move parent | ||
48 | 'g t' = move next sibling | ||
49 | 'g n' = move previous sibling | ||
50 | 'g s' = move first reply \ No newline at end of file | ||
diff --git a/user-profiles/feeds/default.nix b/user-profiles/feeds/default.nix deleted file mode 100644 index 82be90c7..00000000 --- a/user-profiles/feeds/default.nix +++ /dev/null | |||
@@ -1,11 +0,0 @@ | |||
1 | { config, flakeInputs, pkgs, lib, userName, customUtils, ... }: | ||
2 | { | ||
3 | home-manager.users.${userName} = {...}: { | ||
4 | imports = [ | ||
5 | (customUtils.overrideModuleArgs | ||
6 | (import ./module.nix) | ||
7 | (inputs: inputs // { inherit flakeInputs; inherit (config.nixpkgs) system; }) | ||
8 | ) | ||
9 | ]; | ||
10 | }; | ||
11 | } | ||
diff --git a/user-profiles/feeds/imm-notmuch-insert.py b/user-profiles/feeds/imm-notmuch-insert.py deleted file mode 100644 index b7eed292..00000000 --- a/user-profiles/feeds/imm-notmuch-insert.py +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | #!@python@/bin/python | ||
2 | |||
3 | import json | ||
4 | import sys | ||
5 | import subprocess | ||
6 | from io import BytesIO | ||
7 | from email.message import EmailMessage | ||
8 | import configparser | ||
9 | from os import environ | ||
10 | from datetime import * | ||
11 | from dateutil.tz import * | ||
12 | from dateutil.parser import isoparse | ||
13 | from html2text import html2text | ||
14 | |||
15 | def main(): | ||
16 | notmuchConfig = configparser.ConfigParser() | ||
17 | notmuchConfig.read(environ.get('NOTMUCH_CONFIG')) | ||
18 | |||
19 | callbackMessage = json.load(sys.stdin) | ||
20 | |||
21 | msg = EmailMessage() | ||
22 | authors = ', '.join(map(lambda author: author['name'], callbackMessage['feed_item']['authors'])) | ||
23 | if authors: | ||
24 | msg['From'] = f"{callbackMessage['feed_definition']['title']} ({authors}) <imm@imm.invalid>" | ||
25 | else: | ||
26 | msg['From'] = f"{callbackMessage['feed_definition']['title']} <imm@imm.invalid>" | ||
27 | msg['To'] = f"{notmuchConfig['user']['name']} <{notmuchConfig['user']['primary_email']}>" | ||
28 | if 'title' in callbackMessage['feed_item'] and callbackMessage['feed_item']['title']: | ||
29 | msg['Subject'] = callbackMessage['feed_item']['title'] | ||
30 | msg['Item-Identifier'] = f"{callbackMessage['feed_item']['identifier']}" | ||
31 | for link in callbackMessage['feed_item']['links']: | ||
32 | msg.add_header('Link', link['uri']) | ||
33 | date = None | ||
34 | if 'date' in callbackMessage['feed_item']: | ||
35 | date = isoparse(callbackMessage['feed_item']['date']) | ||
36 | else: | ||
37 | date = datetime.now(tzlocal()) | ||
38 | msg['Date'] = date.strftime('%a, %e %b %Y %T %z') | ||
39 | |||
40 | if 'content' in callbackMessage['feed_item'] and callbackMessage['feed_item']['content']: | ||
41 | msg.set_content(html2text(callbackMessage['feed_item']['content'])) | ||
42 | msg.add_alternative(callbackMessage['feed_item']['content'], subtype='html') | ||
43 | |||
44 | |||
45 | subprocess.run( | ||
46 | args=['notmuch', 'insert'], | ||
47 | check=True, | ||
48 | input=bytes(msg) | ||
49 | ) | ||
50 | |||
51 | if __name__ == '__main__': | ||
52 | sys.exit(main()) | ||
diff --git a/user-profiles/feeds/module.nix b/user-profiles/feeds/module.nix deleted file mode 100644 index 63e827eb..00000000 --- a/user-profiles/feeds/module.nix +++ /dev/null | |||
@@ -1,236 +0,0 @@ | |||
1 | { config, flakeInputs, pkgs, lib, system, ... }: | ||
2 | |||
3 | with lib; | ||
4 | |||
5 | let | ||
6 | inherit (flakeInputs.home-manager.lib) hm; | ||
7 | |||
8 | databasePath = "${config.xdg.dataHome}/feeds"; | ||
9 | |||
10 | imm = | ||
11 | let | ||
12 | hlib = pkgs.haskell.lib; | ||
13 | haskellPackages = pkgs.haskellPackages.override { | ||
14 | overrides = finalHaskell: prevHaskell: { | ||
15 | uri-bytestring = finalHaskell.callCabal2nix "uri-bytestring" (pkgs.fetchFromGitHub { | ||
16 | owner = "gkleen"; | ||
17 | repo = "uri-bytestring"; | ||
18 | rev = "5f7f32c8274bc4d1b81d99582f5148fe3e8b637e"; | ||
19 | sha256 = "XLanwyCDIlMuOkpE5LbTNOBfL+1kZX+URfj9Bhs1Nsc="; | ||
20 | fetchSubmodules = true; | ||
21 | }) {}; | ||
22 | atom-conduit = finalHaskell.callCabal2nix "atom-conduit" (pkgs.fetchFromGitHub { | ||
23 | owner = "gkleen"; | ||
24 | repo = "atom-conduit"; | ||
25 | rev = "022f0182a02373f87c06a0a09817c8c41efe2425"; | ||
26 | sha256 = "8yEyh3ymqkoM/YP+eBqPq1I5ofzj0Qn7ojL7IWx1DPo="; | ||
27 | fetchSubmodules = true; | ||
28 | }) {}; | ||
29 | rss-conduit = finalHaskell.callCabal2nix "rss-condit" (pkgs.fetchFromGitHub { | ||
30 | owner = "gkleen"; | ||
31 | repo = "rss-conduit"; | ||
32 | rev = "dbb0960a8d3dc519f1607aa0223b3a25a49282ef"; | ||
33 | sha256 = "Md1XApZWkdv4JvNoaVnjz0S85LbEC6w9U3PUcwXfu94="; | ||
34 | fetchSubmodules = true; | ||
35 | }) {}; | ||
36 | beam-core = hlib.doJailbreak (finalHaskell.callCabal2nix "beam-core" "${beamSrc}/beam-core" {}); | ||
37 | beam-migrate = hlib.doJailbreak (finalHaskell.callCabal2nix "beam-migrate" "${beamSrc}/beam-migrate" {}); | ||
38 | beam-sqlite = hlib.doJailbreak (finalHaskell.callCabal2nix "beam-sqlite" "${beamSrc}/beam-sqlite" {}); | ||
39 | |||
40 | imm = finalHaskell.callCabal2nix "imm" (pkgs.fetchFromGitHub { | ||
41 | owner = "k0ral"; | ||
42 | repo = "imm"; | ||
43 | rev = "5033879667264cb44cee65671a66f6aa43f249e7"; | ||
44 | sha256 = "PG22caLQmAGhLZP49HsazuNd8IFKKaTuhXIQBD8v4Fs="; | ||
45 | fetchSubmodules = true; | ||
46 | }) {}; | ||
47 | }; | ||
48 | }; | ||
49 | beamSrc = pkgs.fetchFromGitHub { | ||
50 | owner = "haskell-beam"; | ||
51 | repo = "beam"; | ||
52 | rev = "efd464b079755a781c2bb7a2fc030d6c141bbb8a"; | ||
53 | sha256 = "8nTuBP/vD0L/qMo4h3XNrGZvpIwXuMVdj40j5gvHU6w="; | ||
54 | fetchSubmodules = true; | ||
55 | }; | ||
56 | in haskellPackages.imm; | ||
57 | immWrapped = pkgs.runCommand "${imm.name}-wrapped-${config.home.username}" | ||
58 | { nativeBuildInputs = with pkgs; [ makeWrapper ]; | ||
59 | } '' | ||
60 | mkdir -p $out/bin | ||
61 | makeWrapper ${imm}/bin/imm $out/bin/imm \ | ||
62 | --add-flags --callbacks=${notmuchCallbacks} | ||
63 | ''; | ||
64 | |||
65 | notmuchCallbacks = pkgs.writeText "imm-callbacks-${config.home.username}.dhall" '' | ||
66 | [ { _executable = "${immNotmuchInsert}/bin/imm-notmuch-insert" | ||
67 | , _arguments = [] : List Text | ||
68 | } | ||
69 | ] | ||
70 | ''; | ||
71 | |||
72 | immNotmuchInsert = pkgs.stdenv.mkDerivation rec { | ||
73 | name = "imm-notmuch-insert-${config.home.username}"; | ||
74 | src = ./imm-notmuch-insert.py; | ||
75 | |||
76 | phases = [ "buildPhase" "checkPhase" "installPhase" "fixupPhase" ]; | ||
77 | |||
78 | python = pkgs.python39.withPackages (ps: with ps; [ configparser python-dateutil html2text ]); | ||
79 | |||
80 | nativeBuildInputs = with pkgs; [ makeWrapper ]; | ||
81 | |||
82 | buildPhase = '' | ||
83 | substituteAll $src imm-notmuch-insert | ||
84 | ''; | ||
85 | |||
86 | doCheck = true; | ||
87 | checkPhase = '' | ||
88 | ${python}/bin/python -m py_compile imm-notmuch-insert | ||
89 | ''; | ||
90 | |||
91 | installPhase = '' | ||
92 | install -m 0755 -D -t $out/bin \ | ||
93 | imm-notmuch-insert | ||
94 | ''; | ||
95 | |||
96 | fixupPhase = '' | ||
97 | wrapProgram $out/bin/imm-notmuch-insert \ | ||
98 | --prefix PATH : ${pkgs.notmuch}/bin \ | ||
99 | --set NOTMUCH_CONFIG ${configPath} | ||
100 | ''; | ||
101 | }; | ||
102 | |||
103 | mkIniKeyValue = key: value: | ||
104 | let | ||
105 | tweakVal = v: | ||
106 | if isString v then | ||
107 | v | ||
108 | else if isList v then | ||
109 | concatMapStringsSep ";" tweakVal v | ||
110 | else if isBool v then | ||
111 | (if v then "true" else "false") | ||
112 | else | ||
113 | toString v; | ||
114 | in "${key}=${tweakVal value}"; | ||
115 | |||
116 | notmuchIni = { | ||
117 | database = { path = databasePath; }; | ||
118 | |||
119 | maildir = { synchronize_flags = false; }; | ||
120 | |||
121 | new = { | ||
122 | ignore = []; | ||
123 | tags = ["new"]; | ||
124 | }; | ||
125 | |||
126 | user = { | ||
127 | name = config.home.username; | ||
128 | primary_email = "${config.home.username}@imm.invalid"; | ||
129 | }; | ||
130 | |||
131 | search = { exclude_tags = ["deleted"]; }; | ||
132 | }; | ||
133 | configPath = pkgs.writeText "notmuchrc" (generators.toINI { mkKeyValue = mkIniKeyValue; } notmuchIni); | ||
134 | |||
135 | afewConfigDir = pkgs.symlinkJoin { | ||
136 | name = "afew-config"; | ||
137 | paths = [ | ||
138 | (pkgs.writeTextDir "config" '' | ||
139 | [InboxFilter] | ||
140 | '') | ||
141 | ]; | ||
142 | }; | ||
143 | |||
144 | notmuchHooksDir = | ||
145 | let | ||
146 | afewHook = pkgs.writeShellScript "afew" '' | ||
147 | exec -- ${pkgs.afew}/bin/afew -c ${afewConfigDir} -C ${configPath} --tag --new -vv | ||
148 | ''; | ||
149 | in pkgs.linkFarm "notmuch-hooks" [ | ||
150 | { name = "post-new"; | ||
151 | path = afewHook; | ||
152 | } | ||
153 | { name = "post-insert"; | ||
154 | path = afewHook; | ||
155 | } | ||
156 | ]; | ||
157 | |||
158 | notmuchWrapped = pkgs.runCommand "${pkgs.notmuch.name}-wrapped-${config.home.username}" | ||
159 | { nativeBuildInputs = with pkgs; [ makeWrapper ]; | ||
160 | } '' | ||
161 | mkdir -p $out/bin | ||
162 | makeWrapper ${pkgs.notmuch}/bin/notmuch $out/bin/notmuch-feeds \ | ||
163 | --set NOTMUCH_CONFIG ${configPath} | ||
164 | ''; | ||
165 | alotWrapped = pkgs.runCommand "${pkgs.alot.name}-wrapped-${config.home.username}" | ||
166 | { nativeBuildInputs = with pkgs; [ makeWrapper gnused ]; | ||
167 | } '' | ||
168 | mkdir -p $out/bin | ||
169 | makeWrapper ${pkgs.alot}/bin/alot $out/bin/alot-feeds \ | ||
170 | --prefix MAILCAPS : ${alotMailcaps} \ | ||
171 | --add-flags --config=${alotConfig} \ | ||
172 | --add-flags --notmuch-config=${configPath} | ||
173 | |||
174 | mkdir $out/share | ||
175 | ln -s ${pkgs.alot}/share/alot $out/share | ||
176 | mkdir -p $out/share/applications | ||
177 | sed -r 's/alot/alot-feeds/g' ${pkgs.alot}/share/applications/alot.desktop > $out/share/applications/alot-feeds.desktop | ||
178 | mkdir -p $out/share/zsh/site-functions | ||
179 | sed -r 's/alot/alot-feeds/g' ${pkgs.alot}/share/zsh/site-functions/_alot > $out/share/zsh/site-functions/_alot-feeds | ||
180 | ''; | ||
181 | |||
182 | alotConfig = pkgs.runCommand "alot" { | ||
183 | realname = notmuchIni.user.name; | ||
184 | address = notmuchIni.user.primary_email; | ||
185 | } "substituteAll ${./alot.config} $out"; | ||
186 | alotMailcaps = pkgs.writeText "mailcaps" '' | ||
187 | text/html; ${pkgs.lynx}/bin/lynx -dump -dont_wrap_pre -assume_charset=utf-8 -display_charset=utf-8 "%s"; nametemplate=%s.html; copiousoutput | ||
188 | ''; | ||
189 | in { | ||
190 | config = { | ||
191 | home.packages = [ immWrapped notmuchWrapped pkgs.notmuch.man alotWrapped ]; | ||
192 | |||
193 | home.activation.createImm = hm.dag.entryAfter ["writeBoundary"] '' | ||
194 | $DRY_RUN_CMD mkdir -p $VERBOSE_ARG ${config.xdg.configHome}/imm | ||
195 | ''; | ||
196 | |||
197 | home.activation.createFeedsDatabase = hm.dag.entryAfter ["linkGeneration" "writeBoundary"] '' | ||
198 | $DRY_RUN_CMD mkdir -p -m 0750 $VERBOSE_ARG ${databasePath} | ||
199 | $DRY_RUN_CMD mkdir -p $VERBOSE_ARG ${databasePath}/new ${databasePath}/cur ${databasePath}/tmp | ||
200 | if ! [[ -d ${databasePath}/.notmuch ]]; then | ||
201 | NOTMUCH_VERBOSE_ARG="--quiet" | ||
202 | if [[ -v VERBOSE ]]; then | ||
203 | NOTMUCH_VERBOSE_ARG="--verbose" | ||
204 | fi | ||
205 | NOTMUCH_CONFIG=${configPath} $DRY_RUN_CMD ${pkgs.notmuch}/bin/notmuch new $NOTMUCH_VERBOSE_ARG | ||
206 | fi | ||
207 | $DRY_RUN_CMD ln -Tsf $VERBOSE_ARG ${notmuchHooksDir} ${databasePath}/.notmuch/hooks | ||
208 | ''; | ||
209 | |||
210 | systemd.user.services."logrotate-imm" = { | ||
211 | Unit = { | ||
212 | Description = "Rotate imm logfile"; | ||
213 | }; | ||
214 | Service = { | ||
215 | Type = "oneshot"; | ||
216 | ExecStart = '' | ||
217 | ${pkgs.logrotate}/bin/logrotate --state ${config.xdg.configHome}/imm/imm.logrotate ${pkgs.writeText "logrotate.conf" '' | ||
218 | ${config.xdg.configHome}/imm/imm.log { | ||
219 | rotate 5 | ||
220 | size 1024k | ||
221 | } | ||
222 | ''} | ||
223 | ''; | ||
224 | }; | ||
225 | }; | ||
226 | systemd.user.timers."logrotate-imm" = { | ||
227 | Timer = { | ||
228 | OnActiveSec = "6h"; | ||
229 | OnUnitActiveSec = "6h"; | ||
230 | }; | ||
231 | Install = { | ||
232 | WantedBy = ["default.target"]; | ||
233 | }; | ||
234 | }; | ||
235 | }; | ||
236 | } | ||