1
0
mirror of https://github.com/kmein/niveum synced 2026-03-16 10:11:08 +01:00

5 Commits

Author SHA1 Message Date
ec632a0a77 manakish: fix imports 2026-02-11 16:47:08 +01:00
33c26717e1 format 2026-02-11 16:47:00 +01:00
3a8fb41b8f yt-dlp-master 2026-02-11 16:46:36 +01:00
4f69710614 mpv: configure with wrappers 2026-02-11 16:46:06 +01:00
0a539e4a77 lix: try out 2026-02-11 16:45:50 +01:00
95 changed files with 1829 additions and 1236 deletions

38
.bin/256color Executable file
View File

@@ -0,0 +1,38 @@
#! /bin/sh
set -euf
pl() {
for i in $(seq $1 $(expr $2 - 1)); do
printf '\e[38;5;%sm%03i\e[m ' $i $i
done
printf '\e[38;5;%sm%03i\e[m\n' $2 $2
}
p() {
printf '\e[38;5;%sm%03i\e[m ' $1 $1
}
pn() {
printf '\e[38;5;%sm%03i\e[m\n' $1 $1
}
p6x6() {
for i in $(seq 0 5); do
for j in $(seq 0 5); do
p $(expr $1 + $i + $j \* 6)
done
echo
done
}
pl 0 7
pl 8 15
p6x6 16
p6x6 52
p6x6 88
p6x6 124
p6x6 160
p6x6 196
pl 232 243
pl 244 255

29
.bin/anki-poem.sh Executable file
View File

@@ -0,0 +1,29 @@
#!/bin/sh
file="${1?please supply a poetry file}"
[ -f "$file" ] || {
echo "'$file' is no file"
exit 1
}
poem="$(mktemp)"
clean () {
rm "$poem"
}
trap clean EXIT
sed '/^$/d' "$file" > "$poem"
htmlize() {
awk 'ORS="<br/>"' \
| head -c -5 # remove final <br/> characters
}
for line_number in $(seq 1 "$(wc -l "$poem" | cut -d' ' -f1)"); do
if [ "$line_number" -gt 3 ] && [ "$line_number" -gt 1 ]; then
sed -n "$((line_number - 3)),$((line_number - 1))p" "$poem"
else
sed -n "1,$((line_number - 1))p" "$poem"
fi | htmlize
printf '\t'
sed -n "${line_number},+1p" "$poem" | htmlize
printf '\n'
done

54
.bin/avesta.sed Executable file
View File

@@ -0,0 +1,54 @@
#!/usr/bin/env -S sed -f
s/ā̊/𐬃/g
s//𐬝/g
s/ṣ̌/𐬴/g
s/š́/𐬳/g
s/ą̄/𐬅/g
s/ŋᵛ/𐬤/g
s/ə̄/𐬇/g
s/ŋ́/𐬣/g
s//𐬒/g
s/xᵛ/𐬓/g
s/a/𐬀/g
s/ā/𐬁/g
s/å/𐬂/g
s/ą/𐬄/g
s/ə/𐬆/g
s/e/𐬈/g
s/ē/𐬉/g
s/o/𐬊/g
s/ō/𐬋/g
s/i/𐬌/g
s/ī/𐬍/g
s/u/𐬎/g
s/ū/𐬏/g
s/k/𐬐/g
s/x/𐬑/g
s/g/𐬔/g
s/ġ/𐬕/g
s/γ/𐬖/g
s/c/𐬗/g
s/j/𐬘/g
s/t/𐬙/g
s/θ/𐬚/g
s/d/𐬛/g
s/δ/𐬜/g
s/p/𐬞/g
s/f/𐬟/g
s/b/𐬠/g
s/β/𐬡/g
s/ŋ/𐬢/g
s/n/𐬥/g
s/ń/𐬦/g
s//𐬧/g
s/m/𐬨/g
s//𐬩/g
s//𐬫/g
s/y/𐬪/g
s/v/𐬬/g
s/r/𐬭/g
s/s/𐬯/g
s/z/𐬰/g
s/š/𐬱/g
s/ž/𐬲/g
s/h/𐬵/g

24
.bin/browser Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/sh -e
#
# Usage: browser
# pipe html to a browser
# e.g.
# $ echo '<h1>hi mom!</h1>' | browser
# $ ron -5 man/rip.5.ron | browser
if [ -t 0 ]; then
if [ -n "$1" ]; then
open $1
else
cat <<usage
Usage: browser
pipe html to a browser
$ echo '<h1>hi mom!</h1>' | browser
$ ron -5 man/rip.5.ron | browser
usage
fi
else
f="/tmp/browser.$RANDOM.html"
cat /dev/stdin > $f
xdg-open $f
fi

46
.bin/bvg.sh Executable file
View File

@@ -0,0 +1,46 @@
#!/bin/sh
interesting="U6 N6 140 M46 184 N84"
curl -sSL 'https://www.bvg.de/disruption-reports/q' \
--data-raw '{"variables":{},"query":"{
allDisruptions {
disruptions {
meldungsId
linie
verkehrsmittel
__typename
... on Traffic {
datum
gueltigVonDatum
gueltigVonZeit
gueltigBisDatum
gueltigBisZeit
richtungName
richtungHafasId
beginnAbschnittName
beginnAbschnittHafasId
endeAbschnittName
endeAbschnittHafasId
textIntUrsache
sev
textIntAuswirkung
umfahrung
textWAPSMSUrsache
textWAPSMSAuswirkung
prioritaet
__typename
}
}
__typename
}
}"}' \
| jq --arg interesting "$interesting" '
.data.allDisruptions.disruptions
| map(select(
(.linie as $linie
| $interesting
| split(" ")
| index($linie))
and (.["__typename"] == "Traffic")
))
'

19
.bin/calendars.sh Executable file
View File

@@ -0,0 +1,19 @@
#!/bin/sh
directory="$(mktemp -d)"
trap clean EXIT
clean() {
rm -rf "$directory"
}
year=$(date +%Y)
output=/tmp/$year.pdf
for month in $(seq 1 12); do
printf "\r%d" "$month" 1>&2
astrolog -zN Berlin -qm "$month" "$year" -X -K -XA -Xr -Xm -Xb -Xo "$(printf "%s/%02d.bmp" "$directory" "$month")" -Xw 1080 720 2>/dev/null
done
printf "\r"
convert "$directory/*.bmp" "$output"
echo "$output"

25
.bin/candyman Executable file
View File

@@ -0,0 +1,25 @@
#!/bin/sh
set -efu
usage() {
echo >&2 "$0 add-{reddit,telegram,youtube,twitch,twitter} NAME"
exit 1
}
candyman() {
curl -fsSv http://news.r/api -H content-type:application/json -d "$(jq -n "
{
command: \"PRIVMSG\",
params: [\"#all\", \"candyman: $1 $2\"]
}
")"
}
[ $# -ge 2 ] || usage
case "$1" in
add-reddit|add-telegram|add-youtube|add-twitter|add-twitch)
candyman "$@"
;;
*) usage;;
esac

23
.bin/chunk-pdf Executable file
View File

@@ -0,0 +1,23 @@
#! /usr/bin/env nix-shell
#! nix-shell -i bash -p pdftk gnugrep
set -efu
INPUT_FILE="${2:?Pass the PDF path as second argument.}"
PAGES_PER_REPORT="${1:?Pass the chunk size as first argument.}"
if [ ! -f "$INPUT_FILE" ]; then
echo >&2 "File $INPUT_FILE does not exist."
exit 1
fi
TOTAL_PAGES="$(pdftk "$INPUT_FILE" dump_data | grep NumberOfPages | cut -f2 -d' ')"
RUNS=$((TOTAL_PAGES/PAGES_PER_REPORT))
for run in $(seq 0 "$((RUNS-1))"); do
start_page=$((run*PAGES_PER_REPORT+1))
end_page=$(((run+1)*PAGES_PER_REPORT))
output_file="chunk_$((run+1)).pdf"
echo "splitting $INPUT_FILE from $start_page to $end_page into $output_file"
pdftk "$INPUT_FILE" cat "$start_page-$end_page" output "$output_file"
done

13
.bin/countdown Executable file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/env -S awk -f
function z() {
getline < "/proc/uptime"
close("/proc/uptime")
return $0
}
BEGIN {
x = z()
while (1) {
y = z()
printf "%02d:%05.2f\r", (y - x) / 60, (y - x) % 60
}
}

14
.bin/csv2json Executable file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env python3
import csv
import json
import sys
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--delimiter", "-d", default=",", help="CSV field separator")
args = parser.parse_args()
if __name__ == "__main__":
json.dump(list(csv.DictReader(sys.stdin, delimiter=args.delimiter)), sys.stdout)

43
.bin/dummy-alert Executable file
View File

@@ -0,0 +1,43 @@
#!/bin/bash
name=$RANDOM
url='http://localhost:9093/api/v1/alerts'
echo "firing up alert $name"
# change url o
curl -XPOST $url -d "[{
\"status\": \"firing\",
\"labels\": {
\"alertname\": \"$name\",
\"service\": \"my-service\",
\"severity\":\"warning\",
\"instance\": \"$name.example.net\"
},
\"annotations\": {
\"summary\": \"High latency is high!\"
},
\"generatorURL\": \"http://prometheus.int.example.net/<generating_expression>\"
}]"
echo ""
echo "press enter to resolve alert"
read
echo "sending resolve"
curl -XPOST $url -d "[{
\"status\": \"resolved\",
\"labels\": {
\"alertname\": \"$name\",
\"service\": \"my-service\",
\"severity\":\"warning\",
\"instance\": \"$name.example.net\"
},
\"annotations\": {
\"summary\": \"High latency is high!\"
},
\"generatorURL\": \"http://prometheus.int.example.net/<generating_expression>\"
}]"
echo ""

7
.bin/elm-publish-private Executable file
View File

@@ -0,0 +1,7 @@
#! /usr/bin/env nix-shell
#! nix-shell -p "(import <nixpkgs> { overlays = [ (import ~/work/fysiweb/engiadina-pwa/devops/pkgs) ]; }).elm-publish-private"
#! nix-shell -i bash
set -efux
exec elm-publish-private "$@"

21
.bin/fix-sd.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/sh
set -xfu
drive="$1"
mountpoint="/media/sd-card-$(date +%s)"
backup_directory="$(pwd)"
trap clean EXIT
clean() {
umount "$mountpoint"
rmdir "$mountpoint"
fsck.exfat "$drive"
}
filenames="$(fsck.exfat "$drive" 2>&1 | sed -nE "s/.* file '(.*?)' is not allocated.*/\1/p")"
mkdir "$mountpoint"
mount "$drive" "$mountpoint"
echo "$filenames" | while read -r filename; do
find "$mountpoint" -type f -name "$filename" -exec mv {} "$backup_directory" \;
done

34
.bin/horoscope.sh Normal file
View File

@@ -0,0 +1,34 @@
#!/bin/sh
set -efu
# Berlin: -d lodeg=13 -d lomin=22 -d losec=41 -d lodir=E -d ladeg=52 -d lamin=27 -d lasec=42 -d ladir=N -d usecoords=1 \
# Kassel: -d lodeg=9 -d lomin=32 -d losec=5 -d lodir=E -d ladeg=51 -d lamin=18 -d lasec=17 -d ladir=N -d usecoords=1 \
[ $# -eq 1 ] || {
echo >&2 Usage: "$0" TIMESTAMP
exit 1
}
export TZ=UTC
chart_path="$(mktemp /tmp/chart_XXX.pdf)"
timestamp="$1"
year="$(date -d "@$timestamp" +%Y)"
month="$(date -d "@$timestamp" +%m)"
day="$(date -d "@$timestamp" +%d)"
hour="$(date -d "@$timestamp" +%H)"
minute="$(date -d "@$timestamp" +%M)"
curl -sSL 'https://edifyingfellowship.org/astro/' \
-d lodeg=9 -d lomin=32 -d losec=5 -d lodir=E -d ladeg=51 -d lamin=18 -d lasec=17 -d ladir=N -d usecoords=1 \
-d ybyr="$year" -d ybmo="$month" -d ybdy="$day" -d ybhr="$hour" -d ybmi="$minute" -d ybsc=0 -d ybtz="$TZ" \
-d currenttime=0 \
-d title="$timestamp" \
-d options[]=VancouverWheel -d options[]=Arrow -d options[]=XBold -d options[]=HouseLabels -d options[]=Placidus \
-d options[]=Sun -d options[]=Moon -d options[]=Mercury -d options[]=Venus -d options[]=Mars -d options[]=Jupiter -d options[]=Saturn -d options[]=Uranus -d options[]=Neptune -d options[]=Pluto -d options[]=Ascendant -d options[]=MC -d options[]=Lilith -d options[]=MeanNode -d options[]=TrueNode \
-d aspectpct=100 -d format=PDF -d Submit= -o "$chart_path"
zathura "$chart_path"

24
.bin/json2csv Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env python3
import csv
import json
import sys
if __name__ == "__main__":
json_list = json.load(sys.stdin)
if not isinstance(json_list, list):
print("JSON object is not a list.", file=sys.stderr)
sys.exit(1)
if len(json_list) == 0:
print("JSON list is empty.", file=sys.stderr)
sys.exit(1)
keys = set()
for element in json_list:
if isinstance(element, dict):
keys |= element.keys()
else:
print("Non-dict element:", element, file=sys.stderr)
sys.exit(1)
writer = csv.DictWriter(sys.stdout, fieldnames=list(keys))
writer.writeheader()
for element in json_list:
writer.writerow(element)

5
.bin/json2csv.jq Executable file
View File

@@ -0,0 +1,5 @@
#!/usr/bin/env -S jq -r -f
(map(keys) | add | unique) as $cols
| map(. as $row | $cols | map($row[.])) as $rows
| $cols, $rows[]
| @csv

15
.bin/libib.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
session_id=7b638c194d9bda74f80043045018cc9e
declare -A libraries
libraries["Literatur"]=344428
libraries["Sprache"]=344160
libraries["Miscellanea"]=344427
libraries["Wissenschaft"]=344429
libraries["Relicta"]=565920
for library in ${!libraries[@]}
do
curl -sSL 'https://www.libib.com/library/functions/csv-export.php' -H "Cookie: PHPSESSID=$session_id" -d export="${libraries[$library]}" > "$library.csv"
done

81
.bin/lieferando.sh Normal file
View File

@@ -0,0 +1,81 @@
#!/bin/sh
set -efu
if echo "$1" | grep -Eq '[[:digit:]]{5}'; then
PLZ="$1"
else
echo >&2 "Usage: $0 PLZ"
exit 1
fi
lieferando_dir=/tmp/lieferando
mkdir -p "$lieferando_dir/$PLZ"
fetch_restaurants() {
cache_path="$lieferando_dir/$PLZ.json"
if [ -r "$cache_path" ]; then
cat "$cache_path"
else
w3m -dump_source "http://www.lieferando.de/$PLZ" \
| gunzip \
| sed -n '/var restaurants/,/];$/p' \
| sed 's/var restaurants =//;$s/;$//' \
| prettier --parser=json \
| jq '
map({
name: .[30] | .name,
category: .[30] |.categories | split(", "),
url: "http://lieferando.de\(.[30] | .url)",
minutes: .[19],
minimum: .[10],
delivery: .[14]
})' \
| tee "$cache_path"
fi
}
fetch_menu() {
[ $# -eq 1 ] || exit 1
slug="$(echo "$1" | sed 's!.*/!!')"
cache_path="$lieferando_dir/$PLZ/$slug.json"
if [ -r "$cache_path" ]; then
cat "$cache_path"
else
w3m -dump_source "$1" \
| gunzip \
| sed -n '/var MenucardProducts/,/\];/p' \
| sed 's/var MenucardProducts =//;s/;$//' \
| jq -r '
unique_by(.productId)
| group_by(.categoryId)
| flatten
' \
| tee "$cache_path"
fi
}
data="$(fetch_restaurants)"
# echo "$data" | jq -c '.[]' | while read -r restaurant; do
# fetch_menu "$(echo "$restaurant" | jq -r .url)"
# done
selected_categories="$(echo "$data" | jq -r 'map(.category) | flatten | unique | .[]' | fzf -m)"
selected_restaurant_url="$(echo "$selected_categories" | jq --argjson restaurants "$data" -sRr '
split("\n")[:-1] as $categories
| $restaurants[]
| select(.category - $categories != .category)
| "\(.name) [🚴\(.minutes)min 💰\(.minimum)€ + \(.delivery)€] (\(.url))"
' \
| fzf \
| sed 's/.*(//;s/)$//'
)"
fetch_menu "$selected_restaurant_url" \
| jq -r '.[] | "\(.price)\t\(.name)"' \
| fzf -m \
| awk '{print $0; sum += $1} END {print "-----"; print sum}'

17
.bin/lit.awk Normal file
View File

@@ -0,0 +1,17 @@
BEGIN {
if (!comment) comment = "--";
if (!begin) begin = "\\begin{code}";
if (!end) end = "\\end{code}";
}
{
if ($0 == begin) {
code = 1;
print comment, $0;
} else if ($0 == end) {
code = 0;
print comment, $0;
} else {
if (code) print $0;
else print comment, $0;
}
}

2
.bin/load.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
uptime | sed 's/.*load average: \(.*\), \(.*\), \(.*\)/\1 \2 \3/'

3
.bin/mail-current-part Executable file
View File

@@ -0,0 +1,3 @@
#! /bin/sh
set -efu
exec curl -fSs --unix-socket /tmp/much.api.sock http://localhost/current/part

View File

@@ -0,0 +1,27 @@
#! /bin/sh
# usage: mail-current-query-find-part-by-name NAME
set -efu
name=$1
query=$(mail-current-query)
result=$(notmuch show --entire-thread=false --format=json "$query")
part_id=$(printf %s "$result" | jq --arg name "$name" '
[
recurse |
select(type == "object") |
{ id, name: .filename } |
select(.id != null and .name != null)
] |
map(select(.name == $name))[0].id
')
if test "$part_id" = null; then
printf 'error: could not find part with name %s\n' \
"$name" \
>&2
exit 1
fi
exec notmuch show --part="$part_id" "$query"

View File

@@ -0,0 +1,39 @@
#! /bin/sh
# usage: mail-current-query-find-part-by-type TYPE
set -efu
type=$1
query=$(mail-current-query)
result=$(notmuch show --entire-thread=false --format=json "$query")
part_id=$(printf %s "$result" | jq --arg type "$type" '
#flatten|map(select(.!=null))[0].body[0] |
#
#if .["content-type"] == $type then
# .id
#elif .["content-type"] | test("^multipart/") then
# .content|map(select(.["content-type"]==$type))[0].id
#else
# null
#end
[
recurse |
select(type == "object") |
{ id, type: .["content-type"] } |
select(.id != null and .type != null)
] |
map(select(.type == $type))[0].id
')
if test "$part_id" = null; then
printf 'error: could not find part with type %s\n' \
"$type" \
>&2
exit 1
fi
exec notmuch show --part="$part_id" "$query"

117
.bin/mp3player-write Executable file
View File

@@ -0,0 +1,117 @@
#!/usr/bin/env bash
# Usage:
# ./mp3_transfer.sh -s 1.3 /mnt/mp3player file1.m4a file2.m4a ...
set -e
# Default speed
SPEED=1.0
# Parse options
while getopts ":s:" opt; do
case $opt in
s)
SPEED=$OPTARG
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires a value." >&2
exit 1
;;
esac
done
# Shift past the options
shift $((OPTIND -1))
# Check arguments
if [ "$#" -lt 2 ]; then
echo "Usage: $0 [-s speed] MOUNT_POINT FILE1 [FILE2 ...]"
exit 1
fi
MOUNT_POINT=$1
shift
FILES=("$@")
# Check mount point exists
if [ ! -d "$MOUNT_POINT" ]; then
echo "Error: Mount point '$MOUNT_POINT' does not exist."
exit 1
fi
# Estimate required space
TOTAL_SIZE=0
for f in "${FILES[@]}"; do
if [ ! -f "$f" ]; then
echo "Warning: File '$f' does not exist, skipping."
continue
fi
# Get file size in bytes
FILE_SIZE=$(stat --printf="%s" "$f")
# Estimate mp3 output size: roughly 1/2 of original m4a (adjust if needed)
TOTAL_SIZE=$((TOTAL_SIZE + FILE_SIZE / 2))
done
# Get available space in bytes
AVAILABLE=$(df --output=avail "$MOUNT_POINT" | tail -n 1)
AVAILABLE=$((AVAILABLE * 1024)) # df reports in KB
if [ "$TOTAL_SIZE" -gt "$AVAILABLE" ]; then
echo "Error: Not enough space on device. Required: $TOTAL_SIZE bytes, Available: $AVAILABLE bytes"
exit 1
fi
echo "Enough space available. Starting conversion..."
sanitize_filename() {
local name="$1"
# Remove path, keep only base name
name=$(basename "$name")
# Remove any extension
name=${name%.*}
# Replace spaces and special chars with underscore
name=$(echo "$name" | tr ' ' '_' | tr -cd '[:alnum:]_-')
# Truncate to max 50 chars
echo "${name:0:50}"
}
# Convert and copy files
for f in "${FILES[@]}"; do
if [ ! -f "$f" ]; then
continue
fi
# Determine the next prefix
existing_prefixes=$(ls "$MOUNT_POINT" | grep -E '^[0-9].*\.mp3$' | sed -E 's/^([0-9]).*/\1/' | sort -n | uniq)
for i in {0..9}; do
if ! echo "$existing_prefixes" | grep -q "^$i$"; then
PREFIX=$i
break
fi
done
echo "Using prefix: $PREFIX"
BASENAME=$(sanitize_filename "$f")
OUT_PATTERN="$MOUNT_POINT/${PREFIX}_%03d_${BASENAME}.mp3"
echo "Converting '$f' to '$OUT_PATTERN' at speed $SPEED..."
ffmpeg -nostdin -i "$f" \
-filter:a "atempo=$SPEED" \
-ar 22050 -ac 1 -c:a libmp3lame -b:a 32k \
-f segment -segment_time 300 \
"$OUT_PATTERN"
# Update prefix for next file
# Count how many segments were created
SEG_COUNT=$(ls "$MOUNT_POINT" | grep -E "^${PREFIX}[0-9]{2}_" | wc -l)
PREFIX=$((PREFIX + SEG_COUNT))
done
echo "All files processed successfully."

1
.bin/mud.sh Executable file
View File

@@ -0,0 +1 @@
ssh mud@hotdog.r -t "MUD_NICKNAME=$LOGNAME mud"

6
.bin/mushakkil.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh
curl -sSL 'https://diac.alsharekh.org/Diac/DiacText' \
-H "Content-Type: application/json" \
--data-raw "$(jq --raw-input '{word: ., type: 1}')" \
--compressed \
| jq -r .diacWord

93
.bin/nix-haddock-index Executable file
View File

@@ -0,0 +1,93 @@
#! /usr/bin/env nix-shell
#! nix-shell -i bash -p coreutils gnugrep gnused graphviz
#
# usage: nix-haddock-index
#
# Run this script in an environment where either NIX_GHC is set, or the ghc
# executable exists, to generate an HTML index file pointing to all Haddock
# files accessible to the respective ghc version.
#
# Additionally, an SVG dependency graph of all packages is linked at the
# bottom of the index file.
#
# Note: all files will be generated in /tmp, and won't be deleted automatically
#
set -efux
if test -z "${NIX_GHC-}"; then
NIX_GHC=$(readlink -f "$(type -P ghc)")
fi
if ! echo $NIX_GHC | grep -q '^/nix/store/'; then
printf '%s: error: unsupported GHC executable path (not in Nix store): %q\n' \
"$0" \
"$NIX_GHC" \
>&2
exit -1
fi
NIX_GHC_PREFIX=$(dirname "$(dirname "$NIX_GHC")")
NIX_GHC_DOCDIR=$NIX_GHC_PREFIX/share/doc/ghc/html
main() {
hash=$(echo $NIX_GHC_PREFIX | sed -n 's|^/nix/store/\([a-z0-9]\+\).*|\1|p')
title="Haddock index for $NIX_GHC_PREFIX"
header=$(
printf 'Haddock index for <a href="%s">%s</a>\n' \
$NIX_GHC_PREFIX \
$NIX_GHC_PREFIX \
)
suffix=${hash:+-$hash}
index_file=/tmp/haddock$suffix-index.html
svg_file=/tmp/haddock$suffix.svg
#if ! test -e $index_file; then
eval "$(
echo 'gen_index() {'
echo ' html_head'
"$NIX_GHC_PREFIX"/bin/ghc-pkg dump | sed -n '
s/^---$/ reset/p
s/^\(name\|version\):\s*\([-A-Za-z0-9_.]\+\)$/ \1=\2/p
s/^haddock-html:\s*\([-A-Za-z0-9_./]\+\)$/ haddock_html \1/p
'
echo ' html_foot'
echo '}'
)"
gen_index > $index_file
#fi
#if ! test -e $svg_file; then
"$NIX_GHC_PREFIX"/bin/ghc-pkg dot | tred | dot -Tsvg | sed '
s/<svg width="[0-9]\+pt" height="[0-9]\+pt"/<svg width="3600px" height="100%"/
' > $svg_file
#fi
echo $index_file
}
reset() {
unset name version
}
haddock_html() {
printf '<li>'
printf '<a href="%s/index.html">%s</a>' "$1" "$name-$version"
printf '</li>\n'
}
html_head() {
printf '<!doctype html>\n'
printf '<title>%s</title>\n' "$title"
printf '<link href="%s" rel="stylesheet" type="text/css">\n' \
"$NIX_GHC_DOCDIR/libraries/ocean.css"
printf '<h1>%s</h1>\n' "$header"
printf '<ul>\n'
}
html_foot() {
printf '</ul>\n'
printf '<a href="%s">graph</a>\n' "$svg_file"
}
main "$@"

15
.bin/notetags.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/sh
# inspired by https://github.com/connermcd/bin/blob/1d38cb98812906d8b95dc6e51e1149e29261617d/notetags
cd "$HOME/notes/" || exit
[ -f tags ] && rm tags
grep -r 'tags:' ./* | while read -r line; do
file=$(echo "$line" | cut -d: -f1)
unparsed_tags=$(echo "$line" | cut -d: -f3) #
tags=$(echo "$unparsed_tags" | sed -e 's/tags: *//g' -e 's/[][,]//g')
for tag in $tags; do
echo "$tag $file /^$unparsed_tags$/;" >> tags
done
done

23
.bin/pdf-ocr.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env nix-shell
#! nix-shell -i bash -p poppler_utils tesseract4
set -eu
pdf_path="$(realpath "$1")"
[ -f "$pdf_path" ] || {
echo "Usage: $0 FILE.pdf" >&2
exit 1
}
tmpdir="$(mktemp -d)"
trap 'rm -rf $tmpdir' EXIT
cd "$tmpdir"
pdftoppm -png "$pdf_path" pdf-ocr
for png in pdf-ocr*.png; do
tesseract "$png" "$png.txt" 2>/dev/null
done
cat pdf-ocr-*.txt

2
.bin/playlist_entries.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
youtube-dl -ij "$*" | jq -sr '.[] | .webpage_url'

65
.bin/prospekte.sh Executable file
View File

@@ -0,0 +1,65 @@
#!/bin/sh
lidl() {
echo LIDL
curl -sSL 'https://endpoints.lidl-flyer.com/v3/region-overview/lidl/de-DE/0.json' \
| jq -r '
.categories
| map(select(.name == "Filial-Angebote") | .subcategories | map(.flyers))
| flatten
| flatten
| .[]
| .pdfUrl
'
}
aldi_nord() {
echo ALDI nord
echo 'https://magazine.aldi-nord.de/aldi-nord/aldi-aktuell/GetPDF.ashx'
echo 'https://magazine.aldi-nord.de/aldi-nord/aldi-vorschau/GetPDF.ashx'
}
rewe_berlin() {(
store_id=662366923
publisher_id=1062
echo REWE
curl -sSL 'https://www.bonialserviceswidget.de/de/stores/'$store_id'/brochures?storeId='$store_id'&publisherId='$publisher_id | while read -r brochure_id; do
curl -sSL 'https://www.bonialserviceswidget.de/de/v5/brochureDetails/'"$brochure_id"'?publisherId='$publisher_id | jq -r .pdfUrl
done
)}
kaufland() {(
region_code=8920
echo KAUFLAND
curl -sSL https://filiale.kaufland.de/prospekte.html | htmlq --attribute href '.flyer a' | grep -Eo 'DE_de_KDZ[^/]*' | sed "s/_3000_/_${region_code}_/" | while read -r flyer_id; do
curl -sSL "https://endpoints.leaflets.kaufland.com/v3/$flyer_id/flyer.json?regionCode=$region_code" | jq -r .flyer.pdfUrl
done
)}
netto_schwarz() {
echo 'NETTO (schwarz)'
curl -sSL 'https://squid-api.tjek.com/v2/catalogs?dealer_ids=90f2VL&order_by=created' \
| jq -r '.[] | .id' \
| while read -r flyer_id; do
curl -sSL "https://squid-api.tjek.com/v2/catalogs/$flyer_id/download" \
| jq -r .pdf_url
done
}
dir="$(mktemp -d)"
trap clean EXIT
clean() {
rm -rf "$dir"
}
prospekt_url="$( (
lidl
aldi_nord
rewe_berlin
kaufland
netto_schwarz
) | fzf)"
curl -sSL "$prospekt_url" -o "$dir/prospekt.pdf"
zathura "$dir/prospekt.pdf"

17
.bin/proxies.sh Normal file
View File

@@ -0,0 +1,17 @@
#!/bin/sh
curl -sSL https://www.netzwelt.de/proxy/index.html \
| pup ".tblc" \
| xml-to-json /dev/stdin \
| jq '
.div.table.tbody.tr
| map(
.td
| {
ip: .[0].a.value,
port: .[1],
country: .[2] | (if type == "string" then . else .a.value end),
security: .[3],
protocol: .[4]
}
)
'

4
.bin/readme Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/sh
curl -sSL "https://raw.githubusercontent.com/$*/master/README.md" \
| pandoc -f gfm -t man -s \
| man -l -

6
.bin/sample-pdf.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh
filepath="$(shuf --head-count=1)"
pages="$(pdfinfo "$filepath" | awk '/^Pages:/{print $2}')"
random_page="$(shuf --input-range="1-$pages" --head-count=1)"
zathura --page="$random_page" "$filepath"

16
.bin/screencap.sh Executable file
View File

@@ -0,0 +1,16 @@
#! /usr/bin/env nix-shell
#! nix-shell -i sh -p coreutils byzanz xorg.xwininfo gnused
# shellcheck shell=sh
# ref https://gist.github.com/aforemny/0994cb7f06ea30d56c8b9681ff5d2054
set -eux
eval "$(xwininfo | \
sed -n -e 's/^ \+Absolute upper-left X: \+\([0-9]\+\).*/x=\1/p' \
-e 's/^ \+Absolute upper-left Y: \+\([0-9]\+\).*/y=\1/p' \
-e 's/^ \+Width: \+\([0-9]\+\).*/w=\1/p' \
-e 's/^ \+Height: \+\([0-9]\+\).*/h=\1/p')"
trap "pkill -f 'sleep 360d'" INT
byzanz-record -e "sleep 360d" -c -x $x -y $y -w $w -h $h "$@"

49
.bin/space.py Normal file
View File

@@ -0,0 +1,49 @@
import ephem
from datetime import datetime, date, timedelta
now = datetime.now()
limit = now + timedelta(days=365)
def events_until(limit):
initial_date = ephem.Date(datetime.now())
events = {}
now = initial_date
while ephem.localtime(now) <= limit:
now = ephem.next_full_moon(now)
events[now] = "🌕"
now = initial_date
while ephem.localtime(now) <= limit:
now = ephem.next_new_moon(now)
events[now] = "🌑"
now = initial_date
while ephem.localtime(now) <= limit:
now = ephem.next_vernal_equinox(now)
events[now] = "spring equinox"
now = initial_date
while ephem.localtime(now) <= limit:
now = ephem.next_autumnal_equinox(now)
events[now] = "fall equinox"
now = initial_date
while ephem.localtime(now) <= limit:
now = ephem.next_winter_solstice(now)
events[now] = "winter solstice"
now = initial_date
while ephem.localtime(now) <= limit:
now = ephem.next_summer_solstice(now)
events[now] = "summer solstice"
return events
events = events_until(limit)
for date, event in sorted(events.items(), key=lambda x: x[0]):
if ephem.localtime(date) < limit:
print(ephem.localtime(date), event)

81
.bin/toposort.nix Normal file
View File

@@ -0,0 +1,81 @@
let
lib = import <nixpkgs/lib>;
in
rec {
inherit lib;
input = [
{
x = [
"pool"
"zfs"
];
y = [
"mdadm"
"raid1"
];
}
{
x = [
"pool"
"zfs"
];
y = [
"disk"
"sda"
];
}
{
x = [
"mdadm"
"raid1"
];
y = [
"disk"
"sdb"
];
}
{
x = [
"mdadm"
"raid1"
];
y = [
"disk"
"sdc"
];
}
];
outNodes = node: graph: lib.unique (builtins.map (e: e.y) (builtins.filter (v: v.x == node) graph));
vertices = graph: lib.unique (builtins.map (x: x.y) graph ++ builtins.map (x: x.x) graph);
deleteVertex = node: graph: (builtins.filter (v: v.x != node && v.y != node) graph);
findSink =
graph:
lib.findFirst (v: outNodes v graph == [ ]) (lib.trace graph (builtins.abort "No sink found")) (
vertices graph
);
topSort =
graph:
if graph == [ ] then
[ ]
else if builtins.length graph == 1 then
let
only = builtins.head graph;
in
[
only.y
only.x
]
else
let
sink = findSink graph;
in
[ sink ] ++ topSort (deleteVertex sink graph);
output = topSort input;
}

18
.bin/ttrss-unread Executable file
View File

@@ -0,0 +1,18 @@
#/usr/bin/env -S deno run -A:q
set -x
session_cache="$HOME/.cache/tt-rss.session"
ttrss_endpoint=https://feed.kmein.de/api/
ttrss_user=k
ttrss_password=$(pass shared/tt-rss/password)
login() {
if [ -f "$session_cache" ]; then
session_id="$(cat "$session_cache")"
else
session_id="$(curl -d '{"op":"login","user":"'"$ttrss_user"'","password":"'"$ttrss_password"'"}' "$ttrss_endpoint" | jq -r .content.session_id)"
echo "$session_id" > "$session_cache"
fi
}
login
curl -d '{"sid":"'"$session_id"'","op":"getUnread"}' "$ttrss_endpoint" | jq .content

16
.bin/tuesday-1800 Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
set -efux
expected_max_results=1024 # the upper bound on the number of restaurants
radius=250
echo '[out:json];node(id:260050809)->.cbase;
(
node(around.cbase:'$radius')[amenity=fast_food];
node(around.cbase:'$radius')[amenity=restaurant];
);out;' \
| curl -sSL -d @- -X POST http://overpass-api.de/api/interpreter \
| jq --argjson random "$(shuf -i 0-$expected_max_results -n 1)" '
.elements
| length as $length
| .[$random % $length]
'

8
.bin/unicode Normal file
View File

@@ -0,0 +1,8 @@
import sys
import unicodedata
for index, character in enumerate(sys.stdin.read().strip()):
try:
print(index, character, hex(ord(character)), unicodedata.category(character), unicodedata.name(character))
except:
print(index, character, hex(ord(character)))

26
.bin/watson2fdf.sh Executable file
View File

@@ -0,0 +1,26 @@
project=Filli
year=2022
for month in Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec; do
from="$(date +%F -d "$month 1, $year")"
to="$(date +%F -d "$month 1, $year + 1 month")"
watson report --json --from "$from" --to "$to" --project "$project"
done | jq --slurp '
def in_array($arr):
. as $value | any($arr[]; . == $value);
map(
["engadin-app","fysiweb","val-muestair","mia-engiadina","ol"] as $official_projects
| (.timespan.from | .[0:7]) as $timespan
| .projects | .[0]
| .time as $total_time
| .tags
| select(. != null)
| map(select(.name | in_array($official_projects)))
| (map(.time)|add) as $official_time
| map({key:.name, value:.time}) | from_entries
| .other |= ($total_time - $official_time)
| map_values(. / (60*60) | ceil)
| .month |= $timespan
)
'

View File

@@ -1,96 +0,0 @@
# niveum — Agent Notes
## What This Is
A NixOS flake managing ~9 machines (desktops, servers, family laptops) for one user (kmein/kfm).
Levantine food-themed hostnames: fatteh, kabsa, kibbeh, makanek, manakish, tabula, tahina, zaatar, ful.
## Repository Structure
```
flake.nix # ~670 lines — inputs, overlay, nixosConfigurations, apps, packages output
configs/ # ~50 NixOS config fragments imported by systems
default.nix # 200+ line mega-module for desktop machines (user, shell, gnupg, i18n, etc.)
graphical/ # Hyprland + home-manager config (415 lines in home-manager.nix)
packages.nix # ~250 lines of environment.systemPackages
bots/ # Telegram/Mastodon/Matrix bot configs
keyboard/ # XKB layouts (Coptic, Avestan, Gothic, etc.)
configs/*.nix # Individual concerns: bluetooth, sound, printing, ssh, fonts, etc.
modules/ # Proper NixOS modules with options (retiolum, telegram-bot, passport, power-action, etc.)
packages/ # ~107 package files (scripts, wrappers, small tools)
systems/<name>/ # Per-machine: configuration.nix + hardware-configuration.nix + extras
lib/ # default.nix (niveum helpers), machines.nix (IP/key inventory), panoptikon.nix
secrets/ # agenix-encrypted .age files (empty dir in checkout, tracked via secrets.txt)
```
## Key Relationships
- **niphas** (input): Provides shared "how I like things" config — nixosModules (shell, editor, git, desktop, nix, udiskie) and overlay (niphas-* packages). Used in `profiles.default` and `profiles.desktop`.
- **configs/default.nix**: The "big desktop profile" — imported by fatteh, kabsa, manakish (the main desktop machines). NOT imported by servers or family laptops.
- **profiles** (in flake.nix): `profiles.default`, `profiles.desktop`, `profiles.server` — lists of modules composed per machine.
- **lib.niveum**: Custom lib injected via overlay (`pkgs.lib.niveum`) — used everywhere for machine addresses, SSH port, helper functions.
## Coding Conventions
- Packages use `writers.writeDashBin`, `writers.writeBashBin`, or `writers.writePython3Bin`
- Dependencies are referenced via `lib.getExe pkg` (main executable) or `lib.getExe' pkg "name"` (specific binary)
- For packages needing many commands via PATH, use `lib.makeBinPath` instead (see `packages/prospekte.nix`)
- Overlay entries use `prev.callPackage packages/foo.nix { }` pattern
- Packages are exported via `inherit (pkgs) ...` in the `packages` output
## Known Bugs / Broken References
All previously broken references have been fixed (see commits `36132b04`, `e67d6d7d`).
Remaining issues:
- `modules/retiolum.nix` uses `<retiolum/hosts>` and `<system-secrets/...>` NIX_PATH lookups — breaks flake purity but works with current `NIX_PATH` setup
## Architectural Issues
### 1. configs/default.nix is a grab-bag (200+ lines, ~15 inline anonymous modules)
It's a list of `imports` mixing inline `{ ... }` blocks with file imports. Hard to find what's defined where.
### 2. Retiolum secret boilerplate repeated 9 times
Every system has a near-identical block:
```nix
age.secrets.retiolum-rsa = { file = ../../secrets/${hostname}-retiolum-privateKey-rsa.age; mode = "400"; owner = "tinc-retiolum"; ... };
age.secrets.retiolum-ed25519 = { ... same ... };
```
Could be a function or module parameterized by hostname.
### 3. Nginx + ACME boilerplate duplicated
ful and makanek have identical nginx recommended settings + ACME config.
### 4. niveum-* overlay aliases
`niveum-terminal`, `niveum-browser`, `niveum-filemanager` are aliases to niphas equivalents. Could be removed by updating ~6 references in configs/ to use niphas-* names directly.
### 5. The `pkgs.lib.niveum` pattern
Custom lib injected via overlay into `pkgs.lib`. Unconventional — only available where overlay is applied. A `specialArgs` approach or standalone lib would be cleaner.
### 6. Restic backup config scattered
`services.restic.backups.niveum` is configured in configs/backup.nix, configs/applicative.nix, and extended in 5+ system files. Hard to see what a given machine backs up.
### 7. configs/ vs modules/ distinction blurry
`configs/` has both stateless config fragments (spacetime.nix = timezone) and stateful ones (backup.nix, cloud.nix). `modules/` has proper option-declaring modules. Some configs/ files import from modules/.
## Machines Overview
| Machine | Role | Profile | Arch | Notes |
|-----------|--------------|------------------|---------|---------------------------------------|
| fatteh | Desktop | default+desktop | x86_64 | ThinkPad T480, CUDA, main daily |
| kabsa | Desktop | default+desktop | x86_64 | ThinkPad X220, constrained (2 jobs) |
| manakish | Desktop | default+desktop | x86_64 | ThinkPad X230 |
| kibbeh | Desktop | default+desktop | x86_64 | Pantheon DE, travel laptop |
| ful | Server | default+server | aarch64 | Oracle/Hetzner, nginx, web services |
| makanek | Server | default+server | x86_64 | Hetzner, gitea, nextcloud, weechat |
| zaatar | Server/Home | default+server | x86_64 | Home assistant, backup server |
| tabula | Family laptop| default | x86_64 | LXQt, user "xenos" |
| tahina | Family laptop| default | x86_64 | Pantheon, user "xenos", German |
## Remaining Improvement Ideas
1. **Extract retiolum secret boilerplate** into a function/module
2. **Break up configs/default.nix** into proper named files
3. **Extract nginx+ACME server profile**
4. **Replace niveum-* aliases** with direct niphas-* references
5. **Fix modules/retiolum.nix** NIX_PATH usage for flake purity

View File

@@ -91,7 +91,7 @@
imap.host = mailhost;
imap.port = 993;
smtp.host = mailhost;
smtp.port = 587;
smtp.port = 25;
smtp.tls.useStartTls = true;
};
ical-ephemeris =

10
configs/bash.nix Normal file
View File

@@ -0,0 +1,10 @@
{ pkgs, ... }:
{
programs.bash = {
promptInit = ''PS1="$(${pkgs.ncurses}/bin/tput bold)\w \$([[ \$? == 0 ]] && echo \"\[\033[1;32m\]\" || echo \"\[\033[1;31m\]\")\$$(${pkgs.ncurses}/bin/tput sgr0) "'';
interactiveShellInit = ''
set -o vi
'';
completion.enable = true;
};
}

View File

@@ -69,7 +69,7 @@ in
wantedBy = [ "multi-user.target" ];
description = "Telegram reverse bot";
path = [ pkgs.ffmpeg ];
enable = false;
enable = true;
script = ''
TELEGRAM_BOT_TOKEN="$(cat "$CREDENTIALS_DIRECTORY/token")" ${pkgs.telebots}/bin/telegram-reverse
'';
@@ -81,7 +81,7 @@ in
systemd.services.telegram-streaming-link = {
wantedBy = [ "multi-user.target" ];
description = "Telegram bot converting YouTube Music <-> Spotify";
enable = false;
enable = true;
script = ''
TELEGRAM_BOT_TOKEN="$(cat "$CREDENTIALS_DIRECTORY/token")" ${pkgs.telebots}/bin/telegram-streaming-link
'';
@@ -92,7 +92,7 @@ in
systemd.services.telegram-betacode = {
wantedBy = [ "multi-user.target" ];
description = "Telegram beta code bot";
enable = false;
enable = true;
script = ''
TELEGRAM_BOT_TOKEN="$(cat "$CREDENTIALS_DIRECTORY/token")" ${pkgs.telebots}/bin/telegram-betacode
'';
@@ -103,7 +103,7 @@ in
systemd.services.telegram-proverb = {
wantedBy = [ "multi-user.target" ];
description = "Telegram proverb bot";
enable = false;
enable = true;
script = ''
TELEGRAM_BOT_TOKEN="$(cat "$CREDENTIALS_DIRECTORY/token")" ${pkgs.telebots}/bin/telegram-proverb
'';

View File

@@ -16,6 +16,9 @@ in
nixpkgs = {
config = {
allowUnfree = true;
packageOverrides = pkgs: {
dmenu = pkgs.writers.writeDashBin "dmenu" ''exec ${pkgs.rofi}/bin/rofi -dmenu "$@"'';
};
permittedInsecurePackages = [
];
};
@@ -66,8 +69,6 @@ in
extraGroups = [
"pipewire"
"audio"
"lp"
"scanner"
];
};
@@ -88,7 +89,7 @@ in
{
sxiv = swallow "${pkgs.nsxiv}/bin/nsxiv";
zathura = swallow "${pkgs.zathura}/bin/zathura";
im = "${pkgs.openssh}/bin/ssh weechat@makanek -t screen -x weechat";
im = "${pkgs.openssh}/bin/ssh weechat@makanek -t tmux attach-session -t IM";
yt = "${pkgs.yt-dlp}/bin/yt-dlp --add-metadata -ic"; # Download video link
yta = "${pkgs.yt-dlp}/bin/yt-dlp --add-metadata --audio-format mp3 --audio-quality 0 -xic"; # Download with audio
};
@@ -152,7 +153,7 @@ in
dconf.enable = true;
dconf.settings = {
# Change the default terminal for Nemo
"org/cinnamon/desktop/applications/terminal".exec = lib.getExe pkgs.niphas-terminal;
"org/cinnamon/desktop/applications/terminal".exec = lib.getExe pkgs.niveum-terminal;
};
};
}

42
configs/direnv.nix Normal file
View File

@@ -0,0 +1,42 @@
{ pkgs, ... }:
let
nixify = pkgs.writers.writeDashBin "nixify" ''
set -efuC
if [ ! -e ./.envrc ]; then
echo use_nix > .envrc
direnv allow
fi
if [ ! -e shell.nix ]; then
cat > shell.nix <<'EOF'
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
packages = [];
}
EOF
''${EDITOR:-vim} shell.nix
fi
'';
in
{
environment.systemPackages = [
pkgs.direnv
nixify
];
home-manager.users.me.programs.direnv = {
enable = true;
stdlib = builtins.readFile "${
pkgs.fetchFromGitHub {
owner = "Mic92";
repo = "dotfiles";
rev = "a0a9b7e358fa70a85cd468f8ca1fbb02ae0a91df";
sha256 = "1y9h5s1lf59sczsm0ksq2x1yhl98ba9lwk5yil3q53rg7n4574pg";
}
}/home/.direnvrc";
};
programs.zsh.interactiveShellInit = ''
eval "$(${pkgs.direnv}/bin/direnv hook zsh)"
'';
}

View File

@@ -38,6 +38,7 @@
pkgs.pyright
pkgs.haskellPackages.haskell-language-server
pkgs.texlab
pkgs.nil
pkgs.gopls
pkgs.nixfmt-rfc-style
pkgs.rust-analyzer

View File

@@ -35,8 +35,10 @@
pkgs.xdg-desktop-portal-hyprland
];
services.getty.autologinOnce = true;
services.getty.autologinUser = config.users.users.me.name;
services.getty.autologinOnce = {
enable = true;
user = config.users.users.me.name;
};
home-manager.users.me = import ./home-manager.nix {
inherit lib pkgs config;

View File

@@ -265,9 +265,9 @@ in
exec-once = [
(lib.getExe pkgs.ashell)
"hyprctl dispatch exec \"[workspace special:${language.obsidian} silent] obsidian\""
(lib.getExe pkgs.niphas-clipboard-watcher)
(lib.getExe pkgs.niphas-redshift)
(lib.getExe pkgs.niphas-set-wallpaper)
"${lib.getExe' pkgs.wl-clipboard "wl-paste"} -t text --watch ${lib.getExe pkgs.clipman} store"
(lib.getExe pkgs.hyprsunset)
(lib.getExe pkgs.hyprpaper)
];
device = [
@@ -341,7 +341,7 @@ in
",XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"
",XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+"
",XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%-"
", Print, exec, ${lib.getExe pkgs.niphas-screenshot}"
", Print, exec, ${lib.getExe pkgs.niphas-screenshot} -m region --clipboard-only"
];
bindl = [
", XF86AudioNext, exec, playerctl next"
@@ -350,12 +350,12 @@ in
", XF86AudioPrev, exec, playerctl previous"
];
bind = [
"${mod}, Return, exec, ${lib.getExe pkgs.niphas-terminal}"
"${mod}, Return, exec, ${lib.getExe pkgs.niveum-terminal}"
"${mod} SHIFT, Q, killactive,"
"${mod} SHIFT, R, exit,"
"${mod}, t, exec, ${lib.getExe pkgs.niphas-file-browser}"
"${mod}, Y, exec, ${lib.getExe pkgs.niphas-web-browser}"
"${mod}, Q, exec, ${lib.getExe pkgs.niphas-clipman}"
"${mod}, t, exec, ${lib.getExe pkgs.niveum-filemanager}"
"${mod}, Y, exec, ${lib.getExe pkgs.niveum-browser}"
"${mod}, Q, exec, ${lib.getExe pkgs.clipman} pick --tool=rofi"
"${mod}, u, exec, ${lib.getExe pkgs.unicodmenu}"
"${mod}, p, exec, ${lib.getExe pkgs.rofi-pass-wayland}"
"${mod} SHIFT, Z, togglefloating,"

View File

@@ -4,6 +4,7 @@
}:
let
ledgerDirectory = "/home/kfm/sync/src/ledger";
hora = pkgs.callPackage ../packages/hora.nix { timeLedger = "${ledgerDirectory}/time.timeclock"; };
in
{
environment.systemPackages =
@@ -11,6 +12,7 @@ in
git = "${pkgs.git}/bin/git -C ${ledgerDirectory}";
in
[
hora
pkgs.hledger
(pkgs.writers.writeDashBin "hledger-git" ''
if [ "$1" = entry ]; then

View File

@@ -243,9 +243,9 @@ in
"${modifier}+w" = "layout tabbed";
"${modifier}+q" = "exec ${config.services.clipmenu.package}/bin/clipmenu";
"${modifier}+Return" = "exec ${lib.getExe pkgs.niphas-terminal}";
"${modifier}+t" = "exec ${lib.getExe pkgs.niphas-file-browser}";
"${modifier}+y" = "exec ${lib.getExe pkgs.niphas-web-browser}";
"${modifier}+Return" = "exec ${lib.getExe pkgs.niveum-terminal}";
"${modifier}+t" = "exec ${lib.getExe pkgs.niveum-filemanager}";
"${modifier}+y" = "exec ${lib.getExe pkgs.niveum-browser}";
"${modifier}+d" =
"exec ${pkgs.writers.writeDash "run" ''exec rofi -modi run,ssh,window -show run''}";

View File

@@ -70,16 +70,23 @@ in
GPODDER_DOWNLOAD_DIR=${config.users.users.me.home}/mobile/audio/Text/podcasts exec ${pkgs.gpodder}/bin/gpodder "$@"
'')
# INTERNET
aria2
telegram-desktop
whois
dnsutils
# FILE MANAGERS
lf
pcmanfm
# MEDIA
ffmpeg
simplescreenrecorder
imagemagick
exiftool
nsxiv
graphviz
# SHELL
bat # better cat
dos2unix
genpass # generate passwords
(pkgs.writers.writeDashBin "genpassphrase" ''${pkgs.genpass}/bin/genpass "$@" --passphrase | ${pkgs.gnused}/bin/sed 's/ /-/g;s/\(^\|-\)\([a-z]\)/\1\U\2/g;s/$/-'$(${pkgs.coreutils}/bin/date +%Y)'/' '')
gcc
@@ -87,10 +94,16 @@ in
pup # html toolkit
xan # csv toolkit
magic-wormhole-rs # file transfer
man-pages
man-pages-posix
exfat # to mount windows drives
# HARDWARE TOOLS
gnome-disk-utility
arandr # xrandr for noobs
wdisplays
libnotify # for notify-send
wl-clipboard # clipboard CLI
dragon-drop # drag and drop
portfolio # personal finance overview
audacity
calibre
@@ -129,7 +142,6 @@ in
polyglot
qrpaste
ttspaste
pi # llm agent
new-mac # get a new mac address
scanned
default-gateway
@@ -242,6 +254,10 @@ in
# proselint
asciidoctor
wordnet
tokei # count lines of code
gnumake
binutils # for strip, ld, ...
# nightly.rust
shellcheck
# photography

View File

@@ -26,7 +26,7 @@ in
openFirewall = true;
};
# users.users.me.extraGroups is set in configs/default.nix which defines the "me" user
users.users.me.extraGroups = [ "lp" "scanner" ];
hardware.printers.ensurePrinters = [
{

279
flake.lock generated
View File

@@ -12,11 +12,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1770165109,
"narHash": "sha256-9VnK6Oqai65puVJ4WYtCTvlJeXxMzAp/69HhQuTdl/I=",
"lastModified": 1762618334,
"narHash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ=",
"owner": "ryantm",
"repo": "agenix",
"rev": "b027ee29d959fda4b60b57566d64c98a202e0feb",
"rev": "fcdea223397448d35d9b31f798479227e80183f6",
"type": "github"
},
"original": {
@@ -113,28 +113,6 @@
"type": "github"
}
},
"blueprint": {
"inputs": {
"nixpkgs": [
"llm-agents",
"nixpkgs"
],
"systems": "systems_2"
},
"locked": {
"lastModified": 1771437256,
"narHash": "sha256-bLqwib+rtyBRRVBWhMuBXPCL/OThfokA+j6+uH7jDGU=",
"owner": "numtide",
"repo": "blueprint",
"rev": "06ee7190dc2620ea98af9eb225aa9627b68b0e33",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "blueprint",
"type": "github"
}
},
"buildbot-nix": {
"inputs": {
"flake-parts": "flake-parts_3",
@@ -143,7 +121,7 @@
"stockholm",
"nixpkgs"
],
"treefmt-nix": "treefmt-nix_3"
"treefmt-nix": "treefmt-nix_2"
},
"locked": {
"lastModified": 1768927382,
@@ -189,11 +167,11 @@
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
"lastModified": 1772261909,
"narHash": "sha256-8XbJXrhMFhLgoBrjFIJx5XJi+SD+7/gbvaIXCuqy9Z0=",
"lastModified": 1769842381,
"narHash": "sha256-0dPzo1ElvAIZ0RwEwx5FfqAUiFj22K9QJOU9stiMCrw=",
"owner": "nix-community",
"repo": "fenix",
"rev": "e4c413b9546d6c9e6426b33b4d6de1a49a375024",
"rev": "b2344f384a82db1410ab09769eb8c4a820de667f",
"type": "github"
},
"original": {
@@ -384,11 +362,11 @@
]
},
"locked": {
"lastModified": 1772302941,
"narHash": "sha256-TL3+ckbOTILXrR0qSK3dJj2BJ0S5yz/YSsUF1oEgd9g=",
"lastModified": 1769580047,
"narHash": "sha256-tNqCP/+2+peAXXQ2V8RwsBkenlfWMERb+Uy6xmevyhM=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "9b9142b5fe214c2adabe86257c33e022372b7c96",
"rev": "366d78c2856de6ab3411c15c1cb4fb4c2bf5c826",
"type": "github"
},
"original": {
@@ -398,26 +376,6 @@
"type": "github"
}
},
"llm-agents": {
"inputs": {
"blueprint": "blueprint",
"nixpkgs": "nixpkgs",
"treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1772328903,
"narHash": "sha256-1f5WHVW5jwO0TEBZNIK3GkgkwTqBaUFrNCf0WQ4/sM8=",
"owner": "numtide",
"repo": "llm-agents.nix",
"rev": "45656c46d998310ea6306a0036d581bf77091213",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "llm-agents.nix",
"type": "github"
}
},
"menstruation-backend": {
"inputs": {
"fenix": [
@@ -492,15 +450,15 @@
"nixpkgs": [
"nixpkgs-unstable"
],
"treefmt-nix": "treefmt-nix_2",
"treefmt-nix": "treefmt-nix",
"wrappers": "wrappers"
},
"locked": {
"lastModified": 1771601908,
"narHash": "sha256-lqscsSHms5xk8iOOEj0J6XtrIcZp7/TXN4iiQjNeXzM=",
"lastModified": 1770756688,
"narHash": "sha256-raCwOTt5xT7J1ysxdGrmBva6OVrvjf47EgVLi5B5R5o=",
"ref": "refs/heads/master",
"rev": "13ee868d5d297fbcfa1370cfff67e5c7f5e3d0aa",
"revCount": 42,
"rev": "86bf2150a7cabd225149f35c0ff57576af6ded44",
"revCount": 38,
"type": "git",
"url": "https://code.kmein.de/kfm/niphas"
},
@@ -516,11 +474,11 @@
]
},
"locked": {
"lastModified": 1771734689,
"narHash": "sha256-/phvMgr1yutyAMjKnZlxkVplzxHiz60i4rc+gKzpwhg=",
"lastModified": 1765267181,
"narHash": "sha256-d3NBA9zEtBu2JFMnTBqWj7Tmi7R5OikoU2ycrdhQEws=",
"owner": "nix-community",
"repo": "nix-index-database",
"rev": "8f590b832326ab9699444f3a48240595954a4b10",
"rev": "82befcf7dc77c909b0f2a09f5da910ec95c5b78f",
"type": "github"
},
"original": {
@@ -537,11 +495,11 @@
]
},
"locked": {
"lastModified": 1771963727,
"narHash": "sha256-gFyFAFYYoNsvd6heI0XtDMIa4pnykjwDljS7dQm45uE=",
"lastModified": 1769018862,
"narHash": "sha256-x3eMpPQhZwEDunyaUos084Hx41XwYTi2uHY4Yc4YNlk=",
"owner": "oddlama",
"repo": "nix-topology",
"rev": "b493b9b970388d79129ce1a92a6b060c9305386f",
"rev": "a15cac71d3399a4c2d1a3482ae62040a3a0aa07f",
"type": "github"
},
"original": {
@@ -574,11 +532,11 @@
},
"nixos-hardware": {
"locked": {
"lastModified": 1771969195,
"narHash": "sha256-qwcDBtrRvJbrrnv1lf/pREQi8t2hWZxVAyeMo7/E9sw=",
"lastModified": 1769302137,
"narHash": "sha256-QEDtctEkOsbx8nlFh4yqPEOtr4tif6KTqWwJ37IM2ds=",
"owner": "NixOS",
"repo": "nixos-hardware",
"rev": "41c6b421bdc301b2624486e11905c9af7b8ec68e",
"rev": "a351494b0e35fd7c0b7a1aae82f0afddf4907aa8",
"type": "github"
},
"original": {
@@ -589,16 +547,16 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1771423170,
"narHash": "sha256-K7Dg9TQ0mOcAtWTO/FX/FaprtWQ8BmEXTpLIaNRhEwU=",
"lastModified": 1769598131,
"narHash": "sha256-e7VO/kGLgRMbWtpBqdWl0uFg8Y2XWFMdz0uUJvlML8o=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "bcc4a9d9533c033d806a46b37dc444f9b0da49dd",
"rev": "fa83fd837f3098e3e678e6cf017b2b36102c7211",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"ref": "nixos-25.11",
"repo": "nixpkgs",
"type": "github"
}
@@ -636,43 +594,11 @@
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1772198003,
"narHash": "sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE=",
"lastModified": 1770197578,
"narHash": "sha256-AYqlWrX09+HvGs8zM6ebZ1pwUqjkfpnv8mewYwAo+iM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "dd9b079222d43e1943b6ebd802f04fd959dc8e61",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1772047000,
"narHash": "sha256-7DaQVv4R97cii/Qdfy4tmDZMB2xxtyIvNGSwXBBhSmo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1267bb4920d0fc06ea916734c11b0bf004bbe17e",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-25.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1771369470,
"narHash": "sha256-0NBlEBKkN3lufyvFegY4TYv5mCNHbi5OmBDrzihbBMQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "0182a361324364ae3f436a63005877674cf45efb",
"rev": "00c21e4c93d963c50d4c0c89bfa84ed6e0694df2",
"type": "github"
},
"original": {
@@ -690,11 +616,11 @@
]
},
"locked": {
"lastModified": 1772326810,
"narHash": "sha256-lqwxrCp2ZgAjlYRKbT+bkvXmxZSibCyB3ee96HwLV34=",
"lastModified": 1769867112,
"narHash": "sha256-n3YYhO6VpGadtVOiL/eAxnm9JBC6GfXsJfj8O6V/JvU=",
"owner": "nix-community",
"repo": "NUR",
"rev": "7bf299ddf8a26872aa45acc49a4424bd17237072",
"rev": "c74b53b75a4219cdecea1194a95e36a222981860",
"type": "github"
},
"original": {
@@ -728,47 +654,6 @@
"type": "github"
}
},
"opencrow": {
"inputs": {
"nixpkgs": [
"nixpkgs"
],
"treefmt-nix": [
"treefmt-nix"
]
},
"locked": {
"lastModified": 1772243521,
"narHash": "sha256-Fi0zLX0hGm2eAQJ0d0FTb2y+KuCcM8zjkzkEyZB4fUI=",
"owner": "pinpox",
"repo": "opencrow",
"rev": "bb555b7796ec1842e0295462736ee7a956abc676",
"type": "github"
},
"original": {
"owner": "pinpox",
"repo": "opencrow",
"type": "github"
}
},
"panoptikon": {
"inputs": {
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1771688635,
"narHash": "sha256-tKmjgdeoQV5W96Chr2B5WOFXC70FvcfxhNCmBT1YZUY=",
"ref": "refs/heads/main",
"rev": "30e15d8f95693ba82d2d93ef9acbc1ceb65ef430",
"revCount": 4,
"type": "git",
"url": "https://code.kmein.de/kfm/panoptikon"
},
"original": {
"type": "git",
"url": "https://code.kmein.de/kfm/panoptikon"
}
},
"retiolum": {
"locked": {
"lastModified": 1756302470,
@@ -790,7 +675,6 @@
"autorenkalender": "autorenkalender",
"fenix": "fenix",
"home-manager": "home-manager",
"llm-agents": "llm-agents",
"menstruation-backend": "menstruation-backend",
"menstruation-telegram": "menstruation-telegram",
"naersk": "naersk",
@@ -798,20 +682,19 @@
"nix-index-database": "nix-index-database",
"nix-topology": "nix-topology",
"nixos-hardware": "nixos-hardware",
"nixpkgs": "nixpkgs_2",
"nixpkgs": "nixpkgs",
"nixpkgs-old": "nixpkgs-old",
"nixpkgs-unstable": "nixpkgs-unstable",
"nur": "nur",
"opencrow": "opencrow",
"panoptikon": "panoptikon",
"retiolum": "retiolum",
"scripts": "scripts",
"stockholm": "stockholm",
"stylix": "stylix",
"telebots": "telebots",
"tinc-graph": "tinc-graph",
"treefmt-nix": "treefmt-nix_4",
"treefmt-nix": "treefmt-nix_3",
"voidrice": "voidrice",
"wallpapers": "wallpapers",
"wetter": "wetter",
"wrappers": "wrappers_2"
}
@@ -819,11 +702,11 @@
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1772178959,
"narHash": "sha256-DkjUvrEnnhHjOcjMx6aXfYGIZ0PWmcYzvVayhRj1r4M=",
"lastModified": 1769786006,
"narHash": "sha256-ax6cH54Nc20QuxlHNC8RMt1P8quMECY4gaACFAdd5ec=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "8494a8b3b769c17e8594d811012cc1b0fab090c7",
"rev": "eb0588812b041ebbf2645555f2a4df3bcd853c6d",
"type": "github"
},
"original": {
@@ -868,11 +751,11 @@
]
},
"locked": {
"lastModified": 1771846963,
"narHash": "sha256-1srlGKTtf0a2nfH78MohqNtkcvLSuEIEVccPD4WJCZk=",
"lastModified": 1769038106,
"narHash": "sha256-k558r83lvHbqDlEFEf3zCX1/WuMNgnp1bjMbwMhg5wM=",
"owner": "krebs",
"repo": "stockholm",
"rev": "bab362d0f6fcde28ac41716ca15cc552d4659ec5",
"rev": "0122ded2137e568e771e753c0c3a17b1b20d9ca7",
"type": "github"
},
"original": {
@@ -894,7 +777,7 @@
"nixpkgs"
],
"nur": "nur_2",
"systems": "systems_3",
"systems": "systems_2",
"tinted-foot": "tinted-foot",
"tinted-kitty": "tinted-kitty",
"tinted-schemes": "tinted-schemes",
@@ -902,11 +785,11 @@
"tinted-zed": "tinted-zed"
},
"locked": {
"lastModified": 1771788390,
"narHash": "sha256-RzBpBwn93GWxLjacTte+ngwwg0L/BVOg4G/sSIeK3Rw=",
"lastModified": 1769829895,
"narHash": "sha256-J2jDCqzdtUxKVstC/zwy4TaSYgUxyzInGZ1qU7W2LaE=",
"owner": "danth",
"repo": "stylix",
"rev": "ebb238f14d6f930068be4718472da3105fd5d3bf",
"rev": "413e927522d65ca8a37b283f4e88ada4865971dd",
"type": "github"
},
"original": {
@@ -946,21 +829,6 @@
"type": "github"
}
},
"systems_3": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"telebots": {
"inputs": {
"nixpkgs": [
@@ -1089,27 +957,6 @@
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": [
"llm-agents",
"nixpkgs"
]
},
"locked": {
"lastModified": 1770228511,
"narHash": "sha256-wQ6NJSuFqAEmIg2VMnLdCnUc0b7vslUohqqGGD+Fyxk=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "337a4fe074be1042a35086f15481d763b8ddc0e7",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
},
"treefmt-nix_2": {
"inputs": {
"nixpkgs": [
"niphas",
@@ -1130,7 +977,7 @@
"type": "github"
}
},
"treefmt-nix_3": {
"treefmt-nix_2": {
"inputs": {
"nixpkgs": [
"stockholm",
@@ -1152,18 +999,18 @@
"type": "github"
}
},
"treefmt-nix_4": {
"treefmt-nix_3": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1770228511,
"narHash": "sha256-wQ6NJSuFqAEmIg2VMnLdCnUc0b7vslUohqqGGD+Fyxk=",
"lastModified": 1769691507,
"narHash": "sha256-8aAYwyVzSSwIhP2glDhw/G0i5+wOrren3v6WmxkVonM=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "337a4fe074be1042a35086f15481d763b8ddc0e7",
"rev": "28b19c5844cc6e2257801d43f2772a4b4c050a1b",
"type": "github"
},
"original": {
@@ -1188,6 +1035,22 @@
"type": "github"
}
},
"wallpapers": {
"flake": false,
"locked": {
"lastModified": 1589319718,
"narHash": "sha256-2NruGq3z37vY3uAH8S4sLqHvFAGi8gaDJAgEzMIvM/4=",
"owner": "kmein",
"repo": "wallpapers",
"rev": "7c553bc6bd78afa6dbf2824691466bbad0d8e6e9",
"type": "github"
},
"original": {
"owner": "kmein",
"repo": "wallpapers",
"type": "github"
}
},
"wetter": {
"inputs": {
"nixpkgs": [
@@ -1236,11 +1099,11 @@
]
},
"locked": {
"lastModified": 1772137435,
"narHash": "sha256-dqkfxxpIiIs4wdWhT4lfQi1lfA0CgIftPiYGvw0tUOk=",
"lastModified": 1770311206,
"narHash": "sha256-gzTvuaJZaymgxQC4rOZ9HlMRRWHVF2moEEaTnCG556A=",
"owner": "lassulus",
"repo": "wrappers",
"rev": "4e12f430ae705d9bbb591ca9c51cbccbee050a23",
"rev": "241f2f7dfcac0dbb2338105bdba7f03f412c5847",
"type": "github"
},
"original": {

View File

@@ -2,6 +2,8 @@
description = "niveum: packages, modules, systems";
inputs = {
self.submodules = true;
agenix.url = "github:ryantm/agenix";
autorenkalender.url = "github:kmein/autorenkalender";
home-manager.url = "github:nix-community/home-manager/release-25.11";
@@ -12,7 +14,6 @@
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
niphas.url = "git+https://code.kmein.de/kfm/niphas";
panoptikon.url = "git+https://code.kmein.de/kfm/panoptikon";
nixos-hardware.url = "github:NixOS/nixos-hardware";
nur.url = "github:nix-community/NUR";
retiolum.url = "github:krebs/retiolum";
@@ -23,13 +24,13 @@
tinc-graph.url = "github:kmein/tinc-graph";
treefmt-nix.url = "github:numtide/treefmt-nix";
voidrice.url = "github:Lukesmithxyz/voidrice";
wallpapers.url = "github:kmein/wallpapers";
nix-topology.url = "github:oddlama/nix-topology";
wetter.url = "github:4z3/wetter";
wrappers.url = "github:lassulus/wrappers";
llm-agents.url = "github:numtide/llm-agents.nix";
opencrow.url = "github:pinpox/opencrow";
voidrice.flake = false;
wallpapers.flake = false;
naersk.url = "github:nix-community/naersk";
fenix.url = "github:nix-community/fenix";
@@ -47,8 +48,6 @@
agenix.inputs.home-manager.follows = "home-manager";
opencrow.inputs.treefmt-nix.follows = "treefmt-nix";
agenix.inputs.nixpkgs.follows = "nixpkgs";
autorenkalender.inputs.nixpkgs.follows = "nixpkgs";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
@@ -66,7 +65,6 @@
wetter.inputs.nixpkgs.follows = "nixpkgs";
niphas.inputs.nixpkgs.follows = "nixpkgs-unstable";
wrappers.inputs.nixpkgs.follows = "nixpkgs";
opencrow.inputs.nixpkgs.follows = "nixpkgs";
};
outputs =
@@ -82,8 +80,6 @@
scripts,
tinc-graph,
nix-topology,
llm-agents,
opencrow,
nixpkgs-unstable,
nixos-hardware,
niphas,
@@ -91,7 +87,6 @@
autorenkalender,
telebots,
stockholm,
panoptikon,
nix-index-database,
stylix,
voidrice,
@@ -173,7 +168,7 @@
${pkgs.nixos-rebuild-ng}/bin/nixos-rebuild-ng switch \
--max-jobs 2 \
--log-format internal-json \
--flake .?submodules=1#${hostname} \
--flake .#${hostname} \
--use-substitutes \
--target-host "$target" \
${lib.optionalString (localSystem != machines.${hostname}.system) "--build-host $target"} \
@@ -195,29 +190,19 @@
nixosModules = {
moodle-dl = import modules/moodle-dl.nix;
passport = import modules/passport.nix;
panoptikon = import modules/panoptikon.nix;
power-action = import modules/power-action.nix;
system-dependent = import modules/system-dependent.nix;
telegram-bot = import modules/telegram-bot.nix;
go-webring = import modules/go-webring.nix;
zsh-kmein = import config/zsh.nix;
};
overlays.default = final: prev: {
# packaged from .bin/
two56color = prev.callPackage packages/256color.nix { };
avesta = prev.callPackage packages/avesta.nix { };
bvg = prev.callPackage packages/bvg.nix { };
charinfo = prev.callPackage packages/charinfo.nix { };
chunk-pdf = prev.callPackage packages/chunk-pdf.nix { };
csv2json = prev.callPackage packages/csv2json.nix { };
fix-sd = prev.callPackage packages/fix-sd.nix { };
json2csv = prev.callPackage packages/json2csv.nix { };
mp3player-write = prev.callPackage packages/mp3player-write.nix { };
mushakkil = prev.callPackage packages/mushakkil.nix { };
nix-haddock-index = prev.callPackage packages/nix-haddock-index.nix { };
pdf-ocr = prev.callPackage packages/pdf-ocr.nix { };
prospekte = prev.callPackage packages/prospekte.nix { };
readme = prev.callPackage packages/readme.nix { };
niveum-terminal = prev.alacritty;
niveum-browser = prev.firefox;
niveum-filemanager = prev.pcmanfm;
ashell = nixpkgs-unstable.legacyPackages.${prev.system}.ashell;
@@ -266,7 +251,6 @@
morris = prev.callPackage packages/morris.nix { };
cro = prev.callPackage packages/cro.nix { };
exodus = prev.callPackage packages/exodus.nix { };
picoclaw = prev.callPackage packages/picoclaw.nix { };
dmenu = prev.writers.writeDashBin "dmenu" ''exec ${final.rofi}/bin/rofi -dmenu "$@"'';
weechatScripts = prev.weechatScripts // {
hotlist2extern = prev.callPackage packages/weechatScripts/hotlist2extern.nix { }; # TODO upstream
@@ -287,7 +271,6 @@
};
# packaged from inputs
opencrow = opencrow.packages.${prev.stdenv.hostPlatform.system}.opencrow;
wetter = wetter.packages.${prev.stdenv.hostPlatform.system}.wetter;
agenix = agenix.packages.${prev.stdenv.hostPlatform.system}.default;
pun-sort-api = scripts.packages.${prev.stdenv.hostPlatform.system}.pun-sort-api;
@@ -297,7 +280,6 @@
menstruation-backend =
menstruation-backend.packages.${prev.stdenv.hostPlatform.system}.menstruation-backend;
telebots = telebots.packages.${prev.stdenv.hostPlatform.system}.telebots;
pi-llm = llm-agents.packages.${prev.stdenv.hostPlatform.system}.pi;
hesychius = scripts.packages.${prev.stdenv.hostPlatform.system}.hesychius;
autorenkalender = autorenkalender.packages.${prev.stdenv.hostPlatform.system}.default;
onomap = scripts.packages.${prev.stdenv.hostPlatform.system}.onomap;
@@ -311,7 +293,6 @@
radio-news = prev.callPackage packages/radio-news { };
untilport = prev.callPackage packages/untilport.nix { };
weechat-declarative = prev.callPackage packages/weechat-declarative.nix { };
pi = prev.callPackage packages/pi.nix { };
# my packages
betacode = prev.callPackage packages/betacode.nix { };
@@ -362,6 +343,7 @@
unicodmenu = prev.callPackage packages/unicodmenu.nix { };
vg = prev.callPackage packages/vg.nix { };
vim-kmein = prev.callPackage packages/vim-kmein { };
vimv = prev.callPackage packages/vimv.nix { };
klem = prev.callPackage packages/klem.nix { };
yt-dlp-master = prev.callPackage packages/yt-dlp-master.nix { };
@@ -370,6 +352,10 @@
inherit lib;
pkgs = final;
};
panoptikon = import lib/panoptikon.nix {
inherit lib;
pkgs = final;
};
};
};
@@ -381,7 +367,6 @@
nixpkgs.overlays = [
self.overlays.default
niphas.overlays.default
panoptikon.overlays.default
(final: prev: {
niphas-git =
(prev.niphas-git.passthru.configuration.apply {
@@ -446,17 +431,11 @@
++ profiles.server
++ [
systems/ful/configuration.nix
panoptikon.nixosModules.default
self.nixosModules.panoptikon
self.nixosModules.go-webring
stockholm.nixosModules.reaktor2
opencrow.nixosModules.default
nur.modules.nixos.default
{
nixpkgs.overlays = [
stockholm.overlays.default
llm-agents.overlays.default
];
}
{ nixpkgs.overlays = [ stockholm.overlays.default ]; }
];
};
zaatar = nixpkgs.lib.nixosSystem {
@@ -566,20 +545,14 @@
];
};
inherit (pkgs)
two56color
avesta
auc
betacode
booksplit
brainmelter
brassica
bvg
charinfo
cheat-sh
chunk-pdf
closest
cro
csv2json
cyberlocker-tools
dawn-editor
default-gateway
@@ -590,7 +563,6 @@
emailmenu
exodus
fkill
fix-sd
fzfmenu
gfs-fonts
bring-out-the-gimp
@@ -601,7 +573,6 @@
image-convert-tolino
ipa
jsesh
json2csv
kirciuoklis
klem
kpaste
@@ -610,31 +581,23 @@
mansplain
manual-sort
morris
mp3player-write
mpv-iptv
mpv-radio
mpv-tuner
mpv-tv
mushakkil
new-mac
niveum-ssh
nix-git
nix-haddock-index
noise-waves
notemenu
obsidian-vim
opustags
pdf-ocr
pi
picoclaw
pls
polyglot
prospekte
q
qrpaste
radio-news
random-zeno
readme
rfc
scanned
stag
@@ -652,6 +615,7 @@
vim-kmein
vim-typewriter
vim-email
vimv
weechat-declarative
wttr
yt-dlp-master
@@ -659,9 +623,4 @@
}
);
};
nixConfig = {
extra-substituters = [ "https://cache.numtide.com" ];
extra-trusted-public-keys = [ "niks3.numtide.com-1:DTx8wZduET09hRmMtKdQDxNNthLQETkc/yaX7M4qK0g=" ];
};
}

47
lib/panoptikon.nix Normal file
View File

@@ -0,0 +1,47 @@
{
pkgs,
lib,
...
}:
{
# watcher scripts
url =
address:
pkgs.writers.writeDash "watch-url" ''
${pkgs.curl}/bin/curl -sSL ${lib.escapeShellArg address} \
| ${pkgs.python3Packages.html2text}/bin/html2text --decode-errors=ignore
'';
urlSelector =
selector: address:
pkgs.writers.writeDash "watch-url-selector" ''
${pkgs.curl}/bin/curl -sSL ${lib.escapeShellArg address} \
| ${pkgs.htmlq}/bin/htmlq ${lib.escapeShellArg selector} \
| ${pkgs.python3Packages.html2text}/bin/html2text
'';
urlJSON =
{
jqScript ? ".",
}:
address:
pkgs.writers.writeDash "watch-url-json" ''
${pkgs.curl}/bin/curl -sSL ${lib.escapeShellArg address} | ${pkgs.jq}/bin/jq -f ${pkgs.writeText "script.jq" jqScript}
'';
# reporter scripts
kpaste-irc =
{
target,
retiolumLink ? false,
server ? "irc.r",
messagePrefix ? "change detected: ",
nick ? ''"$PANOPTIKON_WATCHER"-watcher'',
}:
pkgs.writers.writeDash "kpaste-irc-reporter" ''
KPASTE_CONTENT_TYPE=text/plain ${pkgs.kpaste}/bin/kpaste \
| ${pkgs.gnused}/bin/sed -n "${if retiolumLink then "2" else "3"}s/^/${messagePrefix}/p" \
| ${pkgs.nur.repos.mic92.ircsink}/bin/ircsink \
--nick ${nick} \
--server ${server} \
--target ${target}
'';
}

123
modules/panoptikon.nix Normal file
View File

@@ -0,0 +1,123 @@
{
config,
lib,
pkgs,
...
}:
{
options.services.panoptikon = {
enable = lib.mkEnableOption "Generic command output / website watcher";
watchers = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule (watcher: {
options = {
script = lib.mkOption {
type = lib.types.path;
description = ''
A script whose stdout is to be watched.
'';
example = ''
pkgs.writers.writeDash "github-meta" '''
''${pkgs.curl}/bin/curl -sSL https://api.github.com/meta | ''${pkgs.jq}/bin/jq
'''
'';
};
frequency = lib.mkOption {
type = lib.types.str;
description = ''
How often to run the script. See systemd.time(7) for more information about the format.
'';
example = "*:0/3";
default = "daily";
};
loadCredential = lib.mkOption {
type = lib.types.listOf lib.types.str;
description = ''
This can be used to pass secrets to the systemd service without adding them to the nix store.
'';
default = [ ];
};
reporters = lib.mkOption {
type = lib.types.listOf lib.types.path;
description = ''
A list of scripts that take the diff (if any) via stdin and report it (e.g. to IRC, Telegram or Prometheus). The name of the watcher will be in the $PANOPTIKON_WATCHER environment variable.
'';
example = ''
[
(pkgs.writers.writeDash "telegram-reporter" '''
''${pkgs.curl}/bin/curl -X POST https://api.telegram.org/bot''${TOKEN}/sendMessage \
-d chat_id=123456 \
-d text="$(cat)"
''')
(pkgs.writers.writeDash "notify" '''
''${pkgs.libnotify}/bin/notify-send "$PANOPTIKON_WATCHER has changed."
''')
]
'';
};
};
config = { };
})
);
};
};
config =
let
cfg = config.services.panoptikon;
in
lib.mkIf cfg.enable {
users.extraUsers.panoptikon = {
isSystemUser = true;
createHome = true;
home = "/var/lib/panoptikon";
group = "panoptikon";
};
users.extraGroups.panoptikon = { };
systemd.timers = lib.attrsets.mapAttrs' (
watcherName: _:
lib.nameValuePair "panoptikon-${watcherName}" {
timerConfig.RandomizedDelaySec = toString (60 * 60);
}
) cfg.watchers;
systemd.services = lib.attrsets.mapAttrs' (
watcherName: watcherOptions:
lib.nameValuePair "panoptikon-${watcherName}" {
enable = true;
startAt = watcherOptions.frequency;
serviceConfig = {
Type = "oneshot";
User = "panoptikon";
Group = "panoptikon";
WorkingDirectory = "/var/lib/panoptikon";
RestartSec = toString (60 * 60);
Restart = "on-failure";
LoadCredential = watcherOptions.loadCredential;
};
unitConfig = {
StartLimitIntervalSec = "300";
StartLimitBurst = "5";
};
environment.PANOPTIKON_WATCHER = watcherName;
wants = [ "network-online.target" ];
script = ''
set -fux
${watcherOptions.script} > ${lib.escapeShellArg watcherName}
diff_output=$(${pkgs.diffutils}/bin/diff --new-file ${
lib.escapeShellArg (watcherName + ".old")
} ${lib.escapeShellArg watcherName} || :)
if [ -n "$diff_output" ]
then
${lib.strings.concatMapStringsSep "\n" (
reporter: ''echo "$diff_output" | ${reporter} || :''
) watcherOptions.reporters}
fi
mv ${lib.escapeShellArg watcherName} ${lib.escapeShellArg (watcherName + ".old")}
'';
}
) cfg.watchers;
};
}

73
modules/retiolum.nix Normal file
View File

@@ -0,0 +1,73 @@
{
config,
pkgs,
lib,
...
}:
with lib;
let
netname = "retiolum";
cfg = config.networking.retiolum;
in
{
options = {
networking.retiolum.ipv4 = mkOption {
type = types.str;
description = ''
own ipv4 address
'';
};
networking.retiolum.ipv6 = mkOption {
type = types.str;
description = ''
own ipv6 address
'';
};
networking.retiolum.nodename = mkOption {
type = types.str;
default = config.networking.hostName;
description = ''
tinc network name
'';
};
};
config = {
services.tinc.networks.${netname} = {
name = cfg.nodename;
hosts = builtins.mapAttrs (name: _: builtins.readFile "${<retiolum/hosts>}/${name}") (
builtins.readDir <retiolum/hosts>
);
rsaPrivateKeyFile = toString <system-secrets/retiolum.key>;
ed25519PrivateKeyFile = toString <system-secrets/retiolum.ed25519>;
extraConfig = ''
LocalDiscovery = yes
AutoConnect = yes
'';
};
networking.extraHosts = builtins.readFile (toString <retiolum/etc.hosts>);
environment.systemPackages = [ config.services.tinc.networks.${netname}.package ];
networking.firewall = {
allowedTCPPorts = [ 655 ];
allowedUDPPorts = [ 655 ];
};
#services.netdata.portcheck.checks.tinc.port = 655;
systemd.network = {
enable = true;
networks = {
"${netname}".extraConfig = ''
[Match]
Name = tinc.${netname}
[Network]
Address=${cfg.ipv4}/12
Address=${cfg.ipv6}/16
'';
};
};
};
}

View File

@@ -1,37 +0,0 @@
{
writers,
}:
writers.writeDashBin "256color" ''
pl() {
for i in $(seq $1 $(expr $2 - 1)); do
printf '\e[38;5;%sm%03i\e[m ' $i $i
done
printf '\e[38;5;%sm%03i\e[m\n' $2 $2
}
p() {
printf '\e[38;5;%sm%03i\e[m ' $1 $1
}
p6x6() {
for i in $(seq 0 5); do
for j in $(seq 0 5); do
p $(expr $1 + $i + $j \* 6)
done
echo
done
}
pl 0 7
pl 8 15
p6x6 16
p6x6 52
p6x6 88
p6x6 124
p6x6 160
p6x6 196
pl 232 243
pl 244 255
''

View File

@@ -1,66 +0,0 @@
# Transliterate Latin-script Avestan to Avestan Unicode script
{
lib,
writers,
gnused,
}:
let
sedScript = builtins.toFile "avesta.sed" ''
s/ā̊/𐬃/g
s/t̰/𐬝/g
s/̌/𐬴/g
s/š́/𐬳/g
s/ą̄/𐬅/g
s/ŋ/𐬤/g
s/ə̄/𐬇/g
s/ŋ́/𐬣/g
s/x́/𐬒/g
s/x/𐬓/g
s/a/𐬀/g
s/ā/𐬁/g
s/å/𐬂/g
s/ą/𐬄/g
s/ə/𐬆/g
s/e/𐬈/g
s/ē/𐬉/g
s/o/𐬊/g
s/ō/𐬋/g
s/i/𐬌/g
s/ī/𐬍/g
s/u/𐬎/g
s/ū/𐬏/g
s/k/𐬐/g
s/x/𐬑/g
s/g/𐬔/g
s/ġ/𐬕/g
s/γ/𐬖/g
s/c/𐬗/g
s/j/𐬘/g
s/t/𐬙/g
s/θ/𐬚/g
s/d/𐬛/g
s/δ/𐬜/g
s/p/𐬞/g
s/f/𐬟/g
s/b/𐬠/g
s/β/𐬡/g
s/ŋ/𐬢/g
s/n/𐬥/g
s/ń/𐬦/g
s//𐬧/g
s/m/𐬨/g
s/m̨/𐬩/g
s//𐬫/g
s/y/𐬪/g
s/v/𐬬/g
s/r/𐬭/g
s/s/𐬯/g
s/z/𐬰/g
s/š/𐬱/g
s/ž/𐬲/g
s/h/𐬵/g
'';
in
writers.writeDashBin "avesta" ''
exec ${lib.getExe gnused} -f ${sedScript} "$@"
''

View File

@@ -1,52 +0,0 @@
# Berlin BVG transit disruption checker
{
lib,
writers,
curl,
jq,
}:
writers.writeDashBin "bvg" ''
${lib.getExe curl} -sSL 'https://www.bvg.de/disruption-reports/q' \
--data-raw '{"variables":{},"query":"{
allDisruptions {
disruptions {
meldungsId
linie
verkehrsmittel
__typename
... on Traffic {
datum
gueltigVonDatum
gueltigVonZeit
gueltigBisDatum
gueltigBisZeit
richtungName
richtungHafasId
beginnAbschnittName
beginnAbschnittHafasId
endeAbschnittName
endeAbschnittHafasId
textIntUrsache
sev
textIntAuswirkung
umfahrung
textWAPSMSUrsache
textWAPSMSAuswirkung
prioritaet
__typename
}
}
__typename
}
}"}' \
| ${lib.getExe jq} --arg interesting "$interesting" '
.data.allDisruptions.disruptions
| map(select(
(.linie as $linie
| $interesting
| split(" ")
| index($linie))
and (.["__typename"] == "Traffic")
))
'
''

View File

@@ -1,17 +0,0 @@
# Print Unicode character info for each character on stdin
{
writers,
python3,
}:
writers.writePython3Bin "charinfo" {
flakeIgnore = [ "E501" "E722" ];
} ''
import sys
import unicodedata
for index, character in enumerate(sys.stdin.read().strip()):
try:
print(index, character, hex(ord(character)), unicodedata.category(character), unicodedata.name(character))
except Exception:
print(index, character, hex(ord(character)))
''

View File

@@ -1,31 +0,0 @@
# Split a PDF into chunks of N pages
{
lib,
writers,
pdftk,
gnugrep,
coreutils,
}:
writers.writeDashBin "chunk-pdf" ''
set -efu
INPUT_FILE="''${2:?Pass the PDF path as second argument.}"
PAGES_PER_REPORT="''${1:?Pass the chunk size as first argument.}"
if [ ! -f "$INPUT_FILE" ]; then
echo >&2 "File $INPUT_FILE does not exist."
exit 1
fi
TOTAL_PAGES="$(${lib.getExe pdftk} "$INPUT_FILE" dump_data | ${lib.getExe gnugrep} NumberOfPages | ${lib.getExe' coreutils "cut"} -f2 -d' ')"
RUNS=$((TOTAL_PAGES/PAGES_PER_REPORT))
for run in $(${lib.getExe' coreutils "seq"} 0 "$((RUNS-1))"); do
start_page=$((run*PAGES_PER_REPORT+1))
end_page=$(((run+1)*PAGES_PER_REPORT))
output_file="chunk_$((run+1)).pdf"
echo "splitting $INPUT_FILE from $start_page to $end_page into $output_file"
${lib.getExe pdftk} "$INPUT_FILE" cat "$start_page-$end_page" output "$output_file"
done
''

View File

@@ -1,21 +0,0 @@
# Convert CSV to JSON
{
writers,
python3,
}:
writers.writePython3Bin "csv2json" {
flakeIgnore = [ "E501" ];
} ''
import csv
import json
import sys
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--delimiter", "-d", default=",", help="CSV field separator")
args = parser.parse_args()
if __name__ == "__main__":
json.dump(list(csv.DictReader(sys.stdin, delimiter=args.delimiter)), sys.stdout)
''

View File

@@ -1,35 +0,0 @@
# Recover files from a corrupted exFAT SD card
{
lib,
writers,
exfatprogs,
util-linux,
coreutils,
findutils,
gnused,
}:
writers.writeDashBin "fix-sd" ''
set -efu
drive="''${1:?Usage: fix-sd /dev/sdX [output-dir]}"
output_dir="''${2:-$(${lib.getExe' coreutils "mktemp"} -d "''${TMPDIR:-/tmp}/fix-sd-XXXXXX")}"
mountpoint="$(${lib.getExe' coreutils "mktemp"} -d "''${TMPDIR:-/tmp}/fix-sd-mount-XXXXXX")"
trap clean EXIT
clean() {
${lib.getExe' util-linux "umount"} "$mountpoint" 2>/dev/null || true
${lib.getExe' coreutils "rmdir"} "$mountpoint" 2>/dev/null || true
}
filenames="$(${lib.getExe' exfatprogs "fsck.exfat"} "$drive" 2>&1 | ${lib.getExe gnused} -nE "s/.* file '(.*?)' is not allocated.*/\1/p")"
${lib.getExe' coreutils "mkdir"} -p "$mountpoint" "$output_dir"
${lib.getExe' util-linux "mount"} "$drive" "$mountpoint"
echo "$filenames" | while read -r filename; do
[ -n "$filename" ] || continue
${lib.getExe' findutils "find"} "$mountpoint" -type f -name "$filename" -exec ${lib.getExe' coreutils "cp"} {} "$output_dir" \;
done
echo "Recovered files saved to $output_dir"
${lib.getExe' exfatprogs "fsck.exfat"} "$drive"
''

15
packages/gpt.nix Normal file
View File

@@ -0,0 +1,15 @@
{
curl,
writers,
jq,
apiKeyCommand ? "pass api-keys/openai.com",
model ? "gpt-3.5-turbo",
}:
writers.writeDashBin "gpt" ''
json=$(jq --slurp --raw-input '{model:"${model}", messages: [{role: "user", content: .}]}')
${curl}/bin/curl -sSL https://api.openai.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $(${apiKeyCommand})" \
-d "$json" \
| ${jq}/bin/jq -r '.choices[] | .message.content'
''

81
packages/hora.nix Normal file
View File

@@ -0,0 +1,81 @@
{
symlinkJoin,
hledger,
writers,
lib,
git,
coreutils,
gnugrep,
timeLedger,
...
}:
let
date = "${coreutils}/bin/date +'%Y-%m-%d %H:%M:%S'";
hora = writers.writeDashBin "hora" "${hledger}/bin/hledger -f ${lib.escapeShellArg timeLedger} \"$@\"";
hora-edit = writers.writeDashBin "hora-edit" "$EDITOR ${lib.escapeShellArg timeLedger}";
hora-status = writers.writeDashBin "hora-status" "${coreutils}/bin/tac ${lib.escapeShellArg timeLedger} | ${gnugrep}/bin/grep -m 1 .";
hora-start = writers.writeDashBin "hora-start" ''
last_nonempty_line=$(${hora-status}/bin/hora-status)
(echo $last_nonempty_line | ${gnugrep}/bin/grep -q "^o") || {
echo "Last activity must be closed: $last_nonempty_line" >/dev/stderr
exit 1
}
account=$1
(${hora}/bin/hora accounts | ${gnugrep}/bin/grep -q "^$account\$") || {
echo "The account '$account' is not known. Please add manually."
exit 1
}
message=$2
date=$(${date})
echo "i $date $account $message\n" >> "${timeLedger}"
echo "Started $account at $date" >/dev/stderr
'';
hora-stop = writers.writeDashBin "hora-stop" ''
last_nonempty_line=$(${hora-status}/bin/hora-status)
(echo $last_nonempty_line | ${gnugrep}/bin/grep "^i") || {
echo "Last activity cannot be closed: $last_nonempty_line" >/dev/stderr
exit 1
}
last_activity=$(echo "$last_nonempty_line" | ${coreutils}/bin/cut -d' ' -f 4)
date=$(${date})
echo "o $date\n" >> ${timeLedger}
echo "Stopped $last_activity at $date" >/dev/stderr
'';
hora-year = writers.writeDashBin "hora-year" ''
${hora}/bin/hora balance --tree --monthly --begin $(${coreutils}/bin/date +%Y) --depth 1
'';
hora-git = writers.writeDashBin "hora-git" ''
directory=$(${coreutils}/bin/dirname ${lib.escapeShellArg timeLedger})
if [ $# -gt 0 ]
then
${git}/bin/git -C "$directory" --all --message=$(${date})
else
${git}/bin/git -C "$directory" "$@"
fi
'';
hora-weekly = writers.writeDashBin "hora-weekly" ''
${hora}/bin/hora register -p weekly --depth 1 --empty
'';
in
symlinkJoin {
name = "hora";
paths = [
hora
hora-edit
hora-start
hora-status
hora-stop
hora-year
hora-git
hora-weekly
];
}

View File

@@ -1,32 +0,0 @@
# Convert JSON array of objects to CSV
{
writers,
python3,
}:
writers.writePython3Bin "json2csv" {
flakeIgnore = [ "E501" ];
} ''
import csv
import json
import sys
if __name__ == "__main__":
json_list = json.load(sys.stdin)
if not isinstance(json_list, list):
print("JSON object is not a list.", file=sys.stderr)
sys.exit(1)
if len(json_list) == 0:
print("JSON list is empty.", file=sys.stderr)
sys.exit(1)
keys = set()
for element in json_list:
if isinstance(element, dict):
keys |= element.keys()
else:
print("Non-dict element:", element, file=sys.stderr)
sys.exit(1)
writer = csv.DictWriter(sys.stdout, fieldnames=list(keys))
writer.writeheader()
for element in json_list:
writer.writerow(element)
''

30
packages/k-lock.nix Normal file
View File

@@ -0,0 +1,30 @@
{
writers,
lib,
xlockmore,
}:
let
xlockModes = lib.concatStringsSep "\\n" [
# "braid"
"galaxy"
# "lightning"
# "matrix"
"pyro2"
"space"
];
in
writers.writeDashBin "k-lock" ''
MODE=$(printf "${xlockModes}" | shuf -n 1)
${xlockmore}/bin/xlock \
-saturation 0.4 \
-erasemode no_fade \
+description \
-showdate \
-username " " \
-password " " \
-info " " \
-validate "..." \
-invalid "Computer says no." \
-mode "$MODE"
''

View File

@@ -1,90 +0,0 @@
# Convert and transfer audio files to an MP3 player
{
lib,
writers,
ffmpeg,
coreutils,
gnugrep,
gnused,
}:
writers.writeBashBin "mp3player-write" ''
set -e
SPEED=1.0
while getopts ":s:" opt; do
case $opt in
s) SPEED=$OPTARG ;;
\?) echo "Invalid option: -$OPTARG" >&2; exit 1 ;;
:) echo "Option -$OPTARG requires a value." >&2; exit 1 ;;
esac
done
shift $((OPTIND -1))
if [ "$#" -lt 2 ]; then
echo "Usage: mp3player-write [-s speed] MOUNT_POINT FILE1 [FILE2 ...]"
exit 1
fi
MOUNT_POINT=$1
shift
FILES=("$@")
if [ ! -d "$MOUNT_POINT" ]; then
echo "Error: Mount point '$MOUNT_POINT' does not exist."
exit 1
fi
TOTAL_SIZE=0
for f in "''${FILES[@]}"; do
if [ ! -f "$f" ]; then
echo "Warning: File '$f' does not exist, skipping."
continue
fi
FILE_SIZE=$(${lib.getExe' coreutils "stat"} --printf="%s" "$f")
TOTAL_SIZE=$((TOTAL_SIZE + FILE_SIZE / 2))
done
AVAILABLE=$(${lib.getExe' coreutils "df"} --output=avail "$MOUNT_POINT" | ${lib.getExe' coreutils "tail"} -n 1)
AVAILABLE=$((AVAILABLE * 1024))
if [ "$TOTAL_SIZE" -gt "$AVAILABLE" ]; then
echo "Error: Not enough space. Required: $TOTAL_SIZE bytes, Available: $AVAILABLE bytes"
exit 1
fi
echo "Enough space available. Starting conversion..."
sanitize_filename() {
local name
name=$(${lib.getExe' coreutils "basename"} "$1")
name=''${name%.*}
name=$(echo "$name" | ${lib.getExe' coreutils "tr"} ' ' '_' | ${lib.getExe' coreutils "tr"} -cd '[:alnum:]_-')
echo "''${name:0:50}"
}
for f in "''${FILES[@]}"; do
[ -f "$f" ] || continue
existing_prefixes=$(${lib.getExe' coreutils "ls"} "$MOUNT_POINT" | ${lib.getExe gnugrep} -E '^[0-9].*\.mp3$' | ${lib.getExe gnused} -E 's/^([0-9]).*/\1/' | ${lib.getExe' coreutils "sort"} -n | ${lib.getExe' coreutils "uniq"})
for i in {0..9}; do
if ! echo "$existing_prefixes" | ${lib.getExe gnugrep} -q "^$i$"; then
PREFIX=$i
break
fi
done
BASENAME=$(sanitize_filename "$f")
OUT_PATTERN="$MOUNT_POINT/''${PREFIX}_%03d_''${BASENAME}.mp3"
echo "Converting '$f' to '$OUT_PATTERN' at speed $SPEED..."
${lib.getExe ffmpeg} -nostdin -i "$f" \
-filter:a "atempo=$SPEED" \
-ar 22050 -ac 1 -c:a libmp3lame -b:a 32k \
-f segment -segment_time 300 \
"$OUT_PATTERN"
done
echo "All files processed successfully."
''

View File

@@ -1,14 +0,0 @@
# Add Arabic diacritics (tashkeel) to text via alsharekh.org
{
lib,
writers,
curl,
jq,
}:
writers.writeDashBin "mushakkil" ''
${lib.getExe curl} -sSL 'https://diac.alsharekh.org/Diac/DiacText' \
-H "Content-Type: application/json" \
--data-raw "$(${lib.getExe jq} --raw-input '{word: ., type: 1}')" \
--compressed \
| ${lib.getExe jq} -r .diacWord
''

View File

@@ -1,84 +0,0 @@
# Generate a Haddock index page for all packages visible to the current GHC
{
lib,
writers,
coreutils,
gnugrep,
gnused,
graphviz,
}:
writers.writeBashBin "nix-haddock-index" ''
set -efux
if test -z "''${NIX_GHC-}"; then
NIX_GHC=$(${lib.getExe' coreutils "readlink"} -f "$(type -P ghc)")
fi
if ! echo $NIX_GHC | ${lib.getExe gnugrep} -q '^/nix/store/'; then
printf '%s: error: unsupported GHC executable path (not in Nix store): %q\n' \
"$0" \
"$NIX_GHC" \
>&2
exit 1
fi
NIX_GHC_PREFIX=$(${lib.getExe' coreutils "dirname"} "$(${lib.getExe' coreutils "dirname"} "$NIX_GHC")")
NIX_GHC_DOCDIR=$NIX_GHC_PREFIX/share/doc/ghc/html
main() {
hash=$(echo $NIX_GHC_PREFIX | ${lib.getExe gnused} -n 's|^/nix/store/\([a-z0-9]\+\).*|\1|p')
title="Haddock index for $NIX_GHC_PREFIX"
header=$(
printf 'Haddock index for <a href="%s">%s</a>\n' \
$NIX_GHC_PREFIX \
$NIX_GHC_PREFIX \
)
suffix=''${hash:+-$hash}
index_file=/tmp/haddock$suffix-index.html
svg_file=/tmp/haddock$suffix.svg
eval "$(
echo 'gen_index() {'
echo ' html_head'
"$NIX_GHC_PREFIX"/bin/ghc-pkg dump | ${lib.getExe gnused} -n '
s/^---$/ reset/p
s/^\(name\|version\):\s*\([-A-Za-z0-9_.]\+\)$/ \1=\2/p
s/^haddock-html:\s*\([-A-Za-z0-9_./]\+\)$/ haddock_html \1/p
'
echo ' html_foot'
echo '}'
)"
gen_index > $index_file
"$NIX_GHC_PREFIX"/bin/ghc-pkg dot | ${lib.getExe' graphviz "tred"} | ${lib.getExe' graphviz "dot"} -Tsvg | ${lib.getExe gnused} '
s/<svg width="[0-9]\+pt" height="[0-9]\+pt"/<svg width="3600px" height="100%"/
' > $svg_file
echo $index_file
}
reset() {
unset name version
}
haddock_html() {
printf '<li>'
printf '<a href="%s/index.html">%s</a>' "$1" "$name-$version"
printf '</li>\n'
}
html_head() {
printf '<!doctype html>\n'
printf '<title>%s</title>\n' "$title"
printf '<link href="%s" rel="stylesheet" type="text/css">\n' \
"$NIX_GHC_DOCDIR/libraries/ocean.css"
printf '<h1>%s</h1>\n' "$header"
printf '<ul>\n'
}
html_foot() {
printf '</ul>\n'
printf '<a href="%s">graph</a>\n' "$svg_file"
}
main "$@"
''

View File

@@ -1,30 +0,0 @@
# OCR a PDF file to text using tesseract
{
lib,
writers,
poppler_utils,
tesseract,
coreutils,
}:
writers.writeDashBin "pdf-ocr" ''
set -efu
pdf_path="$(${lib.getExe' coreutils "realpath"} "$1")"
[ -f "$pdf_path" ] || {
echo "Usage: pdf-ocr FILE.pdf" >&2
exit 1
}
tmpdir="$(${lib.getExe' coreutils "mktemp"} -d)"
trap 'rm -rf $tmpdir' EXIT
cd "$tmpdir"
${lib.getExe' poppler_utils "pdftoppm"} -png "$pdf_path" pdf-ocr
for png in pdf-ocr*.png; do
${lib.getExe tesseract} "$png" "$png.txt" 2>/dev/null
done
cat pdf-ocr-*.txt
''

View File

@@ -1,69 +0,0 @@
{
runCommand,
nodejs,
writeShellApplication,
lib,
jq,
cacert,
pi-llm,
}:
let
# Pre-install pi plugins into a fake npm global prefix
pluginPrefixRaw =
runCommand "pi-plugins-raw"
{
nativeBuildInputs = [
nodejs
cacert
];
outputHashMode = "recursive";
outputHashAlgo = "sha256";
outputHash = "sha256-YrrQ5m8XYKFNR2+dn97GYxKxcWPBndomPZsqKfwD6w0=";
impureEnvVars = [
"http_proxy"
"https_proxy"
];
SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt";
}
''
export HOME=$TMPDIR
export npm_config_prefix=$out
npm install -g pi-hooks shitty-extensions
'';
# Remove the resistance extension (annoying terminator quote widget)
pluginPrefix = runCommand "pi-plugins" { } ''
cp -a ${pluginPrefixRaw} $out
chmod -R u+w $out
pkg=$out/lib/node_modules/shitty-extensions/package.json
${lib.getExe jq} '.pi.extensions |= map(select(contains("resistance") | not))' "$pkg" > "$pkg.tmp"
mv "$pkg.tmp" "$pkg"
'';
in
writeShellApplication {
name = "pi";
runtimeInputs = [ nodejs ];
text = ''
set -efu
export npm_config_prefix="${pluginPrefix}"
# Ensure settings.json has our plugins listed
SETTINGS_DIR="''${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}"
SETTINGS_FILE="$SETTINGS_DIR/settings.json"
mkdir -p "$SETTINGS_DIR"
# Add packages to settings if not already present
if [ ! -f "$SETTINGS_FILE" ]; then
echo '{"packages":["npm:pi-hooks","npm:shitty-extensions"]}' > "$SETTINGS_FILE"
else
for pkg in "npm:pi-hooks" "npm:shitty-extensions"; do
if ! grep -q "$pkg" "$SETTINGS_FILE"; then
${lib.getExe jq} --arg p "$pkg" '.packages = ((.packages // []) + [$p] | unique)' "$SETTINGS_FILE" > "$SETTINGS_FILE.tmp"
mv "$SETTINGS_FILE.tmp" "$SETTINGS_FILE"
fi
done
fi
exec ${lib.getExe pi-llm} "$@"
'';
}

View File

@@ -1,34 +0,0 @@
{ lib, buildGoModule, fetchFromGitHub }:
buildGoModule (finalAttrs: {
pname = "picoclaw";
version = "0.1.1";
src = fetchFromGitHub {
owner = "sipeed";
repo = "picoclaw";
rev = "v${finalAttrs.version}";
hash = "sha256-nx/D8ir4/l0pTnMNORby2FNtU+ouKT0DUjP2vpJLmPk=";
};
postPatch = ''
substituteInPlace go.mod --replace "go 1.25.7" "go 1.25.5"
'';
proxyVendor = true;
# Set to lib.fakeHash or empty initially, then update with the actual hash Nix reports.
vendorHash = "sha256-XKwYmbMyf4yg/E4Yv0uMS9v0oAuMZJwvoaAPCL/1AAY=";
subPackages = [ "cmd/picoclaw" ];
ldflags = [
"-s" "-w"
"-X main.version=${finalAttrs.version}"
];
meta = with lib; {
description = "Ultra-efficient AI Assistant in Go for $10 hardware";
homepage = "https://github.com/sipeed/picoclaw";
license = licenses.mit; # Verify license in the repo
maintainers = [];
};
})

View File

@@ -1,77 +0,0 @@
# Browse and view German supermarket flyers (Lidl, Aldi, REWE, Kaufland, Netto)
{
writers,
curl,
jq,
fzf,
zathura,
coreutils,
htmlq,
gnugrep,
gnused,
lib,
}:
writers.writeDashBin "prospekte" ''
export PATH=${lib.makeBinPath [ curl jq fzf zathura coreutils htmlq gnugrep gnused ]}:$PATH
lidl() {
echo LIDL
curl -sSL 'https://endpoints.lidl-flyer.com/v3/region-overview/lidl/de-DE/0.json' \
| jq -r '
.categories
| map(select(.name == "Filial-Angebote") | .subcategories | map(.flyers))
| flatten
| flatten
| .[]
| .pdfUrl
'
}
aldi_nord() {
echo ALDI nord
echo 'https://magazine.aldi-nord.de/aldi-nord/aldi-aktuell/GetPDF.ashx'
echo 'https://magazine.aldi-nord.de/aldi-nord/aldi-vorschau/GetPDF.ashx'
}
rewe_berlin() {
store_id=662366923
publisher_id=1062
echo REWE
curl -sSL "https://www.bonialserviceswidget.de/de/stores/$store_id/brochures?storeId=$store_id&publisherId=$publisher_id" | while read -r brochure_id; do
curl -sSL "https://www.bonialserviceswidget.de/de/v5/brochureDetails/$brochure_id?publisherId=$publisher_id" | jq -r .pdfUrl
done
}
kaufland() {
region_code=8920
echo KAUFLAND
curl -sSL https://filiale.kaufland.de/prospekte.html | htmlq --attribute href '.flyer a' | grep -Eo 'DE_de_KDZ[^/]*' | sed "s/_3000_/_''${region_code}_/" | while read -r flyer_id; do
curl -sSL "https://endpoints.leaflets.kaufland.com/v3/$flyer_id/flyer.json?regionCode=$region_code" | jq -r .flyer.pdfUrl
done
}
netto_schwarz() {
echo 'NETTO (schwarz)'
curl -sSL 'https://squid-api.tjek.com/v2/catalogs?dealer_ids=90f2VL&order_by=created' \
| jq -r '.[] | .id' \
| while read -r flyer_id; do
curl -sSL "https://squid-api.tjek.com/v2/catalogs/$flyer_id/download" \
| jq -r .pdf_url
done
}
dir="$(mktemp -d)"
trap 'rm -rf "$dir"' EXIT
prospekt_url="$( (
lidl
aldi_nord
rewe_berlin
kaufland
netto_schwarz
) | fzf)"
curl -sSL "$prospekt_url" -o "$dir/prospekt.pdf"
zathura "$dir/prospekt.pdf"
''

View File

@@ -6,9 +6,6 @@
jq,
yq,
}:
let
model = "gemini-2.5-flash-lite";
in
writers.writeBashBin "radio-news" ''
set -efu
PATH=$PATH:${
@@ -60,5 +57,5 @@ writers.writeBashBin "radio-news" ''
EOF
)
echo "$REQUEST" | curl "https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=$GEMINI_API_KEY" -s -H "Content-Type: application/json" -d @-
echo "$REQUEST" | curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-8b:generateContent?key=$GEMINI_API_KEY" -s -H "Content-Type: application/json" -d @-
''

View File

@@ -1,13 +0,0 @@
# Render a GitHub repo's README.md as a man page
{
lib,
writers,
curl,
pandoc,
man,
}:
writers.writeDashBin "readme" ''
${lib.getExe curl} -sSL "https://raw.githubusercontent.com/$*/master/README.md" \
| ${lib.getExe pandoc} -f gfm -t man -s \
| ${lib.getExe man} -l -
''

27
packages/vimv.nix Normal file
View File

@@ -0,0 +1,27 @@
{
lib,
stdenv,
bash,
fetchFromGitHub,
}:
stdenv.mkDerivation {
name = "vimv";
src = fetchFromGitHub {
owner = "thameera";
repo = "vimv";
rev = "4152496c1946f68a13c648fb7e583ef23dac4eb8";
sha256 = "1fsrfx2gs6bqx7wk7pgcji2i2x4alqpsi66aif4kqvnpqfhcfzjd";
};
phases = [ "installPhase" ];
installPhase = ''
mkdir -p $out/bin
sed 's:#!/bin/bash:#!${bash}/bin/bash:' $src/vimv > $out/bin/vimv
chmod 755 $out/bin/vimv
'';
meta = with lib; {
homepage = "https://github.com/thameera/vimv";
description = "Batch-rename files using Vim";
license = licenses.mit;
platforms = platforms.all;
};
}

Submodule secrets updated: 4fa163a68e...83d9103f20

View File

@@ -61,8 +61,6 @@ secrets/nextcloud-password-database.age
secrets/nextcloud-password-fysi.age
secrets/nextcloud-password-kieran.age
secrets/onlyoffice-jwt-key.age
secrets/opencrow-matrix-token.age
secrets/opencrow-soul.age
secrets/openweathermap-api-key.age
secrets/restic.age
secrets/secrets.nix

View File

@@ -1,4 +1,3 @@
{ pkgs, ... }:
{
nixpkgs.config = {
allowUnfree = true;
@@ -22,14 +21,7 @@
};
};
services.ollama = {
enable = true;
acceleration = "cuda"; # Force it to use the MX150
package = pkgs.ollama-cuda;
};
nix.settings.system-features = [ "cuda" ];
nixpkgs.config.cudaCapabilities = [ "6.1" ];
programs.nix-required-mounts = {
enable = true;

View File

@@ -16,7 +16,6 @@
./gemini.nix
./wallabag.nix
./nethack.nix
./opencrow.nix
];
niveum.passport = {

View File

@@ -1,83 +0,0 @@
{
config,
pkgs,
...
}:
{
age.secrets = {
opencrow-matrix-token = {
file = ../../secrets/opencrow-matrix-token.age;
};
opencrow-soul = {
file = ../../secrets/opencrow-soul.age;
};
opencrow-gemini-key = {
file = ../../secrets/opencrow-gemini-key.age;
};
opencrow-openrouter-key = {
file = ../../secrets/opencrow-openrouter-key.age;
};
};
environment.systemPackages = [
pkgs.pi
];
services.opencrow = {
enable = true;
package = pkgs.opencrow;
extraPackages = [
pkgs.pi
pkgs.nix
];
environmentFiles = [
config.age.secrets.opencrow-matrix-token.path
config.age.secrets.opencrow-openrouter-key.path
config.age.secrets.opencrow-gemini-key.path
];
extraBindMounts."/run/opencrow/SOUL.md" = {
hostPath = config.age.secrets.opencrow-soul.path;
isReadOnly = true;
};
environment = {
NIX_REMOTE = "daemon";
PI_PERMISSION_LEVEL = "high";
OPENCROW_MATRIX_HOMESERVER = "https://matrix.org";
OPENCROW_MATRIX_USER_ID = "@fable_ai:matrix.org";
OPENCROW_SOUL_FILE = "/run/opencrow/SOUL.md";
OPENCROW_HEARTBEAT_INTERVAL = "2h";
# end of the month
OPENCROW_PI_PROVIDER = "openrouter";
OPENCROW_PI_MODEL = "stepfun/step-3.5-flash:free";
# OPENCROW_PI_PROVIDER = "google";
# OPENCROW_PI_MODEL = "gemini-2.0-flash";
# beginning of the month
# OPENCROW_PI_PROVIDER = "github-copilot";
# OPENCROW_PI_MODEL = "claude-opus-4.6";
};
};
containers.opencrow.config = {
nix.settings.experimental-features = [
"flakes"
"nix-command"
];
};
nix.settings.experimental-features = [
"flakes"
"nix-command"
];
services.restic.backups.niveum.paths = [
"/var/lib/opencrow"
];
}

View File

@@ -5,23 +5,42 @@
...
}:
let
irc-xxx = pkgs.panoptikonReporters.kpaste-irc {
irc-xxx = pkgs.lib.panoptikon.kpaste-irc {
target = lib.escapeShellArg "#xxx";
retiolumLink = true;
};
matrix-kmein = pkgs.panoptikonReporters.matrix {
homeserver = "matrix.4d2.org";
roomId = lib.escapeShellArg "!zlwCuPiCNMSxDviFzA:4d2.org";
tokenPath = config.age.secrets.matrix-token-lakai.path;
};
matrix =
{
server ? "matrix.4d2.org",
target,
}:
pkgs.writers.writeDash "matrix-reporter" ''
export RAW_MESSAGE="$(cat)"
export MESSAGE=$(printf '<b>%s</b><br><pre>%s</pre>' "$PANOPTIKON_WATCHER" "$RAW_MESSAGE")
export MATRIX_TOKEN="$(cat ${config.age.secrets.matrix-token-lakai.path})"
export JSON_PAYLOAD=$(${pkgs.jq}/bin/jq -n --arg msgtype "m.text" --arg body "$RAW_MESSAGE" --arg formattedBody "$MESSAGE" '{msgtype: $msgtype, body: $body, format: "org.matrix.custom.html", formatted_body: $formattedBody}')
${pkgs.curl}/bin/curl -X POST "https://${server}/_matrix/client/r0/rooms/${target}/send/m.room.message" \
-d "$JSON_PAYLOAD" \
-H "Authorization: Bearer $MATRIX_TOKEN" \
-H "Content-Type: application/json"
'';
telegram-kmein = pkgs.panoptikonReporters.telegram {
tokenPath = config.age.secrets.telegram-token-kmein.path;
chatId = "-1001796440545";
};
matrix-kmein = matrix { target = "!zlwCuPiCNMSxDviFzA:4d2.org"; };
irc-kmein = pkgs.panoptikonReporters.kpaste-irc {
telegram-kmein =
let
chatId = "-1001796440545";
in
pkgs.writers.writeDash "telegram-fulltext" ''
export TOKEN="$(cat "$CREDENTIALS_DIRECTORY/token")"
${pkgs.curl}/bin/curl -X POST "https://api.telegram.org/bot''${TOKEN}/sendMessage" \
-d chat_id=${chatId} \
-d text="$(cat)" \
| ${pkgs.jq}/bin/jq -e .ok
'';
irc-kmein = pkgs.lib.panoptikon.kpaste-irc {
messagePrefix = "$PANOPTIKON_WATCHER: ";
target = "kmein";
nick = "panoptikon-kmein";
@@ -29,12 +48,7 @@ let
};
in
{
age.secrets.telegram-token-kmein = {
file = ../../secrets/telegram-token-kmein.age;
owner = "panoptikon";
group = "panoptikon";
mode = "400";
};
age.secrets.telegram-token-kmein.file = ../../secrets/telegram-token-kmein.age;
age.secrets.matrix-token-lakai = {
file = ../../secrets/matrix-token-lakai.age;
owner = "panoptikon";
@@ -46,7 +60,7 @@ in
enable = true;
watchers = {
"github-meta" = {
script = pkgs.panoptikonWatchers.json {
script = pkgs.lib.panoptikon.urlJSON {
jqScript = ''
{
ssh_key_fingerprints: .ssh_key_fingerprints,
@@ -56,71 +70,83 @@ in
} "https://api.github.com/meta";
reporters = [ irc-xxx ];
};
lammla = {
script = pkgs.lib.panoptikon.url "http://lammla.info/index.php?reihe=30";
reporters = [ matrix-kmein ];
};
kratylos = {
script = pkgs.lib.panoptikon.url "https://kratylos.reichert-online.org/current_issue/KRATYLOS";
reporters = [ matrix-kmein ];
};
kobudo-tesshinkan = {
script = pkgs.panoptikonWatchers.html "https://kobudo-tesshinkan.eu/index.php/de/termine-berichte/lehrgaenge/";
script = pkgs.lib.panoptikon.url "https://kobudo-tesshinkan.eu/index.php/de/termine-berichte/lehrgaenge/";
reporters = [
telegram-kmein
matrix-kmein
];
};
zeno-free = {
script = pkgs.lib.panoptikon.urlSelector ".zenoCOMain" "http://www.zeno.org/Lesesaal/M/E-Books";
reporters = [ matrix-kmein ];
};
carolinawelslau = {
script = pkgs.panoptikonWatchers.htmlSelector "#main" "https://carolinawelslau.de/";
script = pkgs.lib.panoptikon.urlSelector "#main" "https://carolinawelslau.de/";
reporters = [ matrix-kmein ];
};
humboldt-preis = {
script = pkgs.panoptikonWatchers.htmlSelector "#content-core" "https://www.hu-berlin.de/de/ueberblick/menschen/ehrungen/humboldtpreis";
script = pkgs.lib.panoptikon.urlSelector "#content-core" "https://www.hu-berlin.de/de/ueberblick/menschen/ehrungen/humboldtpreis";
reporters = [ matrix-kmein ];
};
lisalittmann = {
script = pkgs.panoptikonWatchers.htmlSelector "#site-content" "https://lisalittmann.de/";
script = pkgs.lib.panoptikon.urlSelector "#site-content" "https://lisalittmann.de/";
reporters = [ matrix-kmein ];
};
lisalittmann-archive = {
script = pkgs.panoptikonWatchers.htmlSelector "#site-content" "https://lisalittmann.de/archive/";
script = pkgs.lib.panoptikon.urlSelector "#site-content" "https://lisalittmann.de/archive/";
reporters = [ matrix-kmein ];
};
lisalittmann-projects = {
script = pkgs.panoptikonWatchers.htmlSelector "#site-content" "https://lisalittmann.de/projects/";
script = pkgs.lib.panoptikon.urlSelector "#site-content" "https://lisalittmann.de/projects/";
reporters = [ matrix-kmein ];
};
tatort = {
script = pkgs.panoptikonWatchers.htmlSelector ".linklist" "https://www.daserste.de/unterhaltung/krimi/tatort/sendung/index.html";
script = pkgs.lib.panoptikon.urlSelector ".linklist" "https://www.daserste.de/unterhaltung/krimi/tatort/sendung/index.html";
reporters = [ matrix-kmein ];
};
warpgrid-idiomarium = {
script = pkgs.panoptikonWatchers.htmlSelector "#site-content" "https://warpgrid.de/idiomarium/";
script = pkgs.lib.panoptikon.urlSelector "#site-content" "https://warpgrid.de/idiomarium/";
reporters = [ matrix-kmein ];
};
warpgrid-futurism = {
script = pkgs.panoptikonWatchers.htmlSelector "#site-content" "https://warpgrid.de/futurism/";
script = pkgs.lib.panoptikon.urlSelector "#site-content" "https://warpgrid.de/futurism/";
reporters = [ matrix-kmein ];
};
warpgrid-imagiary = {
script = pkgs.panoptikonWatchers.htmlSelector "#site-content" "https://warpgrid.de/imagiary/";
script = pkgs.lib.panoptikon.urlSelector "#site-content" "https://warpgrid.de/imagiary/";
reporters = [ matrix-kmein ];
};
warpgrid-alchemy = {
script = pkgs.panoptikonWatchers.htmlSelector "#site-content" "https://warpgrid.de/alchemy/";
script = pkgs.lib.panoptikon.urlSelector "#site-content" "https://warpgrid.de/alchemy/";
reporters = [ matrix-kmein ];
};
indogermanische-forschungen = {
script = pkgs.panoptikonWatchers.htmlSelector "#latestIssue" "https://www.degruyter.com/journal/key/INDO/html";
script = pkgs.lib.panoptikon.urlSelector "#latestIssue" "https://www.degruyter.com/journal/key/INDO/html";
reporters = [ matrix-kmein ];
};
ig-neuigkeiten = {
script = pkgs.panoptikonWatchers.htmlSelector "[itemprop=articleBody]" "https://www.indogermanistik.org/aktuelles/neuigkeiten.html";
script = pkgs.lib.panoptikon.urlSelector "[itemprop=articleBody]" "https://www.indogermanistik.org/aktuelles/neuigkeiten.html";
reporters = [ matrix-kmein ];
};
ig-tagungen = {
script = pkgs.panoptikonWatchers.htmlSelector "[itemprop=articleBody]" "https://www.indogermanistik.org/tagungen/tagungen-der-ig.html";
script = pkgs.lib.panoptikon.urlSelector "[itemprop=articleBody]" "https://www.indogermanistik.org/tagungen/tagungen-der-ig.html";
reporters = [ matrix-kmein ];
};
fu-distant = {
script = pkgs.panoptikonWatchers.htmlSelector "#current_events" "https://www.geschkult.fu-berlin.de/en/e/ma-distant/Termine/index.html";
script = pkgs.lib.panoptikon.urlSelector "#current_events" "https://www.geschkult.fu-berlin.de/en/e/ma-distant/Termine/index.html";
reporters = [ matrix-kmein ];
};
fu-aegyptologie = {
script = pkgs.panoptikonWatchers.htmlSelector "#current_events" "https://www.geschkult.fu-berlin.de/e/aegyptologie/termine/index.html";
script = pkgs.lib.panoptikon.urlSelector "#current_events" "https://www.geschkult.fu-berlin.de/e/aegyptologie/termine/index.html";
reporters = [ matrix-kmein ];
};
};

View File

@@ -8,14 +8,17 @@
imports = [
./hardware-configuration.nix
../../configs/spacetime.nix
../../configs/admin-essentials.nix
../../configs/keyboard
../../configs/sound.nix
../../configs/printing.nix
../../configs/nix.nix
../../configs/fonts.nix
../../configs/mycelium.nix
../../configs/retiolum.nix
../../configs/sshd.nix
../../configs/sudo.nix
../../configs/zsh.nix
];
age.secrets = {

View File

@@ -9,7 +9,7 @@
./gitea.nix
./hardware-configuration.nix
./hedgedoc.nix
# ./menstruation.nix
./menstruation.nix
./moinbot.nix
./monitoring
# ./names.nix

View File

@@ -34,6 +34,7 @@
};
swapDevices = [ ];
zramSwap.enable = true;
nix.settings.max-jobs = lib.mkDefault 2;
}

View File

@@ -55,7 +55,7 @@ in
services.nextcloud = {
enable = true;
package = pkgs.nextcloud32;
package = pkgs.nextcloud31;
https = true;

View File

@@ -187,19 +187,16 @@ in
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
restartIfChanged = true;
path = [ pkgs.alacritty.terminfo pkgs.screen ];
environment = {
WEECHAT_HOME = weechatHome;
};
path = [ pkgs.alacritty.terminfo ];
environment.WEECHAT_HOME = weechatHome;
# preStart = "${pkgs.coreutils}/bin/rm $WEECHAT_HOME/*.conf";
script = "${pkgs.screen}/bin/screen -S weechat -d -m ${weechat}/bin/weechat";
preStop = "${pkgs.screen}/bin/screen -S weechat -X quit";
script = "${tmux} -2 new-session -d -s IM ${weechat}/bin/weechat";
preStop = "${tmux} kill-session -t IM";
serviceConfig = {
User = "weechat";
Group = "weechat";
RemainAfterExit = true;
Type = "oneshot";
RuntimeDirectory = "weechat-tmux";
};
};
@@ -213,7 +210,7 @@ in
group = "weechat";
home = "/var/lib/weechat";
isSystemUser = true;
packages = [ pkgs.screen ];
packages = [ pkgs.tmux ];
};
age.secrets.weechat-sec = {

View File

@@ -44,7 +44,7 @@
};
swapDevices = [ ];
zramSwap.enable = false;
zramSwap.enable = true;
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
}

View File

@@ -10,6 +10,8 @@
../../configs/spacetime.nix
../../configs/retiolum.nix
../../configs/sshd.nix
../../configs/nix.nix
../../configs/admin-essentials.nix
];
age.secrets = {

View File

@@ -10,6 +10,8 @@
../../configs/spacetime.nix
../../configs/sshd.nix
../../configs/retiolum.nix
../../configs/nix.nix
../../configs/admin-essentials.nix
];
age.secrets = {

View File

@@ -11,6 +11,7 @@
./hardware-configuration.nix
./home-assistant.nix
../../configs/printing.nix
../../configs/tmux.nix
../../configs/wpa_supplicant.nix
];
@@ -77,8 +78,6 @@
pkgs.python3 # for sshuttle
];
users.users.root.extraGroups = [ "lp" "scanner" ];
networking = {
hostName = "zaatar";
wireless.interfaces = [ "wlp2s0" ];