Compare commits

...

452 Commits

Author SHA1 Message Date
c45898f903 WIP: wg-dev 2024-01-15 04:15:17 +00:00
0efec20904 hosts/common/net/vpn: remove unused "extraOptions" argument 2024-01-15 03:52:31 +00:00
2f04b563d1 nixpkgs: 2024-01-11 -> 2024-01-14
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/06797d4df4baaa51b229081083a88b92dac3ff7c' (2024-01-11)
  → 'github:nixos/nixpkgs/724e39ebb9b8eda97f17d423f66fbc5a991f4f8d' (2024-01-14)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/51f399ec47c082d678261883095bb8ad552e6500' (2024-01-11)
  → 'github:nixos/nixpkgs/6c08fe3ccf437d8b26bec010fd925ddd6bb0d0d5' (2024-01-14)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/c0b3a5af90fae3ba95645bbf85d2b64880addd76' (2024-01-10)
  → 'github:Mic92/sops-nix/70dd0d521f7849338e487a219c1a07c429a66d77' (2024-01-14)
• Updated input 'sops-nix/nixpkgs-stable':
    'github:NixOS/nixpkgs/70bdadeb94ffc8806c0570eb5c2695ad29f0e421' (2024-01-03)
  → 'github:NixOS/nixpkgs/a1982c92d8980a0114372973cbdfe0a307f1bdea' (2024-01-12)
```
2024-01-15 01:32:07 +00:00
5b9c58dbc6 hosts/common: use servo-style dns on all machines
it'll be handy as i want to place individual applications inside VPNs/namespaces
2024-01-15 01:16:22 +00:00
a7964c4f0c hosts/common: net: split upnp config into own file 2024-01-15 01:12:09 +00:00
006a7e9f72 consolidate net-related stuff into hosts/common/net/ directory 2024-01-15 01:11:13 +00:00
3856710faf net: annotate the UPNP rule 2024-01-15 01:08:10 +00:00
6cbc0bedf3 ddns-he (HurricaneElectric): remove
it's unused for a year
2024-01-15 00:55:10 +00:00
fbc0c7615a ddns-afraid (afraid.org): remove
it's unused for a year
2024-01-15 00:54:41 +00:00
34bcdb5128 firefox: disable kinetic scrolling 2024-01-14 20:34:14 +00:00
a5c6e41622 feeds: subscribe to POD OF JAKE 2024-01-14 05:20:28 +00:00
02e03227d8 servo: try to integrate peerswap with clightning, but it fails 2024-01-14 04:33:12 +00:00
faa0a7c9ea peerswap: init at unstable-20240111 2024-01-14 02:55:32 +00:00
812a02bc6b feeds: add The Dollop podcast 2024-01-14 00:49:29 +00:00
27898ecdc8 feeds: unsubscribe from Louis Rossman
his channel is kinda just the same idea  played over and over
2024-01-14 00:36:52 +00:00
1c2324cca4 servo: clightning-sane: status command: show profits from fees 2024-01-13 16:43:49 +00:00
70f059eaac feeds: subscribe to Jack Stauber 2024-01-13 16:43:41 +00:00
bac72be730 servo: clightning-sane: status command: show in/out payment sums 2024-01-13 15:53:48 +00:00
99858c1384 servo: clightning-sane: centralize metric reporting, fix so we blacklist our own channels less frequently 2024-01-13 04:47:20 +00:00
103a300e77 servo: clightning-sane: implement an autobalance subcommand 2024-01-13 03:04:24 +00:00
6b5cdd7508 servo: clightning-sane: log before we give up 2024-01-13 01:10:52 +00:00
2f1e354400 servo: clightning-sane: drop caches after so many failures 2024-01-12 23:54:06 +00:00
585a87130c servo: clightning-sane: remove unused loop_once_with_retries method 2024-01-12 23:31:30 +00:00
0e68533776 servo: clightning-sane: introduce parallelism 2024-01-12 23:30:52 +00:00
882cc5bfd0 servo: clightning-sane: rename Balancer -> LoopRouter 2024-01-12 21:36:20 +00:00
91847a9a8e servo: clightning-sane: factor "loop" action into own subroutine 2024-01-12 21:28:20 +00:00
5c649ff216 servo: clightning-sane: include peer_id in status --full 2024-01-12 20:56:00 +00:00
abdd224211 servo: clightning-sane: increase CLTV 9->18 2024-01-12 20:55:32 +00:00
0c72c59190 servo: clightning-sane: handle closed channels in status listing 2024-01-12 20:28:57 +00:00
432170a69e servo: clightning-sane: rename ppm in/out to theirs/mine 2024-01-12 19:31:39 +00:00
805b37a9a5 servo: clightning-sane: add a --full option for more info 2024-01-12 19:24:50 +00:00
87a0bda011 servo: clightning-sane: perform rebalance operation in a loop 2024-01-12 19:17:07 +00:00
5d2c6e1978 servo: clightning-sane: mark channels which cant be rebalanced freely 2024-01-12 18:43:58 +00:00
abafbd811b servo: clightning-sane: minor bugfixes 2024-01-12 18:30:49 +00:00
aca50d9946 servo: clightning-sane: add a "status" subcommand 2024-01-12 17:42:44 +00:00
bd4f4dab81 servo: clightning-sane: factor out a subcommands interface 2024-01-12 15:42:12 +00:00
aebd11ea82 alacritty: port config: yaml to toml 2024-01-12 03:24:55 +00:00
fa6906fdf9 cross: fix appstream/eyed3 failures from nixpkgs update 2024-01-12 03:24:55 +00:00
cec21375a5 servo: disable mautrix-signal 2024-01-12 03:24:55 +00:00
0428f64afa nixpkgs: 2024-01-10 -> 2024-01-11
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/2f9e98ccf3283a34ce9301c7ee4ca18d219d829d' (2024-01-10)
  → 'github:nixos/nixpkgs/06797d4df4baaa51b229081083a88b92dac3ff7c' (2024-01-11)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/32afa5e024e45885dacadf1c8ad65e9ebc51a901' (2024-01-10)
  → 'github:nixos/nixpkgs/51f399ec47c082d678261883095bb8ad552e6500' (2024-01-11)
```
2024-01-12 03:24:55 +00:00
e0864edefc nixpkgs: 2024-01-10 -> 2024-01-10
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/0231e3ccf485b7b110f0e0e55be6a711cb0093fb' (2024-01-10)
  → 'github:nixos/nixpkgs/2f9e98ccf3283a34ce9301c7ee4ca18d219d829d' (2024-01-10)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/a962df01db9bff000df83733bf6d7ef60a855057' (2024-01-10)
  → 'github:nixos/nixpkgs/32afa5e024e45885dacadf1c8ad65e9ebc51a901' (2024-01-10)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/0ded57412079011f1210c2fcc10e112427d4c0e6' (2024-01-08)
  → 'github:Mic92/sops-nix/c0b3a5af90fae3ba95645bbf85d2b64880addd76' (2024-01-10)
```
2024-01-12 03:24:55 +00:00
7460fd283c nixpkgs: 2024-01-09 -> 2024-01-10
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/fcff3d7883a38ef71832899085ba365658c96867' (2024-01-09)
  → 'github:nixos/nixpkgs/0231e3ccf485b7b110f0e0e55be6a711cb0093fb' (2024-01-10)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/519c93eda20a7c361e6159d853bf33b1e6236141' (2024-01-09)
  → 'github:nixos/nixpkgs/a962df01db9bff000df83733bf6d7ef60a855057' (2024-01-10)
```
2024-01-12 03:24:55 +00:00
7a7dee1630 nixpkgs: 2023-12-29 -> 2024-01-09; sops-nix; uninsane-dot-org
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/f50aae4fb10dd51bd6ffcce0eb96d02b608a9595' (2023-12-29)
  → 'github:nixos/nixpkgs/fcff3d7883a38ef71832899085ba365658c96867' (2024-01-09)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/04df6aa7bad237aeeb69f603e1f4ec1a2c28a4da' (2023-12-29)
  → 'github:nixos/nixpkgs/519c93eda20a7c361e6159d853bf33b1e6236141' (2024-01-09)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/e523e89763ff45f0a6cf15bcb1092636b1da9ed3' (2023-12-24)
  → 'github:Mic92/sops-nix/0ded57412079011f1210c2fcc10e112427d4c0e6' (2024-01-08)
• Updated input 'sops-nix/nixpkgs-stable':
    'github:NixOS/nixpkgs/7790e078f8979a9fcd543f9a47427eeaba38f268' (2023-12-23)
  → 'github:NixOS/nixpkgs/70bdadeb94ffc8806c0570eb5c2695ad29f0e421' (2024-01-03)
• Updated input 'uninsane-dot-org':
    'git+https://git.uninsane.org/colin/uninsane?ref=refs/heads/master&rev=b21e6899490f25fa450fb9e3efa0c8774bcee0d3' (2023-12-31)
  → 'git+https://git.uninsane.org/colin/uninsane?ref=refs/heads/master&rev=4a1fa488e64e6c87c6c951e3fafb2684692f64d3' (2024-01-01)
```
2024-01-12 03:24:55 +00:00
913403aac6 servo: clightning-sane: tidy 2024-01-12 01:25:56 +00:00
432a66bf5f servo: clightning: initialize a script for rebalancing with peers 2024-01-11 23:11:33 +00:00
e2a43ddfa0 servo: clightning: allow group members to run lightning-cli 2024-01-11 15:59:32 +00:00
b2ba204ca1 nixpatches: update hashes (?) 2024-01-11 15:58:44 +00:00
892b045342 pyln-client: init at 23.11.2 2024-01-11 00:38:08 +00:00
8644e6705a servo: decrease ZFS cache size 2024-01-11 00:20:52 +00:00
3f60206eef servo: clightning: tune config 2024-01-10 23:40:17 +00:00
568ead4bd7 servo: lightning: tune config 2024-01-10 21:01:36 +00:00
14241d54c9 flake: fix packages output to eval (even though its dumb and i just use hostPkgs.<machine>.<xyz>) 2024-01-10 11:48:20 +00:00
e4d75c5f38 servo: clightning: disable features which are incompatible with lnd 2024-01-10 11:18:54 +00:00
c42dda1bab servo: clightning: document more parts of the config 2024-01-09 16:19:48 +00:00
3295ae3b74 servo: clightning: update config 2024-01-09 16:13:08 +00:00
e63438bedf feeds: disable The Linux Experience 2024-01-09 00:45:18 +00:00
25422da9ba servo: tune clightning config 2024-01-09 00:42:37 +00:00
37583d8c9c clightning: tune fees, logging 2024-01-06 18:08:51 +00:00
62b3863722 servo: clightning: enable experimental features 2024-01-06 09:13:17 +00:00
b11f03bd18 servo: clightning: docs 2024-01-05 22:09:32 +00:00
63620fa058 servo: clightning: node personalization and docs 2024-01-04 21:55:13 +00:00
cecb114810 clightning: harden 2024-01-04 18:47:40 +00:00
4ce93f74c6 wob: add debug logging 2024-01-04 17:07:47 +00:00
09b806d7a7 go2tv: document youtube workarounds 2024-01-04 16:26:25 +00:00
2f31100c3f servo: ship go2tv 2024-01-04 16:25:50 +00:00
ca3f97ec51 docs: go2tv: elaborate seeking limitations 2024-01-04 16:25:49 +00:00
7378d6c5b2 bitcoind: host behind tor 2024-01-04 16:25:49 +00:00
276de5d662 tor: fix /var/lib/tor directory permissions 2024-01-04 16:25:49 +00:00
6f449cf35f clightning: document some places to find nodes for channels 2024-01-04 16:25:49 +00:00
daf046861c wob: implement as part of sway instead of exclusive to sxmo 2024-01-04 13:08:20 +00:00
43498c62f9 clightning: integrate with tor 2024-01-03 18:29:16 +00:00
22f5853741 firefox: remove unused functions 2024-01-03 14:59:59 +00:00
fe217f6667 firefox: disable ctrl+shift+c shortcut more broadly 2024-01-03 14:59:27 +00:00
41ae86f40f servo: enable clightning 2024-01-03 13:56:42 +00:00
6d52c8ecf8 servo: split tor/i2p into own files 2024-01-03 13:56:14 +00:00
75b649543a firefox: enable ctrl-shift-c-should-copy extension 2024-01-03 13:42:58 +00:00
1261a6f452 firefox-extensions.ctrl-shift-c-should-copy: init at unstable-2023-03-04 2024-01-03 13:33:32 +00:00
041855dbc7 zsh: fix broken <del> and <ctrl>+<arrow> keybindings 2024-01-03 13:07:29 +00:00
3e52956a3a servo: clightning: integrate, but do not enable 2024-01-02 18:32:34 +00:00
d8f4158bc6 servo: consolidate blockchains under cryptocurrencies directory 2024-01-02 18:16:58 +00:00
36638e80a3 bitcoin: add myself as an authenticated rpcuser 2024-01-02 18:11:46 +00:00
28d0a72c62 define (but dont activate) a clighting bitcoin service 2024-01-02 14:29:52 +00:00
6471524f4a programs: zecwallet-lite: move to own file 2024-01-01 15:17:51 +00:00
61b2b8f2cd nixpatches: cleanup 2024-01-01 14:46:37 +00:00
02aae4bb8b conky: start upstreaming it 2024-01-01 14:38:08 +00:00
3efecb9560 sxmo_hook_block_suspend: re-introduce exponential backoff 2024-01-01 13:03:26 +00:00
8d0707699c mpv/vlc: associate with flv video type 2024-01-01 11:48:18 +00:00
318774a2a0 sxmo_suspend: fix that "sxmo_jobs periodic_blink" would hang post-wakeup 2024-01-01 11:48:03 +00:00
b14e997a43 sxmo: remove sxmo_hook_screenoff.sh override
generally, i can get away with the defaults and patch my alternative into sxmo_suspend.sh more reliably/simply
2024-01-01 10:33:24 +00:00
b949438be5 sxmo_suspend.sh: stop, and resume, the sxmo LED blinking
then later i can remove the custom screenoff hook
2024-01-01 10:01:48 +00:00
6ee9e8e405 sxmo_hook_screenoff: decrease the blink frequency even more
if i was smarter i'd just disable the periodic blinking right before entering sleep
2024-01-01 07:24:08 +00:00
09ee8e6efc sxmo_hook_block_suspend: forward only to the next script, not all next scripts 2024-01-01 07:01:09 +00:00
49527edaa9 sxmo_suspend.sh: fix rtcwake to use sudo 2024-01-01 06:38:43 +00:00
92d193ffe3 sxmo_hook_block_suspend: fix recursion counter 2024-01-01 06:19:30 +00:00
4805510073 sxmo-utils: ship with gojq 2024-01-01 06:15:31 +00:00
6fe195e2dd sxmo: block suspend if go2tv is active 2024-01-01 04:56:39 +00:00
c54df8d9c4 hare-ev: 2023-10-31 -> 2023-12-04 2024-01-01 03:56:45 +00:00
6d8b6c61a2 feeds: sort 2024-01-01 03:56:25 +00:00
822653ec10 feeds: vitalik.ca -> vitalik.eth.limo 2024-01-01 03:48:06 +00:00
68502ca944 feeds: add webcurious.co.uk link aggregator 2024-01-01 03:46:52 +00:00
103d11a87c net: fix broken firewall/ipset setup 2023-12-31 14:25:36 +00:00
0028c41bdc uninsane-dot-org: update 2023-12-31 12:22:23 +00:00
a4fe002607 sway: always render KOReader titlebar 2023-12-30 11:57:33 +00:00
b54ab9391b sxmo-utils: add Notejot app 2023-12-30 11:41:36 +00:00
0c7612c83f sxmo-utils: 2023-12-17 -> 2023-12-28
this should fix spurious screenoff -> unlock transitions (thanks Aren!)
2023-12-30 11:31:36 +00:00
f9361af41c go2tv: remove firewall fix and allow SSDP at the iptables layer 2023-12-30 06:16:17 +00:00
3cd3ebed51 nixpkgs -> latest 2023-12-30 05:34:23 +00:00
4ad209020a disable chatty (doesnt cross compile) 2023-12-30 05:34:02 +00:00
556327740b nixpkgs: 2023-12-26 -> 2023-12-29
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/0db7618e46243d3710ff2b8040aca5f6e0102900' (2023-12-26)
  → 'github:nixos/nixpkgs/bd7fd36fe22e0de1162f1623f1736517c1506164' (2023-12-29)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/d956588517edbcde71781bd8ac3a9947a9fc55a6' (2023-12-26)
  → 'github:nixos/nixpkgs/f46c267fc63f01c75fa9f6d9fb8345e6a1ed0063' (2023-12-29)
```
2023-12-29 15:52:32 +00:00
b0ddb1b31c conky: use the same percent symbol even in battery_estimate 2023-12-28 17:43:34 +00:00
70ee98736a conky/battery_estimate: handle the static state better 2023-12-28 17:35:33 +00:00
5de06cef35 conky: fix text substitutions 2023-12-28 17:07:29 +00:00
4f3706622c conky/battery_estimate: render stylized 2023-12-28 03:05:27 +00:00
104e76de47 conky/battery_estimate: render h/m indicators as superscript 2023-12-28 01:53:43 +00:00
1df99978bb conky/battery_estimte: select icon based on battery percentage 2023-12-28 01:11:51 +00:00
3846322f12 conky/battery_estimate: support new-style Thinkpad batteries 2023-12-28 00:41:23 +00:00
623b2c6611 conky/battery_estimate: add debugging 2023-12-28 00:35:48 +00:00
cb4d73f959 nixpkgs: 2023-12-23 -> 2023-12-26
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/2125288b9266cde9e3333a6787525bc151918742' (2023-12-23)
  → 'github:nixos/nixpkgs/0db7618e46243d3710ff2b8040aca5f6e0102900' (2023-12-26)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/d8aba6fe4067abdd8b1a7f398f2b90f21c608530' (2023-12-23)
  → 'github:nixos/nixpkgs/d956588517edbcde71781bd8ac3a9947a9fc55a6' (2023-12-26)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/f7db64b88dabc95e4f7bee20455f418e7ab805d4' (2023-12-18)
  → 'github:Mic92/sops-nix/e523e89763ff45f0a6cf15bcb1092636b1da9ed3' (2023-12-24)
• Updated input 'sops-nix/nixpkgs-stable':
    'github:NixOS/nixpkgs/a19a71d1ee93226fd71984359552affbc1cd3dc3' (2023-12-17)
  → 'github:NixOS/nixpkgs/7790e078f8979a9fcd543f9a47427eeaba38f268' (2023-12-23)
```
2023-12-27 00:34:48 +00:00
58febf51bd remove most useDHCP=false settings
networking.useDHCP was deprecated, and then later undeprecated: it's safe to keep it defaulted
2023-12-24 02:17:06 +00:00
b254379fb1 firefox-extensions: update to latest 2023-12-23 21:31:13 +00:00
835d933719 nixpkgs: 2023-12-22 -> 2023-12-23
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/21e572254ecbbb9d55be98841b279d21ee5754b6' (2023-12-22)
  → 'github:nixos/nixpkgs/2125288b9266cde9e3333a6787525bc151918742' (2023-12-23)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/66bda599f409f9834c6fd6abc602e452a5c16b61' (2023-12-22)
  → 'github:nixos/nixpkgs/d8aba6fe4067abdd8b1a7f398f2b90f21c608530' (2023-12-23)
```
2023-12-23 21:18:25 +00:00
31130d90bc nixpatches: fix broken hash 2023-12-23 12:44:17 +00:00
237c493252 slskd: fix Restart option 2023-12-23 10:23:17 +00:00
18e7acd9e7 slskd: restart even on non-failure exit 2023-12-23 05:39:22 +00:00
906026e333 nixpkgs: 2023-12-21 -> 2023-12-22
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/63fbe1a992e6030fbf444ac9d6b629ec76ab86ad' (2023-12-21)
  → 'github:nixos/nixpkgs/21e572254ecbbb9d55be98841b279d21ee5754b6' (2023-12-22)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/490828bce1b0cdfe328adc7f6280a519d7e68ed4' (2023-12-21)
  → 'github:nixos/nixpkgs/66bda599f409f9834c6fd6abc602e452a5c16b61' (2023-12-22)
```
2023-12-22 19:07:32 +00:00
9e24fba5ee document that loupe is an image viewer 2023-12-21 22:58:23 +00:00
12edd60969 nixpkgs: bump 2023-12-21
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/459873d8d6492b492ca7f9b03d5a50117099abfa' (2023-12-21)
  → 'github:nixos/nixpkgs/63fbe1a992e6030fbf444ac9d6b629ec76ab86ad' (2023-12-21)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/38bbf09b10659db891af01288bd99a5e8e8d7861' (2023-12-21)
  → 'github:nixos/nixpkgs/490828bce1b0cdfe328adc7f6280a519d7e68ed4' (2023-12-21)
```
2023-12-21 20:03:06 +00:00
0f429caaca nixpkgs: 2023-12-20 -> 2023-12-21
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/7749fa1e8c5e2f6a003fd4d3a2ed52924c4a7217' (2023-12-20)
  → 'github:nixos/nixpkgs/459873d8d6492b492ca7f9b03d5a50117099abfa' (2023-12-21)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/9ee63abe2cbeea5bf15f319a0a5aaf0919fe22e8' (2023-12-20)
  → 'github:nixos/nixpkgs/38bbf09b10659db891af01288bd99a5e8e8d7861' (2023-12-21)
```
2023-12-21 18:41:55 +00:00
940f1140a3 disable webkit for erlang 2023-12-21 05:22:45 +00:00
dbb6773634 audacity: disable first-run splashscreen 2023-12-21 04:08:05 +00:00
245a0544bc audacity: ship w/o the webkitgtk dependency 2023-12-21 03:10:38 +00:00
cbd65f0816 argyllcms: build without qemu 2023-12-21 01:44:36 +00:00
f8ea711f6a cross compilation: remove dead code 2023-12-21 00:20:42 +00:00
ace94cf4d6 cross: use newer jbig2dec fix; send dconf upstream 2023-12-20 22:32:07 +00:00
829fde4336 bonsai: grab from upstream PR 2023-12-20 09:24:41 +00:00
ba8774d6e5 hare-ev: remove (upstreamed) 2023-12-20 09:21:11 +00:00
7597853cda nixpkgs: 2023-12-19 -> 2023-12-20
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/7467ab39493e17abc28c7f66179feb0a69a3dbd4' (2023-12-19)
  → 'github:nixos/nixpkgs/7749fa1e8c5e2f6a003fd4d3a2ed52924c4a7217' (2023-12-20)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/63dd8e1d2e81aaecb7de9b70ca143a607b19a3b9' (2023-12-19)
  → 'github:nixos/nixpkgs/9ee63abe2cbeea5bf15f319a0a5aaf0919fe22e8' (2023-12-20)
```
2023-12-20 09:08:42 +00:00
21077c0e34 cross: document rustPlatform cross compilation woes 2023-12-20 08:00:40 +00:00
b6a45656af gui: add planify app 2023-12-19 22:31:14 +00:00
33d2f0895f signal-desktop-from-src: 6.40.0 -> 6.42.0 2023-12-19 20:53:33 +00:00
5cd92279b7 firefox-extensions: update to latest 2023-12-19 19:40:24 +00:00
4085f60018 firefox-extensions.bypass-paywalls-clean: 3.4.6.0 -> 3.4.7.0 2023-12-19 19:40:08 +00:00
3faee78717 docs: cross: update upstreaming status 2023-12-19 19:39:38 +00:00
e96e07ac21 lemoa: todo: fold 2023-12-19 19:39:11 +00:00
0c34aec8ec lemoa: 0.4.0 -> 0.5.0 2023-12-19 18:08:16 +00:00
9d04037bec hare-ev: remove unnecessary rec 2023-12-19 17:44:04 +00:00
6af44bfd86 delfin: add an updateScript 2023-12-19 17:43:07 +00:00
5ceefa4d6d nixpkgs: 2023-12-18 -> 2023-12-19; uninsane-dot-org -> 2023-12-18
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/ab47e6046f991dc98641ffbd9f881afcd304cfca' (2023-12-18)
  → 'github:nixos/nixpkgs/7467ab39493e17abc28c7f66179feb0a69a3dbd4' (2023-12-19)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/f61b7ce80fcc95be72c5c4fea19fba928072af8b' (2023-12-18)
  → 'github:nixos/nixpkgs/63dd8e1d2e81aaecb7de9b70ca143a607b19a3b9' (2023-12-19)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/21f2b8f123a1601fef3cf6bbbdf5171257290a77' (2023-12-17)
  → 'github:Mic92/sops-nix/f7db64b88dabc95e4f7bee20455f418e7ab805d4' (2023-12-18)
• Updated input 'uninsane-dot-org':
    'git+https://git.uninsane.org/colin/uninsane?ref=refs/heads/master&rev=ee722a13732b8d03bae56be8147333d144a02126' (2023-12-10)
  → 'git+https://git.uninsane.org/colin/uninsane?ref=refs/heads/master&rev=41354f754107376f5c9265eae89d07275f0305de' (2023-12-18)
• Removed input 'uninsane-dot-org/flake-utils'
• Removed input 'uninsane-dot-org/flake-utils/systems'
```
2023-12-19 16:44:22 +00:00
f618925190 gui: ship openscad 2023-12-19 08:04:20 +00:00
68ae723543 nixos-prebuild: disable 2023-12-19 01:58:59 +00:00
e4123759f5 nginx: only auto-index /share 2023-12-19 00:12:27 +00:00
5e727a83b3 slskd: disable debug logging 2023-12-18 18:09:58 +00:00
dc288d9aa7 sane_ssdp: reduce verbosity 2023-12-18 18:00:12 +00:00
8d49c423ca transmission: disable debug logging 2023-12-18 17:58:04 +00:00
c056564c9c nixpkgs: 2023-12-17 -> 2023-12-18
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/ec02adf37f19c5dcd891ebf9f175ebb1c4fba80a' (2023-12-17)
  → 'github:nixos/nixpkgs/ab47e6046f991dc98641ffbd9f881afcd304cfca' (2023-12-18)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/91a00709aebb3602f172a0bf47ba1ef013e34835' (2023-12-17)
  → 'github:nixos/nixpkgs/f61b7ce80fcc95be72c5c4fea19fba928072af8b' (2023-12-18)
```
2023-12-18 16:39:25 +00:00
efb2815fa5 uninsane.org: simplify the /share routing (and generalize it to other subdirectories) 2023-12-18 06:03:49 +00:00
577d149728 sxmo-utils: 2023-12-09 -> 2023-12-17 2023-12-18 00:05:14 +00:00
45c2bfaaeb nixpkgs: 2023-12-16 -> 2023-12-17
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/029c707186e2b00f9e98f590b9a019320ccc21d7' (2023-12-16)
  → 'github:nixos/nixpkgs/ec02adf37f19c5dcd891ebf9f175ebb1c4fba80a' (2023-12-17)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/ceb8e4efd95627c0a86f106ba2afcd207ad5c6b3' (2023-12-16)
  → 'github:nixos/nixpkgs/91a00709aebb3602f172a0bf47ba1ef013e34835' (2023-12-17)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/d806e546f96c88cd9f7d91c1c19ebc99ba6277d9' (2023-12-10)
  → 'github:Mic92/sops-nix/21f2b8f123a1601fef3cf6bbbdf5171257290a77' (2023-12-17)
• Updated input 'sops-nix/nixpkgs-stable':
    'github:NixOS/nixpkgs/b8f33c044e51de6dde3ad80a9676945e0e4e3227' (2023-12-09)
  → 'github:NixOS/nixpkgs/a19a71d1ee93226fd71984359552affbc1cd3dc3' (2023-12-17)
```
2023-12-18 00:02:23 +00:00
16d4c9cdf2 nixpkgs: 2023-12-15 -> 2023-12-16
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/9ad53b7aaf2b9e9e0d7e36ff4f8a779bf9b0195f' (2023-12-15)
  → 'github:nixos/nixpkgs/029c707186e2b00f9e98f590b9a019320ccc21d7' (2023-12-16)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/8a205497ba6f6938b7b516c184b7cf326ab15548' (2023-12-15)
  → 'github:nixos/nixpkgs/ceb8e4efd95627c0a86f106ba2afcd207ad5c6b3' (2023-12-16)
```
2023-12-17 21:26:41 +00:00
1063a89541 powerbutton/lid-switch: tune the desired actions 2023-12-17 21:08:16 +00:00
fd0f709d50 git: remove a/ b/ prefixes from diffs 2023-12-17 20:48:31 +00:00
5edd10c332 move kiwix data to /var/lib/kiwix and persist 2023-12-16 03:05:15 +00:00
5c36ee79be kiwix: wikipedia snapshot: 2022-05 -> 2023-11 2023-12-16 01:54:34 +00:00
b2bf9d63a3 mpv: don't assume xdg-terminal-exec is on PATH 2023-12-16 00:43:43 +00:00
e297df011d xdg-terminal-exec: remove (it exists upstream now) 2023-12-16 00:41:51 +00:00
bcac00d766 mpv: uosc: add a "cast" option to the menu 2023-12-16 00:39:36 +00:00
c256d7ded5 koreader: implement copy-to-clipboard 2023-12-15 20:53:04 +00:00
7ba39ea831 koreader: document how to configure 2023-12-15 20:05:06 +00:00
28f90e4421 sxmo: lengthen voldown hold time before revealing terminal 2023-12-15 19:12:26 +00:00
5d66a1e6a5 hare-json: remove. it's been upstreamed as hareThirdParty.hare-json 2023-12-15 17:59:09 +00:00
1522eccfb3 nixpkgs: 2023-12-14 -> 2023-12-15
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/248d12a902bfc36134176f31beba87b1fe30a3c1' (2023-12-14)
  → 'github:nixos/nixpkgs/9ad53b7aaf2b9e9e0d7e36ff4f8a779bf9b0195f' (2023-12-15)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/fd7914c96f7c006047e0154dd239aa2396478094' (2023-12-14)
  → 'github:nixos/nixpkgs/8a205497ba6f6938b7b516c184b7cf326ab15548' (2023-12-15)
```
2023-12-15 17:40:44 +00:00
728604e036 gui hosts: ship delfin 2023-12-15 08:44:32 +00:00
58d4f0d512 delfin: fix cross build 2023-12-15 08:43:10 +00:00
1f7fc8700e delfin: fix icons 2023-12-15 08:30:20 +00:00
a933f8b512 delfin: persist server settings 2023-12-15 08:17:07 +00:00
83b83841d6 delfin: init at 0.2.1 2023-12-15 08:08:11 +00:00
ef8a8bc246 go2tv: document known-good format matrix 2023-12-15 03:22:03 +00:00
136ddda055 nautilus: enable the A/V pane 2023-12-15 02:57:25 +00:00
5fbf2166f1 moby: enable go2tv/catt 2023-12-15 02:33:18 +00:00
ba7bc3bd03 go2tv: docs: show that some mp4s work w/o transcoding 2023-12-15 02:32:44 +00:00
311412c5ee go2tv: configure firewall as needed 2023-12-15 00:50:58 +00:00
d18e94ea87 feeds: subscribe to linmob.net 2023-12-14 22:20:30 +00:00
6a548366cd sway: enable gvfs to support remote filesystems 2023-12-14 21:59:42 +00:00
54d2e875f6 koreader: disable image-based feeds; text only 2023-12-14 20:51:09 +00:00
c5cc0e90a3 wob: theme 2023-12-14 20:49:48 +00:00
50ce8da68c sxmo: remove sxmo-set-permissions job. upstream refactored it to not exist and they use doas now instead 2023-12-14 19:17:38 +00:00
3449bfc2a9 sxmo: bonsai: tune timings: powerhold: 1000ms -> 900ms; volhold: 400ms -> 600ms
this should improve: (1) awkwardly long power hold until window is killed, (2) accidentally seeking the media player when i meant to only adjust volume
2023-12-14 19:12:08 +00:00
18d301d9dd cross: dino: remove patch which has been upstreame into nixpkgs 2023-12-14 19:08:08 +00:00
357bf7f4ca nixpkgs: 2023-12-13 -> 2023-12-14
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/022a4231437548b719eb9e5b8bae1a7f6117fa93' (2023-12-13)
  → 'github:nixos/nixpkgs/1aca249f1846b6bb7a156b809c312de58945c85a' (2023-12-14)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/8556109c1f04574ad59dcb0c4882f44eb27ea581' (2023-12-13)
  → 'github:nixos/nixpkgs/8e23dec5ac5ebc36057e980d4e6a3eb6a44da74b' (2023-12-14)
```
2023-12-14 18:50:36 +00:00
f763448d6f go2tv: docs: firewall 2023-12-14 10:56:07 +00:00
deb828e98a programs: enable go2tv 2023-12-14 10:39:33 +00:00
cbca41accf permit moby to ssh into my devices 2023-12-14 10:35:36 +00:00
ac22e07388 sxmo: bring wob service in-house 2023-12-14 10:33:33 +00:00
cb0d9e077b programs: enable catt 2023-12-14 08:41:16 +00:00
58105e9b62 fix open-in-mpv extension 2023-12-14 07:26:50 +00:00
32fb79d43d dino: auto-start 2023-12-14 01:57:32 +00:00
f129afdae8 flare-signal: document linking/registration issue 2023-12-14 01:56:54 +00:00
29cde5e724 firefox: support Element and Nheko URIs 2023-12-13 23:14:04 +00:00
3467a5df48 feeds: subscribe Origin Stories 2023-12-13 22:31:58 +00:00
694dd59e27 feeds: subscribe bitsaboutmoney 2023-12-13 22:29:22 +00:00
540b3e4af2 firefox: auto-dispatch mpv:// URI handlers 2023-12-13 21:41:06 +00:00
e0211646b2 firefox: extraNativeMessagingHosts -> nativeMessagingHosts 2023-12-13 21:34:59 +00:00
94dcb0f08a firefox: ship open-in-mpv extension 2023-12-13 21:34:34 +00:00
0b38ed2f2a firefox: docs: clarify fxCast behavior 2023-12-13 20:58:45 +00:00
15622251ef firefox: define the fx_cast addon 2023-12-13 20:51:57 +00:00
4eb79a4a5c gui: ship pwvucontrol 2023-12-13 20:43:16 +00:00
9f54413d46 pwvucontrol: support cross compilation 2023-12-13 20:02:48 +00:00
f467898a04 sync TODO 2023-12-13 17:41:31 +00:00
413c8a4fef sponsorblock: re-disable the first-launch nag 2023-12-13 17:37:48 +00:00
d4440736dd nixpkgs: 2023-12-12 -> 2023-12-13
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/a3eee1a84ec0aadb7f567175d79574d63dcecff2' (2023-12-12)
  → 'github:nixos/nixpkgs/022a4231437548b719eb9e5b8bae1a7f6117fa93' (2023-12-13)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/47bca5bb0209496389f3a70d2e388c5531831d60' (2023-12-12)
  → 'github:nixos/nixpkgs/8556109c1f04574ad59dcb0c4882f44eb27ea581' (2023-12-13)
```
2023-12-13 16:27:18 +00:00
bb1ceaed12 gui: disable newsflash
it doesn't cross compile. also, gnome-feeds would be a better implementation if i can get the package updated
2023-12-13 16:27:18 +00:00
51a90136ea sxmo-utils: default preferSystemd to true
this probably removes some duplicate sxmo-utils packages from my install
2023-12-13 16:27:18 +00:00
e7cfa19897 sxmo-utils: use xdg-open in sxmo_open.sh 2023-12-13 16:27:18 +00:00
41411e005f flare-signal-nixified: document experience with 10.1-xx seies 2023-12-13 08:10:50 +00:00
c22119f69b flare-signal-nixified: enable primary device registration 2023-12-13 07:17:17 +00:00
354a4e523b flare-signal-nixified: 0.10.1-beta.4 -> 0.10.1-beta.6 2023-12-13 07:01:16 +00:00
b34b8a249c nixpatches: link but dont apply gnome-feeds update 2023-12-13 03:47:20 +00:00
508257da87 newsflash: enable podcasts/videos; document 2023-12-13 03:45:07 +00:00
fadcf7d7c1 mpv: youtube: associate with another URL variant 2023-12-13 03:44:57 +00:00
7f43360120 newsflash: enable 2023-12-13 03:06:08 +00:00
f9a8389f58 gui: switch from gthumb to loupe for image viewing 2023-12-13 02:29:43 +00:00
f77a18a655 cross: enable Loupe for cross compilation 2023-12-13 02:00:43 +00:00
7e4d6853f5 cross: glycin-loaders: simplify 2023-12-13 01:48:26 +00:00
5615c7cf6e cross: glycin-loader: fix compilation 2023-12-13 01:40:36 +00:00
54c51a5636 fractal-latest: remove old comments 2023-12-12 21:02:09 +00:00
1119726c64 docs: koreader: dictionary installation 2023-12-12 20:56:46 +00:00
101a2bc3af hare-ev: 2023-10-30 -> 2023-12-04 2023-12-12 20:45:46 +00:00
f4bfaf3581 firefox-extensions: update to latest 2023-12-12 20:44:56 +00:00
e8dfc1dc71 sxmo-utils: 2023-11-26 -> 2023-12-09 2023-12-12 20:44:27 +00:00
ef26b9085c nixpatches: remove merged numpy patch 2023-12-12 20:37:55 +00:00
85d9c11733 sxmo: add an option to disable wob 2023-12-12 19:00:43 +00:00
6d41f1f1db sxmo: re-enable audio
SXMO_NO_AUDIO disables too much. i just want to not launch the daemons, and customizing sxmo_hook_start is enough for that
2023-12-12 18:59:31 +00:00
f9434215db nixpkgs: 2023-12-11 -> 2023-12-12
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/43f7188eba3bc2eb73031bf8f9ad1a02224b6be1' (2023-12-12)
  → 'github:nixos/nixpkgs/a3eee1a84ec0aadb7f567175d79574d63dcecff2' (2023-12-12)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/a8dac2fa64af92360f126d2e20f47cd4ccf1c905' (2023-12-11)
  → 'github:nixos/nixpkgs/47bca5bb0209496389f3a70d2e388c5531831d60' (2023-12-12)
```
2023-12-12 18:40:06 +00:00
83d402eb77 nixos-prebuild: fix typo 2023-12-12 18:39:46 +00:00
cec48e0270 nixpkgs: 2023-12-11 -> 2023-12-12
```
• Updated input 'nixpkgs-next-unpatched':
    'github:nixos/nixpkgs/f81605387c494a302c16901ac6459e877c45f913' (2023-12-11)
  → 'github:nixos/nixpkgs/43f7188eba3bc2eb73031bf8f9ad1a02224b6be1' (2023-12-12)
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/e97b3e4186bcadf0ef1b6be22b8558eab1cdeb5d' (2023-12-11)
  → 'github:nixos/nixpkgs/a59c7364955e5f32798d0314fbb6aae347ff064d' (2023-12-12)
```
2023-12-12 09:34:52 +00:00
322038ca21 flake.nix: expose the patched nixpkgs as an output, for debugging 2023-12-12 09:34:28 +00:00
6395e60f17 nixpatches: fix date check to be based on when upstream nixpkgs was updated, not this repo 2023-12-12 09:34:28 +00:00
7969eb12d6 cross: partially fix glycin-loaders 2023-12-12 09:34:28 +00:00
f942e2c5a9 nixpatches: revise numpy master merge date 2023-12-12 09:34:28 +00:00
089f676c4a gui: switch back to gthumb; loupe does not cross compile yet 2023-12-12 08:44:08 +00:00
d2012b4e40 notejot: fix store typo 2023-12-12 07:55:18 +00:00
a319017567 gui: switch from gthumb to loupe 2023-12-12 07:38:13 +00:00
a669c9c88b gui: add Loupe image viewer specialization 2023-12-12 07:36:21 +00:00
8391e500c9 gui: handheld: ship notejot 2023-12-12 07:31:00 +00:00
5f27c8fddf servo: nixos-prebuild: cleanup garbage better 2023-12-12 06:47:47 +00:00
a4ae41e627 servo: nixos-prebuild: dont ship jobs to other builders 2023-12-12 06:44:08 +00:00
a5126ae8fb cross: re-enable jbig2dec fix (turns out it is necessary) 2023-12-12 06:20:43 +00:00
f33776e0ed flake: check.nur: simplify nixpkgs path 2023-12-12 03:53:54 +00:00
189eccb01e nixpatches: improve patch conditionality 2023-12-12 03:22:25 +00:00
4336d68e6f flake: fix CLI argument quoting 2023-12-12 02:16:06 +00:00
4f45adb063 gui: disable slic3r 2023-12-12 02:16:06 +00:00
e6b16624c3 ntfy-waiter: fix port typo in service description 2023-12-12 02:15:01 +00:00
e87d2f545c sftpgo: fix systemd after/wants typo 2023-12-12 02:14:45 +00:00
69bc219efa ports: fix systemd RandomizedDelaySec typo 2023-12-12 02:14:27 +00:00
e4f1cfb53f servo: deploy a service which periodically rebuilds my nix config to populate the cache 2023-12-12 02:13:59 +00:00
f1e59061d7 flake: check.hostConfigs: build *-light first even for -next 2023-12-11 23:00:15 +00:00
cd312e41d4 flake: remove check.hostConfigs variants 2023-12-11 22:51:58 +00:00
1bd2d0dfc1 flake: remove separate nixpkgs-staging and staging-next 2023-12-11 22:33:38 +00:00
49235a4d83 flake: add check.hostConfigsNext 2023-12-11 22:23:14 +00:00
e7826e0648 flake: add host outputs for nixpkgs-staging and nixpkgs-staging-next 2023-12-11 22:15:35 +00:00
e7edb4739f flake.nix: fix for better caching on non-cross builds 2023-12-11 21:24:33 +00:00
4a622c558e signal-desktop-from-src: fix nodejs to 18.x 2023-12-11 21:07:42 +00:00
bfe69a4708 flake: fix patching process to assume less about nixpkgs internals 2023-12-11 21:07:17 +00:00
688b4edf13 mpv: handle shorthand youtu.be URLs too 2023-12-11 16:19:51 +00:00
7ca2e5f539 nixpkgs: 2023-12-10 -> 2023-12-11; uninsane-dot-org
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/64292b08dc5d1538d7ab88817a90b2713c34c8a0' (2023-12-10)
  → 'github:nixos/nixpkgs/e97b3e4186bcadf0ef1b6be22b8558eab1cdeb5d' (2023-12-11)
• Updated input 'uninsane-dot-org':
    'git+https://git.uninsane.org/colin/uninsane?ref=refs/heads/master&rev=8f7a3f3f7ce95f21131f94418c522062a8dc2055' (2023-12-09)
  → 'git+https://git.uninsane.org/colin/uninsane?ref=refs/heads/master&rev=ee722a13732b8d03bae56be8147333d144a02126' (2023-12-10)
```
2023-12-11 06:23:43 +00:00
4c5fb74c7d feeds: subscribe to kosmosghost 2023-12-11 04:55:47 +00:00
ad82bb2630 mimeo: fix infinite loop when dispatching non-specialized http/s URLs 2023-12-11 04:52:49 +00:00
008a6192d4 mpv: associate with https://youtube.com/... 2023-12-11 04:52:49 +00:00
f4d4c7a92a sxmo-utils: remove gojq and just use normal jq 2023-12-11 04:44:45 +00:00
0a41192eb1 sxmo-utils: remove gojq requirement 2023-12-11 03:27:58 +00:00
f044fcb584 gnome-frog: fix cross compilation 2023-12-11 03:27:46 +00:00
9e2c0a7112 megapixels: simplify zbar fix 2023-12-11 03:27:29 +00:00
d2e1441d1f sane-clone: grab package data from ~/nixos instead of nixpkgs
this way i can clone my own packages
2023-12-10 17:28:30 +00:00
abbd28a634 git: add an "amend" alias 2023-12-10 17:01:58 +00:00
b309402784 nixpkgs: update; sops-nix: 2023-12-04 -> 2023-12-10
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/852e0ea0e8e1bd174bf1af9706f6b855319a5f1d' (2023-12-10)
  → 'github:nixos/nixpkgs/64292b08dc5d1538d7ab88817a90b2713c34c8a0' (2023-12-10)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/e91ece6d2cf5a0ae729796b8f0dedceab5107c3d' (2023-12-04)
  → 'github:Mic92/sops-nix/d806e546f96c88cd9f7d91c1c19ebc99ba6277d9' (2023-12-10)
• Updated input 'sops-nix/nixpkgs-stable':
    'github:NixOS/nixpkgs/dc01248a9c946953ad4d438b0a626f5c987a93e4' (2023-12-03)
  → 'github:NixOS/nixpkgs/b8f33c044e51de6dde3ad80a9676945e0e4e3227' (2023-12-09)
```
2023-12-10 16:50:24 +00:00
a7d3ac95aa nginx: uninsane.org: redirect common feed URIs to the canonical feed 2023-12-10 16:31:30 +00:00
255da2b976 docs: gtkcord4: explain how to disable notif sounds 2023-12-10 16:26:26 +00:00
8cdb4aa53d docs: feedbackd: show how to trigger a sound 2023-12-10 16:25:13 +00:00
4d5b462b2c swaync: add rules to help with debugging 2023-12-10 16:18:55 +00:00
f7a318c937 modules/users: fix services to specify PATH with correct precedence 2023-12-10 15:18:26 +00:00
eb5b9b083c mpv-uosc-latest: remove (no longer needed)
nixpkgs mpv-uosc was recently updated, seems to work well out-of-the-box
2023-12-10 02:32:33 +00:00
e0d9a59d10 nixpkgs: 2023-12-09 -> 2023-12-10
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/61b691834e5ce9590c44690e73392ee7e001d45a' (2023-12-09)
  → 'github:nixos/nixpkgs/852e0ea0e8e1bd174bf1af9706f6b855319a5f1d' (2023-12-10)
```
2023-12-10 02:13:59 +00:00
119ac4cf95 cross: start upstreaming wob patch 2023-12-09 20:20:10 +00:00
f53d0e16ff cross: start upstreaming dino patch 2023-12-09 20:11:36 +00:00
5321ccc980 uninsane-dot-org: mobile-linux-push-notifications: fix src-port -> dest-port typo 2023-12-09 18:28:28 +00:00
e8a6fa3506 uninsane-dot-org: mobile-linux-push-notifications: fix link typo 2023-12-09 18:22:58 +00:00
26e1cc2a7a uninsane-dot-org: revise linux-mobile-notifications for sxmo integration 2023-12-09 18:16:32 +00:00
cec4b4b78e sway: fix app_id for gtkcord4 2023-12-09 16:48:17 +00:00
7ce3cb79c9 switch from abaddon -> gtkcord4 as default discord client 2023-12-09 16:45:40 +00:00
4c553b1525 gtkcord4: fix to Default_keyring instead of login.keyring 2023-12-09 16:42:27 +00:00
84ec809fb5 gui: ship gnome.seahorse 2023-12-09 15:02:00 +00:00
f49e466ce8 flake: add a "hostSystems" target 2023-12-09 14:11:37 +00:00
402baa1011 uninsane-dot-org: 2023-12-03 -> 2023-12-09; nixpkgs 2023-12-09 14:01:51 +00:00
01de6f84cf feeds: subscribe to Louis Rossmann 2023-12-09 08:14:16 +00:00
e1e9047664 nixpkgs: 2023-12-08 -> 2023-12-09
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/c89d45747b4ba510caa6b2704b574484b6f93e96' (2023-12-08)
  → 'github:nixos/nixpkgs/d02151974acd5d2e1a47cee3245d97e130c3ecfa' (2023-12-09)
```
2023-12-09 05:51:01 +00:00
0be9831b0c cross: update upstreaming status 2023-12-08 22:49:18 +00:00
1db9d4d10b roles/build-machine: re-enable big-parallel 2023-12-08 20:20:55 +00:00
ccef9d1414 nixpkgs: update
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/f63903a90faf6cce169eb2bcc93fb45c457b1d31' (2023-12-08)
  → 'github:nixos/nixpkgs/c89d45747b4ba510caa6b2704b574484b6f93e96' (2023-12-08)
```
2023-12-08 20:14:44 +00:00
8b09599c5e sane-sync-music: update files if mtime differs
*presumably* most tagging software updates the mtime when tags change, but i didn't actually check
2023-12-08 15:07:12 +00:00
368099e95a cross: ostree: apply Mindavi's PR feedback 2023-12-08 15:00:29 +00:00
34342b7f48 sync.moby: reduce job count 2023-12-08 14:52:11 +00:00
fcc7ebf5c1 sync.desko: fix mountpoint typo 2023-12-08 12:24:00 +00:00
114bdb30e8 flake: sync-*: refactor 2023-12-08 10:25:01 +00:00
4caf61387e sane-sync-music: add --compress and --compat options 2023-12-08 10:24:48 +00:00
ab020327f4 nixpkgs: 2023-12-07 -> 2023-12-08
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/449c6fb06be60edd4233bb9fe748a0754df185b1' (2023-12-07)
  → 'github:nixos/nixpkgs/f63903a90faf6cce169eb2bcc93fb45c457b1d31' (2023-12-08)
```
2023-12-08 04:26:09 +00:00
bacad0f111 sane-sync-music: add a --force-copy flag 2023-12-07 19:00:51 +00:00
9619c6d2e1 sane-sync-music: refactor to facilitate future tweaks 2023-12-07 18:49:01 +00:00
07c7050335 docs: sane-sync-music: document a bug 2023-12-07 18:17:21 +00:00
24a6fba008 sane-tag-music: remove prefer-path flag to force 2023-12-07 18:08:41 +00:00
51c53b2103 sane-tag-music: allow manually specifying tags via CLI 2023-12-07 18:08:41 +00:00
4ae01aa353 sane-tag-music: auto-create id3 tags for MP3 files 2023-12-07 18:08:41 +00:00
0db1e3728a sway: dont ship custom gtk icons
the GNOME 45 update makes it so default adwaita icons are reliable on moby
2023-12-07 17:56:56 +00:00
83c7657951 sane-tag-music: better handle track names for compilation albums 2023-12-07 17:29:10 +00:00
e20386299f sane-tag-music: add a --force flag 2023-12-07 17:29:10 +00:00
d6e43effde sane-tag-music: better handle verbose track names 2023-12-07 17:29:10 +00:00
bbe8f4a852 sane-tag-music: support opus, aac (limited) 2023-12-07 17:29:10 +00:00
8c98e38053 sane-tag-music: better handling of "Various Artists" 2023-12-07 17:29:10 +00:00
96a36d4d6b sane-tag-music: support ogg files 2023-12-07 17:29:10 +00:00
366a9cea0d fractal: ship optimized build 2023-12-07 16:39:36 +00:00
e810774202 fractal,flare: note that release is incompatible with cross compilation 2023-12-07 16:39:36 +00:00
f2de781cbc nixpkgs: update
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/17411d69e415b5f4910f9a66f89dc6a1866cb410' (2023-12-07)
  → 'github:nixos/nixpkgs/449c6fb06be60edd4233bb9fe748a0754df185b1' (2023-12-07)
```
2023-12-07 16:39:36 +00:00
7f08ad01db sane-tag-music: handle more character encoding edgecases 2023-12-07 15:52:28 +00:00
2c66d8cad0 sane-tag-music: don't crash when file opening fails 2023-12-07 15:51:51 +00:00
fc4803f3fd sane-tag-music: fix bug that song would be extracted into a list of chars 2023-12-07 15:51:17 +00:00
5a6d1dd3c2 sane-tag-music: don't write empty tags 2023-12-07 13:55:45 +00:00
ba42ff7469 sane-tag-music: support mp3 2023-12-07 13:55:45 +00:00
a6cc698c69 signal-desktop-from-src: simplify build process 2023-12-07 13:49:07 +00:00
19b0a62fee flake: support cross deployments from non-binfmt machines 2023-12-07 13:49:07 +00:00
1a6ce11b07 disable binfmt emulation on my build machines 2023-12-07 13:49:07 +00:00
49d8578b83 signal-desktop-from-src: build without emulation 2023-12-07 13:49:07 +00:00
53c0cd570a update todos: moby: install games 2023-12-07 13:49:07 +00:00
4d84bdafed koreader: cross-compile without binfmt 2023-12-07 13:49:07 +00:00
059cd38e7b cross: comment out the firefox hacks
they're unused and broken anyway
2023-12-07 13:49:07 +00:00
8f89d11435 cross: fix wob compilation 2023-12-07 13:49:07 +00:00
243f78ff0e nixpkgs: 2023-12-06 -> 2023-12-07
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/2bea1bc0f98bb316e26d1a5a17df58fce54ca8c4' (2023-12-06)
  → 'github:nixos/nixpkgs/17411d69e415b5f4910f9a66f89dc6a1866cb410' (2023-12-07)

```
2023-12-07 13:49:07 +00:00
21be1b392e servo: switch external storage to zfs pool 2023-12-07 08:57:26 +00:00
8b71e6ac5a sane-stop-all-servo: update with newer services 2023-12-07 05:36:09 +00:00
f5f6298284 re-enable flare-signal 2023-12-06 19:27:47 +00:00
c8370bc290 cross: tried to get cinny to cross-compile, not quite there 2023-12-06 19:26:18 +00:00
abc0ac88d3 flare-signal-nixified: cross-compile without emulation 2023-12-06 19:25:09 +00:00
9da604c0af fractal-nixified: fix build 2023-12-06 19:22:45 +00:00
801da9d321 cross: add a cantBinfmt option to force a package to be built on a non-binfmt machine 2023-12-06 19:20:39 +00:00
ac3b0b873b transmission: increase speed limits 2023-12-06 18:03:08 +00:00
9beee146f2 feeds: sort Youtube feeds 2023-12-06 16:49:40 +00:00
2d06401f3c feeds: subscribe to Tom Scott 2023-12-06 16:19:37 +00:00
2db56f2499 feeds: subscribe to TheB1M 2023-12-06 16:18:03 +00:00
63ea6d7002 feeds: subscribe to Exurb1a 2023-12-06 16:16:29 +00:00
3e2523cc2c feeds: subscribe to Cold Fusion 2023-12-06 16:15:25 +00:00
ad3f5e305e feeds: subscribe to Vox
don't @ me
2023-12-06 16:13:08 +00:00
aa5b9e3db3 user services: wrap with user PATH
notably, this alllows Fractal to open links with the preferred browser
2023-12-06 16:09:07 +00:00
46123719e9 feeds: subscribe to Vihart 2023-12-06 16:09:07 +00:00
16bce990c6 feeds: subscribe to PolyMatter 2023-12-06 16:09:07 +00:00
d55e387187 feeds: subscribe to Vsauce 2023-12-06 16:09:06 +00:00
e75c3375dc feeds: subscribe to Channel5 News 2023-12-06 16:08:50 +00:00
b1c7cb367a feeds: subcsribe to hbomberguy 2023-12-06 15:47:39 +00:00
d63d660ec2 feeds: subscribe to ContraPoints 2023-12-06 15:45:43 +00:00
f24a0a84b5 gpodder: ship on all systems
it's more useful on desko/lappy now that i can ship Youtube feeds.
2023-12-06 15:36:41 +00:00
9704dcc997 feeds: add support for video; subscribe to videos in gpodder 2023-12-06 15:36:05 +00:00
80875d6312 feeds: subscribe to Technology Connections 2023-12-06 15:35:38 +00:00
79f4c9f98c flare-signal-nixified: support defaultCrateOverrides 2023-12-06 14:22:16 +00:00
e2735e151e cross: make buildInQemu more flexible to non-stdenv builders 2023-12-06 14:08:46 +00:00
afb4a88830 moby: enable dialect 2023-12-06 14:00:34 +00:00
84dc8cfd23 cross: build dialect so that it doesn't depend on build binaries at runtime 2023-12-06 13:56:39 +00:00
6ef52677ee nixpkgs: 2023-12-05 -> 2023-12-06
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/3532bd963c2a1417e7d5d9a13b90f3ab8e6b6538' (2023-12-05)
  → 'github:nixos/nixpkgs/2bea1bc0f98bb316e26d1a5a17df58fce54ca8c4' (2023-12-06)
```
2023-12-06 01:45:09 +00:00
73c0e9a742 cross: update error message for fractal 2023-12-05 17:02:33 +00:00
7ff259073e swaync: decrease mpris icon size 64 -> 48px 2023-12-05 17:01:57 +00:00
2bf10c60ee swaynotificationcenter: fix mpris icon height even when it fails to load an icon 2023-12-05 16:57:24 +00:00
72f4b43b54 sxmo: better input mappings 2023-12-05 15:12:08 +00:00
e1ced7a7fe sxmo_hook_inputhandler.sh: remove unused VOL_INCR_2 variable 2023-12-05 10:08:16 +00:00
f41b1cf3b5 sxmo: enable powertoggle -> volup/down for seeking even when screen is on
it's not currently mapped to anything else, so...
2023-12-05 10:04:01 +00:00
70693c2052 sxmo: simplify shortcuts
remove power -> volup DE menu map -- it's accessible via sysmenu now

replace power -> voldown terminal map with just voldown hold
2023-12-05 10:02:19 +00:00
f61d7d0f7d sxmo: decrease power-button timeout 2023-12-05 08:54:18 +00:00
3d7ea75bfc sxmo: simplify XDG_SESSION_TYPE fix 2023-12-05 08:50:19 +00:00
f350d7949c sxmo: fix missing XDG_SESSION_TYPE env var 2023-12-05 08:06:14 +00:00
10c21714ef tangram: build without emulation 2023-12-05 06:02:38 +00:00
2dbae69d50 komikku: build without emulation 2023-12-05 05:16:40 +00:00
4cc5eed884 feeds: subscribe to srslywrong.com 2023-12-05 04:25:25 +00:00
9967868e80 nixpkgs: update
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/d90955124ff3af2d469bf10000b09b9d7dfc5240' (2023-12-04)
  → 'github:nixos/nixpkgs/3532bd963c2a1417e7d5d9a13b90f3ab8e6b6538'
```
2023-12-05 02:04:40 +00:00
bb79752101 cross: gnome-online-accounts: disable unnecessary needsBinfmt
perhaps this was fixed in gnome 44 -> gnome 45
2023-12-04 17:50:12 +00:00
ebd24e5999 cross: evolution-data-server: build w/o binfmt/qemu 2023-12-04 17:50:12 +00:00
7a3fa88559 cross: gnome.mutter: build without binfmt/qemu 2023-12-04 17:50:12 +00:00
cff4fdc5f5 feeds: unsubscribe from Daniel Huberman 2023-12-04 12:36:10 +00:00
e7fc52ff20 cross: build neovim w/o binfmt/qemu 2023-12-04 11:26:28 +00:00
b061aff76e IOCTL_... errrors: track mesa 23.3.1 PR which SHOULD fix them? 2023-12-04 11:07:59 +00:00
b14214761b cross: get jbig2dec to build without binfmt/qemu 2023-12-04 11:07:53 +00:00
9bd684a971 cross: waybar: build without binfmt/qemu 2023-12-04 08:57:57 +00:00
89286be9e1 cross: tidy: remove explicit "final." 2023-12-04 07:42:11 +00:00
991a6a7552 cross: build libpanel w/o binfmt/qemu 2023-12-04 07:26:56 +00:00
04af5558b5 ibus: cross compile without binfmt/qemu 2023-12-04 06:59:00 +00:00
3ee487ca94 cross: fix flatpak to not require binfmt/qemu 2023-12-04 05:05:26 +00:00
20352ff170 calls: cross compile without binfmt/qemu 2023-12-04 04:24:53 +00:00
819894ccbf dino: compile without binfmt/qemu 2023-12-04 04:02:07 +00:00
aa46c4cb8f chatty: remove redundant evolution-data-server override: its done in overlays/preferences.nix 2023-12-04 02:09:52 +00:00
1c75977da7 firefox-extensions: update bypass-paywalls-clean, ublacklist, ublock-origin 2023-12-04 01:47:35 +00:00
c099483305 cross: mark as needsBinfmtOrQemu those packages which can build in either 2023-12-04 01:47:35 +00:00
959e200837 cross: remove upstreamed vulkan-tools fix 2023-12-04 00:38:54 +00:00
d9f0bdb089 nixpkgs, sops-nix, uninsane-dot-org -> 2023-12-04
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/0616776a5e4072e9455e3966d1fce58feefa7a58' (2023-12-03)
  → 'github:nixos/nixpkgs/d90955124ff3af2d469bf10000b09b9d7dfc5240' (2023-12-04)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/e19071f9958c8da4f4347d3d78790d97e98ba22f' (2023-12-02)
  → 'github:Mic92/sops-nix/8bca48cb9a12bbd8766f359ad00336924e91b7f7' (2023-12-03)
• Updated input 'sops-nix/nixpkgs-stable':
    'github:NixOS/nixpkgs/dfb95385d21475da10b63da74ae96d89ab352431' (2023-11-25)
  → 'github:NixOS/nixpkgs/dc01248a9c946953ad4d438b0a626f5c987a93e4' (2023-12-03)
• Updated input 'uninsane-dot-org':
    'git+https://git.uninsane.org/colin/uninsane?ref=refs/heads/master&rev=8a4273489d945f21d7e0ca6aac952460c7d4c391' (2023-11-09)
  → 'git+https://git.uninsane.org/colin/uninsane?ref=refs/heads/master&rev=f865fdd262e249bb1b829900f99cbb67f21a0365' (2023-12-03)
```
2023-12-04 00:34:27 +00:00
b50d723158 servo: nginx: remove "root" in uninsane share path 2023-12-03 15:53:29 +00:00
14739af1b9 servo: nginx: dont follow symlinks in the /share directory 2023-12-03 15:51:01 +00:00
747511c6a8 waybar: link to a better playerctl integration 2023-12-03 15:19:55 +00:00
c96f9cd4de ibus: 1.5.29-rc1 -> 1.5.29
TODO: cleanup this patch and then send to nixpkgs :)
2023-12-03 14:41:56 +00:00
31da2f10c9 sane-wipe: support dino 2023-12-03 14:40:14 +00:00
9e51d7f150 sane-wipe-*: consolidate into one sane-wipe binary 2023-12-03 14:25:35 +00:00
b1b1f8d659 cross: vulkan-tools: link to upstream PR 2023-12-03 14:02:57 +00:00
0c0e7881b1 signal-desktop: document a known bug 2023-12-03 13:58:30 +00:00
6c2f07aab1 cross: disable gnome-2048 fix in light of vala fix being upstreamed (still in staging) 2023-12-03 13:46:01 +00:00
84d2b31c51 cross: fix vulkan-tools compilation 2023-12-03 13:29:44 +00:00
2f23d916f5 sxmo: disable xwayland 2023-12-03 13:03:57 +00:00
d413f4a782 gtkcord4: partially re-enable 2023-12-03 13:01:52 +00:00
c2080cfe1e sway: position Signal on the correct desktop even when run without Xwayland 2023-12-03 13:00:29 +00:00
c687d059c5 signal-desktop: support wayland even when running as a service 2023-12-03 13:00:29 +00:00
a131358c36 signal-desktop: support wayland 2023-12-03 13:00:29 +00:00
0ba012fd7c guis: ship vulkan-tools 2023-12-03 13:00:29 +00:00
b43a693a1e nginx: render directory listings for uninsane.org/share 2023-12-03 09:00:45 +00:00
6f4072efdd servo: enable bitcoind 2023-12-03 08:49:24 +00:00
908984c285 cross: mark mutter as needs binfmt 2023-12-03 02:10:34 +00:00
8772aaec65 zfs: dont ship on moby 2023-12-03 00:58:49 +00:00
f3d605bb63 cross: fix fractal-nixified dep which needs binfmt 2023-12-03 00:40:08 +00:00
6741e0b9e1 nixpkgs: -> tip; sops-nix: 2023-11-27 -> 2023-12-02
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/eb18da27b9cb7e2006574cd962f8a22baf2955f1' (2023-12-02)
  → 'github:nixos/nixpkgs/0616776a5e4072e9455e3966d1fce58feefa7a58' (2023-12-03)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/b1edbf5c0464b4cced90a3ba6f999e671f0af631' (2023-11-27)
  → 'github:Mic92/sops-nix/e19071f9958c8da4f4347d3d78790d97e98ba22f' (2023-12-02)
```
2023-12-03 00:22:07 +00:00
a9f932408c servo: add zfs dataset 2023-12-02 17:38:00 +00:00
a00e6984d9 nixpkgs: 2023-12-01 -> 2023-12-02
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/7c12c8615307e2677a5f769e27ddb0ab4e36a940' (2023-12-01)
  → 'github:nixos/nixpkgs/eb18da27b9cb7e2006574cd962f8a22baf2955f1' (2023-12-02)
```
2023-12-02 00:12:16 +00:00
b4738438b1 nixpkgs: 2023-11-30 -> 2023-12-01
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/8d0f0ca32319439fe9940b1de917dbbdcb8e6f3d' (2023-11-30)
  → 'github:nixos/nixpkgs/7c12c8615307e2677a5f769e27ddb0ab4e36a940' (2023-12-01)
```
2023-12-01 16:19:05 +00:00
416c2f2f39 feeds: remove Hard Fork 2023-12-01 15:35:15 +00:00
589f86010f fix that servo had too low of a inotify watch limit for wan.txt path unit to work 2023-12-01 13:18:05 +00:00
76a7c19996 waybar-sxmo-status: fix volume 2023-12-01 12:51:55 +00:00
3fa676e169 sxmo: waybar: include the volume sxmo status (i.e. microphone/headphones) 2023-12-01 08:45:31 +00:00
3193028c48 sxmo_hook_start: dont start the statusbar items 2023-12-01 07:56:43 +00:00
ba823e8283 sxmo: waybar: provide status more granularly 2023-12-01 07:43:20 +00:00
55f4ef9a4f firefox-extensions.metamask: 11.6.2 -> 11.6.3 2023-12-01 04:33:03 +00:00
200b0dcf7c sxmo: better integrate the status components into waybar
maybe i'll remove all the sxmo-specific logic eventually: it seems generalizable
2023-12-01 03:28:32 +00:00
181f9597c2 Merge branch 'dev' 2023-12-01 01:52:12 +00:00
e55c264c29 activationScripts: fix error messages which would occur on boot, for scripts which only want to run during upgrades 2023-12-01 01:51:37 +00:00
dfbae7e7b5 notify user when nixos deploy/activation completes 2023-12-01 01:29:37 +00:00
98fa50d0eb nixpkgs: 2023-11-29 -> 2023-11-30
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/6711380ae7874005d707d7d03830bd5eee40b43b' (2023-11-29)
  → 'github:nixos/nixpkgs/8d0f0ca32319439fe9940b1de917dbbdcb8e6f3d' (2023-11-30)
```
2023-11-30 23:53:17 +00:00
9503658dec sane-tag-music: handle tracks with soundcloud ID at end of title 2023-11-30 13:59:08 +00:00
3c9bf681b2 sane-tag-music: better handle compilation albums 2023-11-30 13:23:55 +00:00
c1b20675c1 sane-tag-music: handle more path schemas 2023-11-30 12:53:04 +00:00
5703caac19 remove unused scripts/ensure-perms script 2023-11-30 12:53:04 +00:00
7abf7459f9 signal-desktop-from-src: 6.38.0 -> 6.40.0 2023-11-30 09:58:25 +00:00
b14c6ecd5b firefox-extensions: update to latest 2023-11-30 09:47:09 +00:00
455127219d flake: rename check.host-configs -> check.hostConfigs 2023-11-30 01:40:50 +00:00
e235014bde cross: lift defaultCrateOverrides patches to toplevel 2023-11-30 01:40:02 +00:00
ed1bf899b6 fractal: annotate crates which require binfmt for cross compilation 2023-11-30 01:36:53 +00:00
36c7f77a98 nixpkgs: 2023-11-28 -> 2023-11-29
```
• Updated input 'nixpkgs-unpatched':
    'github:nixos/nixpkgs/c9702bf40b036c0f1d3d5b0aaf3eee2bf920124c' (2023-11-28)
  → 'github:nixos/nixpkgs/6711380ae7874005d707d7d03830bd5eee40b43b' (2023-11-29)
```
2023-11-30 00:50:35 +00:00
996b4f8366 sane-tag-music: update tags even if file had no existing tags 2023-11-29 13:05:05 +00:00
39d94b34d7 sane-tag-music: better handle singles 2023-11-29 12:57:16 +00:00
6edc6841bf sane-tag-music: support directory/tree operations 2023-11-29 12:52:35 +00:00
b2806bd649 sxmo: ship codemadness-frontends 0.6 2023-11-29 12:31:36 +00:00
936118b8cb sane-tag-music: init 2023-11-29 12:29:58 +00:00
120f251590 sxmo-utils: enable sxmo_youtube.sh script 2023-11-29 10:16:00 +00:00
d9962e1b03 codemadness-frontends: fix cross compilation 2023-11-29 10:15:39 +00:00
1396eb2c58 codemadness-frontends: init at 0.8 2023-11-29 09:51:42 +00:00
174 changed files with 8130 additions and 8703 deletions

18
TODO.md
View File

@@ -1,9 +1,8 @@
## BUGS ## BUGS
- nixpkgs date is incorrect (1970.01.01...)
- ringer (i.e. dino incoming call) doesn't prevent moby from sleeping - ringer (i.e. dino incoming call) doesn't prevent moby from sleeping
- Fractal opens links with non-preferred web browser
- `nix` operations from lappy hang when `desko` is unreachable - `nix` operations from lappy hang when `desko` is unreachable
- could at least direct the cache to `http://desko-hn:5001` - could at least direct the cache to `http://desko-hn:5001`
- waybar isn't visible on moby until after `swaymsg reload`
## REFACTORING: ## REFACTORING:
@@ -28,7 +27,6 @@
#### upstreaming to non-nixpkgs repos #### upstreaming to non-nixpkgs repos
- gtk: build schemas even on cross compilation: <https://github.com/NixOS/nixpkgs/pull/247844> - gtk: build schemas even on cross compilation: <https://github.com/NixOS/nixpkgs/pull/247844>
- sxmo: add new app entries
## IMPROVEMENTS: ## IMPROVEMENTS:
@@ -70,14 +68,14 @@
- UnCiv (Civ V clone; nixpkgs `unciv`; doesn't cross-compile): <https://github.com/yairm210/UnCiv> - UnCiv (Civ V clone; nixpkgs `unciv`; doesn't cross-compile): <https://github.com/yairm210/UnCiv>
- Simon Tatham's Puzzle Collection (not in nixpkgs) <https://git.tartarus.org/?p=simon/puzzles.git> - Simon Tatham's Puzzle Collection (not in nixpkgs) <https://git.tartarus.org/?p=simon/puzzles.git>
- Shootin Stars (Godot; not in nixpkgs) <https://gitlab.com/greenbeast/shootin-stars> - Shootin Stars (Godot; not in nixpkgs) <https://gitlab.com/greenbeast/shootin-stars>
- numberlink (generic name for Flow Free). not packaged in Nix
- Neverball (https://neverball.org/screenshots.php). nix: as `neverball`
#### moby #### moby
- fix cpuidle (gets better power consumption): <https://xnux.eu/log/077.html> - fix cpuidle (gets better power consumption): <https://xnux.eu/log/077.html>
- SwayNC: - SwayNC:
- don't show MPRIS if no players detected - don't show MPRIS if no players detected
- this is a problem of playerctld, i guess - this is a problem of playerctld, i guess
- also, the album icon when "Not playing" doesn't follow the size we give in the config
- that means mpris always takes up excessive space on moby
- add option to change audio output - add option to change audio output
- fix colors (red alert) to match overall theme - fix colors (red alert) to match overall theme
- moby: tune GPS - moby: tune GPS
@@ -88,12 +86,7 @@
- manually do smoothing, as some layer between mepo and geoclue/gpsd? - manually do smoothing, as some layer between mepo and geoclue/gpsd?
- moby: show battery state on ssh login - moby: show battery state on ssh login
- moby: improve gPodder launch time - moby: improve gPodder launch time
- sxmo: port to swaybar like i use on desktop
- users in #sxmo claim it's way better perf
- sxmo: fix youtube scripts (package youtube-cli)
- moby: theme GTK apps (i.e. non-adwaita styles) - moby: theme GTK apps (i.e. non-adwaita styles)
- combine multiple icon themes to get one which has the full icon set?
- get adwaita-icon-theme to ship everything even when cross-compiled?
- especially, make the menubar collapsible - especially, make the menubar collapsible
- try Gradience tool specifically for theming adwaita? <https://linuxphoneapps.org/apps/com.github.gradienceteam.gradience/> - try Gradience tool specifically for theming adwaita? <https://linuxphoneapps.org/apps/com.github.gradienceteam.gradience/>
- phog: remove the gnome-shell runtime dependency to save hella closure size - phog: remove the gnome-shell runtime dependency to save hella closure size
@@ -121,13 +114,10 @@
- add `pkgs.impure-cached.<foo>` package set to build things with ccache enabled - add `pkgs.impure-cached.<foo>` package set to build things with ccache enabled
- every package here can be auto-generated, and marked with some env var so that it doesn't pollute the pure package set - every package here can be auto-generated, and marked with some env var so that it doesn't pollute the pure package set
- would be super handy for package prototyping! - would be super handy for package prototyping!
- get moby to build without binfmt emulation (i.e. make all emulation explicit) - fix desko so it doesn't dispatch so many build jobs to servo by default
- then i can distribute builds across servo + desko, and also allow servo to pull packages from desko w/o worrying about purity
## NEW FEATURES: ## NEW FEATURES:
- migrate MAME cabinet to nix - migrate MAME cabinet to nix
- boot it from PXE from servo? - boot it from PXE from servo?
- deploy to new server, and use it as a remote builder
- enable IPv6 - enable IPv6
- package lemonade lemmy app: <https://linuxphoneapps.org/apps/ml.mdwalters.lemonade/> - package lemonade lemmy app: <https://linuxphoneapps.org/apps/ml.mdwalters.lemonade/>

77
flake.lock generated
View File

@@ -1,23 +1,5 @@
{ {
"nodes": { "nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1694529238,
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"mobile-nixos": { "mobile-nixos": {
"flake": false, "flake": false,
"locked": { "locked": {
@@ -35,13 +17,29 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-next-unpatched": {
"locked": {
"lastModified": 1705233677,
"narHash": "sha256-eq3VE8QGJsunqqF/BlLslWE1gASp4Hlgp0c78coxat0=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "724e39ebb9b8eda97f17d423f66fbc5a991f4f8d",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "staging-next",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable": { "nixpkgs-stable": {
"locked": { "locked": {
"lastModified": 1700905716, "lastModified": 1705033721,
"narHash": "sha256-w1vHn2MbGfdC+CrP3xLZ3scsI06N0iQLU7eTHIVEFGw=", "narHash": "sha256-K5eJHmL1/kev6WuqyqqbS1cdNnSidIZ3jeqJ7GbrYnQ=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "dfb95385d21475da10b63da74ae96d89ab352431", "rev": "a1982c92d8980a0114372973cbdfe0a307f1bdea",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -53,11 +51,11 @@
}, },
"nixpkgs-unpatched": { "nixpkgs-unpatched": {
"locked": { "locked": {
"lastModified": 1701180790, "lastModified": 1705254014,
"narHash": "sha256-kYWcHsk2A1VUpiOvSo7Pq175WnSVeltspTGM2q+Cr3U=", "narHash": "sha256-4RrVNEqxeji4vqDgzSl7JoCD6a0ag5LF9zXFndtqrpE=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "c9702bf40b036c0f1d3d5b0aaf3eee2bf920124c", "rev": "6c08fe3ccf437d8b26bec010fd925ddd6bb0d0d5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -70,6 +68,7 @@
"root": { "root": {
"inputs": { "inputs": {
"mobile-nixos": "mobile-nixos", "mobile-nixos": "mobile-nixos",
"nixpkgs-next-unpatched": "nixpkgs-next-unpatched",
"nixpkgs-unpatched": "nixpkgs-unpatched", "nixpkgs-unpatched": "nixpkgs-unpatched",
"sops-nix": "sops-nix", "sops-nix": "sops-nix",
"uninsane-dot-org": "uninsane-dot-org" "uninsane-dot-org": "uninsane-dot-org"
@@ -83,11 +82,11 @@
"nixpkgs-stable": "nixpkgs-stable" "nixpkgs-stable": "nixpkgs-stable"
}, },
"locked": { "locked": {
"lastModified": 1701127353, "lastModified": 1705201153,
"narHash": "sha256-qVNX0wOl0b7+I35aRu78xUphOyELh+mtUp1KBx89K1Q=", "narHash": "sha256-y0/a4IMDZrc7lAkR7Gcm5R3W2iCBiARHnYZe6vkmiNE=",
"owner": "Mic92", "owner": "Mic92",
"repo": "sops-nix", "repo": "sops-nix",
"rev": "b1edbf5c0464b4cced90a3ba6f999e671f0af631", "rev": "70dd0d521f7849338e487a219c1a07c429a66d77",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -96,34 +95,18 @@
"type": "github" "type": "github"
} }
}, },
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"uninsane-dot-org": { "uninsane-dot-org": {
"inputs": { "inputs": {
"flake-utils": "flake-utils",
"nixpkgs": [ "nixpkgs": [
"nixpkgs-unpatched" "nixpkgs-unpatched"
] ]
}, },
"locked": { "locked": {
"lastModified": 1699515935, "lastModified": 1704082841,
"narHash": "sha256-cJIuVrYorhIzG5pRFZb+ZtaKhTFD92ThC42SaxvSe/E=", "narHash": "sha256-4g3lePnUALb8B1m3rEDD6rrZAq2pTN4qaSnStbd676U=",
"ref": "refs/heads/master", "ref": "refs/heads/master",
"rev": "8a4273489d945f21d7e0ca6aac952460c7d4c391", "rev": "4a1fa488e64e6c87c6c951e3fafb2684692f64d3",
"revCount": 216, "revCount": 234,
"type": "git", "type": "git",
"url": "https://git.uninsane.org/colin/uninsane" "url": "https://git.uninsane.org/colin/uninsane"
}, },

185
flake.nix
View File

@@ -29,7 +29,7 @@
# - daily: # - daily:
# - nixos-unstable cut from master after enough packages have been built in caches. # - nixos-unstable cut from master after enough packages have been built in caches.
# - every 6 hours: # - every 6 hours:
# - master auto-merged into staging. # - master auto-merged into staging and staging-next
# - staging-next auto-merged into staging. # - staging-next auto-merged into staging.
# - manually, approximately once per month: # - manually, approximately once per month:
# - staging-next is cut from staging. # - staging-next is cut from staging.
@@ -44,8 +44,9 @@
# <https://github.com/nixos/nixpkgs/tree/nixos-unstable> # <https://github.com/nixos/nixpkgs/tree/nixos-unstable>
# nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-unstable"; # nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-unstable";
nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=master"; nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=master";
# nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=staging-next"; # nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-staging";
# nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=staging"; # nixpkgs-unpatched.url = "github:nixos/nixpkgs?ref=nixos-staging-next";
nixpkgs-next-unpatched.url = "github:nixos/nixpkgs?ref=staging-next";
mobile-nixos = { mobile-nixos = {
# <https://github.com/nixos/mobile-nixos> # <https://github.com/nixos/mobile-nixos>
@@ -74,6 +75,7 @@
outputs = { outputs = {
self, self,
nixpkgs-unpatched, nixpkgs-unpatched,
nixpkgs-next-unpatched ? nixpkgs-unpatched,
mobile-nixos, mobile-nixos,
sops-nix, sops-nix,
uninsane-dot-org, uninsane-dot-org,
@@ -92,9 +94,9 @@
# rather than apply our nixpkgs patches as a flake input, do that here instead. # rather than apply our nixpkgs patches as a flake input, do that here instead.
# this (temporarily?) resolves the bad UX wherein a subflake residing in the same git # this (temporarily?) resolves the bad UX wherein a subflake residing in the same git
# repo as the main flake causes the main flake to have an unstable hash. # repo as the main flake causes the main flake to have an unstable hash.
nixpkgs = (import ./nixpatches/flake.nix).outputs { patchNixpkgs = variant: nixpkgs: (import ./nixpatches/flake.nix).outputs {
self = nixpkgs; inherit variant nixpkgs;
nixpkgs = nixpkgs-unpatched; self = patchNixpkgs variant nixpkgs;
} // { } // {
# provide values that nixpkgs ordinarily sources from the flake.lock file, # provide values that nixpkgs ordinarily sources from the flake.lock file,
# inaccessible to it here because of the import-from-derivation. # inaccessible to it here because of the import-from-derivation.
@@ -110,21 +112,21 @@
inherit (self) shortRev; inherit (self) shortRev;
}; };
nixpkgsCompiledBy = system: nixpkgs.legacyPackages."${system}"; nixpkgs' = patchNixpkgs "master" nixpkgs-unpatched;
nixpkgsCompiledBy = system: nixpkgs'.legacyPackages."${system}";
evalHost = { name, local, target, light ? false }: nixpkgs.lib.nixosSystem { evalHost = { name, local, target, light ? false, nixpkgs ? nixpkgs' }: nixpkgs.lib.nixosSystem {
system = target; system = target;
modules = [ modules = [
{ {
nixpkgs = (if (local != null) then { nixpkgs.buildPlatform.system = local;
buildPlatform = local;
} else {}) // {
# TODO: does the earlier `system` arg to nixosSystem make its way here?
hostPlatform.system = target;
};
# nixpkgs.buildPlatform = local; # set by instantiate.nix instead
# nixpkgs.config.replaceStdenv = { pkgs }: pkgs.ccacheStdenv; # nixpkgs.config.replaceStdenv = { pkgs }: pkgs.ccacheStdenv;
} }
(optionalAttrs (local != target) {
# XXX(2023/12/11): cache.nixos.org uses `system = ...` instead of `hostPlatform.system`, and that choice impacts the closure of every package.
# so avoid specifying hostPlatform.system on non-cross builds, so i can use upstream caches.
nixpkgs.hostPlatform.system = target;
})
(optionalAttrs light { (optionalAttrs light {
sane.enableSlowPrograms = false; sane.enableSlowPrograms = false;
}) })
@@ -140,39 +142,24 @@
]; ];
}; };
in { in {
nixosConfigurations = nixosConfigurations = let
let hosts = {
hosts = { servo = { name = "servo"; local = "x86_64-linux"; target = "x86_64-linux"; };
servo = { name = "servo"; local = "x86_64-linux"; target = "x86_64-linux"; }; desko = { name = "desko"; local = "x86_64-linux"; target = "x86_64-linux"; };
desko = { name = "desko"; local = "x86_64-linux"; target = "x86_64-linux"; }; desko-light = { name = "desko"; local = "x86_64-linux"; target = "x86_64-linux"; light = true; };
desko-light = { name = "desko"; local = "x86_64-linux"; target = "x86_64-linux"; light = true; }; lappy = { name = "lappy"; local = "x86_64-linux"; target = "x86_64-linux"; };
lappy = { name = "lappy"; local = "x86_64-linux"; target = "x86_64-linux"; }; lappy-light = { name = "lappy"; local = "x86_64-linux"; target = "x86_64-linux"; light = true; };
lappy-light = { name = "lappy"; local = "x86_64-linux"; target = "x86_64-linux"; light = true; }; moby = { name = "moby"; local = "x86_64-linux"; target = "aarch64-linux"; };
moby = { name = "moby"; local = "x86_64-linux"; target = "aarch64-linux"; }; moby-light = { name = "moby"; local = "x86_64-linux"; target = "aarch64-linux"; light = true; };
moby-light = { name = "moby"; local = "x86_64-linux"; target = "aarch64-linux"; light = true; }; rescue = { name = "rescue"; local = "x86_64-linux"; target = "x86_64-linux"; };
rescue = { name = "rescue"; local = "x86_64-linux"; target = "x86_64-linux"; }; };
}; hostsNext = mapAttrs' (h: v: {
# cross-compiled builds: instead of emulating the host, build using a cross-compiler. name = "${h}-next";
# - these are faster to *build* than the emulated variants (useful when tweaking packages), value = v // { nixpkgs = patchNixpkgs "staging-next" nixpkgs-next-unpatched; };
# - but fewer of their packages can be found in upstream caches. }) hosts;
cross = mapAttrValues evalHost hosts; in mapAttrValues evalHost (
emulated = mapAttrValues hosts // hostsNext
(args: evalHost (args // { local = null; })) );
hosts;
prefixAttrs = prefix: attrs: mapAttrs'
(name: value: {
name = prefix + name;
inherit value;
})
attrs;
in
(prefixAttrs "cross-" cross) //
(prefixAttrs "emulated-" emulated) // {
# prefer native builds for these machines:
inherit (emulated) servo desko desko-light lappy lappy-light rescue;
# prefer cross-compiled builds for these machines:
inherit (cross) moby moby-light;
};
# unofficial output # unofficial output
# this produces a EFI-bootable .img file (GPT with a /boot partition and a system (/ or /nix) partition). # this produces a EFI-bootable .img file (GPT with a /boot partition and a system (/ or /nix) partition).
@@ -192,9 +179,12 @@
# unofficial output # unofficial output
hostConfigs = mapAttrValues (host: host.config) self.nixosConfigurations; hostConfigs = mapAttrValues (host: host.config) self.nixosConfigurations;
hostSystems = mapAttrValues (host: host.config.system.build.toplevel) self.nixosConfigurations;
hostPkgs = mapAttrValues (host: host.config.system.build.pkgs) self.nixosConfigurations; hostPkgs = mapAttrValues (host: host.config.system.build.pkgs) self.nixosConfigurations;
hostPrograms = mapAttrValues (host: mapAttrValues (p: p.package) host.config.sane.programs) self.nixosConfigurations; hostPrograms = mapAttrValues (host: mapAttrValues (p: p.package) host.config.sane.programs) self.nixosConfigurations;
patched.nixpkgs = nixpkgs';
overlays = { overlays = {
# N.B.: `nix flake check` requires every overlay to take `final: prev:` at defn site, # N.B.: `nix flake check` requires every overlay to take `final: prev:` at defn site,
# hence the weird redundancy. # hence the weird redundancy.
@@ -208,7 +198,7 @@
passthru = final: prev: passthru = final: prev:
let let
mobile = (import "${mobile-nixos}/overlay/overlay.nix"); mobile = (import "${mobile-nixos}/overlay/overlay.nix");
uninsane = uninsane-dot-org.overlay; uninsane = uninsane-dot-org.overlays.default;
in in
(mobile final prev) (mobile final prev)
// (uninsane final prev) // (uninsane final prev)
@@ -239,23 +229,27 @@
# extract only our own packages from the full set. # extract only our own packages from the full set.
# because of `nix flake check`, we flatten the package set and only surface x86_64-linux packages. # because of `nix flake check`, we flatten the package set and only surface x86_64-linux packages.
packages = mapAttrs packages = mapAttrs
(system: allPkgs: (system: passthruPkgs: passthruPkgs.lib.filterAttrs
allPkgs.lib.filterAttrs (name: pkg: (name: pkg:
# keep only packages which will pass `nix flake check`, i.e. keep only: # keep only packages which will pass `nix flake check`, i.e. keep only:
# - derivations (not package sets) # - derivations (not package sets)
# - packages that build for the given platform # - packages that build for the given platform
(! elem name [ "feeds" "pythonPackagesExtensions" ]) (! elem name [ "feeds" "pythonPackagesExtensions" ])
&& (allPkgs.lib.meta.availableOn allPkgs.stdenv.hostPlatform pkg) && (passthruPkgs.lib.meta.availableOn passthruPkgs.stdenv.hostPlatform pkg)
) )
( (
# expose sane packages and chosen inputs (uninsane.org) # expose sane packages and chosen inputs (uninsane.org)
(import ./pkgs { pkgs = allPkgs; }) // { (import ./pkgs { pkgs = passthruPkgs; }) // {
inherit (allPkgs) uninsane-dot-org; inherit (passthruPkgs) uninsane-dot-org;
} }
) )
) )
# self.legacyPackages; # self.legacyPackages;
{ inherit (self.legacyPackages) x86_64-linux; } {
x86_64-linux = (nixpkgsCompiledBy "x86_64-linux").appendOverlays [
self.overlays.passthru
];
}
; ;
apps."x86_64-linux" = apps."x86_64-linux" =
@@ -263,13 +257,18 @@
pkgs = self.legacyPackages."x86_64-linux"; pkgs = self.legacyPackages."x86_64-linux";
sanePkgs = import ./pkgs { inherit pkgs; }; sanePkgs = import ./pkgs { inherit pkgs; };
deployScript = host: addr: action: pkgs.writeShellScript "deploy-${host}" '' deployScript = host: addr: action: pkgs.writeShellScript "deploy-${host}" ''
nix build '.#nixosConfigurations.${host}.config.system.build.toplevel' --out-link ./result-${host} $@ nix build '.#nixosConfigurations.${host}.config.system.build.toplevel' --out-link ./result-${host} "$@"
sudo nix sign-paths -r -k /run/secrets/nix_serve_privkey $(readlink ./result-${host}) sudo nix sign-paths -r -k /run/secrets/nix_serve_privkey $(readlink ./result-${host})
# XXX: this triggers another config eval & (potentially) build. # XXX: this triggers another config eval & (potentially) build.
# if the config changed between these invocations, the above signatures might not apply to the deployed config. # if the config changed between these invocations, the above signatures might not apply to the deployed config.
# let the user handle that edge case by re-running this whole command # let the user handle that edge case by re-running this whole command.
nixos-rebuild --flake '.#${host}' ${action} --target-host colin@${addr} --use-remote-sudo $@ # N.B.: `--fast` option here is critical to cross-compiled deployments: without it the build machine will try to invoke the host machine's `nix` binary.
# TODO: solve this by replacing the nixos-build invocation with:
# - nix-copy-closure --to $host $result
# - on target: nix-env set -p /nix/var/nix/profiles/system $result
# - on target: $result/bin/switch-to-configuration
nixos-rebuild --flake '.#${host}' ${action} --target-host colin@${addr} --use-remote-sudo "$@" --fast
''; '';
deployApp = host: addr: action: { deployApp = host: addr: action: {
type = "app"; type = "app";
@@ -380,23 +379,47 @@
servo = deployApp "servo" "servo" "switch"; servo = deployApp "servo" "servo" "switch";
}; };
sync-moby = { sync = {
# copy music from the current device to moby
# TODO: should i actually sync from /mnt/servo-media/Music instead of the local drive?
type = "app"; type = "app";
program = builtins.toString (pkgs.writeShellScript "sync-to-moby" '' program = builtins.toString (pkgs.writeShellScript "sync-all" ''
sudo mount /mnt/moby-home RC_lappy=$(nix run '.#sync.lappy' -- "$@")
${pkgs.sane-scripts.sync-music}/bin/sane-sync-music ~/Music /mnt/moby-home/Music RC_moby=$(nix run '.#sync.moby' -- "$@")
RC_desko=$(nix run '.#sync.desko' -- "$@")
echo "lappy: $RC_lappy"
echo "moby: $RC_moby"
echo "desko: $RC_desko"
''); '');
}; };
sync-lappy = { sync.desko = {
# copy music from servo to desko
# can run this from any device that has ssh access to desko and servo
type = "app";
program = builtins.toString (pkgs.writeShellScript "sync-to-desko" ''
sudo mount /mnt/desko-home
${pkgs.sane-scripts.sync-music}/bin/sane-sync-music --compat /mnt/servo-media/Music /mnt/desko-home/Music "$@"
'');
};
sync.lappy = {
# copy music from servo to lappy # copy music from servo to lappy
# can run this from any device that has ssh access to lappy # can run this from any device that has ssh access to lappy and servo
type = "app"; type = "app";
program = builtins.toString (pkgs.writeShellScript "sync-to-lappy" '' program = builtins.toString (pkgs.writeShellScript "sync-to-lappy" ''
sudo mount /mnt/lappy-home sudo mount /mnt/lappy-home
${pkgs.sane-scripts.sync-music}/bin/sane-sync-music /mnt/servo-media/Music /mnt/lappy-home/Music ${pkgs.sane-scripts.sync-music}/bin/sane-sync-music --compress --compat /mnt/servo-media/Music /mnt/lappy-home/Music "$@"
'');
};
sync.moby = {
# copy music from servo to moby
# can run this from any device that has ssh access to moby and servo
type = "app";
program = builtins.toString (pkgs.writeShellScript "sync-to-moby" ''
sudo mount /mnt/moby-home
# N.B.: limited by network/disk -> reduce job count to improve pause/resume behavior
${pkgs.sane-scripts.sync-music}/bin/sane-sync-music --compress --compat --jobs 4 /mnt/servo-media/Music /mnt/moby-home/Music "$@"
''); '');
}; };
@@ -405,12 +428,12 @@
program = builtins.toString (pkgs.writeShellScript "check-all" '' program = builtins.toString (pkgs.writeShellScript "check-all" ''
nix run '.#check.nur' nix run '.#check.nur'
RC0=$? RC0=$?
nix run '.#check.host-configs' nix run '.#check.hostConfigs'
RC1=$? RC1=$?
nix run '.#check.rescue' nix run '.#check.rescue'
RC2=$? RC2=$?
echo "nur: $RC0" echo "nur: $RC0"
echo "host-configs: $RC1" echo "hostConfigs: $RC1"
echo "rescue: $RC2" echo "rescue: $RC2"
exit $(($RC0 | $RC1 | $RC2)) exit $(($RC0 | $RC1 | $RC2))
''); '');
@@ -427,19 +450,19 @@
--option restrict-eval true \ --option restrict-eval true \
--option allow-import-from-derivation true \ --option allow-import-from-derivation true \
--drv-path --show-trace \ --drv-path --show-trace \
-I nixpkgs=$(nix-instantiate --find-file nixpkgs) \ -I nixpkgs=${nixpkgs-unpatched} \
-I ../../ \ -I ../../ \
| tee # tee to prevent interactive mode | tee # tee to prevent interactive mode
''); '');
}; };
check.host-configs = { check.hostConfigs = {
type = "app"; type = "app";
program = let program = let
checkHost = host: let checkHost = host: let
shellHost = pkgs.lib.replaceStrings [ "-" ] [ "_" ] host; shellHost = pkgs.lib.replaceStrings [ "-" ] [ "_" ] host;
in '' in ''
nix build -v '.#nixosConfigurations.${host}.config.system.build.toplevel' --out-link ./result-${host} -j2 $@ nix build -v '.#nixosConfigurations.${host}.config.system.build.toplevel' --out-link ./result-${host} -j2 "$@"
RC_${shellHost}=$? RC_${shellHost}=$?
''; '';
in builtins.toString (pkgs.writeShellScript in builtins.toString (pkgs.writeShellScript
@@ -457,11 +480,29 @@
${checkHost "moby"} ${checkHost "moby"}
${checkHost "rescue"} ${checkHost "rescue"}
# still want to build the -light variants first so as to avoid multiple simultaneous webkitgtk builds
${checkHost "desko-light-next"}
${checkHost "moby-light-next"}
${checkHost "desko-next"}
${checkHost "lappy-next"}
${checkHost "servo-next"}
${checkHost "moby-next"}
${checkHost "rescue-next"}
echo "desko: $RC_desko" echo "desko: $RC_desko"
echo "lappy: $RC_lappy" echo "lappy: $RC_lappy"
echo "servo: $RC_servo" echo "servo: $RC_servo"
echo "moby: $RC_moby" echo "moby: $RC_moby"
echo "rescue: $RC_rescue" echo "rescue: $RC_rescue"
echo "desko-next: $RC_desko_next"
echo "lappy-next: $RC_lappy_next"
echo "servo-next: $RC_servo_next"
echo "moby-next: $RC_moby_next"
echo "rescue-next: $RC_rescue_next"
# i don't really care if the -next hosts fail. i build them mostly to keep the cache fresh/ready
exit $(($RC_desko | $RC_lappy | $RC_servo | $RC_moby | $RC_rescue)) exit $(($RC_desko | $RC_lappy | $RC_servo | $RC_moby | $RC_rescue))
'' ''
); );

View File

@@ -9,6 +9,9 @@
# services.distccd.enable = true; # services.distccd.enable = true;
# sane.programs.distcc.enableFor.user.guest = true; # sane.programs.distcc.enableFor.user.guest = true;
# TODO: remove emulation, but need to fix nixos-rebuild to moby for that.
# sane.roles.build-machine.emulation = true;
sops.secrets.colin-passwd.neededForUsers = true; sops.secrets.colin-passwd.neededForUsers = true;
sane.ports.openFirewall = true; # for e.g. nix-serve sane.ports.openFirewall = true; # for e.g. nix-serve

View File

@@ -22,7 +22,6 @@
# the device type informs (at least): # the device type informs (at least):
# - SXMO_WIFI_MODULE # - SXMO_WIFI_MODULE
# - SXMO_RTW_SCAN_INTERVAL # - SXMO_RTW_SCAN_INTERVAL
# - SXMO_SYS_FILES
# - SXMO_TOUCHSCREEN_ID # - SXMO_TOUCHSCREEN_ID
# - SXMO_MONITOR # - SXMO_MONITOR
# - SXMO_ALSA_CONTROL_NAME # - SXMO_ALSA_CONTROL_NAME

View File

@@ -36,7 +36,6 @@
# sane.programs.consoleUtils.enableFor.user.colin = false; # sane.programs.consoleUtils.enableFor.user.colin = false;
# sane.programs.guiApps.enableFor.user.colin = false; # sane.programs.guiApps.enableFor.user.colin = false;
sane.programs.blueberry.enableFor.user.colin = false; # bluetooth manager: doesn't cross compile! sane.programs.blueberry.enableFor.user.colin = false; # bluetooth manager: doesn't cross compile!
sane.programs.dialect.enableFor.user.colin = false; # drags in 700MB of x86 dependencies (e.g. gtk4)
sane.programs.mercurial.enableFor.user.colin = false; # does not cross compile sane.programs.mercurial.enableFor.user.colin = false; # does not cross compile
sane.programs.nvme-cli.enableFor.system = false; # does not cross compile (libhugetlbfs) sane.programs.nvme-cli.enableFor.system = false; # does not cross compile (libhugetlbfs)

View File

@@ -74,6 +74,7 @@ in
# without this some GUI apps fail: `DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory` # without this some GUI apps fail: `DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory`
# this is because they can't allocate enough video ram. # this is because they can't allocate enough video ram.
# see related nixpkgs issue: <https://github.com/NixOS/nixpkgs/issues/260222> # see related nixpkgs issue: <https://github.com/NixOS/nixpkgs/issues/260222>
# TODO(2023/12/03): remove once mesa 23.3.1 lands: <https://github.com/NixOS/nixpkgs/pull/265740>
# #
# the default CMA seems to be 32M. # the default CMA seems to be 32M.
# i was running fine with 256MB from 2022/07-ish through 2022/12-ish, but then the phone quit reliably coming back from sleep (phosh): maybe a memory leak? # i was running fine with 256MB from 2022/07-ish through 2022/12-ish, but then the phone quit reliably coming back from sleep (phosh): maybe a memory leak?

View File

@@ -15,9 +15,9 @@
}; };
sane.roles.build-machine.enable = true; sane.roles.build-machine.enable = true;
sane.roles.build-machine.emulation = false;
sane.zsh.showDeadlines = false; # ~/knowledge doesn't always exist sane.zsh.showDeadlines = false; # ~/knowledge doesn't always exist
sane.programs.consoleUtils.suggestedPrograms = [ sane.programs.consoleUtils.suggestedPrograms = [
"consoleMediaUtils" # notably, for go2tv / casting
"pcConsoleUtils" "pcConsoleUtils"
"sane-scripts.stop-all-servo" "sane-scripts.stop-all-servo"
]; ];

View File

@@ -1,6 +1,57 @@
# zfs docs:
# - <https://nixos.wiki/wiki/ZFS>
# - <repo:nixos/nixpkgs:nixos/modules/tasks/filesystems/zfs.nix>
#
# zfs check health: `zpool status`
#
# zfs pool creation (requires `boot.supportedFilesystems = [ "zfs" ];`
# - 1. identify disk IDs: `ls -l /dev/disk/by-id`
# - 2. pool these disks: `zpool create -f -m legacy pool raidz ata-ST4000VN008-2DR166_WDH0VB45 ata-ST4000VN008-2DR166_WDH17616 ata-ST4000VN008-2DR166_WDH0VC8Q ata-ST4000VN008-2DR166_WDH17680`
# - legacy documented: <https://superuser.com/questions/790036/what-is-a-zfs-legacy-mount-point>
#
# import pools: `zpool import pool`
# show zfs datasets: `zfs list` (will be empty if haven't imported)
# show zfs properties (e.g. compression): `zfs get all pool`
# set zfs properties: `zfs set compression=on pool`
{ ... }: { ... }:
{ {
# hostId: not used for anything except zfs guardrail?
# [hex(ord(x)) for x in 'serv']
networking.hostId = "73657276";
boot.supportedFilesystems = [ "zfs" ];
# boot.zfs.enabled = true;
boot.zfs.forceImportRoot = false;
# scrub all zfs pools weekly:
services.zfs.autoScrub.enable = true;
boot.extraModprobeConfig = ''
# ZFS likes to use half the ram for its own cache and let the kernel push everything else to swap.
# so, reduce its cache size
# see: <https://askubuntu.com/a/1290387>
# see: <https://serverfault.com/a/1119083>
# see: <https://openzfs.github.io/openzfs-docs/Performance%20and%20Tuning/Module%20Parameters.html#zfs-arc-max>
# for all tunables, see: `man 4 zfs`
# to update these parameters without rebooting:
# - `echo '4294967296' | sane-sudo-redirect /sys/module/zfs/parameters/zfs_arc_max`
options zfs zfs_arc_max=4294967296
'';
# to be able to mount the pool like this, make sure to tell zfs to NOT manage it itself.
# otherwise local-fs.target will FAIL and you will be dropped into a rescue shell.
# - `zfs set mountpoint=legacy pool`
# if done correctly, the pool can be mounted before this `fileSystems` entry is created:
# - `sudo mount -t zfs pool /mnt/persist/pool`
fileSystems."/mnt/pool" = {
device = "pool";
fsType = "zfs";
};
# services.zfs.zed = ... # TODO: zfs can send me emails when disks fail
sane.programs.sysadminUtils.suggestedPrograms = [ "zfs" ];
sane.persist.stores."ext" = {
origin = "/mnt/pool/persist";
storeDescription = "external HDD storage";
};
# increase /tmp space (defaults to 50% of RAM) for building large nix things. # increase /tmp space (defaults to 50% of RAM) for building large nix things.
# even the stock `nixpkgs.linux` consumes > 16 GB of tmp # even the stock `nixpkgs.linux` consumes > 16 GB of tmp
fileSystems."/tmp".options = [ "size=32G" ]; fileSystems."/tmp".options = [ "size=32G" ];
@@ -20,7 +71,7 @@
}; };
# slow, external storage (for archiving, etc) # slow, external storage (for archiving, etc)
fileSystems."/mnt/persist/ext" = { fileSystems."/mnt/usb-hdd" = {
device = "/dev/disk/by-uuid/aa272cff-0fcc-498e-a4cb-0d95fb60631b"; device = "/dev/disk/by-uuid/aa272cff-0fcc-498e-a4cb-0d95fb60631b";
fsType = "btrfs"; fsType = "btrfs";
options = [ options = [
@@ -28,12 +79,7 @@
"defaults" "defaults"
]; ];
}; };
sane.fs."/mnt/usb-hdd".mount = {};
sane.persist.stores."ext" = {
origin = "/mnt/persist/ext/persist";
storeDescription = "external HDD storage";
};
sane.fs."/mnt/persist/ext".mount = {};
sane.persist.sys.byStore.plaintext = [ sane.persist.sys.byStore.plaintext = [
# TODO: this is overly broad; only need media and share directories to be persisted # TODO: this is overly broad; only need media and share directories to be persisted

View File

@@ -27,9 +27,7 @@ in
# view refused packets with: `sudo journalctl -k` # view refused packets with: `sudo journalctl -k`
# networking.firewall.logRefusedPackets = true; # networking.firewall.logRefusedPackets = true;
# The global useDHCP flag is deprecated, therefore explicitly set to false here. # these useDHCP lines are legacy from the auto-generated config. might be safe to remove now?
# Per-interface useDHCP will be mandatory in the future, so this generated config
# replicates the default behaviour.
networking.useDHCP = false; networking.useDHCP = false;
networking.interfaces.eth0.useDHCP = true; networking.interfaces.eth0.useDHCP = true;
# XXX colin: probably don't need this. wlan0 won't be populated unless i touch a value in networking.interfaces.wlan0 # XXX colin: probably don't need this. wlan0 won't be populated unless i touch a value in networking.interfaces.wlan0
@@ -44,41 +42,6 @@ in
# "9.9.9.9" # "9.9.9.9"
# ]; # ];
# use systemd's stub resolver.
# /etc/resolv.conf isn't sophisticated enough to use different servers per net namespace (or link).
# instead, running the stub resolver on a known address in the root ns lets us rewrite packets
# in the ovnps namespace to use the provider's DNS resolvers.
# a weakness is we can only query 1 NS at a time (unless we were to clone the packets?)
# there also seems to be some cache somewhere that's shared between the two namespaces.
# i think this is a libc thing. might need to leverage proper cgroups to _really_ kill it.
# - getent ahostsv4 www.google.com
# - try fix: <https://serverfault.com/questions/765989/connect-to-3rd-party-vpn-server-but-dont-use-it-as-the-default-route/766290#766290>
services.resolved.enable = true;
# without DNSSEC:
# - dig matrix.org => works
# - curl https://matrix.org => works
# with default DNSSEC:
# - dig matrix.org => works
# - curl https://matrix.org => fails
# i don't know why. this might somehow be interfering with the DNS run on this device (trust-dns)
services.resolved.dnssec = "false";
networking.nameservers = [
# use systemd-resolved resolver
# full resolver (which understands /etc/hosts) lives on 127.0.0.53
# stub resolver (just forwards upstream) lives on 127.0.0.54
"127.0.0.53"
];
# nscd -- the Name Service Caching Daemon -- caches DNS query responses
# in a way that's unaware of my VPN routing, so routes are frequently poor against
# services which advertise different IPs based on geolocation.
# nscd claims to be usable without a cache, but in practice i can't get it to not cache!
# nsncd is the Name Service NON-Caching Daemon. it's a drop-in that doesn't cache;
# this is OK on the host -- because systemd-resolved caches. it's probably sub-optimal
# in the netns and we query upstream DNS more often than needed. hm.
# TODO: run a separate recursive resolver in each namespace.
services.nscd.enableNsncd = true;
# services.resolved.extraConfig = '' # services.resolved.extraConfig = ''
# # docs: `man resolved.conf` # # docs: `man resolved.conf`
# # DNS servers to use via the `wg-ovpns` interface. # # DNS servers to use via the `wg-ovpns` interface.

View File

@@ -0,0 +1,84 @@
# as of 2023/12/02: complete blockchain is 530 GiB (on-disk size may be larger)
#
# ports:
# - 8333: for node-to-node communications
# - 8332: rpc (client-to-node)
#
# rpc setup:
# - generate a password
# - use: <https://github.com/bitcoin/bitcoin/blob/master/share/rpcauth/rpcauth.py>
# (rpcauth.py is not included in the `'.#bitcoin'` package result)
# - `wget https://raw.githubusercontent.com/bitcoin/bitcoin/master/share/rpcauth/rpcauth.py`
# - `python ./rpcauth.py colin`
# - copy the hash here. it's SHA-256, so safe to be public.
# - add "rpcuser=colin" and "rpcpassword=<output>" to secrets/servo/bitcoin.conf (i.e. ~/.bitcoin/bitcoin.conf)
# - bitcoin.conf docs: <https://github.com/bitcoin/bitcoin/blob/master/doc/bitcoin-conf.md>
# - validate with `bitcoin-cli -netinfo`
{ config, lib, pkgs, sane-lib, ... }:
let
# wrapper to run bitcoind with the tor onion address as externalip (computed at runtime)
_bitcoindWithExternalIp = with pkgs; writeShellScriptBin "bitcoind" ''
externalip="$(cat /var/lib/tor/onion/bitcoind/hostname)"
exec ${bitcoind}/bin/bitcoind "-externalip=$externalip" "$@"
'';
# the package i provide to services.bitcoind ends up on system PATH, and used by other tools like clightning.
# therefore, even though services.bitcoind only needs `bitcoind` binary, provide all the other bitcoin-related binaries (notably `bitcoin-cli`) as well:
bitcoindWithExternalIp = with pkgs; symlinkJoin {
name = "bitcoind-with-external-ip";
paths = [ _bitcoindWithExternalIp bitcoind ];
};
in
{
sane.persist.sys.byStore.ext = [
# /var/lib/monero/lmdb is what consumes most of the space
{ user = "bitcoind-mainnet"; group = "bitcoind-mainnet"; path = "/var/lib/bitcoind-mainnet"; }
];
# sane.ports.ports."8333" = {
# # this allows other nodes and clients to download blocks from me.
# protocol = [ "tcp" ];
# visibleTo.wan = true;
# description = "colin-bitcoin";
# };
services.tor.relay.onionServices.bitcoind = {
version = 3;
map = [{
# by default tor will route public tor port P to 127.0.0.1:P.
# so if this port is the same as clightning would natively use, then no further config is needed here.
# see: <https://2019.www.torproject.org/docs/tor-manual.html.en#HiddenServicePort>
port = 8333;
# target.port; target.addr; #< set if tor port != clightning port
}];
# allow "tor" group (i.e. bitcoind-mainnet) to read /var/lib/tor/onion/bitcoind/hostname
settings.HiddenServiceDirGroupReadable = true;
};
services.bitcoind.mainnet = {
enable = true;
package = bitcoindWithExternalIp;
rpc.users.colin = {
# see docs at top of file for how to generate this
passwordHMAC = "30002c05d82daa210550e17a182db3f3$6071444151281e1aa8a2729f75e3e2d224e9d7cac3974810dab60e7c28ffaae4";
};
extraConfig = ''
# don't load the wallet, and disable wallet RPC calls
disablewallet=1
# proxy all outbound traffic through Tor
proxy=127.0.0.1:9050
'';
};
users.users.bitcoind-mainnet.extraGroups = [ "tor" ];
systemd.services.bitcoind-mainnet.serviceConfig.RestartSec = "30s"; #< default is 0
sane.users.colin.fs.".bitcoin/bitcoin.conf" = sane-lib.fs.wantedSymlinkTo config.sops.secrets."bitcoin.conf".path;
sops.secrets."bitcoin.conf" = {
mode = "0600";
owner = "colin";
group = "users";
};
sane.programs.bitcoind.enableFor.user.colin = true; # for debugging/administration: `bitcoin-cli`
}

View File

@@ -0,0 +1,766 @@
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ps.pyln-client ])"
# pyln-client docs: <https://github.com/ElementsProject/lightning/tree/master/contrib/pyln-client>
# terminology:
# - "scid": "Short Channel ID", e.g. 123456x7890x0
# from this id, we can locate the actual channel, its peers, and its parameters
import argparse
import logging
import math
import sys
import time
from concurrent.futures import ThreadPoolExecutor
from dataclasses import dataclass
from enum import Enum
from pyln.client import LightningRpc, Millisatoshi, RpcError
logger = logging.getLogger(__name__)
RPC_FILE = "/var/lib/clightning/bitcoin/lightning-rpc"
# CLTV (HLTC delta) of the final hop
# set this too low and you might get inadvertent channel closures (?)
CLTV = 18
# for every sequentally failed transaction, delay this much before trying again.
# note that the initial route building process can involve 10-20 "transient" failures, as it discovers dead channels.
TX_FAIL_BACKOFF = 0.8
MAX_SEQUENTIAL_JOB_FAILURES = 200
class LoopError(Enum):
""" error when trying to loop sats, or when unable to calculate a route for the loop """
TRANSIENT = "TRANSIENT" # try again, we'll maybe find a different route
NO_ROUTE = "NO_ROUTE"
class RouteError(Enum):
""" error when calculated a route """
HAS_BASE_FEE = "HAS_BASE_FEE"
NO_ROUTE = "NO_ROUTE"
class Metrics:
looped_msat: int = 0
sendpay_fail: int = 0
sendpay_succeed: int = 0
own_bad_channel: int = 0
no_route: int = 0
in_ch_unsatisfiable: int = 0
def __repr__(self) -> str:
return f"looped:{self.looped_msat}, tx:{self.sendpay_succeed}, tx_fail:{self.sendpay_fail}, own_bad_ch:{self.own_bad_channel}, no_route:{self.no_route}, in_ch_restricted:{self.in_ch_unsatisfiable}"
@dataclass
class TxBounds:
max_msat: int
min_msat: int = 0
def __repr__(self) -> str:
return f"TxBounds({self.min_msat} <= msat <= {self.max_msat})"
def is_satisfiable(self) -> bool:
return self.min_msat <= self.max_msat
def raise_max_to_be_satisfiable(self) -> "Self":
if self.max_msat < self.min_msat:
logger.debug(f"raising max_msat to be consistent: {self.max_msat} -> {self.min_msat}")
return TxBounds(self.min_msat, self.min_msat)
return TxBounds(min_msat=self.min_msat, max_msat=self.max_msat)
def intersect(self, other: "TxBounds") -> "Self":
return TxBounds(
min_msat=max(self.min_msat, other.min_msat),
max_msat=min(self.max_msat, other.max_msat),
)
def restrict_to_htlc(self, ch: "LocalChannel", why: str = "") -> "Self":
"""
apply min/max HTLC size restrictions of the given channel.
"""
if ch:
why = why or ch.directed_scid_to_me
if why: why = f"{why}: "
new_min, new_max = self.min_msat, self.max_msat
if ch.htlc_minimum_to_me > self.min_msat:
new_min = ch.htlc_minimum_to_me
logger.debug(f"{why}raising min_msat due to HTLC requirements: {self.min_msat} -> {new_min}")
if ch.htlc_maximum_to_me < self.max_msat:
new_max = ch.htlc_maximum_to_me
logger.debug(f"{why}lowering max_msat due to HTLC requirements: {self.max_msat} -> {new_max}")
return TxBounds(min_msat=new_min, max_msat=new_max)
def restrict_to_zero_fees(self, ch: "LocalChannel"=None, base: int=0, ppm: int=0, why:str = "") -> "Self":
"""
restrict tx size such that PPM fees are zero.
if the channel has a base fee, then `max_msat` is forced to 0.
"""
if ch:
why = why or ch.directed_scid_to_me
self = self.restrict_to_zero_fees(base=ch.to_me["base_fee_millisatoshi"], ppm=ch.to_me["fee_per_millionth"], why=why)
if why: why = f"{why}: "
new_max = self.max_msat
ppm_max = math.ceil(1000000 / ppm) - 1 if ppm != 0 else new_max
if ppm_max < new_max:
logger.debug(f"{why}decreasing max_msat due to fee ppm: {new_max} -> {ppm_max}")
new_max = ppm_max
if base != 0:
logger.debug(f"{why}free route impossible: channel has base fees")
new_max = 0
return TxBounds(min_msat=self.min_msat, max_msat=new_max)
class LocalChannel:
def __init__(self, channels: list, rpc: "RpcHelper"):
assert 0 < len(channels) <= 2, f"unexpected: channel count: {channels}"
out = None
in_ = None
for c in channels:
if c["source"] == rpc.self_id:
assert out is None, f"unexpected: multiple channels from self: {channels}"
out = c
if c["destination"] == rpc.self_id:
assert in_ is None, f"unexpected: multiple channels to self: {channels}"
in_ = c
# assert out is not None, f"no channel from self: {channels}"
# assert in_ is not None, f"no channel to self: {channels}"
if out and in_:
assert out["destination"] == in_["source"], f"channel peers are asymmetric?! {channels}"
assert out["short_channel_id"] == in_["short_channel_id"], f"channel ids differ?! {channels}"
self.from_me = out
self.to_me = in_
self.remote_node = rpc.node(self.remote_peer)
self.peer_ch = rpc.peerchannel(self.scid, self.remote_peer)
self.forwards_from_me = rpc.rpc.listforwards(out_channel=self.scid, status="settled")["forwards"]
def __repr__(self) -> str:
return self.to_str(with_scid=True, with_bal_ratio=True, with_cost=False, with_ppm_theirs=False)
def to_str(
self,
with_peer_id:bool = False,
with_scid:bool = False,
with_bal_msat:bool = False,
with_bal_ratio:bool = False,
with_cost:bool = False,
with_ppm_theirs:bool = False,
with_ppm_mine:bool = False,
with_profits:bool = True,
with_payments:bool = False,
) -> str:
base_flag = "*" if not self.online or self.base_fee_to_me != 0 else ""
alias = f"({self.remote_alias}){base_flag}"
peerid = f" {self.remote_peer}" if with_peer_id else ""
scid = f" scid:{self.scid:>13}" if with_scid else ""
bal = f" S:{int(self.sendable):11}/R:{int(self.receivable):11}" if with_bal_msat else ""
ratio = f" MINE:{(100*self.send_ratio):>8.4f}%" if with_bal_ratio else ""
payments = f" OUT:{int(self.out_fulfilled_msat):>11}/IN:{int(self.in_fulfilled_msat):>11}" if with_payments else ""
profits = f" P$:{int(self.fees_lifetime_mine):>8}" if with_profits else ""
cost = f" COST:{self.opportunity_cost_lent:>8}" if with_cost else ""
ppm_theirs = self.ppm_to_me if self.to_me else "N/A"
ppm_theirs = f" PPM_THEIRS:{ppm_theirs:>6}" if with_ppm_theirs else ""
ppm_mine = self.ppm_from_me if self.from_me else "N/A"
ppm_mine = f" PPM_MINE:{ppm_mine:>6}" if with_ppm_mine else ""
return f"channel{alias:30}{peerid}{scid}{bal}{ratio}{payments}{profits}{cost}{ppm_theirs}{ppm_mine}"
@property
def online(self) -> bool:
return self.from_me and self.to_me
@property
def remote_peer(self) -> str:
if self.from_me:
return self.from_me["destination"]
else:
return self.to_me["source"]
@property
def remote_alias(self) -> str:
return self.remote_node["alias"]
@property
def scid(self) -> str:
if self.from_me:
return self.from_me["short_channel_id"]
else:
return self.to_me["short_channel_id"]
@property
def htlc_minimum_to_me(self) -> Millisatoshi:
return self.to_me["htlc_minimum_msat"]
@property
def htlc_minimum_from_me(self) -> Millisatoshi:
return self.from_me["htlc_minimum_msat"]
@property
def htlc_minimum(self) -> Millisatoshi:
return max(self.htlc_minimum_to_me, self.htlc_minimum_from_me)
@property
def htlc_maximum_to_me(self) -> Millisatoshi:
return self.to_me["htlc_maximum_msat"]
@property
def htlc_maximum_from_me(self) -> Millisatoshi:
return self.from_me["htlc_maximum_msat"]
@property
def htlc_maximum(self) -> Millisatoshi:
return min(self.htlc_maximum_to_me, self.htlc_maximum_from_me)
@property
def direction_to_me(self) -> int:
return self.to_me["direction"]
@property
def direction_from_me(self) -> int:
return self.from_me["direction"]
@property
def directed_scid_to_me(self) -> str:
return f"{self.scid}/{self.direction_to_me}"
@property
def directed_scid_from_me(self) -> str:
return f"{self.scid}/{self.direction_from_me}"
@property
def delay_them(self) -> str:
return self.to_me["delay"]
@property
def delay_me(self) -> str:
return self.from_me["delay"]
@property
def ppm_to_me(self) -> int:
return self.to_me["fee_per_millionth"]
@property
def ppm_from_me(self) -> int:
return self.from_me["fee_per_millionth"]
# return self.peer_ch["fee_proportional_millionths"]
@property
def base_fee_to_me(self) -> int:
return self.to_me["base_fee_millisatoshi"]
@property
def receivable(self) -> int:
return self.peer_ch["receivable_msat"]
@property
def sendable(self) -> int:
return self.peer_ch["spendable_msat"]
@property
def in_fulfilled_msat(self) -> Millisatoshi:
return self.peer_ch["in_fulfilled_msat"]
@property
def out_fulfilled_msat(self) -> Millisatoshi:
return self.peer_ch["out_fulfilled_msat"]
@property
def fees_lifetime_mine(self) -> Millisatoshi:
return sum(fwd["fee_msat"] for fwd in self.forwards_from_me)
@property
def send_ratio(self) -> float:
cap = self.receivable + self.sendable
return self.sendable / cap
@property
def opportunity_cost_lent(self) -> int:
""" how much msat did we gain by pushing their channel to its current balance? """
return int(self.receivable * self.ppm_from_me / 1000000)
class RpcHelper:
def __init__(self, rpc: LightningRpc):
self.rpc = rpc
self.self_id = rpc.getinfo()["id"]
def localchannel(self, scid: str) -> LocalChannel:
listchan = self.rpc.listchannels(scid)
# this assertion would probably indicate a typo in the scid
assert listchan and listchan.get("channels", []) != [], f"bad listchannels for {scid}: {listchan}"
return LocalChannel(listchan["channels"], self)
def node(self, id: str) -> dict:
nodes = self.rpc.listnodes(id)["nodes"]
assert len(nodes) == 1, f"unexpected: multiple nodes for {id}: {nodes}"
return nodes[0]
def peerchannel(self, scid: str, peer_id: str) -> dict:
peerchannels = self.rpc.listpeerchannels(peer_id)["channels"]
channels = [c for c in peerchannels if c["short_channel_id"] == scid]
assert len(channels) == 1, f"expected exactly 1 channel, got: {channels}"
return channels[0]
def try_getroute(self, *args, **kwargs) -> dict | None:
""" wrapper for getroute which returns None instead of error if no route exists """
try:
route = self.rpc.getroute(*args, **kwargs)
except RpcError as e:
logger.debug(f"rpc failed: {e}")
return None
else:
route = route["route"]
if route == []: return None
return route
class LoopRouter:
def __init__(self, rpc: RpcHelper, metrics: Metrics = None):
self.rpc = rpc
self.metrics = metrics or Metrics()
self.bad_channels = [] # list of directed scid
self.nonzero_base_channels = [] # list of directed scid
def drop_caches(self) -> None:
logger.info("LoopRouter.drop_caches()")
self.bad_channels = []
def _get_directed_scid(self, scid: str, direction: int) -> dict:
channels = self.rpc.rpc.listchannels(scid)["channels"]
channels = [c for c in channels if c["direction"] == direction]
assert len(channels) == 1, f"expected exactly 1 channel: {channels}"
return channels[0]
def loop_once(self, out_scid: str, in_scid: str, bounds: TxBounds) -> LoopError|int:
out_ch = self.rpc.localchannel(out_scid)
in_ch = self.rpc.localchannel(in_scid)
if out_ch.directed_scid_from_me in self.bad_channels or in_ch.directed_scid_to_me in self.bad_channels:
logger.info(f"loop {out_scid} -> {in_scid} failed in our own channel")
self.metrics.own_bad_channel += 1
return LoopError.TRANSIENT
# bounds = bounds.restrict_to_htlc(out_ch) # htlc bounds seem to be enforced only in the outward direction
bounds = bounds.restrict_to_htlc(in_ch)
bounds = bounds.restrict_to_zero_fees(in_ch)
if not bounds.is_satisfiable():
self.metrics.in_ch_unsatisfiable += 1
return LoopError.NO_ROUTE
logger.debug(f"route with bounds {bounds}")
route = self.route(out_ch, in_ch, bounds)
logger.debug(f"route: {route}")
if route == RouteError.NO_ROUTE:
self.metrics.no_route += 1
return LoopError.NO_ROUTE
elif route == RouteError.HAS_BASE_FEE:
# try again with a different route
return LoopError.TRANSIENT
amount_msat = route[0]["amount_msat"]
invoice_id = f"loop-{time.time():.6f}".replace(".", "_")
invoice_desc = f"bal {out_scid}:{in_scid}"
invoice = self.rpc.rpc.invoice("any", invoice_id, invoice_desc)
logger.debug(f"invoice: {invoice}")
payment = self.rpc.rpc.sendpay(route, invoice["payment_hash"], invoice_id, amount_msat, invoice["bolt11"], invoice["payment_secret"])
logger.debug(f"sent: {payment}")
try:
wait = self.rpc.rpc.waitsendpay(invoice["payment_hash"])
logger.debug(f"result: {wait}")
except RpcError as e:
self.metrics.sendpay_fail += 1
err_data = e.error["data"]
err_scid, err_dir = err_data["erring_channel"], err_data["erring_direction"]
err_directed_scid = f"{err_scid}/{err_dir}"
logger.debug(f"ch failed, adding to excludes: {err_directed_scid}; {e.error}")
self.bad_channels.append(err_directed_scid)
return LoopError.TRANSIENT
else:
self.metrics.sendpay_succeed += 1
self.metrics.looped_msat += int(amount_msat)
return int(amount_msat)
def route(self, out_ch: LocalChannel, in_ch: LocalChannel, bounds: TxBounds) -> list[dict] | RouteError:
exclude = [
# ensure the payment doesn't cross either channel in reverse.
# note that this doesn't preclude it from taking additional trips through self, with other peers.
# out_ch.directed_scid_to_me,
# in_ch.directed_scid_from_me,
# alternatively, never route through self. this avoids a class of logic error, like what to do with fees i charge "myself".
self.rpc.self_id
] + self.bad_channels + self.nonzero_base_channels
out_peer = out_ch.remote_peer
in_peer = in_ch.remote_peer
route_or_bounds = bounds
while isinstance(route_or_bounds, TxBounds):
old_bounds = route_or_bounds
route_or_bounds = self._find_partial_route(out_peer, in_peer, old_bounds, exclude=exclude)
if route_or_bounds == old_bounds:
return RouteError.NO_ROUTE
if isinstance(route_or_bounds, RouteError):
return route_or_bounds
route = self._add_route_endpoints(route_or_bounds, out_ch, in_ch)
return route
def _find_partial_route(self, out_peer: str, in_peer: str, bounds: TxBounds, exclude: list[str]=[]) -> list[dict] | RouteError | TxBounds:
route = self.rpc.try_getroute(in_peer, amount_msat=bounds.max_msat, riskfactor=0, fromid=out_peer, exclude=exclude, cltv=CLTV)
if route is None:
logger.debug(f"no route for {bounds.max_msat}msat {out_peer} -> {in_peer}")
return RouteError.NO_ROUTE
send_msat = route[0]["amount_msat"]
if send_msat != Millisatoshi(bounds.max_msat):
logger.debug(f"found route with non-zero fee: {send_msat} -> {bounds.max_msat}. {route}")
error = None
for hop in route:
hop_scid = hop["channel"]
hop_dir = hop["direction"]
directed_scid = f"{hop_scid}/{hop_dir}"
ch = self._get_directed_scid(hop_scid, hop_dir)
if ch["base_fee_millisatoshi"] != 0:
self.nonzero_base_channels.append(directed_scid)
error = RouteError.HAS_BASE_FEE
bounds = bounds.restrict_to_zero_fees(ppm=ch["fee_per_millionth"], why=directed_scid)
return bounds.raise_max_to_be_satisfiable() if error is None else error
return route
def _add_route_endpoints(self, route, out_ch: LocalChannel, in_ch: LocalChannel):
inbound_hop = dict(
id=self.rpc.self_id,
channel=in_ch.scid,
direction=in_ch.direction_to_me,
amount_msat=route[-1]["amount_msat"],
delay=route[-1]["delay"],
style="tlv",
)
route = self._add_route_delay(route, in_ch.delay_them) + [ inbound_hop ]
outbound_hop = dict(
id=out_ch.remote_peer,
channel=out_ch.scid,
direction=out_ch.direction_from_me,
amount_msat=route[0]["amount_msat"],
delay=route[0]["delay"] + out_ch.delay_them,
style="tlv",
)
route = [ outbound_hop ] + route
return route
def _add_route_delay(self, route: list[dict], delay: int) -> list[dict]:
return [ dict(hop, delay=hop["delay"] + delay) for hop in route ]
@dataclass
class LoopJob:
out: str # scid
in_: str # scid
amount: int
@dataclass
class LoopJobIdle:
sec: int = 10
class LoopJobDone(Enum):
COMPLETED = "COMPLETED"
ABORTED = "ABORTED"
class AbstractLoopRunner:
def __init__(self, looper: LoopRouter, bounds: TxBounds, parallelism: int):
self.looper = looper
self.bounds = bounds
self.parallelism = parallelism
self.bounds_map = {} # map (out:str, in_:str) -> TxBounds. it's a cache so we don't have to try 10 routes every time.
def pop_job(self) -> LoopJob | LoopJobIdle | LoopJobDone:
raise NotImplemented # abstract method
def finished_job(self, job: LoopJob, progress: int|LoopError) -> None:
raise NotImplemented # abstract method
def run_to_completion(self, exit_on_any_completed:bool = False) -> None:
self.exiting = False
self.exit_on_any_completed = exit_on_any_completed
if self.parallelism == 1:
# run inline to aid debugging
self._worker_thread()
else:
with ThreadPoolExecutor(max_workers=self.parallelism) as executor:
_ = list(executor.map(lambda _i: self._try_invoke(self._worker_thread), range(self.parallelism)))
def drop_caches(self) -> None:
logger.info("AbstractLoopRunner.drop_caches()")
self.looper.drop_caches()
self.bounds_map = {}
def _try_invoke(self, f, *args) -> None:
"""
try to invoke `f` with the provided `args`, and log if it fails.
this overcomes the issue that background tasks which fail via Exception otherwise do so silently.
"""
try:
f(*args)
except Exception as e:
logger.error(f"task failed: {e}")
def _worker_thread(self) -> None:
while not self.exiting:
job = self.pop_job()
logger.debug(f"popped job: {job}")
if isinstance(job, LoopJobDone):
return self._worker_finished(job)
if isinstance(job, LoopJobIdle):
logger.debug(f"idling for {job.sec}")
time.sleep(job.sec)
continue
result = self._execute_job(job)
logger.debug(f"finishing job {job} with {result}")
self.finished_job(job, result)
def _execute_job(self, job: LoopJob) -> LoopError|int:
bounds = self.bounds_map.get((job.out, job.in_), self.bounds)
bounds = bounds.intersect(TxBounds(max_msat=job.amount))
if not bounds.is_satisfiable():
logger.debug(f"TxBounds for job are unsatisfiable; skipping: {bounds} {job}")
return LoopError.NO_ROUTE
amt_looped = self.looper.loop_once(job.out, job.in_, bounds)
if amt_looped in (0, LoopError.NO_ROUTE, LoopError.TRANSIENT):
return amt_looped
logger.info(f"looped {amt_looped} from {job.out} -> {job.in_}")
bounds = bounds.intersect(TxBounds(max_msat=amt_looped))
self.bounds_map[(job.out, job.in_)] = bounds
return amt_looped
def _worker_finished(self, job: LoopJobDone) -> None:
if job == LoopJobDone.COMPLETED and self.exit_on_any_completed:
logger.debug(f"worker completed -> exiting pool")
self.exiting = True
class LoopPairState:
# TODO: use this in MultiLoopBalancer, or stop shoving state in here and put it on LoopBalancer instead.
def __init__(self, out: str, in_: str, amount: int):
self.out = out
self.in_ = in_
self.amount_target = amount
self.amount_looped = 0
self.amount_outstanding = 0
self.tx_fail_count = 0
self.route_fail_count = 0
self.last_job_start_time = None
self.failed_tx_throttler = 0 # increase by one every time we fail, decreases more gradually, when we succeed
class LoopBalancer(AbstractLoopRunner):
def __init__(self, out: str, in_: str, amount: int, looper: LoopRouter, bounds: TxBounds, parallelism: int=1):
super().__init__(looper, bounds, parallelism)
self.state = LoopPairState(out, in_, amount)
def pop_job(self) -> LoopJob | LoopJobIdle | LoopJobDone:
if self.state.tx_fail_count + 10*self.state.route_fail_count >= MAX_SEQUENTIAL_JOB_FAILURES:
logger.info(f"giving up ({self.state.out} -> {self.state.in_}): {self.state.tx_fail_count} tx failures, {self.state.route_fail_count} route failures")
return LoopJobDone.ABORTED
if self.state.tx_fail_count + self.state.route_fail_count > 0:
# N.B.: last_job_start_time is guaranteed to have been set by now
idle_until = self.state.last_job_start_time + TX_FAIL_BACKOFF*self.state.failed_tx_throttler
idle_for = idle_until - time.time()
if self.state.amount_outstanding != 0 or idle_for > 0:
# when we hit transient failures, restrict to just one job in flight at a time.
# this is aimed for the initial route building, where multiple jobs in flight is just useless,
# but it's not a bad idea for network blips, etc, either.
logger.info(f"throttling ({self.state.out} -> {self.state.in_}) for {idle_for:.0f}: {self.state.tx_fail_count} tx failures, {self.state.route_fail_count} route failures")
return LoopJobIdle(idle_for) if idle_for > 0 else LoopJobIdle()
amount_avail = self.state.amount_target - self.state.amount_looped - self.state.amount_outstanding
if amount_avail < self.bounds.min_msat:
if self.state.amount_outstanding == 0: return LoopJobDone.COMPLETED
return LoopJobIdle() # sending out another job would risk over-transferring
amount_this_job = min(amount_avail, self.bounds.max_msat)
self.state.amount_outstanding += amount_this_job
self.state.last_job_start_time = time.time()
return LoopJob(out=self.state.out, in_=self.state.in_, amount=amount_this_job)
def finished_job(self, job: LoopJob, progress: int) -> None:
self.state.amount_outstanding -= job.amount
if progress == LoopError.NO_ROUTE:
self.state.route_fail_count += 1
self.state.failed_tx_throttler += 10
elif progress == LoopError.TRANSIENT:
self.state.tx_fail_count += 1
self.state.failed_tx_throttler += 1
else:
self.state.amount_looped += progress
self.state.tx_fail_count = 0
self.state.route_fail_count = 0
self.state.failed_tx_throttler = max(0, self.state.failed_tx_throttler - 0.2)
logger.info(f"loop progressed ({job.out} -> {job.in_}) {progress}: {self.state.amount_looped} of {self.state.amount_target}")
class MultiLoopBalancer(AbstractLoopRunner):
"""
multiplexes jobs between multiple LoopBalancers.
note that the child LoopBalancers don't actually execute the jobs -- just produce them.
"""
def __init__(self, looper: LoopRouter, bounds: TxBounds, parallelism: int=1):
super().__init__(looper, bounds, parallelism)
self.loops = []
# job_index: increments on every job so we can grab jobs evenly from each LoopBalancer.
# in that event that producers are idling, it can actually increment more than once,
# so don't take this too literally
self.job_index = 0
def add_loop(self, out: LocalChannel, in_: LocalChannel, amount: int) -> None:
"""
start looping sats from out -> in_
"""
assert not any(l.state.out == out.scid and l.state.in_ == in_.scid for l in self.loops), f"tried to add duplicate loops from {out} -> {in_}"
logger.info(f"looping from ({out}) to ({in_})")
self.loops.append(LoopBalancer(out.scid, in_.scid, amount, self.looper, self.bounds, self.parallelism))
def pop_job(self) -> LoopJob | LoopJobIdle | LoopJobDone:
# N.B.: this can be called in parallel, so try to be consistent enough to not crash
idle_job = None
abort_job = None
for i, _ in enumerate(self.loops):
loop = self.loops[(self.job_index + i) % len(self.loops)]
self.job_index += 1
job = loop.pop_job()
if isinstance(job, LoopJob):
return job
if isinstance(job, LoopJobIdle):
idle_job = LoopJobIdle(min(job.sec, idle_job.sec)) if idle_job is not None else job
if job == LoopJobDone.ABORTED:
abort_job = job
# either there's a task to idle, or we have to terminate.
# if terminating, terminate ABORTED if any job aborted, else COMPLETED
if idle_job is not None: return idle_job
if abort_job is not None: return abort_job
return LoopJobDone.COMPLETED
def finished_job(self, job: LoopJob, progress: int) -> None:
# this assumes (enforced externally) that we have only one loop for a given out/in_ pair
for l in self.loops:
if l.state.out == job.out and l.state.in_ == job.in_:
l.finished_job(job, progress)
logger.info(f"total: {self.looper.metrics}")
def balance_loop(rpc: RpcHelper, out: str, in_: str, amount_msat: int, min_msat: int, max_msat: int, parallelism: int):
looper = LoopRouter(rpc)
bounds = TxBounds(min_msat=min_msat, max_msat=max_msat)
balancer = LoopBalancer(out, in_, amount_msat, looper, bounds, parallelism)
balancer.run_to_completion()
def autobalance_once(rpc: RpcHelper, metrics: Metrics, bounds: TxBounds, parallelism: int) -> bool:
"""
autobalances all channels.
returns True if channels are balanced (or as balanced as can be); False if in need of further balancing
"""
looper = LoopRouter(rpc, metrics)
balancer = MultiLoopBalancer(looper, bounds, parallelism)
channels = []
for peerch in rpc.rpc.listpeerchannels()["channels"]:
try:
channels.append(rpc.localchannel(peerch["short_channel_id"]))
except:
logger.info(f"NO CHANNELS for {peerch['peer_id']}")
channels = [ch for ch in channels if ch.online and ch.base_fee_to_me == 0]
give_to = [ ch for ch in channels if ch.send_ratio > 0.95 ]
take_from = [ ch for ch in channels if ch.send_ratio < 0.20 ]
if give_to == [] and take_from == []:
return True
for to in give_to:
for from_ in take_from:
balancer.add_loop(to, from_, 10000000)
balancer.run_to_completion(exit_on_any_completed=True)
return False
def autobalance(rpc: RpcHelper, min_msat: int, max_msat: int, parallelism: int):
bounds = TxBounds(min_msat=min_msat, max_msat=max_msat)
metrics = Metrics()
while not autobalance_once(rpc, metrics, bounds, parallelism):
pass
def show_status(rpc: RpcHelper, full: bool=False):
"""
show a table of channel balances between peers.
"""
for peerch in rpc.rpc.listpeerchannels()["channels"]:
try:
ch = rpc.localchannel(peerch["short_channel_id"])
except:
print(f"{peerch['peer_id']} scid:{peerch['short_channel_id']} state:{peerch['state']} NO CHANNELS")
else:
print(ch.to_str(with_scid=True, with_bal_ratio=True, with_payments=True, with_cost=full, with_ppm_theirs=True, with_ppm_mine=True, with_peer_id=full))
def main():
logging.basicConfig()
logger.setLevel(logging.INFO)
parser = argparse.ArgumentParser(description="rebalance lightning channel balances")
parser.add_argument("--verbose", action="store_true", help="more logging")
parser.add_argument("--min-msat", default="999", help="min transaction size")
parser.add_argument("--max-msat", default="1000000", help="max transaction size")
parser.add_argument("--jobs", default="1", help="how many HTLCs to keep in-flight at once")
subparsers = parser.add_subparsers(help="action")
status_parser = subparsers.add_parser("status")
status_parser.set_defaults(action="status")
status_parser.add_argument("--full", action="store_true", help="more info per channel")
loop_parser = subparsers.add_parser("loop")
loop_parser.set_defaults(action="loop")
loop_parser.add_argument("out", help="peer id to send tx through")
loop_parser.add_argument("in_", help="peer id to receive tx through")
loop_parser.add_argument("amount", help="total amount of msat to loop")
autobal_parser = subparsers.add_parser("autobalance")
autobal_parser.set_defaults(action="autobalance")
args = parser.parse_args()
if args.verbose:
logger.setLevel(logging.DEBUG)
rpc = RpcHelper(LightningRpc(RPC_FILE))
if args.action == "status":
show_status(rpc, full=args.full)
if args.action == "loop":
balance_loop(rpc, out=args.out, in_=args.in_, amount_msat=int(args.amount), min_msat=int(args.min_msat), max_msat=int(args.max_msat), parallelism=int(args.jobs))
if args.action == "autobalance":
autobalance(rpc, min_msat=int(args.min_msat), max_msat=int(args.max_msat), parallelism=int(args.jobs))
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,135 @@
# clightning is an implementation of Bitcoin's Lightning Network.
# as such, this assumes that `services.bitcoin` is enabled.
# docs:
# - tor clightning config: <https://docs.corelightning.org/docs/tor>
# - `lightning-cli` and subcommands: <https://docs.corelightning.org/reference/lightning-cli>
# - `man lightningd-config`
#
# management/setup/use:
# - guide: <https://github.com/ElementsProject/lightning>
#
# debugging:
# - `lightning-cli getlog debug`
# - `lightning-cli listpays` -> show payments this node sent
# - `lightning-cli listinvoices` -> show payments this node received
#
# first, acquire peers:
# - `lightning-cli connect id@host`
# where `id` is the node's pubkey, and `host` is perhaps an ip:port tuple, or a hash.onion:port tuple.
# for testing, choose any node listed on <https://1ml.com>
# - `lightning-cli listpeers`
# should show the new peer, with `connected: true`
#
# then, fund the clightning wallet
# - `lightning-cli newaddr`
#
# then, open channels
# - `lightning-cli connect ...`
# - `lightning-cli fundchannel <node_id> <amount_in_satoshis>`
#
# who to federate with?
# - a lot of the larger nodes allow hands-free channel creation
# - either inbound or outbound, sometimes paid
# - find nodes on:
# - <https://terminal.lightning.engineering/>
# - <https://1ml.com>
# - tor nodes: <https://1ml.com/node?order=capacity&iponionservice=true>
# - <https://lightningnetwork.plus>
# - <https://mempool.space/lightning>
# - <https://amboss.space>
# - a few tor-capable nodes which allow channel creation:
# - <https://c-otto.de/>
# - <https://cyberdyne.sh/>
# - <https://yalls.org/about/>
# - <https://coincept.com/>
# - more resources: <https://www.lopp.net/lightning-information.html>
# - node routability: https://hashxp.org/lightning/node/<id>
# - especially, acquire inbound liquidity via lightningnetwork.plus's swap feature
# - most of the opportunities are gated behind a minimum connection or capacity requirement
#
# tune payment parameters
# - `lightning-cli setchannel <id> [feebase] [feeppm] [htlcmin] [htlcmax] [enforcedelay] [ignorefeelimits]`
# - e.g. `lightning-cli setchannel all 0 10`
# - it's suggested that feebase=0 simplifies routing.
#
# teardown:
# - `lightning-cli withdraw <bc1... dest addr> <amount in satoshis> [feerate]`
#
# sanity:
# - `lightning-cli listfunds`
#
# to receive a payment (do as `clightning` user):
# - `lightning-cli invoice <amount in millisatoshi> <label> <description>`
# - specify amount as `any` if undetermined
# - then give the resulting bolt11 URI to the payer
# to send a payment:
# - `lightning-cli pay <bolt11 URI>`
# - or `lightning-cli pay <bolt11 URI> [amount_msat] [label] [riskfactor] [maxfeepercent] ...`
# - amount_msat must be "null" if the bolt11 URI specifies a value
# - riskfactor defaults to 10
# - maxfeepercent defaults to 0.5
# - label is a human-friendly label for my records
{ config, pkgs, ... }:
{
sane.persist.sys.byStore.ext = [
{ user = "clightning"; group = "clightning"; mode = "0710"; path = "/var/lib/clightning"; }
];
# `lightning-cli` finds its RPC file via `~/.lightning/bitcoin/lightning-rpc`, to message the daemon
sane.user.fs.".lightning".symlink.target = "/var/lib/clightning";
# see bitcoin.nix for how to generate this
services.bitcoind.mainnet.rpc.users.clightning.passwordHMAC =
"befcb82d9821049164db5217beb85439$2c31ac7db3124612e43893ae13b9527dbe464ab2d992e814602e7cb07dc28985";
sane.services.clightning.enable = true;
sane.services.clightning.proxy = "127.0.0.1:9050"; # proxy outgoing traffic through tor
# sane.services.clightning.publicAddress = "statictor:127.0.0.1:9051";
sane.services.clightning.getPublicAddressCmd = "cat /var/lib/tor/onion/clightning/hostname";
services.tor.relay.onionServices.clightning = {
version = 3;
map = [{
# by default tor will route public tor port P to 127.0.0.1:P.
# so if this port is the same as clightning would natively use, then no further config is needed here.
# see: <https://2019.www.torproject.org/docs/tor-manual.html.en#HiddenServicePort>
port = 9735;
# target.port; target.addr; #< set if tor port != clightning port
}];
# allow "tor" group (i.e. clightning) to read /var/lib/tor/onion/clightning/hostname
settings.HiddenServiceDirGroupReadable = true;
};
# must be in "tor" group to read /var/lib/tor/onion/*/hostname
users.users.clightning.extraGroups = [ "tor" ];
systemd.services.clightning.after = [ "tor.service" ];
# lightning-config contains fields from here:
# - <https://docs.corelightning.org/docs/configuration>
# secret config includes:
# - bitcoin-rpcpassword
# - alias=nodename
# - rgb=rrggbb
# - fee-base=<millisatoshi>
# - fee-per-satoshi=<ppm>
# - feature configs (i.e. experimental-xyz options)
sane.services.clightning.extraConfig = ''
log-level=debug:lightningd
# peerswap:
# - config example: <https://github.com/fort-nix/nix-bitcoin/pull/462/files#diff-b357d832705b8ce8df1f41934d613f79adb77c4cd5cd9e9eb12a163fca3e16c6>
# XXX: peerswap crashes clightning on launch. stacktrace is useless.
# plugin=${pkgs.peerswap}/bin/peerswap
# peerswap-db-path=/var/lib/clightning/peerswap/swaps
# peerswap-policy-path=...
'';
sane.services.clightning.extraConfigFiles = [ config.sops.secrets."lightning-config".path ];
sops.secrets."lightning-config" = {
mode = "0640";
owner = "clightning";
group = "clightning";
};
sane.programs.clightning.enableFor.user.colin = true; # for debugging/admin: `lightning-cli`
}

View File

@@ -0,0 +1,10 @@
{ ... }:
{
imports = [
./bitcoin.nix
./clightning.nix
./i2p.nix
./monero.nix
./tor.nix
];
}

View File

@@ -0,0 +1,4 @@
{ ... }:
{
services.i2p.enable = true;
}

View File

@@ -20,12 +20,6 @@
tx-proxy=tor,127.0.0.1:9050 tx-proxy=tor,127.0.0.1:9050
''; '';
services.i2p.enable = true;
# tor: `tor.enable` doesn't start a relay, exit node, proxy, etc. it's minimal.
# tor.client.enable configures a torsocks proxy, accessible *only* to localhost.
services.tor.enable = true;
services.tor.client.enable = true;
# monero ports: <https://monero.stackexchange.com/questions/604/what-ports-does-monero-use-rpc-p2p-etc> # monero ports: <https://monero.stackexchange.com/questions/604/what-ports-does-monero-use-rpc-p2p-etc>
# - 18080 = "P2P" monero node <-> monero node connections # - 18080 = "P2P" monero node <-> monero node connections
# - 18081 = "RPC" monero client -> monero node connections # - 18081 = "RPC" monero client -> monero node connections

View File

@@ -0,0 +1,25 @@
# tor settings: <https://2019.www.torproject.org/docs/tor-manual.html.en>
{ lib, ... }:
{
# tor hidden service hostnames aren't deterministic, so persist.
# might be able to get away with just persisting /var/lib/tor/onion, not sure.
sane.persist.sys.byStore.plaintext = [
{ user = "tor"; group = "tor"; mode = "0710"; path = "/var/lib/tor"; }
];
# tor: `tor.enable` doesn't start a relay, exit node, proxy, etc. it's minimal.
# tor.client.enable configures a torsocks proxy, accessible *only* to localhost.
# at 127.0.0.1:9050
services.tor.enable = true;
services.tor.client.enable = true;
# in order for services to read /var/lib/tor/onion/*/hostname, they must be able to traverse /var/lib/tor,
# and /var/lib/tor must have g+x.
# DataDirectoryGroupReadable causes tor to use g+rx, technically more than we need, but all the files are 600 so it's fine.
services.tor.settings.DataDirectoryGroupReadable = true;
# StateDirectoryMode defaults to 0700, and thereby prevents the onion hostnames from being group readable
systemd.services.tor.serviceConfig.StateDirectoryMode = lib.mkForce "0710";
users.users.tor.homeMode = "0710"; # home mode defaults to 0700, causing readability problems, enforced by nixos "users" activation script
services.tor.settings.SafeLogging = false; # show actual .onion names in the syslog, else debugging is impossible
}

View File

@@ -1,27 +0,0 @@
{ config, lib, pkgs, ... }:
# using manual ddns now
lib.mkIf false
{
systemd.services.ddns-afraid = {
description = "update dynamic DNS entries for freedns.afraid.org";
serviceConfig = {
EnvironmentFile = config.sops.secrets."ddns_afraid.env".path;
# TODO: ProtectSystem = "strict";
# TODO: ProtectHome = "full";
# TODO: PrivateTmp = true;
};
script = let
curl = "${pkgs.curl}/bin/curl -4";
in ''
${curl} "https://freedns.afraid.org/dynamic/update.php?$AFRAID_KEY"
'';
};
systemd.timers.ddns-afraid = {
wantedBy = [ "multi-user.target" ];
timerConfig = {
OnStartupSec = "2min";
OnUnitActiveSec = "10min";
};
};
}

View File

@@ -1,30 +0,0 @@
{ config, lib, pkgs, ... }:
# we use manual DDNS now
lib.mkIf false
{
systemd.services.ddns-he = {
description = "update dynamic DNS entries for HurricaneElectric";
serviceConfig = {
EnvironmentFile = config.sops.secrets."ddns_he.env".path;
# TODO: ProtectSystem = "strict";
# TODO: ProtectHome = "full";
# TODO: PrivateTmp = true;
};
# HE DDNS API is documented: https://dns.he.net/docs.html
script = let
crl = "${pkgs.curl}/bin/curl -4";
in ''
${crl} "https://he.uninsane.org:$HE_PASSPHRASE@dyn.dns.he.net/nic/update?hostname=he.uninsane.org"
${crl} "https://native.uninsane.org:$HE_PASSPHRASE@dyn.dns.he.net/nic/update?hostname=native.uninsane.org"
${crl} "https://uninsane.org:$HE_PASSPHRASE@dyn.dns.he.net/nic/update?hostname=uninsane.org"
'';
};
systemd.timers.ddns-he = {
wantedBy = [ "multi-user.target" ];
timerConfig = {
OnStartupSec = "2min";
OnUnitActiveSec = "10min";
};
};
}

View File

@@ -3,8 +3,7 @@
imports = [ imports = [
./calibre.nix ./calibre.nix
./coturn.nix ./coturn.nix
./ddns-afraid.nix ./cryptocurrencies
./ddns-he.nix
./email ./email
./ejabberd.nix ./ejabberd.nix
./freshrss.nix ./freshrss.nix
@@ -18,9 +17,9 @@
./komga.nix ./komga.nix
./lemmy.nix ./lemmy.nix
./matrix ./matrix
./monero.nix
./navidrome.nix ./navidrome.nix
./nginx.nix ./nginx.nix
./nixos-prebuild.nix
./nixserve.nix ./nixserve.nix
./ntfy ./ntfy
./pict-rs.nix ./pict-rs.nix

View File

@@ -172,13 +172,15 @@ in
users.users.sftpgo.extraGroups = [ "export" ]; users.users.sftpgo.extraGroups = [ "export" ];
systemd.services.sftpgo.serviceConfig = { systemd.services.sftpgo = {
ReadOnlyPaths = [ "/var/export" ];
ReadWritePaths = [ "/var/export/playground" ];
after = [ "network-online.target" ]; after = [ "network-online.target" ];
wants = [ "network-online.target" ]; wants = [ "network-online.target" ];
serviceConfig = {
ReadOnlyPaths = [ "/var/export" ];
ReadWritePaths = [ "/var/export/playground" ];
Restart = "always"; Restart = "always";
RestartSec = "20s"; RestartSec = "20s";
};
}; };
} }

View File

@@ -1,9 +1,19 @@
# how to update wikipedia snapshot:
# - browse for later snapshots:
# - <https://mirror.accum.se/mirror/wikimedia.org/other/kiwix/zim/wikipedia>
# - DL directly, or via rsync (resumable):
# - `rsync --progress --append-verify rsync://mirror.accum.se/mirror/wikimedia.org/other/kiwix/zim/wikipedia/wikipedia_en_all_maxi_2022-05.zim .`
{ ... }: { ... }:
{ {
sane.persist.sys.byStore.ext = [
{ user = "colin"; group = "users"; path = "/var/lib/kiwix"; }
];
sane.services.kiwix-serve = { sane.services.kiwix-serve = {
enable = true; enable = true;
port = 8013; port = 8013;
zimPaths = [ "/var/lib/uninsane/www-archive/wikipedia_en_all_maxi_2022-05.zim" ]; zimPaths = [ "/var/lib/kiwix/wikipedia_en_all_maxi_2023-11.zim" ];
}; };
services.nginx.virtualHosts."w.uninsane.org" = { services.nginx.virtualHosts."w.uninsane.org" = {

View File

@@ -1,6 +1,8 @@
# config options: # config options:
# - <https://github.com/mautrix/signal/blob/master/mautrix_signal/example-config.yaml> # - <https://github.com/mautrix/signal/blob/master/mautrix_signal/example-config.yaml>
{ config, pkgs, ... }: { config, lib, pkgs, ... }:
lib.mkIf false # disabled 2024/01/11: i don't use it, and pkgs.mautrix-signal had some API changes
{ {
sane.persist.sys.byStore.plaintext = [ sane.persist.sys.byStore.plaintext = [
{ user = "mautrix-signal"; group = "mautrix-signal"; path = "/var/lib/mautrix-signal"; } { user = "mautrix-signal"; group = "mautrix-signal"; path = "/var/lib/mautrix-signal"; }

View File

@@ -54,8 +54,10 @@ in
services.nginx.recommendedOptimisation = true; services.nginx.recommendedOptimisation = true;
# web blog/personal site # web blog/personal site
# alternative way to link stuff into the share:
# sane.fs."/var/lib/uninsane/share/Ubunchu".mount.bind = "/var/lib/uninsane/media/Books/Visual/HiroshiSeo/Ubunchu";
# sane.fs."/var/lib/uninsane/media/Books/Visual/HiroshiSeo/Ubunchu".dir = {};
services.nginx.virtualHosts."uninsane.org" = publog { services.nginx.virtualHosts."uninsane.org" = publog {
root = "${pkgs.uninsane-dot-org}/share/uninsane-dot-org";
# a lot of places hardcode https://uninsane.org, # a lot of places hardcode https://uninsane.org,
# and then when we mix http + non-https, we get CORS violations # and then when we mix http + non-https, we get CORS violations
# and things don't look right. so force SSL. # and things don't look right. so force SSL.
@@ -65,9 +67,28 @@ in
# for OCSP stapling # for OCSP stapling
sslTrustedCertificate = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; sslTrustedCertificate = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
# uninsane.org/share/foo => /var/lib/uninsane/root/share/foo. locations."/" = {
# yes, nginx does not strip the prefix when evaluating against the root. root = "${pkgs.uninsane-dot-org}/share/uninsane-dot-org";
locations."/share".root = "/var/lib/uninsane/root"; tryFiles = "$uri $uri/ @fallback";
};
# unversioned files
locations."@fallback" = {
root = "/var/www/sites/uninsane.org";
};
# uninsane.org/share/foo => /var/www/sites/uninsane.org/share/foo.
# special-cased to enable directory listings
locations."/share" = {
root = "/var/www/sites/uninsane.org";
extraConfig = ''
# autoindex => render directory listings
autoindex on;
# don't follow any symlinks when serving files
# otherwise it allows a directory escape
disable_symlinks on;
'';
};
# allow matrix users to discover that @user:uninsane.org is reachable via matrix.uninsane.org # allow matrix users to discover that @user:uninsane.org is reachable via matrix.uninsane.org
locations."= /.well-known/matrix/server".extraConfig = locations."= /.well-known/matrix/server".extraConfig =
@@ -108,6 +129,19 @@ in
# proxyPass = "http://127.0.0.1:4000"; # proxyPass = "http://127.0.0.1:4000";
# extraConfig = pleromaExtraConfig; # extraConfig = pleromaExtraConfig;
# }; # };
# redirect common feed URIs to the canonical feed
locations."= /atom".extraConfig = "return 301 /atom.xml;";
locations."= /feed".extraConfig = "return 301 /atom.xml;";
locations."= /feed.xml".extraConfig = "return 301 /atom.xml;";
locations."= /rss".extraConfig = "return 301 /atom.xml;";
locations."= /rss.xml".extraConfig = "return 301 /atom.xml;";
locations."= /blog/atom".extraConfig = "return 301 /atom.xml;";
locations."= /blog/atom.xml".extraConfig = "return 301 /atom.xml;";
locations."= /blog/feed".extraConfig = "return 301 /atom.xml;";
locations."= /blog/feed.xml".extraConfig = "return 301 /atom.xml;";
locations."= /blog/rss".extraConfig = "return 301 /atom.xml;";
locations."= /blog/rss.xml".extraConfig = "return 301 /atom.xml;";
}; };
@@ -135,7 +169,6 @@ in
security.acme.defaults.email = "admin.acme@uninsane.org"; security.acme.defaults.email = "admin.acme@uninsane.org";
sane.persist.sys.byStore.plaintext = [ sane.persist.sys.byStore.plaintext = [
# TODO: mode?
{ user = "acme"; group = "acme"; path = "/var/lib/acme"; } { user = "acme"; group = "acme"; path = "/var/lib/acme"; }
{ user = "colin"; group = "users"; path = "/var/www/sites"; } { user = "colin"; group = "users"; path = "/var/www/sites"; }
]; ];

View File

@@ -0,0 +1,26 @@
{ lib, pkgs, ... }:
lib.optionalAttrs false # disabled until i can be sure it's not gonna OOM my server in the middle of the night
{
systemd.services.nixos-prebuild = {
description = "build a nixos image with all updated deps";
path = with pkgs; [ coreutils git nix ];
script = ''
working=$(mktemp -d /tmp/nixos-prebuild.XXXXXX)
pushd "$working"
git clone https://git.uninsane.org/colin/nix-files.git \
&& cd nix-files \
&& nix flake update \
|| true
RC=$(nix run "$working/nix-files#check" -- -j1 --cores 5 --builders "")
popd
rm -rf "$working"
exit "$RC"
'';
};
systemd.timers.nixos-prebuild = {
wantedBy = [ "multi-user.target" ];
timerConfig.OnCalendar = "11,23:00:00";
};
}

View File

@@ -64,7 +64,7 @@ in
protocol = [ "tcp" ]; protocol = [ "tcp" ];
visibleTo.lan = true; visibleTo.lan = true;
visibleTo.wan = true; visibleTo.wan = true;
description = "colin-notification-waiter-${builtins.toString (port+1)}-of-${builtins.toString numPorts}"; description = "colin-notification-waiter-${builtins.toString (port - portLow + 1)}-of-${builtins.toString numPorts}";
}; };
})); }));
systemd.services = lib.mkMerge (builtins.map mkService portRange); systemd.services = lib.mkMerge (builtins.map mkService portRange);

View File

@@ -57,7 +57,7 @@
# what unit is this? kbps?? # what unit is this? kbps??
global.upload.speed_limit = 32000; global.upload.speed_limit = 32000;
web.logging = true; web.logging = true;
debug = true; # debug = true;
flags.no_logo = true; # don't show logo at start flags.no_logo = true; # don't show logo at start
# flags.volatile = true; # store searches and active transfers in RAM (completed transfers still go to disk). rec for btrfs/zfs # flags.volatile = true; # store searches and active transfers in RAM (completed transfers still go to disk). rec for btrfs/zfs
}; };
@@ -66,8 +66,8 @@
serviceConfig = { serviceConfig = {
# run this behind the OVPN static VPN # run this behind the OVPN static VPN
NetworkNamespacePath = "/run/netns/ovpns"; NetworkNamespacePath = "/run/netns/ovpns";
Restart = "on-failure"; Restart = lib.mkForce "always"; # exits "success" when it fails to connect to soulseek server
RestartSec = "30s"; RestartSec = "60s";
Group = "media"; Group = "media";
}; };
}; };

View File

@@ -16,7 +16,7 @@
# transmission will by default not allow the world to read its files. # transmission will by default not allow the world to read its files.
services.transmission.downloadDirPermissions = "775"; services.transmission.downloadDirPermissions = "775";
services.transmission.extraFlags = [ services.transmission.extraFlags = [
"--log-level=debug" # "--log-level=debug"
]; ];
services.transmission.settings = { services.transmission.settings = {
@@ -39,9 +39,9 @@
encryption = 2; encryption = 2;
# units in kBps # units in kBps
speed-limit-down = 3000; speed-limit-down = 12000;
speed-limit-down-enabled = true; speed-limit-down-enabled = true;
speed-limit-up = 600; speed-limit-up = 800;
speed-limit-up-enabled = true; speed-limit-up-enabled = true;
# see: https://git.zknt.org/mirror/transmission/commit/cfce6e2e3a9b9d31a9dafedd0bdc8bf2cdb6e876?lang=bg-BG # see: https://git.zknt.org/mirror/transmission/commit/cfce6e2e3a9b9d31a9dafedd0bdc8bf2cdb6e876?lang=bg-BG

View File

@@ -5,18 +5,16 @@
./fs.nix ./fs.nix
./hardware ./hardware
./home ./home
./hostnames.nix
./hosts.nix ./hosts.nix
./ids.nix ./ids.nix
./machine-id.nix ./machine-id.nix
./net.nix ./net
./nix-path ./nix-path
./persist.nix ./persist.nix
./programs ./programs
./secrets.nix ./secrets.nix
./ssh.nix ./ssh.nix
./users ./users
./vpn.nix
]; ];
sane.nixcache.enable-trusted-keys = true; sane.nixcache.enable-trusted-keys = true;
@@ -94,7 +92,21 @@
text = '' text = ''
# show which packages changed versions or are new/removed in this upgrade # show which packages changed versions or are new/removed in this upgrade
# source: <https://github.com/luishfonseca/dotfiles/blob/32c10e775d9ec7cc55e44592a060c1c9aadf113e/modules/upgrade-diff.nix> # source: <https://github.com/luishfonseca/dotfiles/blob/32c10e775d9ec7cc55e44592a060c1c9aadf113e/modules/upgrade-diff.nix>
${pkgs.nvd}/bin/nvd --nix-bin-dir=${pkgs.nix}/bin diff /run/current-system "$systemConfig" # modified to not error on boot (when /run/current-system doesn't exist)
if [ -d /run/current-system ]; then
${pkgs.nvd}/bin/nvd --nix-bin-dir=${pkgs.nix}/bin diff /run/current-system "$systemConfig"
fi
'';
};
system.activationScripts.notifyActive = {
text = ''
# send a notification to any sway users logged in, that the system has been activated/upgraded.
# this probably doesn't work if more than one sway session exists on the system.
_notifyActiveSwaySock="$(echo /run/user/*/sway-ipc.*.sock)"
if [ -e "$_notifyActiveSwaySock" ]; then
SWAYSOCK="$_notifyActiveSwaySock" ${pkgs.sway}/bin/swaymsg -- exec \
"${pkgs.libnotify}/bin/notify-send 'nixos activated' 'version: $(cat $systemConfig/nixos-version)'"
fi
''; '';
}; };

View File

@@ -50,6 +50,8 @@ let
else else
"infrequent" "infrequent"
)); ));
} // lib.optionalAttrs (lib.hasPrefix "https://www.youtube.com/" raw.url) {
format = "video";
} // lib.optionalAttrs (raw.is_podcast or false) { } // lib.optionalAttrs (raw.is_podcast or false) {
format = "podcast"; format = "podcast";
} // lib.optionalAttrs (raw.title or "" != "") { } // lib.optionalAttrs (raw.title or "" != "") {
@@ -60,6 +62,7 @@ let
(fromDb "acquiredlpbonussecretsecret.libsyn.com" // tech) # ACQ2 - more "Acquired" episodes (fromDb "acquiredlpbonussecretsecret.libsyn.com" // tech) # ACQ2 - more "Acquired" episodes
(fromDb "allinchamathjason.libsyn.com" // pol) (fromDb "allinchamathjason.libsyn.com" // pol)
(fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech) # Civboot -- https://anchor.fm/civboot (fromDb "anchor.fm/s/34c7232c/podcast/rss" // tech) # Civboot -- https://anchor.fm/civboot
(fromDb "anchor.fm/s/2da69154/podcast/rss" // tech) # POD OF JAKE -- https://podofjake.com/
(fromDb "cast.postmarketos.org" // tech) (fromDb "cast.postmarketos.org" // tech)
(fromDb "congressionaldish.libsyn.com" // pol) # Jennifer Briney (fromDb "congressionaldish.libsyn.com" // pol) # Jennifer Briney
(fromDb "craphound.com" // pol) # Cory Doctorow -- both podcast & text entries (fromDb "craphound.com" // pol) # Cory Doctorow -- both podcast & text entries
@@ -71,20 +74,22 @@ let
(fromDb "feeds.feedburner.com/radiolab" // pol) # Radiolab -- also available here, but ONLY OVER HTTP: <http://feeds.wnyc.org/radiolab> (fromDb "feeds.feedburner.com/radiolab" // pol) # Radiolab -- also available here, but ONLY OVER HTTP: <http://feeds.wnyc.org/radiolab>
(fromDb "feeds.libsyn.com/421877" // rat) # Less Wrong Curated (fromDb "feeds.libsyn.com/421877" // rat) # Less Wrong Curated
(fromDb "feeds.megaphone.fm/behindthebastards" // pol) # also Maggie Killjoy (fromDb "feeds.megaphone.fm/behindthebastards" // pol) # also Maggie Killjoy
(fromDb "feeds.megaphone.fm/hubermanlab" // uncat) # Daniel Huberman on sleep # (fromDb "feeds.megaphone.fm/hubermanlab" // uncat) # Daniel Huberman on sleep
(fromDb "feeds.megaphone.fm/recodedecode" // tech) # The Verge - Decoder (fromDb "feeds.megaphone.fm/recodedecode" // tech) # The Verge - Decoder
(fromDb "feeds.simplecast.com/54nAGcIl" // pol) # The Daily (fromDb "feeds.simplecast.com/54nAGcIl" // pol) # The Daily
(fromDb "feeds.simplecast.com/82FI35Px" // pol) # Ezra Klein Show (fromDb "feeds.simplecast.com/82FI35Px" // pol) # Ezra Klein Show
(fromDb "feeds.simplecast.com/wgl4xEgL" // rat) # Econ Talk (fromDb "feeds.simplecast.com/wgl4xEgL" // rat) # Econ Talk
(fromDb "feeds.simplecast.com/xKJ93w_w" // uncat) # Atlas Obscura (fromDb "feeds.simplecast.com/xKJ93w_w" // uncat) # Atlas Obscura
(fromDb "feeds.simplecast.com/l2i9YnTd" // tech // pol) # Hard Fork (NYtimes tech) # (fromDb "feeds.simplecast.com/l2i9YnTd" // tech // pol) # Hard Fork (NYtimes tech)
(fromDb "feeds.transistor.fm/acquired" // tech) (fromDb "feeds.transistor.fm/acquired" // tech)
(fromDb "lexfridman.com/podcast" // rat) (fromDb "lexfridman.com/podcast" // rat)
(fromDb "mapspodcast.libsyn.com" // uncat) # Multidisciplinary Association for Psychedelic Studies (fromDb "mapspodcast.libsyn.com" // uncat) # Multidisciplinary Association for Psychedelic Studies
(fromDb "omegataupodcast.net" // tech) # 3/4 German; 1/4 eps are English (fromDb "omegataupodcast.net" // tech) # 3/4 German; 1/4 eps are English
(fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol) # Maggie Killjoy -- referenced by Cory Doctorow (fromDb "omny.fm/shows/cool-people-who-did-cool-stuff" // pol) # Maggie Killjoy -- referenced by Cory Doctorow
(fromDb "omny.fm/shows/the-dollop-with-dave-anthony-and-gareth-reynolds") # The Dollop history/comedy
(fromDb "originstories.libsyn.com" // uncat)
(fromDb "podcast.posttv.com/itunes/post-reports.xml" // pol) (fromDb "podcast.posttv.com/itunes/post-reports.xml" // pol)
(fromDb "podcast.thelinuxexp.com" // tech) # (fromDb "podcast.thelinuxexp.com" // tech) # low-brow linux/foss PR announcements
(fromDb "politicalorphanage.libsyn.com" // pol) (fromDb "politicalorphanage.libsyn.com" // pol)
(fromDb "reverseengineering.libsyn.com/rss" // tech) # UnNamed Reverse Engineering Podcast (fromDb "reverseengineering.libsyn.com/rss" // tech) # UnNamed Reverse Engineering Podcast
(fromDb "rss.acast.com/deconstructed") # The Intercept - Deconstructed (fromDb "rss.acast.com/deconstructed") # The Intercept - Deconstructed
@@ -93,6 +98,7 @@ let
(fromDb "rss.art19.com/60-minutes" // pol) (fromDb "rss.art19.com/60-minutes" // pol)
(fromDb "rss.art19.com/the-portal" // rat) # Eric Weinstein (fromDb "rss.art19.com/the-portal" // rat) # Eric Weinstein
(fromDb "seattlenice.buzzsprout.com" // pol) (fromDb "seattlenice.buzzsprout.com" // pol)
(fromDb "srslywrong.com" // pol)
(fromDb "sharkbytes.transistor.fm" // tech) # Wireshark Podcast o_0 (fromDb "sharkbytes.transistor.fm" // tech) # Wireshark Podcast o_0
(fromDb "sscpodcast.libsyn.com" // rat) # Astral Codex Ten (fromDb "sscpodcast.libsyn.com" // rat) # Astral Codex Ten
(fromDb "talesfromthebridge.buzzsprout.com" // tech) # Sci-Fi? has Peter Watts; author of No Moods, Ads or Cutesy Fucking Icons (rifters.com) (fromDb "talesfromthebridge.buzzsprout.com" // tech) # Sci-Fi? has Peter Watts; author of No Moods, Ads or Cutesy Fucking Icons (rifters.com)
@@ -111,137 +117,118 @@ let
]; ];
texts = [ texts = [
# AGGREGATORS (> 1 post/day) (fromDb "amosbbatto.wordpress.com" // tech)
(fromDb "lwn.net" // tech) (fromDb "applieddivinitystudies.com" // rat)
# (fromDb "lesswrong.com" // rat) (fromDb "artemis.sh" // tech)
(fromDb "ascii.textfiles.com" // tech) # Jason Scott
(fromDb "austinvernon.site" // tech)
(fromDb "balajis.com" // pol) # Balaji
(fromDb "ben-evans.com/benedictevans" // pol)
(fromDb "bitbashing.io" // tech)
(fromDb "bitsaboutmoney.com" // uncat)
(fromDb "blog.danieljanus.pl" // tech)
(fromDb "blog.dshr.org" // pol) # David Rosenthal
(fromDb "blog.jmp.chat" // tech)
(fromDb "blog.rust-lang.org" // tech)
(fromDb "blog.thalheim.io" // tech) # Mic92
(fromDb "bunniestudios.com" // tech) # Bunnie Juang
(fromDb "capitolhillseattle.com" // pol)
# (fromDb "drewdevault.com" // tech)
# (fromDb "econlib.org" // pol) # (fromDb "econlib.org" // pol)
(fromDb "edwardsnowden.substack.com" // pol // text)
# AGGREGATORS (< 1 post/day) (fromDb "fasterthanli.me" // tech)
(fromDb "gwern.net" // rat)
(fromDb "harihareswara.net" // tech // pol) # rec by Cory Doctorow
(fromDb "ianthehenry.com" // tech)
(fromDb "idiomdrottning.org" // uncat)
(fromDb "interconnected.org/home/feed" // rat) # Matt Webb -- engineering-ish, but dreamy
(fromDb "jeffgeerling.com" // tech)
(fromDb "jefftk.com" // tech)
(fromDb "kosmosghost.github.io/index.xml" // tech)
# (fromDb "lesswrong.com" // rat)
(fromDb "linmob.net" // tech)
(fromDb "lwn.net" // tech)
(fromDb "lynalden.com" // pol)
(fromDb "mako.cc/copyrighteous" // tech // pol) # rec by Cory Doctorow
(fromDb "mg.lol" // tech)
(fromDb "mindingourway.com" // rat)
(fromDb "morningbrew.com/feed" // pol)
(fromDb "overcomingbias.com" // rat) # Robin Hanson
(fromDb "palladiummag.com" // uncat) (fromDb "palladiummag.com" // uncat)
(fromDb "philosopher.coach" // rat) # Peter Saint-Andre -- side project of stpeter.im
(fromDb "pomeroyb.com" // tech)
(fromDb "preposterousuniverse.com" // rat) # Sean Carroll
(fromDb "profectusmag.com" // uncat) (fromDb "profectusmag.com" // uncat)
(fromDb "project-insanity.org" // tech) # shared blog by a few NixOS devs, notably onny
(fromDb "putanumonit.com" // rat) # mostly dating topics. not advice, or humor, but looking through a social lens
(fromDb "richardcarrier.info" // rat)
(fromDb "rifters.com/crawl" // uncat) # No Moods, Ads or Cutesy Fucking Icons
(fromDb "righto.com" // tech) # Ken Shirriff
(fromDb "rootsofprogress.org" // rat) # Jason Crawford
(fromDb "sagacioussuricata.com" // tech) # ian (Sanctuary)
(fromDb "semiaccurate.com" // tech) (fromDb "semiaccurate.com" // tech)
(mkText "https://linuxphoneapps.org/blog/atom.xml" // tech // infrequent) (fromDb "sideways-view.com" // rat) # Paul Christiano
(fromDb "tuxphones.com" // tech) (fromDb "slimemoldtimemold.com" // rat)
(fromDb "spectrum.ieee.org" // tech) (fromDb "spectrum.ieee.org" // tech)
(fromDb "stpeter.im/atom.xml" // pol)
# (fromDb "theregister.com" // tech) # (fromDb "theregister.com" // tech)
(fromDb "thisweek.gnome.org" // tech) (fromDb "thisweek.gnome.org" // tech)
# more nixos stuff here, but unclear how to subscribe: <https://nixos.org/blog/categories.html> (fromDb "tuxphones.com" // tech)
(mkText "https://nixos.org/blog/announcements-rss.xml" // tech // infrequent)
(mkText "https://nixos.org/blog/stories-rss.xml" // tech // weekly)
## n.b.: quality RSS list here: <https://forum.merveilles.town/thread/57/share-your-rss-feeds%21-6/>
(mkText "https://forum.merveilles.town/rss.xml" // pol // infrequent)
## No Moods, Ads or Cutesy Fucking Icons
(fromDb "rifters.com/crawl" // uncat)
# DEVELOPERS
(fromDb "blog.jmp.chat" // tech)
(fromDb "uninsane.org" // tech) (fromDb "uninsane.org" // tech)
(fromDb "blog.thalheim.io" // tech) # Mic92 (fromDb "unintendedconsequenc.es" // rat)
(fromDb "ascii.textfiles.com" // tech) # Jason Scott # (fromDb "vitalik.ca" // tech) # moved to vitalik.eth.limo
(fromDb "vitalik.eth.limo" // tech) # Vitalik Buterin
(fromDb "webcurious.co.uk" // uncat)
(fromDb "xn--gckvb8fzb.com" // tech) (fromDb "xn--gckvb8fzb.com" // tech)
(fromDb "amosbbatto.wordpress.com" // tech) (mkSubstack "astralcodexten" // rat // daily) # Scott Alexander
(fromDb "fasterthanli.me" // tech)
(fromDb "jeffgeerling.com" // tech)
(fromDb "mg.lol" // tech)
# (fromDb "drewdevault.com" // tech)
## Ken Shirriff
(fromDb "righto.com" // tech)
## shared blog by a few NixOS devs, notably onny
(fromDb "project-insanity.org" // tech)
## Vitalik Buterin
(fromDb "vitalik.ca" // tech)
## ian (Sanctuary)
(fromDb "sagacioussuricata.com" // tech)
(fromDb "artemis.sh" // tech)
## Bunnie Juang
(fromDb "bunniestudios.com" // tech)
(fromDb "blog.danieljanus.pl" // tech)
(fromDb "ianthehenry.com" // tech)
(fromDb "bitbashing.io" // tech)
(fromDb "idiomdrottning.org" // uncat)
(mkText "http://boginjr.com/feed" // tech // infrequent)
(mkText "https://anish.lakhwara.com/home.html" // tech // weekly)
(fromDb "jefftk.com" // tech)
(fromDb "pomeroyb.com" // tech)
(fromDb "harihareswara.net" // tech // pol) # rec by Cory Doctorow
(fromDb "mako.cc/copyrighteous" // tech // pol) # rec by Cory Doctorow
# (mkText "https://til.simonwillison.net/tils/feed.atom" // tech // weekly)
# TECH PROJECTS
(fromDb "blog.rust-lang.org" // tech)
# (TECH; POL) COMMENTATORS
## Matt Webb -- engineering-ish, but dreamy
(fromDb "interconnected.org/home/feed" // rat)
(fromDb "edwardsnowden.substack.com" // pol // text)
## Julia Evans
(mkText "https://jvns.ca/atom.xml" // tech // weekly)
(mkText "http://benjaminrosshoffman.com/feed" // pol // weekly)
## Ben Thompson
(mkText "https://www.stratechery.com/rss" // pol // weekly)
## Balaji
(fromDb "balajis.com" // pol)
(fromDb "ben-evans.com/benedictevans" // pol)
(fromDb "lynalden.com" // pol)
(fromDb "austinvernon.site" // tech)
(mkSubstack "oversharing" // pol // daily)
(mkSubstack "byrnehobart" // pol // infrequent) (mkSubstack "byrnehobart" // pol // infrequent)
# (mkSubstack "doomberg" // tech // weekly) # articles are all pay-walled # (mkSubstack "doomberg" // tech // weekly) # articles are all pay-walled
## David Rosenthal
(fromDb "blog.dshr.org" // pol)
## Matt Levine
(mkText "https://www.bloomberg.com/opinion/authors/ARbTQlRLRjE/matthew-s-levine.rss" // pol // weekly)
(fromDb "stpeter.im/atom.xml" // pol)
## Peter Saint-Andre -- side project of stpeter.im
(fromDb "philosopher.coach" // rat)
(fromDb "morningbrew.com/feed" // pol)
# RATIONALITY/PHILOSOPHY/ETC
(mkSubstack "samkriss" // humor // infrequent)
(fromDb "unintendedconsequenc.es" // rat)
(fromDb "applieddivinitystudies.com" // rat)
(fromDb "slimemoldtimemold.com" // rat)
(fromDb "richardcarrier.info" // rat)
(fromDb "gwern.net" // rat)
## Jason Crawford
(fromDb "rootsofprogress.org" // rat)
## Robin Hanson
(fromDb "overcomingbias.com" // rat)
## Scott Alexander
(mkSubstack "astralcodexten" // rat // daily)
## Paul Christiano
(fromDb "sideways-view.com" // rat)
## Sean Carroll
(fromDb "preposterousuniverse.com" // rat)
(mkSubstack "eliqian" // rat // weekly) (mkSubstack "eliqian" // rat // weekly)
(mkSubstack "oversharing" // pol // daily)
(mkSubstack "samkriss" // humor // infrequent)
(mkText "http://benjaminrosshoffman.com/feed" // pol // weekly)
(mkText "http://boginjr.com/feed" // tech // infrequent)
(mkText "https://acoup.blog/feed" // rat // weekly) (mkText "https://acoup.blog/feed" // rat // weekly)
(fromDb "mindingourway.com" // rat) (mkText "https://anish.lakhwara.com/home.html" // tech // weekly)
(mkText "https://forum.merveilles.town/rss.xml" // pol // infrequent) #quality RSS list here: <https://forum.merveilles.town/thread/57/share-your-rss-feeds%21-6/>
## mostly dating topics. not advice, or humor, but looking through a social lens
(fromDb "putanumonit.com" // rat)
# LOCAL
(fromDb "capitolhillseattle.com" // pol)
# CODE
# (mkText "https://github.com/Kaiteki-Fedi/Kaiteki/commits/master.atom" // tech // infrequent) # (mkText "https://github.com/Kaiteki-Fedi/Kaiteki/commits/master.atom" // tech // infrequent)
(mkText "https://jvns.ca/atom.xml" // tech // weekly) # Julia Evans
(mkText "https://linuxphoneapps.org/blog/atom.xml" // tech // infrequent)
(mkText "https://nixos.org/blog/announcements-rss.xml" // tech // infrequent) # more nixos stuff here, but unclear how to subscribe: <https://nixos.org/blog/categories.html>
(mkText "https://nixos.org/blog/stories-rss.xml" // tech // weekly)
# (mkText "https://til.simonwillison.net/tils/feed.atom" // tech // weekly)
(mkText "https://www.bloomberg.com/opinion/authors/ARbTQlRLRjE/matthew-s-levine.rss" // pol // weekly) # Matt Levine
(mkText "https://www.stratechery.com/rss" // pol // weekly) # Ben Thompson
];
videos = [
(fromDb "youtube.com/@Channel5YouTube" // pol)
(fromDb "youtube.com/@ColdFusion")
(fromDb "youtube.com/@ContraPoints" // pol)
(fromDb "youtube.com/@Exurb1a")
(fromDb "youtube.com/@hbomberguy")
(fromDb "youtube.com/@JackStauber")
(fromDb "youtube.com/@PolyMatter")
# (fromDb "youtube.com/@rossmanngroup" // pol // tech) # Louis Rossmann
(fromDb "youtube.com/@TechnologyConnections" // tech)
(fromDb "youtube.com/@TheB1M")
(fromDb "youtube.com/@TomScottGo")
(fromDb "youtube.com/@Vihart")
(fromDb "youtube.com/@Vox")
(fromDb "youtube.com/@Vsauce")
]; ];
images = [ images = [
(fromDb "smbc-comics.com" // img // humor)
(fromDb "xkcd.com" // img // humor)
(fromDb "turnoff.us" // img // humor)
(fromDb "pbfcomics.com" // img // humor)
# (mkImg "http://dilbert.com/feed" // humor // daily)
(fromDb "poorlydrawnlines.com/feed" // img // humor)
# ART
(fromDb "miniature-calendar.com" // img // art // daily) (fromDb "miniature-calendar.com" // img // art // daily)
(fromDb "pbfcomics.com" // img // humor)
(fromDb "poorlydrawnlines.com/feed" // img // humor)
(fromDb "smbc-comics.com" // img // humor)
(fromDb "turnoff.us" // img // humor)
(fromDb "xkcd.com" // img // humor)
]; ];
in in
{ {
sane.feeds = texts ++ images ++ podcasts; sane.feeds = texts ++ images ++ podcasts ++ videos;
assertions = builtins.map assertions = builtins.map
(p: { (p: {

View File

@@ -1,4 +1,4 @@
{ lib, pkgs, ... }: { config, lib, pkgs, ... }:
{ {
imports = [ imports = [
@@ -40,6 +40,12 @@
# non-free firmware # non-free firmware
hardware.enableRedistributableFirmware = true; hardware.enableRedistributableFirmware = true;
# default is 252274, which is too low particularly for servo.
# manifests as spurious "No space left on device" when trying to install watches,
# e.g. in dyn-dns by `systemctl start dyn-dns-watcher.path`.
# see: <https://askubuntu.com/questions/828779/failed-to-add-run-systemd-ask-password-to-directory-watch-no-space-left-on-dev>
boot.kernel.sysctl."fs.inotify.max_user_watches" = 1048576;
# powertop will default to putting USB devices -- including HID -- to sleep after TWO SECONDS # powertop will default to putting USB devices -- including HID -- to sleep after TWO SECONDS
powerManagement.powertop.enable = false; powerManagement.powertop.enable = false;
# linux CPU governor: <https://www.kernel.org/doc/Documentation/cpu-freq/governors.txt> # linux CPU governor: <https://www.kernel.org/doc/Documentation/cpu-freq/governors.txt>
@@ -58,10 +64,19 @@
powerManagement.cpuFreqGovernor = "ondemand"; powerManagement.cpuFreqGovernor = "ondemand";
services.logind.extraConfig = '' services.logind.extraConfig = ''
# dont shutdown when power button is short-pressed # see: `man logind.conf`
HandlePowerKey=ignore # dont shutdown when power button is short-pressed (commonly done an accident, or by cats).
# but do on long-press: useful to gracefully power-off server.
HandlePowerKey=lock
HandlePowerKeyLongPress=poweroff
HandleLidSwitch=lock
''; '';
# some packages build only if binfmt *isn't* present
nix.settings.system-features = lib.mkIf (config.boot.binfmt.emulatedSystems == []) [
"no-binfmt"
];
# services.snapper.configs = { # services.snapper.configs = {
# root = { # root = {
# subvolume = "/"; # subvolume = "/";

View File

@@ -1,19 +1,32 @@
{ config, lib, ...}: { config, lib, ...}:
let let
# ProgramConfig -> { "<mime-type>" = { priority, desktop }; }
weightedMimes = prog: builtins.mapAttrs (_key: desktop: { priority = prog.mime.priority; desktop = desktop; }) prog.mime.associations;
# [ { "<mime-type>" = { priority, desktop } ]; } ] -> { "<mime-type>" = [ { priority, desktop } ... ]; }
mergeMimes = mimes: lib.foldAttrs (item: acc: [item] ++ acc) [] mimes;
# [ { priority, desktop } ... ] -> Self
sortOneMimeType = associations: builtins.sort (l: r: assert l.priority != r.priority; l.priority < r.priority) associations;
sortMimes = mimes: builtins.mapAttrs (_k: sortOneMimeType) mimes;
removePriorities = mimes: builtins.mapAttrs (_k: associations: builtins.map (a: a.desktop) associations) mimes;
# [ ProgramConfig ] # [ ProgramConfig ]
enabledPrograms = builtins.filter (p: p.enabled) (builtins.attrValues config.sane.programs); enabledPrograms = builtins.filter
(p: p.enabled)
(builtins.attrValues config.sane.programs);
# [ { "<mime-type>" = { prority, desktop } ] # [ { "<mime-type>" = { prority, desktop } ]
enabledWeightedMimes = builtins.map weightedMimes enabledPrograms; enabledWeightedMimes = builtins.map weightedMimes enabledPrograms;
# ProgramConfig -> { "<mime-type>" = { priority, desktop }; }
weightedMimes = prog: builtins.mapAttrs
(_key: desktop: {
priority = prog.mime.priority; desktop = desktop;
})
prog.mime.associations;
# [ { "<mime-type>" = { priority, desktop } ]; } ] -> { "<mime-type>" = [ { priority, desktop } ... ]; }
mergeMimes = mimes: lib.foldAttrs (item: acc: [item] ++ acc) [] mimes;
# [ { priority, desktop } ... ] -> Self
sortOneMimeType = associations: builtins.sort
(l: r: assert l.priority != r.priority; l.priority < r.priority)
associations;
sortMimes = mimes: builtins.mapAttrs (_k: sortOneMimeType) mimes;
removePriorities = mimes: builtins.mapAttrs
(_k: associations: builtins.map (a: a.desktop) associations)
mimes;
in in
{ {
# the xdg mime type for a file can be found with: # the xdg mime type for a file can be found with:
@@ -25,4 +38,6 @@ in
# there's also options to *remove* [non-default] associations from specific apps # there's also options to *remove* [non-default] associations from specific apps
xdg.mime.enable = true; xdg.mime.enable = true;
xdg.mime.defaultApplications = removePriorities (sortMimes (mergeMimes enabledWeightedMimes)); xdg.mime.defaultApplications = removePriorities (sortMimes (mergeMimes enabledWeightedMimes));
} }

View File

@@ -19,7 +19,7 @@
}; };
sane.hosts.by-name."moby" = { sane.hosts.by-name."moby" = {
ssh.authorized = lib.mkDefault false; # moby's too easy to hijack: don't let it ssh places # ssh.authorized = lib.mkDefault false; # moby's too easy to hijack: don't let it ssh places
ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICrR+gePnl0nV/vy7I5BzrGeyVL+9eOuXHU1yNE3uCwU"; ssh.user_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICrR+gePnl0nV/vy7I5BzrGeyVL+9eOuXHU1yNE3uCwU";
ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO1N/IT3nQYUD+dBlU1sTEEVMxfOyMkrrDeyHcYgnJvw"; ssh.host_pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO1N/IT3nQYUD+dBlU1sTEEVMxfOyMkrrDeyHcYgnJvw";
wg-home.pubkey = "I7XIR1hm8bIzAtcAvbhWOwIAabGkuEvbWH/3kyIB1yA="; wg-home.pubkey = "I7XIR1hm8bIzAtcAvbhWOwIAabGkuEvbWH/3kyIB1yA=";

View File

@@ -53,6 +53,10 @@
sane.ids.monero.gid = 2416; sane.ids.monero.gid = 2416;
sane.ids.slskd.uid = 2417; sane.ids.slskd.uid = 2417;
sane.ids.slskd.gid = 2417; sane.ids.slskd.gid = 2417;
sane.ids.bitcoind-mainnet.uid = 2418;
sane.ids.bitcoind-mainnet.gid = 2418;
sane.ids.clightning.uid = 2419;
sane.ids.clightning.gid = 2419;
sane.ids.colin.uid = 1000; sane.ids.colin.uid = 1000;
sane.ids.guest.uid = 1100; sane.ids.guest.uid = 1100;

View File

@@ -1,6 +1,12 @@
{ lib, ... }: { lib, ... }:
{ {
imports = [
./dns.nix
./hostnames.nix
./upnp.nix
./vpn.nix
];
# the default backend is "wpa_supplicant". # the default backend is "wpa_supplicant".
# wpa_supplicant reliably picks weak APs to connect to. # wpa_supplicant reliably picks weak APs to connect to.
# see: <https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/474> # see: <https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/474>
@@ -35,10 +41,6 @@
# e.g. openconnect drags in webkitgtk (for SSO)! # e.g. openconnect drags in webkitgtk (for SSO)!
networking.networkmanager.plugins = lib.mkForce []; networking.networkmanager.plugins = lib.mkForce [];
networking.firewall.allowedUDPPorts = [
1900 # to received UPnP advertisements. required by sane-ip-check-upnp
];
# keyfile.path = where networkmanager should look for connection credentials # keyfile.path = where networkmanager should look for connection credentials
networking.networkmanager.extraConfig = '' networking.networkmanager.extraConfig = ''
[keyfile] [keyfile]

37
hosts/common/net/dns.nix Normal file
View File

@@ -0,0 +1,37 @@
{ ... }:
{
# use systemd's stub resolver.
# /etc/resolv.conf isn't sophisticated enough to use different servers per net namespace (or link).
# instead, running the stub resolver on a known address in the root ns lets us rewrite packets
# in the ovnps namespace to use the provider's DNS resolvers.
# a weakness is we can only query 1 NS at a time (unless we were to clone the packets?)
# there also seems to be some cache somewhere that's shared between the two namespaces.
# i think this is a libc thing. might need to leverage proper cgroups to _really_ kill it.
# - getent ahostsv4 www.google.com
# - try fix: <https://serverfault.com/questions/765989/connect-to-3rd-party-vpn-server-but-dont-use-it-as-the-default-route/766290#766290>
services.resolved.enable = true;
# without DNSSEC:
# - dig matrix.org => works
# - curl https://matrix.org => works
# with default DNSSEC:
# - dig matrix.org => works
# - curl https://matrix.org => fails
# i don't know why. this might somehow be interfering with the DNS run on this device (trust-dns)
services.resolved.dnssec = "false";
networking.nameservers = [
# use systemd-resolved resolver
# full resolver (which understands /etc/hosts) lives on 127.0.0.53
# stub resolver (just forwards upstream) lives on 127.0.0.54
"127.0.0.53"
];
# nscd -- the Name Service Caching Daemon -- caches DNS query responses
# in a way that's unaware of my VPN routing, so routes are frequently poor against
# services which advertise different IPs based on geolocation.
# nscd claims to be usable without a cache, but in practice i can't get it to not cache!
# nsncd is the Name Service NON-Caching Daemon. it's a drop-in that doesn't cache;
# this is OK on the host -- because systemd-resolved caches. it's probably sub-optimal
# in the netns and we query upstream DNS more often than needed. hm.
# TODO: run a separate recursive resolver in each namespace.
services.nscd.enableNsncd = true;
}

View File

@@ -1,4 +1,3 @@
# TODO: move to hosts/common/
{ config, lib, ... }: { config, lib, ... }:
{ {

20
hosts/common/net/upnp.nix Normal file
View File

@@ -0,0 +1,20 @@
{ pkgs, ... }:
{
networking.firewall.allowedUDPPorts = [
# to receive UPnP advertisements. required by sane-ip-check.
# N.B. sane-ip-check isn't query/response based. it needs to receive on port 1900 -- not receive responses FROM port 1900.
1900
];
networking.firewall.extraCommands = with pkgs; ''
# after an outgoing SSDP query to the multicast address, open FW for incoming responses.
# necessary for anything DLNA, especially go2tv
# source: <https://serverfault.com/a/911286>
# context: <https://github.com/alexballas/go2tv/issues/72>
# ipset -! means "don't fail if set already exists"
${ipset}/bin/ipset create -! upnp hash:ip,port timeout 10
${iptables}/bin/iptables -A OUTPUT -d 239.255.255.250/32 -p udp -m udp --dport 1900 -j SET --add-set upnp src,src --exist
${iptables}/bin/iptables -A INPUT -p udp -m set --match-set upnp dst,dst -j ACCEPT
'';
}

View File

@@ -8,21 +8,41 @@
# - copy the Address, PublicKey, Endpoint from OVPN's config # - copy the Address, PublicKey, Endpoint from OVPN's config
# N.B.: maximum interface name in Linux is 15 characters. # N.B.: maximum interface name in Linux is 15 characters.
let let
def-wg-vpn = name: { endpoint, publicKey, address, dns, privateKeyFile, extraOptions ? {} }: { def-wg-vpn = name: { endpoint, publicKey, address, dns, privateKeyFile }: {
networking.wg-quick.interfaces."${name}" = { # networking.wg-quick.interfaces."${name}" = {
inherit address privateKeyFile dns; # inherit address privateKeyFile dns;
peers = [ # peers = [
{ # {
allowedIPs = [ # allowedIPs = [
"0.0.0.0/0" # "0.0.0.0/0"
"::/0" # "::/0"
]; # ];
inherit endpoint publicKey; # inherit endpoint publicKey;
} # }
]; # ];
# to start: `systemctl start wg-quick-${name}` # # to start: `systemctl start wg-quick-${name}`
autostart = false; # autostart = false;
} // extraOptions; # };
systemd.network.netdevs."${name}" = {
# see: `man 5 systemd.netdev`
wireguardConfig = {
PrivateKeyFile = privateKeyFile;
};
wireguardPeers = [{
AllowedIPs = [
"0.0.0.0/0"
"::/0"
];
Endpoint = endpoint;
PublicKey = publicKey;
}];
};
systemd.network.networks."${name}" = {
# see: `man 5 systemd.network`
matchConfig.Name = name;
networkConfig.Address = address;
networkConfig.DNS = dns;
};
}; };
def-ovpn = name: { endpoint, publicKey, address }: def-wg-vpn "ovpnd-${name}" { def-ovpn = name: { endpoint, publicKey, address }: def-wg-vpn "ovpnd-${name}" {
inherit endpoint publicKey address; inherit endpoint publicKey address;

View File

@@ -10,7 +10,7 @@ in
type = types.submodule { type = types.submodule {
options.autostart = mkOption { options.autostart = mkOption {
type = types.bool; type = types.bool;
default = true; default = false;
}; };
}; };
}; };
@@ -22,14 +22,6 @@ in
name = ''"view members" default to false''; name = ''"view members" default to false'';
hash = "sha256-9BX8iO86CU1lNrKS1G2BjDR+3IlV9bmhRNTsLrxChwQ="; hash = "sha256-9BX8iO86CU1lNrKS1G2BjDR+3IlV9bmhRNTsLrxChwQ=";
}) })
(pkgs.fetchpatch {
# this makes it so Abaddon reports its app_name in notifications.
# not 100% necessary; just a nice-to-have. maybe don't rely on it until it's merged upstream.
# upstream PR: <https://github.com/uowuo/abaddon/pull/247>
url = "https://git.uninsane.org/colin/abaddon/commit/18cd863fdbb5e6b1e9aaf9394dbd673d51839f30.patch";
name = "set glib application name";
hash = "sha256-IFYxf1D8hIsxgZehGd6hL3zJiBkPZfWGm+Faaa5ZFl4=";
})
]; ];
}); });

View File

@@ -7,18 +7,34 @@
{ {
sane.programs.alacritty = { sane.programs.alacritty = {
env.TERMINAL = lib.mkDefault "alacritty"; env.TERMINAL = lib.mkDefault "alacritty";
# note: alacritty will switch to .toml config in 13.0 release fs.".config/alacritty/alacritty.toml".symlink.text = ''
# - run `alacritty migrate` to convert the yaml to toml [font]
fs.".config/alacritty/alacritty.yml".symlink.text = '' size = 14
font:
size: 14
key_bindings: [[keyboard.bindings]]
- { key: N, mods: Control, action: CreateNewWindow } mods = "Control"
- { key: PageUp, mods: Control, action: ScrollPageUp } key = "N"
- { key: PageDown, mods: Control, action: ScrollPageDown } action = "CreateNewWindow"
- { key: PageUp, mods: Control|Shift, action: ScrollPageUp }
- { key: PageDown, mods: Control|Shift, action: ScrollPageDown } [[keyboard.bindings]]
mods = "Control"
key = "PageUp"
action = "ScrollPageUp"
[[keyboard.bindings]]
mods = "Control"
key = "PageDown"
action = "ScrollPageDown"
[[keyboard.bindings]]
mods = "Control|Shift"
key = "PageUp"
action = "ScrollPageUp"
[[keyboard.bindings]]
mods = "Control|Shift"
key = "PageDown"
action = "ScrollPageDown"
''; '';
}; };
} }

View File

@@ -44,11 +44,10 @@ in
"sane-scripts.shutdown" "sane-scripts.shutdown"
"sane-scripts.sudo-redirect" "sane-scripts.sudo-redirect"
"sane-scripts.sync-from-servo" "sane-scripts.sync-from-servo"
"sane-scripts.tag-music"
"sane-scripts.vpn" "sane-scripts.vpn"
"sane-scripts.which" "sane-scripts.which"
"sane-scripts.wipe-browser" "sane-scripts.wipe"
"sane-scripts.wipe-flare"
"sane-scripts.wipe-fractal"
]; ];
"sane-scripts.sys-utils" = declPackageSet [ "sane-scripts.sys-utils" = declPackageSet [
"sane-scripts.ip-port-forward" "sane-scripts.ip-port-forward"
@@ -110,6 +109,7 @@ in
"wget" "wget"
"wirelesstools" # iwlist "wirelesstools" # iwlist
"xq" # jq for XML "xq" # jq for XML
# "zfs" # doesn't cross-compile (requires samba)
]; ];
sysadminExtraUtils = declPackageSet [ sysadminExtraUtils = declPackageSet [
"backblaze-b2" "backblaze-b2"
@@ -144,6 +144,7 @@ in
"lshw" "lshw"
# "memtester" # "memtester"
"mercurial" # hg "mercurial" # hg
"mimeo" # like xdg-open
"neovim" # needed as a user package, for swap persistence "neovim" # needed as a user package, for swap persistence
# "nettools" # "nettools"
# "networkmanager" # "networkmanager"
@@ -182,7 +183,9 @@ in
]; ];
consoleMediaUtils = declPackageSet [ consoleMediaUtils = declPackageSet [
"catt" # cast videos to chromecast
"ffmpeg" "ffmpeg"
"go2tv" # cast videos to UPNP/DLNA device (i.e. tv).
"imagemagick" "imagemagick"
"sox" "sox"
"yt-dlp" "yt-dlp"
@@ -219,6 +222,9 @@ in
cargo.persist.byStore.plaintext = [ ".cargo" ]; cargo.persist.byStore.plaintext = [ ".cargo" ];
# auth token, preferences
delfin.persist.byStore.private = [ ".config/delfin" ];
# creds, but also 200 MB of node modules, etc # creds, but also 200 MB of node modules, etc
discord.persist.byStore.private = [ ".config/discord" ]; discord.persist.byStore.private = [ ".config/discord" ];
@@ -276,9 +282,6 @@ in
whalebird.persist.byStore.private = [ ".config/Whalebird" ]; whalebird.persist.byStore.private = [ ".config/Whalebird" ];
yarn.persist.byStore.plaintext = [ ".cache/yarn" ]; yarn.persist.byStore.plaintext = [ ".cache/yarn" ];
# zcash coins. safe to delete, just slow to regenerate (10-60 minutes)
zecwallet-lite.persist.byStore.private = [ ".zcash" ];
}; };
programs.feedbackd = lib.mkIf config.sane.programs.feedbackd.enabled { programs.feedbackd = lib.mkIf config.sane.programs.feedbackd.enabled {

View File

@@ -0,0 +1,22 @@
{ pkgs, ... }:
{
sane.programs.audacity = {
package = pkgs.audacity.override {
# wxGTK32 uses webkitgtk-4.0.
# audacity doesn't actually need webkit though, so diable to reduce closure
wxGTK32 = pkgs.wxGTK32.override {
withWebKit = false;
};
};
# disable first-run splash screen
fs.".config/audacity/audacity.cfg".file.text = ''
PrefsVersion=1.1.1r1
[GUI]
ShowSplashScreen=0
[Version]
Major=3
Minor=4
'';
};
}

View File

@@ -0,0 +1,29 @@
# use like:
# - catt -d lgtv_chrome cast ./path/to.mp4
#
# support matrix:
# - webm: audio only
# - mp4: audio + video
{ config, lib, ... }:
let
cfg = config.sane.programs.catt;
in
{
sane.programs.catt = {
fs.".config/catt/catt.cfg".symlink.text = ''
[options]
device = lgtv_chrome
[aliases]
lgtv_chrome = 10.78.79.106
'';
};
# necessary to cast local files
networking.firewall.allowedTCPPortRanges = lib.mkIf cfg.enabled [
{
from = 45000;
to = 47000;
}
];
}

View File

@@ -1,40 +1,8 @@
{ pkgs, ... }: { pkgs, ... }:
let
chattyNoOauth = pkgs.chatty.override {
# the OAuth feature (presumably used for web-based logins) pulls a full webkitgtk.
# especially when using the gtk3 version of evolution-data-server, it's an ancient webkitgtk_4_1.
# disable OAuth for a faster build & smaller closure
evolution-data-server = pkgs.evolution-data-server.override {
enableOAuth2 = false;
gnome-online-accounts = pkgs.gnome-online-accounts.override {
# disables the upstream "goabackend" feature -- presumably "Gnome Online Accounts Backend"
# frees us from webkit_4_1, in turn.
enableBackend = false;
gvfs = pkgs.gvfs.override {
# saves 20 minutes of build time, for unused feature
samba = null;
};
};
};
};
chatty-latest = pkgs.chatty-latest.override {
evolution-data-server-gtk4 = pkgs.evolution-data-server-gtk4.override {
gnome-online-accounts = pkgs.gnome-online-accounts.override {
# disables the upstream "goabackend" feature -- presumably "Gnome Online Accounts Backend"
# frees us from webkit_4_1, in turn.
enableBackend = false;
gvfs = pkgs.gvfs.override {
# saves 20 minutes of build time and cross issues, for unused feature
samba = null;
};
};
};
};
in
{ {
sane.programs.chatty = { sane.programs.chatty = {
# package = chattyNoOauth; # package = chattyNoOauth;
package = chatty-latest; package = pkgs.chatty-latest;
suggestedPrograms = [ "gnome-keyring" ]; suggestedPrograms = [ "gnome-keyring" ];
persist.byStore.private = [ persist.byStore.private = [
".local/share/chatty" # matrix avatars and files ".local/share/chatty" # matrix avatars and files

View File

@@ -1,52 +1,184 @@
#!/bin/sh
#!/usr/bin/env nix-shell #!/usr/bin/env nix-shell
#!nix-shell -i bash #!nix-shell -i bash
usage() {
echo "usage: battery_estimate [options...]"
echo
echo "pretty-prints a battery estimate (icon to indicate state, and a duration estimate)"
echo
echo "options:"
echo " --debug: output additional information, to stderr"
echo " --minute-suffix <string>: use the provided string as a minutes suffix"
echo " --hour-suffix <string>: use the provided string as an hours suffix"
echo " --icon-suffix <string>: use the provided string as an icon suffix"
echo " --percent-suffix <string>: use the provided string when displaying percents"
}
# these icons come from sxmo; they only render in nerdfonts # these icons come from sxmo; they only render in nerdfonts
bat_dis="󱊢" icon_bat_chg=("󰢟" "󱊤" "󱊥" "󰂅")
bat_chg="󱊥" icon_bat_dis=("󰂎" "󱊡" "󱊢" "󱊣")
suffix_icon="" # thin space
suffix_percent="%"
# suffix_icon=" "
# render time like: 2ʰ08ᵐ
# unicode sub/super-scripts: <https://en.wikipedia.org/wiki/Unicode_subscripts_and_superscripts>
# symbol_hr="ʰ"
# symbol_min="ᵐ"
# render time like: 2ₕ08ₘ
# symbol_hr="ₕ"
# symbol_min="ₘ"
# render time like: 2h08m
# symbol_hr="h"
# symbol_min="m"
# render time like: 2:08
# symbol_hr=":"
# symbol_min=
# render time like: 208⧗
symbol_hr=""
symbol_min="⧗"
# variants:
# symbol_hr=":"
# symbol_min="⧖"
# symbol_min="⌛"
# render time like: 2'08"
# symbol_hr="'"
# symbol_min='"'
log() {
if [ "$BATTERY_ESTIMATE_DEBUG" = "1" ]; then
printf "$@" >&2
echo >&2
fi
}
render_icon() {
# args:
# 1: "chg" or "dis"
# 2: current battery percentage
level=$(($2 / 25))
level=$(($level > 3 ? 3 : $level))
level=$(($level < 0 ? 0 : $level))
log "icon: %s %d" "$1" "$level"
if [ "$1" = "dis" ]; then
printf "%s" "${icon_bat_dis[$level]}"
elif [ "$1" = "chg" ]; then
printf "%s" "${icon_bat_chg[$level]}"
fi
}
try_path() { try_path() {
# returns: # assigns output variables:
# - perc, perc_left (0-100) # - perc, perc_from_full (0-100)
# - full, rate (pos means charging) # - full, rate (pos means charging)
if [ -f "$1/capacity" ]; then if [ -f "$1/capacity" ]; then
log "perc, perc_from_full from %s" "$1/capacity"
perc=$(cat "$1/capacity") perc=$(cat "$1/capacity")
perc_left=$((100 - $perc)) perc_from_full=$((100 - $perc))
fi fi
if [ -f "$1/charge_full_design" ] && [ -f "$1/current_now" ]; then if [ -f "$1/charge_full_design" ] && [ -f "$1/current_now" ]; then
log "full, rate from %s and %s" "$1/charge_full_design" "$1/current_now"
# current is positive when charging # current is positive when charging
full=$(cat "$1/charge_full_design") full=$(cat "$1/charge_full_design")
rate=$(cat "$1/current_now") rate=$(cat "$1/current_now")
fi elif [ -f "$1/energy_full" ] && [ -f "$1/power_now" ]; then
if [ -f "$1/energy_full" ] && [ -f "$1/energy_now" ]; then log "full, rate from %s and %s" "$1/energy_full" "$1/power_now"
# energy is positive when discharging # power_now is positive when discharging
full=$(cat "$1/energy_full")
rate=-$(cat "$1/power_now")
elif [ -f "$1/energy_full" ] && [ -f "$1/energy_now" ]; then
log "full, rate from %s and %s" "$1/energy_full" "$1/energy_now"
log " this is a compatibility path for legacy Thinkpad batteries which do not populate the 'power_now' field, and incorrectly populate 'energy_now' with power info"
# energy_now is positive when discharging
full=$(cat "$1/energy_full") full=$(cat "$1/energy_full")
rate=-$(cat "$1/energy_now") rate=-$(cat "$1/energy_now")
fi fi
} }
try_path "/sys/class/power_supply/axp20x-battery" # Pinephone try_all_paths() {
try_path "/sys/class/power_supply/BAT0" # Thinkpad try_path "/sys/class/power_supply/axp20x-battery" # Pinephone
try_path "/sys/class/power_supply/BAT0" # Thinkpad
log "perc: %d, perc_from_full: %d" "$perc" "$perc_from_full"
log "full: %f, rate: %f" "$full" "$rate"
log " rate > 0 means charging, else discharging"
}
fmt_minutes() { fmt_minutes() {
# args:
# 1: icon to render
# 2: string to show if charge/discharge time is indefinite
# 3: minutes to stable state (i.e. to full charge or full discharge)
# - we work in minutes instead of hours for precision: bash math is integer-only
log "charge/discharge time: %f min" "$3"
# args: <battery symbol> <text if ludicrous estimate> <estimated minutes to full/empty> # args: <battery symbol> <text if ludicrous estimate> <estimated minutes to full/empty>
if [[ $3 -gt 1440 ]]; then if [ -n "$3" ] && [ "$3" -lt 1440 ]; then
printf "%s %s" "$1" "$2" # more than 1d
else
hr=$(($3 / 60)) hr=$(($3 / 60))
hr_in_min=$(($hr * 60)) hr_in_min=$(($hr * 60))
min=$(($3 - $hr_in_min)) min=$(($3 - $hr_in_min))
printf "%s %dh%02dm" "$1" "$hr" "$min" printf "%s%s%d%s%02d%s" "$1" "$suffix_icon" "$hr" "$symbol_hr" "$min" "$symbol_min"
else
log "charge/discharge duration > 1d"
printf "%s%s%s" "$1" "$suffix_icon" "$2" # more than 1d
fi fi
} }
if [[ $rate -lt 0 ]]; then pretty_output() {
# discharging if [ -n "$perc" ]; then
fmt_minutes "$bat_dis" '∞' "$(($full * 60 * $perc / (-100 * $rate)))" duration=""
elif [[ $rate -gt 0 ]]; then if [ "$rate" -gt 0 ]; then
# charging log "charging"
fmt_minutes "$bat_chg" '100%' "$(($full * 60 * $perc_left / (100 * $rate)))" icon="$(render_icon chg $perc)"
elif [[ "$perc" != "" ]]; then duration="$(($full * 60 * $perc_from_full / (100 * $rate)))"
echo "$bat_dis $perc%" else
fi log "discharging"
icon="$(render_icon dis $perc)"
if [ "$rate" -lt 0 ]; then
duration="$(($full * 60 * $perc / (-100 * $rate)))"
fi
fi
fmt_minutes "$icon" "$perc$suffix_percent" "$duration"
fi
}
while [ "$#" -gt 0 ]; do
case "$1" in
"--debug")
shift
BATTERY_ESTIMATE_DEBUG=1
;;
"--icon-suffix")
shift
suffix_icon="$1"
shift
;;
"--hour-suffix")
shift
symbol_hr="$1"
shift
;;
"--minute-suffix")
shift
symbol_min="$1"
shift
;;
"--percent-suffix")
shift
suffix_percent="$1"
shift
;;
*)
usage
exit 1
;;
esac
done
try_all_paths
pretty_output

View File

@@ -3,48 +3,80 @@
-- - can also use #rrggbb syntax -- - can also use #rrggbb syntax
-- example configs: <https://forum.manjaro.org/t/conky-showcase-2022/97123> -- example configs: <https://forum.manjaro.org/t/conky-showcase-2022/97123>
-- example configs: <https://www.reddit.com/r/Conkyporn/> -- example configs: <https://www.reddit.com/r/Conkyporn/>
--
-- exec options:
-- `exec <cmd>` => executes the command, synchronously, renders its output as text
-- `texeci <interval_sec> <cmd>` => executes the command periodically, async (to not block render), renders as text
-- `pexec <cmd>` => executes the command, synchronously, parses its output
conky.config = { conky.config = {
out_to_wayland = true, out_to_wayland = true,
update_interval = 10, update_interval = 10,
alignment = 'middle_middle', alignment = 'middle_middle',
own_window_type = 'desktop', own_window_type = 'desktop',
-- own_window_argb_value: opacity of the background (0-255) -- own_window_argb_value: opacity of the background (0-255)
own_window_argb_value = 0, own_window_argb_value = 0,
-- own_window_argb_value = 92, -- own_window_argb_value = 92,
-- own_window_colour = '#beebe5', -- beebe5 matches nixos flake bg color -- own_window_colour = '#beebe5', -- beebe5 matches nixos flake bg color
-- "border" pads the entire conky window -- "border" pads the entire conky window
-- this can be used to control the extent of the own_window background -- this can be used to control the extent of the own_window background
border_inner_margin = 8, border_inner_margin = 8,
-- optionally, actually draw borders -- optionally, actually draw borders
-- draw_borders = true, -- draw_borders = true,
-- shades are drop-shadows, outline is the centered version. both apply to text only -- shades are drop-shadows, outline is the centered version. both apply to text only
draw_shades = true, draw_shades = true,
draw_outline = false, draw_outline = false,
default_shade_color = '#beebe5', default_shade_color = '#beebe5',
default_outline_color = '#beebe5', default_outline_color = '#beebe5',
font = 'sans-serif:size=8', font = 'sans-serif:size=8',
use_xft = true, use_xft = true,
default_color = '#ffffff', default_color = '#ffffff',
color1 = '000000', color1 = '000000',
color2 = '404040', color2 = '404040',
} }
-- texeci <interval_sec> <cmd>: run the command periodically, _in a separate thread_ so as not to block rendering vars = {
-- kBps = 'K/s',
kBps = 'ᴷᐟˢ',
-- percent = '%',
-- percent = '﹪',
percent = '٪',
-- percent = '⁒',
-- percent = '',
icon_suffix = nil,
hour_suffix = nil,
minute_suffix = '${font sans-serif:size=14}${color2}⧗',
}
bat_args = ""
if vars.icon_suffix ~= nil then
bat_args = bat_args .. " --icon-suffix '" .. vars.icon_suffix .. "'"
end
if vars.hour_suffix ~= nil then
bat_args = bat_args .. " --hour-suffix '" .. vars.hour_suffix .. "'"
end
if vars.minute_suffix ~= nil then
bat_args = bat_args .. " --minute-suffix '" .. vars.minute_suffix .. "'"
end
if vars.percent ~= nil then
bat_args = bat_args .. " --percent-suffix '" .. vars.percent .. "'"
end
-- N.B.: `[[ <text> ]]` is Lua's multiline string literal
conky.text = [[ conky.text = [[
${color1}${shadecolor 707070}${font sans-serif:size=50:style=Bold}${alignc}${exec date +"%H:%M"}${font} ${color1}${shadecolor 707070}${font sans-serif:size=50:style=Bold}${alignc}${exec date +"%H:%M"}${font}
${color2}${shadecolor a4d7d0}${font sans-serif:size=20}${alignc}${exec date +"%a %d %b"}${font} ${color2}${shadecolor a4d7d0}${font sans-serif:size=20}${alignc}${exec date +"%a %d %b"}${font}
${color1}${shadecolor}${font sans-serif:size=22:style=Bold}${alignc}${exec @bat@ }${font} ${color1}${shadecolor}${font sans-serif:size=22:style=Bold}${alignc}${execp @bat@ ]] .. bat_args .. [[ }${font}
${color1}${shadecolor}${font sans-serif:size=20:style=Bold}${alignc}${texeci 600 @weather@ }${font} ${color1}${shadecolor}${font sans-serif:size=20:style=Bold}${alignc}${texeci 600 @weather@ }${font}
${color2}${shadecolor a4d7d0}${font sans-serif:size=16}${alignc}⇅ ${downspeedf wlan0}K/s${font} ${color2}${shadecolor a4d7d0}${font sans-serif:size=16}${alignc}⇅ ${downspeedf wlan0}]] .. vars.kBps .. [[${font}
${font sans-serif:size=16}${alignc}☵ $memperc%  $cpu%${font} ${font sans-serif:size=16}${alignc}☵ $memperc]] .. vars.percent .. [[  $cpu]] .. vars.percent .. [[${font}
]] ]]

View File

@@ -7,10 +7,12 @@
./alacritty.nix ./alacritty.nix
./animatch.nix ./animatch.nix
./assorted.nix ./assorted.nix
./audacity.nix
./bemenu.nix ./bemenu.nix
./brave.nix ./brave.nix
./calls.nix ./calls.nix
./cantata.nix ./cantata.nix
./catt.nix
./chatty.nix ./chatty.nix
./conky ./conky
./cozy.nix ./cozy.nix
@@ -32,6 +34,7 @@
./gnome-feeds.nix ./gnome-feeds.nix
./gnome-keyring.nix ./gnome-keyring.nix
./gnome-weather.nix ./gnome-weather.nix
./go2tv.nix
./gpodder.nix ./gpodder.nix
./gthumb.nix ./gthumb.nix
./gtkcord4.nix ./gtkcord4.nix
@@ -42,19 +45,24 @@
./koreader ./koreader
./libreoffice.nix ./libreoffice.nix
./lemoa.nix ./lemoa.nix
./loupe.nix
./mako.nix ./mako.nix
./megapixels.nix
./mepo.nix ./mepo.nix
./mimeo
./mopidy.nix ./mopidy.nix
./mpv.nix ./mpv.nix
./msmtp.nix ./msmtp.nix
./nautilus.nix
./neovim.nix ./neovim.nix
./newsflash.nix ./newsflash.nix
./nheko.nix ./nheko.nix
./nix-index.nix ./nix-index.nix
./notejot.nix
./ntfy-sh.nix ./ntfy-sh.nix
./obsidian.nix ./obsidian.nix
./offlineimap.nix ./offlineimap.nix
./open-in-mpv.nix
./planify.nix
./playerctl.nix ./playerctl.nix
./rhythmbox.nix ./rhythmbox.nix
./ripgrep.nix ./ripgrep.nix
@@ -76,8 +84,10 @@
./wike.nix ./wike.nix
./wine.nix ./wine.nix
./wireshark.nix ./wireshark.nix
./wob.nix
./xarchiver.nix ./xarchiver.nix
./zeal.nix ./zeal.nix
./zecwallet-lite.nix
./zsh ./zsh
]; ];

View File

@@ -40,7 +40,7 @@ in
type = types.submodule { type = types.submodule {
options.autostart = mkOption { options.autostart = mkOption {
type = types.bool; type = types.bool;
default = false; default = true;
}; };
}; };
}; };

View File

@@ -1,3 +1,6 @@
# test with e.g.
# - `fbcli --event proxied-message-new-instant`
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
let let
cfg = config.sane.programs.feedbackd; cfg = config.sane.programs.feedbackd;

View File

@@ -38,25 +38,16 @@ let
# defaultSettings = firefoxSettings; # defaultSettings = firefoxSettings;
defaultSettings = librewolfSettings; defaultSettings = librewolfSettings;
addon = name: extid: hash: pkgs.fetchFirefoxAddon { package = (pkgs.wrapFirefox cfg.browser.browser {
inherit name hash;
url = "https://addons.mozilla.org/firefox/downloads/latest/${name}/latest.xpi";
# extid can be found by unar'ing the above xpi, and copying browser_specific_settings.gecko.id field
fixedExtid = extid;
};
localAddon = pkg: pkgs.fetchFirefoxAddon {
inherit (pkg) name;
src = "${pkg}/share/mozilla/extensions/\\{ec8030f7-c20a-464f-9b0e-13a3a9e97384\\}/${pkg.extid}.xpi";
fixedExtid = pkg.extid;
};
package = pkgs.wrapFirefox cfg.browser.browser {
# inherit the default librewolf.cfg # inherit the default librewolf.cfg
# it can be further customized via ~/.librewolf/librewolf.overrides.cfg # it can be further customized via ~/.librewolf/librewolf.overrides.cfg
inherit (cfg.browser) extraPrefsFiles libName; inherit (cfg.browser) extraPrefsFiles libName;
extraNativeMessagingHosts = optional cfg.addons.browserpass-extension.enable pkgs.browserpass; nativeMessagingHosts = lib.optionals cfg.addons.browserpass-extension.enable [
# extraNativeMessagingHosts = [ pkgs.gopass-native-messaging-host ]; pkgs.browserpass
] ++ lib.optionals cfg.addons.fxCast.enable [
pkgs.fx-cast-bridge
];
nixExtensions = concatMap (ext: optional ext.enable ext.package) (attrValues cfg.addons); nixExtensions = concatMap (ext: optional ext.enable ext.package) (attrValues cfg.addons);
@@ -113,7 +104,17 @@ let
# NewTabPage = true; # NewTabPage = true;
}; };
# extraPrefs = ... # extraPrefs = ...
}; }).overrideAttrs (base: {
# de-associate `ctrl+shift+c` from activating the devtools.
# based on <https://stackoverflow.com/a/54260938>
buildCommand = (base.buildCommand or "") + ''
mkdir omni
${pkgs.buildPackages.unzip}/bin/unzip $out/lib/${cfg.browser.libName}/browser/omni.ja -d omni
rm $out/lib/${cfg.browser.libName}/browser/omni.ja
${pkgs.buildPackages.gnused}/bin/sed -i s'/devtools-commandkey-inspector = C/devtools-commandkey-inspector = VK_F12/' omni/localization/en-US/devtools/startup/key-shortcuts.ftl
pushd omni; ${pkgs.buildPackages.zip}/bin/zip $out/lib/${cfg.browser.libName}/browser/omni.ja -r ./*; popd
'';
});
addonOpts = types.submodule { addonOpts = types.submodule {
options = { options = {
@@ -157,6 +158,16 @@ in
default = {}; default = {};
}; };
sane.programs.firefox.config.addons = { sane.programs.firefox.config.addons = {
fxCast = {
# add a menu to cast to chromecast devices, but it doesn't seem to work very well.
# right click (or shift+rc) a video, then select "cast".
# - asciinema.org: icon appears, but glitches when clicked.
# - youtube.com: no icon appears, even when site is whitelisted.
# future: maybe better to have browser open all videos in mpv, and then use mpv for casting.
# see e.g. `ff2mpv`, `open-in-mpv` (both are packaged in nixpkgs)
package = pkgs.firefox-extensions.fx_cast;
enable = lib.mkDefault false;
};
browserpass-extension = { browserpass-extension = {
package = pkgs.firefox-extensions.browserpass-extension; package = pkgs.firefox-extensions.browserpass-extension;
enable = lib.mkDefault true; enable = lib.mkDefault true;
@@ -165,6 +176,10 @@ in
package = pkgs.firefox-extensions.bypass-paywalls-clean; package = pkgs.firefox-extensions.bypass-paywalls-clean;
enable = lib.mkDefault true; enable = lib.mkDefault true;
}; };
ctrl-shift-c-should-copy = {
package = pkgs.firefox-extensions.ctrl-shift-c-should-copy;
enable = lib.mkDefault false; # prefer patching firefox source code, so it works in more places
};
ether-metamask = { ether-metamask = {
package = pkgs.firefox-extensions.ether-metamask; package = pkgs.firefox-extensions.ether-metamask;
enable = lib.mkDefault false; # until i can disable the first-run notification enable = lib.mkDefault false; # until i can disable the first-run notification
@@ -173,6 +188,10 @@ in
package = pkgs.firefox-extensions.i2p-in-private-browsing; package = pkgs.firefox-extensions.i2p-in-private-browsing;
enable = lib.mkDefault config.services.i2p.enable; enable = lib.mkDefault config.services.i2p.enable;
}; };
open-in-mpv = {
package = pkgs.firefox-extensions.open-in-mpv;
enable = lib.mkDefault config.sane.programs.open-in-mpv.enabled;
};
sidebery = { sidebery = {
package = pkgs.firefox-extensions.sidebery; package = pkgs.firefox-extensions.sidebery;
enable = lib.mkDefault true; enable = lib.mkDefault true;
@@ -195,6 +214,10 @@ in
sane.programs.firefox = { sane.programs.firefox = {
inherit package; inherit package;
suggestedPrograms = [
"open-in-mpv"
];
mime.associations = let mime.associations = let
inherit (cfg.browser) desktop; inherit (cfg.browser) desktop;
in { in {
@@ -239,6 +262,18 @@ in
// note that too-large scrollbars (like 50px wide) tend to obscure content (and make buttons unclickable) // note that too-large scrollbars (like 50px wide) tend to obscure content (and make buttons unclickable)
defaultPref("widget.non-native-theme.scrollbar.size.override", 20); defaultPref("widget.non-native-theme.scrollbar.size.override", 20);
defaultPref("widget.non-native-theme.scrollbar.style", 4); defaultPref("widget.non-native-theme.scrollbar.style", 4);
// disable inertial/kinetic/momentum scrolling because it just gets in the way on touchpads
// source: <https://kparal.wordpress.com/2019/10/31/disabling-kinetic-scrolling-in-firefox/>
defaultPref("apz.gtk.kinetic_scroll.enabled", false);
// auto-dispatch mpv:// URIs to xdg-open without prompting.
// can do this with other protocols too (e.g. matrix?). see about:config for common handlers.
defaultPref("network.protocol-handler.external.mpv", true);
// element:// for Element matrix client
defaultPref("network.protocol-handler.external.element", true);
// matrix: for Nheko matrix client
defaultPref("network.protocol-handler.external.matrix", true);
''; '';
fs."${cfg.browser.dotDir}/default".dir = {}; fs."${cfg.browser.dotDir}/default".dir = {};
# instruct Firefox to put the profile in a predictable directory (so we can do things like persist just it). # instruct Firefox to put the profile in a predictable directory (so we can do things like persist just it).

View File

@@ -1,15 +1,18 @@
# Flare is a 3rd-party GTK4 Signal app. # Flare is a 3rd-party GTK4 Signal app.
# UI is effectively a clone of Fractal. # UI is effectively a clone of Fractal.
# #
# compatibility: ### compatibility:
# - desko: works fine. pairs, and exchanges contact list (but not message history) with the paired device. exchanges future messages fine. # - desko: works fine. pairs, and exchanges contact list (but not message history) with the paired device. exchanges future messages fine.
# - moby (cross compiled flare-signal-nixified): nope. it pairs, but can only *receive* messages and never *send* them. # - moby (cross compiled flare-signal-nixified): nope. it pairs, but can only *receive* messages and never *send* them.
# - even `rsync`ing the data and keyrings from desko -> moby, still fails in that same manner. # - even `rsync`ing the data and keyrings from desko -> moby, still fails in that same manner.
# - console shows error messages. quite possibly an endianness mismatch somewhere # - console shows error messages. quite possibly an endianness mismatch somewhere
# - moby (partially-emulated flare-signal): works! pairs and can send/receive messages, same as desko. # - moby (partially-emulated flare-signal): works! pairs and can send/receive messages, same as desko.
# #
# error signatures (to reset, run `sane-wipe-fractal`): ### debugging:
# - upon sending a message, the other side receives it, but Signal desktop gets "A message from Colin could not be delivered" and the local CLI shows: # - `RUST_LOG=flare=trace flare`
#
### error signatures (to reset, run `sane-wipe flare`):
#### upon sending a message, the other side receives it, but Signal desktop gets "A message from Colin could not be delivered" and the local CLI shows:
# ``` # ```
# ERROR libsignal_service::websocket] SignalWebSocket: Websocket error: SignalWebSocket: end of application request stream; socket closing # ERROR libsignal_service::websocket] SignalWebSocket: Websocket error: SignalWebSocket: end of application request stream; socket closing
# ERROR presage::manager] Error opening envelope: ProtobufDecodeError(DecodeError { description: "invalid tag value: 0", stack: [("Content", "data_message")] }), message will be skipped! # ERROR presage::manager] Error opening envelope: ProtobufDecodeError(DecodeError { description: "invalid tag value: 0", stack: [("Content", "data_message")] }), message will be skipped!
@@ -18,7 +21,8 @@
# - this occurs on moby, desko, `flare-signal` and `flare-signal-nixified` # - this occurs on moby, desko, `flare-signal` and `flare-signal-nixified`
# - the Websocket error seems to be unrelated, occurs during normal/good operation # - the Websocket error seems to be unrelated, occurs during normal/good operation
# - related issues: <https://github.com/whisperfish/presage/issues/152> # - related issues: <https://github.com/whisperfish/presage/issues/152>
# error when sending from Flare to other Flare device: #
#### error when sending from Flare to other Flare device:
# - ``` # - ```
# ERROR libsignal_protocol::session_cipher] Message from <UUID>.3 failed to decrypt; sender ratchet public key <key> message counter 1 # ERROR libsignal_protocol::session_cipher] Message from <UUID>.3 failed to decrypt; sender ratchet public key <key> message counter 1
# No current session # No current session
@@ -26,6 +30,32 @@
# ``` # ```
# - but signal iOS will still read it. # - but signal iOS will still read it.
# #
#### HTTP 405 when linking flare to iOS signal:
# [DEBUG libsignal_service_hyper::push_service] HTTP request PUT https://chat.signal.org/v1/devices/{uuid}.{timestamp?}:{b64-string}
# [TRACE libsignal_service_hyper::push_service] Unhandled response 405 with body: {"code":405,"message":"HTTP 405 Method Not Allowed"}
# [ERROR flare::gui::error_dialog] ErrorDialog displaying error: Something unexpected happened with the signal backend. Please retry later.
# [TRACE flare::gui::error_dialog] ErrorDialog full error: Presage(
# ProvisioningError(
# ServiceError(
# UnhandledResponseCode {
# http_code: 405,
# },
# ),
# ),
# )
# flare matrix suggests the signal endpoint has changed:
# - "/v1/device/link instead of confirming via /v1/devices/{I'd}"
# - this endpoint is declared in libsignal-service-rs (used both by flare and presage)
# - libsignal-service/src/provisioning/manager.rs
# - libsignal-service issues a put_json to that URL (i.e. HTTP PUT)
# - libsignal-service is "based on" the official rust signal API <https://github.com/signalapp/libsignal>
# - did these guys recently change it?
# - no, but Signal-Desktop did. see ccb5eb0dd2 from 2023/08/29
# - that's a fairly involved change.
# - signalcli is reporting this same error: <https://github.com/AsamK/signal-cli/issues/1399>
# - Mixin Messenger / libsignal_protocol_dart doesn't seem to be reporting any issue
# - <https://github.com/MixinNetwork/flutter-app>
#
# well, seems to have unpredictable errors particularly when being used on multiple devices. # well, seems to have unpredictable errors particularly when being used on multiple devices.
# desktop _seems_ more reliable than on mobile, but not confident. # desktop _seems_ more reliable than on mobile, but not confident.

View File

@@ -23,7 +23,7 @@ let
in in
{ {
sane.programs.fractal = { sane.programs.fractal = {
package = pkgs.fractal-nixified; package = pkgs.fractal-nixified.optimized;
# package = pkgs.fractal-latest; # package = pkgs.fractal-latest;
# package = pkgs.fractal-next; # package = pkgs.fractal-next;

View File

@@ -13,6 +13,7 @@ in
user.name = "Colin"; user.name = "Colin";
user.email = "colin@uninsane.org"; user.email = "colin@uninsane.org";
alias.amend = "commit --amend --no-edit";
alias.br = "branch"; alias.br = "branch";
alias.co = "checkout"; alias.co = "checkout";
alias.cp = "cherry-pick"; alias.cp = "cherry-pick";
@@ -23,6 +24,7 @@ in
alias.st = "status"; alias.st = "status";
alias.stat = "status"; alias.stat = "status";
diff.noprefix = true; #< don't show a/ or b/ prefixes in diffs
# difftastic docs: # difftastic docs:
# - <https://difftastic.wilfred.me.uk/git.html> # - <https://difftastic.wilfred.me.uk/git.html>
diff.tool = "difftastic"; diff.tool = "difftastic";

View File

@@ -0,0 +1,38 @@
# TROUBLESHOOTING:
# - turn the tv off and on again (no, really...)
#
# SANITY CHECKS:
# - `go2tv -u 'https://uninsane.org/share/AmenBreak.mp4'`
# - LGTV: works, but not seekable
# - `go2tv -u 'https://youtu.be/p3G5IXn0K7A'`
# - LGTV: FAILS ("this file cannot be recognized")
# - no fix via transcoding, altering the URI, etc.
# - workable if you use an invidious frontend, but you lose seeking.
# - e.g. `go2tv -u 'https://inv.us.projectsegfau.lt/latest_version?id=qBzjHU_zEwM&itag=18'`
# - e.g. `go2tv -tc -u 'https://yt.artemislena.eu/latest_version?id=qBzjHU_zEwM&itag=22'`
# - sometimes transcoding is needed, sometimes not...
# - `go2tv -v /mnt/servo-media/Videos/Shows/bebop/session1.mkv`
# - LGTV: works
# - `go2tv -tc -v /mnt/servo-media/Videos/Shows/bebop/session1.mkv`
# - LGTV: works
#
# WHEN TO TRANSCODE:
# - mkv container + mpeg-2 video + AC-3/48k stereo audio:
# - LGTV: no transcoding needed
# - mkv container + H.264 video + AAC/48k 5.1 audio:
# - LGTV: no transcoding needed
# - mp4 container + H.264 video + MP3/48k stereo audio:
# - LGTV: no transcoding needed
# - mp4 container + H.264 video + AAC/44k1 stereo audio:
# - LGTV: no transcoding needed
# - mkv container + H.265 video + E-AC-3/48k stereo audio:
# - LGTV: no transcoding needed
{ config, lib, pkgs, ... }:
let
cfg = config.sane.programs.go2tv;
in
{
# for serving local files
# see: go2tv/soapcalls/utils/iptools.go
networking.firewall.allowedTCPPorts = lib.mkIf cfg.enabled [ 3500 ];
}

View File

@@ -5,7 +5,7 @@
let let
feeds = sane-lib.feeds; feeds = sane-lib.feeds;
all-feeds = config.sane.feeds; all-feeds = config.sane.feeds;
wanted-feeds = feeds.filterByFormat ["podcast"] all-feeds; wanted-feeds = feeds.filterByFormat [ "podcast" "video" ] all-feeds;
in { in {
sane.programs.gpodder = { sane.programs.gpodder = {
package = pkgs.gpodder-adaptive-configured.overrideAttrs (base: { package = pkgs.gpodder-adaptive-configured.overrideAttrs (base: {

View File

@@ -3,6 +3,7 @@
sane.programs.gthumb = { sane.programs.gthumb = {
# compile without webservices to avoid the expensive webkitgtk dependency # compile without webservices to avoid the expensive webkitgtk dependency
package = pkgs.gthumb.override { withWebservices = false; }; package = pkgs.gthumb.override { withWebservices = false; };
mime.priority = 200; # gthumb is kinda bloated image/gallery viewer
mime.associations = { mime.associations = {
"image/gif" = "org.gnome.gThumb.desktop"; "image/gif" = "org.gnome.gThumb.desktop";
"image/heif" = "org.gnome.gThumb.desktop"; # apple codec "image/heif" = "org.gnome.gThumb.desktop"; # apple codec

View File

@@ -1,3 +1,6 @@
# FIRST-TIME SETUP:
# - disable notification sounds: hamburger menu in bottom-left -> preferences
# - notification sounds can be handled by swaync
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
let let
cfg = config.sane.programs.gtkcord4; cfg = config.sane.programs.gtkcord4;
@@ -9,11 +12,26 @@ in
type = types.submodule { type = types.submodule {
options.autostart = mkOption { options.autostart = mkOption {
type = types.bool; type = types.bool;
default = false; default = true;
}; };
}; };
}; };
package = pkgs.gtkcord4.overrideAttrs (upstream: {
postConfigure = (upstream.postConfigure or "") + ''
# gtkcord4 uses go-keyring to interface with the org.freedesktop.secrets provider (i.e. gnome-keyring).
# go-keyring hardcodes `login.keyring` as the keyring to store secrets in, instead of reading `~/.local/share/keyring/default`.
# `login.keyring` seems to be a special keyring preconfigured (by gnome-keyring) to encrypt everything to the user's password.
# that's redundant with my fs-level encryption and makes the keyring less inspectable,
# so patch gtkcord4 to use Default_keyring instead.
# see:
# - <https://github.com/diamondburned/gtkcord4/issues/139>
# - <https://github.com/zalando/go-keyring/issues/46>
substituteInPlace vendor/github.com/zalando/go-keyring/secret_service/secret_service.go \
--replace '"login"' '"Default_keyring"'
'';
});
persist.byStore.private = [ persist.byStore.private = [
".cache/gtkcord4" ".cache/gtkcord4"
".config/gtkcord4" # empty? ".config/gtkcord4" # empty?

View File

@@ -0,0 +1,40 @@
local logger = require("logger")
logger.info("applying colin patch colin-impl-clipboard")
-- source: <https://github.com/ncopa/lua-shell/blob/master/shell.lua>
local function shescape(arg)
if arg:match("[^A-Za-z0-9_/:=-]") then
arg = "'"..arg:gsub("'", "'\\''").."'"
end
return arg
end
-- 2023/12/15: the default setClipboardText doesn't do anything
-- frontend/device/sdl/device.lua calls frontend/device/input.lua is noop
local input = require("ffi/input")
input.setClipboardText = function(text)
logger.info("input.setClipboardText")
local cmd = "wl-copy " .. shescape(text)
logger.info("invoke: " .. cmd)
os.execute(cmd)
end
-- 2023/12/15: the default ReaderLink "Copy" option (when clicking a URL) doesn't do anything
-- patch so it calls `setClipboardText`
local ReaderLink = require("apps/reader/modules/readerlink")
local UIManager = require("ui/uimanager")
local _ = require("gettext")
local orig_ReaderLink_init = ReaderLink.init;
ReaderLink.init = function(self)
orig_ReaderLink_init(self)
self._external_link_buttons["10_copy"] = function(this, link_url)
return {
text = _("Copy"),
callback = function()
UIManager:close(this.external_link_dialog)
input.setClipboardText(link_url)
end,
}
end
end

View File

@@ -1,9 +1,21 @@
# docs:
# - <https://koreader.rocks/user_guide/>
# - <https://github.com/koreader/koreader/wiki>
#
# post-installation setup:
# - download dictionaries:
# - search icon > settings > dictionary settings > download dictionaries
# - these are stored in `~/.config/koreader/data/dict`
# - configure defaults:
# - edit keys in ~/.config/koreader/settings.reader.lua
# - default font size: `["copt_font_size"] = 28,`
# - home dir: `["home_dir"] = "/home/colin/Books",`
{ config, lib, pkgs, sane-lib, ... }: { config, lib, pkgs, sane-lib, ... }:
let let
feeds = sane-lib.feeds; feeds = sane-lib.feeds;
allFeeds = config.sane.feeds; allFeeds = config.sane.feeds;
wantedFeeds = feeds.filterByFormat [ "image" "text" ] allFeeds; wantedFeeds = feeds.filterByFormat [ "text" ] allFeeds;
koreaderRssEntries = builtins.map (feed: koreaderRssEntries = builtins.map (feed:
# format: # format:
# { "<rss/atom url>", limit = <int>, download_full_article=<bool>, include_images=<bool>, enable_filter=<bool>, filter_element = "<css selector>"}, # { "<rss/atom url>", limit = <int>, download_full_article=<bool>, include_images=<bool>, enable_filter=<bool>, filter_element = "<css selector>"},
@@ -14,7 +26,7 @@ let
# enable_filter = true => only render content that matches the filter_element css selector. # enable_filter = true => only render content that matches the filter_element css selector.
let fields = [ let fields = [
(lib.escapeShellArg feed.url) (lib.escapeShellArg feed.url)
"limit = 5" "limit = 20"
"download_full_article = true" "download_full_article = true"
"include_images = true" "include_images = true"
"enable_filter = false" "enable_filter = false"
@@ -26,9 +38,13 @@ in {
package = pkgs.koreader-from-src; package = pkgs.koreader-from-src;
# koreader applies these lua "patches" at boot: # koreader applies these lua "patches" at boot:
# - <https://github.com/koreader/koreader/wiki/User-patches> # - <https://github.com/koreader/koreader/wiki/User-patches>
# - 2023/10/29: koreader code hasn't changed, but somehow FTP browser seems usable even without the isConnected patch now. # the naming is IMPORTANT. these must start with a `2-` in order to be invoked during the right initialization phase
#
# 2023/10/29: koreader code hasn't changed, but somehow FTP browser seems usable even without the isConnected patch now.
# fs.".config/koreader/patches/2-colin-NetworkManager-isConnected.lua".symlink.target = "${./2-colin-NetworkManager-isConnected.lua}"; # fs.".config/koreader/patches/2-colin-NetworkManager-isConnected.lua".symlink.target = "${./2-colin-NetworkManager-isConnected.lua}";
fs.".config/koreader/patches/2-02-colin-impl-clipboard-ops.lua".symlink.target = "${./2-02-colin-impl-clipboard-ops.lua}";
# koreader news plugin, enabled by default. file format described here: # koreader news plugin, enabled by default. file format described here:
# - <repo:koreader/koreader:plugins/newsdownloader.koplugin/feed_config.lua> # - <repo:koreader/koreader:plugins/newsdownloader.koplugin/feed_config.lua>
fs.".config/koreader/news/feed_config.lua".symlink.text = '' fs.".config/koreader/news/feed_config.lua".symlink.text = ''

View File

@@ -0,0 +1,14 @@
{ pkgs, ... }:
{
sane.programs.loupe = {
mime.associations = {
"image/gif" = "org.gnome.Loupe.desktop";
"image/heif" = "org.gnome.Loupe.desktop"; # apple codec
"image/png" = "org.gnome.Loupe.desktop";
"image/jpeg" = "org.gnome.Loupe.desktop";
"image/svg+xml" = "org.gnome.Loupe.desktop";
"image/webp" = "org.gnome.Loupe.desktop";
};
};
}

View File

@@ -1,11 +0,0 @@
{ pkgs, ... }:
{
sane.programs.megapixels.package = pkgs.megapixels.override {
# megapixels uses zbar to read barcodes.
# zbar by default ships zbarcam-gtk and zbarcam-qt, neither of which megapixels needs.
# but the latter takes a dep on qt, which bloats the closure and the build, so disable this feature.
zbar = pkgs.zbar.override {
enableVideo = false;
};
};
}

View File

@@ -0,0 +1,78 @@
# mimeo is an exec dispatcher like xdg-open, but why allows mapping different URL regexes to different handlers.
# my setup sets mimeo as the default http/https handler,
# and from there it dispatches specialized rules, falling back to the original http/https handler if no URL specialization exists
{ config, lib, pkgs, ... }:
let
mimeo-open-desktop = pkgs.static-nix-shell.mkPython3Bin {
pname = "mimeo-open-desktop";
src = ./.;
pkgs = [ "mimeo" ];
};
# [ProgramConfig]
enabledPrograms = builtins.filter
(p: p.enabled)
(builtins.attrValues config.sane.programs);
# [ProgramConfig]
sortedPrograms = builtins.sort
(l: r: l.priority or 1000 < r.priority or 1000)
enabledPrograms;
fmtAssoc = regex: desktop: ''
${mimeo-open-desktop}/bin/mimeo-open-desktop ${desktop} %U
${regex}
'';
assocs = builtins.map
(program: lib.mapAttrsToList fmtAssoc program.mime.urlAssociations)
sortedPrograms;
assocs' = lib.flatten assocs;
fmtFallbackAssoc = mimeType: desktop: if mimeType == "x-scheme-handler/http" then ''
${mimeo-open-desktop}/bin/mimeo-open-desktop ${desktop} %U
^http://.*
'' else if mimeType == "x-scheme-handler/https" then ''
${mimeo-open-desktop}/bin/mimeo-open-desktop ${desktop} %U
^https://.*
'' else "";
fmtFallbackAssoc' = mimeType: desktop:
lib.optionalString (desktop != "mimeo.desktop") (fmtFallbackAssoc mimeType desktop);
fallbackAssocs = builtins.map
(program: lib.mapAttrsToList fmtFallbackAssoc' program.mime.associations)
sortedPrograms;
fallbackAssocs' = lib.flatten fallbackAssocs;
in
{
sane.programs.mimeo = {
package = pkgs.mimeo.overridePythonAttrs (upstream: {
nativeBuildInputs = (upstream.nativeBuildInputs or []) ++ [
pkgs.copyDesktopItems
];
desktopItems = [
(pkgs.makeDesktopItem {
name = "mimeo";
desktopName = "Mimeo";
exec = "mimeo %U";
comment = "Open files by MIME-type or file name using regular expressions.";
})
];
# upstream mimeo doesn't run preInstall/postInstall hooks, but we need that for the .desktop file
installPhase = ''
runHook preInstall
${upstream.installPhase}
runHook postInstall
'';
passthru = (upstream.passthru or {}) // {
inherit mimeo-open-desktop;
};
});
fs.".config/mimeo/associations.txt".symlink.text = lib.concatStringsSep "\n" (assocs' ++ fallbackAssocs');
mime.priority = 20;
mime.associations."x-scheme-handler/http" = "mimeo.desktop";
mime.associations."x-scheme-handler/https" = "mimeo.desktop";
};
}

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ])" -p mimeo
# TODO: migrate nixpkgs mimeo to be `buildPythonPackage` to make it importable here.
# see <doc/languages-frameworks/python.section.md>
import subprocess
import sys
desktop = sys.argv[1]
opener_args = sys.argv[2:]
desktop_fields=subprocess.check_output([
"mimeo",
"--desk2field",
"Exec",
desktop
]).decode('utf-8')
# print(f"fields: {desktop_fields!r}")
desktop_exec = '\n'.join(desktop_fields.split('\n')[1:])
# print(f"exec: {desktop_exec!r}")
# TODO: this is obviously not correct if any of the args included spaces
desktop_argv = [f.strip() for f in desktop_exec.split(' ') if f.strip()]
# print(f"desktop_argv: {desktop_argv!r}")
# fields explained: <https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s07.html>
# - %U = all URLs
# - %U = just the first URL
substituted_argv = []
for arg in desktop_argv:
if arg == '%U':
substituted_argv += opener_args
elif arg == '%u':
substituted_argv += opener_args[:1]
else:
substituted_argv += [arg]
# print(f"argv: {substituted_argv}")
print(subprocess.check_output(substituted_argv).decode())

View File

@@ -23,15 +23,18 @@ in
package = pkgs.wrapMpv pkgs.mpv-unwrapped { package = pkgs.wrapMpv pkgs.mpv-unwrapped {
scripts = with pkgs.mpvScripts; [ scripts = with pkgs.mpvScripts; [
mpris mpris
# uosc uosc
pkgs.mpv-uosc-latest # pkgs.mpv-uosc-latest
]; ];
extraMakeWrapperArgs = lib.optionals (cfg.config.vo != null) [ extraMakeWrapperArgs = lib.optionals (cfg.config.vo != null) [
# 2023/08/29: fixes an error where mpv on moby launches with the message # 2023/08/29: fixes an error where mpv on moby launches with the message
# "DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory" # "DRM_IOCTL_MODE_CREATE_DUMB failed: Cannot allocate memory"
# audio still works, and controls, screenshotting, etc -- just not the actual rendering # audio still works, and controls, screenshotting, etc -- just not the actual rendering
# this is likely a regression for mpv 0.36.0. #
# the actual error message *appears* to come from the mesa library, but it's tough to trace. # this is likely a regression for mpv 0.36.0.
# the actual error message *appears* to come from the mesa library, but it's tough to trace.
#
# TODO(2023/12/03): remove once mesa 23.3.1 lands: <https://github.com/NixOS/nixpkgs/pull/265740>
# #
# backend compatibility (2023/10/22): # backend compatibility (2023/10/22):
# run with `--vo=help` to see a list of all output options. # run with `--vo=help` to see a list of all output options.
@@ -54,13 +57,46 @@ in
]; ];
}; };
persist.byStore.plaintext = [ ".local/state/mpv/watch_later" ]; persist.byStore.plaintext = [ ".local/state/mpv/watch_later" ];
fs.".config/mpv/input.conf".symlink.text = '' fs.".config/mpv/input.conf".symlink.text = let
execInTerm = "${pkgs.xdg-terminal-exec}/bin/xdg-terminal-exec";
in ''
# docs:
# - <https://mpv.io/manual/master/#list-of-input-commands>
# - script-binding: <https://mpv.io/manual/master/#command-interface-script-binding>
# - properties: <https://mpv.io/manual/master/#property-list>
# let volume/power keys be interpreted by the system. # let volume/power keys be interpreted by the system.
# this is important for sxmo. # this is important for sxmo.
# mpv defaults is POWER = close, VOLUME_{UP,DOWN} = adjust application-level volume # mpv defaults is POWER = close, VOLUME_{UP,DOWN} = adjust application-level volume
POWER ignore POWER ignore
VOLUME_UP ignore VOLUME_UP ignore
VOLUME_DOWN ignore VOLUME_DOWN ignore
# uosc menu
# text after the shebang is parsed by uosc to construct the menu and names
menu script-binding uosc/menu
s script-binding uosc/subtitles #! Subtitles
a script-binding uosc/audio #! Audio tracks
q script-binding uosc/stream-quality #! Stream quality
p script-binding uosc/items #! Playlist
c script-binding uosc/chapters #! Chapters
> script-binding uosc/next #! Navigation > Next
< script-binding uosc/prev #! Navigation > Prev
o script-binding uosc/open-file #! Navigation > Open file
# set video-aspect-override "-1" #! Utils > Aspect ratio > Default
# set video-aspect-override "16:9" #! Utils > Aspect ratio > 16:9
# set video-aspect-override "4:3" #! Utils > Aspect ratio > 4:3
# set video-aspect-override "2.35:1" #! Utils > Aspect ratio > 2.35:1
# script-binding uosc/audio-device #! Utils > Audio devices
# script-binding uosc/editions #! Utils > Editions
ctrl+s async screenshot #! Utils > Screenshot
alt+i script-binding uosc/keybinds #! Utils > Key bindings
O script-binding uosc/show-in-directory #! Utils > Show in directory
# script-binding uosc/open-config-directory #! Utils > Open config directory
# set pause yes; run ${execInTerm} go2tv -v "''${stream-open-filename}" #! Cast
# set pause yes; run ${execInTerm} go2tv -u "''${stream-open-filename}" #! Cast (...) > Stream
# set pause yes; run go2tv #! Cast (...) > GUI
# TODO: unify "Cast" and "Cast (stream)" options above.
''; '';
fs.".config/mpv/mpv.conf".symlink.text = '' fs.".config/mpv/mpv.conf".symlink.text = ''
save-position-on-quit=yes save-position-on-quit=yes
@@ -91,6 +127,7 @@ in
in '' in ''
# docs: # docs:
# - <https://github.com/tomasklaen/uosc> # - <https://github.com/tomasklaen/uosc>
# - <https://github.com/tomasklaen/uosc/blob/main/src/uosc.conf>
# - <https://superuser.com/questions/1775550/add-new-buttons-to-mpv-uosc-ui> # - <https://superuser.com/questions/1775550/add-new-buttons-to-mpv-uosc-ui>
timeline_style=bar timeline_style=bar
timeline_persistency=paused,audio timeline_persistency=paused,audio
@@ -107,8 +144,7 @@ in
text_border=6.0 text_border=6.0
font_bold=yes font_bold=yes
background_text=ff8080 color=foreground=ff8080,background_text=ff8080
foreground=ff8080
ui_scale=1.0 ui_scale=1.0
''; '';
@@ -122,7 +158,11 @@ in
mime.associations."video/mp4" = "mpv.desktop"; mime.associations."video/mp4" = "mpv.desktop";
mime.associations."video/quicktime" = "mpv.desktop"; mime.associations."video/quicktime" = "mpv.desktop";
mime.associations."video/webm" = "mpv.desktop"; mime.associations."video/webm" = "mpv.desktop";
mime.associations."video/x-flv" = "mpv.desktop";
mime.associations."video/x-matroska" = "mpv.desktop"; mime.associations."video/x-matroska" = "mpv.desktop";
mime.urlAssociations."^https?://(www.)?youtube.com/watch\?.*v=" = "mpv.desktop";
mime.urlAssociations."^https?://(www.)?youtube.com/v/" = "mpv.desktop";
mime.urlAssociations."^https?://(www.)?youtu.be/.+" = "mpv.desktop";
}; };
} }

View File

@@ -0,0 +1,12 @@
{ pkgs, ... }:
{
sane.programs."gnome.nautilus" = {
package = pkgs.gnome.nautilus.overrideAttrs (orig: {
# enable the "Audio and Video Properties" pane. see: <https://nixos.wiki/wiki/Nautilus>
buildInputs = orig.buildInputs ++ (with pkgs.gst_all_1; [
gst-plugins-good
gst-plugins-bad
]);
});
};
}

View File

@@ -1,12 +1,19 @@
# news-flash RSS viewer # news-flash RSS viewer
# - feeds have to be manually imported:
# - Local RSS -> Import OPML -> ~/.config/newsflashFeeds.opml
# - clicking article-embedded links doesn't work because of xdg portal stuff
# - need to either run unsandboxed, or install a org.freedesktop.portal.OpenURI handler
{ config, sane-lib, ... }: { config, sane-lib, ... }:
let let
feeds = sane-lib.feeds; feeds = sane-lib.feeds;
all-feeds = config.sane.feeds; all-feeds = config.sane.feeds;
wanted-feeds = feeds.filterByFormat ["text" "image"] all-feeds; # text/image: newsflash renders these natively
# podcast/video: newsflash dispatches these to xdg-open
wanted-feeds = feeds.filterByFormat [ "text" "image" "podcast" "video" ] all-feeds;
in { in {
sane.programs.newsflash = { sane.programs.newsflash = {
slowToBuild = true; # mainly for desktop: webkitgtk-6.0
persist.byStore.plaintext = [ ".local/share/news-flash" ]; persist.byStore.plaintext = [ ".local/share/news-flash" ];
fs.".config/newsflashFeeds.opml".symlink.text = fs.".config/newsflashFeeds.opml".symlink.text =
feeds.feedsToOpml wanted-feeds feeds.feedsToOpml wanted-feeds

View File

@@ -0,0 +1,8 @@
{ ... }:
{
sane.programs.notejot = {
persist.byStore.private = [
".local/share/io.github.lainsce.Notejot"
];
};
}

View File

@@ -0,0 +1,18 @@
{ ... }:
{
sane.programs.open-in-mpv = {
# taken from <https://github.com/Baldomo/open-in-mpv>
fs.".config/open-in-mpv/config.yml".symlink.text = ''
players:
mpv:
name: mpv
executable: mpv
fullscreen: "--fs"
pip: "--ontop --no-border --autofit=384x216 --geometry=98\\%:98\\%"
enqueue: ""
new_window: ""
needs_ipc: true
flag_overrides: {}
'';
};
}

View File

@@ -0,0 +1,11 @@
{ ... }:
{
sane.programs.planify = {
persist.byStore.private = [
# TODO items as a sqlite database
".local/share/io.github.alainm23.planify"
];
slowToBuild = true; # webkitgtk-6.0; slow for desktop
};
}

View File

@@ -1,3 +1,10 @@
# TODO(bug): signal-desktop is known to hang on exit.
# particularly, it may fail to start (because e.g. there's no wayland session yet),
# and it will try to exit -- after which the service would restart -- but it hangs w/ no GUI instead.
# characterized by these log messages:
#
# Dec 03 13:46:23 moby signal-desktop[4097]: [4097:1203/134623.906367:ERROR:ozone_platform_x11.cc(240)] Missing X server or $DISPLAY
# Dec 03 13:46:23 moby signal-desktop[4097]: [4097:1203/134623.909667:ERROR:env.cc(255)] The platform failed to initialize. Exiting.
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
let let
cfg = config.sane.programs.signal-desktop; cfg = config.sane.programs.signal-desktop;
@@ -30,6 +37,8 @@ in
Restart = "always"; Restart = "always";
RestartSec = "20s"; RestartSec = "20s";
}; };
# for some reason the --ozone-platform-hint=auto flag fails when signal-desktop is launched from a service
environment.NIXOS_OZONE_WL = "1";
}; };
}; };
} }

View File

@@ -17,6 +17,9 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
let let
cfg = config.sane.programs.swaynotificationcenter; cfg = config.sane.programs.swaynotificationcenter;
mprisIconSize = 48;
fbcli-wrapper = pkgs.writeShellApplication { fbcli-wrapper = pkgs.writeShellApplication {
name = "swaync-fbcli"; name = "swaync-fbcli";
runtimeInputs = [ runtimeInputs = [
@@ -134,6 +137,12 @@ in
hash = "sha256-Y8fiZbAP9yGOVU3rOkZKO8TnPPlrGpINWYGaqeeNzF0="; hash = "sha256-Y8fiZbAP9yGOVU3rOkZKO8TnPPlrGpINWYGaqeeNzF0=";
}) })
]; ];
postPatch = (upstream.postPatch or "") + ''
# XXX: this might actually be changing the DPI, not the scaling...
# in that case, it might be possible to do this in CSS
substituteInPlace src/controlCenter/widgets/mpris/mpris_player.ui \
--replace '96' '${builtins.toString mprisIconSize}'
'';
})); }));
suggestedPrograms = [ "feedbackd" ]; suggestedPrograms = [ "feedbackd" ];
fs.".config/swaync/style.css".symlink.text = '' fs.".config/swaync/style.css".symlink.text = ''
@@ -218,6 +227,27 @@ in
# - SWAYNC_REPLACES_ID # - SWAYNC_REPLACES_ID
# - SWAYNC_ID # - SWAYNC_ID
# - SWAYNC_SUMMARY # - SWAYNC_SUMMARY
# rules to use for testing. trigger with:
# - `notify-send test test:message` (etc)
# should also be possible to trigger via any messaging app
fbcli-test-im = {
body = "test:message";
exec = "${fbcli} --event proxied-message-new-instant";
};
fbcli-test-call = {
body = "test:call";
exec = "${fbcli} --event phone-incoming-call -t 20";
};
fbcli-test-call-stop = {
body = "test:call-stop";
exec = "${fbcli-stop} --event phone-incoming-call -t 20";
};
fbcli-test-timer = {
body = "test:timer";
exec = "${fbcli} --event timeout-completed";
};
incoming-im-known-app-name = { incoming-im-known-app-name = {
# trigger notification sound on behalf of these IM clients. # trigger notification sound on behalf of these IM clients.
app-name = "(Chats|Dino|discord|Element|Fractal|gtkcord4)"; app-name = "(Chats|Dino|discord|Element|Fractal|gtkcord4)";
@@ -367,21 +397,21 @@ in
command = "${systemctl-toggle}/bin/systemctl-toggle --user geary"; command = "${systemctl-toggle}/bin/systemctl-toggle --user geary";
active = "${pkgs.systemd}/bin/systemctl is-active --user geary"; active = "${pkgs.systemd}/bin/systemctl is-active --user geary";
} }
] ++ lib.optionals config.sane.programs.abaddon.enabled [ # ] ++ lib.optionals config.sane.programs.abaddon.enabled [
{ # # XXX: disabled in favor of gtkcord4: abaddon has troubles auto-connecting at start
type = "toggle";
label = "󰊴"; # Discord chat client; icons: 󰊴, 🎮
command = "${systemctl-toggle}/bin/systemctl-toggle --user abaddon";
active = "${pkgs.systemd}/bin/systemctl is-active --user abaddon";
}
# ] ++ lib.optionals config.sane.programs.gtkcord4.enabled [
# # XXX: disabled in favor of abaddon: gtkcord4 leaks memory
# { # {
# type = "toggle"; # type = "toggle";
# label = "󰊴"; # Discord chat client; icons: 󰊴, 🎮 # label = "󰊴"; # Discord chat client; icons: 󰊴, 🎮
# command = "${systemctl-toggle}/bin/systemctl-toggle --user gtkcord4"; # command = "${systemctl-toggle}/bin/systemctl-toggle --user abaddon";
# active = "${pkgs.systemd}/bin/systemctl is-active --user gtkcord4"; # active = "${pkgs.systemd}/bin/systemctl is-active --user abaddon";
# } # }
] ++ lib.optionals config.sane.programs.gtkcord4.enabled [
{
type = "toggle";
label = "󰊴"; # Discord chat client; icons: 󰊴, 🎮
command = "${systemctl-toggle}/bin/systemctl-toggle --user gtkcord4";
active = "${pkgs.systemd}/bin/systemctl is-active --user gtkcord4";
}
] ++ lib.optionals config.sane.programs.signal-desktop.enabled [ ] ++ lib.optionals config.sane.programs.signal-desktop.enabled [
{ {
type = "toggle"; type = "toggle";
@@ -414,7 +444,7 @@ in
clear-all-button = true; clear-all-button = true;
}; };
mpris = { mpris = {
image-size = 64; image-size = mprisIconSize;
image-radius = 8; image-radius = 8;
}; };
title = { title = {

View File

@@ -32,6 +32,7 @@ in
mime.associations."video/mp4" = "vlc.desktop"; mime.associations."video/mp4" = "vlc.desktop";
mime.associations."video/quicktime" = "vlc.desktop"; mime.associations."video/quicktime" = "vlc.desktop";
mime.associations."video/webm" = "vlc.desktop"; mime.associations."video/webm" = "vlc.desktop";
mime.associations."video/x-flv" = "vlc.desktop";
mime.associations."video/x-matroska" = "vlc.desktop"; mime.associations."video/x-matroska" = "vlc.desktop";
}; };
} }

View File

@@ -0,0 +1,143 @@
# docs:
# - <https://github.com/francma/wob/blob/master/wob.ini.5.scd>
# - `wob -vv` to see config defaults
#
# the wob services defined here are largely based on those from SXMO.
#
# this should arguably be just a (user) service. nothing actually needs `wob` on the PATH.
#
{ config, lib, pkgs, ... }:
let
cfg = config.sane.programs.wob;
in
{
sane.programs.wob = {
configOption = with lib; mkOption {
default = {};
type = types.submodule {
options.autostart = mkOption {
type = types.bool;
default = true;
};
options.sock = mkOption {
type = types.str;
default = "sxmo.wobsock";
};
};
};
fs.".config/wob/wob.ini".symlink.text = ''
timeout = 900
anchor = top right
orientation = vertical
# margin top right bottom left
# note that wob is "aware" of the sway bar, so margin 0 never overlaps it.
# however it's not aware of sway's window title
margin = 54 3 54 3
height = 164
width = 30
border_offset = 0
border_size = 2
bar_padding = 0
# very light teal, derived from conky background
bar_color = e1f0efDC
background_color = 000000B4
border_color = 000000C8
overflow_bar_color = FF4040DC
overflow_background_color = FFFFFFC8
overflow_border_color = FF4040DC
'';
services.wob = {
description = "Wayland Overlay Bar (renders volume/backlight levels)";
wantedBy = lib.mkIf cfg.config.autostart [ "default.target" ];
serviceConfig = {
# ExecStart = "${cfg.package}/bin/wob";
Type = "simple";
Restart = "always";
RestartSec = "20s";
};
path = [ cfg.package ];
script = ''
wobsock="$XDG_RUNTIME_DIR/${cfg.config.sock}"
rm -f "$wobsock" || true
mkfifo "$wobsock" && wob <> "$wobsock"
# TODO: cleanup should be done in a systemd OnFailure, or OnExit, or whatever
rm -f "$wobsock"
'';
};
services.wob-pulse = {
description = "notify wob when pulseaudio volume changes";
wantedBy = [ "wob.service" ];
serviceConfig = {
Type = "simple";
Restart = "always";
RestartSec = "20s";
};
path = with pkgs; [
# coreutils
gnugrep
gnused
pulseaudio
];
# environment.WOB_VERBOSE = "1";
script = ''
debug() {
printf "$@" >&2
printf "\n" >&2
}
verbose() {
if [ "$WOB_VERBOSE" = "1" ]; then
debug "$@"
fi
}
volismuted() {
pactl get-sink-mute @DEFAULT_SINK@ | grep -q "Mute: yes"
}
volget() {
if volismuted; then
verbose "muted"
printf "0"
else
pactl get-sink-volume @DEFAULT_SINK@ | head -n1 | cut -d'/' -f2 | sed 's/ //g' | sed 's/\%//'
fi
}
notify_volume_change() {
verbose "notify_volume_change"
vol=$(volget)
verbose "got volume: %d -> %d" "$lastvol" "$vol"
if [ "$vol" != "$lastvol" ]; then
debug "notify wob: %d -> %d" "$lastvol" "$vol"
printf "%s\n" "$vol" > "$XDG_RUNTIME_DIR/${cfg.config.sock}"
fi
lastvol="$vol"
}
pactl subscribe | while read -r line; do
verbose "pactl says: %s" "$line"
case "$line" in
"Event 'change' on sink "*)
notify_volume_change
;;
"Event 'change' on source "*)
# microphone volume changed. ignore.
;;
esac
done
'';
};
};
}

View File

@@ -0,0 +1,16 @@
# zcash wallet
#
# N.B.: zecwallet is UNMAINTAINED. as of 2024/01/01 it requires manual intervention to sync:
# 1. launch it, and wait 5min for it to timeout.
# 2. set the node address to https://lwd3.zcash-infra.com:9067
# 3. close the application and re-open
# more info:
# - <https://forum.zcashcommunity.com/t/zecwallet-lightwalletd-server-continuation/45659/>
# - <https://status.zcash-infra.com/>
{ ... }:
{
sane.programs.zecwallet-lite = {
# zcash coins. safe to delete, just slow to regenerate (10-60 minutes)
persist.byStore.private = [ ".zcash" ];
};
}

View File

@@ -85,6 +85,16 @@ in
# emulate bash keybindings # emulate bash keybindings
bindkey -e bindkey -e
# fixup bindings not handled by bash, see: <https://wiki.archlinux.org/title/Zsh#Key_bindings>
# `bindkey -e` seems to define most of the `key` array. everything in the Arch defaults except for these:
key[Backspace]="''${terminfo[kbs]}"
key[Control-Left]="''${terminfo[kLFT5]}"
key[Control-Right]="''${terminfo[kRIT5]}"
key[Shift-Tab]="''${terminfo[kcbt]}"
bindkey -- "''${key[Delete]}" delete-char
bindkey -- "''${key[Control-Left]}" backward-word
bindkey -- "''${key[Control-Right]}" forward-word
# or manually recreate what i care about... # or manually recreate what i care about...
# key[Left]=''${terminfo[kcub1]} # key[Left]=''${terminfo[kcub1]}
# key[Right]=''${terminfo[kcuf1]} # key[Right]=''${terminfo[kcuf1]}

View File

@@ -13,6 +13,7 @@
]; ];
group = "users"; group = "users";
extraGroups = [ extraGroups = [
"clightning" # servo, for clightning-cli
"dialout" # required for modem access (moby) "dialout" # required for modem access (moby)
"export" # to read filesystem exports (servo) "export" # to read filesystem exports (servo)
"feedbackd" # moby, so `fbcli` can control vibrator and LEDs "feedbackd" # moby, so `fbcli` can control vibrator and LEDs

View File

@@ -57,11 +57,12 @@ in
sane.programs.guiBaseApps = declPackageSet [ sane.programs.guiBaseApps = declPackageSet [
"abaddon" # discord client "abaddon" # discord client
"alacritty" # terminal emulator "alacritty" # terminal emulator
"delfin" # Jellyfin client
"dialect" # language translation "dialect" # language translation
"dino" # XMPP client "dino" # XMPP client
# "emote" # "emote"
"evince" # works on phosh "evince" # works on phosh
# "flare-signal" # gtk4 signal client "flare-signal" # gtk4 signal client
# "foliate" # e-book reader # "foliate" # e-book reader
"fractal" # matrix client "fractal" # matrix client
"g4music" # local music player "g4music" # local music player
@@ -77,17 +78,23 @@ in
# "gnome.gnome-system-monitor" # "gnome.gnome-system-monitor"
# "gnome.gnome-terminal" # works on phosh # "gnome.gnome-terminal" # works on phosh
"gnome.gnome-weather" "gnome.gnome-weather"
"gthumb" "gnome.seahorse" # keyring/secret manager
# "gtkcord4" # Discord client. 2023/11/21: disabled because it leaks memory "gnome-frog" # OCR/QR decoder
"gpodder"
# "gthumb"
"gtkcord4" # Discord client. 2023/11/21: disabled because v0.0.12 leaks memory
"lemoa" # lemmy app "lemoa" # lemmy app
"libnotify" # for notify-send; debugging
# "lollypop" # "lollypop"
"loupe" # image viewer
"mate.engrampa" # archive manager "mate.engrampa" # archive manager
"mepo" # maps viewer "mepo" # maps viewer
"mpv" "mpv"
"networkmanagerapplet" # for nm-connection-editor: it's better than not having any gui! "networkmanagerapplet" # for nm-connection-editor: it's better than not having any gui!
"ntfy-sh" # notification service "ntfy-sh" # notification service
# "newsflash" # "newsflash" # RSS viewer
"pavucontrol" "pavucontrol"
"pwvucontrol" # pipewire version of pavu
# "picard" # music tagging # "picard" # music tagging
# "libsForQt5.plasmatube" # Youtube player # "libsForQt5.plasmatube" # Youtube player
"signal-desktop" "signal-desktop"
@@ -96,6 +103,7 @@ in
# "tdesktop" # broken on phosh # "tdesktop" # broken on phosh
# "tokodon" # "tokodon"
"tuba" # mastodon/pleroma client (stores pw in keyring) "tuba" # mastodon/pleroma client (stores pw in keyring)
"vulkan-tools" # vulkaninfo
# "whalebird" # pleroma client (Electron). input is broken on phosh. # "whalebird" # pleroma client (Electron). input is broken on phosh.
"xdg-terminal-exec" "xdg-terminal-exec"
"xterm" # broken on phosh "xterm" # broken on phosh
@@ -104,13 +112,15 @@ in
sane.programs.handheldGuiApps = declPackageSet [ sane.programs.handheldGuiApps = declPackageSet [
"calls" # gnome calls (dialer/handler) "calls" # gnome calls (dialer/handler)
# "celluloid" # mpv frontend # "celluloid" # mpv frontend
"chatty" # matrix/xmpp/irc client # "chatty" # matrix/xmpp/irc client (2023/12/29: disabled because broken cross build)
"cozy" # audiobook player "cozy" # audiobook player
"epiphany" # gnome's web browser "epiphany" # gnome's web browser
"gpodder" # "iotas" # note taking app
"komikku" "komikku"
"koreader" "koreader"
"megapixels" # camera app "megapixels" # camera app
"notejot" # note taking, e.g. shopping list
"planify" # todo-tracker/planner
"portfolio-filemanager" "portfolio-filemanager"
"tangram" # web browser "tangram" # web browser
"wike" # Wikipedia Reader "wike" # Wikipedia Reader
@@ -153,8 +163,9 @@ in
"mumble" "mumble"
# "nheko" # Matrix chat client # "nheko" # Matrix chat client
# "obsidian" # "obsidian"
"openscad" # 3d modeling
# "rhythmbox" # local music player # "rhythmbox" # local music player
"slic3r" # "slic3r"
"soundconverter" "soundconverter"
"spotify" # x86-only "spotify" # x86-only
"steam" "steam"

View File

@@ -21,7 +21,6 @@ in
services.xserver.displayManager.gdm.enable = true; services.xserver.displayManager.gdm.enable = true;
# gnome does networking stuff with networkmanager # gnome does networking stuff with networkmanager
networking.useDHCP = false;
networking.networkmanager.enable = true; networking.networkmanager.enable = true;
networking.wireless.enable = lib.mkForce false; networking.wireless.enable = lib.mkForce false;
}; };

View File

@@ -74,7 +74,6 @@ in
services.gnome.gnome-online-miners.enable = mkForce false; services.gnome.gnome-online-miners.enable = mkForce false;
# XXX: phosh enables networkmanager by default; can probably disable these lines # XXX: phosh enables networkmanager by default; can probably disable these lines
networking.useDHCP = false;
networking.networkmanager.enable = true; networking.networkmanager.enable = true;
networking.wireless.enable = lib.mkForce false; networking.wireless.enable = lib.mkForce false;

View File

@@ -4,8 +4,8 @@
# sway-config docs: `man 5 sway` # sway-config docs: `man 5 sway`
let let
cfg = config.sane.gui.sway; cfg = config.sane.gui.sway;
defaultPackage = let wrapSway = sway': swayOverrideArgs: let
# `defaultPackage` exists to create a `sway.desktop` file # `wrapSway` exists to create a `sway.desktop` file
# which will launch sway with our desired debugging facilities. # which will launch sway with our desired debugging facilities.
# i.e. redirect output to syslog. # i.e. redirect output to syslog.
scfg = config.programs.sway; scfg = config.programs.sway;
@@ -14,31 +14,36 @@ let
echo "launching sway-session (sway.desktop)..." | ${systemd-cat} --identifier=sway-session echo "launching sway-session (sway.desktop)..." | ${systemd-cat} --identifier=sway-session
sway 2>&1 | ${systemd-cat} --identifier=sway-session sway 2>&1 | ${systemd-cat} --identifier=sway-session
''; '';
origSway = pkgs.sway.override { # this override is what `programs.nixos` would do internally if we left `package` unset.
# this override is what `programs.nixos` would do internally if we left `package` unset. configuredSway = sway'.override swayOverrideArgs;
extraSessionCommands = scfg.extraSessionCommands;
extraOptions = scfg.extraOptions;
withBaseWrapper = scfg.wrapperFeatures.base;
withGtkWrapper = scfg.wrapperFeatures.gtk;
isNixOS = true;
# TODO: `enableXWayland = ...`?
};
desktop-file = pkgs.runCommand "sway-desktop-wrapper" {} '' desktop-file = pkgs.runCommand "sway-desktop-wrapper" {} ''
mkdir -p $out/share/wayland-sessions mkdir -p $out/share/wayland-sessions
substitute ${origSway}/share/wayland-sessions/sway.desktop $out/share/wayland-sessions/sway.desktop \ substitute ${configuredSway}/share/wayland-sessions/sway.desktop $out/share/wayland-sessions/sway.desktop \
--replace 'Exec=sway' 'Exec=${swayWithLogger}/bin/sway-session' --replace 'Exec=sway' 'Exec=${swayWithLogger}/bin/sway-session'
# XXX(2023/09/24) phog greeter (mobile greeter) will crash if DesktopNames is not set # XXX(2023/09/24) phog greeter (mobile greeter) will crash if DesktopNames is not set
echo "DesktopNames=Sway" >> $out/share/wayland-sessions/sway.desktop echo "DesktopNames=Sway" >> $out/share/wayland-sessions/sway.desktop
''; '';
in pkgs.symlinkJoin { in pkgs.symlinkJoin {
inherit (origSway) name meta; inherit (configuredSway) name meta;
# the order of these `paths` is suchs that the desktop-file should claim share/wayland-sessions/sway.deskop, # the order of these `paths` is suchs that the desktop-file should claim share/wayland-sessions/sway.deskop,
# overriding whatever the origSway provides # overriding whatever the configuredSway provides
paths = [ desktop-file origSway ]; paths = [ desktop-file configuredSway ];
passthru = { passthru = {
inherit (origSway.passthru) providedSessions; inherit (configuredSway.passthru) providedSessions;
# nixos/modules/programs/wayland/sway.nix will call `.override` on the package we provide it
override = wrapSway sway';
}; };
}; };
defaultPackage = wrapSway pkgs.sway {
# this is technically optional, in that the nixos sway module will call `override` with these args anyway.
# but that wasn't always the case; it may change again; so don't rely on it.
inherit (config.programs.sway)
extraSessionCommands extraOptions;
withBaseWrapper = config.programs.sway.wrapperFeatures.base;
withGtkWrapper = config.programs.sway.wrapperFeatures.gtk;
isNixOS = true;
# TODO: `enableXWayland = ...`?
};
in in
{ {
options = with lib; { options = with lib; {
@@ -176,7 +181,7 @@ in
"playerctl" # for waybar & particularly to have playerctld running "playerctl" # for waybar & particularly to have playerctld running
# "mako" # notification daemon # "mako" # notification daemon
"swaynotificationcenter" # notification daemon "swaynotificationcenter" # notification daemon
# # "pavucontrol" "wob" # render volume changes on-screen
# "gnome.gnome-bluetooth" # XXX(2023/05/14): broken # "gnome.gnome-bluetooth" # XXX(2023/05/14): broken
# "gnome.gnome-control-center" # XXX(2023/06/28): depends on webkitgtk4_1 # "gnome.gnome-control-center" # XXX(2023/06/28): depends on webkitgtk4_1
"sway-contrib.grimshot" "sway-contrib.grimshot"
@@ -197,7 +202,7 @@ in
sane.gui.gtk.enable = lib.mkDefault true; sane.gui.gtk.enable = lib.mkDefault true;
# sane.gui.gtk.gtk-theme = lib.mkDefault "Fluent-Light-compact"; # sane.gui.gtk.gtk-theme = lib.mkDefault "Fluent-Light-compact";
sane.gui.gtk.gtk-theme = lib.mkDefault "Tokyonight-Light-B"; sane.gui.gtk.gtk-theme = lib.mkDefault "Tokyonight-Light-B";
sane.gui.gtk.icon-theme = lib.mkDefault "HighContrast"; # 4/5 coverage on moby # sane.gui.gtk.icon-theme = lib.mkDefault "HighContrast"; # 4/5 coverage on moby
# sane.gui.gtk.icon-theme = lib.mkDefault "WhiteSur"; # 3.5/5 coverage on moby, but it provides a bunch for Fractal/Dino # sane.gui.gtk.icon-theme = lib.mkDefault "WhiteSur"; # 3.5/5 coverage on moby, but it provides a bunch for Fractal/Dino
# sane.gui.gtk.icon-theme = lib.mkDefault "Humanity"; # 3.5/5 coverage on moby, but it provides the bookmark icon # sane.gui.gtk.icon-theme = lib.mkDefault "Humanity"; # 3.5/5 coverage on moby, but it provides the bookmark icon
# sane.gui.gtk.icon-theme = lib.mkDefault "Paper"; # 3.5/5 coverage on moby, but it provides the bookmark icon # sane.gui.gtk.icon-theme = lib.mkDefault "Paper"; # 3.5/5 coverage on moby, but it provides the bookmark icon
@@ -230,6 +235,7 @@ in
# emulate pulseaudio for legacy apps (e.g. sxmo-utils) # emulate pulseaudio for legacy apps (e.g. sxmo-utils)
pulse.enable = true; pulse.enable = true;
}; };
services.gvfs.enable = true; # allow nautilus to mount remote filesystems (e.g. ftp://...)
# rtkit/RealtimeKit: allow applications which want realtime audio (e.g. Dino? Pulseaudio server?) to request it. # rtkit/RealtimeKit: allow applications which want realtime audio (e.g. Dino? Pulseaudio server?) to request it.
# this might require more configuration (e.g. polkit-related) to work exactly as desired. # this might require more configuration (e.g. polkit-related) to work exactly as desired.
# - readme outlines requirements: <https://github.com/heftig/rtkit> # - readme outlines requirements: <https://github.com/heftig/rtkit>
@@ -254,7 +260,6 @@ in
# }; # };
# sane.persist.sys.byStore.plaintext = [ "/var/lib/alsa" ]; # sane.persist.sys.byStore.plaintext = [ "/var/lib/alsa" ];
networking.useDHCP = false;
networking.networkmanager.enable = true; networking.networkmanager.enable = true;
networking.wireless.enable = lib.mkForce false; networking.wireless.enable = lib.mkForce false;
@@ -277,6 +282,7 @@ in
# - org.freedesktop.impl.portal.ScreenCast # - org.freedesktop.impl.portal.ScreenCast
# - org.freedesktop.impl.portal.Screenshot # - org.freedesktop.impl.portal.Screenshot
enable = true; enable = true;
package = cfg.package;
extraPackages = []; # nixos adds swaylock, swayidle, foot, dmenu by default extraPackages = []; # nixos adds swaylock, swayidle, foot, dmenu by default
# extraOptions = [ "--debug" ]; # extraOptions = [ "--debug" ];
# "wrapGAppsHook wrapper to execute sway with required environment variables for GTK applications." # "wrapGAppsHook wrapper to execute sway with required environment variables for GTK applications."
@@ -287,7 +293,6 @@ in
# this sets XDG_CURRENT_DESKTOP=sway # this sets XDG_CURRENT_DESKTOP=sway
# and makes sure that sway is launched dbus-run-session. # and makes sure that sway is launched dbus-run-session.
wrapperFeatures.base = true; wrapperFeatures.base = true;
package = cfg.package;
}; };
programs.xwayland.enable = cfg.config.xwayland; programs.xwayland.enable = cfg.config.xwayland;
# provide portals for: # provide portals for:

View File

@@ -1,3 +1,6 @@
# docs:
# - `man 5 sway`
#
# xwayland enable|disable|force # xwayland enable|disable|force
# - enable: lazily launch xwayland on first client connection # - enable: lazily launch xwayland on first client connection
# - disable: never launch xwayland # - disable: never launch xwayland
@@ -148,10 +151,17 @@ for_window [title="megapixels"] inhibit_idle open
for_window [app_id="im.dino.Dino"] move container to workspace number 1 for_window [app_id="im.dino.Dino"] move container to workspace number 1
for_window [app_id="org.gnome.Fractal"] move container to workspace number 1 for_window [app_id="org.gnome.Fractal"] move container to workspace number 1
for_window [app_id="geary"] move container to workspace number 1 for_window [app_id="geary"] move container to workspace number 1
for_window [app_id="signal"] move container to workspace number 1
# class=Signal for when it's running with Xwayland
for_window [class="Signal"] move container to workspace number 1 for_window [class="Signal"] move container to workspace number 1
for_window [app_id="xyz.diamondb.gtkcord4"] move container to workspace number 1 for_window [app_id="so.libdb.gtkcord4"] move container to workspace number 1
for_window [app_id="abaddon"] move container to workspace number 1 for_window [app_id="abaddon"] move container to workspace number 1
# window display settings
# force KOReader to always display a titlebar, even when the only window being rendered.
# desirable primarily to avoid slooow reflows when another app is opened. but also nice to have the book title rendered.
for_window [app_id="KOReader"] border normal
### displays ### displays
## DESKTOP ## DESKTOP
output "Goldstar Company Ltd LG ULTRAWIDE 0x00004E94" { output "Goldstar Company Ltd LG ULTRAWIDE 0x00004E94" {

View File

@@ -59,6 +59,8 @@ window#waybar {
#cpu, #cpu,
#custom-media, #custom-media,
#custom-swaync, #custom-swaync,
#custom-sxmo,
#custom-sxmo-sane,
#disk, #disk,
#idle_inhibitor, #idle_inhibitor,
#memory, #memory,

View File

@@ -32,6 +32,8 @@ in
# - source: <https://www.reddit.com/r/swaywm/comments/ni0vso/waybar_spotify_tracktitle/> # - source: <https://www.reddit.com/r/swaywm/comments/ni0vso/waybar_spotify_tracktitle/>
# - alternative: <https://github.com/Alexays/Waybar/wiki/Module:-MPRIS> # - alternative: <https://github.com/Alexays/Waybar/wiki/Module:-MPRIS>
# - alternative: <https://github.com/Alexays/Waybar/wiki/Module:-Custom#mpris-controller> # - alternative: <https://github.com/Alexays/Waybar/wiki/Module:-Custom#mpris-controller>
# - alternative: <https://www.reddit.com/r/swaywm/comments/g6nw46/comment/fob604s/>
# - this one shades the background based on how far through the song you are
# #
# N.B.: for this to behave well with multiple MPRIS clients, # N.B.: for this to behave well with multiple MPRIS clients,
# `playerctld` must be enabled. see: <https://github.com/altdesktop/playerctl/issues/161> # `playerctld` must be enabled. see: <https://github.com/altdesktop/playerctl/issues/161>

View File

@@ -68,6 +68,11 @@ let
''; '';
hookPkgs = { hookPkgs = {
block_suspend = pkgs.static-nix-shell.mkBash {
pname = "sxmo_hook_block_suspend.sh";
pkgs = [ "procps" ];
src = ./hooks;
};
inputhandler = pkgs.static-nix-shell.mkBash { inputhandler = pkgs.static-nix-shell.mkBash {
pname = "sxmo_hook_inputhandler.sh"; pname = "sxmo_hook_inputhandler.sh";
pkgs = [ "coreutils" "playerctl" "pulseaudio" ]; pkgs = [ "coreutils" "playerctl" "pulseaudio" ];
@@ -83,11 +88,6 @@ let
pkgs = [ "sway" ]; pkgs = [ "sway" ];
src = ./hooks; src = ./hooks;
}; };
screenoff = pkgs.static-nix-shell.mkBash {
pname = "sxmo_hook_screenoff.sh";
pkgs = [ "sway" ];
src = ./hooks;
};
start = pkgs.static-nix-shell.mkBash { start = pkgs.static-nix-shell.mkBash {
pname = "sxmo_hook_start.sh"; pname = "sxmo_hook_start.sh";
pkgs = [ "systemd" "xdg-user-dirs" ]; pkgs = [ "systemd" "xdg-user-dirs" ];
@@ -150,7 +150,7 @@ in
# by including hooks here, updating the sxmo package also updates the hooks # by including hooks here, updating the sxmo package also updates the hooks
# without requiring any reboot # without requiring any reboot
"sxmo_hook_apps.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_apps.sh"; "sxmo_hook_apps.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_apps.sh";
"sxmo_hook_block_suspend.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_block_suspend.sh"; # "sxmo_hook_block_suspend.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_block_suspend.sh";
"sxmo_hook_call_audio.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_call_audio.sh"; "sxmo_hook_call_audio.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_call_audio.sh";
"sxmo_hook_contextmenu_fallback.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_contextmenu_fallback.sh"; "sxmo_hook_contextmenu_fallback.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_contextmenu_fallback.sh";
"sxmo_hook_contextmenu.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_contextmenu.sh"; "sxmo_hook_contextmenu.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_contextmenu.sh";
@@ -176,6 +176,7 @@ in
"sxmo_hook_restart_modem_daemons.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_restart_modem_daemons.sh"; "sxmo_hook_restart_modem_daemons.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_restart_modem_daemons.sh";
"sxmo_hook_ring.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_ring.sh"; "sxmo_hook_ring.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_ring.sh";
"sxmo_hook_rotate.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_rotate.sh"; "sxmo_hook_rotate.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_rotate.sh";
"sxmo_hook_screenoff.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_screenoff.sh";
"sxmo_hook_scripts.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_scripts.sh"; "sxmo_hook_scripts.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_scripts.sh";
"sxmo_hook_sendsms.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_sendsms.sh"; "sxmo_hook_sendsms.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_sendsms.sh";
"sxmo_hook_smslog.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_smslog.sh"; "sxmo_hook_smslog.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_smslog.sh";
@@ -186,10 +187,10 @@ in
"sxmo_hook_tailtextlog.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_tailtextlog.sh"; "sxmo_hook_tailtextlog.sh" = "${package}/share/sxmo/default_hooks/sxmo_hook_tailtextlog.sh";
} // { } // {
# default hooks for this nix module, not upstreamable # default hooks for this nix module, not upstreamable
"sxmo_hook_block_suspend.sh" = "${hookPkgs.block_suspend}/bin/sxmo_hook_block_suspend.sh";
"sxmo_hook_inputhandler.sh" = "${hookPkgs.inputhandler}/bin/sxmo_hook_inputhandler.sh"; "sxmo_hook_inputhandler.sh" = "${hookPkgs.inputhandler}/bin/sxmo_hook_inputhandler.sh";
"sxmo_hook_postwake.sh" = "${hookPkgs.postwake}/bin/sxmo_hook_postwake.sh"; "sxmo_hook_postwake.sh" = "${hookPkgs.postwake}/bin/sxmo_hook_postwake.sh";
"sxmo_hook_rotate.sh" = "${hookPkgs.rotate}/bin/sxmo_hook_rotate.sh"; "sxmo_hook_rotate.sh" = "${hookPkgs.rotate}/bin/sxmo_hook_rotate.sh";
"sxmo_hook_screenoff.sh" = "${hookPkgs.screenoff}/bin/sxmo_hook_screenoff.sh";
"sxmo_hook_start.sh" = "${hookPkgs.start}/bin/sxmo_hook_start.sh"; "sxmo_hook_start.sh" = "${hookPkgs.start}/bin/sxmo_hook_start.sh";
"sxmo_suspend.sh" = "${hookPkgs.suspend}/bin/sxmo_suspend.sh"; "sxmo_suspend.sh" = "${hookPkgs.suspend}/bin/sxmo_suspend.sh";
}; };
@@ -234,9 +235,10 @@ in
SXMO_DISABLE_CONFIGVERSION_CHECK = mkSettingsOpt "1" "allow omitting the configversion line from user-provided sxmo dotfiles"; SXMO_DISABLE_CONFIGVERSION_CHECK = mkSettingsOpt "1" "allow omitting the configversion line from user-provided sxmo dotfiles";
SXMO_UNLOCK_IDLE_TIME = mkSettingsOpt "300" "how many seconds of inactivity before locking the screen"; # lock -> screenoff happens 8s later, not configurable SXMO_UNLOCK_IDLE_TIME = mkSettingsOpt "300" "how many seconds of inactivity before locking the screen"; # lock -> screenoff happens 8s later, not configurable
# SXMO_WM = mkSettingsOpt "sway" "sway or dwm. ordinarily initialized by sxmo_{x,w}init.sh"; # SXMO_WM = mkSettingsOpt "sway" "sway or dwm. ordinarily initialized by sxmo_{x,w}init.sh";
SXMO_NO_AUDIO = mkSettingsOpt "1" "don't start pipewire/pulseaudio in sxmo_hook_start.sh"; SXMO_NO_AUDIO = mkSettingsOpt "" "don't start pipewire/pulseaudio in sxmo_hook_start.sh, don't show audio in statusbar, disable audio menu";
SXMO_STATES = mkSettingsOpt "unlock screenoff" "list of states the device should support (unlock, lock, screenoff)"; SXMO_STATES = mkSettingsOpt "unlock screenoff" "list of states the device should support (unlock, lock, screenoff)";
SXMO_SWAY_SCALE = mkSettingsOpt "1" "sway output scale"; SXMO_SWAY_SCALE = mkSettingsOpt "1" "sway output scale";
SXMO_WOB_DISABLE = mkSettingsOpt "" "disable the on-screen volume display";
}; };
}; };
default = {}; default = {};
@@ -264,8 +266,8 @@ in
suggestedPrograms = [ suggestedPrograms = [
"guiApps" "guiApps"
"bemenu" # specifically to import its theming "bemenu" # specifically to import its theming
"sfeed" # want this here so that the user's ~/.sfeed/sfeedrc gets created "sfeed" # want this here so that the user's ~/.sfeed/sfeedrc gets created
# "superd" # make superctl (used by sxmo) be on PATH # "superd" # make superctl (used by sxmo) be on PATH
# "sway-autoscaler" # "sway-autoscaler"
]; ];
@@ -293,7 +295,7 @@ in
enable = true; enable = true;
# we manage the greeter ourselves (TODO: merge this into sway config as well) # we manage the greeter ourselves (TODO: merge this into sway config as well)
useGreeter = false; useGreeter = false;
waybar.top = import ./waybar-top.nix; waybar.top = import ./waybar-top.nix { inherit pkgs; };
# reset extra waybar style # reset extra waybar style
waybar.extra_style = ""; waybar.extra_style = "";
config = { config = {
@@ -307,7 +309,12 @@ in
# these could be added, but i don't see much benefit. # these could be added, but i don't see much benefit.
font = "pango:monospace 10"; font = "pango:monospace 10";
mod = "Mod1"; # prefer Alt mod = "Mod1"; # prefer Alt
# xwayland = false; # disable to reduce RAM usage. N.B.: xwayland is needed for electron apps! # about xwayland:
# - required by many electron apps, though some electron apps support NIXOS_OZONE_WL=1 for native wayland.
# - when xwayland is enabled, KOreader incorrectly chooses the X11 backend
# -> slower; blurrier
# - xwayland uses a small amount of memory (like 30MiB, IIRC?)
xwayland = false;
workspace_layout = "tabbed"; workspace_layout = "tabbed";
brightness_down_cmd = "sxmo_brightness.sh down"; brightness_down_cmd = "sxmo_brightness.sh down";
@@ -378,7 +385,12 @@ in
bindsym button2 kill bindsym button2 kill
bindswitch lid:on exec sxmo_wm.sh dpms on bindswitch lid:on exec sxmo_wm.sh dpms on
bindswitch lid:off exec sxmo_wm.sh dpms off bindswitch lid:off exec sxmo_wm.sh dpms off
exec 'printf %s "$SWAYSOCK" > "$XDG_RUNTIME_DIR"/sxmo.swaysock' exec 'printf %s "$SWAYSOCK" > "$XDG_RUNTIME_DIR"/sxmo.swaysock'
# XXX(2023/12/04): this shouldn't be necessary, but without this Komikku fails to launch because XDG_SESSION_TYPE is unset
exec dbus-update-activation-environment --systemd XDG_SESSION_TYPE
exec_always ${sxmo_init} exec_always ${sxmo_init}
''; '';
}; };
@@ -437,57 +449,76 @@ in
event_name = eventName; event_name = eventName;
inherit transitions; inherit transitions;
}; };
friendlyToBonsai = { timeout ? null, trigger ? null, power_pressed ? {}, power_released ? {}, voldown_pressed ? {}, voldown_released ? {}, volup_pressed ? {}, volup_released ? {} }@args: friendlyToBonsai = { trigger ? null, terminal ? false, timeout ? {}, power_pressed ? {}, power_released ? {}, voldown_pressed ? {}, voldown_released ? {}, volup_pressed ? {}, volup_released ? {} }@args:
if trigger != null then [ if trigger != null then [
(doExec trigger (friendlyToBonsai (builtins.removeAttrs args ["trigger"]))) (doExec trigger (friendlyToBonsai (builtins.removeAttrs args ["trigger"])))
] else [ ] else let
(lib.mkIf (timeout != null) (onDelay (timeout.ms or 400) (friendlyToBonsai (builtins.removeAttrs timeout ["ms"])))) events = [ ]
(lib.mkIf (power_pressed != {}) (onEvent "power_pressed" (friendlyToBonsai power_pressed))) ++ (lib.optional (timeout != {}) (onDelay (timeout.ms or 400) (friendlyToBonsai (builtins.removeAttrs timeout ["ms"]))))
(lib.mkIf (power_released != {}) (onEvent "power_released" (friendlyToBonsai power_released))) ++ (lib.optional (power_pressed != {}) (onEvent "power_pressed" (friendlyToBonsai power_pressed)))
(lib.mkIf (voldown_pressed != {}) (onEvent "voldown_pressed" (friendlyToBonsai voldown_pressed))) ++ (lib.optional (power_released != {}) (onEvent "power_released" (friendlyToBonsai power_released)))
(lib.mkIf (voldown_released != {}) (onEvent "voldown_released" (friendlyToBonsai voldown_released))) ++ (lib.optional (voldown_pressed != {}) (onEvent "voldown_pressed" (friendlyToBonsai voldown_pressed)))
(lib.mkIf (volup_pressed != {}) (onEvent "volup_pressed" (friendlyToBonsai volup_pressed))) ++ (lib.optional (voldown_released != {}) (onEvent "voldown_released" (friendlyToBonsai voldown_released)))
(lib.mkIf (volup_released != {}) (onEvent "volup_released" (friendlyToBonsai volup_released))) ++ (lib.optional (volup_pressed != {}) (onEvent "volup_pressed" (friendlyToBonsai volup_pressed)))
]; ++ (lib.optional (volup_released != {}) (onEvent "volup_released" (friendlyToBonsai volup_released)))
recurseVolUpDown = ttl: if ttl == 0 then { ;
} else { in assert terminal -> events == []; events;
voldown_pressed = {
trigger = "powerhold_voldown";
timeout.ms = 1000;
power_released = {};
} // recurseVolUpDown (ttl - 1);
volup_pressed = { # trigger ${button}_hold_N every `holdTime` ms until ${button} is released
trigger = "powerhold_volup"; recurseHold = button: { count ? 1, maxHolds ? 5, prefix ? "", holdTime ? 600, ... }@opts: lib.optionalAttrs (count <= maxHolds) {
timeout.ms = 1000; "${button}_released".terminal = true; # end the hold -> back to root state
power_released = {}; timeout = {
} // recurseVolUpDown (ttl - 1); ms = holdTime;
trigger = "${prefix}${button}_hold_${builtins.toString count}";
} // (recurseHold button (opts // { count = count+1; }));
};
# trigger volup_tap_N or voldown_tap_N on every tap.
# if a volume button is held, then switch into `recurseHold`'s handling instead
volumeActions = { count ? 1, maxTaps ? 5, prefix ? "", timeout ? 600, ... }@opts: lib.optionalAttrs (count != maxTaps) {
volup_pressed = (recurseHold "volup" opts) // {
volup_released = {
trigger = "${prefix}volup_tap_${builtins.toString count}";
timeout.ms = timeout;
} // (volumeActions (opts // { count = count+1; }));
};
voldown_pressed = (recurseHold "voldown" opts) // {
voldown_released = {
trigger = "${prefix}voldown_tap_${builtins.toString count}";
timeout.ms = timeout;
} // (volumeActions (opts // { count = count+1; }));
};
}; };
in friendlyToBonsai { in friendlyToBonsai {
# map sequences of "events" to an argument to pass to sxmo_hook_inputhandler.sh # map sequences of "events" to an argument to pass to sxmo_hook_inputhandler.sh
# tap the power button N times to trigger N different actions # map: power (short), power (short) x2, power (long)
power_pressed.timeout.ms = 1200; # press w/o release. this is a long timeout because it's tied to the "kill window" action. power_pressed.timeout.ms = 900; # press w/o release. this is a long timeout because it's tied to the "kill window" action.
power_pressed.timeout.trigger = "powerhold"; power_pressed.timeout.trigger = "powerhold";
power_pressed.power_released.timeout.trigger = "powerbutton_one"; power_pressed.power_released.timeout.trigger = "powerbutton_one";
power_pressed.power_released.timeout.ms = 600; # long timeout to make `powertoggle_*` easier power_pressed.power_released.timeout.ms = 300;
power_pressed.power_released.power_pressed.trigger = "powerbutton_two"; power_pressed.power_released.power_pressed.trigger = "powerbutton_two";
# power_pressed.power_released.power_released.timeout.trigger = "powerbutton_two"; # map: volume taps and holds
# power_pressed.power_released.power_released.power_released.trigger = "powerbutton_three"; volup_pressed = (recurseHold "volup" {}) // {
# this either becomes volup_hold_* (via recurseHold, above) or:
# tap power, then tap up/down after releasing it # - a short volup_tap_1 followed by:
power_pressed.power_released.voldown_pressed.trigger = "powertoggle_voldown"; # - a *finalized* volup_1 (i.e. end of action)
power_pressed.power_released.volup_pressed.trigger = "powertoggle_volup"; # - more taps/holds, in which case we prefix it with `modal_<action>`
# to denote that we very explicitly entered this state.
# chording: hold power and then tap vol-up N times to adjust the volume by N increments. #
# XXX: HOLDING POWER LIKE THIS IS RISKY. but the default hard-power-off is like 10s, so... i guess this works until it becomes a problem...? # it's clunky: i do it this way so that voldown can map to keyboard/terminal in unlock mode
power_pressed.voldown_pressed = (recurseVolUpDown 5).voldown_pressed; # but trigger media controls in screenoff
power_pressed.volup_pressed = (recurseVolUpDown 5).volup_pressed; # in a way which *still* allows media controls if explicitly entered into via a tap on volup first
volup_released = (volumeActions { prefix = "modal_"; }) // {
# tap just one of the volume buttons. trigger = "volup_tap_1";
voldown_pressed.trigger = "voldown_one"; timeout.ms = 300;
volup_pressed.trigger = "volup_one"; timeout.trigger = "volup_1";
};
};
voldown_pressed = (volumeActions {}).voldown_pressed // {
trigger = "voldown_start";
};
}; };
# sxmo puts in /share/sxmo: # sxmo puts in /share/sxmo:
@@ -497,16 +528,6 @@ in
# - and more # - and more
# environment.pathsToLink = [ "/share/sxmo" ]; # environment.pathsToLink = [ "/share/sxmo" ];
systemd.services."sxmo-set-permissions" = {
# TODO: some of these could be modified to be udev rules
description = "configure specific /sys and /dev nodes to be writable by sxmo scripts";
serviceConfig = {
Type = "oneshot";
ExecStart = "${package}/bin/sxmo_setpermissions.sh";
};
wantedBy = [ "multi-user.target" ];
};
# if superd fails to start a service within 100ms, it'll try to start again # if superd fails to start a service within 100ms, it'll try to start again
# the fallout of this is that during intense lag (e.g. OOM or swapping) it can # the fallout of this is that during intense lag (e.g. OOM or swapping) it can
# start the service many times. # start the service many times.
@@ -583,11 +604,7 @@ in
]; ];
sane.user.services = let sane.user.services = let
sxmoPath = [ sxmoPath = [ package ] ++ package.runtimeDeps;
"/etc/profiles/per-user/colin" # so as to launch user-enabled applications (like g4music, etc)
"/run/wrappers" # for doas, and anything else suid
"/run/current-system/sw" # for things installed system-wide, especially flock
] ++ [ package ] ++ package.runtimeDeps;
sxmoEnvSetup = '' sxmoEnvSetup = ''
# mimic my sxmo_init.sh a bit. refer to the actual sxmo_init.sh above for details. # mimic my sxmo_init.sh a bit. refer to the actual sxmo_init.sh above for details.
# the specific ordering, and the duplicated profile sourcing, matters. # the specific ordering, and the duplicated profile sourcing, matters.
@@ -610,16 +627,19 @@ in
serviceConfig.RestartSec = "20s"; serviceConfig.RestartSec = "20s";
}; };
in { in {
# these are defined here, and started mostly in sxmo_hook_start.sh.
# the ones commented our here are the ones i explicitly no longer use.
# uncommenting them here *won't* cause them to be auto-started.
sxmo_autosuspend = sxmoService "autosuspend"; sxmo_autosuspend = sxmoService "autosuspend";
sxmo_battery_monitor = sxmoService "battery_monitor"; # sxmo_battery_monitor = sxmoService "battery_monitor";
sxmo_desktop_widget = sxmoService "hook_desktop_widget"; sxmo_desktop_widget = sxmoService "hook_desktop_widget";
sxmo_hook_lisgd = sxmoService "hook_lisgdstart"; sxmo_hook_lisgd = sxmoService "hook_lisgdstart";
sxmo_menumode_toggler = sxmoService "menumode_toggler"; sxmo_menumode_toggler = sxmoService "menumode_toggler";
sxmo_modemmonitor = sxmoService "modemmonitor"; sxmo_modemmonitor = sxmoService "modemmonitor";
sxmo_networkmonitor = sxmoService "networkmonitor"; # sxmo_networkmonitor = sxmoService "networkmonitor";
sxmo_notificationmonitor = sxmoService "notificationmonitor"; sxmo_notificationmonitor = sxmoService "notificationmonitor";
sxmo_soundmonitor = sxmoService "soundmonitor"; # sxmo_soundmonitor = sxmoService "soundmonitor";
sxmo_wob = sxmoService "wob"; # sxmo_wob = sxmoService "wob";
sxmo-x11-status = sxmoService "status_xsetroot"; sxmo-x11-status = sxmoService "status_xsetroot";
bonsaid.path = sxmoPath; bonsaid.path = sxmoPath;

View File

@@ -0,0 +1,57 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p procps
# Basic exponential backoff, this should save some resources if we're blocked by
# the same thing for a while
delay() {
sleep "$delay_time"
delay_time="$((delay_time*2))"
if [ "$delay_time" -gt 45 ]; then
delay_time=45
fi
}
wait_item() {
delay_time=1
while $1 > /dev/null 2>&1; do
echo "Blocking suspend for $1"
waited=1
delay
done
}
##################################### below is original, not shared with upstream sxmo_hook_block_suspend.sh
casting_go2tv() {
pgrep -f go2tv
}
# forward to the next block_suspend.sh script (if any).
# have to handle the case where this script is on PATH, and also when it was called without being on PATH.
# the implementation here causes us to call ourselves exactly once, at most (or twice, if there are duplicate PATH entries)
SXMO_HOOK_BLOCK_SUSPEND_DEPTH=$((${SXMO_HOOK_BLOCK_SUSPEND_DEPTH:-0} + 1))
echo "recurse counter: $SXMO_HOOK_BLOCK_SUSPEND_DEPTH"
block_suspend_next=true
FWD_COUNT=0
IFS=:
for p in $PATH ; do
echo "testing: $p/sxmo_hook_block_suspend.sh"
if $(test -x "$p/sxmo_hook_block_suspend.sh"); then
FWD_COUNT=$(($FWD_COUNT + 1))
fi
if [ "$FWD_COUNT" -eq "$SXMO_HOOK_BLOCK_SUSPEND_DEPTH" ]; then
block_suspend_next="$p/sxmo_hook_block_suspend.sh"
break
fi
done
while [ "$waited" != "0" ]; do
waited=0
echo "forwarding to: $block_suspend_next"
SXMO_HOOK_BLOCK_SUSPEND_DEPTH="$SXMO_HOOK_BLOCK_SUSPEND_DEPTH" "$block_suspend_next"
# wait for my own items last. else, we could wait for go2tv, then wait for internals, and in the meantime go2tv was re-spawned.
wait_item casting_go2tv
done

View File

@@ -10,40 +10,41 @@
# - bonsai mappings are static, so buttons can't benefit from non-compounding unless they're mapped accordingly for all lock states # - bonsai mappings are static, so buttons can't benefit from non-compounding unless they're mapped accordingly for all lock states
# - this limitation could be removed, but with work # - this limitation could be removed, but with work
# #
# proposed future design: # example of a design which considers these things:
# - when unlocked: # - when unlocked:
# - volup-release -> app menu # - volup toggle -> app menu
# - volup-hold -> WM menu # - voldown press -> keyboard
# - voldown-release -> toggle keyboard # - voldown hold -> terminal
# - voldown-hold -> terminal # - power x2 -> screenoff
# - pow-volup xN -> volume up # - hold power -> kill app
# - pow-voldown xN -> volume down # - when locked:
# - pow-x2 -> screen off # - volup tap -> volume up
# - pow-hold -> kill app # - volup hold -> media seek forward
# - when screenoff: # - voldown tap -> volume down
# - volup -> volume up # - voldown hold -> media seek backward
# - voldown -> volume down # - power x1 -> screen on
# - pow-x1 -> screen on # - power x2 -> play/pause media
# - pow-x2 -> toggle player # some trickiness allows for media controls in unlocked mode:
# - pow-volup -> seek +30s # - volup tap -> enter media mode
# - pow-voldown -> seek -10s # - i.e. in this state, vol tap/hold is mapped to volume/seek
# benefits: # - if, after entering media mode, no more taps occur, then we trigger the default app-menu action
# - volup and voldown are able to be far more responsive # limitations/downsides:
# - which means faster vkbd, menus, volume adjustment (when locked) # - power mappings means phone is artificially slow to unlock.
# - less mental load than the chording-based approach (where i hold power to adjust volume) # - media controls when unlocked have quirks:
# - less risk due to not chording the power button # - mashing voldown to decrease the volume will leave you with a toggled keyboard.
# drawbacks: # - seeking backward isn't possible except by first tapping volup.
# - volup/down actions are triggered by the release instead of the press; slight additional latency for pulling open the keyboard
# - moving the WM menu into the top-level menu could allow keeping voldown free of complication
# increments to use for volume adjustment # increments to use for volume adjustment
VOL_INCR_1=5 VOL_INCR=5
VOL_INCR_2=10
# replicating the naming from upstream sxmo_hook_inputhandler.sh... # replicating the naming from upstream sxmo_hook_inputhandler.sh...
ACTION="$1" ACTION="$1"
STATE=$(cat "$SXMO_STATE") STATE=$(cat "$SXMO_STATE")
noop() {
true
}
handle_with() { handle_with() {
echo "sxmo_hook_inputhandler.sh: STATE=$STATE ACTION=$ACTION: handle_with: $@" echo "sxmo_hook_inputhandler.sh: STATE=$STATE ACTION=$ACTION: handle_with: $@"
@@ -51,18 +52,6 @@ handle_with() {
exit 0 exit 0
} }
# handle_with_state_toggle() {
# # - unlock,lock => screenoff
# # - screenoff => unlock
# #
# # probably not handling proximity* correctly here
# case "$STATE" in
# *lock)
# respond_with sxmo_state.sh set screenoff
# *)
# respond_with sxmo_state.sh set unlock
# esac
# }
# state is one of: # state is one of:
# - "unlock" => normal operation; display on and touchscreen on # - "unlock" => normal operation; display on and touchscreen on
@@ -79,24 +68,35 @@ if [ "$STATE" = "unlock" ]; then
handle_with sxmo_killwindow.sh handle_with sxmo_killwindow.sh
;; ;;
"volup_one") "volup_tap_1")
# swallow: this could be the start to a media control (multi taps / holds),
# or it could be just a single tap -> release, handled next/below
handle_with noop
;;
"volup_1")
# volume up once: app-specific menu w/ fallback to SXMO system menu # volume up once: app-specific menu w/ fallback to SXMO system menu
handle_with sxmo_appmenu.sh handle_with sxmo_appmenu.sh
;; ;;
"voldown_one") "voldown_start")
# volume down once: toggle keyboard # volume down once: toggle keyboard
handle_with sxmo_keyboard.sh toggle handle_with sxmo_keyboard.sh toggle
;; ;;
"voldown_hold_2")
"powertoggle_volup") # hold voldown to launch terminal
# power -> volume up: DE menu # note we already triggered the keyboard; that's fine: usually keyboard + terminal go together :)
handle_with sxmo_wmmenu.sh # voldown_hold_1 frequently triggers during short taps meant only to reveal the keyboard,
;; # so prefer a longer hold duration
"powertoggle_voldown")
# power -> volume down: launch terminal
handle_with sxmo_terminal.sh handle_with sxmo_terminal.sh
;; ;;
"voldown_tap_1")
# swallow, to prevent keyboard from also triggering media controls
handle_with noop
;;
voldown_hold_*)
# swallow, to prevent terminal from also triggering media controls
handle_with noop
;;
esac esac
fi fi
@@ -110,14 +110,6 @@ if [ "$STATE" = "screenoff" ]; then
# power toggle during deep sleep often gets misread as power hold, so treat same # power toggle during deep sleep often gets misread as power hold, so treat same
handle_with sxmo_state.sh set unlock handle_with sxmo_state.sh set unlock
;; ;;
"powertoggle_volup"|"powerhold_volup")
# power -> volume up: seek forward
handle_with playerctl position 30+
;;
"powertoggle_voldown"|"powerhold_voldown")
# power -> volume down: seek backward
handle_with playerctl position 10-
;;
esac esac
fi fi
@@ -133,21 +125,20 @@ case "$ACTION" in
;; ;;
# powerbutton_three: intentional no-op because overloading the kill-window handler is risky # powerbutton_three: intentional no-op because overloading the kill-window handler is risky
"volup_one") volup_tap*|modal_volup_tap*)
handle_with pactl set-sink-volume @DEFAULT_SINK@ +"$VOL_INCR_1%" handle_with pactl set-sink-volume @DEFAULT_SINK@ +"$VOL_INCR%"
;; ;;
"voldown_one") voldown_tap*|modal_voldown_tap*)
handle_with pactl set-sink-volume @DEFAULT_SINK@ -"$VOL_INCR_1%" handle_with pactl set-sink-volume @DEFAULT_SINK@ -"$VOL_INCR%"
;; ;;
# HOLD power button and tap volup/down to adjust volume volup_hold*|modal_volup_hold*)
"powerhold_volup") handle_with playerctl position 30+
handle_with pactl set-sink-volume @DEFAULT_SINK@ +"$VOL_INCR_1%"
;; ;;
"powerhold_voldown") voldown_hold*|modal_voldown_hold*)
handle_with pactl set-sink-volume @DEFAULT_SINK@ -"$VOL_INCR_1%" handle_with playerctl position 10-
;; ;;
esac esac
handle_with echo "no-op" handle_with noop

View File

@@ -1,22 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p sway
# this hook is mostly identical to default sxmo_hook_screenoff.sh except:
# - the LED frequency is adjusted from its default of "blink every 2s"
# - dwm-specific bits are removed
BLINK_FREQ=8
swaymsg mode default
sxmo_wm.sh dpms on
sxmo_wm.sh inputevent touchscreen off
sxmo_jobs.sh start periodic_blink sxmo_run_periodically.sh "$BLINK_FREQ" sxmo_led.sh blink red blue
wait
# avoid immediate suspension. particularly, ensure that we get at least one blink in
sxmo_wakelock.sh lock sxmo_hold_a_bit "$BLINK_FREQ"s
sxmo_wakelock.sh unlock sxmo_not_screenoff

View File

@@ -10,14 +10,15 @@ xdg-user-dirs-update
sxmo_jobs.sh start daemon_manager sxmo_jobs.sh start daemon_manager
# Periodically update some status bar components # Periodically update some status bar components
sxmo_hook_statusbar.sh all # don't: statusbar is managed by waybar
sxmo_jobs.sh start statusbar_periodics sxmo_run_aligned.sh 60 \ # sxmo_hook_statusbar.sh all
sxmo_hook_statusbar.sh periodics # sxmo_jobs.sh start statusbar_periodics sxmo_run_aligned.sh 60 \
# sxmo_hook_statusbar.sh periodics
# TODO: start these externally, via `wantedBy` in nix # TODO: start these externally, via `wantedBy` in nix
# don't: mako is managed externally # don't: i don't use mako
# superctl start mako # superctl start mako
systemctl --user start sxmo_wob # systemctl --user start sxmo_wob
systemctl --user start sxmo_menumode_toggler systemctl --user start sxmo_menumode_toggler
systemctl --user start bonsaid systemctl --user start bonsaid
# don't: sway background is managed externally # don't: sway background is managed externally
@@ -49,16 +50,22 @@ fi
# superctl start sxmo_conky # superctl start sxmo_conky
# Monitor the battery # Monitor the battery
systemctl --user start sxmo_battery_monitor # don't: this is *exclusively* for sxmo_hook_statusbar.sh, which i don't use.
# systemctl --user start sxmo_battery_monitor
# It watch network changes and update the status bar icon by example # It watch network changes and update the status bar icon by example
systemctl --user start sxmo_networkmonitor # don't: this is for sxmo_hook_statusbar.sh, which i don't use.
# this means we never call sxmo_hook_network_{up,down,...}, but the defaults are no-op anyway
# systemctl --user start sxmo_networkmonitor
# The daemon that display notifications popup messages # The daemon that display notifications popup messages
# more importantly: it lights the led green when a notification arrives
systemctl --user start sxmo_notificationmonitor systemctl --user start sxmo_notificationmonitor
# monitor for headphone for statusbar # monitor for headphone for statusbar
systemctl --user start sxmo_soundmonitor # this also invokes `wob` whenever the volume is changed
# don't: my volume monitoring is handled by sway
# systemctl --user start sxmo_soundmonitor
# rotate UI based on physical display angle by default # rotate UI based on physical display angle by default
if [ -n "$SXMO_AUTOROTATE" ]; then if [ -n "$SXMO_AUTOROTATE" ]; then

View File

@@ -30,15 +30,22 @@ logger = logging.getLogger(__name__)
NTFY_HOST = 'uninsane.org' NTFY_HOST = 'uninsane.org'
NTFY_PORT_BASE = 5550 NTFY_PORT_BASE = 5550
SUSPEND_TIME=300
# duration in seconds to sleep for
SUSPEND_TIME = 300
# take care that WOWLAN_DELAY might include more than you think (e.g. time spent configuring wowlan pattern rules) # take care that WOWLAN_DELAY might include more than you think (e.g. time spent configuring wowlan pattern rules)
WOWLAN_DELAY=6 WOWLAN_DELAY = 6
# SXMO LED blink frequency to set on resume
BLINK_FREQ = 5
class Executor: class Executor:
def __init__(self, dry_run: bool = False): def __init__(self, dry_run: bool = False):
self.dry_run = dry_run self.dry_run = dry_run
def exec(self, cmd: list[str], sudo: bool = False, check: bool = True): def exec(self, cmd: list[str], sudo: bool = False, check: bool = True, wait: bool = True):
if check: assert wait, "can't check_output without first waiting for process completion"
if sudo: if sudo:
cmd = [ 'doas' ] + cmd cmd = [ 'doas' ] + cmd
@@ -46,18 +53,24 @@ class Executor:
if self.dry_run: if self.dry_run:
return return
try: if wait:
res = subprocess.run(cmd, capture_output=True) try:
except Exception as e: res = subprocess.run(cmd, capture_output=True)
if check: raise except Exception as e:
logger.warning(f"error invoking subprocess: {e}") if check: raise
return logger.warning(f"error invoking subprocess: {e}")
return
logger.debug(res.stdout) logger.debug(res.stdout)
if res.stderr: if res.stderr:
logger.warning(res.stderr) logger.warning(res.stderr)
if check: if check:
res.check_returncode() res.check_returncode()
else:
res = subprocess.Popen(cmd)
return res
def try_connect(self, dest, delay): def try_connect(self, dest, delay):
logger.debug(f"opening socket to {dest} with timeout {delay}") logger.debug(f"opening socket to {dest} with timeout {delay}")
@@ -124,13 +137,33 @@ class Suspender:
def suspend(self, duration: int, mode: str): def suspend(self, duration: int, mode: str):
logger.info(f"calling suspend for duration: {duration}") logger.info(f"calling suspend for duration: {duration}")
if mode == 'rtcwake': if mode == 'rtcwake':
self.executor.exec(['rtcwake', '-m', 'mem', '-s', str(duration)], check=False) self.executor.exec(['rtcwake', '-m', 'mem', '-s', str(duration)], sudo=True, check=False)
elif mode == 'sleep': elif mode == 'sleep':
time.sleep(duration) time.sleep(duration)
else: else:
assert False, f"unknown suspend mode: {mode}" assert False, f"unknown suspend mode: {mode}"
class SxmoApi:
def __init__(self, executor: Executor):
self.executor = executor
def halt_services(self) -> None:
res = self.executor.exec(['sxmo_jobs.sh', 'running', 'periodic_blink'], check=False)
self.was_blinking = res and res.returncode == 0
if self.was_blinking:
self.executor.exec(['sxmo_jobs.sh', 'stop', 'periodic_blink'], check=False)
def resume_services(self) -> None:
if self.was_blinking:
# XXX: sxmo_jobs.sh is supposed to run the job in the background, but somehow it fails (blocks), only when invoked from Python.
# oh well, just call it asynchronously (wait=False)
self.executor.exec(['sxmo_jobs.sh', 'start', 'periodic_blink', 'sxmo_run_periodically.sh', str(BLINK_FREQ), 'sxmo_led.sh', 'blink', 'red', 'blue'], check=False, wait=False)
def call_postwake_hook(self) -> None:
self.executor.exec(['sxmo_hook_postwake.sh'], check=False)
def main(): def main():
logging.basicConfig() logging.basicConfig()
logging.getLogger().setLevel(logging.INFO) logging.getLogger().setLevel(logging.INFO)
@@ -152,7 +185,9 @@ def main():
suspend_mode = args.suspend_mode suspend_mode = args.suspend_mode
executor = Executor(dry_run=args.dry_run) executor = Executor(dry_run=args.dry_run)
suspender = Suspender(executor, wowlan_delay=wowlan_delay) suspender = Suspender(executor, wowlan_delay=wowlan_delay)
sxmo_api = SxmoApi(executor)
sxmo_api.halt_services()
suspender.open_ntfy_stream() suspender.open_ntfy_stream()
suspender.configure_wowlan() suspender.configure_wowlan()
@@ -165,7 +200,8 @@ def main():
logger.info(f"suspended for {time_spent:.0f} seconds") logger.info(f"suspended for {time_spent:.0f} seconds")
suspender.close_ntfy_stream() suspender.close_ntfy_stream()
executor.exec(['sxmo_hook_postwake.sh'], check=False) sxmo_api.resume_services()
sxmo_api.call_postwake_hook()
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@@ -0,0 +1,122 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p sxmo-utils -p sxmo-utils.runtimeDeps
#
# usage:
# waybar-sxmo-status widget1 [ widget2 [...]]
#
# where each widget is one of:
# - modem-state
# - modem-tech
# - modem-signal
# - wifi-status
# - volume
# sxmo_hook_statusbar.sh assumes:
# - mmcli, jq on PATH
# - sxmo_hook_icons.sh and sxmo_common.sh are sourcable
# - from sxmo_common, it only uses sxmobar (and aliases jq=gojq)
# setup environment so that the hooks will be on PATH:
# - sxmo_hook_statusbar.sh
# - sxmo_hook_icons.sh
export HOME="${HOME:-/home/colin}"
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
export PATH="$XDG_CONFIG_HOME/sxmo/hooks:$PATH"
# ensure that sxmo_audio.sh tells us the volume instead of early-returning
export SXMO_NO_AUDIO=
# clunky interaction between us and sxmo_hook_statusbar.sh:
# - we export `sxmobar` to it, but within that function cannot modify the environment
# of *this* script, because it gets run in a different process.
# - so, `sxmobar` prints info to stdout, and then this script re-interprets that info.
# - practically, `sxmobar` prints shell commands, and then this script `eval`s them, to achieve that IPC.
sxmobar() {
action="$1"
shift
if [ "$action" = "-a" ]; then
while [ -n "$*" ]; do
arg="$1"
case "$arg" in
"-f"|"-b"|"-t"|"-e")
# foreground/background/text/emphasis: ignore it
shift
shift
;;
*)
# begin arguments
break
;;
esac
done
echo "setitem $@"
fi
}
export -f sxmobar
setitem() {
id="$1"
priority="$2"
value="$3"
case "$id" in
modem-state)
modem_state="$value"
;;
modem-tech)
modem_tech="$value"
;;
modem-signal)
modem_signal="$value"
;;
wifi-status)
wifi_status="$value"
;;
volume)
volume="$value"
;;
esac
}
while [ -n "$*" ]; do
variable="$1"
shift
case "$variable" in
"--verbose")
set -x
;;
"modem-state")
if [ -z "$modem_state" ]; then
eval "$(sxmo_hook_statusbar.sh modem)"
fi
echo -n "$modem_state"
;;
"modem-tech")
if [ -z "$modem_tech" ]; then
eval "$(sxmo_hook_statusbar.sh modem)"
fi
echo -n "$modem_tech"
;;
"modem-signal")
if [ -z "$modem_signal" ]; then
eval "$(sxmo_hook_statusbar.sh modem)"
fi
echo -n "$modem_signal"
;;
"wifi-status")
if [ -z "$wifi_status" ]; then
eval "$(sxmo_hook_statusbar.sh network wifi wlan0)"
fi
echo -n "$wifi_status"
;;
"volume")
if [ -z "$volume" ]; then
eval "$(sxmo_hook_statusbar.sh volume)"
fi
echo -n "$volume"
;;
*)
echo -n "UNK: $variable"
;;
esac
done

View File

@@ -1,12 +1,30 @@
# docs: https://github.com/Alexays/Waybar/wiki/Configuration # docs: https://github.com/Alexays/Waybar/wiki/Configuration
# format specifiers: https://fmt.dev/latest/syntax.html#syntax # format specifiers: https://fmt.dev/latest/syntax.html#syntax
# this is merged with the sway/waybar-top.nix defaults # this is merged with the sway/waybar-top.nix defaults
{ pkgs }:
let
waybar-sxmo-status = pkgs.static-nix-shell.mkBash {
pname = "waybar-sxmo-status";
src = ./.;
pkgs = [ "sxmo-utils" "sxmo-utils.runtimeDeps" ];
};
in
{ {
height = 26; height = 26;
modules-left = [ "sway/workspaces" ]; modules-left = [ "sway/workspaces" ];
modules-center = [ ]; modules-center = [ ];
modules-right = [ "custom/swaync" "custom/sxmo" ]; modules-right = [
"custom/swaync"
"clock"
"battery"
"custom/sxmo-sane"
# "custom/sxmo"
# "custom/sxmo/modem-state"
# "custom/sxmo/modem-tech"
# "custom/sxmo/modem-signal"
# "custom/sxmo/wifi"
];
"sway/workspaces" = { "sway/workspaces" = {
all-outputs = true; all-outputs = true;
@@ -20,12 +38,56 @@
}; };
}; };
"custom/sxmo-sane" = {
# this calls all the SXMO indicators, inline.
# so it works even without the "statusbar periodics" sxmo service running.
interval = 2;
format = "{}";
exec = "${waybar-sxmo-status}/bin/waybar-sxmo-status modem-state modem-tech modem-signal wifi-status volume";
};
"custom/sxmo" = { "custom/sxmo" = {
# this gives wifi state, batter, mic/speaker, lockstate, time all as one widget. # this gives wifi state, battery, mic/speaker, lockstate, time all as one widget.
# a good starting point, but may want to split these apart later to make things configurable. # a good starting point, but may want to split these apart later to make things configurable.
# e.g. distinct vol-up & vol-down buttons next to the speaker? # the values for this bar are computed in sxmo:configs/default_hooks/sxmo_hook_statusbar.sh
exec = "sxmo_status.sh"; exec = "sxmo_status.sh";
interval = 1; interval = 1;
format = "{}"; format = "{}";
}; };
# not ported: battery, ethernet
"custom/sxmo/modem-state" = {
exec = "cat /run/user/1000/sxmo_status/default/10-modem-state";
interval = 2;
format = "{}";
};
"custom/sxmo/modem-tech" = {
exec = "cat /run/user/1000/sxmo_status/default/11-modem-tech";
interval = 2;
format = "{}";
};
"custom/sxmo/modem-signal" = {
exec = "cat /run/user/1000/sxmo_status/default/12-modem-signal";
interval = 2;
format = "{}";
};
"custom/sxmo/wifi" = {
exec = "cat /run/user/1000/sxmo_status/default/30-wifi-status";
interval = 2;
format = "{}";
};
"custom/sxmo/volume" = {
exec = "cat /run/user/1000/sxmo_status/default/50-volume";
interval = 2;
format = "{}";
};
"custom/sxmo/state" = {
exec = "cat /run/user/1000/sxmo_status/default/90-state";
interval = 2;
format = "{}";
};
"custom/sxmo/time" = {
exec = "cat /run/user/1000/sxmo_status/default/99-time";
interval = 2;
format = "{}";
};
} }

View File

@@ -94,6 +94,7 @@ in
speedFactor = 2; speedFactor = 2;
supportedFeatures = [ supportedFeatures = [
# "big-parallel" # it can't reliably build webkitgtk # "big-parallel" # it can't reliably build webkitgtk
"no-binfmt"
]; ];
mandatoryFeatures = [ ]; mandatoryFeatures = [ ];
sshUser = "nixremote"; sshUser = "nixremote";

View File

@@ -13,7 +13,7 @@ in
}; };
emulation = mkOption { emulation = mkOption {
type = types.bool; type = types.bool;
default = true; default = false;
}; };
ccache = mkOption { ccache = mkOption {
type = types.bool; type = types.bool;
@@ -35,6 +35,8 @@ in
# it's nice to not be limited in that way, so increase this a bit. # it's nice to not be limited in that way, so increase this a bit.
nix.nrBuildUsers = 64; nix.nrBuildUsers = 64;
nix.settings.system-features = [ "big-parallel" ];
# enable cross compilation # enable cross compilation
# TODO: do this via stdenv injection, linking into /run/binfmt the stuff in <nixpkgs:nixos/modules/system/boot/binfmt.nix> # TODO: do this via stdenv injection, linking into /run/binfmt the stuff in <nixpkgs:nixos/modules/system/boot/binfmt.nix>
boot.binfmt.emulatedSystems = lib.optionals cfg.emulation [ boot.binfmt.emulatedSystems = lib.optionals cfg.emulation [

View File

@@ -10,6 +10,7 @@
config = lib.mkIf config.sane.roles.handheld { config = lib.mkIf config.sane.roles.handheld {
sane.programs.guiApps.suggestedPrograms = [ sane.programs.guiApps.suggestedPrograms = [
"consoleMediaUtils" # overbroad, but handy on very rare occasion
"handheldGuiApps" "handheldGuiApps"
]; ];
}; };

View File

@@ -0,0 +1,9 @@
{
"description": "A podcast for potential-pursuing optimists, for doers who want to make a dent in the universe, for those interested in crypto, longevity, city-building, etc., and for anyone who loves learning the stories of extraordinary entrepreneurs.",
"is_podcast": true,
"site_name": "",
"site_url": "",
"title": "POD OF JAKE",
"url": "https://anchor.fm/s/2da69154/podcast/rss",
"velocity": 0.124
}

View File

@@ -0,0 +1,9 @@
{
"description": "About the modern financial infrastructure that the world sits atop of.",
"is_podcast": false,
"site_name": "Bits about Money",
"site_url": "https://www.bitsaboutmoney.com",
"title": "Bits about Money",
"url": "https://www.bitsaboutmoney.com/archive/rss/",
"velocity": 0.041
}

View File

@@ -0,0 +1,9 @@
{
"description": "Recent content on The KosmosGhost Site",
"is_podcast": false,
"site_name": "The KosmosGhost Site",
"site_url": "https://kosmosghost.github.io",
"title": "The KosmosGhost Site",
"url": "https://kosmosghost.github.io/index.xml",
"velocity": 0.0
}

View File

@@ -0,0 +1,9 @@
{
"description": "LINMOB.net is a blog about LINux on MOBile devices. With the PinePhone (Pro) and Librem 5 shipping it is back to report on GNU+Linux on mobile devices.",
"is_podcast": false,
"site_name": "LINux on MOBile",
"site_url": "https://linmob.net",
"title": "LINux on MOBile",
"url": "https://linmob.net/feed.xml",
"velocity": 0.176
}

View File

@@ -0,0 +1,9 @@
{
"description": "<p>Comedians Dave Anthony and Gareth Reynolds picks a subject from history and examine it.</p>",
"is_podcast": true,
"site_name": "",
"site_url": "",
"title": "The Dollop with Dave Anthony and Gareth Reynolds",
"url": "https://www.omnycontent.com/d/playlist/885ace83-027a-47ad-ad67-aca7002f1df8/22b063ac-654d-428f-bd69-ae2400349cde/65ff0206-b585-4e2a-9872-ae240034c9c9/podcast.rss",
"velocity": 0.188
}

Some files were not shown because too many files have changed in this diff Show More